Selaa lähdekoodia

Merge branch 'feature_20260622_zhaohaipeng_feature_optimize_adaptive' into pre-master

zhaohaipeng 1 kuukausi sitten
vanhempi
commit
dfdab5303c
21 muutettua tiedostoa jossa 681 lisäystä ja 39 poistoa
  1. 1 1
      ad-engine-commons/pom.xml
  2. 2 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/dto/AdPlatformCreativeDTO.java
  3. 118 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/helper/CreativeKFinalDataHelper.java
  4. 75 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/helper/LayerAgentFlowControlDataHelper.java
  5. 75 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/helper/LayerCustomerFlowControlDataHelper.java
  6. 20 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/RedisTemplateConfig.java
  7. 10 10
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/score/model/PAIModelV1.java
  8. 1 1
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/RootSessionIdExpConfig.java
  9. 68 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/RootSessionIdTailUtil.java
  10. 12 0
      ad-engine-server/src/main/resources/application-dev.yml
  11. 12 0
      ad-engine-server/src/main/resources/application-pre.yml
  12. 12 0
      ad-engine-server/src/main/resources/application-prod.yml
  13. 9 0
      ad-engine-server/src/main/resources/application-test.yml
  14. 26 0
      ad-engine-server/src/test/java/com/tzld/piaoquan/ad/engine/service/FeatureServiceTest.java
  15. 12 4
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/feature/FeatureService.java
  16. 9 19
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/impl/RankServiceImpl.java
  17. 161 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBasic.java
  18. 15 1
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBy847.java
  19. 14 1
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBy849.java
  20. 18 1
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBy851.java
  21. 11 1
      pom.xml

+ 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.35</version>
+            <version>1.1.36</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

@@ -72,4 +72,6 @@ public class AdPlatformCreativeDTO {
     private String adSkuCode;
 
     private String adSkuName;
+
+    private Long agentId;
 }

+ 118 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/helper/CreativeKFinalDataHelper.java

@@ -0,0 +1,118 @@
+package com.tzld.piaoquan.ad.engine.commons.helper;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+@Slf4j
+@Component
+public class CreativeKFinalDataHelper {
+
+    @Resource(name = "newAdRedisTemplate")
+    private RedisTemplate<String, String> newAdRedisTemplate;
+
+    private static final String CREATIVE_CODE_SET_KEY_FORMAT = "ad:addv:cost:current:creative:code:%s";
+    private static final String CREATIVE_K_KEY_FORMAT = "ad:addv:cost:k:%s";
+
+    /**
+     * Apollo 动态配置:kFlow 转换参数
+     * 配置格式:{"kFlowMax": 1, "kFlowMin": 0.95, "kMin": 0.8}
+     */
+    @ApolloJsonValue("${ad.addv.kfinal.flow.config:{}}")
+    private KFlowConfig kFlowConfig;
+
+    private volatile static Map<String, Double> creativeKFinalMap = Collections.emptyMap();
+
+    @Data
+    static class KFlowConfig {
+        private double kFlowMax = 1.0;
+        private double kFlowMin = 0.95;
+        private double kMin = 0.8;
+    }
+
+    // 服务启动时初始化数据
+    @PostConstruct
+    public void init() {
+        Map<String, Double> map = updateCreativeKFinalMap();
+        creativeKFinalMap = Collections.unmodifiableMap(map);
+    }
+
+    // 每1分钟更新一次数据
+    @Scheduled(fixedRate = 60 * 1000)
+    public void scheduledUpdate() {
+        Map<String, Double> map = updateCreativeKFinalMap();
+        creativeKFinalMap = Collections.unmodifiableMap(map);
+    }
+
+    public static Double getKFinal(String creativeCode) {
+        if (creativeCode != null && creativeKFinalMap != null) {
+            return creativeKFinalMap.get(creativeCode);
+        }
+        return null;
+    }
+
+    private Map<String, Double> updateCreativeKFinalMap() {
+        Map<String, Double> tmpMap = new HashMap<>();
+        try {
+            String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
+            String setKey = String.format(CREATIVE_CODE_SET_KEY_FORMAT, today);
+            Set<String> creativeCodes = newAdRedisTemplate.opsForSet().members(setKey);
+            if (CollectionUtils.isEmpty(creativeCodes)) {
+                log.info("creative kFinal: code set is empty for date={}", today);
+                return tmpMap;
+            }
+            for (String creativeCode : creativeCodes) {
+                try {
+                    String kKey = String.format(CREATIVE_K_KEY_FORMAT, creativeCode);
+                    String value = newAdRedisTemplate.opsForValue().get(kKey);
+                    if (StringUtils.isNotBlank(value)) {
+                        JSONObject jsonObject = JSON.parseObject(value);
+                        Double kFinal = jsonObject.getDouble("kFinal");
+                        if (kFinal != null) {
+                            double kFlow = computeKFlow(kFinal);
+                            tmpMap.put(creativeCode, kFlow);
+                        }
+                    }
+                } catch (Exception e) {
+                    log.error("update creative kFinal error creativeCode={}", creativeCode, e);
+                }
+            }
+            log.info("update creative kFinal map success size={}", tmpMap.size());
+        } catch (Exception e) {
+            log.error("update creative kFinal map error", e);
+        }
+        return tmpMap;
+    }
+
+    /**
+     * 根据 kFinal 计算 kFlow:
+     * 1. kFlow = kFlowMin + (kFinal - kMin) / (1 - kMin) * (kFlowMax - kFlowMin)
+     * 2. kFlow = clamp(kFlow, kFlowMin, kFlowMax)
+     */
+    private double computeKFlow(double kFinal) {
+        double kFlowMax = kFlowConfig != null ? kFlowConfig.getKFlowMax() : 1.0;
+        double kFlowMin = kFlowConfig != null ? kFlowConfig.getKFlowMin() : 0.95;
+        double kMin = kFlowConfig != null ? kFlowConfig.getKMin() : 0.8;
+        if(kMin >=1){
+            return 1d;
+        }
+        double kFlow = kFlowMin + (kFinal - kMin) / (1.0 - kMin) * (kFlowMax - kFlowMin);
+        return Math.max(kFlowMin, Math.min(kFlowMax, kFlow));
+    }
+}

+ 75 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/helper/LayerAgentFlowControlDataHelper.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 LayerAgentFlowControlDataHelper {
+    @Autowired
+    protected AlgorithmRedisHelper algRedisHelper;
+
+    private static final String redisKey = "ad:engine:strategy:flowcontrol:layer_agent";
+    private static final String keyFormat = "%s:%s:%s";
+
+    private volatile static Map<String, Pair<Double, Double>> layerAgentMap = Collections.emptyMap();
+
+    // 服务启动时初始化数据
+    @PostConstruct
+    public void init() {
+        Map<String, Pair<Double, Double>> map = updateLayerAgentMap();
+        layerAgentMap = Collections.unmodifiableMap(map);
+    }
+
+    // 每5分钟更新一次数据
+    @Scheduled(fixedRate = 5 * 60 * 1000)
+    public void scheduledUpdate() {
+        Map<String, Pair<Double, Double>> map = updateLayerAgentMap();
+        layerAgentMap = Collections.unmodifiableMap(map);
+    }
+
+    public static Pair<Double, Double> getWeight(String layer, String profession, String agentId) {
+        if (null != layerAgentMap) {
+            String key = String.format(keyFormat, layer, profession, agentId);
+            if (layerAgentMap.containsKey(key)) {
+                return layerAgentMap.get(key);
+            }
+        }
+        return null;
+    }
+
+    private Map<String, Pair<Double, Double>> updateLayerAgentMap() {
+        Map<String, Pair<Double, Double>> tmpLayerAgentMap = 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]);
+                            tmpLayerAgentMap.put(key, Pair.of(cpmDiff, viewRate));
+                        }
+                    }
+                }
+            }
+            log.info("update layer agent flow control success size={}", tmpLayerAgentMap.size());
+        } catch (Exception e) {
+            log.error("update layer agent flow control error", e);
+        }
+        return tmpLayerAgentMap;
+    }
+}

+ 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;
+    }
+}

+ 20 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/RedisTemplateConfig.java

@@ -68,6 +68,26 @@ public class RedisTemplateConfig {
         return new LettuceConnectionFactory(adRedisConfig, lettuceClientConfiguration);
     }
 
+
+    @Bean
+    @ConfigurationProperties(prefix = "spring.redis-ad-cache")
+    public RedisStandaloneConfiguration newAdRedisConfig() {
+        return new RedisStandaloneConfiguration();
+    }
+
+    @Bean("newAdRedisFactory")
+    public LettuceConnectionFactory newAdRedisFactory(GenericObjectPoolConfig<LettucePoolingClientConfiguration> config,@Qualifier("newAdRedisConfig") RedisStandaloneConfiguration adRedisConfig) {
+        LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
+        return new LettuceConnectionFactory(adRedisConfig, lettuceClientConfiguration);
+    }
+
+    @Bean(name = "newAdRedisTemplate")
+    public RedisTemplate<String, String> newAdRedisTemplate(@Qualifier("newAdRedisFactory") RedisConnectionFactory adRedisFactory) {
+        return buildRedisTemplateByString(adRedisFactory);
+    }
+
+
+
     /**
      * 构建redisTemplate 使用string序列化
      *

+ 10 - 10
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/score/model/PAIModelV1.java

@@ -119,22 +119,22 @@ public class PAIModelV1 {
             "timediff_view", "vid_rank_ctcvr_14d", "vid_rank_ctcvr_1d", "vid_rank_ctcvr_3d", "vid_rank_ctcvr_7d",
             "vid_rank_ctr_14d", "vid_rank_ctr_1d", "vid_rank_ctr_3d", "vid_rank_ctr_7d", "vid_rank_ecpm_14d", "vid_rank_ecpm_1d",
             "vid_rank_ecpm_3d", "vid_rank_ecpm_7d",
-            "j1_3d_ctcvr", "j1_3d_ctr",
-            "j2_3d_ctcvr", "j2_3d_ctr",
-            "j3_3h_ctcvr", "j3_3h_ctr", "j3_3d_ctcvr", "j3_3d_ctr",
-            "j4_3d_ctcvr", "j4_3d_ctr",
-            "j5_3d_ctcvr", "j5_3d_ctr",
+            "j1_3d_conver_x_log_view", "j1_3d_conver", "j1_3d_ctcvr", "j1_3d_ctr",
+            "j2_3d_conver_x_log_view", "j2_3d_conver", "j2_3d_ctcvr", "j2_3d_ctr",
+            "j3_3h_conver_x_log_view", "j3_3h_conver", "j3_3h_ctcvr", "j3_3h_ctr", "j3_3d_conver_x_log_view", "j3_3d_conver", "j3_3d_ctcvr", "j3_3d_ctr",
+            "j4_3d_conver_x_log_view", "j4_3d_conver", "j4_3d_ctcvr", "j4_3d_ctr",
+            "j5_3d_conver_x_log_view", "j5_3d_conver", "j5_3d_ctcvr", "j5_3d_ctr",
             "j6_1h_click", "j6_1h_conver", "j6_1h_conver_x_ctcvr", "j6_1h_conver_x_log_view", "j6_1h_ctcvr", "j6_1h_ctr", "j6_1h_cvr", "j6_1h_ecpm",
             "j6_2h_click", "j6_2h_conver", "j6_2h_conver_x_ctcvr", "j6_2h_conver_x_log_view", "j6_2h_ctcvr", "j6_2h_ctr", "j6_2h_cvr", "j6_2h_ecpm",
             "j6_3h_click", "j6_3h_conver", "j6_3h_conver_x_ctcvr", "j6_3h_conver_x_log_view", "j6_3h_ctcvr", "j6_3h_ctr", "j6_3h_cvr", "j6_3h_ecpm",
             "j6_6h_ctr", "j6_6h_ecpm",
             "j6_12h_click", "j6_12h_conver", "j6_12h_conver_x_ctcvr", "j6_12h_conver_x_log_view", "j6_12h_ctcvr", "j6_12h_ctr", "j6_12h_cvr", "j6_12h_ecpm",
             "j6_3d_click", "j6_3d_conver", "j6_3d_conver_x_ctcvr", "j6_3d_conver_x_log_view", "j6_3d_ctcvr", "j6_3d_ctr", "j6_3d_cvr", "j6_3d_ecpm",
-            "j7_3d_ctcvr", "j7_3d_ctr",
-            "j8_3d_ctcvr", "j8_3d_ctr",
-            "j9_3d_ctcvr", "j9_3d_ctr", "j9_3h_ctcvr", "j9_3h_ctr",
-            "j10_3d_ctcvr", "j10_3d_ctr",
-            "j11_3d_ctcvr", "j11_3d_ctr"
+            "j7_3d_conver_x_log_view", "j7_3d_conver", "j7_3d_ctcvr", "j7_3d_ctr",
+            "j8_3d_conver_x_log_view", "j8_3d_conver", "j8_3d_ctcvr", "j8_3d_ctr",
+            "j9_3d_conver_x_log_view", "j9_3d_conver", "j9_3d_ctcvr", "j9_3d_ctr", "j9_3h_conver_x_log_view", "j9_3h_conver", "j9_3h_ctcvr", "j9_3h_ctr",
+            "j10_3d_conver_x_log_view", "j10_3d_conver", "j10_3d_ctcvr", "j10_3d_ctr",
+            "j11_3d_conver_x_log_view", "j11_3d_conver", "j11_3d_ctcvr", "j11_3d_ctr"
     };
 
     /**

+ 1 - 1
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/entity/RootSessionIdExpConfig.java → ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/RootSessionIdExpConfig.java

@@ -1,4 +1,4 @@
-package com.tzld.piaoquan.ad.engine.service.entity;
+package com.tzld.piaoquan.ad.engine.commons.util;
 
 import lombok.Data;
 

+ 68 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/RootSessionIdTailUtil.java

@@ -0,0 +1,68 @@
+package com.tzld.piaoquan.ad.engine.commons.util;
+
+import com.tzld.piaoquan.ad.engine.commons.score.ScoreParam;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+@Slf4j
+public class RootSessionIdTailUtil {
+    public static final int rankTailN = 6;
+    public static final int reRankTailN = 7;
+    public static final long allApp = 999;
+
+    // appType: 999 表示全量
+    public static List<RootSessionIdExpConfig> getRootSessionIdTailConfig(ScoreParam scoreParam, int nFromEnd, List<RootSessionIdExpConfig> rootSessionIdConfig) {
+        try {
+            List<RootSessionIdExpConfig> hitConfigs = new ArrayList<>();
+            if (CollectionUtils.isNotEmpty(rootSessionIdConfig)) {
+                Long appType = scoreParam.getAppType();
+                String tail = getNthCharFromEnd(scoreParam.getRootSessionId(), nFromEnd);
+                for (RootSessionIdExpConfig item : rootSessionIdConfig) {
+                    Set<Long> appTypeSet = item.getAppType();
+                    if (null == appTypeSet) {
+                        continue;
+                    }
+
+                    // match all
+                    if (appTypeSet.contains(allApp)) {
+                        hitConfigs.add(item);
+                        continue;
+                    }
+                    // match app & tail
+                    Set<String> tailSet = item.getTail();
+                    if (null != appType && null != tail && null != tailSet) {
+                        if (appTypeSet.contains(appType) && tailSet.contains(tail)) {
+                            hitConfigs.add(item);
+                            continue;
+                        }
+                    }
+                }
+            }
+            return hitConfigs;
+        } catch (Exception e) {
+            log.error("rootSessionId尾号配置异常", e);
+        }
+        return Collections.emptyList();
+    }
+
+    public static String getNthCharFromEnd(String rootSessionId, int nFromEnd) {
+        if (StringUtils.isBlank(rootSessionId) || nFromEnd < 1) {
+            return null;
+        }
+
+        // 计算开始位置
+        int position = rootSessionId.length() - nFromEnd;
+
+        // 检查位置是否有效
+        if (position < 0) {
+            return null;
+        }
+        return String.valueOf(rootSessionId.charAt(position));
+    }
+}

+ 12 - 0
ad-engine-server/src/main/resources/application-dev.yml

@@ -46,6 +46,18 @@ spring:
         max-active: 1000 # 连接池最大连接数(使用负值表示没有限制) 默认 8
         max-idle: 20 # 连接池中的最大空闲连接 默认 8
         min-idle: 10 # 连接池中的最小空闲连接 默认 0
+
+  redis-ad-cache:
+    hostName: r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 1000 # 连接池最大连接数(使用负值表示没有限制) 默认 8
+        max-idle: 20 # 连接池中的最大空闲连接 默认 8
+        min-idle: 10 # 连接池中的最小空闲连接 默认 0
+
   redis-algorithm:
     hostName: r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com
     port: 6379

+ 12 - 0
ad-engine-server/src/main/resources/application-pre.yml

@@ -45,6 +45,18 @@ spring:
         max-active: 50 # 连接池最大连接数(使用负值表示没有限制) 默认 8
         max-idle: 20 # 连接池中的最大空闲连接 默认 8
         min-idle: 10 # 连接池中的最小空闲连接 默认 0`
+
+  redis-ad-cache:
+    hostName: r-bp1wxi22yugkp044xa.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 1000 # 连接池最大连接数(使用负值表示没有限制) 默认 8
+        max-idle: 20 # 连接池中的最大空闲连接 默认 8
+        min-idle: 10 # 连接池中的最小空闲连接 默认 0
+
   redis-algorithm:
     hostName: r-bp1fogs2mflr1ybfot.redis.rds.aliyuncs.com
     port: 6379

+ 12 - 0
ad-engine-server/src/main/resources/application-prod.yml

@@ -46,6 +46,18 @@ spring:
         max-active: 1000 # 连接池最大连接数(使用负值表示没有限制) 默认 8
         max-idle: 20 # 连接池中的最大空闲连接 默认 8
         min-idle: 10 # 连接池中的最小空闲连接 默认 0
+
+  redis-ad-cache:
+    hostName: r-bp1wxi22yugkp044xa.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 1000 # 连接池最大连接数(使用负值表示没有限制) 默认 8
+        max-idle: 20 # 连接池中的最大空闲连接 默认 8
+        min-idle: 10 # 连接池中的最小空闲连接 默认 0
+
   redis-algorithm:
     hostName: r-bp1fogs2mflr1ybfot.redis.rds.aliyuncs.com
     port: 6379

+ 9 - 0
ad-engine-server/src/main/resources/application-test.yml

@@ -40,6 +40,15 @@ spring:
     port: 6379
     password: Wqsd@2019
     timeout: 1000
+
+  redis-ad-cache:
+    hostName: r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+
+
+
   redis-algorithm:
     hostName: r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com
 #    hostName: r-bp1fogs2mflr1ybfot.redis.rds.aliyuncs.com

+ 26 - 0
ad-engine-server/src/test/java/com/tzld/piaoquan/ad/engine/service/FeatureServiceTest.java

@@ -0,0 +1,26 @@
+package com.tzld.piaoquan.ad.engine.service;
+
+import com.tzld.piaoquan.ad.engine.server.Application;
+import com.tzld.piaoquan.ad.engine.service.feature.FeatureService;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest(classes = Application.class)
+public class FeatureServiceTest {
+
+
+    @Autowired
+    private FeatureService featureService;
+
+    @Test
+    public void featureV3OptimizeTest() {
+
+        // List<FeatureKeyProto> protos = new ArrayList<>();
+        // protos.add(featureService.genWithKeyMap("o:%s:%s", "alg_videoid_feature", "10035427", ImmutableMap.of("videoid", "68781839")));
+
+        // System.out.println(featureService.invokeFeatureService(protos));
+    }
+
+
+}

+ 12 - 4
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/feature/FeatureService.java

@@ -13,6 +13,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
 import java.util.*;
@@ -21,6 +22,9 @@ import java.util.*;
 @Component
 public class FeatureService {
 
+    @Value("${feature.service.optimize.switch}")
+    private Boolean featureServiceOptimizeSwtich;
+
     @Autowired
     private FeatureV2RemoteService remoteService;
 
@@ -430,10 +434,14 @@ public class FeatureService {
         for (Map.Entry<String, String> entry : metaFeatureMap.entrySet()) {
             String key = entry.getKey();
             try {
-                Map<String, String> valueMap = JSONUtils.fromJson(entry.getValue(), new TypeToken<Map<String, String>>() {
-                }, Collections.emptyMap());
-                String value = valueMap.getOrDefault("feature", "{}");
-                newFeatureMap.put(key, value);
+                if (Boolean.TRUE.equals(featureServiceOptimizeSwtich)) {
+                    newFeatureMap.put(key, entry.getValue());
+                } else {
+                    Map<String, String> valueMap = JSONUtils.fromJson(entry.getValue(), new TypeToken<Map<String, String>>() {
+                    }, Collections.emptyMap());
+                    String value = valueMap.getOrDefault("feature", "{}");
+                    newFeatureMap.put(key, value);
+                }
             } catch (Exception e) {
                 log.error("featureStrCover error: ", e);
             }

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

@@ -6,8 +6,8 @@ import com.tzld.piaoquan.ad.engine.commons.dto.AdPlatformCreativeDTO;
 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;
-import com.tzld.piaoquan.ad.engine.commons.util.RootSessionIdUtil;
-import com.tzld.piaoquan.ad.engine.service.entity.RootSessionIdExpConfig;
+import com.tzld.piaoquan.ad.engine.commons.util.RootSessionIdExpConfig;
+import com.tzld.piaoquan.ad.engine.commons.util.RootSessionIdTailUtil;
 import com.tzld.piaoquan.ad.engine.service.log.LogHubService;
 import com.tzld.piaoquan.ad.engine.service.predict.helper.NewExpInfoHelper;
 import com.tzld.piaoquan.ad.engine.service.predict.param.ThresholdPredictModelParam;
@@ -56,8 +56,6 @@ public class RankServiceImpl implements RankService {
     private LogHubService logHubService;
     @Autowired
     private AdCreativeFeatureContainer adCreativeFeatureContainer;
-    @Autowired
-    private RootSessionIdUtil rootSessionIdUtil;
 
     @Autowired
     private RankStrategyBy680 rankStrategyBy680;
@@ -139,21 +137,13 @@ public class RankServiceImpl implements RankService {
 
     private String getRankStrategyCode(ScoreParam scoreParam) {
         try {
-            if (CollectionUtils.isNotEmpty(rankRootSessionIdConfig)) {
-                Long appType = scoreParam.getAppType();
-                String rootSessionId = scoreParam.getRootSessionId();
-                if (null != appType && null != rootSessionId) {
-                    String tail = rootSessionIdUtil.getTail(rootSessionId);
-                    if (null != tail) {
-                        for (RootSessionIdExpConfig item : rankRootSessionIdConfig) {
-                            if (null != item.getAppType() && null != item.getTail()) {
-                                if (item.getAppType().contains(appType) && item.getTail().contains(tail)) {
-                                    if (null != item.getConfig() && item.getConfig().containsKey("rank")) {
-                                        return item.getConfig().get("rank");
-                                    }
-                                }
-                            }
-                        }
+            List<RootSessionIdExpConfig> expConfigs = RootSessionIdTailUtil.getRootSessionIdTailConfig(scoreParam, RootSessionIdTailUtil.rankTailN, rankRootSessionIdConfig);
+            if (!expConfigs.isEmpty()) {
+                RootSessionIdExpConfig expConfig = expConfigs.get(0);
+                if (null != expConfig && null != expConfig.getConfig()) {
+                    String expCode = expConfig.getConfig().get("rank");
+                    if (null != expCode) {
+                        return expCode;
                     }
                 }
             }

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

@@ -8,6 +8,9 @@ import com.tzld.piaoquan.ad.engine.commons.dto.AdPlatformCreativeDTO;
 import com.tzld.piaoquan.ad.engine.commons.enums.CrowdLayerEnum;
 import com.tzld.piaoquan.ad.engine.commons.enums.FilterTypeEnum;
 import com.tzld.piaoquan.ad.engine.commons.enums.RedisPrefixEnum;
+import com.tzld.piaoquan.ad.engine.commons.helper.CreativeKFinalDataHelper;
+import com.tzld.piaoquan.ad.engine.commons.helper.LayerAgentFlowControlDataHelper;
+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.redis.AdRedisHelper;
 import com.tzld.piaoquan.ad.engine.commons.redis.AlgorithmRedisHelper;
@@ -15,6 +18,8 @@ import com.tzld.piaoquan.ad.engine.commons.score.ScoreParam;
 import com.tzld.piaoquan.ad.engine.commons.thread.ThreadPoolFactory;
 import com.tzld.piaoquan.ad.engine.commons.util.DateUtils;
 import com.tzld.piaoquan.ad.engine.commons.util.ObjUtil;
+import com.tzld.piaoquan.ad.engine.commons.util.RootSessionIdExpConfig;
+import com.tzld.piaoquan.ad.engine.commons.util.RootSessionIdTailUtil;
 import com.tzld.piaoquan.ad.engine.service.entity.*;
 import com.tzld.piaoquan.ad.engine.service.feature.Feature;
 import com.tzld.piaoquan.ad.engine.service.feature.FeatureService;
@@ -47,6 +52,21 @@ public abstract class RankStrategyBasic implements RankStrategy {
     @ApolloJsonValue("${h5.score.suppress:{}}")
     private Map<String, Double> h5ScoreSuppress;
 
+    @ApolloJsonValue("${rerank.strategy.flow.ctl.customer:{}}")
+    private Map<String, Double> flowCtlCustomerParams;
+
+    @ApolloJsonValue("${rerank.strategy.flow.ctl.agent:{}}")
+    private Map<String, Double> flowCtlAgentParams;
+
+    @ApolloJsonValue("${rerank.root.session.id.tail.config:[]}")
+    private List<RootSessionIdExpConfig> rerankRootSessionIdConfig;
+
+    @ApolloJsonValue("${h5.score.suppress.customer.white:[]}")
+    private Set<Long> customerIdWhiteSet;
+
+    @Value("${rank.strategy.default.cxr:0.000001}")
+    protected Double defaultCxr;
+
     @Value("${guarantee.exp:742}")
     protected String guaranteeExp;
 
@@ -407,6 +427,7 @@ public abstract class RankStrategyBasic implements RankStrategy {
         String clazzL4 = userLayer.getOrDefault("class_l4", "近期未出现");
         map.put("layer_l4", layerL4);
         map.put("clazz_l4", clazzL4);
+        map.put("rootSessionId", rootSessionId);
         return map;
     }
 
@@ -1118,6 +1139,7 @@ public abstract class RankStrategyBasic implements RankStrategy {
             reqFeature.put("landingPageType", String.valueOf(adPlatformCreativeDTO.getLandingPageType()));
             reqFeature.put("category_name", adPlatformCreativeDTO.getCategoryName());
             reqFeature.put("material_md5", adPlatformCreativeDTO.getMaterialMd5());
+            reqFeature.put("agentId", adPlatformCreativeDTO.getAgentId() != null ? String.valueOf(adPlatformCreativeDTO.getAgentId()) : "");
             reqFeature.put("ad_profession_id", adPlatformCreativeDTO.getAdProfessionId() != null ? String.valueOf(adPlatformCreativeDTO.getAdProfessionId()) : "");
             reqFeature.put("ad_profession_name", adPlatformCreativeDTO.getAdProfessionName() != null ? adPlatformCreativeDTO.getAdProfessionName() : "");
             reqFeature.put("ad_category_name", adPlatformCreativeDTO.getAdCategoryName());
@@ -1204,6 +1226,14 @@ public abstract class RankStrategyBasic implements RankStrategy {
         if (org.springframework.util.CollectionUtils.isEmpty(h5ScoreSuppress) || Objects.isNull(item)) {
             return 1.0;
         }
+
+        Long customerId = item.getCustomerId();
+
+        if (!CollectionUtils.isEmpty(customerIdWhiteSet) && Objects.nonNull(customerId) && customerIdWhiteSet.contains(customerId)) {
+            log.info("getH5SuppressWeight 客户命中白名单, customerId:{}", customerId);
+            return 1.0;
+        }
+
         try {
             Integer landingPageType = item.getLandingPageType();
             String profession = item.getProfession();
@@ -1219,6 +1249,16 @@ public abstract class RankStrategyBasic implements RankStrategy {
         return 1.0;
     }
 
+    protected double getDefaultCxr(double cxr) {
+        try {
+            if (null != defaultCxr) {
+                return Math.max(cxr, defaultCxr);
+            }
+        } catch (Exception e) {
+            log.error("cxr", e);
+        }
+        return cxr;
+    }
 
     protected boolean landingH5Page(AdRankItem item) {
         if (Objects.isNull(item)) {
@@ -1332,4 +1372,125 @@ public abstract class RankStrategyBasic implements RankStrategy {
             return false;
         }
     }
+
+    // rerank
+    protected void calRerankWeight(ScoreParam scoreParam, String layer, List<AdRankItem> items) {
+        try {
+            List<RootSessionIdExpConfig> expConfigs = RootSessionIdTailUtil.getRootSessionIdTailConfig(scoreParam, RootSessionIdTailUtil.reRankTailN, rerankRootSessionIdConfig);
+            if (expConfigs.isEmpty()) {
+                return;
+            }
+            Set<String> hit = new HashSet<>();
+            for (RootSessionIdExpConfig expConfig : expConfigs) {
+                if (null != expConfig && null != expConfig.getConfig()) {
+                    String rerankStrategy = expConfig.getConfig().get("rerank");
+                    if (null == rerankStrategy || hit.contains(rerankStrategy)) {
+                        continue;
+                    }
+                    hit.add(rerankStrategy);
+                    switch (rerankStrategy) {
+                        case "flowCtlC":
+                            calFlowControlWeight(rerankStrategy, layer, items, flowCtlCustomerParams);
+                            break;
+                        case "flowCtlA":
+                            calFlowControlWeight(rerankStrategy, layer, items, flowCtlAgentParams);
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            }
+
+            calCreativeKFinalWeight("kFinal",items);
+        } catch (Exception e) {
+            log.error("cal rerank weight error", e);
+        }
+    }
+
+    // 控制流量
+    protected void calFlowControlWeight(String flowCtlType, String layer, List<AdRankItem> items, Map<String, Double> flowControlParams) {
+        try {
+            if (org.springframework.util.CollectionUtils.isEmpty(flowControlParams)) {
+                return;
+            }
+            double cpmPow = flowControlParams.getOrDefault("cpmPow", 0.3);
+            double lowerCpmWeight = flowControlParams.getOrDefault("lowerCpmWeight", 1.0);
+            double upperCpmWeight = flowControlParams.getOrDefault("upperCpmWeight", 1.2);
+            double flowPow = flowControlParams.getOrDefault("flowPow", 1.2);
+            double lowerFlowWeight = flowControlParams.getOrDefault("lowerFlowWeight", 0.77);
+            double upperFlowWeight = flowControlParams.getOrDefault("upperFlowWeight", 1.0);
+
+            double hitViewRate = flowControlParams.getOrDefault("hitViewRate", 0.05);
+            double plusViewRate = flowControlParams.getOrDefault("plusViewRate", 20.0);
+            double viewRatePow = flowControlParams.getOrDefault("viewRatePow", 0.2);
+            double viewRateScale = flowControlParams.getOrDefault("viewRateScale", 0.5491);
+            if ("flowCtlC".equals(flowCtlType)) {
+                for (AdRankItem item : items) {
+                    String profession = item.getProfession();
+                    String customerId = String.valueOf(item.getCustomerId());
+                    Pair<Double, Double> pair = LayerCustomerFlowControlDataHelper.getWeight(layer, profession, customerId);
+                    double flowWeight = getFlowControlWeight(pair,
+                            cpmPow, lowerCpmWeight, upperCpmWeight,
+                            flowPow, lowerFlowWeight, upperFlowWeight,
+                            hitViewRate, plusViewRate, viewRatePow, viewRateScale);
+                    item.getScoreMap().put(flowCtlType, flowWeight);
+                }
+            } else if ("flowCtlA".equals(flowCtlType)) {
+                for (AdRankItem item : items) {
+                    String profession = item.getProfession();
+                    String agentId = String.valueOf(item.getAgentId());
+                    Pair<Double, Double> pair = LayerAgentFlowControlDataHelper.getWeight(layer, profession, agentId);
+                    double flowWeight = getFlowControlWeight(pair,
+                            cpmPow, lowerCpmWeight, upperCpmWeight,
+                            flowPow, lowerFlowWeight, upperFlowWeight,
+                            hitViewRate, plusViewRate, viewRatePow, viewRateScale);
+                    item.getScoreMap().put(flowCtlType, flowWeight);
+                }
+            }
+        } catch (Exception e) {
+            log.error("cal flow control weight error", e);
+        }
+    }
+
+
+    // 加V打压系数
+    protected void calCreativeKFinalWeight(String flowCtlType, List<AdRankItem> items) {
+        try {
+            for (AdRankItem item : items) {
+                Double kFinal = CreativeKFinalDataHelper.getKFinal(item.getCreativeCode());
+                if(kFinal != null){
+                    item.getScoreMap().put(flowCtlType, kFinal);
+                }
+            }
+        } catch (Exception e) {
+            log.error("calCreativeKFinalWeight weight error", e);
+        }
+    }
+
+    private double getFlowControlWeight(Pair<Double, Double> pair,
+                                        double cpmPow, double lowerCpmWeight, double upperCpmWeight,
+                                        double flowPow, double lowerFlowWeight, double upperFlowWeight,
+                                        double hitViewRate, double plusViewRate, double viewRatePow, double viewRateScale) {
+        try {
+            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;
+    }
 }

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

@@ -182,6 +182,7 @@ public class RankStrategyBy847 extends RankStrategyBasic {
                     adRankItem.setCpm(ObjUtil.nullOrDefault(dto.getCpm(), 90).doubleValue());
                     adRankItem.setSkuId(dto.getSkuId());
                     adRankItem.setCustomerId(dto.getCustomerId());
+                    adRankItem.setAgentId(dto.getAgentId());
                     adRankItem.setProfession(dto.getProfession());
                     adRankItem.setLandingPageType(dto.getLandingPageType());
                     adRankItem.setRandom(random.nextInt(1000));
@@ -328,6 +329,7 @@ public class RankStrategyBy847 extends RankStrategyBasic {
                 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) {
@@ -370,6 +372,11 @@ 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"));
+
+        // 计算rerank权重
+        String layer = reqFeature.get("layer_l4");
+        calRerankWeight(scoreParam, layer, result);
+
         for (AdRankItem item : result) {
             double bid = item.getCpa();
             if (scoreParam.getExpCodeSet().contains(correctCpaExp1) || scoreParam.getExpCodeSet().contains(correctCpaExp2)) {
@@ -396,12 +403,16 @@ public class RankStrategyBy847 extends RankStrategyBasic {
                     expNewKey, expNewThreshold,
                     expLowerWeight, expUpperWeight, expScale);
 
+            // 控制流量权重
+            double flowCtlC = item.getScoreMap().getOrDefault("flowCtlC", 1.0);
+            double flowCtlA = item.getScoreMap().getOrDefault("flowCtlA", 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 = h5Weight * expWeight * item.getLrScore() * bid * scoreCoefficient * guaranteeScoreCoefficient * layerAndCreativeWeight;
+            double score = flowCtlC * flowCtlA * 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());
@@ -438,6 +449,9 @@ public class RankStrategyBy847 extends RankStrategyBasic {
                 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);
             }

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

@@ -182,6 +182,7 @@ public class RankStrategyBy849 extends RankStrategyBasic {
                     adRankItem.setCpm(ObjUtil.nullOrDefault(dto.getCpm(), 90).doubleValue());
                     adRankItem.setSkuId(dto.getSkuId());
                     adRankItem.setCustomerId(dto.getCustomerId());
+                    adRankItem.setAgentId(dto.getAgentId());
                     adRankItem.setProfession(dto.getProfession());
                     adRankItem.setLandingPageType(dto.getLandingPageType());
                     adRankItem.setRandom(random.nextInt(1000));
@@ -328,6 +329,7 @@ public class RankStrategyBy849 extends RankStrategyBasic {
                 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) {
@@ -370,6 +372,10 @@ public class RankStrategyBy849 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"));
+
+        // 计算rerank权重
+        String layer = reqFeature.get("layer_l4");
+        calRerankWeight(scoreParam, layer, result);
         for (AdRankItem item : result) {
             double bid = item.getCpa();
             if (scoreParam.getExpCodeSet().contains(correctCpaExp1) || scoreParam.getExpCodeSet().contains(correctCpaExp2)) {
@@ -396,12 +402,16 @@ public class RankStrategyBy849 extends RankStrategyBasic {
                     expNewKey, expNewThreshold,
                     expLowerWeight, expUpperWeight, expScale);
 
+            // 控制流量权重
+            double flowCtlC = item.getScoreMap().getOrDefault("flowCtlC", 1.0);
+            double flowCtlA = item.getScoreMap().getOrDefault("flowCtlA", 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 = h5Weight * expWeight * item.getLrScore() * bid * scoreCoefficient * guaranteeScoreCoefficient * layerAndCreativeWeight;
+            double score = flowCtlC * flowCtlA * 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());
@@ -438,6 +448,9 @@ public class RankStrategyBy849 extends RankStrategyBasic {
                 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);
             }

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

@@ -1,5 +1,6 @@
 package com.tzld.piaoquan.ad.engine.service.score.strategy;
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
 import com.tzld.piaoquan.ad.engine.commons.dto.AdPlatformCreativeDTO;
@@ -105,6 +106,7 @@ public class RankStrategyBy851 extends RankStrategyBasic {
         String userLayer = reqFeature.get("layer_l4");
         // feature1
         Feature feature = this.getFeatureV2(userLayer, scoreParam, request);
+        log.info("851 feature: {}", JSON.toJSONString(feature));
         if (feature == null) {
             log.warn("adItemRank: feature is null, skip processing. request={}", request);
             return new ArrayList<>();
@@ -187,6 +189,7 @@ public class RankStrategyBy851 extends RankStrategyBasic {
                     adRankItem.setCpm(ObjUtil.nullOrDefault(dto.getCpm(), 90).doubleValue());
                     adRankItem.setSkuId(dto.getSkuId());
                     adRankItem.setCustomerId(dto.getCustomerId());
+                    adRankItem.setAgentId(dto.getAgentId());
                     adRankItem.setProfession(dto.getProfession());
                     adRankItem.setLandingPageType(dto.getLandingPageType());
                     adRankItem.setRandom(random.nextInt(1000));
@@ -237,6 +240,7 @@ public class RankStrategyBy851 extends RankStrategyBasic {
                         cidFeatureMap.put("cid", "");
                         cidFeatureMap.put("adid", "");
                         cidFeatureMap.put("adverid", "");
+                        cidFeatureMap.put("customer", "");
                     }
                     return adRankItem;
                 } finally {
@@ -336,6 +340,7 @@ public class RankStrategyBy851 extends RankStrategyBasic {
                 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) {
@@ -378,6 +383,9 @@ public class RankStrategyBy851 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"));
+
+        // 计算rerank权重
+        calRerankWeight(scoreParam, userLayer, result);
         for (AdRankItem item : result) {
             double bid = item.getCpa();
             if (scoreParam.getExpCodeSet().contains(correctCpaExp1) || scoreParam.getExpCodeSet().contains(correctCpaExp2)) {
@@ -404,12 +412,17 @@ public class RankStrategyBy851 extends RankStrategyBasic {
                     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 = h5Weight * expWeight * item.getLrScore() * bid * scoreCoefficient * guaranteeScoreCoefficient * layerAndCreativeWeight;
+            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());
@@ -446,6 +459,9 @@ public class RankStrategyBy851 extends RankStrategyBasic {
                 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);
             }
@@ -924,6 +940,7 @@ public class RankStrategyBy851 extends RankStrategyBasic {
     }
 
     private Map<String, Map<String, Double>> parseD2FeatureMap(Map<String, String> d2Feature) {
+        log.info("parseD2FeatureMap d2Feature: {}", d2Feature);
         Map<String, Map<String, Double>> vidRankMaps = new HashMap<>();
         for (Map.Entry<String, String> entry : d2Feature.entrySet()) {
             String key = entry.getKey();

+ 11 - 1
pom.xml

@@ -330,7 +330,17 @@
             <version>2.0.23</version>
         </dependency>
 
-
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.junit.vintage</groupId>
+                    <artifactId>junit-vintage-engine</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
 
         <!--easyexcel-->
     </dependencies>