瀏覽代碼

fix计算偏好的elements分数异常

apple 6 天之前
父節點
當前提交
9e5359d509

+ 34 - 11
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelV536.java

@@ -686,12 +686,27 @@ public class RankStrategy4RegionMergeModelV536 extends RankStrategy4RegionMergeM
     /**
      * V536 新增: 计算用户偏好元素 × 视频实质元素 的 3 个交叉特征
      * 视频数据源: alg_vid_feature_basic_info → 实质元素 JSON {"花卉":0.0089,"晚安祝福":0.0089,...}
+     * 离线训练使用的是视频的实质元素分(非用户×视频乘积),与离线口径保持一致。
      * 写入 item.featureMap: user_pref_video_overlap_cnt / user_pref_video_max_score / user_pref_video_sum_score
+     *
+     * 标准化到 0-1: 除以离线数据 global_max(20260713 分区 10万条样本统计极值+安全余量)
+     *   overlap_cnt_max = 14  (10万样本 max=12, +2余量)
+     *   max_score_max   = 0.21 (10万样本 max=0.186)
+     *   sum_score_max   = 0.89 (10万样本 max=0.8335)
      */
+    private static final double OVERLAP_CNT_MAX = 14.0;
+    private static final double MAX_SCORE_MAX = 0.21;
+    private static final double SUM_SCORE_MAX = 0.89;
+
     private static void computeUserPrefVideoCrossFeatures(Map<String, Double> userElementScores,
                                                           Map<String, String> rankInfo,
                                                           Map<String, Float> featureMap) {
-        if (MapUtils.isEmpty(userElementScores)) return;
+        if (MapUtils.isEmpty(userElementScores)) {
+            featureMap.put("user_pref_video_overlap_cnt", 0.0f);
+            featureMap.put("user_pref_video_max_score", 0.0f);
+            featureMap.put("user_pref_video_sum_score", 0.0f);
+            return;
+        }
 
         String videoElementsJson = rankInfo.get("实质元素");
         if (StringUtils.isBlank(videoElementsJson)) {
@@ -701,11 +716,19 @@ public class RankStrategy4RegionMergeModelV536 extends RankStrategy4RegionMergeM
             return;
         }
 
-        Map<String, Double> videoElements;
+        Map<String, Double> videoElements = new LinkedHashMap<>();
         try {
-            videoElements = JSON.parseObject(videoElementsJson, Map.class);
+            Map<String, Object> rawMap = JSON.parseObject(videoElementsJson, Map.class);
+            if (rawMap != null) {
+                for (Map.Entry<String, Object> entry : rawMap.entrySet()) {
+                    Object val = entry.getValue();
+                    if (val instanceof Number) {
+                        videoElements.put(entry.getKey(), ((Number) val).doubleValue());
+                    }
+                }
+            }
         } catch (Exception e) {
-            videoElements = Collections.emptyMap();
+            // 解析失败,videoElements 保持空
         }
 
         if (MapUtils.isEmpty(videoElements)) {
@@ -723,17 +746,17 @@ public class RankStrategy4RegionMergeModelV536 extends RankStrategy4RegionMergeM
             String elementName = userElem.getKey();
             if (videoElements.containsKey(elementName)) {
                 overlapCnt++;
-                double userScore = userElem.getValue();
                 double videoScore = videoElements.getOrDefault(elementName, 0.0);
-                sumScore += userScore * videoScore;
-                if (userScore > maxScore) {
-                    maxScore = userScore;
+                sumScore += videoScore;
+                if (videoScore > maxScore) {
+                    maxScore = videoScore;
                 }
             }
         }
 
-        featureMap.put("user_pref_video_overlap_cnt", (float) overlapCnt);
-        featureMap.put("user_pref_video_max_score", (float) maxScore);
-        featureMap.put("user_pref_video_sum_score", (float) sumScore);
+        // 标准化到 0-1
+        featureMap.put("user_pref_video_overlap_cnt", (float) Math.min(overlapCnt / OVERLAP_CNT_MAX, 1.0));
+        featureMap.put("user_pref_video_max_score", (float) Math.min(maxScore / MAX_SCORE_MAX, 1.0));
+        featureMap.put("user_pref_video_sum_score", (float) Math.min(sumScore / SUM_SCORE_MAX, 1.0));
     }
 }