Browse Source

Merge branch '20251216-wyp-823' into test

wangyunpeng 11 hours ago
parent
commit
da85149cc0
27 changed files with 1634 additions and 417 deletions
  1. 2 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/dto/AdPlatformCreativeDTO.java
  2. 2 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/param/RankRecommendRequestParam.java
  3. 2 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/score/ScoreParam.java
  4. 1 1
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/score/ScorerPipeline.java
  5. 13 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/thread/ThreadPoolFactory.java
  6. 8 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/feature/Feature.java
  7. 336 76
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/impl/PredictModelServiceImpl.java
  8. 3 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/request/ThresholdPredictModelRequestParam.java
  9. 3 1
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/BasicPredict.java
  10. 10 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictContext.java
  11. 177 177
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictServiceV2.java
  12. 43 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy599.java
  13. 42 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy667.java
  14. 111 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy673.java
  15. 103 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy817.java
  16. 85 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy819.java
  17. 93 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy820.java
  18. 153 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy823.java
  19. 86 86
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/RootSessionIdPredict.java
  20. 74 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/ThresholdPredictStrategy.java
  21. 7 7
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/UserLayerRootSessionIdPredict.java
  22. 4 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/convert/RequestConvert.java
  23. 63 11
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/scorer/PAIScorer.java
  24. 64 11
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/scorer/PAIScorerV2.java
  25. 104 15
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBasic.java
  26. 23 16
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBy683.java
  27. 22 16
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBy688.java

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

@@ -54,4 +54,6 @@ public class AdPlatformCreativeDTO {
     private Long customerId;
 
     private String categoryName;
+
+    private String materialMd5;
 }

+ 2 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/param/RankRecommendRequestParam.java

@@ -6,6 +6,7 @@ import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
 import java.util.List;
+import java.util.Map;
 
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -17,4 +18,5 @@ public class RankRecommendRequestParam extends RecommendRequestParam{
      String rootSessionId;
      String rootSourceId;
      Boolean isFilterUser;
+     Map<String,Object> engineInfo;
 }

+ 2 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/score/ScoreParam.java

@@ -30,5 +30,7 @@ public class ScoreParam {
     private String expCode;
 
     private Boolean isFilterUser;
+
+    Map<String,Object> engineInfo;
 }
 

+ 1 - 1
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/score/ScorerPipeline.java

@@ -18,7 +18,7 @@ import java.util.concurrent.*;
 @Slf4j
 public class ScorerPipeline {
     public static final int corePoolSize = 128;
-    public static final int SCORE_TIME_OUT = 400;
+    public static final int SCORE_TIME_OUT = 500;
     public static final Logger LOGGER = LoggerFactory.getLogger(ScorerPipeline.class);
     public static final ExecutorService executorService = Executors.newFixedThreadPool(corePoolSize);
 

+ 13 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/thread/ThreadPoolFactory.java

@@ -26,6 +26,14 @@ public final class ThreadPoolFactory {
             new ThreadFactoryBuilder().setNameFormat("Feature-%d").build(),
             new ThreadPoolExecutor.AbortPolicy());
 
+    private final static ExecutorService SCORE = new CommonThreadPoolExecutor(
+            512,
+            512,
+            0L, TimeUnit.SECONDS,
+            new LinkedBlockingQueue<>(5000),
+            new ThreadFactoryBuilder().setNameFormat("SCORE-%d").build(),
+            new ThreadPoolExecutor.AbortPolicy());
+
     public static ExecutorService defaultPool() {
         return DEFAULT;
     }
@@ -34,4 +42,9 @@ public final class ThreadPoolFactory {
         return FEATURE;
     }
 
+    public static ExecutorService score() {
+        return SCORE;
+    }
+
+
 }

+ 8 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/feature/Feature.java

@@ -23,4 +23,12 @@ public class Feature {
     // k1:skuid、k2:表、v:特征值
     private Map<String, Map<String, Map<String, String>>> skuFeature = new HashMap<>();
 
+    // 合并方法,使用 putAll() 合并,且如果目标为空则取源
+    public void merge(Feature other) {
+        this.cidFeature.putAll(other.cidFeature);
+        this.videoFeature.putAll(other.videoFeature);
+        this.adVerFeature.putAll(other.adVerFeature);
+        this.userFeature.putAll(other.userFeature);
+        this.skuFeature.putAll(other.skuFeature);
+    }
 }

+ 336 - 76
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/impl/PredictModelServiceImpl.java

@@ -3,13 +3,12 @@ package com.tzld.piaoquan.ad.engine.service.predict.impl;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.TypeReference;
+import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
 import com.tzld.piaoquan.ad.engine.commons.enums.AppTypeEnum;
 import com.tzld.piaoquan.ad.engine.commons.enums.RedisPrefixEnum;
 import com.tzld.piaoquan.ad.engine.commons.redis.AdRedisHelper;
 import com.tzld.piaoquan.ad.engine.commons.redis.AlgorithmRedisHelper;
-import com.tzld.piaoquan.ad.engine.commons.util.AbUtil;
 import com.tzld.piaoquan.ad.engine.commons.util.DateUtils;
-import com.tzld.piaoquan.ad.engine.service.log.LogHubService;
 import com.tzld.piaoquan.ad.engine.service.predict.PredictModelService;
 import com.tzld.piaoquan.ad.engine.service.predict.config.AbConfig;
 import com.tzld.piaoquan.ad.engine.service.predict.config.NewExpUserGroupConfig;
@@ -29,6 +28,7 @@ import com.tzld.piaoquan.ad.engine.commons.feign.manager.service.HolidayService;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.MapUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
@@ -44,8 +44,6 @@ import java.util.*;
 @Service
 public class PredictModelServiceImpl implements PredictModelService {
     private final static Logger log = LoggerFactory.getLogger(PredictModelServiceImpl.class);
-    @Value("${ad.own.experiment.tier:ab_test002}")
-    private String adOwnExperimentTier;
 
     @Autowired
     private AbTestConfigContainer abTestConfigContainer;
@@ -62,25 +60,39 @@ public class PredictModelServiceImpl implements PredictModelService {
     @Autowired
     RoiModelConfig roiModelConfig;
 
+    // @Autowired
+    // private PredictServiceV2 predictServiceV2;
+    // @Autowired
+    // private RootSessionIdPredict rootSessionIdPredict;
     @Autowired
-    private PredictServiceV2 predictServiceV2;
+    private UserLayerRootSessionIdPredict userLayerRootSessionIdPredict;
     @Autowired
-    private RootSessionIdPredict rootSessionIdPredict;
+    private PredictStrategyBy673 predictStrategyBy673;
     @Autowired
-    private UserLayerRootSessionIdPredict userLayerRootSessionIdPredict;
-
+    private PredictStrategyBy667 predictStrategyBy667;
     @Autowired
-    private UserService userService;
-
+    private PredictStrategyBy599 predictStrategyBy599;
+    @Autowired
+    private PredictStrategyBy817 predictStrategyBy817;
+    @Autowired
+    private PredictStrategyBy819 predictStrategyBy819;
+    @Autowired
+    private PredictStrategyBy820 predictStrategyBy820;
     @Autowired
-    private LogHubService logHubService;
+    private PredictStrategyBy823 predictStrategyBy823;
 
-    @Value("${ad.predict.share0.exp.code:000}")
-    private String adPredictNoShareUserExpCode;
+    @Autowired
+    private UserService userService;
 
+    // @Value("${ad.own.experiment.tier:ab_test002}")
+    // private String adOwnExperimentTier;
+    // @Autowired
+    // private LogHubService logHubService;
+    // @Value("${ad.predict.share0.exp.code:000}")
+    // private String adPredictNoShareUserExpCode;
 
-    @Value("${ad.predict.immersion.exp.code:607}")
-    private String adPredictImmersionExpCode;
+    // @Value("${ad.predict.immersion.exp.code:607}")
+    // private String adPredictImmersionExpCode;
 
     @Value("${ad.predict.param.testIds:0}")
     private String testIds;
@@ -101,9 +113,13 @@ public class PredictModelServiceImpl implements PredictModelService {
     @Value("#{'${show.ad.whitelist.mid:}'.split(',')}")
     private Set<String> showAdWhitelistMidSet;
 
+    @Value("${experiment.817.ad.hour:5,8}")
+    private String experiment817WithAdHour;
+
     @Autowired
     private AdRedisHelper adRedisHelper;
 
+    // List<Integer> appIdArr = Arrays.asList(new Integer[]{0, 3, 4, 5, 6, 17, 18, 19, 21, 22});
     @Autowired
     private HolidayService holidayService;
 
@@ -139,6 +155,237 @@ public class PredictModelServiceImpl implements PredictModelService {
             }
 
 
+            List<Map<String, Object>> mapList = (List) requestParam.getAbExpInfo().get("ab_test002");
+
+            // 该用户所有实验合集
+            Set<String> expCodes = new HashSet<>();
+            for (Map<String, Object> map : mapList) {
+                String expCode = map.getOrDefault("abExpCode", "").toString();
+                expCodes.add(expCode);
+            }
+            boolean execute817 = false;
+            // 不出广告时间判定
+            int hourOfDay = DateUtils.getCurrentHour();
+            if (0 <= hourOfDay && hourOfDay < 8 && !isAdvanceShowAd()) {
+                // 0点到8点 && 不是节日
+                boolean isIn817Time = false;
+                try {
+                    String[] split = experiment817WithAdHour.split(",");
+                    if (Integer.parseInt(split[0]) <= hourOfDay && hourOfDay < Integer.parseInt(split[1])) {
+                        isIn817Time = true;
+                    }
+                } catch (Exception e) {
+                    log.error("experiment817WithAdHour配置异常", e);
+                }
+                // 在 817实验时间范围 && 817实验开启
+                if (isIn817Time && expCodes.contains("817")) {
+                    execute817 = true;
+                } else {
+                    result.put("ad_predict", 1);
+                    result.put("no_ad_strategy", "no_ad_time_with_fixed_time");
+                    return result;
+                }
+            }
+
+            // 新老实验和填充requestParam参数(老实验可能直接返回结果)
+            Map<String, Object> result1 = getParamAndFill(requestParam, result);
+            if (result1 != null) {
+                result1.put("ad_predict", 1);
+                return result1;
+            }
+
+
+            PredictContext predictContext = ConvertUtil.predictParam2Context(requestParam);
+            // 817熔断
+            if (execute817) {
+                return predictStrategyBy817.predict(predictContext);
+            }
+
+            // 823熔断
+            if (predictStrategyBy823.in823Ab(requestParam, expCodes, hourOfDay)) {
+                Map<String, Object> resultMap = predictStrategyBy823.predict(predictContext);
+                predictStrategyBy823.addConfigExt(requestParam, resultMap);
+                return resultMap;
+            }
+
+            // 819只做参数填充
+            Map<String, Object> predictExtInfo = null;
+            if (expCodes.contains("819")) {
+                predictExtInfo = predictStrategyBy819.predict(predictContext);
+            }
+
+            Map<String, Object> userLayerPredict = userLayerRootSessionIdPredict.predict(predictContext);
+            if (MapUtils.isNotEmpty(userLayerPredict)) {
+                // 填充 819 参数
+                if (MapUtils.isNotEmpty(predictExtInfo)) {
+                    userLayerPredict.putAll(predictExtInfo);
+                }
+                return userLayerPredict;
+            }
+
+
+            if (expCodes.contains("820")) {
+                Map<String, Object> userLayerPredict820 = predictStrategyBy820.predict(predictContext);
+                if (MapUtils.isNotEmpty(userLayerPredict820)) {
+                    // 填充 819 参数
+                    if (MapUtils.isNotEmpty(predictExtInfo)) {
+                        userLayerPredict820.putAll(predictExtInfo);
+                    }
+                    return userLayerPredict820;
+                }
+            }
+
+            if (expCodes.contains("673")) {
+                Map<String, Object> predictResult = predictStrategyBy673.predict(predictContext);
+                if (Objects.nonNull(predictResult)) {
+                    // 填充 819 参数
+                    if (MapUtils.isNotEmpty(predictExtInfo)) {
+                        predictResult.putAll(predictExtInfo);
+                    }
+                    return predictResult;
+                }
+            }
+
+            Map<String, Object> predictResult;
+            if (expCodes.contains("599")) {
+                predictResult = predictStrategyBy599.predict(predictContext);
+            } else if (expCodes.contains("667")) {
+                predictResult = predictStrategyBy667.predict(predictContext);
+            } else {
+                predictResult = predictStrategyBy599.predict(predictContext);
+            }
+            // 填充 819 参数
+            if (MapUtils.isNotEmpty(predictResult) && MapUtils.isNotEmpty(predictExtInfo)) {
+                predictResult.putAll(predictExtInfo);
+            }
+            return predictResult;
+
+        } catch (Exception e) {
+            log.error("svc=adPredict appType={} group={} newGroup={} pqtId={}"
+                    , requestParam.getAppType(), requestParam.getAbTestCode(), requestParam.getNewExpGroup(), requestParam.getPqtId(), e);
+            result.put("ad_predict", 1);
+            result.put("no_ad_strategy", "error");
+            return result;
+        }
+
+    }
+
+    private @Nullable Map<String, Object> getParamAndFill(ThresholdPredictModelRequestParam requestParam, Map<String, Object> result) {
+        String abtestId = null;
+        String abTestConfigTag = null;
+        Map<String, Object> abtestParam = null;
+        String midGroup = null;
+        String shareType = null;
+
+        String[] appIdArr = oldExpGroupAppId.split(",");
+        // 新老实验系统
+        List<String> appIdList = Arrays.asList(appIdArr);
+        if (appIdList.contains(requestParam.getAppType().toString())) {
+            String[] abParamArr = abConfig.getAbParams(requestParam.getAbTestCode(), requestParam.getAbExpInfo());
+            if (abParamArr == null) {
+                abParamArr = NewExpUserGroupConfig.newExpUserGroupMap.get(requestParam.getAppType().toString());
+                if (abParamArr == null) {
+                    result.put("msg", "abConfig_error");
+                    return result;
+                }
+            }
+            abtestId = abParamArr[0];
+            abTestConfigTag = abParamArr[1];
+            HashMap<String, Map<String, Object>> abConfigMap = abConfig.getAbConfigMap();
+            abtestParam = abConfigMap.getOrDefault(abtestId + "-" + abTestConfigTag, null);
+            if (abtestParam == null) {
+                result.put("msg", "abConfig_error");
+                return result;
+            }
+            // Determine the group to which mid belongs
+            String groupClassKey = (String) abtestParam.get("group_class_key");
+            String midGroupKeyName = RuleRedisKeyConst.KEY_NAME_PREFIX_MID_GROUP + groupClassKey + ":" + requestParam.getMid();
+            midGroup = redisHelper.getString(midGroupKeyName);
+
+            // 没有时为新用户或者无分享用户
+            shareType = midGroup;
+            if (midGroup == null) {
+                midGroup = "mean_group";
+                shareType = "noShare";
+            }
+            String[] noAdMidGroupList = new String[0];
+            noAdMidGroupList = ((JSONArray) abtestParam.get("no_ad_mid_group_list")).toArray(noAdMidGroupList);
+
+            boolean inNoAdGroup = false;
+            for (String group : noAdMidGroupList) {
+                if (group.equals(midGroup)) {
+                    inNoAdGroup = true;
+                    break;
+                }
+            }
+            // 不出广告组
+            if (inNoAdGroup) {
+                // User is in the no-ad group, no ad should be shown
+                result.put("mid_group", midGroup);
+                result.put("ad_predict", 1);
+                result.put("no_ad_strategy", "no_ad_mid_group_with_video");
+                return result;
+            }
+            // top1广告不出视频
+            Map<String, List<String>> noAdGroupWithVideoMapping = (Map) abtestParam.getOrDefault("no_ad_group_with_video_mapping", new HashMap<>());
+            if (noAdGroupWithVideoMapping.keySet().contains(midGroup)
+                    &&
+                    topOneVideoContainer.inNoAdTopVideo(requestParam.getAppType().longValue(), requestParam.getVideoId())
+            ) {
+                result.put("mid_group", midGroup);
+                result.put("ad_predict", 1);
+                result.put("no_ad_strategy", "no_ad_mid_group_with_video");
+                return result;
+            }
+        } else {
+            String midGroupKeyName = RuleRedisKeyConst.KEY_NAME_PREFIX_MID_GROUP + "class1:" + requestParam.getMid();
+            midGroup = redisHelper.getString(midGroupKeyName);
+            shareType = midGroup;
+            if (midGroup == null) {
+                midGroup = "mean_group";
+                shareType = "noShare";
+            }
+        }
+
+        // 市-中文
+        requestParam.setRegion(requestParam.getRegion().replace("省", ""));
+        requestParam.setCity(requestParam.getCity().replace("市", ""));
+        requestParam.setShareType(shareType);
+        String userLayer = userService.getUserLayer4Level(requestParam.getMid());
+        requestParam.setUserLayer(userLayer);
+        return null;
+    }
+
+
+    public Map<String, Object> adPredictOld(ThresholdPredictModelRequestParam requestParam) {
+        Map<String, Object> result = new HashMap<>();
+        result.put("pqtId", requestParam.getPqtId());
+
+        // 白名单用户固定出广告
+        if (CollectionUtils.isNotEmpty(showAdWhitelistMidSet) && showAdWhitelistMidSet.contains(requestParam.getMid())) {
+            result.put("ad_predict", 2);
+            result.put("ad_strategy", "show_ad_whitelist");
+            return result;
+        }
+
+        try {
+            String[] withoutAdVideoIdsArr = withoutAdVideoIds.split(",");
+            for (String videoId : withoutAdVideoIdsArr) {
+                if (videoId.equals(requestParam.getVideoId() + "")) {
+                    if (requestParam.getAppType().equals(0)
+                            || requestParam.getAppType().equals(4)
+                            || requestParam.getAppType().equals(5)
+                            || requestParam.getAppType().equals(21)
+                    ) {
+                        result = new HashMap<>();
+                        result.put("ad_predict", 1);
+                        result.put("no_ad_strategy", "no_ad_with_video_in_white_list");
+                        return result;
+                    }
+                }
+            }
+
+
             List<Map<String, Object>> mapList = (List) requestParam.getAbExpInfo().get("ab_test002");
 
             Map<String, List<JSONObject>> configMap = new HashMap<>();
@@ -173,13 +420,13 @@ public class PredictModelServiceImpl implements PredictModelService {
                 return result;
             }
 
-            if (AbUtil.isInAbExp(expCodes, requestParam.getAppType(), requestParam.getNewExpGroup(), "713")) {
-                PredictContext context = ConvertUtil.predictParam2Context(requestParam);
-                Map<String, Object> resultMap = predictServiceV2.predict(context);
-                logHubService.crowdChooseLogUpload(context);
-                resultMap.put("pqtId", requestParam.getPqtId());
-                return resultMap;
-            }
+            // if (AbUtil.isInAbExp(expCodes, requestParam.getAppType(), requestParam.getNewExpGroup(), "713")) {
+            //     PredictContext context = ConvertUtil.predictParam2Context(requestParam);
+            //     Map<String, Object> resultMap = predictServiceV2.predict(context);
+            //     logHubService.crowdChooseLogUpload(context);
+            //     resultMap.put("pqtId", requestParam.getPqtId());
+            //     return resultMap;
+            // }
 
             String abtestId = null;
             String abTestConfigTag = null;
@@ -265,77 +512,90 @@ public class PredictModelServiceImpl implements PredictModelService {
             // 市-中文
             requestParam.setRegion(requestParam.getRegion().replace("省", ""));
             requestParam.setCity(requestParam.getCity().replace("市", ""));
-            // 设置信息
-            ThresholdPredictModelParam modelParam = ThresholdPredictModelParam.builder()
-                    .build();
-            BeanUtils.copyProperties(requestParam, modelParam);
-            modelParam.setDate(new Date());
-            modelParam.setAbtestId(abtestId);
-            modelParam.setAbTestConfigTag(abTestConfigTag);
-            modelParam.setAbtestParam(abtestParam);
-            modelParam.setMidGroup(midGroup);
-            modelParam.setExtraParam(new HashMap<>());
-            modelParam.addUserExtraFuture("shareType", shareType);
-            setExtraParam(modelParam);
-
             requestParam.setShareType(shareType);
             String userLayer = userService.getUserLayer4Level(requestParam.getMid());
             requestParam.setUserLayer(userLayer);
 
             // 先走rootSessionId 实验
-            Map<String, Object> predict = rootSessionIdPredict.predict(ConvertUtil.predictParam2Context(requestParam));
-            if (MapUtils.isNotEmpty(predict)) {
-                return predict;
-            }
+            // Map<String, Object> predict = rootSessionIdPredict.predict(ConvertUtil.predictParam2Context(requestParam));
+            // if (MapUtils.isNotEmpty(predict)) {
+            //     return predict;
+            // }
 
             Map<String, Object> userLayerPredict = userLayerRootSessionIdPredict.predict(ConvertUtil.predictParam2Context(requestParam));
             if (MapUtils.isNotEmpty(userLayerPredict)) {
                 return userLayerPredict;
             }
 
-            String appTypeStr = requestParam.getAppType().toString();
-
-            List<String> userSourceAndLayerAdRateExpIds = Arrays.asList(userSourceLayerAdRateExpIds.split(","));
-            boolean inAdRateExp = this.checkInAnyExpIdsAndNewAb(expCodes, userSourceAndLayerAdRateExpIds, appTypeStr, requestParam.getNewExpGroup(), modelParam);
-            if (inAdRateExp) {
-                result = ThresholdModelContainer.getThresholdPredictModel("random673").predict(modelParam);
-                // 如果676实验返回结果,表示未命中规则即对应的用户来源和所属层存在配置,使用676实验的结果,否则继续走599实验
-                if (Objects.nonNull(result)) {
-                    return result;
+            if (expCodes.contains("673")) {
+                Map<String, Object> predictResult = predictStrategyBy673.predict(ConvertUtil.predictParam2Context(requestParam));
+                if (Objects.nonNull(predictResult)) {
+                    return predictResult;
                 }
             }
 
-            // 新老实验系统兼容
-            if (expCodes.contains("599") ||
-                    (expCodes.contains(NewExpInfoHelper.flagId) && NewExpInfoHelper.checkInNewExpGroupAndSetParamIfIn(
-                            requestParam.getAppType().toString(), requestParam.getNewExpGroup(), "599", modelParam))) {
-                // NewExpInfoHelper.flagId   647
-                result = ThresholdModelContainer.
-                        getThresholdPredictModel("random")
-                        .predict(modelParam);
-            } else if (expCodes.contains("667") ||
-                    (expCodes.contains(NewExpInfoHelper.flagId) && NewExpInfoHelper.checkInNewExpGroupAndSetParamIfIn(
-                            requestParam.getAppType().toString(), requestParam.getNewExpGroup(), "667", modelParam))) {
-                // NewExpInfoHelper.flagId   647
-                result = ThresholdModelContainer.
-                        getThresholdPredictModel("random667")
-                        .predict(modelParam);
-            } else if (inExpList(expCodes, adPredictImmersionExpCode)
-                    ||
-                    (expCodes.contains(NewExpInfoHelper.flagId) && NewExpInfoHelper.checkInNewExpGroupAndSetParamIfIn(
-                            requestParam.getAppType().toString(), requestParam.getNewExpGroup(), "607", modelParam))) {
-                // adPredictImmersionExpCode 607 631
-                result = ThresholdModelContainer.
-                        getThresholdPredictModel("immersion")
-                        .predict(modelParam);
+            if (expCodes.contains("599")) {
+                return predictStrategyBy599.predict(ConvertUtil.predictParam2Context(requestParam));
+            } else if (expCodes.contains("667")) {
+                return predictStrategyBy667.predict(ConvertUtil.predictParam2Context(requestParam));
             } else {
-                Object thresholdMixFunc = abtestParam.getOrDefault("threshold_mix_func", "basic");
-                result = ThresholdModelContainer.
-                        getThresholdPredictModel(thresholdMixFunc.toString())
-                        .predict(modelParam);
+                return predictStrategyBy599.predict(ConvertUtil.predictParam2Context(requestParam));
             }
 
-            return result;
+            // 设置信息
+            // ThresholdPredictModelParam modelParam = ThresholdPredictModelParam.builder()
+            //         .build();
+            // BeanUtils.copyProperties(requestParam, modelParam);
+            // modelParam.setDate(new Date());
+            // modelParam.setAbtestId(abtestId);
+            // modelParam.setAbTestConfigTag(abTestConfigTag);
+            // modelParam.setAbtestParam(abtestParam);
+            // modelParam.setMidGroup(midGroup);
+            // modelParam.setExtraParam(new HashMap<>());
+            // modelParam.addUserExtraFuture("shareType", shareType);
+            // setExtraParam(modelParam);
+
+            // String appTypeStr = requestParam.getAppType().toString();
+            //
+            // List<String> userSourceAndLayerAdRateExpIds = Arrays.asList(userSourceLayerAdRateExpIds.split(","));
+            // boolean inAdRateExp = this.checkInAnyExpIdsAndNewAb(expCodes, userSourceAndLayerAdRateExpIds, appTypeStr, requestParam.getNewExpGroup(), modelParam);
+            // if (inAdRateExp) {
+            //     result = ThresholdModelContainer.getThresholdPredictModel("random673").predict(modelParam);
+            //     // 如果676实验返回结果,表示未命中规则即对应的用户来源和所属层存在配置,使用676实验的结果,否则继续走599实验
+            //     if (Objects.nonNull(result)) {
+            //         return result;
+            //     }
+            // }
+            // // 新老实验系统兼容
+            // if (expCodes.contains("599") ||
+            //         (expCodes.contains(NewExpInfoHelper.flagId) && NewExpInfoHelper.checkInNewExpGroupAndSetParamIfIn(
+            //                 requestParam.getAppType().toString(), requestParam.getNewExpGroup(), "599", modelParam))) {
+            //     // NewExpInfoHelper.flagId   647
+            //     result = ThresholdModelContainer.
+            //             getThresholdPredictModel("random")
+            //             .predict(modelParam);
+            // } else if (expCodes.contains("667") ||
+            //         (expCodes.contains(NewExpInfoHelper.flagId) && NewExpInfoHelper.checkInNewExpGroupAndSetParamIfIn(
+            //                 requestParam.getAppType().toString(), requestParam.getNewExpGroup(), "667", modelParam))) {
+            //     // NewExpInfoHelper.flagId   647
+            //     result = ThresholdModelContainer.
+            //             getThresholdPredictModel("random667")
+            //             .predict(modelParam);
+            // } else if (inExpList(expCodes, adPredictImmersionExpCode)
+            //         ||
+            //         (expCodes.contains(NewExpInfoHelper.flagId) && NewExpInfoHelper.checkInNewExpGroupAndSetParamIfIn(
+            //                 requestParam.getAppType().toString(), requestParam.getNewExpGroup(), "607", modelParam))) {
+            //     // adPredictImmersionExpCode 607 631
+            //     result = ThresholdModelContainer.
+            //             getThresholdPredictModel("immersion")
+            //             .predict(modelParam);
+            // } else {
+            //     Object thresholdMixFunc = abtestParam.getOrDefault("threshold_mix_func", "basic");
+            //     result = ThresholdModelContainer.
+            //             getThresholdPredictModel(thresholdMixFunc.toString())
+            //             .predict(modelParam);
+            // }
+            // return result;
         } catch (Exception e) {
             log.error("svc=adPredict appType={} group={} newGroup={} pqtId={}"
                     , requestParam.getAppType(), requestParam.getAbTestCode(), requestParam.getNewExpGroup(), requestParam.getPqtId(), e);

+ 3 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/request/ThresholdPredictModelRequestParam.java

@@ -45,4 +45,7 @@ public class ThresholdPredictModelRequestParam {
     private String shareType;
 
     private String userLayer;
+
+    private String rootSourceId;
+    private Integer userShareDepth;
 }

+ 3 - 1
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/BasicPredict.java

@@ -12,10 +12,11 @@ public abstract class BasicPredict {
 
     public abstract Map<String, Object> predict(PredictContext ctx);
 
+    public abstract String name();
+
     protected Map<String, Object> rtnNoAdPredict(PredictContext ctx) {
         Map<String, Object> rtnMap = new HashMap<>();
         rtnMap.put("ad_predict", 1);
-        rtnMap.put("no_ad_strategy", "713_exp");
         rtnMap.put("pqtId", ctx.getPqtId());
         return rtnMap;
     }
@@ -28,6 +29,7 @@ public abstract class BasicPredict {
         return rtnMap;
     }
 
+
     protected double calcScoreByMid(String mid) {
         int hash = mid.hashCode();
         hash = hash < 0 ? -hash : hash;

+ 10 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictContext.java

@@ -6,6 +6,7 @@ import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -76,4 +77,13 @@ public class PredictContext {
     private String userLayer;
 
     private PredictLogParam logParam = new PredictLogParam();
+
+    public String getHandleAfterShareType() {
+        if (StringUtils.isEmpty(shareType)) {
+            return "";
+        }
+        return shareType
+                .replace("return", "")
+                .replace("mids", "");
+    }
 }

+ 177 - 177
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictServiceV2.java

@@ -1,177 +1,177 @@
-package com.tzld.piaoquan.ad.engine.service.predict.v2;
-
-import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
-import com.tzld.piaoquan.ad.engine.commons.util.NumUtil;
-import com.tzld.piaoquan.ad.engine.service.feature.Feature;
-import com.tzld.piaoquan.ad.engine.service.feature.FeatureService;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections4.MapUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.HashMap;
-import java.util.Map;
-
-@Slf4j
-@Service
-public class PredictServiceV2 extends BasicPredict {
-
-    @Autowired
-    private FeatureService featureService;
-
-    @ApolloJsonValue("${exp.713.config:{}}")
-    private Map<String, Double> exp713Config;
-
-    @Override
-    public Map<String, Object> predict(PredictContext ctx) {
-        Feature feature = featureService.getPredictFeature(ctx);
-        Map<String, Map<String, String>> userFeature = feature.getUserFeature();
-        Map<String, String> featureMap = userFeature.getOrDefault("alg_ad_crowd_choose_feature_v2", new HashMap<>());
-        double minScore = exp713Config.getOrDefault("minScore", 0.1d);
-        double maxScore = exp713Config.getOrDefault("maxScore", 0.8d);
-        double score = maxScore;
-
-        ctx.getLogParam().setBIsNewUser(true);
-
-        if (MapUtils.isNotEmpty(featureMap)) {
-
-            double adViewCnt = Double.parseDouble(featureMap.getOrDefault("ad_view_cnt", "0"));
-            double adClick = Double.parseDouble(featureMap.getOrDefault("ad_click", "0"));
-            double adConver = Double.parseDouble(featureMap.getOrDefault("ad_conver", "0"));
-            double hasAdClick = Double.parseDouble(featureMap.getOrDefault("has_ad_click", "0"));
-            double hasAdShare = Double.parseDouble(featureMap.getOrDefault("has_ad_share", "0"));
-            double hasAdReturnCnt = Double.parseDouble(featureMap.getOrDefault("has_ad_return_cnt", "0"));
-            double noAdClick = Double.parseDouble(featureMap.getOrDefault("no_ad_click", "0"));
-            double noAdShare = Double.parseDouble(featureMap.getOrDefault("no_ad_share", "0"));
-            double noAdReturnCnt = Double.parseDouble(featureMap.getOrDefault("no_ad_return_cnt", "0"));
-
-            // 计算出回流出广告时的收益
-            double adClickValue = NumUtil.div(adClick, adViewCnt) * NumUtil.log10(adClick);
-            double adConverValue = NumUtil.div(adConver, adViewCnt) * NumUtil.log10(adConver);
-            double hasAdShareValue = NumUtil.div(hasAdShare, hasAdClick) * NumUtil.log10(hasAdShare);
-            double hasAdReturnValue = NumUtil.div(hasAdReturnCnt, hasAdClick) * NumUtil.log10(hasAdReturnCnt);
-            double hasAdValue = adClickValue + adConverValue + hasAdShareValue + hasAdReturnValue;
-
-            // 计算回流不出广告时的收益
-            double noAdShareValue = NumUtil.div(noAdShare, noAdClick) * NumUtil.log10(noAdShare);
-            double noAdReturnValue = NumUtil.div(noAdReturnCnt, noAdClick) * NumUtil.log10(noAdReturnCnt + hasAdReturnCnt);
-            double noAdValue = noAdShareValue + noAdReturnValue;
-
-            // 计算最终的收益
-            double hasRate = exp713Config.getOrDefault("hasRate", 1d);
-            double noRate = exp713Config.getOrDefault("noRate", 1d);
-            score = NumUtil.softmax(new double[]{hasAdValue * hasRate, noAdValue * noRate})[0];
-
-
-            ctx.getLogParam().getMetaFeature().putAll(feature.getUserFeature());
-            for (Map.Entry<String, String> entry : featureMap.entrySet()) {
-                ctx.getLogParam().getAllFeature().put(entry.getKey(), Double.parseDouble(entry.getValue()));
-            }
-            ctx.getLogParam().getScoreMap().put("adClickValue", NumUtil.round(adClickValue, 6));
-            ctx.getLogParam().getScoreMap().put("adConverValue", NumUtil.round(adConverValue, 6));
-            ctx.getLogParam().getScoreMap().put("hasAdShareValue", NumUtil.round(hasAdShareValue, 6));
-            ctx.getLogParam().getScoreMap().put("hasAdReturnValue", NumUtil.round(hasAdReturnValue, 6));
-            ctx.getLogParam().getScoreMap().put("hasAdValue", NumUtil.round(hasAdValue, 6));
-            ctx.getLogParam().getScoreMap().put("noAdShareValue", NumUtil.round(noAdShareValue, 6));
-            ctx.getLogParam().getScoreMap().put("noAdReturnValue", NumUtil.round(noAdReturnValue, 6));
-            ctx.getLogParam().getScoreMap().put("noAdValue", NumUtil.round(noAdValue, 6));
-            ctx.getLogParam().getScoreMap().put("originScore", NumUtil.round(score, 6));
-            ctx.getLogParam().getScoreMap().put("hasRate", NumUtil.round(hasRate, 6));
-            ctx.getLogParam().getScoreMap().put("noRate", NumUtil.round(noRate, 6));
-
-            ctx.getLogParam().setBIsNewUser(false);
-        }
-
-        // 分数截断,避免过长或过短
-        if (score < minScore) {
-            score = minScore;
-        } else if (score > maxScore) {
-            score = maxScore;
-        }
-
-        double random = Math.random();
-        boolean isShowAd = random < score;
-        ctx.getLogParam().setExpId("713");
-        ctx.getLogParam().setScore(score);
-        ctx.getLogParam().getScoreMap().put("score", NumUtil.round(score, 6));
-        ctx.getLogParam().setAIsShowAd(isShowAd);
-        ctx.getLogParam().getScoreMap().put("minScore", minScore);
-        ctx.getLogParam().getScoreMap().put("maxScore", maxScore);
-        ctx.getLogParam().getScoreMap().put("random", random);
-
-
-        return isShowAd ? rtnAdPredict(ctx) : rtnNoAdPredict(ctx);
-    }
-
-
-    // public Map<String, Object> adPredictV1(PredictContext context){
-    //
-    //     Feature feature = featureService.getPredictFeature(context);
-    //     Map<String, Map<String, String>> userFeature = feature.getUserFeature();
-    //     Map<String, String> featureMap = userFeature.getOrDefault("alg_ad_crowd_choose_feature", new HashMap<>());
-    //
-    //     double score = -1;
-    //
-    //     // 没有特征为新用户,随机出广告
-    //     if (MapUtils.isEmpty(featureMap)) {
-    //         double newUserShowAdRate = exp713Config.getOrDefault("newUserShowAdRate", 0.8d);
-    //         double randomRate = Math.random();
-    //         if (randomRate < newUserShowAdRate) {
-    //             context.getLogParam().getScoreMap().put("newUserShowAdRate", newUserShowAdRate);
-    //             context.getLogParam().getScoreMap().put("randomRate", randomRate);
-    //             score = 1;
-    //         }
-    //     } else {
-    //         context.getLogParam().getMetaFeature().putAll(userFeature);
-    //         for (Map.Entry<String, String> entry : featureMap.entrySet()) {
-    //             context.getLogParam().getAllFeature().put(entry.getKey(), Double.parseDouble(entry.getValue()));
-    //         }
-    //
-    //         // 获取需要的特征值
-    //         double showAdClickPv = Double.parseDouble(featureMap.getOrDefault("show_ad_click_pv", "0"));
-    //         double noShowAdClickPv = Double.parseDouble(featureMap.getOrDefault("no_show_ad_click_pv", "0"));
-    //         double showAdIncome = Double.parseDouble(featureMap.getOrDefault("show_ad_income", "0"));
-    //         double showAdSharePv = Double.parseDouble(featureMap.getOrDefault("show_ad_share_pv", "0"));
-    //         double noShowAdSharePv = Double.parseDouble(featureMap.getOrDefault("no_show_ad_share_pv", "0"));
-    //         double showAdNewReturnPv = Double.parseDouble(featureMap.getOrDefault("show_ad_new_return_pv", "0"));
-    //         double noShowAdNewReturnPv = Double.parseDouble(featureMap.getOrDefault("no_show_ad_new_return_pv", "0"));
-    //
-    //         // 计算中间过程值
-    //         double singleReturnAdIncome = NumUtil.div(showAdIncome, (showAdClickPv + noShowAdClickPv));
-    //         double showAdShareRate = NumUtil.div((showAdSharePv + 1), (showAdClickPv + 1));
-    //         double noShowAdShareRate = NumUtil.div((noShowAdSharePv + 1), (noShowAdClickPv + 1));
-    //         double returnDivShare = NumUtil.div((showAdNewReturnPv + noShowAdNewReturnPv + 1), (showAdSharePv + noShowAdSharePv + 1));
-    //
-    //         double busDauBalanceRate = exp713Config.getOrDefault("busDauBalanceRate", 0.1d);
-    //         score = singleReturnAdIncome + ((showAdShareRate - noShowAdShareRate) * returnDivShare * busDauBalanceRate);
-    //
-    //
-    //         context.getLogParam().getScoreMap().put("singleReturnAdIncome", singleReturnAdIncome);
-    //         context.getLogParam().getScoreMap().put("showAdShareRate", showAdShareRate);
-    //         context.getLogParam().getScoreMap().put("noShowAdShareRate", noShowAdShareRate);
-    //         context.getLogParam().getScoreMap().put("returnDivShare", returnDivShare);
-    //         context.getLogParam().getScoreMap().put("busDauBalanceRate", busDauBalanceRate);
-    //
-    //     }
-    //     double showAdScoreThreshold = exp713Config.getOrDefault("showAdScoreThreshold", 0d);
-    //     boolean isShowAd = score >= showAdScoreThreshold;
-    //
-    //     context.getLogParam().setAIsShowAd(isShowAd);
-    //     context.getLogParam().setExpId("713");
-    //     context.getLogParam().setScore(score);
-    //     context.getLogParam().getScoreMap().put("score", score);
-    //     context.getLogParam().getScoreMap().put("showAdScoreThreshold", showAdScoreThreshold);
-    //
-    //
-    //     logHubService.crowdChooseLogUpload(context);
-    //
-    //
-    //     if (isShowAd) {
-    //         Map<String, Object> rtnMap = rtnAdPredict();
-    //         rtnMap.putAll(context.getLogParam().getScoreMap());
-    //         return rtnMap;
-    //     } else {
-    //         return rtnNoAdPredict("713_exp");
-    //     }
-    // }
-}
+// package com.tzld.piaoquan.ad.engine.service.predict.v2;
+//
+// import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
+// import com.tzld.piaoquan.ad.engine.commons.util.NumUtil;
+// import com.tzld.piaoquan.ad.engine.service.feature.Feature;
+// import com.tzld.piaoquan.ad.engine.service.feature.FeatureService;
+// import lombok.extern.slf4j.Slf4j;
+// import org.apache.commons.collections4.MapUtils;
+// import org.springframework.beans.factory.annotation.Autowired;
+// import org.springframework.stereotype.Service;
+//
+// import java.util.HashMap;
+// import java.util.Map;
+//
+// @Slf4j
+// @Service
+// public class PredictServiceV2 extends BasicPredict {
+//
+//     @Autowired
+//     private FeatureService featureService;
+//
+//     @ApolloJsonValue("${exp.713.config:{}}")
+//     private Map<String, Double> exp713Config;
+//
+//     @Override
+//     public Map<String, Object> predict(PredictContext ctx) {
+//         Feature feature = featureService.getPredictFeature(ctx);
+//         Map<String, Map<String, String>> userFeature = feature.getUserFeature();
+//         Map<String, String> featureMap = userFeature.getOrDefault("alg_ad_crowd_choose_feature_v2", new HashMap<>());
+//         double minScore = exp713Config.getOrDefault("minScore", 0.1d);
+//         double maxScore = exp713Config.getOrDefault("maxScore", 0.8d);
+//         double score = maxScore;
+//
+//         ctx.getLogParam().setBIsNewUser(true);
+//
+//         if (MapUtils.isNotEmpty(featureMap)) {
+//
+//             double adViewCnt = Double.parseDouble(featureMap.getOrDefault("ad_view_cnt", "0"));
+//             double adClick = Double.parseDouble(featureMap.getOrDefault("ad_click", "0"));
+//             double adConver = Double.parseDouble(featureMap.getOrDefault("ad_conver", "0"));
+//             double hasAdClick = Double.parseDouble(featureMap.getOrDefault("has_ad_click", "0"));
+//             double hasAdShare = Double.parseDouble(featureMap.getOrDefault("has_ad_share", "0"));
+//             double hasAdReturnCnt = Double.parseDouble(featureMap.getOrDefault("has_ad_return_cnt", "0"));
+//             double noAdClick = Double.parseDouble(featureMap.getOrDefault("no_ad_click", "0"));
+//             double noAdShare = Double.parseDouble(featureMap.getOrDefault("no_ad_share", "0"));
+//             double noAdReturnCnt = Double.parseDouble(featureMap.getOrDefault("no_ad_return_cnt", "0"));
+//
+//             // 计算出回流出广告时的收益
+//             double adClickValue = NumUtil.div(adClick, adViewCnt) * NumUtil.log10(adClick);
+//             double adConverValue = NumUtil.div(adConver, adViewCnt) * NumUtil.log10(adConver);
+//             double hasAdShareValue = NumUtil.div(hasAdShare, hasAdClick) * NumUtil.log10(hasAdShare);
+//             double hasAdReturnValue = NumUtil.div(hasAdReturnCnt, hasAdClick) * NumUtil.log10(hasAdReturnCnt);
+//             double hasAdValue = adClickValue + adConverValue + hasAdShareValue + hasAdReturnValue;
+//
+//             // 计算回流不出广告时的收益
+//             double noAdShareValue = NumUtil.div(noAdShare, noAdClick) * NumUtil.log10(noAdShare);
+//             double noAdReturnValue = NumUtil.div(noAdReturnCnt, noAdClick) * NumUtil.log10(noAdReturnCnt + hasAdReturnCnt);
+//             double noAdValue = noAdShareValue + noAdReturnValue;
+//
+//             // 计算最终的收益
+//             double hasRate = exp713Config.getOrDefault("hasRate", 1d);
+//             double noRate = exp713Config.getOrDefault("noRate", 1d);
+//             score = NumUtil.softmax(new double[]{hasAdValue * hasRate, noAdValue * noRate})[0];
+//
+//
+//             ctx.getLogParam().getMetaFeature().putAll(feature.getUserFeature());
+//             for (Map.Entry<String, String> entry : featureMap.entrySet()) {
+//                 ctx.getLogParam().getAllFeature().put(entry.getKey(), Double.parseDouble(entry.getValue()));
+//             }
+//             ctx.getLogParam().getScoreMap().put("adClickValue", NumUtil.round(adClickValue, 6));
+//             ctx.getLogParam().getScoreMap().put("adConverValue", NumUtil.round(adConverValue, 6));
+//             ctx.getLogParam().getScoreMap().put("hasAdShareValue", NumUtil.round(hasAdShareValue, 6));
+//             ctx.getLogParam().getScoreMap().put("hasAdReturnValue", NumUtil.round(hasAdReturnValue, 6));
+//             ctx.getLogParam().getScoreMap().put("hasAdValue", NumUtil.round(hasAdValue, 6));
+//             ctx.getLogParam().getScoreMap().put("noAdShareValue", NumUtil.round(noAdShareValue, 6));
+//             ctx.getLogParam().getScoreMap().put("noAdReturnValue", NumUtil.round(noAdReturnValue, 6));
+//             ctx.getLogParam().getScoreMap().put("noAdValue", NumUtil.round(noAdValue, 6));
+//             ctx.getLogParam().getScoreMap().put("originScore", NumUtil.round(score, 6));
+//             ctx.getLogParam().getScoreMap().put("hasRate", NumUtil.round(hasRate, 6));
+//             ctx.getLogParam().getScoreMap().put("noRate", NumUtil.round(noRate, 6));
+//
+//             ctx.getLogParam().setBIsNewUser(false);
+//         }
+//
+//         // 分数截断,避免过长或过短
+//         if (score < minScore) {
+//             score = minScore;
+//         } else if (score > maxScore) {
+//             score = maxScore;
+//         }
+//
+//         double random = Math.random();
+//         boolean isShowAd = random < score;
+//         ctx.getLogParam().setExpId("713");
+//         ctx.getLogParam().setScore(score);
+//         ctx.getLogParam().getScoreMap().put("score", NumUtil.round(score, 6));
+//         ctx.getLogParam().setAIsShowAd(isShowAd);
+//         ctx.getLogParam().getScoreMap().put("minScore", minScore);
+//         ctx.getLogParam().getScoreMap().put("maxScore", maxScore);
+//         ctx.getLogParam().getScoreMap().put("random", random);
+//
+//
+//         return isShowAd ? rtnAdPredict(ctx) : rtnNoAdPredict(ctx);
+//     }
+//
+//
+//     // public Map<String, Object> adPredictV1(PredictContext context){
+//     //
+//     //     Feature feature = featureService.getPredictFeature(context);
+//     //     Map<String, Map<String, String>> userFeature = feature.getUserFeature();
+//     //     Map<String, String> featureMap = userFeature.getOrDefault("alg_ad_crowd_choose_feature", new HashMap<>());
+//     //
+//     //     double score = -1;
+//     //
+//     //     // 没有特征为新用户,随机出广告
+//     //     if (MapUtils.isEmpty(featureMap)) {
+//     //         double newUserShowAdRate = exp713Config.getOrDefault("newUserShowAdRate", 0.8d);
+//     //         double randomRate = Math.random();
+//     //         if (randomRate < newUserShowAdRate) {
+//     //             context.getLogParam().getScoreMap().put("newUserShowAdRate", newUserShowAdRate);
+//     //             context.getLogParam().getScoreMap().put("randomRate", randomRate);
+//     //             score = 1;
+//     //         }
+//     //     } else {
+//     //         context.getLogParam().getMetaFeature().putAll(userFeature);
+//     //         for (Map.Entry<String, String> entry : featureMap.entrySet()) {
+//     //             context.getLogParam().getAllFeature().put(entry.getKey(), Double.parseDouble(entry.getValue()));
+//     //         }
+//     //
+//     //         // 获取需要的特征值
+//     //         double showAdClickPv = Double.parseDouble(featureMap.getOrDefault("show_ad_click_pv", "0"));
+//     //         double noShowAdClickPv = Double.parseDouble(featureMap.getOrDefault("no_show_ad_click_pv", "0"));
+//     //         double showAdIncome = Double.parseDouble(featureMap.getOrDefault("show_ad_income", "0"));
+//     //         double showAdSharePv = Double.parseDouble(featureMap.getOrDefault("show_ad_share_pv", "0"));
+//     //         double noShowAdSharePv = Double.parseDouble(featureMap.getOrDefault("no_show_ad_share_pv", "0"));
+//     //         double showAdNewReturnPv = Double.parseDouble(featureMap.getOrDefault("show_ad_new_return_pv", "0"));
+//     //         double noShowAdNewReturnPv = Double.parseDouble(featureMap.getOrDefault("no_show_ad_new_return_pv", "0"));
+//     //
+//     //         // 计算中间过程值
+//     //         double singleReturnAdIncome = NumUtil.div(showAdIncome, (showAdClickPv + noShowAdClickPv));
+//     //         double showAdShareRate = NumUtil.div((showAdSharePv + 1), (showAdClickPv + 1));
+//     //         double noShowAdShareRate = NumUtil.div((noShowAdSharePv + 1), (noShowAdClickPv + 1));
+//     //         double returnDivShare = NumUtil.div((showAdNewReturnPv + noShowAdNewReturnPv + 1), (showAdSharePv + noShowAdSharePv + 1));
+//     //
+//     //         double busDauBalanceRate = exp713Config.getOrDefault("busDauBalanceRate", 0.1d);
+//     //         score = singleReturnAdIncome + ((showAdShareRate - noShowAdShareRate) * returnDivShare * busDauBalanceRate);
+//     //
+//     //
+//     //         context.getLogParam().getScoreMap().put("singleReturnAdIncome", singleReturnAdIncome);
+//     //         context.getLogParam().getScoreMap().put("showAdShareRate", showAdShareRate);
+//     //         context.getLogParam().getScoreMap().put("noShowAdShareRate", noShowAdShareRate);
+//     //         context.getLogParam().getScoreMap().put("returnDivShare", returnDivShare);
+//     //         context.getLogParam().getScoreMap().put("busDauBalanceRate", busDauBalanceRate);
+//     //
+//     //     }
+//     //     double showAdScoreThreshold = exp713Config.getOrDefault("showAdScoreThreshold", 0d);
+//     //     boolean isShowAd = score >= showAdScoreThreshold;
+//     //
+//     //     context.getLogParam().setAIsShowAd(isShowAd);
+//     //     context.getLogParam().setExpId("713");
+//     //     context.getLogParam().setScore(score);
+//     //     context.getLogParam().getScoreMap().put("score", score);
+//     //     context.getLogParam().getScoreMap().put("showAdScoreThreshold", showAdScoreThreshold);
+//     //
+//     //
+//     //     logHubService.crowdChooseLogUpload(context);
+//     //
+//     //
+//     //     if (isShowAd) {
+//     //         Map<String, Object> rtnMap = rtnAdPredict();
+//     //         rtnMap.putAll(context.getLogParam().getScoreMap());
+//     //         return rtnMap;
+//     //     } else {
+//     //         return rtnNoAdPredict("713_exp");
+//     //     }
+//     // }
+// }

+ 43 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy599.java

@@ -0,0 +1,43 @@
+package com.tzld.piaoquan.ad.engine.service.predict.v2;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Slf4j
+@Service
+public class PredictStrategyBy599 extends ThresholdPredictStrategy {
+    @Override
+    Map<String, Double> thresholdConfig(PredictContext ctx) {
+        try {
+            JSONObject json = ctx.getExpConfigMap().getOrDefault("599", new JSONObject());
+            return json.toJavaObject(new TypeReference<Map<String, Double>>() {
+            });
+        } catch (Exception e) {
+            log.error("PredictStrategyBy599 parse 599 exp param error \n", e);
+            return Collections.emptyMap();
+        }
+    }
+
+    @Override
+    List<String> genThresholdKeys(PredictContext ctx) {
+
+        List<String> keys = new ArrayList<>();
+        for (String appType : Arrays.asList(ctx.getAppType(), "default")) {
+            for (String userLayer : Arrays.asList(ctx.getUserLayer(), "default")) {
+                keys.add(String.join("_", appType, userLayer, ctx.getHandleAfterShareType()));
+            }
+        }
+        keys.add("default_threshold");
+        return keys;
+    }
+
+    @Override
+    public String name() {
+        return "599";
+    }
+
+}

+ 42 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy667.java

@@ -0,0 +1,42 @@
+package com.tzld.piaoquan.ad.engine.service.predict.v2;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Slf4j
+@Service
+public class PredictStrategyBy667 extends ThresholdPredictStrategy {
+    @Override
+    Map<String, Double> thresholdConfig(PredictContext ctx) {
+        try {
+            JSONObject json = ctx.getExpConfigMap().getOrDefault("667", new JSONObject());
+            return json.toJavaObject(new TypeReference<Map<String, Double>>() {
+            });
+        } catch (Exception e) {
+            log.error("PredictStrategyBy667 parse 667 exp param error \n", e);
+            return Collections.emptyMap();
+        }
+    }
+
+    @Override
+    List<String> genThresholdKeys(PredictContext ctx) {
+        List<String> keys = new ArrayList<>();
+        for (String appType : Arrays.asList(ctx.getAppType(), "default")) {
+            for (String userLayer : Arrays.asList(ctx.getUserLayer(), "default")) {
+                keys.add(String.join("_", appType, userLayer, ctx.getHandleAfterShareType()));
+            }
+        }
+        keys.add("default_threshold");
+        return keys;
+    }
+
+    @Override
+    public String name() {
+        return "667";
+    }
+
+}

+ 111 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy673.java

@@ -0,0 +1,111 @@
+package com.tzld.piaoquan.ad.engine.service.predict.v2;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Slf4j
+@Service
+public class PredictStrategyBy673 extends ThresholdPredictStrategy {
+
+    @Value("${filter.with.region:1}")
+    private String filterWithRegion;
+    @Override
+    Map<String, Double> thresholdConfig(PredictContext ctx) {
+
+        if (StringUtils.isAnyBlank(ctx.getUserExternalSource(), ctx.getShareLayer())) {
+            return Collections.emptyMap();
+        }
+
+        try {
+            JSONObject json = ctx.getExpConfigMap().getOrDefault("673", new JSONObject());
+            String configKey = String.format("%s:%s", ctx.getUserExternalSource(), ctx.getShareLayer());
+            if("1".equals(filterWithRegion) && StringUtils.isNotBlank(configKey)) {
+                String region = StringUtils.isBlank(ctx.getRegion()) ? "未知地区" : ctx.getRegion();
+                String city = StringUtils.isBlank(ctx.getCity()) ? "未知地区" : ctx.getCity();
+                configKey = configKey + ":" + region + "_" + city;
+                log.info( "PredictStrategyBy673 configKey: {}", configKey);
+            }
+            JSONObject configJson = json.getJSONObject(configKey);
+            if (MapUtils.isEmpty(configJson)) {
+                return Collections.emptyMap();
+            }
+            return configJson.toJavaObject(new TypeReference<Map<String, Double>>() {
+            });
+        } catch (Exception e) {
+            log.error("PredictStrategyBy673 parse 673 exp param error \n", e);
+            return Collections.emptyMap();
+        }
+    }
+
+    @Override
+    public Map<String, Object> predict(PredictContext ctx) {
+        Map<String, Double> thresholdConfig = this.thresholdConfig(ctx);
+        if (MapUtils.isEmpty(thresholdConfig)) {
+            return null;
+        }
+        double score = this.calcScoreByMid(ctx.getMid());
+
+        List<String> thresholdKeys = genThresholdKeys(ctx);
+        if (CollectionUtils.isEmpty(thresholdKeys)) {
+            return null;
+        }
+
+        String finalThresholdKeys = "";
+        double threshold = 0d;
+
+        for (String thresholdKey : thresholdKeys) {
+            if (thresholdConfig.containsKey(thresholdKey)) {
+                finalThresholdKeys = thresholdKey;
+                threshold = thresholdConfig.get(thresholdKey);
+                break;
+            }
+        }
+        Map<String, Object> rtnMap = new HashMap<>();
+        if (score < threshold) {
+            rtnMap.putAll(rtnAdPredict(ctx));
+            rtnMap.put("model", this.name());
+        } else {
+            rtnMap.putAll(rtnNoAdPredict(ctx));
+            rtnMap.put("no_ad_strategy", this.name());
+        }
+
+        rtnMap.put("score", score);
+        rtnMap.put("threshold", threshold);
+        rtnMap.put("userLayer", ctx.getUserLayer());
+        rtnMap.put("thresholdParamKey", finalThresholdKeys);
+        rtnMap.put("shareType", ctx.getHandleAfterShareType());
+
+        this.printLog(rtnMap, ctx, thresholdConfig);
+
+        return rtnMap;
+
+    }
+
+
+    @Override
+    List<String> genThresholdKeys(PredictContext ctx) {
+
+        List<String> keys = new ArrayList<>();
+        for (String appType : Arrays.asList(ctx.getAppType(), "default")) {
+            for (String userLayer : Arrays.asList(ctx.getUserLayer(), "default")) {
+                keys.add(String.join("_", appType, userLayer, ctx.getHandleAfterShareType()));
+            }
+        }
+        keys.add("default_threshold");
+        return keys;
+    }
+
+    @Override
+    public String name() {
+        return "673";
+    }
+
+}

+ 103 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy817.java

@@ -0,0 +1,103 @@
+package com.tzld.piaoquan.ad.engine.service.predict.v2;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
+import com.tzld.piaoquan.ad.engine.commons.util.JSONUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Slf4j
+@Service
+public class PredictStrategyBy817 extends BasicPredict {
+
+    @ApolloJsonValue("${experiment.817.root.session.id.tail.config:[]}")
+    private List<RootSessionIdTailConfigItem> configItems;
+
+    @Override
+    public String name() {
+        return "817";
+    }
+
+    @Override
+    public Map<String, Object> predict(PredictContext ctx) {
+
+        String rootSessionId = ctx.getRootSessionId();
+        String userLayer = ctx.getUserLayer();
+        String shareType = ctx.getShareType();
+        if (CollectionUtils.isEmpty(configItems) || StringUtils.isAnyBlank(rootSessionId, userLayer, shareType)) {
+            Map<String, Object> returnMap = new HashMap<>();
+            returnMap.putAll(rtnNoAdPredict(ctx));
+            returnMap.put("msg","no_config_error");
+            return returnMap;
+        }
+
+        double score = this.calcScoreByMid(ctx.getMid());
+        String tail = rootSessionId.substring(rootSessionId.length() - 1);
+        shareType = ctx.getShareType()
+                .replace("return", "")
+                .replace("mids", "");
+
+        for (RootSessionIdTailConfigItem item : configItems) {
+            if (item.getTail().contains(tail)) {
+                Map<String, Object> returnMap = new HashMap<>();
+                double threshold;
+                String thresholdKey = "";
+
+                // 生成可用的Key列表
+                List<String> keys = Arrays.asList(userLayer + "_" + shareType, "default_" + shareType, "default_threshold");
+                for (String key : keys) {
+                    if (item.getConfig().containsKey(key)) {
+                        thresholdKey = key;
+                        break;
+                    }
+                }
+
+
+                threshold = item.getConfig().getOrDefault(thresholdKey, 0.0);
+
+                if (score < threshold) {
+                    returnMap.putAll(rtnAdPredict(ctx));
+                    returnMap.put("model", this.name());
+                } else {
+                    returnMap.putAll(rtnNoAdPredict(ctx));
+                    returnMap.put("no_ad_strategy", this.name());
+                }
+
+                returnMap.put("score", score);
+                returnMap.put("threshold", threshold);
+                returnMap.put("userLayer", userLayer);
+
+                JSONObject logJson = new JSONObject();
+                logJson.putAll(returnMap);
+                logJson.put("mid", ctx.getMid());
+                logJson.put("appType", ctx.getAppType());
+                logJson.put("rootSessionIdTail", tail);
+                logJson.put("shareType", shareType);
+
+                logJson.put("expId", "userLayerRootSessionIdTailExp");
+                logJson.put("thresholdParamKey", thresholdKey);
+                logJson.put("adPlatformType", ctx.getAdPlatformType());
+                logJson.put("abCode", ctx.getAdAbCode());
+                logJson.put("configItem", item);
+                logJson.put("rootSessionId", ctx.getRootSessionId());
+
+                log.info("广告跳出选择 -- 817实验结果: {}, 参数: {}",
+                        JSONUtils.toJson(returnMap), logJson.toJSONString());
+
+                return returnMap;
+            }
+        }
+
+        Map<String, Object> returnMap = new HashMap<>();
+        returnMap.putAll(rtnNoAdPredict(ctx));
+        returnMap.put("msg","no_config_error");
+        return returnMap;
+    }
+
+}

+ 85 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy819.java

@@ -0,0 +1,85 @@
+package com.tzld.piaoquan.ad.engine.service.predict.v2;
+
+import com.alibaba.fastjson.JSONObject;
+import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
+import com.tzld.piaoquan.ad.engine.commons.util.JSONUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service
+public class PredictStrategyBy819 extends BasicPredict {
+
+    @ApolloJsonValue("${experiment.819.root.session.id.tail.config:[]}")
+    private List<RootSessionIdTailConfigItem> configItems;
+
+    @Override
+    public String name() {
+        return "819";
+    }
+
+    @Override
+    public Map<String, Object> predict(PredictContext ctx) {
+        Map<String, Object> returnMap = new HashMap<>();
+        String rootSessionId = ctx.getRootSessionId();
+        String userLayer = ctx.getUserLayer();
+        String shareType = ctx.getShareType();
+        returnMap.put("ecpm_model","819");
+        if (CollectionUtils.isEmpty(configItems) || StringUtils.isAnyBlank(rootSessionId, userLayer, shareType)) {
+            returnMap.put("ecpm_msg","no_config_error");
+            return returnMap;
+        }
+        String tail = rootSessionId.substring(rootSessionId.length() - 1);
+        shareType = ctx.getShareType()
+                .replace("return", "")
+                .replace("mids", "");
+
+        for (RootSessionIdTailConfigItem item : configItems) {
+            if (item.getTail().contains(tail)) {
+                String thresholdKey = "";
+                // 生成可用的Key列表
+                List<String> keys = Arrays.asList(userLayer + "_" + shareType, "default_" + shareType, "default_threshold");
+                for (String key : keys) {
+                    if (item.getConfig().containsKey(key)) {
+                        thresholdKey = key;
+                        break;
+                    }
+                }
+
+                double ecpm = item.getConfig().getOrDefault(thresholdKey, -1.0);
+                returnMap.put("ecpm_value", ecpm);
+                returnMap.put("ecpm_thresholdKey", thresholdKey);
+                returnMap.put("ecpm_userLayer", userLayer);
+                returnMap.put("ecpm_rootSessionId", ctx.getRootSessionId());
+                JSONObject logJson = new JSONObject();
+                logJson.putAll(returnMap);
+                logJson.put("mid", ctx.getMid());
+                logJson.put("appType", ctx.getAppType());
+                logJson.put("rootSessionIdTail", tail);
+                logJson.put("shareType", shareType);
+
+                logJson.put("expId", "userLayerRootSessionIdTailExp");
+                logJson.put("thresholdParamKey", thresholdKey);
+                logJson.put("adPlatformType", ctx.getAdPlatformType());
+                logJson.put("abCode", ctx.getAdAbCode());
+                logJson.put("configItem", item);
+                logJson.put("rootSessionId", ctx.getRootSessionId());
+
+                log.info("广告跳出选择 -- 819实验结果: {}, 参数: {}",
+                        JSONUtils.toJson(returnMap), logJson.toJSONString());
+
+                return returnMap;
+            }
+        }
+        returnMap.put("ecpm_msg","未命中");
+        return returnMap;
+    }
+
+}

+ 93 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy820.java

@@ -0,0 +1,93 @@
+package com.tzld.piaoquan.ad.engine.service.predict.v2;
+
+import com.alibaba.fastjson.JSONObject;
+import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
+import com.tzld.piaoquan.ad.engine.commons.util.JSONUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Slf4j
+@Service
+public class PredictStrategyBy820 extends BasicPredict {
+
+    @ApolloJsonValue("${experiment.820.root.session.id.tail.config:[]}")
+    private List<RootSessionIdTailConfigItem> configItems;
+
+    @Override
+    public String name() {
+        return "820";
+    }
+
+    @Override
+    public Map<String, Object> predict(PredictContext ctx) {
+
+        String rootSessionId = ctx.getRootSessionId();
+        String userLayer = ctx.getUserLayer();
+        String shareType = ctx.getShareType();
+        if (CollectionUtils.isEmpty(configItems) || StringUtils.isAnyBlank(rootSessionId, userLayer, shareType)) {
+            return Collections.emptyMap();
+        }
+        double score = this.calcScoreByMid(ctx.getMid());
+        String tail = rootSessionId.substring(rootSessionId.length() - 1);
+        shareType = ctx.getShareType()
+                .replace("return", "")
+                .replace("mids", "");
+
+        for (RootSessionIdTailConfigItem item : configItems) {
+            if (item.getTail().contains(tail)) {
+                Map<String, Object> returnMap = new HashMap<>();
+                double threshold;
+                String thresholdKey = "";
+
+                // 生成可用的Key列表
+                List<String> keys = Arrays.asList(userLayer + "_" + shareType, "default_" + shareType, "default_threshold");
+                for (String key : keys) {
+                    if (item.getConfig().containsKey(key)) {
+                        thresholdKey = key;
+                        break;
+                    }
+                }
+
+
+                threshold = item.getConfig().getOrDefault(thresholdKey, 0.0);
+
+                if (score < threshold) {
+                    returnMap.putAll(rtnAdPredict(ctx));
+                    returnMap.put("model", this.name());
+                } else {
+                    returnMap.putAll(rtnNoAdPredict(ctx));
+                    returnMap.put("no_ad_strategy", this.name());
+                }
+
+                returnMap.put("score", score);
+                returnMap.put("threshold", threshold);
+                returnMap.put("userLayer", userLayer);
+
+                JSONObject logJson = new JSONObject();
+                logJson.putAll(returnMap);
+                logJson.put("mid", ctx.getMid());
+                logJson.put("appType", ctx.getAppType());
+                logJson.put("rootSessionIdTail", tail);
+                logJson.put("shareType", shareType);
+
+                logJson.put("expId", "userLayerRootSessionIdTailExp");
+                logJson.put("thresholdParamKey", thresholdKey);
+                logJson.put("adPlatformType", ctx.getAdPlatformType());
+                logJson.put("abCode", ctx.getAdAbCode());
+                logJson.put("configItem", item);
+                logJson.put("rootSessionId", ctx.getRootSessionId());
+
+                log.info("广告跳出选择 -- 820实验结果: {}, 参数: {}",
+                        JSONUtils.toJson(returnMap), logJson.toJSONString());
+
+                return returnMap;
+            }
+        }
+        return Collections.emptyMap();
+    }
+
+}

+ 153 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyBy823.java

@@ -0,0 +1,153 @@
+package com.tzld.piaoquan.ad.engine.service.predict.v2;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
+import com.tzld.piaoquan.ad.engine.commons.util.JSONUtils;
+import com.tzld.piaoquan.ad.engine.service.predict.param.request.ThresholdPredictModelRequestParam;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Slf4j
+@Service
+public class PredictStrategyBy823 extends BasicPredict {
+
+    @Value("${experiment.823.ad.hour:0,8}")
+    private String experiment823WithAdHour;
+
+    @ApolloJsonValue("${experiment.823.config:{}}")
+    private JSONObject experiment823Config;
+
+
+    @Override
+    public String name() {
+        return "823";
+    }
+
+    @Override
+    public Map<String, Object> predict(PredictContext ctx) {
+
+        String rootSessionId = ctx.getRootSessionId();
+        String userLayer = ctx.getUserLayer();
+        String shareType = ctx.getShareType();
+
+        double score = this.calcScoreByMid(ctx.getMid());
+        String tail = rootSessionId.substring(rootSessionId.length() - 1);
+        shareType = ctx.getShareType()
+                .replace("return", "")
+                .replace("mids", "");
+
+        Map<String, Object> returnMap = new HashMap<>();
+
+
+        returnMap.putAll(rtnAdPredict(ctx));
+        returnMap.put("model", this.name());
+
+        returnMap.put("score", score);
+        returnMap.put("userLayer", userLayer);
+
+        JSONObject logJson = new JSONObject();
+        logJson.putAll(returnMap);
+        logJson.put("mid", ctx.getMid());
+        logJson.put("appType", ctx.getAppType());
+        logJson.put("rootSessionIdTail", tail);
+        logJson.put("shareType", shareType);
+
+        logJson.put("expId", "userLayerRootSessionIdTailExp");
+        logJson.put("adPlatformType", ctx.getAdPlatformType());
+        logJson.put("abCode", ctx.getAdAbCode());
+        logJson.put("rootSessionId", ctx.getRootSessionId());
+
+        log.info("广告跳出选择 -- 823实验结果: {}, 参数: {}",
+                JSONUtils.toJson(returnMap), logJson.toJSONString());
+
+        return returnMap;
+    }
+
+    public void addConfigExt(ThresholdPredictModelRequestParam params, Map<String, Object> resultMap) {
+        String channel = "*";
+        List<String> channels = new ArrayList<>(experiment823Config.keySet());
+        for (String s : channels) {
+            if (params.getRootSourceId().startsWith(s)) {
+                channel = s;
+                break;
+            }
+        }
+        JSONObject LayerConfig = experiment823Config.getJSONObject(channel);
+        JSONObject config;
+        if (params.getUserShareDepth() == 0) {
+            config = LayerConfig.getJSONObject("首层");
+        } else {
+            config = LayerConfig.getJSONObject("非首层");
+        }
+
+        resultMap.put("headVideo", config.getJSONObject("headVideo"));
+        resultMap.put("recommend", config.getJSONObject("recommend"));
+    }
+
+    public boolean in823Ab(ThresholdPredictModelRequestParam params, Set<String> expCodes, int hourOfDay) {
+        if (params.getUserShareDepth() != 0 || !expCodes.contains("823")) {
+            return false;
+        }
+        boolean isIn823Time = false;
+        try {
+            String[] split = experiment823WithAdHour.split(",");
+            if (Integer.parseInt(split[0]) <= hourOfDay && hourOfDay < Integer.parseInt(split[1])) {
+                isIn823Time = true;
+            }
+        } catch (Exception e) {
+            log.error("experiment823WithAdHour配置异常", e);
+        }
+        if (!isIn823Time) {
+            return false;
+        }
+        String channel = "*";
+        List<String> channels = new ArrayList<>(experiment823Config.keySet());
+        for (String s : channels) {
+            if (params.getRootSourceId().startsWith(s)) {
+                channel = s;
+                break;
+            }
+        }
+        JSONObject LayerConfig = experiment823Config.getJSONObject(channel);
+        JSONObject config;
+        if (params.getUserShareDepth() == 0) {
+            config = LayerConfig.getJSONObject("首层");
+        } else {
+            config = LayerConfig.getJSONObject("非首层");
+        }
+        JSONArray rootSessionIds = config.getJSONArray("rootSessionId");
+        if (Objects.isNull(rootSessionIds) || !rootSessionIds.contains(getGroup(params.getRootSessionId()))) {
+            return false;
+        }
+        JSONArray putScenes = config.getJSONArray("putScene");
+        if (Objects.isNull(putScenes)) {
+            if (channel.equals("*")) {
+                return false;
+            } else {
+                return true;
+            }
+        }
+        boolean isScene = false;
+        for (Object putScene : putScenes) {
+            if (params.getRootSourceId().startsWith((String) putScene)) {
+                isScene = true;
+                break;
+            }
+        }
+        return isScene;
+    }
+
+    private String getGroup(String rootSessionId) {
+        if (StringUtils.isBlank(rootSessionId)) {
+            return null;
+        }
+        return String.valueOf(rootSessionId.charAt(rootSessionId.length() - 1));
+    }
+}
+

+ 86 - 86
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/RootSessionIdPredict.java

@@ -1,86 +1,86 @@
-package com.tzld.piaoquan.ad.engine.service.predict.v2;
-
-import com.alibaba.fastjson.JSONObject;
-import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
-import com.tzld.piaoquan.ad.engine.commons.util.JSONUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.stereotype.Component;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-@Slf4j
-@Component
-public class RootSessionIdPredict extends BasicPredict {
-
-    @ApolloJsonValue("${root.session.id.tail.predict.config:[]}")
-    private List<RootSessionIdTailConfigItem> configItems;
-
-    @Override
-    public Map<String, Object> predict(PredictContext ctx) {
-        String rootSessionId = ctx.getRootSessionId();
-        if (CollectionUtils.isEmpty(configItems) || StringUtils.isEmpty(rootSessionId) || StringUtils.isEmpty(ctx.getShareType())) {
-            return Collections.emptyMap();
-        }
-
-
-        double score = this.calcScoreByMid(ctx.getMid());
-
-        String appType = ctx.getAppType();
-        String tail = rootSessionId.substring(rootSessionId.length() - 1);
-        String shareType = ctx.getShareType()
-                .replace("return", "")
-                .replace("mids", "");
-
-
-        for (RootSessionIdTailConfigItem item : configItems) {
-            if (item.getAppType().contains(appType) && item.getTail().contains(tail)) {
-                double threshold;
-                if (item.getConfig().containsKey(shareType)) {
-                    threshold = item.getConfig().getOrDefault(shareType, 0d);
-                } else {
-                    threshold = item.getConfig().getOrDefault("threshold", 0d);
-                }
-
-                Map<String, Object> returnMap = new HashMap<>();
-
-                if (score < threshold) {
-                    returnMap.putAll(rtnAdPredict(ctx));
-                    returnMap.put("model", "rootSessionIdTailModel");
-                } else {
-                    returnMap.putAll(rtnNoAdPredict(ctx));
-                    returnMap.put("no_ad_strategy", "rootSessionIdTailModel");
-                }
-
-                returnMap.put("score", score);
-                returnMap.put("threshold", threshold);
-
-                JSONObject logJson = new JSONObject();
-                logJson.putAll(returnMap);
-                logJson.put("mid", ctx.getMid());
-                logJson.put("appType", appType);
-                logJson.put("rootSessionIdTail", tail);
-                logJson.put("shareType", shareType);
-
-                logJson.put("expId", "rootSessionIdTailExp");
-                logJson.put("thresholdParamKey", shareType);
-                logJson.put("adPlatformType", ctx.getAdPlatformType());
-                logJson.put("abCode", ctx.getAdAbCode());
-                logJson.put("extraParam", ctx.getExpConfigMap());
-                logJson.put("configItem", item);
-                logJson.put("rootSessionId", ctx.getRootSessionId());
-
-                log.info("广告跳出选择 -- rootSessionId尾号实验结果: {}, 参数: {}",
-                        JSONUtils.toJson(returnMap), logJson.toJSONString());
-
-                return returnMap;
-            }
-        }
-
-        return Collections.emptyMap();
-    }
-}
+// package com.tzld.piaoquan.ad.engine.service.predict.v2;
+//
+// import com.alibaba.fastjson.JSONObject;
+// import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
+// import com.tzld.piaoquan.ad.engine.commons.util.JSONUtils;
+// import lombok.extern.slf4j.Slf4j;
+// import org.apache.commons.collections4.CollectionUtils;
+// import org.apache.commons.lang3.StringUtils;
+// import org.springframework.stereotype.Component;
+//
+// import java.util.Collections;
+// import java.util.HashMap;
+// import java.util.List;
+// import java.util.Map;
+//
+// @Slf4j
+// @Component
+// public class RootSessionIdPredict extends BasicPredict {
+//
+//     @ApolloJsonValue("${root.session.id.tail.predict.config:[]}")
+//     private List<RootSessionIdTailConfigItem> configItems;
+//
+//     @Override
+//     public Map<String, Object> predict(PredictContext ctx) {
+//         String rootSessionId = ctx.getRootSessionId();
+//         if (CollectionUtils.isEmpty(configItems) || StringUtils.isEmpty(rootSessionId) || StringUtils.isEmpty(ctx.getShareType())) {
+//             return Collections.emptyMap();
+//         }
+//
+//
+//         double score = this.calcScoreByMid(ctx.getMid());
+//
+//         String appType = ctx.getAppType();
+//         String tail = rootSessionId.substring(rootSessionId.length() - 1);
+//         String shareType = ctx.getShareType()
+//                 .replace("return", "")
+//                 .replace("mids", "");
+//
+//
+//         for (RootSessionIdTailConfigItem item : configItems) {
+//             if (item.getAppType().contains(appType) && item.getTail().contains(tail)) {
+//                 double threshold;
+//                 if (item.getConfig().containsKey(shareType)) {
+//                     threshold = item.getConfig().getOrDefault(shareType, 0d);
+//                 } else {
+//                     threshold = item.getConfig().getOrDefault("threshold", 0d);
+//                 }
+//
+//                 Map<String, Object> returnMap = new HashMap<>();
+//
+//                 if (score < threshold) {
+//                     returnMap.putAll(rtnAdPredict(ctx));
+//                     returnMap.put("model", "rootSessionIdTailModel");
+//                 } else {
+//                     returnMap.putAll(rtnNoAdPredict(ctx));
+//                     returnMap.put("no_ad_strategy", "rootSessionIdTailModel");
+//                 }
+//
+//                 returnMap.put("score", score);
+//                 returnMap.put("threshold", threshold);
+//
+//                 JSONObject logJson = new JSONObject();
+//                 logJson.putAll(returnMap);
+//                 logJson.put("mid", ctx.getMid());
+//                 logJson.put("appType", appType);
+//                 logJson.put("rootSessionIdTail", tail);
+//                 logJson.put("shareType", shareType);
+//
+//                 logJson.put("expId", "rootSessionIdTailExp");
+//                 logJson.put("thresholdParamKey", shareType);
+//                 logJson.put("adPlatformType", ctx.getAdPlatformType());
+//                 logJson.put("abCode", ctx.getAdAbCode());
+//                 logJson.put("extraParam", ctx.getExpConfigMap());
+//                 logJson.put("configItem", item);
+//                 logJson.put("rootSessionId", ctx.getRootSessionId());
+//
+//                 log.info("广告跳出选择 -- rootSessionId尾号实验结果: {}, 参数: {}",
+//                         JSONUtils.toJson(returnMap), logJson.toJSONString());
+//
+//                 return returnMap;
+//             }
+//         }
+//
+//         return Collections.emptyMap();
+//     }
+// }

+ 74 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/ThresholdPredictStrategy.java

@@ -0,0 +1,74 @@
+package com.tzld.piaoquan.ad.engine.service.predict.v2;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.tzld.piaoquan.ad.engine.commons.util.JSONUtils;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+public abstract class ThresholdPredictStrategy extends BasicPredict {
+
+    abstract Map<String, Double> thresholdConfig(PredictContext ctx);
+
+    abstract List<String> genThresholdKeys(PredictContext ctx);
+
+    @Override
+    public Map<String, Object> predict(PredictContext ctx) {
+        Map<String, Double> thresholdConfig = this.thresholdConfig(ctx);
+
+        double score = this.calcScoreByMid(ctx.getMid());
+
+        List<String> thresholdKeys = genThresholdKeys(ctx);
+
+        String finalThresholdKeys = "";
+        double threshold = 0d;
+
+        for (String thresholdKey : thresholdKeys) {
+            if (thresholdConfig.containsKey(thresholdKey)) {
+                finalThresholdKeys = thresholdKey;
+                threshold = thresholdConfig.get(thresholdKey);
+                break;
+            }
+        }
+
+        Map<String, Object> rtnMap = new HashMap<>();
+        if (score < threshold) {
+            rtnMap.putAll(rtnAdPredict(ctx));
+            rtnMap.put("model", this.name());
+        } else {
+            rtnMap.putAll(rtnNoAdPredict(ctx));
+            rtnMap.put("no_ad_strategy", this.name());
+        }
+
+        rtnMap.put("score", score);
+        rtnMap.put("threshold", threshold);
+        rtnMap.put("userLayer", ctx.getUserLayer());
+        rtnMap.put("thresholdParamKey", finalThresholdKeys);
+        rtnMap.put("shareType", ctx.getHandleAfterShareType());
+
+        this.printLog(rtnMap, ctx, thresholdConfig);
+
+        return rtnMap;
+
+    }
+
+    protected void printLog(Map<String, Object> rtnMap, PredictContext ctx, Map<String, Double> thresholdConfig) {
+        JSONObject logJson = new JSONObject();
+        logJson.putAll(rtnMap);
+        logJson.put("mid", ctx.getMid());
+        logJson.put("appType", ctx.getAppType());
+
+        logJson.put("expId", this.name());
+        logJson.put("adPlatformType", ctx.getAdPlatformType());
+        logJson.put("abCode", ctx.getAdAbCode());
+        logJson.put("configItem", thresholdConfig);
+        logJson.put("rootSessionId", ctx.getRootSessionId());
+
+        log.info("广告跳出选择 -- {}实验结果: {}, 参数: {}",
+                this.name(), JSONUtils.toJson(rtnMap), logJson.toJSONString());
+    }
+}

+ 7 - 7
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/UserLayerRootSessionIdPredict.java

@@ -3,11 +3,9 @@ package com.tzld.piaoquan.ad.engine.service.predict.v2;
 import com.alibaba.fastjson.JSONObject;
 import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
 import com.tzld.piaoquan.ad.engine.commons.util.JSONUtils;
-import com.tzld.piaoquan.ad.engine.service.user.UserService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import java.util.*;
@@ -16,9 +14,6 @@ import java.util.*;
 @Component
 public class UserLayerRootSessionIdPredict extends BasicPredict {
 
-    @Autowired
-    private UserService userService;
-
     @ApolloJsonValue("${user.layer.root.session.id.tail.predict.config:[]}")
     private List<RootSessionIdTailConfigItem> configItems;
 
@@ -59,10 +54,10 @@ public class UserLayerRootSessionIdPredict extends BasicPredict {
 
                 if (score < threshold) {
                     returnMap.putAll(rtnAdPredict(ctx));
-                    returnMap.put("model", "userLayerRootSessionIdTailModel");
+                    returnMap.put("model", this.name());
                 } else {
                     returnMap.putAll(rtnNoAdPredict(ctx));
-                    returnMap.put("no_ad_strategy", "userLayerRootSessionIdTailModel");
+                    returnMap.put("no_ad_strategy", this.name());
                 }
 
                 returnMap.put("score", score);
@@ -93,4 +88,9 @@ public class UserLayerRootSessionIdPredict extends BasicPredict {
 
         return Collections.emptyMap();
     }
+
+    @Override
+    public String name() {
+        return "userLayerRootSessionIdTailModel";
+    }
 }

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

@@ -1,6 +1,7 @@
 package com.tzld.piaoquan.ad.engine.service.score.convert;
 
 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.param.RecommendRequestParam;
 import com.tzld.piaoquan.ad.engine.commons.score.ScoreParam;
 import com.tzld.piaoquan.ad.engine.commons.util.AbUtil;
@@ -45,6 +46,9 @@ public class RequestConvert {
         // 本次命中的实验
         String expCode = AbUtil.chooseAdAlgExpCode(expCodeSet, request.getAppType(), request.getNewExpGroup());
         scoreParam.setExpCode(expCode);
+        if (request instanceof RankRecommendRequestParam) {
+            scoreParam.setEngineInfo(((RankRecommendRequestParam) request).getEngineInfo());
+        }
         return scoreParam;
     }
 

+ 63 - 11
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/scorer/PAIScorer.java

@@ -7,7 +7,9 @@ import com.tzld.piaoquan.ad.engine.commons.score.BaseXGBoostModelScorer;
 import com.tzld.piaoquan.ad.engine.commons.score.ScoreParam;
 import com.tzld.piaoquan.ad.engine.commons.score.ScorerConfigInfo;
 import com.tzld.piaoquan.ad.engine.commons.score.model.PAIModelV1;
+import com.tzld.piaoquan.ad.engine.commons.score.model.PAIModelV2;
 import com.tzld.piaoquan.ad.engine.commons.score.model.XGBoostModel683;
+import com.tzld.piaoquan.ad.engine.commons.thread.ThreadPoolFactory;
 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;
@@ -53,29 +55,79 @@ public class PAIScorer extends AbstractScorer {
         return result;
     }
 
+//    private List<AdRankItem> rankByJava(final Map<String, String> sceneFeatureMap,
+//                                        final Map<String, String> userFeatureMap,
+//                                        final List<AdRankItem> items) {
+//        long startTime = System.currentTimeMillis();
+//        PAIModelV1 model = PAIModelV1.getModel();
+//        // 所有都参与打分,按照ctr排序
+//        multipleCtrScore(items, userFeatureMap, sceneFeatureMap, model);
+//
+//        // debug log
+//        if (LOGGER.isDebugEnabled()) {
+//            for (int i = 0; i < items.size(); i++) {
+//                LOGGER.debug("before enter feeds model predict ctr score [{}] [{}]", items.get(i), items.get(i));
+//            }
+//        }
+//
+//        Collections.sort(items);
+//
+//        LOGGER.debug("ctr ranker java execute time: [{}]", System.currentTimeMillis() - startTime);
+//        LOGGER.debug("[ctr ranker time java] items size={}, cost={} ", items != null ? items.size() : 0,
+//                System.currentTimeMillis() - startTime);
+//        return items;
+//    }
+
     private List<AdRankItem> rankByJava(final Map<String, String> sceneFeatureMap,
                                         final Map<String, String> userFeatureMap,
                                         final List<AdRankItem> items) {
+        if (items == null || items.isEmpty()) {
+            return Collections.emptyList();
+        }
+
         long startTime = System.currentTimeMillis();
         PAIModelV1 model = PAIModelV1.getModel();
-        // 所有都参与打分,按照ctr排序
-        multipleCtrScore(items, userFeatureMap, sceneFeatureMap, model);
 
-        // debug log
-        if (LOGGER.isDebugEnabled()) {
-            for (int i = 0; i < items.size(); i++) {
-                LOGGER.debug("before enter feeds model predict ctr score [{}] [{}]", items.get(i), items.get(i));
+        final int batchSize = 300;
+        List<List<AdRankItem>> batches = new ArrayList<>();
+        for (int i = 0; i < items.size(); i += batchSize) {
+            batches.add(new ArrayList<>(items.subList(i, Math.min(i + batchSize, items.size()))));
+        }
+
+        ExecutorService executor = ThreadPoolFactory.score();
+        List<Future<List<AdRankItem>>> futures = new ArrayList<>();
+
+        for (List<AdRankItem> batch : batches) {
+            futures.add(executor.submit(() -> {
+                try {
+                    multipleCtrScore(batch, userFeatureMap, sceneFeatureMap, model);
+                } catch (Exception e) {
+                    LOGGER.error("Error during multipleCtrScore batch execution", e);
+                }
+                return batch;
+            }));
+        }
+
+        // 合并结果
+        List<AdRankItem> merged = new ArrayList<>();
+        for (Future<List<AdRankItem>> future : futures) {
+            try {
+                merged.addAll(future.get(400, TimeUnit.MILLISECONDS));
+            } catch (Exception e) {
+                LOGGER.error("Execution error in batch", e);
             }
         }
 
-        Collections.sort(items);
+        Collections.sort(merged);
 
-        LOGGER.debug("ctr ranker java execute time: [{}]", System.currentTimeMillis() - startTime);
-        LOGGER.debug("[ctr ranker time java] items size={}, cost={} ", items != null ? items.size() : 0,
-                System.currentTimeMillis() - startTime);
-        return items;
+        LOGGER.debug("ctr ranker java execute time: [{}ms]", System.currentTimeMillis() - startTime);
+        return merged;
     }
 
+
+
+
+
     private void multipleCtrScore(final List<AdRankItem> items,
                                   final Map<String, String> userFeatureMap,
                                   final Map<String, String> sceneFeatureMap,

+ 64 - 11
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/scorer/PAIScorerV2.java

@@ -4,16 +4,23 @@ package com.tzld.piaoquan.ad.engine.service.score.scorer;
 import com.tzld.piaoquan.ad.engine.commons.score.AbstractScorer;
 import com.tzld.piaoquan.ad.engine.commons.score.ScoreParam;
 import com.tzld.piaoquan.ad.engine.commons.score.ScorerConfigInfo;
+import com.tzld.piaoquan.ad.engine.commons.score.model.PAIModelV1;
 import com.tzld.piaoquan.ad.engine.commons.score.model.PAIModelV2;
+import com.tzld.piaoquan.ad.engine.commons.thread.ThreadPoolFactory;
 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.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
 
 public class PAIScorerV2 extends AbstractScorer {
 
@@ -48,27 +55,73 @@ public class PAIScorerV2 extends AbstractScorer {
         return result;
     }
 
+//    private List<AdRankItem> rankByJava(final Map<String, String> sceneFeatureMap,
+//                                        final Map<String, String> userFeatureMap,
+//                                        final List<AdRankItem> items) {
+//        long startTime = System.currentTimeMillis();
+//        PAIModelV2 model = PAIModelV2.getModel();
+//        // 所有都参与打分,按照ctr排序
+//        multipleCtrScore(items, userFeatureMap, sceneFeatureMap, model);
+//
+//        // debug log
+//        if (LOGGER.isDebugEnabled()) {
+//            for (int i = 0; i < items.size(); i++) {
+//                LOGGER.debug("before enter feeds model predict ctr score [{}] [{}]", items.get(i), items.get(i));
+//            }
+//        }
+//
+//        Collections.sort(items);
+//
+//        LOGGER.debug("ctr ranker java execute time: [{}]", System.currentTimeMillis() - startTime);
+//        LOGGER.debug("[ctr ranker time java] items size={}, cost={} ", items != null ? items.size() : 0,
+//                System.currentTimeMillis() - startTime);
+//        return items;
+//    }
+
     private List<AdRankItem> rankByJava(final Map<String, String> sceneFeatureMap,
                                         final Map<String, String> userFeatureMap,
                                         final List<AdRankItem> items) {
+        if (items == null || items.isEmpty()) {
+            return Collections.emptyList();
+        }
+
         long startTime = System.currentTimeMillis();
         PAIModelV2 model = PAIModelV2.getModel();
-        // 所有都参与打分,按照ctr排序
-        multipleCtrScore(items, userFeatureMap, sceneFeatureMap, model);
 
-        // debug log
-        if (LOGGER.isDebugEnabled()) {
-            for (int i = 0; i < items.size(); i++) {
-                LOGGER.debug("before enter feeds model predict ctr score [{}] [{}]", items.get(i), items.get(i));
+        final int batchSize = 300;
+        List<List<AdRankItem>> batches = new ArrayList<>();
+        for (int i = 0; i < items.size(); i += batchSize) {
+            batches.add(new ArrayList<>(items.subList(i, Math.min(i + batchSize, items.size()))));
+        }
+
+        ExecutorService executor = ThreadPoolFactory.score();
+        List<Future<List<AdRankItem>>> futures = new ArrayList<>();
+
+        for (List<AdRankItem> batch : batches) {
+            futures.add(executor.submit(() -> {
+                try {
+                    multipleCtrScore(batch, userFeatureMap, sceneFeatureMap, model);
+                } catch (Exception e) {
+                    LOGGER.error("Error during multipleCtrScore batch execution", e);
+                }
+                return batch;
+            }));
+        }
+
+        // 合并结果
+        List<AdRankItem> merged = new ArrayList<>();
+        for (Future<List<AdRankItem>> future : futures) {
+            try {
+                merged.addAll(future.get(400, TimeUnit.MILLISECONDS));
+            } catch (Exception e) {
+                LOGGER.error("Execution error in batch", e);
             }
         }
 
-        Collections.sort(items);
+        Collections.sort(merged);
 
-        LOGGER.debug("ctr ranker java execute time: [{}]", System.currentTimeMillis() - startTime);
-        LOGGER.debug("[ctr ranker time java] items size={}, cost={} ", items != null ? items.size() : 0,
-                System.currentTimeMillis() - startTime);
-        return items;
+        LOGGER.debug("ctr ranker java execute time: [{}ms]", System.currentTimeMillis() - startTime);
+        return merged;
     }
 
     private void multipleCtrScore(final List<AdRankItem> items,

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

@@ -13,6 +13,7 @@ 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;
 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.service.entity.*;
@@ -27,6 +28,10 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 
 import java.util.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -113,6 +118,9 @@ public abstract class RankStrategyBasic implements RankStrategy {
     @Value("${filter.config.value:[]}")
     protected String filterConfigValue;
 
+    @Value("${feature.branch.config.value:500}")
+    protected Integer featureBranchConfigValue;
+
     @Autowired
     private FeatureService featureService;
     @Autowired
@@ -153,25 +161,88 @@ public abstract class RankStrategyBasic implements RankStrategy {
     }};
 
 
+//    protected Feature getFeature(ScoreParam param, RankRecommendRequestParam request) {
+//        List<AdPlatformCreativeDTO> adIdList = request.getAdIdList();
+//        List<String> cidList = adIdList.stream()
+//                .map(AdPlatformCreativeDTO::getCreativeId)
+//                .map(Object::toString)
+//                .collect(Collectors.toList());
+//
+//        List<String> adVerIdList = adIdList.stream()
+//                .map(AdPlatformCreativeDTO::getAdVerId)
+//                .filter(StringUtils::isNotBlank)
+//                .distinct()
+//                .collect(Collectors.toList());
+//
+//        List<Long> skuIdList = adIdList.stream()
+//                .map(AdPlatformCreativeDTO::getSkuId)
+//                .filter(Objects::nonNull)
+//                .distinct()
+//                .collect(Collectors.toList());
+//        return featureService.getFeature(cidList, adVerIdList, skuIdList, param);
+//    }
+
     protected Feature getFeature(ScoreParam param, RankRecommendRequestParam request) {
         List<AdPlatformCreativeDTO> adIdList = request.getAdIdList();
-        List<String> cidList = adIdList.stream()
-                .map(AdPlatformCreativeDTO::getCreativeId)
-                .map(Object::toString)
-                .collect(Collectors.toList());
+        Feature finalFeature = null;
 
-        List<String> adVerIdList = adIdList.stream()
-                .map(AdPlatformCreativeDTO::getAdVerId)
-                .filter(StringUtils::isNotBlank)
-                .distinct()
-                .collect(Collectors.toList());
+        // 分批处理 AdPlatformCreativeDTO 列表
+        List<List<AdPlatformCreativeDTO>> adIdBatches = partitionList(adIdList, featureBranchConfigValue);
 
-        List<Long> skuIdList = adIdList.stream()
-                .map(AdPlatformCreativeDTO::getSkuId)
-                .filter(Objects::nonNull)
-                .distinct()
-                .collect(Collectors.toList());
-        return featureService.getFeature(cidList, adVerIdList, skuIdList, param);
+        // 使用 ThreadPoolFactory 获取 DEFAULT 线程池
+        ExecutorService executorService = ThreadPoolFactory.defaultPool();  // 使用 DEFAULT 线程池
+        List<Callable<Feature>> tasks = new ArrayList<>();
+
+        for (List<AdPlatformCreativeDTO> batch : adIdBatches) {
+            // 提取批次中的 cidList、adVerIdList 和 skuIdList
+            List<String> cidList = batch.stream()
+                    .map(AdPlatformCreativeDTO::getCreativeId)
+                    .map(Object::toString)
+                    .collect(Collectors.toList());
+
+            List<String> adVerIdList = batch.stream()
+                    .map(AdPlatformCreativeDTO::getAdVerId)
+                    .filter(StringUtils::isNotBlank)
+                    .distinct()
+                    .collect(Collectors.toList());
+
+            List<Long> skuIdList = batch.stream()
+                    .map(AdPlatformCreativeDTO::getSkuId)
+                    .filter(Objects::nonNull)
+                    .distinct()
+                    .collect(Collectors.toList());
+
+            // 将每个批次的请求任务封装为 Callable
+            tasks.add(() -> featureService.getFeature(cidList, adVerIdList, skuIdList, param));
+        }
+
+        try {
+            // 执行所有的任务并等待所有任务完成
+            List<Future<Feature>> futures = executorService.invokeAll(tasks);
+
+            // 等待所有任务完成并合并结果
+            for (Future<Feature> future : futures) {
+                Feature batchFeature = future.get();  // 获取每个任务的结果
+                if (finalFeature == null) {
+                    finalFeature = batchFeature;
+                } else {
+                    // 合并特征
+                    finalFeature.merge(batchFeature);
+                }
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            log.error("getFeature error", e);
+        }
+        return finalFeature;
+    }
+
+    // 辅助方法:将列表分成指定大小的批次
+    private <T> List<List<T>> partitionList(List<T> originalList, Integer batchSize) {
+        List<List<T>> batches = new ArrayList<>();
+        for (int i = 0; i < originalList.size(); i += batchSize) {
+            batches.add(originalList.subList(i, Math.min(i + batchSize, originalList.size())));
+        }
+        return batches;
     }
 
     protected Set<String> getNoApiAdVerIds() {
@@ -360,6 +431,14 @@ public abstract class RankStrategyBasic implements RankStrategy {
 
 
     protected boolean getIsGuaranteedFlow(ScoreParam scoreParam) {
+        // 817实验不要保量
+        if( scoreParam.getEngineInfo() != null && "817".equals(scoreParam.getEngineInfo().get("model"))){
+            return false;
+        }
+        // 819实验不要保量
+        if( valid819Ab(scoreParam)){
+            return false;
+        }
         if (System.currentTimeMillis() < guaranteeSwitchingTime) {
             return scoreParam.getExpCodeSet().contains(guaranteeExp);
         }
@@ -368,6 +447,15 @@ public abstract class RankStrategyBasic implements RankStrategy {
         return i < guaranteeWeight;
     }
 
+    private boolean valid819Ab(ScoreParam scoreParam){
+        // 819实验判断
+        boolean in819Ab = scoreParam.getEngineInfo() != null
+                && "819".equals(scoreParam.getEngineInfo().get("ecpm_model"))
+                && scoreParam.getEngineInfo().get("ecpm_value") != null
+                && Double.parseDouble(scoreParam.getEngineInfo().get("ecpm_value").toString()) >= 0;
+        return in819Ab;
+    }
+
     protected Map<String, GuaranteeView> getGuaranteeViewMap(RankRecommendRequestParam request, boolean isGuaranteedFlow) {
         Map<String, GuaranteeView> map = new HashMap<>();
         try {
@@ -875,6 +963,7 @@ public abstract class RankStrategyBasic implements RankStrategy {
             reqFeature.put("adverid", String.valueOf(adPlatformCreativeDTO.getAdVerId()));
             reqFeature.put("profession", adPlatformCreativeDTO.getProfession());
             reqFeature.put("category_name", adPlatformCreativeDTO.getCategoryName());
+            reqFeature.put("material_md5", adPlatformCreativeDTO.getMaterialMd5());
         }
         adRankItem.getMetaFeatureMap().put("reqFeature", reqFeature);
         adRankItem.getMetaFeatureMap().put("sceneFeature", sceneFeatureMap);

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

@@ -201,6 +201,7 @@ public class RankStrategyBy683 extends RankStrategyBasic {
                     cidFeatureMap.put("adverid", dto.getAdVerId() != null ? dto.getAdVerId() : "");
                     cidFeatureMap.put("profession", dto.getProfession() != null ? dto.getProfession() : "");
                     cidFeatureMap.put("category_name", dto.getCategoryName() != null ? dto.getCategoryName() : "");
+                    cidFeatureMap.put("material_md5", dto.getMaterialMd5() != null ? dto.getMaterialMd5() : "");
                     //DNN模型没训练过的cid才不传入广告相关的稀疏特征
                     if (CollectionUtils.isNotEmpty(DnnCidDataHelper.getCidSetV2()) && !DnnCidDataHelper.getCidSetV2().contains(adRankItem.getAdId())) {
                         cidFeatureMap.put("cid", "");
@@ -861,30 +862,36 @@ public class RankStrategyBy683 extends RankStrategyBasic {
             add("user_skuid_conver_30d");
             add("user_conver_ad_class");
             add("category_name");
+            add("material_md5");
         }};
     }
 
     private Map<String, String> featureBucket(Map<String, String> featureMap) {
         Map<String, String> newFeatureMap = new ConcurrentHashMap<>(featureMap.size());
         for (Map.Entry<String, String> entry : featureMap.entrySet()) {
-            String name = entry.getKey();
-            if (this.sparseFeatureSet.contains(name)) {
-                if (entry.getValue() != null) {
-                    newFeatureMap.put(name, entry.getValue());
+            try {
+                String name = entry.getKey();
+                if (this.sparseFeatureSet.contains(name)) {
+                    if (entry.getValue() != null) {
+                        newFeatureMap.put(name, entry.getValue());
+                    }
+                    continue;
                 }
-                continue;
-            }
-            double score = Double.parseDouble(entry.getValue());
-            // 注意:0值、不在分桶文件中的特征,会被过滤掉。
-            if (score > 1E-8) {
-                if (this.bucketsMap.containsKey(name) && this.bucketsLen.containsKey(name)) {
-                    double[] buckets = this.bucketsMap.get(name);
-                    double bucketNum = this.bucketsLen.get(name);
-                    Double scoreNew = 1.0 / bucketNum * (ExtractorUtils.findInsertPosition(buckets, score) + 1.0);
-                    newFeatureMap.put(name, String.valueOf(scoreNew));
-                } else {
-                    newFeatureMap.put(name, String.valueOf(score));
+
+                double score = Double.parseDouble(entry.getValue());
+                // 注意:0值、不在分桶文件中的特征,会被过滤掉。
+                if (score > 1E-8) {
+                    if (this.bucketsMap.containsKey(name) && this.bucketsLen.containsKey(name)) {
+                        double[] buckets = this.bucketsMap.get(name);
+                        double bucketNum = this.bucketsLen.get(name);
+                        Double scoreNew = 1.0 / bucketNum * (ExtractorUtils.findInsertPosition(buckets, score) + 1.0);
+                        newFeatureMap.put(name, String.valueOf(scoreNew));
+                    } else {
+                        newFeatureMap.put(name, String.valueOf(score));
+                    }
                 }
+            } catch (Exception e) {
+                log.error("featureBucket error: ", e);
             }
         }
         return newFeatureMap;

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

@@ -201,6 +201,7 @@ public class RankStrategyBy688 extends RankStrategyBasic {
                     cidFeatureMap.put("adverid", dto.getAdVerId() != null ? dto.getAdVerId() : "");
                     cidFeatureMap.put("profession", dto.getProfession() != null ? dto.getProfession() : "");
                     cidFeatureMap.put("category_name", dto.getCategoryName() != null ? dto.getCategoryName() : "");
+                    cidFeatureMap.put("material_md5", dto.getMaterialMd5() != null ? dto.getMaterialMd5() : "");
                     //DNN模型没训练过的cid才不传入广告相关的稀疏特征
                     if (CollectionUtils.isNotEmpty(DnnCidDataHelper.getCidSet()) && !DnnCidDataHelper.getCidSet().contains(adRankItem.getAdId())) {
                         cidFeatureMap.put("cid", "");
@@ -871,30 +872,35 @@ public class RankStrategyBy688 extends RankStrategyBasic {
             add("user_skuid_conver_30d");
             add("user_conver_ad_class");
             add("category_name");
+            add("material_md5");
         }};
     }
 
     private Map<String, String> featureBucket(Map<String, String> featureMap) {
         Map<String, String> newFeatureMap = new ConcurrentHashMap<>(featureMap.size());
         for (Map.Entry<String, String> entry : featureMap.entrySet()) {
-            String name = entry.getKey();
-            if (this.sparseFeatureSet.contains(name)) {
-                if (entry.getValue() != null) {
-                    newFeatureMap.put(name, entry.getValue());
+            try {
+                String name = entry.getKey();
+                if (this.sparseFeatureSet.contains(name)) {
+                    if (entry.getValue() != null) {
+                        newFeatureMap.put(name, entry.getValue());
+                    }
+                    continue;
                 }
-                continue;
-            }
-            double score = Double.parseDouble(entry.getValue());
-            // 注意:0值、不在分桶文件中的特征,会被过滤掉。
-            if (score > 1E-8) {
-                if (this.bucketsMap.containsKey(name) && this.bucketsLen.containsKey(name)) {
-                    double[] buckets = this.bucketsMap.get(name);
-                    double bucketNum = this.bucketsLen.get(name);
-                    Double scoreNew = 1.0 / bucketNum * (ExtractorUtils.findInsertPosition(buckets, score) + 1.0);
-                    newFeatureMap.put(name, String.valueOf(scoreNew));
-                } else {
-                    newFeatureMap.put(name, String.valueOf(score));
+                double score = Double.parseDouble(entry.getValue());
+                // 注意:0值、不在分桶文件中的特征,会被过滤掉。
+                if (score > 1E-8) {
+                    if (this.bucketsMap.containsKey(name) && this.bucketsLen.containsKey(name)) {
+                        double[] buckets = this.bucketsMap.get(name);
+                        double bucketNum = this.bucketsLen.get(name);
+                        Double scoreNew = 1.0 / bucketNum * (ExtractorUtils.findInsertPosition(buckets, score) + 1.0);
+                        newFeatureMap.put(name, String.valueOf(scoreNew));
+                    } else {
+                        newFeatureMap.put(name, String.valueOf(score));
+                    }
                 }
+            } catch (Exception e) {
+                log.error("featureBucket error: ", e);
             }
         }
         return newFeatureMap;