浏览代码

883
新竞价
新计价
886
旧竞价
Copc的计价
887
旧竞价
f的计价

fanjinyang 1 周之前
父节点
当前提交
223e890d42

+ 0 - 1
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/impl/RankServiceImpl.java

@@ -27,7 +27,6 @@ import com.tzld.piaoquan.recommend.feature.domain.ad.base.AdItemFeature;
 import com.tzld.piaoquan.recommend.feature.domain.ad.base.AdRankItem;
 import com.tzld.piaoquan.recommend.feature.domain.ad.base.UserAdFeature;
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;

+ 134 - 57
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBy886.java

@@ -3,6 +3,7 @@ package com.tzld.piaoquan.ad.engine.service.score.strategy;
 import com.alibaba.fastjson.JSONObject;
 import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
 import com.tzld.piaoquan.ad.engine.commons.dto.AdPlatformCreativeDTO;
+import com.tzld.piaoquan.ad.engine.commons.helper.CreativeUserLayerDataHelper;
 import com.tzld.piaoquan.ad.engine.commons.helper.DnnCidDataHelper;
 import com.tzld.piaoquan.ad.engine.commons.param.RankRecommendRequestParam;
 import com.tzld.piaoquan.ad.engine.commons.score.ScoreParam;
@@ -83,6 +84,9 @@ public class RankStrategyBy886 extends RankStrategyBasic {
     @Override
     public List<AdRankItem> adItemRank(RankRecommendRequestParam request, ScoreParam scoreParam) {
         Map<String, Double> weightParam = ObjUtil.nullOrDefault(weightMap, new HashMap<>());
+
+
+        Map<Long, Double> creativeScoreCoefficient = getCreativeScoreCoefficient();
         Set<String> noApiAdVerIds = getNoApiAdVerIds();
 
         long ts = System.currentTimeMillis() / 1000;
@@ -186,21 +190,19 @@ public class RankStrategyBy886 extends RankStrategyBasic {
                     adRankItem.setAgentId(dto.getAgentId());
                     adRankItem.setProfession(dto.getProfession());
                     adRankItem.setLandingPageType(dto.getLandingPageType());
-                    adRankItem.setTargetingConversion(dto.getTargetingConversion());
                     adRankItem.setRandom(random.nextInt(1000));
                     if (noApiAdVerIds.contains(dto.getAdVerId())) {
                         adRankItem.getExt().put("isApi", "0");
                     } else {
                         adRankItem.getExt().put("isApi", "1");
                     }
-                    adRankItem.getExt().put("recallsources", dto.getRecallSources());
-                    fillAdRankItemExt(adRankItem, dto);
-                    // 886 的竞价系数来自当前广告候选,缺失时使用中性值以兼容历史请求。
+                    // 883 的竞价系数来自当前广告候选,缺失时使用中性值以兼容历史请求。
                     adRankItem.getScoreMap().put("fRankCoefficient", normalizeCoefficient(dto.getFRankCoefficient()));
                     adRankItem.getScoreMap().put("rcRankCoefficient", normalizeCoefficient(dto.getRcRankCoefficient()));
                     adRankItem.getScoreMap().put("bidCoefficient", normalizeCoefficient(dto.getBidCoefficient()));
-                    // 计价系数不参与排序,但需要进入排序日志,供曝光计价链路回溯。
                     adRankItem.getScoreMap().put("pricingCoefficient", normalizeCoefficient(dto.getPricingCoefficient()));
+                    adRankItem.getExt().put("recallsources", dto.getRecallSources());
+                    fillAdRankItemExt(adRankItem, dto);
                     adRankItem.getExt().put("correctCpaMap", JSONObject.toJSONString(correctCpaMap.get(dto.getAdId())));
                     adRankItem.getExt().put("correctionFactor", correctCpaMap.get(dto.getAdId()).getCorrectionFactor());
                     setGuaranteeWeight(map, dto.getAdVerId(), adRankItem.getExt(), isGuaranteedFlow, reqFeature);
@@ -322,86 +324,131 @@ public class RankStrategyBy886 extends RankStrategyBasic {
         if (CollectionUtils.isEmpty(adRankItems)) {
             log.error("adRankItems is empty");
         }
-        List<AdRankItem> result = ScorerUtils.getScorerPipeline(ScorerUtils.PAI_SCORE_CONF_20250804).scoring(sceneFeatureMap, userFeatureMap, adRankItems);
+        List<AdRankItem> result = ScorerUtils.getScorerPipeline(ScorerUtils.PAI_SCORE_CONF_20250214).scoring(sceneFeatureMap, userFeatureMap, adRankItems);
         if (CollectionUtils.isEmpty(result)) {
             log.error("scoring result is empty");
         }
         long time5 = System.currentTimeMillis();
+        int viewLimit = NumberUtils.toInt(paramsMap.getOrDefault("viewLimit", "3000"));
         // calibrate score for negative sampling or cold start
         for (AdRankItem item : result) {
-            double scanScore = item.getScoreMap().getOrDefault("scanScore", 0.0);
-            double addWechatScore = item.getScoreMap().getOrDefault("addWechatScore", 0.0);
-            double conversionScore = item.getScoreMap().getOrDefault("conversionScore", 0.0);
-            double calibratedScanScore = scanScore / (scanScore + (1 - scanScore) / negSampleRate);
-            double calibratedConversionScore = conversionScore / (conversionScore + (1 - conversionScore) / negSampleRate);
-            item.getScoreMap().put("calibratedScanScore", calibratedScanScore);
-            item.getScoreMap().put("calibratedConversionScore", calibratedConversionScore);
-            double calibratedScore = 0.0;
-            if (Objects.equals(item.getLandingPageType(), 3) && Objects.equals(item.getTargetingConversion(), "10019")) {
-                calibratedScore = calibratedScanScore;
-            } else if (Objects.equals(item.getLandingPageType(), 3) && Objects.equals(item.getTargetingConversion(), "10004")) {
-                calibratedScore = calibratedScanScore * addWechatScore;
-            } else {
-                calibratedScore = calibratedConversionScore;
+            double originalScore = item.getLrScore();
+            double calibratedScore = originalScore / (originalScore + (1 - originalScore) / negSampleRate);
+            // 该创意尚未在模型中训练,打分不可靠
+            Map<String, Map<String, String>> cidFeature = allCidFeature.getOrDefault(String.valueOf(item.getAdId()), EMPTY_NESTED_MAP);
+            Map<String, String> b3Feature = cidFeature.getOrDefault("alg_cid_feature_cid_action", EMPTY_STRING_MAP);
+            double view3Day = Double.parseDouble(b3Feature.getOrDefault("ad_view_3d", "0"));
+            if ((CollectionUtils.isNotEmpty(DnnCidDataHelper.getCidSet()) && !DnnCidDataHelper.getCidSet().contains(item.getAdId()))
+                    || view3Day <= viewLimit) {
+                double view = Double.parseDouble(b3Feature.getOrDefault("ad_view_14d", "0"));
+                double conver = Double.parseDouble(b3Feature.getOrDefault("ad_conversion_14d", "0"));
+                double smoothCxr = NumUtil.divSmoothV1(conver, view, 1.64);
+                smoothCxr = this.getDefaultCxr(smoothCxr);
+                //模型打分和统计计算取打分更低的
+                item.getScoreMap().put("cvcvrItemValue", 1.0);
+                if (smoothCxr <= calibratedScore) {
+                    calibratedScore = smoothCxr;
+                    item.getScoreMap().put("cvcvrItemValue", 2.0);
+                }
             }
+            item.setLrScore(calibratedScore);
+            item.getScoreMap().put("originCtcvrScore", originalScore);
             item.getScoreMap().put("modelCtcvrScore", calibratedScore);
             item.getScoreMap().put("ctcvrScore", calibratedScore);
-            item.setLrScore(calibratedScore);
         }
 
-        // 886 的 eCPM 与排序分分开:eCPM 表示竞价基础值,score 表示叠加 851 外围权重后的排序值。
+        String calibModelName = paramsMap.getOrDefault("calibModelName", "dnnV3");
+        calculateCtcvrScore(result, request, scoreParam, calibModelName, reqFeature);
+
+        double minValidCopc = NumberUtils.toDouble(paramsMap.getOrDefault("minValidCopc", "0.8"));
+        double maxValidCopc = NumberUtils.toDouble(paramsMap.getOrDefault("maxValidCopc", "10"));
+        double minCopc = NumberUtils.toDouble(paramsMap.getOrDefault("minCopc", "0.2"));
+        double maxCopc = NumberUtils.toDouble(paramsMap.getOrDefault("maxCopc", "2.5"));
+        calibrationCidCtcvr(result, calibModelName, reqFeature, minValidCopc, maxValidCopc, minCopc, maxCopc);
+        if (CollectionUtils.isEmpty(result)) {
+            log.error("calculateCtcvrScore result is empty");
+        }
+        // loop
         double cpmCoefficient = weightParam.getOrDefault("cpmCoefficient", 0.9);
         boolean isGuaranteeType = false;
-
+        // 查询人群分层信息
+        String peopleLayer = Optional.of(reqFeature)
+                .map(f -> f.get("layer"))
+                .map(s -> s.replace("-炸", ""))
+                .orElse(null);
+
+        // 控制曝光参数
+        String expOldKey = paramsMap.getOrDefault("expOldKey", "ad_view_yesterday");
+        double expOldThreshold = NumberUtils.toDouble(paramsMap.getOrDefault("expOldThreshold", "1000"));
+        String expNewKey = paramsMap.getOrDefault("expNewKey", "ad_view_today");
+        double expNewThreshold = NumberUtils.toDouble(paramsMap.getOrDefault("expNewThreshold", "3000"));
+        double expLowerWeight = NumberUtils.toDouble(paramsMap.getOrDefault("expLowerWeight", "0.2"));
+        double expUpperWeight = NumberUtils.toDouble(paramsMap.getOrDefault("expUpperWeight", "1.0"));
+        double expScale = NumberUtils.toDouble(paramsMap.getOrDefault("expScale", "10.0"));
         int openH5 = NumberUtils.toInt(paramsMap.getOrDefault("openH5", "0"));
 
-        // 与 851 一致,通过尾号 rerank 配置填充 flowCtlC、flowCtlA 和 kFinal。
+        // 计算rerank权重
         calRerankWeight(scoreParam, userLayer, result);
         for (AdRankItem item : result) {
-            // modelCtcvrScore 是负采样(含冷启动兜底)阶段固化的分数。
-            double modelCtcvrScore = item.getScoreMap().getOrDefault("modelCtcvrScore", item.getLrScore());
             double bid = item.getCpa();
+            if (scoreParam.getExpCodeSet().contains(correctCpaExp1) || scoreParam.getExpCodeSet().contains(correctCpaExp2)) {
+                Double correctionFactor = (Double) item.getExt().get("correctionFactor");
+                item.getScoreMap().put("correctionFactor", correctionFactor);
+                bid = bid * correctionFactor;
+            }
+            double ecpm = item.getLrScore() * bid * 1000;
+            if (isGuaranteedFlow && item.getExt().get("isGuaranteed") != null && (boolean) item.getExt().get("isGuaranteed")) {
+                isGuaranteeType = true;
+            }
+
             double fRankCoefficient = item.getScoreMap().getOrDefault("fRankCoefficient", 1.0D);
             double rcRankCoefficient = item.getScoreMap().getOrDefault("rcRankCoefficient", 1.0D);
             double bidCoefficient = item.getScoreMap().getOrDefault("bidCoefficient", 1.0D);
-            double ecpm = modelCtcvrScore * bid * fRankCoefficient * rcRankCoefficient * bidCoefficient * 1000;
 
-            double h5Weight = 1.0D;
+
+            // h5 降权
+            double h5Weight = 1;
             if (openH5 > 0) {
                 h5Weight = this.getH5SuppressWeight(item);
             }
-            double flowCtlC = item.getScoreMap().getOrDefault("flowCtlC", 1.0D);
-            double flowCtlA = item.getScoreMap().getOrDefault("flowCtlA", 1.0D);
-            double guaranteeScoreCoefficient = getGuaranteeScoreCoefficient(isGuaranteedFlow, item.getExt());
-            double score = item.getLrScore() * bid * 1000;
 
-            // 没有转化回传的广告主沿用配置 CPM,避免以不可靠的模型预估参与竞价。
-            if (noApiAdVerIds.contains(item.getAdVerId())) {
-                ecpm = item.getCpm();
-                score = item.getCpm() * cpmCoefficient / 1000;
-            }
-
-            // scoreMap 是排序日志的数据源;写入 eCPM 分子及实际参与 score 计算的全部外围因子。
-            item.getScoreMap().put("modelCtcvrScore", modelCtcvrScore);
+            // 控制曝光权重
+            Map<String, Map<String, String>> cidFeature = allCidFeature.getOrDefault(String.valueOf(item.getAdId()), EMPTY_NESTED_MAP);
+            Map<String, String> b3Feature = cidFeature.getOrDefault("alg_cid_feature_cid_action", EMPTY_STRING_MAP);
+            double expWeight = getExpWeight(b3Feature,
+                    expOldKey, expOldThreshold,
+                    expNewKey, expNewThreshold,
+                    expLowerWeight, expUpperWeight, expScale);
+
+            // 控制流量权重
+            double flowCtlC = item.getScoreMap().getOrDefault("flowCtlC", 1.0);
+            double flowCtlA = item.getScoreMap().getOrDefault("flowCtlA", 1.0);
+            double kFinal = item.getScoreMap().getOrDefault("kFinal", 1.0);
+
+            String layerAndCreativeWeightMapKey = getLayerAndCreativeWeightMapKey(peopleLayer, String.valueOf(item.getAdId()));
+            // 人群分层&创意的权重
+            double layerAndCreativeWeight = getLayerAndCreativeWeight(layerAndCreativeWeightMapKey);
+            double scoreCoefficient = creativeScoreCoefficient.getOrDefault(item.getAdId(), 1d);
+            double guaranteeScoreCoefficient = getGuaranteeScoreCoefficient(isGuaranteedFlow, item.getExt());
+            double score = flowCtlC * flowCtlA * h5Weight * expWeight * item.getLrScore() * bid * scoreCoefficient * guaranteeScoreCoefficient * layerAndCreativeWeight * kFinal;
+            item.getScoreMap().put("guaranteeScoreCoefficient", guaranteeScoreCoefficient);
+            item.getScoreMap().put("cpa", item.getCpa());
+            item.getScoreMap().put("cpm", item.getCpm());
             item.getScoreMap().put("bid", bid);
+            item.getScoreMap().put("cpmCoefficient", cpmCoefficient);
+            item.getScoreMap().put("scoreCoefficient", scoreCoefficient);
+            item.getScoreMap().put("h5", h5Weight);
             item.getScoreMap().put("fRankCoefficient", fRankCoefficient);
             item.getScoreMap().put("rcRankCoefficient", rcRankCoefficient);
             item.getScoreMap().put("bidCoefficient", bidCoefficient);
             item.getScoreMap().put("ecpm", ecpm);
-            item.getScoreMap().put("flowCtlC", flowCtlC);
-            item.getScoreMap().put("flowCtlA", flowCtlA);
-            item.getScoreMap().put("h5", h5Weight);
-            item.getScoreMap().put("guaranteeScoreCoefficient", guaranteeScoreCoefficient);
-            item.getScoreMap().put("score", score);
-
-
-            if (isGuaranteedFlow && item.getExt().get("isGuaranteed") != null && (boolean) item.getExt().get("isGuaranteed")) {
-                isGuaranteeType = true;
-            }
-            item.getScoreMap().put("cpa", item.getCpa());
-            item.getScoreMap().put("cpm", item.getCpm());
             item.getFeatureMap().putAll(userFeatureMap);
             item.getFeatureMap().putAll(sceneFeatureMap);
+
+            // 没有转化回传的广告主,使用后台配置的CPM
+            if (noApiAdVerIds.contains(item.getAdVerId())) {
+                score = item.getCpm() * cpmCoefficient / 1000;
+            }
             item.setScore(score);
         }
 
@@ -418,10 +465,17 @@ public class RankStrategyBy886 extends RankStrategyBasic {
                 participateCompetitionType.add("guarantee");
             }
             top1Item.getExt().put("participateCompetitionType", StringUtils.join(participateCompetitionType, ","));
-            top1Item.getExt().put("ecpm", top1Item.getScoreMap().get("ecpm"));
+            Double modelCtcvrScore = top1Item.getScoreMap().get("modelCtcvrScore");
+            Double ctcvrScore = top1Item.getScoreMap().get("ctcvrScore");
             if (scoreParam.getExpCodeSet().contains(checkoutEcpmExp)) {
+                top1Item.getExt().put("ecpm", ctcvrScore * top1Item.getCpa() * 1000);
                 String filterEcpmValue = paramsMap.getOrDefault("filterEcpm", filterEcpm);
                 top1Item.getExt().put("filterEcpm", filterEcpmValue);
+                if (noApiAdVerIds.contains(top1Item.getAdVerId())) {
+                    top1Item.getExt().put("ecpm", top1Item.getCpm());
+                }
+            } else {
+                top1Item.getExt().put("ecpm", modelCtcvrScore * top1Item.getCpa() * 1000);
             }
             putMetaFeature(top1Item, feature, reqFeature, sceneFeatureMap, request);
             top1Item.getExt().put("model", logModelName);
@@ -437,10 +491,6 @@ public class RankStrategyBy886 extends RankStrategyBasic {
         return result;
     }
 
-    private double normalizeCoefficient(Number coefficient) {
-        return coefficient == null ? 1.0D : coefficient.doubleValue();
-    }
-
     /**
      * 获取人群分层和创意的权重
      *
@@ -1075,4 +1125,31 @@ public class RankStrategyBy886 extends RankStrategyBasic {
         return Math.min(Math.max(lowerWeight, weight), upperWeight);
     }
 
+    private void calibrationCidCtcvr(List<AdRankItem> items, String modelName, Map<String, String> reqFeature,
+                                     double minValid, double maxValid,
+                                     double minVal, double maxVal) {
+        try {
+            String layer = reqFeature.get("layer_l4");
+            for (AdRankItem item : items) {
+                String cid = String.valueOf(item.getAdId());
+                Double diff = CreativeUserLayerDataHelper.getCopc(modelName, cid, layer);
+                if (null != diff) {
+                    double newDiff = Math.min(Math.max(minVal, diff), maxVal);
+                    if (newDiff < minValid || newDiff > maxValid) {
+                        double ctcvr = item.getLrScore() * newDiff;
+                        item.getScoreMap().put("cidCtcvrScore", ctcvr);
+                        item.getScoreMap().put("ctcvrScore", ctcvr);
+                        item.setLrScore(ctcvr);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("calibCidScore error", e);
+        }
+    }
+
+    private double normalizeCoefficient(Number coefficient) {
+        return coefficient == null ? 1.0D : coefficient.doubleValue();
+    }
+
 }

+ 111 - 48
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBy887.java

@@ -3,6 +3,7 @@ package com.tzld.piaoquan.ad.engine.service.score.strategy;
 import com.alibaba.fastjson.JSONObject;
 import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
 import com.tzld.piaoquan.ad.engine.commons.dto.AdPlatformCreativeDTO;
+import com.tzld.piaoquan.ad.engine.commons.helper.CreativeUserLayerDataHelper;
 import com.tzld.piaoquan.ad.engine.commons.helper.DnnCidDataHelper;
 import com.tzld.piaoquan.ad.engine.commons.param.RankRecommendRequestParam;
 import com.tzld.piaoquan.ad.engine.commons.score.ScoreParam;
@@ -83,6 +84,9 @@ public class RankStrategyBy887 extends RankStrategyBasic {
     @Override
     public List<AdRankItem> adItemRank(RankRecommendRequestParam request, ScoreParam scoreParam) {
         Map<String, Double> weightParam = ObjUtil.nullOrDefault(weightMap, new HashMap<>());
+
+
+        Map<Long, Double> creativeScoreCoefficient = getCreativeScoreCoefficient();
         Set<String> noApiAdVerIds = getNoApiAdVerIds();
 
         long ts = System.currentTimeMillis() / 1000;
@@ -192,14 +196,13 @@ public class RankStrategyBy887 extends RankStrategyBasic {
                     } else {
                         adRankItem.getExt().put("isApi", "1");
                     }
-                    adRankItem.getExt().put("recallsources", dto.getRecallSources());
-                    fillAdRankItemExt(adRankItem, dto);
                     // 883 的竞价系数来自当前广告候选,缺失时使用中性值以兼容历史请求。
                     adRankItem.getScoreMap().put("fRankCoefficient", normalizeCoefficient(dto.getFRankCoefficient()));
                     adRankItem.getScoreMap().put("rcRankCoefficient", normalizeCoefficient(dto.getRcRankCoefficient()));
                     adRankItem.getScoreMap().put("bidCoefficient", normalizeCoefficient(dto.getBidCoefficient()));
-                    // 计价系数不参与排序,但需要进入排序日志,供曝光计价链路回溯。
                     adRankItem.getScoreMap().put("pricingCoefficient", normalizeCoefficient(dto.getPricingCoefficient()));
+                    adRankItem.getExt().put("recallsources", dto.getRecallSources());
+                    fillAdRankItemExt(adRankItem, dto);
                     adRankItem.getExt().put("correctCpaMap", JSONObject.toJSONString(correctCpaMap.get(dto.getAdId())));
                     adRankItem.getExt().put("correctionFactor", correctCpaMap.get(dto.getAdId()).getCorrectionFactor());
                     setGuaranteeWeight(map, dto.getAdVerId(), adRankItem.getExt(), isGuaranteedFlow, reqFeature);
@@ -354,68 +357,98 @@ public class RankStrategyBy887 extends RankStrategyBasic {
             item.getScoreMap().put("ctcvrScore", calibratedScore);
         }
 
-        // 883 的 eCPM 与排序分分开:eCPM 表示竞价基础值,score 表示叠加 851 外围权重后的排序值。
+        String calibModelName = paramsMap.getOrDefault("calibModelName", "dnnV3");
+        calculateCtcvrScore(result, request, scoreParam, calibModelName, reqFeature);
+
+        double minValidCopc = NumberUtils.toDouble(paramsMap.getOrDefault("minValidCopc", "0.8"));
+        double maxValidCopc = NumberUtils.toDouble(paramsMap.getOrDefault("maxValidCopc", "10"));
+        double minCopc = NumberUtils.toDouble(paramsMap.getOrDefault("minCopc", "0.2"));
+        double maxCopc = NumberUtils.toDouble(paramsMap.getOrDefault("maxCopc", "2.5"));
+        calibrationCidCtcvr(result, calibModelName, reqFeature, minValidCopc, maxValidCopc, minCopc, maxCopc);
+        if (CollectionUtils.isEmpty(result)) {
+            log.error("calculateCtcvrScore result is empty");
+        }
+        // loop
         double cpmCoefficient = weightParam.getOrDefault("cpmCoefficient", 0.9);
         boolean isGuaranteeType = false;
-
+        // 查询人群分层信息
+        String peopleLayer = Optional.of(reqFeature)
+                .map(f -> f.get("layer"))
+                .map(s -> s.replace("-炸", ""))
+                .orElse(null);
+
+        // 控制曝光参数
+        String expOldKey = paramsMap.getOrDefault("expOldKey", "ad_view_yesterday");
+        double expOldThreshold = NumberUtils.toDouble(paramsMap.getOrDefault("expOldThreshold", "1000"));
+        String expNewKey = paramsMap.getOrDefault("expNewKey", "ad_view_today");
+        double expNewThreshold = NumberUtils.toDouble(paramsMap.getOrDefault("expNewThreshold", "3000"));
+        double expLowerWeight = NumberUtils.toDouble(paramsMap.getOrDefault("expLowerWeight", "0.2"));
+        double expUpperWeight = NumberUtils.toDouble(paramsMap.getOrDefault("expUpperWeight", "1.0"));
+        double expScale = NumberUtils.toDouble(paramsMap.getOrDefault("expScale", "10.0"));
         int openH5 = NumberUtils.toInt(paramsMap.getOrDefault("openH5", "0"));
 
-        // 与 851 一致,通过尾号 rerank 配置填充 flowCtlC、flowCtlA 和 kFinal。
+        // 计算rerank权重
         calRerankWeight(scoreParam, userLayer, result);
         for (AdRankItem item : result) {
-            // modelCtcvrScore 是负采样(含冷启动兜底)阶段固化的分数。
-            double modelCtcvrScore = item.getScoreMap().getOrDefault("modelCtcvrScore", item.getLrScore());
             double bid = item.getCpa();
+            if (scoreParam.getExpCodeSet().contains(correctCpaExp1) || scoreParam.getExpCodeSet().contains(correctCpaExp2)) {
+                Double correctionFactor = (Double) item.getExt().get("correctionFactor");
+                item.getScoreMap().put("correctionFactor", correctionFactor);
+                bid = bid * correctionFactor;
+            }
+            double modelCtcvrScore = item.getScoreMap().getOrDefault("modelCtcvrScore", item.getLrScore());
+            if (isGuaranteedFlow && item.getExt().get("isGuaranteed") != null && (boolean) item.getExt().get("isGuaranteed")) {
+                isGuaranteeType = true;
+            }
+
             double fRankCoefficient = item.getScoreMap().getOrDefault("fRankCoefficient", 1.0D);
             double rcRankCoefficient = item.getScoreMap().getOrDefault("rcRankCoefficient", 1.0D);
             double bidCoefficient = item.getScoreMap().getOrDefault("bidCoefficient", 1.0D);
-            double ecpm = modelCtcvrScore * bid * fRankCoefficient * rcRankCoefficient * bidCoefficient * 1000;
+            double ecpm = modelCtcvrScore * fRankCoefficient * bid * 1000;
 
-            double h5Weight = 1.0D;
+            // h5 降权
+            double h5Weight = 1;
             if (openH5 > 0) {
                 h5Weight = this.getH5SuppressWeight(item);
             }
-            double flowCtlC = item.getScoreMap().getOrDefault("flowCtlC", 1.0D);
-            double flowCtlA = item.getScoreMap().getOrDefault("flowCtlA", 1.0D);
-            double guaranteeScoreCoefficient = getGuaranteeScoreCoefficient(isGuaranteedFlow, item.getExt());
-//            double score = ecpm
-//                    * flowCtlC
-//                    * flowCtlA
-//                    * h5Weight
-//                    * guaranteeScoreCoefficient;
-            double score = modelCtcvrScore * bid * 1000
-                    * flowCtlC
-                    * flowCtlA
-                    * h5Weight
-                    * guaranteeScoreCoefficient;
-
-            // 没有转化回传的广告主沿用配置 CPM,避免以不可靠的模型预估参与竞价。
-            if (noApiAdVerIds.contains(item.getAdVerId())) {
-                ecpm = item.getCpm();
-                score = item.getCpm() * cpmCoefficient / 1000;
-            }
 
-            // scoreMap 是排序日志的数据源;写入 eCPM 分子及实际参与 score 计算的全部外围因子。
-            item.getScoreMap().put("modelCtcvrScore", modelCtcvrScore);
+            // 控制曝光权重
+            Map<String, Map<String, String>> cidFeature = allCidFeature.getOrDefault(String.valueOf(item.getAdId()), EMPTY_NESTED_MAP);
+            Map<String, String> b3Feature = cidFeature.getOrDefault("alg_cid_feature_cid_action", EMPTY_STRING_MAP);
+            double expWeight = getExpWeight(b3Feature,
+                    expOldKey, expOldThreshold,
+                    expNewKey, expNewThreshold,
+                    expLowerWeight, expUpperWeight, expScale);
+
+            // 控制流量权重
+            double flowCtlC = item.getScoreMap().getOrDefault("flowCtlC", 1.0);
+            double flowCtlA = item.getScoreMap().getOrDefault("flowCtlA", 1.0);
+            double kFinal = item.getScoreMap().getOrDefault("kFinal", 1.0);
+
+            String layerAndCreativeWeightMapKey = getLayerAndCreativeWeightMapKey(peopleLayer, String.valueOf(item.getAdId()));
+            // 人群分层&创意的权重
+            double layerAndCreativeWeight = getLayerAndCreativeWeight(layerAndCreativeWeightMapKey);
+            double scoreCoefficient = creativeScoreCoefficient.getOrDefault(item.getAdId(), 1d);
+            double guaranteeScoreCoefficient = getGuaranteeScoreCoefficient(isGuaranteedFlow, item.getExt());
+            double score = flowCtlC * flowCtlA * h5Weight * expWeight * item.getLrScore() * bid * scoreCoefficient * guaranteeScoreCoefficient * layerAndCreativeWeight * kFinal;
+            item.getScoreMap().put("guaranteeScoreCoefficient", guaranteeScoreCoefficient);
+            item.getScoreMap().put("cpa", item.getCpa());
+            item.getScoreMap().put("cpm", item.getCpm());
             item.getScoreMap().put("bid", bid);
+            item.getScoreMap().put("cpmCoefficient", cpmCoefficient);
+            item.getScoreMap().put("scoreCoefficient", scoreCoefficient);
+            item.getScoreMap().put("h5", h5Weight);
             item.getScoreMap().put("fRankCoefficient", fRankCoefficient);
             item.getScoreMap().put("rcRankCoefficient", rcRankCoefficient);
             item.getScoreMap().put("bidCoefficient", bidCoefficient);
             item.getScoreMap().put("ecpm", ecpm);
-            item.getScoreMap().put("flowCtlC", flowCtlC);
-            item.getScoreMap().put("flowCtlA", flowCtlA);
-            item.getScoreMap().put("h5", h5Weight);
-            item.getScoreMap().put("guaranteeScoreCoefficient", guaranteeScoreCoefficient);
-            item.getScoreMap().put("score", score);
-
-
-            if (isGuaranteedFlow && item.getExt().get("isGuaranteed") != null && (boolean) item.getExt().get("isGuaranteed")) {
-                isGuaranteeType = true;
-            }
-            item.getScoreMap().put("cpa", item.getCpa());
-            item.getScoreMap().put("cpm", item.getCpm());
             item.getFeatureMap().putAll(userFeatureMap);
             item.getFeatureMap().putAll(sceneFeatureMap);
+
+            // 没有转化回传的广告主,使用后台配置的CPM
+            if (noApiAdVerIds.contains(item.getAdVerId())) {
+                score = item.getCpm() * cpmCoefficient / 1000;
+            }
             item.setScore(score);
         }
 
@@ -432,10 +465,17 @@ public class RankStrategyBy887 extends RankStrategyBasic {
                 participateCompetitionType.add("guarantee");
             }
             top1Item.getExt().put("participateCompetitionType", StringUtils.join(participateCompetitionType, ","));
-            top1Item.getExt().put("ecpm", top1Item.getScoreMap().get("ecpm"));
+            Double modelCtcvrScore = top1Item.getScoreMap().get("modelCtcvrScore");
+            Double ctcvrScore = top1Item.getScoreMap().get("ctcvrScore");
             if (scoreParam.getExpCodeSet().contains(checkoutEcpmExp)) {
+                top1Item.getExt().put("ecpm", ctcvrScore * top1Item.getCpa() * 1000);
                 String filterEcpmValue = paramsMap.getOrDefault("filterEcpm", filterEcpm);
                 top1Item.getExt().put("filterEcpm", filterEcpmValue);
+                if (noApiAdVerIds.contains(top1Item.getAdVerId())) {
+                    top1Item.getExt().put("ecpm", top1Item.getCpm());
+                }
+            } else {
+                top1Item.getExt().put("ecpm", modelCtcvrScore * top1Item.getCpa() * 1000);
             }
             putMetaFeature(top1Item, feature, reqFeature, sceneFeatureMap, request);
             top1Item.getExt().put("model", logModelName);
@@ -451,10 +491,6 @@ public class RankStrategyBy887 extends RankStrategyBasic {
         return result;
     }
 
-    private double normalizeCoefficient(Number coefficient) {
-        return coefficient == null ? 1.0D : coefficient.doubleValue();
-    }
-
     /**
      * 获取人群分层和创意的权重
      *
@@ -1089,4 +1125,31 @@ public class RankStrategyBy887 extends RankStrategyBasic {
         return Math.min(Math.max(lowerWeight, weight), upperWeight);
     }
 
+    private void calibrationCidCtcvr(List<AdRankItem> items, String modelName, Map<String, String> reqFeature,
+                                     double minValid, double maxValid,
+                                     double minVal, double maxVal) {
+        try {
+            String layer = reqFeature.get("layer_l4");
+            for (AdRankItem item : items) {
+                String cid = String.valueOf(item.getAdId());
+                Double diff = CreativeUserLayerDataHelper.getCopc(modelName, cid, layer);
+                if (null != diff) {
+                    double newDiff = Math.min(Math.max(minVal, diff), maxVal);
+                    if (newDiff < minValid || newDiff > maxValid) {
+                        double ctcvr = item.getLrScore() * newDiff;
+                        item.getScoreMap().put("cidCtcvrScore", ctcvr);
+                        item.getScoreMap().put("ctcvrScore", ctcvr);
+                        item.setLrScore(ctcvr);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("calibCidScore error", e);
+        }
+    }
+
+    private double normalizeCoefficient(Number coefficient) {
+        return coefficient == null ? 1.0D : coefficient.doubleValue();
+    }
+
 }