yaodaoseng пре 1 недеља
родитељ
комит
87cf070f2b

+ 1 - 1
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/controller/PredictController.java

@@ -33,7 +33,7 @@ public class PredictController {
     @RequestMapping("/ab/model")
     public Map<String,Object> adPredictByAbTestModel(@RequestBody ThresholdPredictModelRequestParam param){
 
-        return predictModelService.adPredict(param);
+        return predictModelService.adPredictWithDataFill(param);
     }
 
 

+ 2 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/PredictModelService.java

@@ -9,6 +9,8 @@ public interface PredictModelService {
 
     public Map<String,Object> adPredict(ThresholdPredictModelRequestParam requestParam);
 
+    public Map<String, Object> adPredictWithDataFill(ThresholdPredictModelRequestParam requestParam);
+
     public Map<String,Object> adRecommendPredictByRoiModel(RoiPredictModelRequestParam requestParam);
 }
 

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

@@ -87,6 +87,9 @@ public class PredictModelServiceImpl implements PredictModelService {
     private PredictStrategyByRorCopy predictStrategyByRorCopy;
     @Autowired
     private PredictStrategyByFissionRateCopy predictStrategyByFissionRateCopy;
+    @Autowired
+    private PredictStrategyByAppTypeTail predictStrategyByAppTypeTail;
+
 
     @Autowired
     private UserService userService;
@@ -133,6 +136,21 @@ public class PredictModelServiceImpl implements PredictModelService {
     List<Integer> appIdArr = Arrays.asList(new Integer[]{0, 3, 4, 5, 6, 17, 18, 19, 21, 22});
 
 
+    public Map<String, Object> adPredictWithDataFill(ThresholdPredictModelRequestParam requestParam) {
+
+        Map<String, Object> result = adPredict(requestParam);
+
+        if (MapUtils.isNotEmpty(result)) {
+            PredictContext predictContext = ConvertUtil.predictParam2Context(requestParam);
+            Map<String, Object> ecpmExperiment = predictStrategyByAppTypeTail.predict(predictContext);
+            // 填充 ecpm实验 参数
+            if (MapUtils.isNotEmpty(ecpmExperiment)) {
+                result.putAll(ecpmExperiment);
+            }
+        }
+        return result;
+    }
+
     public Map<String, Object> adPredict(ThresholdPredictModelRequestParam requestParam) {
         Map<String, Object> result = new HashMap<>();
         result.put("pqtId", requestParam.getPqtId());

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

@@ -0,0 +1,111 @@
+package com.tzld.piaoquan.ad.engine.service.predict.v2;
+
+import com.alibaba.fastjson.JSONObject;
+import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
+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.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 基于 appType 和 rootSessionId 尾号的广告预测策略
+ * <p>
+ * 核心逻辑:
+ * 1. 根据 appType 和 rootSessionId 的尾号进行匹配
+ * 2. 只做数据填充(如 ecpmValue),不决定是否出广告
+ * 3. 返回匹配的配置信息,供后续流程使用
+ * <p>
+ * 配置格式示例:
+ * <pre>
+ * [
+ *   {
+ *     "appType": ["0", "3"],
+ *     "tail": ["0", "1", "2"],
+ *     "config": {
+ *       "ecpmValue": 60
+ *     }
+ *   },
+ *   {
+ *     "appType": ["1", "4"],
+ *     "tail": ["0", "1", "2"],
+ *     "config": {
+ *       "ecpmValue": 50
+ *     }
+ *   }
+ * ]
+ * </pre>
+ */
+@Slf4j
+@Service
+public class PredictStrategyByAppTypeTail extends BasicPredict {
+
+    /**
+     * Apollo 动态配置:根据 rootSessionId 尾号和 appType 进行匹配
+     */
+    @ApolloJsonValue("${experiment.app.type.tail.ecpm.config:[]}")
+    private List<RootSessionIdTailConfigItem> configItems;
+
+    /**
+     * 策略名称标识
+     */
+    @Override
+    public String name() {
+        return "app_type_tail_ecpm_strategy";
+    }
+
+    /**
+     * 核心预测方法:根据 appType 和 rootSessionId 尾号填充数据
+     *
+     * @param ctx 预测上下文,包含 appType、rootSessionId 等信息
+     * @return 预测结果 Map,包含:
+     *         - 匹配的配置信息(如 ecpmValue)
+     *         - 返回 null 表示未匹配到任何配置,跳过该策略
+     */
+    @Override
+    public Map<String, Object> predict(PredictContext ctx) {
+        try {
+            String rootSessionId = ctx.getRootSessionId();
+            String appType = ctx.getAppType();
+
+            // 前置校验:配置为空或必要参数为空时,返回 null(跳过该策略)
+            if (CollectionUtils.isEmpty(configItems) || StringUtils.isAnyBlank(rootSessionId, appType)) {
+                return null;
+            }
+
+            // 提取 rootSessionId 的最后一个字符作为尾号
+            String tail = rootSessionId.substring(rootSessionId.length() - 1);
+
+            // 遍历配置项,查找同时匹配 appType 和尾号的配置
+            for (RootSessionIdTailConfigItem item : configItems) {
+                if (item.getAppType() != null && item.getTail() != null) {
+                    // 检查是否同时匹配 appType 和 tail
+                    if (item.getAppType().contains(appType) && item.getTail().contains(tail)) {
+                        // 匹配成功,填充数据
+                        Map<String, Object> rtnMap = new HashMap<>();
+                        
+                        // 将配置中的所有参数填充到返回结果中
+                        if (item.getConfig() != null) {
+                            rtnMap.putAll(item.getConfig());
+                        }
+                        rtnMap.put("ecpm_model",name());
+                        rtnMap.put("ecpm_rootSessionId", ctx.getRootSessionId());
+                        
+                        return rtnMap;
+                    }
+                }
+            }
+
+            // 未匹配到任何配置,返回 null
+            return null;
+
+        } catch (Exception e) {
+            log.error("[PredictStrategyByAppTypeTail] predict error, ctx: {}", ctx, e);
+            return null;
+        }
+    }
+}
+