Kaynağa Gözat

增加校准ctcvrScore

xueyiming 3 gün önce
ebeveyn
işleme
320cd518a3

+ 1 - 1
ad-engine-commons/pom.xml

@@ -26,7 +26,7 @@
         <dependency>
             <groupId>com.tzld.piaoquan</groupId>
             <artifactId>recommend-feature-client</artifactId>
-            <version>1.1.22</version>
+            <version>1.1.24</version>
         </dependency>
         <dependency>
             <groupId>com.tzld.piaoquan</groupId>

+ 2 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/dto/AdPlatformCreativeDTO.java

@@ -50,4 +50,6 @@ public class AdPlatformCreativeDTO {
     private Long skuId;
 
     private String customer;
+
+    private Long customerId;
 }

+ 13 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/entity/CalibrationCtcvrData.java

@@ -0,0 +1,13 @@
+package com.tzld.piaoquan.ad.engine.service.entity;
+
+import lombok.Data;
+
+@Data
+public class CalibrationCtcvrData {
+
+    private Integer view;
+
+    private Double realCtcvr;
+
+    private Double pCtcvr;
+}

+ 115 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBasic.java

@@ -12,6 +12,7 @@ import com.tzld.piaoquan.ad.engine.commons.redis.AlgorithmRedisHelper;
 import com.tzld.piaoquan.ad.engine.commons.score.ScoreParam;
 import com.tzld.piaoquan.ad.engine.commons.util.DateUtils;
 import com.tzld.piaoquan.ad.engine.commons.util.ObjUtil;
+import com.tzld.piaoquan.ad.engine.service.entity.CalibrationCtcvrData;
 import com.tzld.piaoquan.ad.engine.service.entity.GuaranteeView;
 import com.tzld.piaoquan.ad.engine.service.feature.Feature;
 import com.tzld.piaoquan.ad.engine.service.feature.FeatureService;
@@ -24,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 
 import java.util.*;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -39,6 +41,9 @@ public abstract class RankStrategyBasic implements RankStrategy {
     protected String guaranteeExp;
     @ApolloJsonValue("${alpha:1.0}")
     protected Double alpha;
+
+    @ApolloJsonValue("${calibration.view.count:5000}")
+    protected Integer calibrationViewCount;
     @Autowired
     private FeatureService featureService;
     @Autowired
@@ -48,6 +53,11 @@ public abstract class RankStrategyBasic implements RankStrategy {
 
     String adPlatformGuaranteeKey = "ad:platform:guarantee:data:{date}:{adverId}";
 
+    String realCtcvrCustomerKey = "ad:platform:real:ctcvr:{model}:{layer}:{class}:{profession}:{customerId}";
+
+    String realCtcvrProfessionKey = "ad:platform:real:ctcvr:{model}:{layer}:{class}:{profession}";
+
+
     protected static final List<String> hasChannelScenes = new ArrayList<String>() {{
         add("DaiTou");
         add("GzhTouLiu");
@@ -366,4 +376,109 @@ public abstract class RankStrategyBasic implements RankStrategy {
             return new HashMap<>();
         }
     }
+
+    protected void calibrationCtcvrScore(List<AdRankItem> adRankItems, String mid, boolean isFilterUser, String modelName) {
+        // 1. 获取用户分层信息
+        Map<String, String> userLayer = getUserLayer(mid);
+        String layer = userLayer.getOrDefault("layer", "无曝光");
+        String clazz = userLayer.getOrDefault("class", "近期未出现");
+        if (isFilterUser) {
+            layer += "-炸";
+        }
+
+        // 2. 构建Key模板
+        String customerKeyTemplate = realCtcvrCustomerKey
+                .replace("{model}", modelName)
+                .replace("{layer}", layer)
+                .replace("{class}", clazz);
+
+        String professionKeyTemplate = realCtcvrProfessionKey
+                .replace("{model}", modelName)
+                .replace("{layer}", layer)
+                .replace("{class}", clazz);
+
+        // 3. 定义Key生成器
+        Function<AdRankItem, String> customerKeyFunc = e ->
+                (e.getProfession() != null && e.getCustomerId() != null)
+                        ? customerKeyTemplate.replace("{profession}", e.getProfession())
+                        .replace("{customerId}", String.valueOf(e.getCustomerId()))
+                        : null;
+
+        Function<AdRankItem, String> professionKeyFunc = e ->
+                (e.getProfession() != null)
+                        ? professionKeyTemplate.replace("{profession}", e.getProfession())
+                        : null;
+
+        // 4. 获取校准数据
+        Map<String, CalibrationCtcvrData> customerMap = getCtcvrMap(adRankItems, customerKeyFunc);
+        Map<String, CalibrationCtcvrData> professionMap = getCtcvrMap(adRankItems, professionKeyFunc);
+        // 5. 校准分数
+        for (AdRankItem item : adRankItems) {
+            CalibrationCtcvrData data = null;
+            String customerKey = customerKeyFunc.apply(item);
+            String professionKey = professionKeyFunc.apply(item);
+
+            if (customerKey != null) {
+                data = customerMap.get(customerKey);
+            }
+            if (data == null && professionKey != null) {
+                data = professionMap.get(professionKey);
+            }
+            item.getExt().put("calibrationCtcvrData", JSONObject.toJSONString(data));
+            if (data == null || data.getView() == null || data.getView() < calibrationViewCount) continue;
+
+            Map<String, Double> scoreMap = item.getScoreMap();
+            Double pCtcvr = data.getPCtcvr();
+            Double realCtcvr = data.getRealCtcvr();
+
+            if (pCtcvr != null && pCtcvr != 0.0 && realCtcvr != null && realCtcvr != 0.0) {
+                double diff = realCtcvr / pCtcvr;
+                if (Math.abs(diff - 1) >= 0.1) {
+                    Double ctcvrScore = scoreMap.get("ctcvrScore");
+                    if (ctcvrScore == null) {
+                        continue;
+                    }
+                    scoreMap.put("calibrationCtcvrScore", ctcvrScore * diff);
+                    item.setLrScore(ctcvrScore * diff);
+                }
+            }
+        }
+    }
+
+    // 通用CTR数据获取方法
+    private Map<String, CalibrationCtcvrData> getCtcvrMap(
+            List<AdRankItem> items,
+            Function<AdRankItem, String> keyGenerator
+    ) {
+        // 生成有效Key集合
+        List<String> redisKeys = items.stream()
+                .map(keyGenerator)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+
+        // 批量查询Redis
+        List<String> redisValues = algRedisHelper.mget(redisKeys);
+        Map<String, CalibrationCtcvrData> resultMap = new HashMap<>();
+
+        for (int i = 0; i < redisKeys.size(); i++) {
+            String val = redisValues.get(i);
+            if (StringUtils.isEmpty(val)) continue;
+
+            try {
+                JSONObject json = JSONObject.parseObject(val);
+                Integer view = json.getInteger("view");
+                Double ctcvr = json.getDouble("ctcvr");
+                Double pCtcvr = json.getDouble("pCtcvr");
+                CalibrationCtcvrData data = new CalibrationCtcvrData();
+                data.setView(view);
+                data.setRealCtcvr(ctcvr);
+                data.setPCtcvr(pCtcvr);
+                resultMap.put(redisKeys.get(i), data);
+            } catch (Exception e) {
+                log.error("getCtcvrMap error", e);
+            }
+        }
+        return resultMap;
+    }
 }

+ 2 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBy679.java

@@ -110,6 +110,8 @@ public class RankStrategyBy679 extends RankStrategyBasic {
                     adRankItem.setCampaignId(dto.getCampaignId());
                     adRankItem.setCpm(ObjUtil.nullOrDefault(dto.getCpm(), 90).doubleValue());
                     adRankItem.setSkuId(dto.getSkuId());
+                    adRankItem.setCustomerId(dto.getCustomerId());
+                    adRankItem.setProfession(dto.getProfession());
                     adRankItem.setRandom(random.nextInt(1000));
                     if (noApiAdVerIds.contains(dto.getAdVerId())) {
                         adRankItem.getExt().put("isApi", "0");

+ 2 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBy680.java

@@ -148,6 +148,8 @@ public class RankStrategyBy680 extends RankStrategyBasic {
                     adRankItem.setCampaignId(dto.getCampaignId());
                     adRankItem.setCpm(ObjUtil.nullOrDefault(dto.getCpm(), 90).doubleValue());
                     adRankItem.setSkuId(dto.getSkuId());
+                    adRankItem.setCustomerId(dto.getCustomerId());
+                    adRankItem.setProfession(dto.getProfession());
                     adRankItem.setRandom(random.nextInt(1000));
                     if (noApiAdVerIds.contains(dto.getAdVerId())) {
                         adRankItem.getExt().put("isApi", "0");

+ 2 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBy683.java

@@ -120,6 +120,8 @@ public class RankStrategyBy683 extends RankStrategyBasic {
                     adRankItem.setCampaignId(dto.getCampaignId());
                     adRankItem.setCpm(ObjUtil.nullOrDefault(dto.getCpm(), 90).doubleValue());
                     adRankItem.setSkuId(dto.getSkuId());
+                    adRankItem.setCustomerId(dto.getCustomerId());
+                    adRankItem.setProfession(dto.getProfession());
                     adRankItem.setRandom(random.nextInt(1000));
                     if (noApiAdVerIds.contains(dto.getAdVerId())) {
                         adRankItem.getExt().put("isApi", "0");

+ 4 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBy688.java

@@ -185,6 +185,8 @@ public class RankStrategyBy688 extends RankStrategyBasic {
                     adRankItem.setCampaignId(dto.getCampaignId());
                     adRankItem.setCpm(ObjUtil.nullOrDefault(dto.getCpm(), 90).doubleValue());
                     adRankItem.setSkuId(dto.getSkuId());
+                    adRankItem.setCustomerId(dto.getCustomerId());
+                    adRankItem.setProfession(dto.getProfession());
                     adRankItem.setRandom(random.nextInt(1000));
                     if (noApiAdVerIds.contains(dto.getAdVerId())) {
                         adRankItem.getExt().put("isApi", "0");
@@ -312,6 +314,8 @@ public class RankStrategyBy688 extends RankStrategyBasic {
             item.getScoreMap().put("originCtcvrScore", originalScore);
             item.getScoreMap().put("ctcvrScore", calibratedScore);
         }
+        //校准Ctcvr
+        calibrationCtcvrScore(result, request.getMid(), request.getIsFilterUser(), "dnn");
 
         // loop
         double cpmCoefficient = weightParam.getOrDefault("cpmCoefficient", 0.9);