Browse Source

feat:添加str+校准

zhaohaipeng 3 weeks ago
parent
commit
3a8f405eb8

+ 43 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelBasic.java

@@ -1,5 +1,7 @@
 package com.tzld.piaoquan.recommend.server.service.rank.strategy;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
 import com.google.common.reflect.TypeToken;
 import com.tzld.piaoquan.recommend.server.common.base.RankItem;
@@ -18,6 +20,7 @@ import com.tzld.piaoquan.recommend.server.util.JSONUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.RandomUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
@@ -48,6 +51,11 @@ public abstract class RankStrategy4RegionMergeModelBasic extends RankService {
     @ApolloJsonValue("${RankReduceByFestiveConfig:{}}")
     private Map<String, String> rankReduceByFestiveConfig = new HashMap<>();
 
+    @ApolloJsonValue("${str.plus.calibration.merge.cate2:[]}")
+    private Set<String> strPlusCalibrationMergeCate2;
+
+    public static final String STR_PLUS_CALIBRATION_ATTRIBUTE_KEY_PREFIX = "alg_rec_model_calibration_str:";
+
     String CLASS_NAME = this.getClass().getSimpleName();
 
     public void duplicate(Set<Long> setVideo, List<Video> videos) {
@@ -399,6 +407,41 @@ public abstract class RankStrategy4RegionMergeModelBasic extends RankService {
         return regionMap;
     }
 
+    /**
+     * 计算MergeCate2的str+校准系数
+     */
+    protected double calcStrPlusCalibrationCoefficientByMergeCate2(String mergeCate2) {
+        if (CollectionUtils.isEmpty(strPlusCalibrationMergeCate2) || StringUtils.isEmpty(mergeCate2)) {
+            return 1d;
+        }
+
+        if (!strPlusCalibrationMergeCate2.contains(mergeCate2)) {
+            return 1d;
+        }
+
+        try {
+
+            String key = STR_PLUS_CALIBRATION_ATTRIBUTE_KEY_PREFIX + mergeCate2;
+            String value = redisTemplate.opsForValue().get(key);
+            if (StringUtils.isEmpty(value)) {
+                return 1d;
+            }
+
+            JSONObject valueJson = JSON.parseObject(value);
+            double rStrPlus = valueJson.getDoubleValue("r_str_plus");
+            double pStrPlus = valueJson.getDoubleValue("p_str_plus");
+            double coefficient = rStrPlus / pStrPlus;
+            if (coefficient <= 0d) {
+                return 1d;
+            }
+            return coefficient;
+        } catch (Exception e) {
+            log.error("calcStrPlusCalibrationCoefficientByMergeCate2 error mergeCate2: {} \n", mergeCate2, e);
+        }
+
+        return 1d;
+    }
+
     private boolean isInsertDouHotFlowPoolVideo() {
         double rand = RandomUtils.nextDouble(0, 1);
         return rand <= newFlowPoolSelectRate;

+ 312 - 202
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelV565.java

@@ -1,16 +1,20 @@
 package com.tzld.piaoquan.recommend.server.service.rank.strategy;
 
+import com.alibaba.fastjson.JSON;
 import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
+import com.tzld.piaoquan.recommend.server.common.ThreadPoolFactory;
 import com.tzld.piaoquan.recommend.server.common.base.RankItem;
+import com.tzld.piaoquan.recommend.server.model.MachineInfo;
 import com.tzld.piaoquan.recommend.server.model.Video;
 import com.tzld.piaoquan.recommend.server.service.FeatureService;
 import com.tzld.piaoquan.recommend.server.service.rank.RankParam;
+import com.tzld.piaoquan.recommend.server.service.rank.bo.UserSRBO;
+import com.tzld.piaoquan.recommend.server.service.rank.bo.UserShareReturnProfile;
 import com.tzld.piaoquan.recommend.server.service.rank.extractor.ExtractVideoMergeCate;
+import com.tzld.piaoquan.recommend.server.service.rank.tansform.FeatureV6;
 import com.tzld.piaoquan.recommend.server.service.recall.strategy.*;
 import com.tzld.piaoquan.recommend.server.service.score.ScorerUtils;
-import com.tzld.piaoquan.recommend.server.util.CommonCollectionUtils;
-import com.tzld.piaoquan.recommend.server.util.ExtractFeature20250218;
-import com.tzld.piaoquan.recommend.server.util.FeatureBucketUtils;
+import com.tzld.piaoquan.recommend.server.util.*;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.MapUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -18,6 +22,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.*;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 @Service
@@ -25,234 +31,137 @@ import java.util.stream.Collectors;
 public class RankStrategy4RegionMergeModelV565 extends RankStrategy4RegionMergeModelBasic {
     @ApolloJsonValue("${rank.score.merge.weightv565:}")
     private Map<String, Double> mergeWeight;
-
     @Autowired
     private FeatureService featureService;
 
     @Override
     public List<Video> mergeAndRankRovRecall(RankParam param) {
-
-        long startTime = System.currentTimeMillis();
-
         Map<String, Double> mergeWeight = this.mergeWeight != null ? this.mergeWeight : new HashMap<>(0);
+
         //-------------------融-------------------
         //-------------------合-------------------
         //-------------------逻-------------------
         //-------------------辑-------------------
 
-        List<Video> oldRovs = new ArrayList<>();
-        oldRovs.addAll(extractAndSort(param, RegionHRecallStrategy.PUSH_FORM));
-        oldRovs.addAll(extractAndSort(param, RegionHDupRecallStrategy.PUSH_FORM));
-        oldRovs.addAll(extractAndSort(param, Region24HRecallStrategy.PUSH_FORM));
-        oldRovs.addAll(extractAndSort(param, RegionRelative24HRecallStrategy.PUSH_FORM));
-        oldRovs.addAll(extractAndSort(param, RegionRelative24HDupRecallStrategy.PUSH_FORM));
-        removeDuplicate(oldRovs);
-        int sizeReturn = param.getSize();
-        List<Video> v0 = oldRovs.size() <= sizeReturn
-                ? oldRovs
-                : oldRovs.subList(0, sizeReturn);
+        long currentMs = System.currentTimeMillis();
         Set<Long> setVideo = new HashSet<>();
-        this.duplicate(setVideo, v0);
-        setVideo.addAll(v0.stream().map(Video::getVideoId).collect(Collectors.toSet()));
-        List<Video> rovRecallRank = new ArrayList<>(v0);
+        setVideo.add(param.getHeadVid());
+        List<Video> rovRecallRank = new ArrayList<>();
+        // -------------------5路特殊旧召回------------------
+        RecallUtils.extractOldSpecialRecall(param, setVideo, rovRecallRank);
         //-------------------return相似召回------------------
-        List<Video> v6 = extractAndSort(param, ReturnVideoRecallStrategy.PUSH_FORM);
-        v6 = v6.stream().filter(r -> !setVideo.contains(r.getVideoId())).collect(Collectors.toList());
-        v6 = v6.subList(0, Math.min(mergeWeight.getOrDefault("v6", 5.0).intValue(), v6.size()));
-        rovRecallRank.addAll(v6);
-        setVideo.addAll(v6.stream().map(Video::getVideoId).collect(Collectors.toSet()));
+        RecallUtils.extractRecall(mergeWeight.getOrDefault("v6", 5.0).intValue(), param, ReturnVideoRecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
         //-------------------新地域召回------------------
-        List<Video> v1 = extractAndSort(param, RegionRealtimeRecallStrategyV1.PUSH_FORM);
-        v1 = v1.stream().filter(r -> !setVideo.contains(r.getVideoId())).collect(Collectors.toList());
-        v1 = v1.subList(0, Math.min(mergeWeight.getOrDefault("v1", 5.0).intValue(), v1.size()));
-        rovRecallRank.addAll(v1);
-        setVideo.addAll(v1.stream().map(Video::getVideoId).collect(Collectors.toSet()));
+        RecallUtils.extractRecall(mergeWeight.getOrDefault("v1", 5.0).intValue(), param, RegionRealtimeRecallStrategyV1.PUSH_FORM, setVideo, rovRecallRank);
         //-------------------scene cf rovn------------------
-        List<Video> sceneCFRovn = extractAndSort(param, SceneCFRovnRecallStrategy.PUSH_FORM);
-        sceneCFRovn = sceneCFRovn.stream().filter(r -> !setVideo.contains(r.getVideoId())).collect(Collectors.toList());
-        sceneCFRovn = sceneCFRovn.subList(0, Math.min(mergeWeight.getOrDefault("sceneCFRovn", 5.0).intValue(), sceneCFRovn.size()));
-        rovRecallRank.addAll(sceneCFRovn);
-        setVideo.addAll(sceneCFRovn.stream().map(Video::getVideoId).collect(Collectors.toSet()));
+        RecallUtils.extractRecall(mergeWeight.getOrDefault("sceneCFRovn", 5.0).intValue(), param, SceneCFRovnRecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
         //-------------------scene cf rosn------------------
-        List<Video> sceneCFRosn = extractAndSort(param, SceneCFRosnRecallStrategy.PUSH_FORM);
-        sceneCFRosn = sceneCFRosn.stream().filter(r -> !setVideo.contains(r.getVideoId())).collect(Collectors.toList());
-        sceneCFRosn = sceneCFRosn.subList(0, Math.min(mergeWeight.getOrDefault("sceneCFRosn", 5.0).intValue(), sceneCFRosn.size()));
-        rovRecallRank.addAll(sceneCFRosn);
-        setVideo.addAll(sceneCFRosn.stream().map(Video::getVideoId).collect(Collectors.toSet()));
-
+        RecallUtils.extractRecall(mergeWeight.getOrDefault("sceneCFRosn", 5.0).intValue(), param, SceneCFRosnRecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+        // -------------------user cate1------------------
+        RecallUtils.extractRecall(mergeWeight.getOrDefault("cate1RecallN", 5.0).intValue(), param, UserCate1RecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+        // -------------------user cate2------------------
+        RecallUtils.extractRecall(mergeWeight.getOrDefault("cate2RecallN", 5.0).intValue(), param, UserCate2RecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+        // -------------------head province cate1------------------
+        RecallUtils.extractRecall(mergeWeight.getOrDefault("headCate1RecallN", 3.0).intValue(), param, HeadProvinceCate1RecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+        // -------------------head province cate2------------------
+        RecallUtils.extractRecall(mergeWeight.getOrDefault("headCate2RecallN", 3.0).intValue(), param, HeadProvinceCate2RecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+        //-------------------head cate2 of rovn------------------
+        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);
 
         //-------------------排-------------------
         //-------------------序-------------------
         //-------------------逻-------------------
         //-------------------辑-------------------
+        Map<String, String> rtFeatureDumpsMap = dumpsRtFeature(param.getUserRTShareList());
 
-        // 1 批量获取特征  省份参数要对齐  headvid  要传递过来!
-        List<String> vids = CommonCollectionUtils.toListDistinct(rovRecallRank, v -> String.valueOf(v.getVideoId()));
-
+        // 1. 批量获取特征  省份参数要对齐  headvid  要传递过来!
         // k1:视频、k2:表、k3:特征、v:特征值
-        String provinceCn = param.getProvince().replaceAll("省$", "");
+        List<String> vids = CommonCollectionUtils.toListDistinct(rovRecallRank, v -> String.valueOf(v.getVideoId()));
         String headVid = String.valueOf(param.getHeadVid());
-        String sceneType = String.valueOf(param.getHotSceneType());
         Map<String, Map<String, Map<String, String>>> videoBaseInfoMap = featureService.getVideoBaseInfo(headVid, vids);
-        String appType = String.valueOf(param.getAppType());
-        String brand = "";
-        if (Objects.nonNull(param.getMachineInfo())) {
-            brand = param.getMachineInfo().getBrand();
-        }
-
-        long ts = System.currentTimeMillis() / 1000;
-
-        FeatureService.Feature feature = featureService.getFeatureByNewLabel(appType, sceneType, provinceCn, brand, param.getMid(), headVid, vids, videoBaseInfoMap);
+        FeatureService.Feature feature = featureService.getFeatureV3(param, 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, Double> userFeatureMapDouble = new HashMap<>();
-
-        Map<String, String> c1 = featureOriginUser.getOrDefault("mid_global_feature_20250212", new HashMap<>());
-        Map<String, String> c4 = featureOriginUser.getOrDefault("mid_u2u_friend_index_feature_20250212", new HashMap<>());
-        Map<String, String> c5 = featureOriginUser.getOrDefault("alg_mid_feature_return_tags", new HashMap<>());
-        Map<String, String> c6 = featureOriginUser.getOrDefault("alg_mid_feature_share_tags", new HashMap<>());
-        Map<String, String> c7 = featureOriginUser.getOrDefault("alg_mid_feature_sharecf", new HashMap<>());
-        Map<String, String> c8 = featureOriginUser.getOrDefault("alg_mid_feature_returncf", new HashMap<>());
-
-        ExtractFeature20250218.handleC1(c1, userFeatureMapDouble);
-        ExtractFeature20250218.handleC4(c4, userFeatureMapDouble);
-        Map<String, Map<String, String[]>> c78FeatureMap = ExtractFeature20250218.handleC7ToC8(c7, c8);
+        // 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);
 
+        // 3. 特征处理
         List<RankItem> rankItems = CommonCollectionUtils.toList(rovRecallRank, RankItem::new);
-        for (RankItem item : rankItems) {
-
-            String vidStr = String.valueOf(item.getVideoId());
-
-            Map<String, Double> featureMap = new HashMap<>();
-            Map<String, String> v1Feature = videoBaseInfoMap.getOrDefault(vidStr, new HashMap<>()).getOrDefault("alg_vid_feature_basic_info", new HashMap<>());
-            Map<String, Map<String, String>> videoFeatureMap = featureOriginVideo.getOrDefault(vidStr, new HashMap<>());
-            Map<String, String> b1 = videoFeatureMap.getOrDefault("alg_vid_global_feature_20250212", new HashMap<>());
-            Map<String, String> b2 = videoFeatureMap.getOrDefault("alg_vid_recommend_exp_feature_20250212", new HashMap<>());
-            Map<String, String> b3 = videoFeatureMap.getOrDefault("alg_vid_recommend_flowpool_exp_feature_20250212", new HashMap<>());
-            Map<String, String> b4 = videoFeatureMap.getOrDefault("alg_vid_apptype_recommend_exp_feature_20250212", new HashMap<>());
-            Map<String, String> b5 = videoFeatureMap.getOrDefault("alg_vid_province_recommend_exp_feature_20250212", new HashMap<>());
-            Map<String, String> b6 = videoFeatureMap.getOrDefault("alg_vid_brand_recommend_exp_feature_20250212", new HashMap<>());
-            Map<String, String> b7 = videoFeatureMap.getOrDefault("alg_vid_hotsencetype_recommend_exp_feature_20250212", new HashMap<>());
-            Map<String, String> b8 = videoFeatureMap.getOrDefault("alg_merge_cate1_recommend_exp_feature_20250212", new HashMap<>());
-            Map<String, String> b9 = videoFeatureMap.getOrDefault("alg_merge_cate2_recommend_exp_feature_20250212", new HashMap<>());
-            Map<String, String> b10 = videoFeatureMap.getOrDefault("alg_channel_recommend_exp_feature_20250212", new HashMap<>());
-            Map<String, String> b11 = videoFeatureMap.getOrDefault("alg_festive_recommend_exp_feature_20250212", new HashMap<>());
-            Map<String, String> b12 = videoFeatureMap.getOrDefault("alg_vid_long_period_recommend_exp_feature_20250212", new HashMap<>());
-            Map<String, String> b13 = videoFeatureMap.getOrDefault("alg_video_unionid_recommend_exp_feature_20250212", new HashMap<>());
-
-            Map<String, String> c2 = videoFeatureMap.getOrDefault("mid_merge_cate1_feature_20250212", new HashMap<>());
-            Map<String, String> c3 = videoFeatureMap.getOrDefault("mid_merge_cate2_feature_20250212", new HashMap<>());
-
-            Map<String, String> d1 = videoFeatureMap.getOrDefault("scene_type_vid_cf_feature_20250212", new HashMap<>());
-            Map<String, String> d2 = videoFeatureMap.getOrDefault("vid_click_cf_feature_20250212", new HashMap<>());
-            Map<String, String> d3 = videoFeatureMap.getOrDefault("alg_recsys_feature_cf_i2i_v2", new HashMap<>());
-
-            Map<String, Map<String, String>> b2ToB11AndB13Map = new HashMap<>();
-            b2ToB11AndB13Map.put("b2", b2);
-            b2ToB11AndB13Map.put("b3", b3);
-            b2ToB11AndB13Map.put("b4", b4);
-            b2ToB11AndB13Map.put("b5", b5);
-            b2ToB11AndB13Map.put("b6", b6);
-            b2ToB11AndB13Map.put("b7", b7);
-            b2ToB11AndB13Map.put("b8", b8);
-            b2ToB11AndB13Map.put("b9", b9);
-            b2ToB11AndB13Map.put("b10", b10);
-            b2ToB11AndB13Map.put("b11", b11);
-            b2ToB11AndB13Map.put("b13", b13);
-
-            ExtractFeature20250218.handleB1(b1, featureMap);
-            ExtractFeature20250218.handleB12(b12, featureMap);
-            ExtractFeature20250218.handleB2ToB11AndB13(b2ToB11AndB13Map, featureMap);
-            ExtractFeature20250218.handleC2ToC3(c2, c3, featureMap);
-            ExtractFeature20250218.useC7ToC8(c78FeatureMap, vidStr, featureMap);
-            ExtractFeature20250218.handleC5ToC6(c5, c6, v1Feature, featureMap);
-            ExtractFeature20250218.handleD1(d1, featureMap);
-            ExtractFeature20250218.handleD2(d2, featureMap);
-            ExtractFeature20250218.handleD3(d3, featureMap);
-            ExtractFeature20250218.handleVideoBasicFeature(v1Feature, ts, featureMap);
-            ExtractFeature20250218.handleVideoSimilarity(v1Feature, headVideoInfo, featureMap);
-
-            item.featureMapDouble = featureMap;
-        }
-
-        // 3 连续值特征分桶
-        Map<String, Float> userFeatureMap = FeatureBucketUtils.bucketFeatureV2("20250218_bucket_322.txt", userFeatureMapDouble);
-        for (RankItem item : rankItems) {
-            Map<String, Double> featureMapDouble = item.featureMapDouble;
-            item.featureMap = FeatureBucketUtils.bucketFeatureV2("20250218_bucket_322.txt", featureMapDouble);
-        }
+        Map<String, Float> userFeatureMap = getUserFeature(currentMs, param, headVideoInfo, userProfile, featureOriginUser);
+        batchGetVideoFeature(currentMs, userProfile, headVideoInfo, videoBaseInfoMap,
+                newC7Map, newC8Map, featureOriginUser, userBehaviorVideoMap, featureOriginVideo, rankItems);
 
-
-        // 4.1 排序模型计算 - str
+        // 4. 排序模型计算
         Map<String, Float> sceneFeatureMap = new HashMap<>(0);
-        List<RankItem> items = ScorerUtils.getScorerPipeline("feeds_score_config_xgb_str_20250228.conf").scoring(sceneFeatureMap, userFeatureMap, rankItems);
-        // 4.2 排序模型计算 - ros
-        this.addRosScore(rankItems, userFeatureMapDouble, sceneFeatureMap);
-
-        // 5 排序公式特征
-        double xgbRovNegRate = mergeWeight.getOrDefault("xgbRovNegRate", 0.05);
-
-        double calcVorMode = mergeWeight.getOrDefault("calcVorMode", 3d);
-        double calcRosMode = mergeWeight.getOrDefault("calcRosMode", 0d);
-        double calcStrMode = mergeWeight.getOrDefault("calcStrMode", 3d);
-
-
-        double rosAdd = mergeWeight.getOrDefault("ros_add", 0d);
-        double vorAdd = mergeWeight.getOrDefault("vor_add", 0d);
+        List<RankItem> items = ScorerUtils.getScorerPipeline("feeds_score_config_fm_xgb_20250317.conf").scoring(sceneFeatureMap, userFeatureMap, userFeatureMap, rankItems);
+
+        // 5. 排序公式特征
+        double xgbRovNegRate = mergeWeight.getOrDefault("xgbRovNegRate", 0.059);
+        double xgbNorPowerWeight = mergeWeight.getOrDefault("xgbNorPowerWeight", 1.22);
+        double xgbNorPowerExp = mergeWeight.getOrDefault("xgbNorPowerExp", 1.15);
+        Map<String, Map<String, String>> vid2MapFeature = this.getVideoRedisFeature(vids, "redis:vid_hasreturn_vor:");
+
+        // 获取权重
+        Map<String, Double> cate2Coefficient = new HashMap<>();
+        double cate2CoefficientFunc = mergeWeight.getOrDefault("cate2CoefficientFunc", 0d);
+        if (cate2CoefficientFunc == 1d) {
+            String headVidStr = String.valueOf(param.getHeadVid());
+            String mergeCate2 = this.findVideoMergeCate2(videoBaseInfoMap, headVidStr);
+            Double length = mergeWeight.getOrDefault("cate2CoefficientLength", 10000d);
+            Map<String, Double> simCateScore = this.findSimCateScore(mergeCate2, length.intValue());
+            cate2Coefficient.putAll(simCateScore);
+        }
+        Double cate2CoefficientDenominator = mergeWeight.getOrDefault("cate2CoefficientDenominator", 1d);
+        Map<String, String> regionMap = getUserRegion(param);
 
-        Map<String, Map<String, String>> vid2MapFeature = this.getVideoRedisFeature(vids, "redis:vid_hasreturn_vor_4share:");
         List<Video> result = new ArrayList<>();
         for (RankItem item : items) {
+            String vidMergeCate2 = this.findVideoMergeCate2(videoBaseInfoMap, String.valueOf(item.getVideoId()));
+
+            double strPlusCalibrationCoefficient = this.calcStrPlusCalibrationCoefficientByMergeCate2(vidMergeCate2);
+
             double score;
             double fmRovOrigin = item.getScoreRov();
             item.getScoresMap().put("fmRovOrigin", fmRovOrigin);
-            double fmRov = restoreScore(fmRovOrigin, xgbRovNegRate);
-            fmRov = this.handleStr(fmRov, calcStrMode, item, mergeWeight);
+            double fmRovCoefficientBefore = restoreScore(fmRovOrigin, xgbRovNegRate);
+            item.getScoresMap().put("fmRovCoefficientBefore", fmRovCoefficientBefore);
 
+            double fmRov = fmRovCoefficientBefore * strPlusCalibrationCoefficient;
             item.getScoresMap().put("fmRov", fmRov);
-            item.getScoresMap().put("xgbRovNegRate", xgbRovNegRate);
-            item.getScoresMap().put("calcStrMode", calcStrMode);
-
-            Map<String, String> vidFeatureMap = vid2MapFeature.getOrDefault(String.valueOf(item.getVideoId()), new HashMap<>());
-
-
-            double originScoreRos = item.getScoreRos();
-            double ros = this.handleRos(originScoreRos, calcRosMode, item, mergeWeight);
-
-            item.getScoresMap().put("RosXGBScore", originScoreRos);
-            item.getScoresMap().put("hasReturnRovScore", ros);
-            item.getScoresMap().put("calcRosMode", calcRosMode);
-
-
-            double vor24h = Double.parseDouble(vidFeatureMap.getOrDefault("vor_24h", "0"));
-            double vor = this.handleVor(vor24h, calcVorMode, item, mergeWeight);
-
-            item.getScoresMap().put("originVor", vor24h);
+            item.getScoresMap().put("strPlusCalibrationCoefficient", fmRov);
+            double hasReturnRovScore = Double.parseDouble(vid2MapFeature.getOrDefault(item.getVideoId() + "", new HashMap<>()).getOrDefault("rov", "0"));
+            item.getScoresMap().put("hasReturnRovScore", hasReturnRovScore);
+            double norXGBScore = item.getScoresMap().getOrDefault("NorXGBScore", 0d);
+            double newNorXGBScore = norPowerCalibration(xgbNorPowerWeight, xgbNorPowerExp, norXGBScore);
+            double vor = Double.parseDouble(vid2MapFeature.getOrDefault(item.getVideoId() + "", new HashMap<>()).getOrDefault("vor", "0"));
             item.getScoresMap().put("vor", vor);
-            item.getScoresMap().put("calcVorMode", calcVorMode);
 
+            Double scoreCoefficient = cate2Coefficient.getOrDefault(vidMergeCate2, 0d);
+            item.getScoresMap().put("scoreCoefficient", scoreCoefficient);
+            item.getScoresMap().put("cate2CoefficientDenominator", cate2CoefficientDenominator);
 
-            item.getScoresMap().put("rosAdd", rosAdd);
-            item.getScoresMap().put("vorAdd", vorAdd);
-            score = fmRov * (rosAdd + ros) * (vorAdd + vor);
+            score = fmRov * (0.1 + newNorXGBScore) * (0.1 + vor) * (1 + scoreCoefficient / cate2CoefficientDenominator);
 
             Video video = item.getVideo();
             video.setScore(score);
             video.setSortScore(score);
             video.setScoresMap(item.getScoresMap());
+            // video.setAllFeatureMap(item.getAllFeatureMap());
 
-            String mergeCate2 = ExtractVideoMergeCate.parseMergeCate2(String.valueOf(item.getVideoId()), featureOriginVideo);
+            String mergeCate2 = ExtractVideoMergeCate.parseMergeCate2(String.valueOf(item.getVideoId()), videoBaseInfoMap);
             if (StringUtils.isNotBlank(mergeCate2)) {
                 video.getMergeCateList().add(mergeCate2);
             }
 
-            Map<String, String> allFeatureMap = new HashMap<>();
-            item.getFeatureMapDouble().forEach((key, value) -> allFeatureMap.put(key, String.valueOf(value)));
-            video.setAllFeatureMap(allFeatureMap);
-
             if (MapUtils.isNotEmpty(feature.getVideoFeature()) && MapUtils.isNotEmpty(feature.getVideoFeature().get(item.getVideoId() + ""))) {
                 video.getMetaFeatureMap().putAll(feature.getVideoFeature().get(item.getVideoId() + ""));
             }
@@ -265,45 +174,246 @@ public class RankStrategy4RegionMergeModelV565 extends RankStrategy4RegionMergeM
             if (MapUtils.isNotEmpty(feature.getUserFeature())) {
                 video.getMetaFeatureMap().putAll(feature.getUserFeature());
             }
-
+            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);
         result.sort(Comparator.comparingDouble(o -> -o.getSortScore()));
+        return result;
+    }
 
-        log.info("565 run time: {}", (System.currentTimeMillis() - startTime));
+    private UserShareReturnProfile parseUserProfile(Map<String, Map<String, String>> userOriginInfo) {
+        if (null != userOriginInfo) {
+            Map<String, String> c9 = userOriginInfo.get("alg_recsys_feature_user_share_return_stat");
+            if (null != c9 && !c9.isEmpty()) {
+                String c9Str = JSONUtils.toJson(c9);
+                if (!c9Str.isEmpty()) {
+                    try {
+                        return JSON.parseObject(c9Str, UserShareReturnProfile.class);
+                    } catch (Exception e) {
+                        log.error("parseObject user profile error! value=[{}]", c9Str, e);
+                    }
+                }
+            }
+        }
+        return null;
+    }
 
-        return result;
+    private Map<String, Map<String, String>> getUserBehaviorVideoMap(UserShareReturnProfile userProfile) {
+        Set<String> vidSet = new HashSet<>();
+        if (null != userProfile) {
+            for (List<UserSRBO> list : Arrays.asList(userProfile.getM_s_s(), userProfile.getM_r_s(), userProfile.getL_s_s(), userProfile.getL_r_s())) {
+                if (null != list) {
+                    for (UserSRBO u : list) {
+                        if (null != u) {
+                            vidSet.add(u.getId() + "");
+                        }
+                    }
+                }
+            }
+        }
+
+        Map<String, Map<String, String>> historyVideoMap = new HashMap<>();
+        if (!vidSet.isEmpty()) {
+            Map<String, Map<String, Map<String, String>>> videoMap = featureService.getVideoBaseInfo("", new ArrayList<>(vidSet));
+            if (null != videoMap && !videoMap.isEmpty()) {
+                for (Map.Entry<String, Map<String, Map<String, String>>> entry : videoMap.entrySet()) {
+                    String vid = entry.getKey();
+                    Map<String, Map<String, String>> map = entry.getValue();
+                    if (null != map && map.containsKey("alg_vid_feature_basic_info")) {
+                        historyVideoMap.put(vid, map.get("alg_vid_feature_basic_info"));
+                    }
+                }
+            }
+        }
+        return historyVideoMap;
+    }
+
+    private Map<String, Float> getUserFeature(long currentMs, RankParam param, 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);
+
+        // head video feature
+        FeatureV6.getVideoBaseFeature("h", currentMs, headInfo, featMap);
+
+        // user feature
+        Map<String, String> baseInfo = getUserBaseInfo(param);
+        FeatureV6.getUserFeature(userOriginInfo, featMap);
+        FeatureV6.getUserProfileFeature(userProfile, baseInfo, featMap);
+
+        return FeatureBucketUtils.noBucketFeature(featMap);
+    }
+
+    private Map<String, Float> getVideoFeature(long currentMs, String vid,
+                                               UserShareReturnProfile userProfile,
+                                               Map<String, String> headInfo, Map<String, String> rankInfo,
+                                               Map<String, Map<String, String[]>> c7Map,
+                                               Map<String, Map<String, String[]>> c8Map,
+                                               Map<String, Map<String, String>> userOriginInfo,
+                                               Map<String, Map<String, String>> historyVideoMap,
+                                               Map<String, Map<String, Map<String, String>>> videoOriginInfo) {
+        Map<String, Double> featMap = new HashMap<>();
+        // user & video feature
+        FeatureV6.getUserTagsCrossVideoFeature("c5", rankInfo, userOriginInfo.get("alg_mid_feature_return_tags"), featMap);
+        FeatureV6.getUserTagsCrossVideoFeature("c6", rankInfo, userOriginInfo.get("alg_mid_feature_share_tags"), featMap);
+        FeatureV6.getUserCFFeature("c7", vid, c7Map, featMap);
+        FeatureV6.getUserCFFeature("c8", vid, c8Map, featMap);
+
+        // rank video feature
+        FeatureV6.getVideoBaseFeature("r", currentMs, rankInfo, featMap);
+        FeatureV6.getVideoFeature(vid, videoOriginInfo, featMap);
+
+        // head&rank cross feature
+        FeatureV6.getHeadRankVideoCrossFeature(headInfo, rankInfo, featMap);
+
+        // user profile & rank cross
+        FeatureV6.getProfileVideoCrossFeature(currentMs, userProfile, rankInfo, historyVideoMap, featMap);
+
+        return FeatureBucketUtils.noBucketFeature(featMap);
     }
 
-    /**
-     * ros模型打分
-     */
-    private void addRosScore(List<RankItem> rankItems, Map<String, Double> userFeatureMapDouble, Map<String, Float> sceneFeatureMap) {
-        List<RankItem> rosRankItems = new ArrayList<>(rankItems.size());
-        for (RankItem rankItem : rankItems) {
-            RankItem rosRankItem = new RankItem(rankItem.getVideo());
-            // 复用了str的二分类xgboost score,所以和str保持一致
-            rosRankItem.featureMap = FeatureBucketUtils.bucketFeatureV2("20250306_ros_bucket_229.txt", rankItem.featureMapDouble);
-            rosRankItems.add(rosRankItem);
+    private void batchGetVideoFeature(long currentMs,
+                                      UserShareReturnProfile userProfile,
+                                      Map<String, String> headInfo,
+                                      Map<String, Map<String, Map<String, String>>> videoBaseInfoMap,
+                                      Map<String, Map<String, String[]>> c7Map,
+                                      Map<String, Map<String, String[]>> c8Map,
+                                      Map<String, Map<String, String>> userOriginInfo,
+                                      Map<String, Map<String, String>> historyVideoMap,
+                                      Map<String, Map<String, Map<String, String>>> videoOriginInfo,
+                                      List<RankItem> rankItems) {
+        if (null != rankItems && !rankItems.isEmpty()) {
+            List<Future<Integer>> futures = new ArrayList<>();
+            for (RankItem item : rankItems) {
+                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.norFeatureMap = item.featureMap;
+                    return 1;
+                });
+                futures.add(future);
+            }
+
+            try {
+                for (Future<Integer> future : futures) {
+                    future.get(1000, TimeUnit.MILLISECONDS);
+                }
+            } catch (Exception e) {
+                log.error("get feature error", e);
+            }
+            // 超时后取消
+            for (Future<Integer> future : futures) {
+                try {
+                    if (!future.isDone()) {
+                        future.cancel(true);
+                    }
+                } catch (Exception e) {
+                    log.error("cancel feature error", e);
+                }
+            }
         }
-        Map<String, Float> userFeatureMap = FeatureBucketUtils.bucketFeatureV2("20250306_ros_bucket_229.txt", userFeatureMapDouble);
-        ScorerUtils.getScorerPipeline("feeds_score_config_xgb_ros_binary_20250319.conf").scoring(sceneFeatureMap, userFeatureMap, rosRankItems);
+    }
 
-        // 将ros分数补充到之前的列表中
-        Map<Long, RankItem> vidRosMap = new HashMap<>(rosRankItems.size());
-        for (RankItem rosRankItem : rosRankItems) {
-            vidRosMap.put(rosRankItem.getVideoId(), rosRankItem);
+    private Map<String, String> getUserBaseInfo(RankParam param) {
+        Map<String, String> baseInfo = new HashMap<>();
+        String province = param.getProvince();
+        if (null != province && !province.isEmpty()) {
+            baseInfo.put("province", province.replaceAll("省$", ""));
         }
 
-        for (RankItem rankItem : rankItems) {
-            if (vidRosMap.containsKey(rankItem.getVideoId())) {
-                RankItem rosRankItem = vidRosMap.get(rankItem.getVideoId());
+        String city = param.getCity();
+        if (null != city && !city.isEmpty()) {
+            baseInfo.put("city", city.replaceAll("市$", ""));
+        }
 
-                // 复用了rov的xgboost model类,所以取scoreRov的值
-                rankItem.setScoreRos(rosRankItem.getScoreRov());
-                rankItem.getScoresMap().put("RosXGBScore", rosRankItem.getScoreRov());
+        MachineInfo machineInfo = param.getMachineInfo();
+        if (null != machineInfo) {
+            String model = machineInfo.getModel();
+            if (null != model && !model.isEmpty()) {
+                baseInfo.put("model", model);
+            }
+            String brand = machineInfo.getBrand();
+            if (null != brand && !brand.isEmpty()) {
+                baseInfo.put("brand", brand);
+            }
+            String system = machineInfo.getSystem();
+            if (null != system && !system.isEmpty()) {
+                baseInfo.put("system", system);
             }
         }
+        String userChannel = param.getChannelName();
+        if (null != userChannel && !userChannel.isEmpty()) {
+            baseInfo.put("user_channel", userChannel);
+        }
+        if (FeatureUtils.firstLevel(param.getUserShareDepth())) {
+            baseInfo.put("user_level", "1st");
+        }
+        return baseInfo;
+    }
+
+    private double norPowerCalibration(double weight, double exp, double score) {
+        double newScore = weight * Math.pow(score, exp);
+        if (newScore > 100) {
+            newScore = 100;
+        } else if (newScore < score) {
+            newScore = score;
+        }
+        return newScore;
+    }
+
+    private Map<String, Double> findSimCateScore(String headCate2, int length) {
+        if (StringUtils.isBlank(headCate2)) {
+            return new HashMap<>();
+        }
+
+        String redisKey = String.format("alg_recsys_good_cate_pair_list:%s", headCate2);
+        String cate2Value = redisTemplate.opsForValue().get(redisKey);
+        if (StringUtils.isEmpty(cate2Value)) {
+            return new HashMap<>();
+        }
+
+        return this.parsePair(cate2Value, length);
+    }
+
+    private Map<String, Double> parsePair(String value, int length) {
+        if (StringUtils.isBlank(value)) {
+            return new HashMap<>();
+        }
+
+        String[] split = value.split("\t");
+        if (split.length != 2) {
+            return new HashMap<>();
+        }
+
+        String[] valueList = split[0].trim().split(",");
+        String[] scoreList = split[1].trim().split(",");
+        if (valueList.length != scoreList.length) {
+            return new HashMap<>();
+        }
+
+        int minLength = Math.min(length, valueList.length);
+        Map<String, Double> resultMap = new HashMap<>();
+        for (int i = 0; i < minLength; i++) {
+            resultMap.put(valueList[i].trim(), Double.parseDouble(scoreList[i].trim()));
+        }
+
+        return resultMap;
+    }
+
+    private String findVideoMergeCate2(Map<String, Map<String, Map<String, String>>> featureOriginVideo, String vid) {
+        Map<String, String> videoInfo = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_basic_info", new HashMap<>());
+        return videoInfo.get("merge_second_level_cate");
     }
 }