|
@@ -317,6 +317,162 @@ public abstract class RankStrategyBasic implements RankStrategy {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ protected Map<Long, CorrectCpaParam> getCorrectCpaParamMap(RankRecommendRequestParam request, ScoreParam scoreParam) {
|
|
|
+ Map<String, String> userLayer = this.getUserLayer(request.getMid());
|
|
|
+
|
|
|
+ String layer = userLayer.getOrDefault("layer", "无曝光");
|
|
|
+ String clazz = userLayer.getOrDefault("class", "近期未出现");
|
|
|
+ if (StringUtils.isNotEmpty(layer) && layer.equals("已转化")) {
|
|
|
+ layer = "有转化";
|
|
|
+ }
|
|
|
+ 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)
|
|
|
+ .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();
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ correctCpaParam.setCorrectionFactor(correctionFactor);
|
|
|
+ resultMap.put(creativeId, correctCpaParam);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("getCorrectCpaParamMap error", e);
|
|
|
+ }
|
|
|
+ return resultMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ private <T> Map<T, JSONObject> getRedisData(
|
|
|
+ Collection<T> ids,
|
|
|
+ Function<T, String> hourKeyBuilder,
|
|
|
+ Function<T, String> dayKeyBuilder) {
|
|
|
+
|
|
|
+ Map<T, JSONObject> resultMap = new HashMap<>();
|
|
|
+ if (CollectionUtils.isEmpty(ids)) {
|
|
|
+ return resultMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建Keys
|
|
|
+ List<String> hourKeys = ids.stream()
|
|
|
+ .map(hourKeyBuilder)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ List<String> dayKeys = ids.stream()
|
|
|
+ .map(dayKeyBuilder)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ // 批量获取Redis值
|
|
|
+ List<String> hourValues = adRedisHelper.mget(hourKeys);
|
|
|
+ List<String> dayValues = adRedisHelper.mget(dayKeys);
|
|
|
+
|
|
|
+ // 解析数据
|
|
|
+ Iterator<T> idIter = ids.iterator();
|
|
|
+ for (int i = 0; i < ids.size(); i++) {
|
|
|
+ T id = idIter.next();
|
|
|
+ JSONObject jsonObj = new JSONObject();
|
|
|
+
|
|
|
+ // 解析小时数据
|
|
|
+ parseRedisValue(hourValues.get(i), jsonObj, "Hour", "ctcvr", "pCtcvr", "views");
|
|
|
+ // 解析天数据
|
|
|
+ parseRedisValue(dayValues.get(i), jsonObj, "Day", "ctcvr", "pCtcvr", "views");
|
|
|
+
|
|
|
+ resultMap.put(id, jsonObj);
|
|
|
+ }
|
|
|
+ return resultMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void parseRedisValue(String value, JSONObject target,
|
|
|
+ String suffix, String... keys) {
|
|
|
+ if (StringUtils.isEmpty(value)) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ JSONObject source = JSONObject.parseObject(value);
|
|
|
+ for (String key : keys) {
|
|
|
+ Object val = source.get(key);
|
|
|
+ if (val != null) {
|
|
|
+ String newKey = (key.equals("ctcvr") ? "realCtcvr" : key) + suffix;
|
|
|
+ target.put(newKey, val);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("Parse redis value failed: {}", value, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
protected AdRankItem creativeCovertRankItem(AdPlatformCreativeDTO dto, RankRecommendRequestParam request, Set<String> noApiAdVerIds) {
|
|
|
AdRankItem adRankItem = new AdRankItem();
|
|
|
adRankItem.setAdId(dto.getCreativeId());
|