Prechádzať zdrojové kódy

Merge branch 'layer_customer_flow_control' of algorithm/ad-engine into master

jiachanghui 2 týždňov pred
rodič
commit
8a7e819afe

+ 75 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/helper/LayerCustomerFlowControlDataHelper.java

@@ -0,0 +1,75 @@
+package com.tzld.piaoquan.ad.engine.commons.helper;
+
+import com.tzld.piaoquan.ad.engine.commons.redis.AlgorithmRedisHelper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.tuple.Pair;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@Component
+public class LayerCustomerFlowControlDataHelper {
+    @Autowired
+    protected AlgorithmRedisHelper algRedisHelper;
+
+    private static final String redisKey = "ad:engine:strategy:flowcontrol:layer_customer";
+    private static final String keyFormat = "%s:%s:%s";
+
+    private volatile static Map<String, Pair<Double, Double>> layerCustomerMap = Collections.emptyMap();
+
+    // 服务启动时初始化数据
+    @PostConstruct
+    public void init() {
+        Map<String, Pair<Double, Double>> map = updateLayerCustomerMap();
+        layerCustomerMap = Collections.unmodifiableMap(map);
+    }
+
+    // 每5分钟更新一次数据
+    @Scheduled(fixedRate = 5 * 60 * 1000)
+    public void scheduledUpdate() {
+        Map<String, Pair<Double, Double>> map = updateLayerCustomerMap();
+        layerCustomerMap = Collections.unmodifiableMap(map);
+    }
+
+    public static Pair<Double, Double> getWeight(String layer, String profession, String customerId) {
+        if (null != layerCustomerMap) {
+            String key = String.format(keyFormat, layer, profession, customerId);
+            if (layerCustomerMap.containsKey(key)) {
+                return layerCustomerMap.get(key);
+            }
+        }
+        return null;
+    }
+
+    private Map<String, Pair<Double, Double>> updateLayerCustomerMap() {
+        Map<String, Pair<Double, Double>> tmpLayerCustomerMap = new HashMap<>();
+        try {
+            String value = algRedisHelper.get(redisKey);
+            if (null != value && !value.isEmpty()) {
+                String[] cells = value.split(",");
+                for (String cell : cells) {
+                    String[] pair = cell.split("_");
+                    if (2 == pair.length) {
+                        String key = pair[0];
+                        String[] values = pair[1].split(":");
+                        if (2 == values.length) {
+                            double cpmDiff = Double.parseDouble(values[0]);
+                            double viewRate = Double.parseDouble(values[1]);
+                            tmpLayerCustomerMap.put(key, Pair.of(cpmDiff, viewRate));
+                        }
+                    }
+                }
+            }
+            log.info("update layer customer flow control success size={}", tmpLayerCustomerMap.size());
+        } catch (Exception e) {
+            log.error("update layer customer flow control error", e);
+        }
+        return tmpLayerCustomerMap;
+    }
+}

+ 54 - 1
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBy847.java

@@ -5,6 +5,7 @@ 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.helper.LayerCustomerFlowControlDataHelper;
 import com.tzld.piaoquan.ad.engine.commons.param.RankRecommendRequestParam;
 import com.tzld.piaoquan.ad.engine.commons.score.ScoreParam;
 import com.tzld.piaoquan.ad.engine.commons.score.ScorerUtils;
@@ -19,6 +20,7 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.MapUtils;
 import org.apache.commons.lang.math.NumberUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 import org.xm.Similarity;
@@ -370,6 +372,20 @@ public class RankStrategyBy847 extends RankStrategyBasic {
         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"));
+
+        // 控制流量参数
+        String layer = reqFeature.get("layer_l4");
+        double cpmPow = NumberUtils.toDouble(paramsMap.getOrDefault("cpmPow", "0.3"));
+        double lowerCpmWeight = NumberUtils.toDouble(paramsMap.getOrDefault("lowerCpmWeight", "1.0"));
+        double upperCpmWeight = NumberUtils.toDouble(paramsMap.getOrDefault("upperCpmWeight", "1.2"));
+        double flowPow = NumberUtils.toDouble(paramsMap.getOrDefault("flowPow", "1.2"));
+        double lowerFlowWeight = NumberUtils.toDouble(paramsMap.getOrDefault("lowerFlowWeight", "0.77"));
+        double upperFlowWeight = NumberUtils.toDouble(paramsMap.getOrDefault("upperFlowWeight", "1.0"));
+
+        double hitViewRate = NumberUtils.toDouble(paramsMap.getOrDefault("hitViewRate", "0.05"));
+        double plusViewRate = NumberUtils.toDouble(paramsMap.getOrDefault("plusViewRate", "20"));
+        double viewRatePow = NumberUtils.toDouble(paramsMap.getOrDefault("viewRatePow", "0.2"));
+        double viewRateScale = NumberUtils.toDouble(paramsMap.getOrDefault("viewRateScale", "0.5491"));
         for (AdRankItem item : result) {
             double bid = item.getCpa();
             if (scoreParam.getExpCodeSet().contains(correctCpaExp1) || scoreParam.getExpCodeSet().contains(correctCpaExp2)) {
@@ -396,12 +412,18 @@ public class RankStrategyBy847 extends RankStrategyBasic {
                     expNewKey, expNewThreshold,
                     expLowerWeight, expUpperWeight, expScale);
 
+            // 分层控制流量
+            double flowWeight = getFlowControlWeight(layer, item,
+                    cpmPow, lowerCpmWeight, upperCpmWeight,
+                    flowPow, lowerFlowWeight, upperFlowWeight,
+                    hitViewRate, plusViewRate, viewRatePow, viewRateScale);
+
             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 = h5Weight * expWeight * item.getLrScore() * bid * scoreCoefficient * guaranteeScoreCoefficient * layerAndCreativeWeight;
+            double score = flowWeight * h5Weight * expWeight * item.getLrScore() * bid * scoreCoefficient * guaranteeScoreCoefficient * layerAndCreativeWeight;
             item.getScoreMap().put("guaranteeScoreCoefficient", guaranteeScoreCoefficient);
             item.getScoreMap().put("cpa", item.getCpa());
             item.getScoreMap().put("cpm", item.getCpm());
@@ -409,6 +431,7 @@ public class RankStrategyBy847 extends RankStrategyBasic {
             item.getScoreMap().put("cpmCoefficient", cpmCoefficient);
             item.getScoreMap().put("scoreCoefficient", scoreCoefficient);
             item.getScoreMap().put("h5", h5Weight);
+            item.getScoreMap().put("flow", flowWeight);
             item.getFeatureMap().putAll(userFeatureMap);
             item.getFeatureMap().putAll(sceneFeatureMap);
 
@@ -1036,4 +1059,34 @@ public class RankStrategyBy847 extends RankStrategyBasic {
             log.error("calibCidScore error", e);
         }
     }
+
+    private double getFlowControlWeight(String layer, AdRankItem item,
+                                        double cpmPow, double lowerCpmWeight, double upperCpmWeight,
+                                        double flowPow, double lowerFlowWeight, double upperFlowWeight,
+                                        double hitViewRate, double plusViewRate, double viewRatePow, double viewRateScale) {
+        try {
+            String profession = item.getProfession();
+            String customerId = String.valueOf(item.getCustomerId());
+            Pair<Double, Double> pair = LayerCustomerFlowControlDataHelper.getWeight(layer, profession, customerId);
+            if (null != pair) {
+                double cpmWeight = 1;
+                double flowWeight = 1;
+                double cpmDiff = pair.getLeft();
+                double viewRate = pair.getRight();
+                if (cpmDiff > 0) {
+                    cpmWeight = Math.pow(cpmDiff, cpmPow);
+                    cpmWeight = Math.min(Math.max(lowerCpmWeight, cpmWeight), upperCpmWeight);
+                }
+                if (viewRate > hitViewRate) {
+                    flowWeight = 1 / Math.pow(viewRate * 100 + plusViewRate, viewRatePow) / viewRateScale;
+                    flowWeight = Math.pow(flowWeight, flowPow);
+                    flowWeight = Math.min(Math.max(lowerFlowWeight, flowWeight), upperFlowWeight);
+                }
+                return cpmWeight * flowWeight;
+            }
+        } catch (Exception e) {
+            log.error("flowWeight error", e);
+        }
+        return 1;
+    }
 }