luojunhui пре 9 часа
родитељ
комит
a64048eea9

+ 34 - 46
core/src/main/java/com/tzld/videoVector/service/impl/MaterialSearchServiceImpl.java

@@ -388,9 +388,9 @@ public class MaterialSearchServiceImpl implements MaterialSearchService {
             ScoredMaterial item = new ScoredMaterial();
             item.setConfigCode(configCode);
             item.setModality(modality);
-            item.setSim(round4(sim));
+            item.setSim(MaterialQualityCalculator.round4(sim));
             item.setQualityScore(0.5);
-            item.setFinalScore(round4(simNorm));
+            item.setFinalScore(MaterialQualityCalculator.round4(simNorm));
             if (m instanceof VideoMatch) {
                 VideoMatch vm = (VideoMatch) m;
                 item.setVideoId(String.valueOf(vm.getVideoId()));
@@ -423,11 +423,11 @@ public class MaterialSearchServiceImpl implements MaterialSearchService {
         for (String mid : materialIds) {
             AdsMaterialTouliuAllChannel s = statsMap.get(mid);
             if (s == null) continue;
-            Double ctr = divide(s.getClicks(), s.getImpressions());
-            Double cvr = divide(s.getConversions(), s.getImpressions());
-            Double roi = divide(s.getIncome(), s.getCost());
-            Double openRate = divide(s.getFirstUv(), s.getConversions());
-            Double fissionRate = divide(s.getFission0Uv(), s.getFirstUv());
+            Double ctr = MaterialQualityCalculator.divide(s.getClicks(), s.getImpressions());
+            Double cvr = MaterialQualityCalculator.divide(s.getConversions(), s.getImpressions());
+            Double roi = MaterialQualityCalculator.divide(s.getIncome(), s.getCost());
+            Double openRate = MaterialQualityCalculator.divide(s.getFirstUv(), s.getConversions());
+            Double fissionRate = MaterialQualityCalculator.divide(s.getFission0Uv(), s.getFirstUv());
             if (ctr != null || cvr != null || roi != null || openRate != null || fissionRate != null) {
                 effMap.put(mid, new double[]{
                         ctr != null ? ctr : 0, cvr != null ? cvr : 0,
@@ -462,9 +462,9 @@ public class MaterialSearchServiceImpl implements MaterialSearchService {
             item.setSourceType(m.getSourceType());
             item.setSource(mapSourceTypeLabel(m.getSourceType()));
             item.setText(m.getText());
-            item.setSim(round4(sim));
-            item.setQualityScore(round4(qualityScore));
-            item.setFinalScore(round4(finalScore));
+            item.setSim(MaterialQualityCalculator.round4(sim));
+            item.setQualityScore(MaterialQualityCalculator.round4(qualityScore));
+            item.setFinalScore(MaterialQualityCalculator.round4(finalScore));
 
             // 元数据
             JSONObject deconstructJson = deconstructMap.get(m.getMaterialId());
@@ -484,23 +484,23 @@ public class MaterialSearchServiceImpl implements MaterialSearchService {
                 item.setImpressions(s.getImpressions());
                 item.setClicks(s.getClicks());
                 item.setConversions(s.getConversions());
-                item.setCost(round4(s.getCost()));
-                item.setIncome(round4(s.getIncome()));
+                item.setCost(MaterialQualityCalculator.round4(s.getCost()));
+                item.setIncome(MaterialQualityCalculator.round4(s.getIncome()));
                 item.setFirstUv(s.getFirstUv());
                 item.setFission0Uv(s.getFission0Uv());
             }
             if (eff != null) {
-                item.setCtr(round4(eff[0]));
-                item.setCvr(round4(eff[1]));
-                item.setRoi(round4(eff[2]));
-                item.setOpenRate(round4(eff[3]));
-                item.setFissionRate(round4(eff[4]));
+                item.setCtr(MaterialQualityCalculator.round4(eff[0]));
+                item.setCvr(MaterialQualityCalculator.round4(eff[1]));
+                item.setRoi(MaterialQualityCalculator.round4(eff[2]));
+                item.setOpenRate(MaterialQualityCalculator.round4(eff[3]));
+                item.setFissionRate(MaterialQualityCalculator.round4(eff[4]));
                 // 维度得分 = 原始比率
-                item.setCtrScore(round4(eff[0]));
-                item.setCvrScore(round4(eff[1]));
-                item.setRoiScore(round4(eff[2]));
-                item.setOpenRateScore(round4(eff[3]));
-                item.setFissionRateScore(round4(eff[4]));
+                item.setCtrScore(MaterialQualityCalculator.round4(eff[0]));
+                item.setCvrScore(MaterialQualityCalculator.round4(eff[1]));
+                item.setRoiScore(MaterialQualityCalculator.round4(eff[2]));
+                item.setOpenRateScore(MaterialQualityCalculator.round4(eff[3]));
+                item.setFissionRateScore(MaterialQualityCalculator.round4(eff[4]));
             }
             list.add(item);
         }
@@ -508,14 +508,6 @@ public class MaterialSearchServiceImpl implements MaterialSearchService {
         return list.stream().limit(topN).collect(Collectors.toList());
     }
 
-    /** a / b,任一方为 null 或 b==0 时返回 null */
-    private static Double divide(Number a, Number b) {
-        if (a == null || b == null) return null;
-        double bd = b.doubleValue();
-        if (bd == 0) return null;
-        return a.doubleValue() / bd;
-    }
-
     /** 从不同类型的 Match 中提取相似度分数 */
     private double getMatchScore(Object match) {
         if (match instanceof VideoMatch) return ((VideoMatch) match).getScore();
@@ -547,22 +539,22 @@ public class MaterialSearchServiceImpl implements MaterialSearchService {
         vo.setImpressions(s.getImpressions());
         vo.setClicks(s.getClicks());
         vo.setConversions(s.getConversions());
-        vo.setCost(round4(s.getCost()));
-        vo.setIncome(round4(s.getIncome()));
+        vo.setCost(MaterialQualityCalculator.round4(s.getCost()));
+        vo.setIncome(MaterialQualityCalculator.round4(s.getIncome()));
         vo.setFirstUv(s.getFirstUv());
         vo.setFission0Uv(s.getFission0Uv());
 
         // 效率指标
-        Double ctr = divide(s.getClicks(), s.getImpressions());
-        Double cvr = divide(s.getConversions(), s.getImpressions());
-        Double roi = divide(s.getIncome(), s.getCost());
-        Double openRate = divide(s.getFirstUv(), s.getConversions());
-        Double fissionRate = divide(s.getFission0Uv(), s.getFirstUv());
-        vo.setCtr(ctr != null ? round4(ctr) : null);
-        vo.setCvr(cvr != null ? round4(cvr) : null);
-        vo.setRoi(roi != null ? round4(roi) : null);
-        vo.setOpenRate(openRate != null ? round4(openRate) : null);
-        vo.setFissionRate(fissionRate != null ? round4(fissionRate) : null);
+        Double ctr = MaterialQualityCalculator.divide(s.getClicks(), s.getImpressions());
+        Double cvr = MaterialQualityCalculator.divide(s.getConversions(), s.getImpressions());
+        Double roi = MaterialQualityCalculator.divide(s.getIncome(), s.getCost());
+        Double openRate = MaterialQualityCalculator.divide(s.getFirstUv(), s.getConversions());
+        Double fissionRate = MaterialQualityCalculator.divide(s.getFission0Uv(), s.getFirstUv());
+        vo.setCtr(ctr != null ? MaterialQualityCalculator.round4(ctr) : null);
+        vo.setCvr(cvr != null ? MaterialQualityCalculator.round4(cvr) : null);
+        vo.setRoi(roi != null ? MaterialQualityCalculator.round4(roi) : null);
+        vo.setOpenRate(openRate != null ? MaterialQualityCalculator.round4(openRate) : null);
+        vo.setFissionRate(fissionRate != null ? MaterialQualityCalculator.round4(fissionRate) : null);
 
         // 单素材查询无批内排名,维度得分置 null
         return vo;
@@ -763,10 +755,6 @@ public class MaterialSearchServiceImpl implements MaterialSearchService {
         return Math.max(0, Math.min(1, x));
     }
 
-    private static double round4(double v) {
-        return Math.round(v * 10000.0) / 10000.0;
-    }
-
     private static String mapSourceTypeLabel(Short sourceType) {
         if (sourceType == null) return null;
         if (sourceType == 1) return "外部合作";

+ 23 - 37
core/src/main/java/com/tzld/videoVector/service/recall/impl/VectorRecallTestServiceImpl.java

@@ -1337,52 +1337,38 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
         map.put("fission0Uv", s.getFission0Uv());
 
         // 效率指标
-        Double ctr = divide(s.getClicks(), s.getImpressions());
-        Double cvr = divide(s.getConversions(), s.getImpressions());
-        Double roi = divide(s.getIncome(), s.getCost());
-        Double openRate = divide(s.getFirstUv(), s.getConversions());
-        Double fissionRate = divide(s.getFission0Uv(), s.getFirstUv());
-        if (ctr != null) { map.put("ctr", round4(ctr)); map.put("ctrScore", round4(ctr)); }
-        if (cvr != null) { map.put("cvr", round4(cvr)); map.put("cvrScore", round4(cvr)); }
-        if (roi != null) { map.put("roi", round4(roi)); map.put("roiScore", round4(roi)); }
-        if (openRate != null) { map.put("openRate", round4(openRate)); map.put("openRateScore", round4(openRate)); }
-        if (fissionRate != null) { map.put("fissionRate", round4(fissionRate)); map.put("fissionRateScore", round4(fissionRate)); }
+        Double ctr = MaterialQualityCalculator.divide(s.getClicks(), s.getImpressions());
+        Double cvr = MaterialQualityCalculator.divide(s.getConversions(), s.getImpressions());
+        Double roi = MaterialQualityCalculator.divide(s.getIncome(), s.getCost());
+        Double openRate = MaterialQualityCalculator.divide(s.getFirstUv(), s.getConversions());
+        Double fissionRate = MaterialQualityCalculator.divide(s.getFission0Uv(), s.getFirstUv());
+        if (ctr != null) { map.put("ctr", MaterialQualityCalculator.round4(ctr)); map.put("ctrScore", MaterialQualityCalculator.round4(ctr)); }
+        if (cvr != null) { map.put("cvr", MaterialQualityCalculator.round4(cvr)); map.put("cvrScore", MaterialQualityCalculator.round4(cvr)); }
+        if (roi != null) { map.put("roi", MaterialQualityCalculator.round4(roi)); map.put("roiScore", MaterialQualityCalculator.round4(roi)); }
+        if (openRate != null) { map.put("openRate", MaterialQualityCalculator.round4(openRate)); map.put("openRateScore", MaterialQualityCalculator.round4(openRate)); }
+        if (fissionRate != null) { map.put("fissionRate", MaterialQualityCalculator.round4(fissionRate)); map.put("fissionRateScore", MaterialQualityCalculator.round4(fissionRate)); }
 
         // 综合质量分(等权加权,测试路径无批内百分位排名,用原始比率近似)
         double qs = computeSimpleQualityScore(s);
-        map.put("qualityScore", round4(qs));
+        map.put("qualityScore", MaterialQualityCalculator.round4(qs));
 
         return map;
     }
 
-    /** a / b,任一方为 null 或 b==0 时返回 null */
-    private static Double divide(Number a, Number b) {
-        if (a == null || b == null) return null;
-        double bd = b.doubleValue();
-        if (bd == 0) return null;
-        return a.doubleValue() / bd;
-    }
-
-    private static double round4(double v) {
-        return Math.round(v * 10000.0) / 10000.0;
-    }
-
-    /** 简单质量分:等权加权所有有数据的效率指标 */
+    /** 简单质量分:加权求和,与 MaterialSearchServiceImpl 权重默认值保持一致 */
     private double computeSimpleQualityScore(AdsMaterialTouliuAllChannel s) {
         if (s == null) return 0;
-        int count = 0;
-        double sum = 0;
-        Double ctr = divide(s.getClicks(), s.getImpressions());
-        Double cvr = divide(s.getConversions(), s.getImpressions());
-        Double roi = divide(s.getIncome(), s.getCost());
-        Double openRate = divide(s.getFirstUv(), s.getConversions());
-        Double fissionRate = divide(s.getFission0Uv(), s.getFirstUv());
-        if (ctr != null) { sum += ctr; count++; }
-        if (cvr != null) { sum += cvr; count++; }
-        if (roi != null) { sum += roi; count++; }
-        if (openRate != null) { sum += openRate; count++; }
-        if (fissionRate != null) { sum += fissionRate; count++; }
-        return count > 0 ? sum / count : 0;
+        double wCtr = 0.2, wCvr = 0.2, wRoi = 0.2, wOpenRate = 0.2, wFissionRate = 0.2;
+        Double ctr = MaterialQualityCalculator.divide(s.getClicks(), s.getImpressions());
+        Double cvr = MaterialQualityCalculator.divide(s.getConversions(), s.getImpressions());
+        Double roi = MaterialQualityCalculator.divide(s.getIncome(), s.getCost());
+        Double openRate = MaterialQualityCalculator.divide(s.getFirstUv(), s.getConversions());
+        Double fissionRate = MaterialQualityCalculator.divide(s.getFission0Uv(), s.getFirstUv());
+        return (ctr != null ? wCtr * ctr : 0)
+             + (cvr != null ? wCvr * cvr : 0)
+             + (roi != null ? wRoi * roi : 0)
+             + (openRate != null ? wOpenRate * openRate : 0)
+             + (fissionRate != null ? wFissionRate * fissionRate : 0);
     }
 
     private Map<String, AdsMaterialTouliuAllChannel> loadMaterialTouliuStats(

+ 13 - 32
core/src/main/java/com/tzld/videoVector/util/MaterialQualityCalculator.java

@@ -117,38 +117,6 @@ public class MaterialQualityCalculator {
 
     // ===== 百分位排名计算 =====
 
-    /**
-     * 对值列表计算批内百分位排名(等值取平均排名)
-     * @return 与输入同序的百分位数组 [0, 1]
-     */
-    public static List<Double> computePercentileRanks(List<Double> values) {
-        int n = values.size();
-        List<Double> result = new ArrayList<>(Collections.nCopies(n, 0.5));
-        if (n <= 1) {
-            return result;
-        }
-
-        // 按值升序排列的索引
-        List<Integer> sortedIdx = new ArrayList<>(n);
-        for (int i = 0; i < n; i++) sortedIdx.add(i);
-        sortedIdx.sort(Comparator.comparingDouble(values::get));
-
-        for (int i = 0; i < n; ) {
-            double val = values.get(sortedIdx.get(i));
-            int j = i;
-            while (j < n && Double.compare(values.get(sortedIdx.get(j)), val) == 0) {
-                j++;
-            }
-            double avgRank = (i + j - 1) / 2.0;
-            double pct = avgRank / (n - 1);
-            for (int k = i; k < j; k++) {
-                result.set(sortedIdx.get(k), pct);
-            }
-            i = j;
-        }
-        return result;
-    }
-
     @FunctionalInterface
     private interface ValueExtractor {
         double extract(DimValues dv);
@@ -187,6 +155,19 @@ public class MaterialQualityCalculator {
 
     // ===== 辅助方法 =====
 
+    /** a / b,任一方为 null 或 b==0 时返回 null */
+    public static Double divide(Number a, Number b) {
+        if (a == null || b == null) return null;
+        double bd = b.doubleValue();
+        if (bd == 0) return null;
+        return a.doubleValue() / bd;
+    }
+
+    /** 四舍五入保留 4 位小数 */
+    public static double round4(double v) {
+        return Math.round(v * 10000.0) / 10000.0;
+    }
+
     private static double nullToZero(Double v) { return v == null ? 0 : v; }
     private static double nullToZero(Long v) { return v == null ? 0 : v; }