|
@@ -64,8 +64,15 @@ public abstract class RankStrategyBasic implements RankStrategy {
|
|
|
@Value("${correct.cpa.beta.2:0.2}")
|
|
|
protected Double correctCpaBeta2;
|
|
|
|
|
|
- @Value("${correct.cpa.view:1000}")
|
|
|
- protected Integer correctCpaView;
|
|
|
+ @Value("${correct.cpa.view.hour:300}")
|
|
|
+ protected Integer correctCpaViewHour;
|
|
|
+
|
|
|
+ @Value("${correct.cpa.view.day:300}")
|
|
|
+ protected Integer correctCpaViewDay;
|
|
|
+
|
|
|
+ @Value("${correct.cpa.min.ctcvr:0.000001}")
|
|
|
+ protected Double minCtcvr;
|
|
|
+
|
|
|
|
|
|
@Value("${exclude.exp:772}")
|
|
|
protected String excludeExp;
|
|
@@ -97,16 +104,14 @@ public abstract class RankStrategyBasic implements RankStrategy {
|
|
|
|
|
|
String adPlatformGuaranteeKey = "ad:platform:guarantee:data:{date}:{adverId}";
|
|
|
|
|
|
- String adCustomerLayerHourKey = "ad:platform:customer:hour:{layer}:{clazz}:{customerId}";
|
|
|
-
|
|
|
- String adVerLayerHourKey = "ad:platform:adver:hour:{layer}:{clazz}:{adverId}";
|
|
|
+ String adLayerHourKey = "ad:platform:ad:hour:{layer}:{clazz}:{adId}";
|
|
|
|
|
|
- String adCustomerLayerDayKey = "ad:platform:customer:day:{layer}:{clazz}:{customerId}";
|
|
|
-
|
|
|
- String adVerLayerDayKey = "ad:platform:adver:day:{layer}:{clazz}:{adverId}";
|
|
|
+ String adLayerDayKey = "ad:platform:ad:day:{layer}:{clazz}:{adId}";
|
|
|
|
|
|
String cidLayerKey = "ad:engine:cid:layer:info:{cid}:{userLayer}";
|
|
|
|
|
|
+ private static final double DEFAULT_CORRECTION = 1.0;
|
|
|
+
|
|
|
|
|
|
protected static final List<String> hasChannelScenes = new ArrayList<String>() {{
|
|
|
add("DaiTou");
|
|
@@ -382,94 +387,69 @@ public abstract class RankStrategyBasic implements RankStrategy {
|
|
|
if (request.getIsFilterUser()) {
|
|
|
layer = layer + "-炸";
|
|
|
}
|
|
|
-
|
|
|
- String redisAdCustomerLayerHourKey = adCustomerLayerHourKey.replace("{layer}", layer).replace("{clazz}", clazz);
|
|
|
- String redisAdVerLayerHourKey = adVerLayerHourKey.replace("{layer}", layer).replace("{clazz}", clazz);
|
|
|
- String redisAadCustomerLayerDayKey = adCustomerLayerDayKey.replace("{layer}", layer).replace("{clazz}", clazz);
|
|
|
- String redisAdVerLayerDayKey = adVerLayerDayKey.replace("{layer}", layer).replace("{clazz}", clazz);
|
|
|
-
|
|
|
-
|
|
|
Map<Long, CorrectCpaParam> resultMap = new HashMap<>();
|
|
|
try {
|
|
|
if (CollectionUtils.isEmpty(request.getAdIdList())) {
|
|
|
return resultMap;
|
|
|
}
|
|
|
-
|
|
|
- // 抽取公共方法获取数据
|
|
|
- List<Long> customerIds = request.getAdIdList().stream()
|
|
|
- .map(AdPlatformCreativeDTO::getCustomerId)
|
|
|
- .distinct()
|
|
|
- .collect(Collectors.toList());
|
|
|
- Map<Long, JSONObject> customerLayerMap = getRedisData(
|
|
|
- customerIds,
|
|
|
- id -> redisAdCustomerLayerHourKey.replace("{customerId}", String.valueOf(id)),
|
|
|
- id -> redisAadCustomerLayerDayKey.replace("{customerId}", String.valueOf(id))
|
|
|
- );
|
|
|
-
|
|
|
- List<String> adVerIds = request.getAdIdList().stream()
|
|
|
- .map(AdPlatformCreativeDTO::getAdVerId)
|
|
|
+ String redisAdLayerHourKey = adLayerHourKey.replace("{layer}", layer).replace("{clazz}", clazz);
|
|
|
+ String redisAdLayerDayKey = adLayerDayKey.replace("{layer}", layer).replace("{clazz}", clazz);
|
|
|
+ Function<Long, String> hourKeyFunc = id -> redisAdLayerHourKey.replace("{adId}", String.valueOf(id));
|
|
|
+ Function<Long, String> dayKeyFunc = id -> redisAdLayerDayKey.replace("{adId}", String.valueOf(id));
|
|
|
+ List<Long> adIds = request.getAdIdList().stream()
|
|
|
+ .map(AdPlatformCreativeDTO::getAdId)
|
|
|
.distinct()
|
|
|
.collect(Collectors.toList());
|
|
|
- Map<String, JSONObject> adVerLayerMap = getRedisData(
|
|
|
- adVerIds,
|
|
|
- id -> redisAdVerLayerHourKey.replace("{adverId}", id),
|
|
|
- id -> redisAdVerLayerDayKey.replace("{adverId}", id)
|
|
|
- );
|
|
|
-
|
|
|
- for (AdPlatformCreativeDTO adPlatformCreativeDTO : request.getAdIdList()) {
|
|
|
- Long creativeId = adPlatformCreativeDTO.getCreativeId();
|
|
|
- Long customerId = adPlatformCreativeDTO.getCustomerId();
|
|
|
- JSONObject jsonObject;
|
|
|
- if (customerId != null && customerId != 0 && customerLayerMap.containsKey(customerId)) {
|
|
|
- jsonObject = customerLayerMap.get(customerId);
|
|
|
- } else {
|
|
|
- jsonObject = adVerLayerMap.get(adPlatformCreativeDTO.getAdVerId());
|
|
|
- }
|
|
|
- CorrectCpaParam correctCpaParam = new CorrectCpaParam();
|
|
|
+ Map<Long, JSONObject> adLayerMap = getRedisData(adIds, hourKeyFunc, dayKeyFunc);
|
|
|
+ adIds.forEach(adId -> {
|
|
|
+ JSONObject jsonObject = adLayerMap.get(adId);
|
|
|
+ CorrectCpaParam param = new CorrectCpaParam();
|
|
|
+
|
|
|
if (jsonObject == null) {
|
|
|
- correctCpaParam.setCorrectionFactor(1.0);
|
|
|
- resultMap.put(creativeId, correctCpaParam);
|
|
|
- continue;
|
|
|
- }
|
|
|
- Integer views = jsonObject.getInteger("viewsHour");
|
|
|
- Double realCtcvrHour = jsonObject.getDouble("realCtcvrHour");
|
|
|
- Double pCtcvrHour = jsonObject.getDouble("pCtcvrHour");
|
|
|
- Double realCtcvrDay = jsonObject.getDouble("realCtcvrDay");
|
|
|
- Double pCtcvrDay = jsonObject.getDouble("pCtcvrDay");
|
|
|
- correctCpaParam.setRealCtcvrHour(realCtcvrHour);
|
|
|
- correctCpaParam.setPCtcvrHour(pCtcvrHour);
|
|
|
- correctCpaParam.setRealCtcvrDay(realCtcvrDay);
|
|
|
- correctCpaParam.setPCtcvrDay(pCtcvrDay);
|
|
|
- correctCpaParam.setView(views);
|
|
|
- double correctionFactor = 1.0;
|
|
|
- //曝光数小于目标曝光数,不进行修正
|
|
|
- if (views == null || views < correctCpaView) {
|
|
|
- correctCpaParam.setCorrectionFactor(correctionFactor);
|
|
|
- resultMap.put(creativeId, correctCpaParam);
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (realCtcvrHour != null && pCtcvrHour != null && realCtcvrDay != null && pCtcvrDay != null) {
|
|
|
- if (scoreParam.getExpCodeSet().contains(correctCpaExp2)) {
|
|
|
- correctionFactor = (1 - correctCpaAlpha2 - correctCpaBeta2) +
|
|
|
- NumUtil.div(realCtcvrHour, pCtcvrHour) * correctCpaAlpha2 +
|
|
|
- NumUtil.div(realCtcvrDay, pCtcvrDay) * correctCpaBeta2;
|
|
|
- } else {
|
|
|
- correctionFactor = Math.pow(NumUtil.div(realCtcvrHour, pCtcvrHour), correctCpaAlpha1) *
|
|
|
- Math.pow(NumUtil.div(realCtcvrDay, pCtcvrDay), correctCpaBeta1);
|
|
|
- }
|
|
|
- if (correctionFactor <= 0) {
|
|
|
- correctionFactor = 1;
|
|
|
- }
|
|
|
+ param.setCorrectionFactor(DEFAULT_CORRECTION);
|
|
|
+ } else {
|
|
|
+ // 设置基础参数
|
|
|
+ param.setViewsHour(jsonObject.getInteger("viewsHour"));
|
|
|
+ param.setViewsDay(jsonObject.getInteger("viewsDay"));
|
|
|
+ param.setRealCtcvrHour(jsonObject.getDouble("realCtcvrHour"));
|
|
|
+ param.setPCtcvrHour(jsonObject.getDouble("pCtcvrHour"));
|
|
|
+ param.setRealCtcvrDay(jsonObject.getDouble("realCtcvrDay"));
|
|
|
+ param.setPCtcvrDay(jsonObject.getDouble("pCtcvrDay"));
|
|
|
+ // 计算校正因子
|
|
|
+ double factor = calculateCorrection(jsonObject, scoreParam);
|
|
|
+ param.setCorrectionFactor(factor > 0 ? factor : DEFAULT_CORRECTION);
|
|
|
}
|
|
|
- correctCpaParam.setCorrectionFactor(correctionFactor);
|
|
|
- resultMap.put(creativeId, correctCpaParam);
|
|
|
- }
|
|
|
+ resultMap.put(adId, param);
|
|
|
+ });
|
|
|
} catch (Exception e) {
|
|
|
log.error("getCorrectCpaParamMap error", e);
|
|
|
}
|
|
|
return resultMap;
|
|
|
}
|
|
|
|
|
|
+ private double calculateCorrection(JSONObject jsonObject, ScoreParam scoreParam) {
|
|
|
+ // 安全获取值
|
|
|
+ Integer viewsHour = jsonObject.getInteger("viewsHour");
|
|
|
+ Integer viewsDay = jsonObject.getInteger("viewsDay");
|
|
|
+ double realCtcvrHour = safeDouble(jsonObject.getDouble("realCtcvrHour"), minCtcvr);
|
|
|
+ double pCtcvrHour = safeDouble(jsonObject.getDouble("pCtcvrHour"), minCtcvr);
|
|
|
+ double realCtcvrDay = safeDouble(jsonObject.getDouble("realCtcvrDay"), minCtcvr);
|
|
|
+ double pCtcvrDay = safeDouble(jsonObject.getDouble("pCtcvrDay"), minCtcvr);
|
|
|
+
|
|
|
+ if (scoreParam.getExpCodeSet().contains(correctCpaExp2)) {
|
|
|
+ double alpha = isValidViews(viewsHour, correctCpaViewHour) ? correctCpaAlpha2 : 0;
|
|
|
+ double beta = isValidViews(viewsDay, correctCpaViewDay) ? correctCpaBeta2 : 0;
|
|
|
+ return (1 - alpha - beta) +
|
|
|
+ (realCtcvrHour / pCtcvrHour) * alpha +
|
|
|
+ (realCtcvrDay / pCtcvrDay) * beta;
|
|
|
+ } else {
|
|
|
+ double alpha = isValidViews(viewsHour, correctCpaViewHour) ? correctCpaAlpha1 : 0;
|
|
|
+ double beta = isValidViews(viewsDay, correctCpaViewDay) ? correctCpaBeta1 : 0;
|
|
|
+ return Math.pow(realCtcvrHour / pCtcvrHour, alpha) *
|
|
|
+ Math.pow(realCtcvrDay / pCtcvrDay, beta);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private <T> Map<T, JSONObject> getRedisData(
|
|
|
Collection<T> ids,
|
|
|
Function<T, String> hourKeyBuilder,
|
|
@@ -695,4 +675,14 @@ public abstract class RankStrategyBasic implements RankStrategy {
|
|
|
return new HashMap<>();
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // 安全的数值转换
|
|
|
+ private double safeDouble(Double value, Double min) {
|
|
|
+ return (value == null || value == 0) ? min : value;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 视图数校验封装
|
|
|
+ private boolean isValidViews(Integer views, int threshold) {
|
|
|
+ return views != null && views >= threshold;
|
|
|
+ }
|
|
|
}
|