|
|
@@ -0,0 +1,98 @@
|
|
|
+package com.tzld.piaoquan.ad.engine.service.predict.v2;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
|
|
|
+import com.tzld.piaoquan.ad.engine.commons.enums.RedisPrefixEnum;
|
|
|
+import com.tzld.piaoquan.ad.engine.commons.redis.AdRedisHelper;
|
|
|
+import com.tzld.piaoquan.ad.engine.commons.util.JSONUtils;
|
|
|
+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.CollectionUtils;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 基于 ROR的广告预测策略
|
|
|
+ * <p>
|
|
|
+ * 核心逻辑:
|
|
|
+ * 1. 根据用户的历史行为特征(启动次数launchs、留存率ror、人群分层ad_level)计算展示广告的概率阈值
|
|
|
+ * 2. 通过 mid 的 hash 值生成伪随机分数
|
|
|
+ * 3. 如果分数 <= 阈值,则展示广告;否则不展示
|
|
|
+ * <p>
|
|
|
+ * 用于控制不同用户群体的广告曝光频率,实现精细化运营
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class PredictStrategyChubuchuModi extends BasicPredict {
|
|
|
+ /**
|
|
|
+ * Apollo 动态配置:根据 rootSessionId 尾号和 appType 进行流量分桶
|
|
|
+ * <p>
|
|
|
+ * 配置格式示例:
|
|
|
+ * <pre>
|
|
|
+ * [
|
|
|
+ * {
|
|
|
+ * "appType": ["0", "3"],
|
|
|
+ * "tail": ["0", "1", "2"]
|
|
|
+ * }
|
|
|
+ * ]
|
|
|
+ * </pre>
|
|
|
+ */
|
|
|
+ @ApolloJsonValue("${experiment.chubuchu.modi.root.session.id.tail.config:[]}")
|
|
|
+ private List<RootSessionIdTailConfigItem> configItems;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 策略名称标识
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+
|
|
|
+public String name() {
|
|
|
+ return "chubuchu_modi";
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> predict(PredictContext ctx) {
|
|
|
+
|
|
|
+ try {
|
|
|
+ String rootSessionId = ctx.getRootSessionId();
|
|
|
+ if (CollectionUtils.isEmpty(configItems) || StringUtils.isAnyBlank(rootSessionId)) {
|
|
|
+ return Collections.emptyMap();
|
|
|
+ }
|
|
|
+ String appType = ctx.getAppType();
|
|
|
+ String tail = rootSessionId.substring(rootSessionId.length() - 1);
|
|
|
+
|
|
|
+ for (RootSessionIdTailConfigItem item : configItems) {
|
|
|
+ if (item.getAppType().contains(appType) && item.getTail().contains(tail)) {
|
|
|
+ Map<String, Object> returnMap = new HashMap<>();
|
|
|
+ double threshold = 0.5;
|
|
|
+ // 取随机,各50%概率
|
|
|
+ double score = this.calcScoreByMid(ctx.getMid());
|
|
|
+ if (score < threshold) {
|
|
|
+ returnMap.putAll(rtnAdPredict(ctx));
|
|
|
+ returnMap.put("model", this.name());
|
|
|
+ } else {
|
|
|
+ returnMap.putAll(rtnNoAdPredict(ctx));
|
|
|
+ returnMap.put("model", this.name());
|
|
|
+ returnMap.put("no_ad_strategy", this.name());
|
|
|
+ }
|
|
|
+ returnMap.put("score", score);
|
|
|
+ returnMap.put("threshold", threshold);
|
|
|
+
|
|
|
+ return returnMap;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return Collections.emptyMap();
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("[PredictStrategyChubuchuModi] predict error, ctx: {}", ctx, e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|