yaodaoseng 4 дней назад
Родитель
Сommit
cbf122c8a4

+ 21 - 14
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyByFissionRate.java

@@ -94,10 +94,10 @@ public class PredictStrategyByFissionRate extends BasicPredict {
             String appType = ctx.getAppType();
 
             // 获取默认概率阈值(基于 rootSessionId 尾号和 appType 匹配配置)
-            Double defaultFissionRate = getDefaultFissionRate(rootSessionId, appType);
+            Boolean matchResult = getDefaultFissionRate(rootSessionId, appType);
 
             // 用户不在实验分桶内,跳过该策略
-            if (defaultFissionRate == null) {
+            if (!matchResult) {
                 return null;
             }
 
@@ -107,6 +107,7 @@ public class PredictStrategyByFissionRate extends BasicPredict {
             String launchs = null;   // 启动次数分桶(如 "0-5", "5-10" 等)
             String ror = null;       // 留存率分桶
             String adLevel = null;   // 广告等级(用户对广告的敏感度分层)
+            String return30day = null;   // 用户回流率分桶
 
             // 根据 mid 获取用户近一个月的历史行为特征
             Feature feature = featureService.getMidBehaviorFeature(TABLE_NAME, ctx.getMid());
@@ -119,16 +120,22 @@ public class PredictStrategyByFissionRate extends BasicPredict {
                 launchs = algMidHistoryBehavior1month.get("launchs");
                 ror = algMidHistoryBehavior1month.get("ror");
                 adLevel = algMidHistoryBehavior1month.get("ad_level");
+                return30day = algMidHistoryBehavior1month.get("return_30day");
             }
 
             // 计算最终的广告展示概率阈值
             // 优先使用 Redis 中基于用户特征的精细化阈值,否则使用默认阈值
-            double showAdFissionRate = getShowAdFissionRate(launchs, ror, adLevel, defaultFissionRate);
+            Double showAdFissionRate = getShowAdFissionRate(launchs, ror, adLevel, return30day);
+
+            if (showAdFissionRate == null) {
+                return null;
+            }
 
             // 记录决策相关的特征和参数,用于日志分析和效果追踪
             rtnMap.put("launchs", launchs);
             rtnMap.put("ror", ror);
             rtnMap.put("ad_level", adLevel);
+            rtnMap.put("return_30day", return30day);
             rtnMap.put("fission_rate", showAdFissionRate);
             return rtnMap;
         } catch (Exception e) {
@@ -146,28 +153,27 @@ public class PredictStrategyByFissionRate extends BasicPredict {
      * @param launchs            启动次数分桶
      * @param ror                留存率分桶
      * @param ad_level           人群分层
-     * @param defaultFissionRate 默认裂变值(兜底值)
      * @return 广告展示概率阈值 [0, 1]
      */
-    private double getShowAdFissionRate(String launchs, String ror, String ad_level, Double defaultFissionRate) {
+    private Double getShowAdFissionRate(String launchs, String ror, String ad_level, String return30day) {
         // 任一特征为空,使用默认概率
-        if (StringUtils.isAnyBlank(launchs, ror, ad_level)) {
-            return defaultFissionRate;
+        if (StringUtils.isAnyBlank(launchs, ror, ad_level, return30day)) {
+            return null;
         }
         try {
             // 构建 Redis key:格式为 "ad_level:launchs:ror",例如 "有转化:10:000"
-            String keyId = ad_level + ":" + launchs + ":" + ror;
+            String keyId = ad_level + ":" + launchs + ":" + ror + ":" + return30day;
             String key = String.format(RedisPrefixEnum.AD_USER_FISSION_RATE_BEHAVIOR.getPrefix(), keyId);
 
             // 从 Redis 获取概率值
             String fissionRate = adRedisHelper.get(key);
 
             // 解析概率值,如果为 null 则使用默认值
-            return fissionRate == null ? defaultFissionRate : Double.parseDouble(fissionRate);
+            return StringUtils.isBlank(fissionRate) ? null : Double.parseDouble(fissionRate);
         } catch (Exception e) {
             // 解析失败(如非数字字符串)或 Redis 异常,记录错误并使用默认值
             log.error("getShowAdFissionRate error, launchs: {}, ror: {}, ad_level: {}, e = ", launchs, ror, ad_level, e);
-            return defaultFissionRate;
+            return null;
         }
     }
 
@@ -180,10 +186,10 @@ public class PredictStrategyByFissionRate extends BasicPredict {
      * @param appType       应用类型
      * @return 默认概率,如果不匹配任何配置则返回 null
      */
-    private Double getDefaultFissionRate(String rootSessionId, String appType) {
+    private Boolean getDefaultFissionRate(String rootSessionId, String appType) {
         // 前置校验
         if (CollectionUtils.isEmpty(configItems) || StringUtils.isAnyBlank(rootSessionId) || appType == null) {
-            return null;
+            return false;
         }
 
         // 提取 rootSessionId 的最后一个字符作为尾号,用于流量分桶
@@ -193,14 +199,15 @@ public class PredictStrategyByFissionRate extends BasicPredict {
         for (RootSessionIdTailConfigItem item : configItems) {
             if (item.getAppType() != null && item.getTail() != null) {
                 if (item.getAppType().contains(appType) && item.getTail().contains(tail)) {
-                    return item.getConfig().get("default_fission_rate");
+//                    return item.getConfig().get("default_fission_rate");
+                    return true;
                 }
             }
 
         }
 
         // 未匹配到任何配置
-        return null;
+        return false;
     }
 
 }

+ 22 - 14
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/v2/PredictStrategyByRor.java

@@ -94,10 +94,10 @@ public class PredictStrategyByRor extends BasicPredict {
             String appType = ctx.getAppType();
 
             // 获取默认概率阈值(基于 rootSessionId 尾号和 appType 匹配配置)
-            Double defaultProbability = getDefaultProbability(rootSessionId, appType);
+            Boolean matchResult = getDefaultProbability(rootSessionId, appType);
 
             // 用户不在实验分桶内,跳过该策略
-            if (defaultProbability == null) {
+            if (!matchResult) {
                 return null;
             }
 
@@ -107,6 +107,7 @@ public class PredictStrategyByRor extends BasicPredict {
             String launchs = null;   // 启动次数分桶(如 "0-5", "5-10" 等)
             String ror = null;       // 留存率分桶
             String adLevel = null;   // 广告等级(用户对广告的敏感度分层)
+            String return30day = null;   // 用户回流率分桶
 
             // 根据 mid 获取用户近一个月的历史行为特征
             Feature feature = featureService.getMidBehaviorFeature(TABLE_NAME, ctx.getMid());
@@ -119,11 +120,16 @@ public class PredictStrategyByRor extends BasicPredict {
                 launchs = algMidHistoryBehavior1month.get("launchs");
                 ror = algMidHistoryBehavior1month.get("ror");
                 adLevel = algMidHistoryBehavior1month.get("ad_level");
+                return30day = algMidHistoryBehavior1month.get("return_30day");
             }
 
             // 计算最终的广告展示概率阈值
             // 优先使用 Redis 中基于用户特征的精细化阈值,否则使用默认阈值
-            double showAdProbability = getShowAdProbability(launchs, ror, adLevel, defaultProbability);
+            Double showAdProbability = getShowAdProbability(launchs, ror, adLevel,return30day);
+
+            if (showAdProbability == null) {
+                return null;
+            }
 
             // 基于 mid 的 hash 值生成 [0, 1) 范围内的伪随机分数
             // 同一个 mid 在同一小时内(RandW 每小时更新)会得到相同的分数
@@ -144,6 +150,7 @@ public class PredictStrategyByRor extends BasicPredict {
             rtnMap.put("score", score);
             rtnMap.put("threshold", showAdProbability);
             rtnMap.put("launchs", launchs);
+            rtnMap.put("return_30day", return30day);
             rtnMap.put("ror", ror);
             rtnMap.put("ad_level", adLevel);
             return rtnMap;
@@ -162,28 +169,28 @@ public class PredictStrategyByRor extends BasicPredict {
      * @param launchs            启动次数分桶
      * @param ror                留存率分桶
      * @param ad_level           人群分层
-     * @param defaultProbability 默认概率(兜底值)
+     *
      * @return 广告展示概率阈值 [0, 1]
      */
-    private double getShowAdProbability(String launchs, String ror, String ad_level, Double defaultProbability) {
+    private Double getShowAdProbability(String launchs, String ror, String ad_level,String return30day) {
         // 任一特征为空,使用默认概率
-        if (StringUtils.isAnyBlank(launchs, ror, ad_level)) {
-            return defaultProbability;
+        if (StringUtils.isAnyBlank(launchs, ror, ad_level,return30day)) {
+            return null;
         }
         try {
             // 构建 Redis key:格式为 "ad_level:launchs:ror",例如 "有转化:10:000"
-            String keyId = ad_level + ":" + launchs + ":" + ror;
+            String keyId = ad_level + ":" + launchs + ":" + ror + ":" + return30day;
             String key = String.format(RedisPrefixEnum.AD_USER_ROR_BEHAVIOR.getPrefix(), keyId);
 
             // 从 Redis 获取概率值
             String probability = adRedisHelper.get(key);
 
             // 解析概率值,如果为 null 则使用默认值
-            return probability == null ? defaultProbability : Double.parseDouble(probability);
+            return StringUtils.isBlank(probability) ? null : Double.parseDouble(probability);
         } catch (Exception e) {
             // 解析失败(如非数字字符串)或 Redis 异常,记录错误并使用默认值
             log.error("getShowAdProbability error, launchs: {}, ror: {}, ad_level: {}, e = ", launchs, ror, ad_level, e);
-            return defaultProbability;
+            return null;
         }
     }
 
@@ -196,10 +203,10 @@ public class PredictStrategyByRor extends BasicPredict {
      * @param appType       应用类型
      * @return 默认概率,如果不匹配任何配置则返回 null
      */
-    private Double getDefaultProbability(String rootSessionId, String appType) {
+    private Boolean getDefaultProbability(String rootSessionId, String appType) {
         // 前置校验
         if (CollectionUtils.isEmpty(configItems) || StringUtils.isAnyBlank(rootSessionId) || appType == null) {
-            return null;
+            return false;
         }
 
         // 提取 rootSessionId 的最后一个字符作为尾号,用于流量分桶
@@ -209,14 +216,15 @@ public class PredictStrategyByRor extends BasicPredict {
         for (RootSessionIdTailConfigItem item : configItems) {
             if (item.getAppType() != null && item.getTail() != null) {
                 if (item.getAppType().contains(appType) && item.getTail().contains(tail)) {
-                    return item.getConfig().get("default_probability");
+//                    return item.getConfig().get("default_probability");
+                    return true;
                 }
             }
 
         }
 
         // 未匹配到任何配置
-        return null;
+        return false;
     }
 
 }