Browse Source

添加外部渠道分层特征

jch 3 weeks ago
parent
commit
a742260464

+ 87 - 181
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/FeatureService.java

@@ -8,6 +8,7 @@ import com.tzld.piaoquan.recommend.server.model.MachineInfo;
 import com.tzld.piaoquan.recommend.server.remote.FeatureV2RemoteService;
 import com.tzld.piaoquan.recommend.server.service.rank.RankParam;
 import com.tzld.piaoquan.recommend.server.service.rank.bo.UserShareReturnProfile;
+import com.tzld.piaoquan.recommend.server.util.FeatureUtils;
 import com.tzld.piaoquan.recommend.server.util.JSONUtils;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
@@ -31,107 +32,6 @@ public class FeatureService {
     private static final Set<String> hotSceneSet = new HashSet<>(Arrays.asList("1008", "1007", "1058", "1074", "1010"));
     private static final Set<String> hotSceneTypeSet = new HashSet<>(Arrays.asList("1008", "1007"));
 
-    /**
-     * @return k1:视频、k2:表、k3:特征、v:特征值
-     */
-    public Feature getFeature(String mid, List<String> vidList, String appType,
-                              String province, String headVid) {
-
-
-        List<FeatureKeyProto> protos = new ArrayList<>();
-
-        for (String vid : vidList) {
-            // TODO 补充其他特征
-            // vid
-            // protos.add(genWithVid("alg_vid_feature_all_exp", vid));
-            protos.add(genWithVid("alg_vid_feature_all_exp_v2", vid));
-            protos.add(genWithVid("alg_vid_feature_all_share", vid));
-            protos.add(genWithVid("alg_vid_feature_all_return", vid));
-            // protos.add(genWithVid("alg_vid_feature_exp2share", vid));
-            protos.add(genWithVid("alg_vid_feature_exp2share_v2", vid));
-            protos.add(genWithVid("alg_vid_feature_share2return", vid));
-            // protos.add(genWithVid("alg_vid_feature_feed_noflow_exp", vid));
-            protos.add(genWithVid("alg_vid_feature_feed_noflow_exp_v2", vid));
-            // protos.add(genWithVid("alg_vid_feature_feed_noflow_root_share", vid));
-            protos.add(genWithVid("alg_vid_feature_feed_noflow_root_share_v2", vid));
-            // protos.add(genWithVid("alg_vid_feature_feed_noflow_root_return", vid));
-            protos.add(genWithVid("alg_vid_feature_feed_noflow_root_return_v2", vid));
-            // protos.add(genWithVid("alg_vid_feature_feed_flow_exp", vid));
-            protos.add(genWithVid("alg_vid_feature_feed_flow_exp_v2", vid));
-            // protos.add(genWithVid("alg_vid_feature_feed_flow_root_share", vid));
-            protos.add(genWithVid("alg_vid_feature_feed_flow_root_share_v2", vid));
-            // protos.add(genWithVid("alg_vid_feature_feed_flow_root_return", vid));
-            protos.add(genWithVid("alg_vid_feature_feed_flow_root_return_v2", vid));
-
-            protos.add(genWithVid("alg_vid_feature_basic_info", vid));
-            // vid + apptype
-
-            // vid + province
-            // protos.add(genWithVidAndProvince("alg_vid_feature_feed_province_exp", vid, province));
-            protos.add(genWithVidAndProvince("alg_vid_feature_feed_province_exp_v2", vid, province));
-            // protos.add(genWithVidAndProvince("alg_vid_feature_feed_province_root_share", vid, province));
-            protos.add(genWithVidAndProvince("alg_vid_feature_feed_province_root_share_v2", vid, province));
-            // protos.add(genWithVidAndProvince("alg_vid_feature_feed_province_root_return", vid, province));
-            protos.add(genWithVidAndProvince("alg_vid_feature_feed_province_root_return_v2", vid, province));
-
-            // vid + headvid
-            protos.add(genWithVidAndHeadVid("alg_recsys_feature_cf_i2i_new", vid, headVid));
-            //protos.add(genWithVidAndHeadVid("alg_recsys_feature_cf_i2i_new_v2", vid, headVid));
-        }
-
-        // 头部视频的基础信息
-        protos.add(genWithVid("alg_vid_feature_basic_info", headVid));
-
-        // user
-        protos.add(genWithMid("alg_mid_feature_play", mid));
-        protos.add(genWithMid("alg_mid_feature_share_and_return", mid));
-        protos.add(genWithMid("alg_mid_feature_play_tags", mid));
-        protos.add(genWithMid("alg_mid_feature_return_tags", mid));
-        protos.add(genWithMid("alg_mid_feature_share_tags", mid));
-        // protos.add(genWithMid("alg_mid_feature_feed_exp_share_tags", mid));
-        protos.add(genWithMid("alg_mid_feature_feed_exp_share_tags_v2", mid));
-        // protos.add(genWithMid("alg_mid_feature_feed_exp_return_tags", mid));
-        protos.add(genWithMid("alg_mid_feature_feed_exp_return_tags_v2", mid));
-        protos.add(genWithMid("alg_mid_feature_sharecf", mid));
-        protos.add(genWithMid("alg_mid_feature_returncf", mid));
-
-
-        Map<String, String> result = remoteService.getFeature(protos);
-
-        Feature feature = new Feature();
-
-        result.entrySet().forEach(e -> {
-
-            String[] uk = StringUtils.split(e.getKey(), ":");
-            String prefix = uk[0];
-            String table = uk[1];
-            Map<String, String> colMap = JSONUtils.fromJson(e.getValue(), new TypeToken<Map<String, String>>() {
-            }, Collections.emptyMap());
-            String featureStr = colMap.get("feature");
-
-            switch (prefix) {
-                case "v":
-                    String vid = uk[2];
-                    Map<String, Map<String, String>> tableFeatureMap = feature.getVideoFeature().getOrDefault(vid, new HashMap<>());
-                    tableFeatureMap.put(table, JSONUtils.fromJson(featureStr, new TypeToken<Map<String, String>>() {
-                    }, Collections.emptyMap()));
-                    feature.getVideoFeature().put(vid, tableFeatureMap);
-                    break;
-                case "u":
-                    feature.getUserFeature().put(table, JSONUtils.fromJson(featureStr, new TypeToken<Map<String, String>>() {
-                    }, Collections.emptyMap()));
-                    break;
-                default:
-                    break;
-            }
-
-        });
-
-
-        return feature;
-    }
-
-
     public Map<String, Map<String, Map<String, String>>> getVideoBaseInfo(String headVid, List<String> vidList) {
         List<FeatureKeyProto> protos = new ArrayList<>();
         if (null != headVid && !headVid.isEmpty()) {
@@ -144,86 +44,9 @@ public class FeatureService {
         return feature.getVideoFeature();
     }
 
-    public Feature getNewFeature(String province, String mid, String sceneType, String headVid,
-                                 Map<String, Map<String, Map<String, String>>> videoBaseInfoMap, List<String> vidList) {
-        List<FeatureKeyProto> protos = new ArrayList<>();
-        String i2iSceneType = "other";
-        if (hotSceneSet.contains(sceneType)) {
-            i2iSceneType = sceneType;
-        }
-        for (String vid : vidList) {
-            // ********************* old vid ******************
-            protos.add(genWithVid("alg_vid_feature_all_exp_v2", vid));
-            protos.add(genWithVid("alg_vid_feature_all_share", vid));
-            protos.add(genWithVid("alg_vid_feature_all_return", vid));
-            protos.add(genWithVid("alg_vid_feature_exp2share_v2", vid));
-            protos.add(genWithVid("alg_vid_feature_share2return", vid));
-            protos.add(genWithVid("alg_vid_feature_feed_noflow_exp_v2", vid));
-            protos.add(genWithVid("alg_vid_feature_feed_noflow_root_share_v2", vid));
-            protos.add(genWithVid("alg_vid_feature_feed_noflow_root_return_v2", vid));
-            protos.add(genWithVid("alg_vid_feature_feed_flow_exp_v2", vid));
-            protos.add(genWithVid("alg_vid_feature_feed_flow_root_share_v2", vid));
-            protos.add(genWithVid("alg_vid_feature_feed_flow_root_return_v2", vid));
-
-            // vid + province
-            protos.add(genWithVidAndProvince("alg_vid_feature_feed_province_exp_v2", vid, province));
-            protos.add(genWithVidAndProvince("alg_vid_feature_feed_province_root_share_v2", vid, province));
-            protos.add(genWithVidAndProvince("alg_vid_feature_feed_province_root_return_v2", vid, province));
-
-            // headvid + vid
-            // protos.add(genWithKeyMap("alg_recsys_feature_cf_i2i_new_v2", vid, ImmutableMap.of("vid_a", headVid, "vid_b", vid)));
-
-            // ********************* new vid ******************
-            protos.add(genWithKeyMap("alg_vid_feature_day", vid, ImmutableMap.of("vid", vid)));
-            protos.add(genWithKeyMap("alg_sence_type_feature", vid, ImmutableMap.of("sence_type", sceneType, "videoid", vid)));
-            protos.add(genWithKeyMap("alg_videoid_feature", vid, ImmutableMap.of("videoid", vid)));
-            // protos.add(genWithKeyMap("alg_recsys_feature_cf_i2i_scene_rov", vid, ImmutableMap.of("sence_type", i2iSceneType, "vid_a", headVid, "vid_b", vid)));
-            // protos.add(genWithKeyMap("alg_recsys_feature_cf_i2i_scene_ros", vid, ImmutableMap.of("sence_type", i2iSceneType, "vid_a", headVid, "vid_b", vid)));
-            // protos.add(genWithKeyMap("alg_recsys_feature_weak_cf_i2i_scene_rov", vid, ImmutableMap.of("sence_type", i2iSceneType, "vid_a", headVid, "vid_b", vid)));
-            // protos.add(genWithKeyMap("alg_recsys_feature_weak_cf_i2i_scene_ros", vid, ImmutableMap.of("sence_type", i2iSceneType, "vid_a", headVid, "vid_b", vid)));
-            if (null != videoBaseInfoMap && videoBaseInfoMap.containsKey(vid)) {
-                Map<String, Map<String, String>> videoInfo = videoBaseInfoMap.get(vid);
-                if (null != videoInfo && videoInfo.containsKey("alg_vid_feature_basic_info")) {
-                    Map<String, String> baseInfo = videoInfo.get("alg_vid_feature_basic_info");
-                    if (null != baseInfo) {
-                        String cate1 = baseInfo.get("cate1_list");
-                        if (null != cate1 && !cate1.isEmpty()) {
-                            protos.add(genWithKeyMap("alg_cate1_feature", vid, ImmutableMap.of("cate1", cate1)));
-                            protos.add(genWithKeyMap("alg_cate1_feature_day", vid, ImmutableMap.of("cate1", cate1)));
-                        }
-                        String cate2 = baseInfo.get("cate2");
-                        if (null != cate2 && !cate2.isEmpty()) {
-                            protos.add(genWithKeyMap("alg_cate2_feature", vid, ImmutableMap.of("cate2", cate2)));
-                            protos.add(genWithKeyMap("alg_cate2_feature_day", vid, ImmutableMap.of("cate2", cate2)));
-                        }
-                        String vidSource = baseInfo.get("vid_source");
-                        if (null != vidSource && !vidSource.isEmpty()) {
-                            protos.add(genWithKeyMap("alg_vid_source_feature", vid, ImmutableMap.of("vid_source", vidSource)));
-                            protos.add(genWithKeyMap("alg_video_source_feature_day", vid, ImmutableMap.of("video_source", vidSource)));
-                        }
-                        String videoUnionid = baseInfo.get("title_time_w_h_unionid");
-                        if (null != videoUnionid && !videoUnionid.isEmpty()) {
-                            protos.add(genWithKeyMap("alg_video_unionid_feature_day", vid, ImmutableMap.of("video_unionid", videoUnionid)));
-                        }
-                    }
-                }
-            }
-        }
-
-        // user
-        protos.add(genWithMid("alg_mid_feature_play", mid));
-        protos.add(genWithMid("alg_mid_feature_share_and_return", mid));
-        protos.add(genWithMid("alg_mid_feature_play_tags", mid));
-        protos.add(genWithMid("alg_mid_feature_return_tags", mid));
-        protos.add(genWithMid("alg_mid_feature_share_tags", mid));
-        protos.add(genWithMid("alg_mid_feature_feed_exp_share_tags_v2", mid));
-        protos.add(genWithMid("alg_mid_feature_feed_exp_return_tags_v2", mid));
-        protos.add(genWithMid("alg_mid_feature_sharecf", mid));
-        protos.add(genWithMid("alg_mid_feature_returncf", mid));
-
-        return getFeatureByProto(protos);
-    }
-
+    /**
+     * @return k1:视频、k2:表、k3:特征、v:特征值
+     */
     public Feature getFeatureV3(RankParam param, Map<String, Map<String, Map<String, String>>> videoBaseInfoMap, List<String> vidList) {
         String mid = param.getMid();
         String mergeMid = getMergeMid(param.getUid(), mid);
@@ -324,6 +147,89 @@ public class FeatureService {
         return getFeatureByProto(protos);
     }
 
+    /**
+     * @return k1:视频、k2:表、k3:特征、v:特征值
+     */
+    public Feature getFeatureV4(RankParam param, Map<String, String> headInfo, Map<String, Map<String, Map<String, String>>> videoBaseInfoMap, List<String> vidList) {
+        String mid = param.getMid();
+        String mergeMid = getMergeMid(param.getUid(), mid);
+        String headVid = String.valueOf(param.getHeadVid());
+        String province = param.getProvince().replaceAll("省$", "");
+        String apptype = param.getAppType() + "";
+        String orgHotScene = String.valueOf(param.getHotSceneType());
+        String brand = "";
+        if (null != param.getMachineInfo()) {
+            MachineInfo machineInfo = param.getMachineInfo();
+            if (null != machineInfo.getBrand()) {
+                brand = machineInfo.getBrand();
+            }
+        }
+        String hotSceneType = orgHotScene;
+        if (!hotSceneTypeSet.contains(hotSceneType)) {
+            hotSceneType = "other";
+        }
+        String senceType = orgHotScene;
+        if (!hotSceneSet.contains(senceType)) {
+            senceType = "other";
+        }
+        String userChannel = "-1";
+        if (null != param.getChannelName() && !param.getChannelName().isEmpty()) {
+            userChannel = param.getChannelName();
+        }
+        String userLayer = "非0层";
+        if (FeatureUtils.firstLevel(param.getUserShareDepth())) {
+            userLayer = "0层";
+        }
+        String unionid = "-1";
+        if (null != headInfo) {
+            unionid = headInfo.getOrDefault("title_time_w_h_unionid", unionid);
+        }
+
+        List<FeatureKeyProto> protos = new ArrayList<>();
+        // vid
+        for (String vid : vidList) {
+            protos.add(genWithKeyMap("alg_recsys_feature_video_clean_stat", vid, ImmutableMap.of("vid", vid)));
+            protos.add(genWithKeyMap("alg_vid_global_feature_20250212", vid, ImmutableMap.of("vid", vid)));
+            protos.add(genWithKeyMap("alg_vid_recommend_exp_feature_20250212", vid, ImmutableMap.of("vid", vid)));
+            protos.add(genWithKeyMap("alg_vid_recommend_flowpool_exp_feature_20250212", vid, ImmutableMap.of("vid", vid)));
+            protos.add(genWithKeyMap("alg_vid_apptype_recommend_exp_feature_20250212", vid, ImmutableMap.of("vid", vid, "apptype", apptype)));
+            protos.add(genWithKeyMap("alg_vid_province_recommend_exp_feature_20250212", vid, ImmutableMap.of("vid", vid, "province", province)));
+            protos.add(genWithKeyMap("alg_vid_brand_recommend_exp_feature_20250212", vid, ImmutableMap.of("vid", vid, "brand", brand)));
+            protos.add(genWithKeyMap("alg_vid_hotsencetype_recommend_exp_feature_20250212", vid, ImmutableMap.of("vid", vid, "hotsencetype", hotSceneType)));
+
+            protos.add(genWithKeyMap("scene_type_vid_cf_feature_20250212", vid, ImmutableMap.of("sence_type", senceType, "vid_a", headVid, "vid_b", vid)));
+            protos.add(genWithKeyMap("vid_click_cf_feature_20250212", vid, ImmutableMap.of("vid_a", headVid, "vid_b", vid)));
+            protos.add(genWithKeyMap("alg_recsys_feature_cf_i2i_v2", vid, ImmutableMap.of("vid_a", headVid, "vid_b", vid)));
+            protos.add(genWithKeyMap("alg_recsys_feature_video_recommend_channel_layer", vid, ImmutableMap.of("channel", userChannel, "layer", userLayer, "vid", vid)));
+            protos.add(genWithKeyMap("alg_recsys_feature_video_recommend_channel_layer_head", vid, ImmutableMap.of("channel", userChannel, "layer", userLayer, "unionid", unionid, "vid", vid)));
+            if (null != videoBaseInfoMap) {
+                Map<String, Map<String, String>> videoInfo = videoBaseInfoMap.getOrDefault(vid, new HashMap<>());
+                Map<String, String> baseInfo = videoInfo.getOrDefault("alg_vid_feature_basic_info", new HashMap<>());
+                String merge_cate1 = baseInfo.getOrDefault("merge_first_level_cate", "unknown").trim();
+                protos.add(genWithKeyMap("alg_merge_cate1_recommend_exp_feature_20250212", vid, ImmutableMap.of("merge_cate1", merge_cate1)));
+
+                String merge_cate2 = baseInfo.getOrDefault("merge_second_level_cate", "unknown").trim();
+                protos.add(genWithKeyMap("alg_merge_cate2_recommend_exp_feature_20250212", vid, ImmutableMap.of("merge_cate2", merge_cate2)));
+
+                String channel = baseInfo.getOrDefault("channel", "unknown").trim();
+                protos.add(genWithKeyMap("alg_channel_recommend_exp_feature_20250212", vid, ImmutableMap.of("channel", channel)));
+
+                String festive = baseInfo.getOrDefault("festive_label2", "unknown").trim();
+                protos.add(genWithKeyMap("alg_festive_recommend_exp_feature_20250212", vid, ImmutableMap.of("festive", festive)));
+
+                String videoUnionid = baseInfo.getOrDefault("title_time_w_h_unionid", "unknown");
+                protos.add(genWithKeyMap("alg_video_unionid_recommend_exp_feature_20250212", vid, ImmutableMap.of("video_unionid", videoUnionid)));
+            }
+        }
+        // user
+        protos.add(genWithMid("alg_mid_feature_return_tags", mid));
+        protos.add(genWithMid("alg_mid_feature_share_tags", mid));
+        protos.add(genWithMid("mid_global_feature_20250212", mid));
+        protos.add(genWithMid("alg_recsys_feature_user_share_return_stat", mergeMid));
+
+        return getFeatureByProto(protos);
+    }
+
     public Feature getFeatureByNewLabel(String appType, String hotSceneType, String province, String brand, String mid, String headVideoId, List<String> vidList, Map<String, Map<String, Map<String, String>>> videoBaseInfoMap) {
 
         List<FeatureKeyProto> protos = new ArrayList<>();

+ 25 - 6
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelV566.java

@@ -45,6 +45,7 @@ public class RankStrategy4RegionMergeModelV566 extends RankStrategy4RegionMergeM
 
         long currentMs = System.currentTimeMillis();
         Set<Long> setVideo = new HashSet<>();
+        setVideo.add(param.getHeadVid());
         List<Video> rovRecallRank = new ArrayList<>();
         // -------------------5路特殊旧召回------------------
         RecallUtils.extractOldSpecialRecall(param, setVideo, rovRecallRank);
@@ -68,6 +69,12 @@ public class RankStrategy4RegionMergeModelV566 extends RankStrategy4RegionMergeM
         RecallUtils.extractRecall(mergeWeight.getOrDefault("headCate2Rov", 5.0).intValue(), param, HeadCate2RovRecallStrategy.PUSH_FROM, setVideo, rovRecallRank);
         //-------------------city rovn------------------
         RecallUtils.extractRecall(mergeWeight.getOrDefault("cityRov", 5.0).intValue(), param, CityRovnRecallStrategy.PUSH_FROM, setVideo, rovRecallRank);
+        //-------------------priori province rovn------------------
+        RecallUtils.extractRecall(mergeWeight.getOrDefault("prioriProvinceRov", 5.0).intValue(), param, PrioriProvinceRovnRecallStrategy.PUSH_FROM, setVideo, rovRecallRank);
+        //-------------------channel layer rovn------------------
+        RecallUtils.extractRecall(mergeWeight.getOrDefault("channelLayerRov", 5.0).intValue(), param, ChannelLayerRovnRecallStrategy.PUSH_FROM, setVideo, rovRecallRank);
+        //-------------------channel layer head rovn------------------
+        RecallUtils.extractRecall(mergeWeight.getOrDefault("channelLayerHeadRov", 5.0).intValue(), param, ChannelLayerHeadRovnRecallStrategy.PUSH_FROM, setVideo, rovRecallRank);
 
         //-------------------排-------------------
         //-------------------序-------------------
@@ -80,21 +87,22 @@ public class RankStrategy4RegionMergeModelV566 extends RankStrategy4RegionMergeM
         List<String> vids = CommonCollectionUtils.toListDistinct(rovRecallRank, v -> String.valueOf(v.getVideoId()));
         String headVid = String.valueOf(param.getHeadVid());
         Map<String, Map<String, Map<String, String>>> videoBaseInfoMap = featureService.getVideoBaseInfo(headVid, vids);
-        FeatureService.Feature feature = featureService.getFeatureV3(param, videoBaseInfoMap, vids);
+        Map<String, String> headVideoInfo = videoBaseInfoMap.getOrDefault(headVid, new HashMap<>()).getOrDefault("alg_vid_feature_basic_info", new HashMap<>());
+        FeatureService.Feature feature = featureService.getFeatureV4(param, headVideoInfo, videoBaseInfoMap, vids);
         Map<String, Map<String, String>> featureOriginUser = feature.getUserFeature();
         Map<String, Map<String, Map<String, String>>> featureOriginVideo = feature.getVideoFeature();
-        Map<String, String> headVideoInfo = videoBaseInfoMap.getOrDefault(headVid, new HashMap<>()).getOrDefault("alg_vid_feature_basic_info", new HashMap<>());
 
         // 2. 用户信息预处理
         Map<String, Map<String, String[]>> newC7Map = FeatureV6.parseUCFScore(featureOriginUser.getOrDefault("alg_mid_feature_sharecf", new HashMap<>()));
         Map<String, Map<String, String[]>> newC8Map = FeatureV6.parseUCFScore(featureOriginUser.getOrDefault("alg_mid_feature_returncf", new HashMap<>()));
         UserShareReturnProfile userProfile = parseUserProfile(featureOriginUser);
         Map<String, Map<String, String>> userBehaviorVideoMap = getUserBehaviorVideoMap(userProfile);
+        Map<String, String> creativeInfo = param.getCreativeInfoFeature();
 
         // 3. 特征处理
         List<RankItem> rankItems = CommonCollectionUtils.toList(rovRecallRank, RankItem::new);
-        Map<String, Float> userFeatureMap = getUserFeature(currentMs, param, headVideoInfo, userProfile, featureOriginUser);
-        batchGetVideoFeature(currentMs, userProfile, headVideoInfo, videoBaseInfoMap,
+        Map<String, Float> userFeatureMap = getUserFeature(currentMs, param, creativeInfo, headVideoInfo, userProfile, featureOriginUser);
+        batchGetVideoFeature(currentMs, userProfile, creativeInfo, headVideoInfo, videoBaseInfoMap,
                 newC7Map, newC8Map, featureOriginUser, userBehaviorVideoMap, featureOriginVideo, rankItems);
 
         // 4. 排序模型计算
@@ -118,6 +126,7 @@ public class RankStrategy4RegionMergeModelV566 extends RankStrategy4RegionMergeM
             cate2Coefficient.putAll(simCateScore);
         }
         Double cate2CoefficientDenominator = mergeWeight.getOrDefault("cate2CoefficientDenominator", 1d);
+        Map<String, String> regionMap = getUserRegion(param);
 
         List<Video> result = new ArrayList<>();
         for (RankItem item : items) {
@@ -166,6 +175,12 @@ public class RankStrategy4RegionMergeModelV566 extends RankStrategy4RegionMergeM
             if (null != rtFeatureDumpsMap && !rtFeatureDumpsMap.isEmpty()) {
                 video.getMetaFeatureMap().put("rt", rtFeatureDumpsMap);
             }
+            if (MapUtils.isNotEmpty(param.getCreativeInfoFeature())) {
+                video.getMetaFeatureMap().put("creativeInfo", param.getCreativeInfoFeature());
+            }
+            if (MapUtils.isNotEmpty(regionMap)) {
+                video.getMetaFeatureMap().put("region", regionMap);
+            }
             result.add(video);
         }
         ExtractVideoMergeCate.addOtherParam(result, videoBaseInfoMap);
@@ -220,12 +235,13 @@ public class RankStrategy4RegionMergeModelV566 extends RankStrategy4RegionMergeM
         return historyVideoMap;
     }
 
-    private Map<String, Float> getUserFeature(long currentMs, RankParam param, Map<String, String> headInfo, UserShareReturnProfile userProfile, Map<String, Map<String, String>> userOriginInfo) {
+    private Map<String, Float> getUserFeature(long currentMs, RankParam param, Map<String, String> creativeInfo, Map<String, String> headInfo, UserShareReturnProfile userProfile, Map<String, Map<String, String>> userOriginInfo) {
         Map<String, Double> featMap = new HashMap<>();
         // context feature
         String appType = String.valueOf(param.getAppType());
         String hotSceneType = String.valueOf(param.getHotSceneType());
         FeatureV6.getContextFeature(currentMs, appType, hotSceneType, featMap);
+        FeatureV6.getCreativeBaseFeature("e1", creativeInfo, featMap);
 
         // head video feature
         FeatureV6.getVideoBaseFeature("h", currentMs, headInfo, featMap);
@@ -240,6 +256,7 @@ public class RankStrategy4RegionMergeModelV566 extends RankStrategy4RegionMergeM
 
     private Map<String, Float> getVideoFeature(long currentMs, String vid,
                                                UserShareReturnProfile userProfile,
+                                               Map<String, String> creativeInfo,
                                                Map<String, String> headInfo, Map<String, String> rankInfo,
                                                Map<String, Map<String, String[]>> c7Map,
                                                Map<String, Map<String, String[]>> c8Map,
@@ -259,6 +276,7 @@ public class RankStrategy4RegionMergeModelV566 extends RankStrategy4RegionMergeM
 
         // head&rank cross feature
         FeatureV6.getHeadRankVideoCrossFeature(headInfo, rankInfo, featMap);
+        FeatureV6.getCreativeCrossFeature("e1", creativeInfo, rankInfo, featMap);
 
         // user profile & rank cross
         FeatureV6.getProfileVideoCrossFeature(currentMs, userProfile, rankInfo, historyVideoMap, featMap);
@@ -268,6 +286,7 @@ public class RankStrategy4RegionMergeModelV566 extends RankStrategy4RegionMergeM
 
     private void batchGetVideoFeature(long currentMs,
                                       UserShareReturnProfile userProfile,
+                                      Map<String, String> creativeInfo,
                                       Map<String, String> headInfo,
                                       Map<String, Map<String, Map<String, String>>> videoBaseInfoMap,
                                       Map<String, Map<String, String[]>> c7Map,
@@ -282,7 +301,7 @@ public class RankStrategy4RegionMergeModelV566 extends RankStrategy4RegionMergeM
                 String vid = item.getVideoId() + "";
                 Map<String, String> rankInfo = videoBaseInfoMap.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_basic_info", new HashMap<>());
                 Future<Integer> future = ThreadPoolFactory.defaultPool().submit(() -> {
-                    item.featureMap = getVideoFeature(currentMs, vid, userProfile, headInfo, rankInfo, c7Map, c8Map, userOriginInfo, historyVideoMap, videoOriginInfo);
+                    item.featureMap = getVideoFeature(currentMs, vid, userProfile, creativeInfo, headInfo, rankInfo, c7Map, c8Map, userOriginInfo, historyVideoMap, videoOriginInfo);
                     item.norFeatureMap = item.featureMap;
                     return 1;
                 });

+ 37 - 2
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/tansform/FeatureV6.java

@@ -6,6 +6,7 @@ import com.tzld.piaoquan.recommend.server.service.rank.bo.VideoAttrSRBO;
 import com.tzld.piaoquan.recommend.server.service.rank.extractor.ExtractorUtils;
 import com.tzld.piaoquan.recommend.server.util.FeatureUtils;
 import com.tzld.piaoquan.recommend.server.util.SimilarityUtils;
+import com.tzld.piaoquan.recommend.similarity.word2vec.Segment;
 
 import java.util.*;
 
@@ -20,7 +21,7 @@ public class FeatureV6 {
     private static final List<String> b1Periods = Arrays.asList("1h", "3h", "6h", "24h", "72h", "168h");
     private static final List<String> b2Periods = Arrays.asList("1h", "3h", "6h", "24h");
     private static final List<String> b3Periods = Arrays.asList("1h", "3h", "6h", "24h", "72h");
-    private static final List<String> b4Periods = Arrays.asList("1h", "3h", "6h", "12h");
+    private static final List<String> b4Periods = Arrays.asList("1h", "3h", "6h", "12h", "24h", "72h");
     private static final List<String> b5Periods = Arrays.asList("1h", "3h", "6h", "12h", "24h", "72h");
     private static final List<String> b6Periods = Arrays.asList("1h", "24h");
     private static final List<String> b7Periods = Arrays.asList("1h", "3h", "6h", "12h", "24h", "72h");
@@ -28,11 +29,14 @@ public class FeatureV6 {
     private static final List<String> b9Periods = Arrays.asList("1h", "3h", "24h");
     private static final List<String> b10Periods = Arrays.asList("1h", "12h");
     private static final List<String> b11Periods = Arrays.asList("1h", "12h");
-    private static final List<String> b13Periods = Arrays.asList("1h", "3h", "24h", "72h");
+    private static final List<String> b13Periods = Arrays.asList("1h", "3h", "6h", "12h", "24h", "72h");
+    private static final List<String> b14Periods = Arrays.asList("1h", "2h", "3h", "6h", "12h");
+    private static final List<String> b15Periods = Arrays.asList("1h", "2h", "3h", "6h", "12h");
     private static final List<String> videoCateAttrs = Arrays.asList(FeatureUtils.cate1Attr, FeatureUtils.cate2Attr, FeatureUtils.festive1Attr,
             FeatureUtils.channelAttr, FeatureUtils.sourceAttr, FeatureUtils.uidAttr, FeatureUtils.mergeCate1Attr, FeatureUtils.mergeCate2Attr);
     private static final List<String> videoSimAttrs = Arrays.asList("title", "cate2", "cate2_list", "keywords");
     private static final List<String> reqVideoSimAttrs = Arrays.asList("title", "keywords", "merge_first_level_cate", "merge_second_level_cate");
+    private static final List<String> creativeSimAttrs = Arrays.asList("title");
     private static final List<String> hVideoSimAttrs = Arrays.asList("title");
     private static final List<String> cfList = Arrays.asList("share", "return");
     private static final List<String> userAttrList = Arrays.asList("province", "city", "model", "brand", "system", "user_channel", "user_level");
@@ -167,6 +171,8 @@ public class FeatureV6 {
         oneTypeStatFeature("b10", "return_n_uv", b10Periods, videoOriginInfo.getOrDefault(vid, new HashMap<>()).get("alg_channel_recommend_exp_feature_20250212"), featMap);
         oneTypeStatFeature("b11", "return_n_uv", b11Periods, videoOriginInfo.getOrDefault(vid, new HashMap<>()).get("alg_festive_recommend_exp_feature_20250212"), featMap);
         oneTypeStatFeature("b13", "return_n_uv", b13Periods, videoOriginInfo.getOrDefault(vid, new HashMap<>()).get("alg_video_unionid_recommend_exp_feature_20250212"), featMap);
+        oneTypeStatFeature("b14", b14Periods, videoOriginInfo.getOrDefault(vid, new HashMap<>()).get("alg_recsys_feature_video_recommend_channel_layer"), featMap);
+        oneTypeStatFeature("b15", b15Periods, videoOriginInfo.getOrDefault(vid, new HashMap<>()).get("alg_recsys_feature_video_recommend_channel_layer_head"), featMap);
 
         // head video cf
         headVideoCFD1Feature("d1", videoOriginInfo.getOrDefault(vid, new HashMap<>()).get("scene_type_vid_cf_feature_20250212"), featMap);
@@ -216,6 +222,35 @@ public class FeatureV6 {
         getTwoVideoCrossFeature("sim", reqVideoSimAttrs, headInfo, rankInfo, featMap);
     }
 
+    public static void getCreativeBaseFeature(String prefix, Map<String, String> creativeInfo, Map<String, Double> featMap) {
+        if (null == creativeInfo || creativeInfo.isEmpty()) {
+            return;
+        }
+        if (creativeInfo.containsKey("ghId")) {
+            String ghId = creativeInfo.get("ghId");
+            if (null != ghId && !ghId.isEmpty()) {
+                String key = String.format("%s@gid@%s", prefix, ghId);
+                featMap.put(key, 1.0);
+            }
+        }
+        if (creativeInfo.containsKey("name")) {
+            String name = creativeInfo.get("name");
+            if (null != name && !name.isEmpty()) {
+                List<String> words = Segment.getWords(name);
+                for (String word : words) {
+                    if (null != word && word.length() > 1) {
+                        String key = String.format("%s@name@%s", prefix, word);
+                        featMap.put(key, 1.0);
+                    }
+                }
+            }
+        }
+    }
+
+    public static void getCreativeCrossFeature(String prefix, Map<String, String> creativeInfo, Map<String, String> rankInfo, Map<String, Double> featMap) {
+        getTwoVideoCrossFeature(prefix, creativeSimAttrs, creativeInfo, rankInfo, featMap);
+    }
+
     public static void getProfileVideoCrossFeature(long currentMs, UserShareReturnProfile profile, Map<String, String> rankVideo, Map<String, Map<String, String>> hVideoMap, Map<String, Double> featMap) {
         if (null == profile) {
             return;

+ 4 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/RecallService.java

@@ -123,6 +123,10 @@ public class RecallService implements ApplicationContextAware {
         if (CollectionUtils.isNotEmpty(abExpCodes) && abExpCodes.contains("568")) {
             strategies.add(strategyMap.get(PremiumROVRecallStrategy.class.getSimpleName()));
         }
+        if (CollectionUtils.isNotEmpty(abExpCodes) && abExpCodes.contains("566")) {
+            strategies.add(strategyMap.get(ChannelLayerRovnRecallStrategy.class.getSimpleName()));
+            strategies.add(strategyMap.get(ChannelLayerHeadRovnRecallStrategy.class.getSimpleName()));
+        }
 
         // 命中用户黑名单不走流量池
         if (!param.isRiskUser()) {

+ 119 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/strategy/ChannelLayerHeadRovnRecallStrategy.java

@@ -0,0 +1,119 @@
+package com.tzld.piaoquan.recommend.server.service.recall.strategy;
+
+import com.tzld.piaoquan.recommend.server.model.Video;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterParam;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterResult;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterService;
+import com.tzld.piaoquan.recommend.server.service.recall.FilterParamFactory;
+import com.tzld.piaoquan.recommend.server.service.recall.RecallParam;
+import com.tzld.piaoquan.recommend.server.service.recall.RecallStrategy;
+import com.tzld.piaoquan.recommend.server.util.FeatureUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.MutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+public class ChannelLayerHeadRovnRecallStrategy implements RecallStrategy {
+    private final String CLASS_NAME = this.getClass().getSimpleName();
+    @Autowired
+    private FilterService filterService;
+    @Autowired
+    @Qualifier("redisTemplate")
+    public RedisTemplate<String, String> redisTemplate;
+
+    public static final String PUSH_FROM = "channel_layer_head_rovn";
+    public static final String redisKeyPrefix = "channel_layer_head_rovn_recall";
+
+    @Override
+    public String pushFrom() {
+        return PUSH_FROM;
+    }
+
+    @Override
+    public List<Video> recall(RecallParam param) {
+        List<Video> videosResult = new ArrayList<>();
+        try {
+            String userChannel = param.getChannelName();
+            if (null == userChannel || userChannel.isEmpty()) {
+                return videosResult;
+            }
+            String userLayer = "非0层";
+            if (FeatureUtils.firstLevel(param.getUserShareDepth())) {
+                userLayer = "0层";
+            }
+            Map<String, String> headInfo = param.getHeadInfo();
+            if (MapUtils.isEmpty(headInfo)) {
+                return videosResult;
+            }
+            String unionid = headInfo.getOrDefault("title_time_w_h_unionid", "");
+            if (unionid.isEmpty()) {
+                return videosResult;
+            }
+            String redisKey = String.format("%s:%s:%s:%s", redisKeyPrefix, userChannel, userLayer, unionid);
+            String redisValue = redisTemplate.opsForValue().get(redisKey);
+            if (null == redisValue || redisValue.isEmpty()) {
+                return videosResult;
+            }
+            Pair<List<Long>, Map<Long, Double>> pair = parsePair(redisValue, param.getVideoId(), 50);
+            fillVideoResult(param, pair, videosResult);
+        } catch (Exception e) {
+            log.error("recall is wrong in {}, error={}", CLASS_NAME, e);
+        }
+        return videosResult;
+    }
+
+    private Pair<List<Long>, Map<Long, Double>> parsePair(String data, long headVid, int size) {
+        List<Long> idsList = new ArrayList<>();
+        Map<Long, Double> scoresMap = new HashMap<>();
+        if (!StringUtils.isBlank(data)) {
+            String[] cells = data.split("\t");
+            if (2 == cells.length) {
+                List<Long> ids = Arrays.stream(cells[0].split(",")).map(Long::valueOf).collect(Collectors.toList());
+                List<Double> scores = Arrays.stream(cells[1].split(",")).map(Double::valueOf).collect(Collectors.toList());
+                if (!ids.isEmpty() && ids.size() == scores.size()) {
+                    int minSize = Math.min(size, ids.size());
+                    for (int i = 0; i < minSize; ++i) {
+                        long id = ids.get(i);
+                        double score = scores.get(i);
+                        if (headVid != id && !scoresMap.containsKey(id)) {
+                            idsList.add(id);
+                            scoresMap.put(id, score);
+                        }
+                    }
+                }
+            }
+        }
+        return new MutablePair<>(idsList, scoresMap);
+    }
+
+    private void fillVideoResult(RecallParam param, Pair<List<Long>, Map<Long, Double>> pair, List<Video> videosResult) {
+        if (null != pair) {
+            List<Long> ids = pair.getLeft();
+            Map<Long, Double> scoresMap = pair.getRight();
+            if (null != ids && null != scoresMap && !ids.isEmpty()) {
+                FilterParam filterParam = FilterParamFactory.create(param, ids);
+                FilterResult filterResult = filterService.filter(filterParam);
+                if (null != filterResult && CollectionUtils.isNotEmpty(filterResult.getVideoIds())) {
+                    filterResult.getVideoIds().forEach(vid -> {
+                        Video video = new Video();
+                        video.setVideoId(vid);
+                        video.setRovScore(scoresMap.getOrDefault(vid, 0D));
+                        video.setPushFrom(pushFrom());
+                        videosResult.add(video);
+                    });
+                }
+            }
+        }
+    }
+}

+ 110 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/strategy/ChannelLayerRovnRecallStrategy.java

@@ -0,0 +1,110 @@
+package com.tzld.piaoquan.recommend.server.service.recall.strategy;
+
+import com.tzld.piaoquan.recommend.server.model.Video;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterParam;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterResult;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterService;
+import com.tzld.piaoquan.recommend.server.service.recall.FilterParamFactory;
+import com.tzld.piaoquan.recommend.server.service.recall.RecallParam;
+import com.tzld.piaoquan.recommend.server.service.recall.RecallStrategy;
+import com.tzld.piaoquan.recommend.server.util.FeatureUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.MutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+public class ChannelLayerRovnRecallStrategy implements RecallStrategy {
+    private final String CLASS_NAME = this.getClass().getSimpleName();
+    @Autowired
+    private FilterService filterService;
+    @Autowired
+    @Qualifier("redisTemplate")
+    public RedisTemplate<String, String> redisTemplate;
+
+    public static final String PUSH_FROM = "channel_layer_rovn";
+    public static final String redisKeyPrefix = "channel_layer_rovn_recall";
+
+    @Override
+    public String pushFrom() {
+        return PUSH_FROM;
+    }
+
+    @Override
+    public List<Video> recall(RecallParam param) {
+        List<Video> videosResult = new ArrayList<>();
+        try {
+            String userChannel = param.getChannelName();
+            if (null == userChannel || userChannel.isEmpty()) {
+                return videosResult;
+            }
+            String userLayer = "非0层";
+            if (FeatureUtils.firstLevel(param.getUserShareDepth())) {
+                userLayer = "0层";
+            }
+            String redisKey = String.format("%s:%s:%s", redisKeyPrefix, userChannel, userLayer);
+            String redisValue = redisTemplate.opsForValue().get(redisKey);
+            if (null == redisValue || redisValue.isEmpty()) {
+                return videosResult;
+            }
+            Pair<List<Long>, Map<Long, Double>> pair = parsePair(redisValue, param.getVideoId(), 50);
+            fillVideoResult(param, pair, videosResult);
+        } catch (Exception e) {
+            log.error("recall is wrong in {}, error={}", CLASS_NAME, e);
+        }
+        return videosResult;
+    }
+
+    private Pair<List<Long>, Map<Long, Double>> parsePair(String data, long headVid, int size) {
+        List<Long> idsList = new ArrayList<>();
+        Map<Long, Double> scoresMap = new HashMap<>();
+        if (!StringUtils.isBlank(data)) {
+            String[] cells = data.split("\t");
+            if (2 == cells.length) {
+                List<Long> ids = Arrays.stream(cells[0].split(",")).map(Long::valueOf).collect(Collectors.toList());
+                List<Double> scores = Arrays.stream(cells[1].split(",")).map(Double::valueOf).collect(Collectors.toList());
+                if (!ids.isEmpty() && ids.size() == scores.size()) {
+                    int minSize = Math.min(size, ids.size());
+                    for (int i = 0; i < minSize; ++i) {
+                        long id = ids.get(i);
+                        double score = scores.get(i);
+                        if (headVid != id && !scoresMap.containsKey(id)) {
+                            idsList.add(id);
+                            scoresMap.put(id, score);
+                        }
+                    }
+                }
+            }
+        }
+        return new MutablePair<>(idsList, scoresMap);
+    }
+
+    private void fillVideoResult(RecallParam param, Pair<List<Long>, Map<Long, Double>> pair, List<Video> videosResult) {
+        if (null != pair) {
+            List<Long> ids = pair.getLeft();
+            Map<Long, Double> scoresMap = pair.getRight();
+            if (null != ids && null != scoresMap && !ids.isEmpty()) {
+                FilterParam filterParam = FilterParamFactory.create(param, ids);
+                FilterResult filterResult = filterService.filter(filterParam);
+                if (null != filterResult && CollectionUtils.isNotEmpty(filterResult.getVideoIds())) {
+                    filterResult.getVideoIds().forEach(vid -> {
+                        Video video = new Video();
+                        video.setVideoId(vid);
+                        video.setRovScore(scoresMap.getOrDefault(vid, 0D));
+                        video.setPushFrom(pushFrom());
+                        videosResult.add(video);
+                    });
+                }
+            }
+        }
+    }
+}