Browse Source

feat:创意热度排序策略

zhaohaipeng 11 hours ago
parent
commit
c829d44f4e

+ 28 - 3
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBasic.java

@@ -3,13 +3,14 @@ package com.tzld.piaoquan.ad.engine.service.score.strategy;
 import com.alibaba.fastjson.JSONObject;
 import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
 import com.tzld.piaoquan.ad.engine.commons.dto.AdPlatformCreativeDTO;
-import com.tzld.piaoquan.ad.engine.commons.redis.AlgorithmRedisHelper;
-import com.tzld.piaoquan.ad.engine.commons.util.DateUtils;
-import com.tzld.piaoquan.ad.engine.service.entity.GuaranteeView;
 import com.tzld.piaoquan.ad.engine.commons.enums.RedisPrefixEnum;
 import com.tzld.piaoquan.ad.engine.commons.param.RankRecommendRequestParam;
 import com.tzld.piaoquan.ad.engine.commons.redis.AdRedisHelper;
+import com.tzld.piaoquan.ad.engine.commons.redis.AlgorithmRedisHelper;
 import com.tzld.piaoquan.ad.engine.commons.score.ScoreParam;
+import com.tzld.piaoquan.ad.engine.commons.util.DateUtils;
+import com.tzld.piaoquan.ad.engine.commons.util.ObjUtil;
+import com.tzld.piaoquan.ad.engine.service.entity.GuaranteeView;
 import com.tzld.piaoquan.ad.engine.service.feature.Feature;
 import com.tzld.piaoquan.ad.engine.service.feature.FeatureService;
 import com.tzld.piaoquan.recommend.feature.domain.ad.base.AdRankItem;
@@ -268,6 +269,30 @@ public abstract class RankStrategyBasic implements RankStrategy {
         }
     }
 
+    protected AdRankItem creativeCovertRankItem(AdPlatformCreativeDTO dto, RankRecommendRequestParam request, Set<String> noApiAdVerIds) {
+        AdRankItem adRankItem = new AdRankItem();
+        adRankItem.setAdId(dto.getCreativeId());
+        adRankItem.setCreativeCode(dto.getCreativeCode());
+        adRankItem.setAdVerId(dto.getAdVerId());
+        adRankItem.setVideoId(request.getVideoId());
+        adRankItem.setCpa(dto.getCpa());
+        adRankItem.setId(dto.getAdId());
+        adRankItem.setCampaignId(dto.getCampaignId());
+        adRankItem.setCpm(ObjUtil.nullOrDefault(dto.getCpm(), 90).doubleValue());
+        adRankItem.setSkuId(dto.getSkuId());
+        adRankItem.getExt().put("recallsources", dto.getRecallSources());
+        adRankItem.setRandom(new Random().nextInt(1000));
+        if (CollectionUtils.isNotEmpty(noApiAdVerIds)) {
+            if (noApiAdVerIds.contains(dto.getAdVerId())) {
+                adRankItem.getExt().put("isApi", "0");
+            } else {
+                adRankItem.getExt().put("isApi", "1");
+            }
+        }
+
+        return adRankItem;
+    }
+
     protected void putMetaFeature(AdRankItem adRankItem, Feature feature, Map<String, String> reqFeature,
                                   Map<String, String> sceneFeatureMap, RankRecommendRequestParam request) {
         Map<String, Map<String, String>> userFeature = feature.getUserFeature();

+ 102 - 31
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/strategy/RankStrategyBy687.java

@@ -20,6 +20,7 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.util.*;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -29,7 +30,7 @@ public class RankStrategyBy687 extends RankStrategyBasic {
     @Autowired
     private RankStrategyBy688 rankStrategyBy688;
 
-    @ApolloJsonValue("${cid.open.hot.rank.user.layer :[]}")
+    @ApolloJsonValue("${cid.open.hot.rank.user.layer:[]}")
     private Set<String> openHotRankUserLayers;
 
     @Value("${cid.hot.rank.view.threshold:5000}")
@@ -43,10 +44,12 @@ public class RankStrategyBy687 extends RankStrategyBasic {
     @Autowired
     private FeatureService featureService;
 
+    private static final String CUSTOMER_FIELD_NAME = "customer";
+
     @Override
     public List<AdRankItem> adItemRank(RankRecommendRequestParam request, ScoreParam scoreParam) {
         // 没有mid或者未配置分层,走基线排序
-        if (StringUtils.isEmpty(request.getMid()) && CollectionUtils.isEmpty(openHotRankUserLayers)) {
+        if (StringUtils.isEmpty(request.getMid()) || CollectionUtils.isEmpty(openHotRankUserLayers)) {
             return rankStrategyBy688.adItemRank(request, scoreParam);
         }
 
@@ -56,34 +59,66 @@ public class RankStrategyBy687 extends RankStrategyBasic {
             return rankStrategyBy688.adItemRank(request, scoreParam);
         }
 
+        Set<String> noApiAdVerIds = getNoApiAdVerIds();
+
         List<AdPlatformCreativeDTO> recallCreativeList = request.getAdIdList();
 
         // 获取所有创意对应的客户列表
         List<Long> creativeIds = recallCreativeList.stream().map(AdPlatformCreativeDTO::getCreativeId).collect(Collectors.toList());
         Feature feature = featureService.getCreativeBasicInfo(creativeIds);
-        this.fullCustomerInfo(feature.getCidFeature(), recallCreativeList);
 
-        List<String> customers = recallCreativeList.stream()
-                .map(AdPlatformCreativeDTO::getCustomer)
+        List<AdRankItem> rankItems = new ArrayList<>(recallCreativeList.size());
+        for (AdPlatformCreativeDTO dto : recallCreativeList) {
+            AdRankItem adRankItem = this.creativeCovertRankItem(dto, request, noApiAdVerIds);
+            this.fullCustomerInfo(feature.getCidFeature(), adRankItem);
+            rankItems.add(adRankItem);
+        }
+
+        // 选择一个客户
+        List<String> customers = rankItems.stream()
+                .map(i -> i.getExt().getOrDefault(CUSTOMER_FIELD_NAME, ""))
+                .map(Objects::toString)
+                .filter(StringUtils::isNotEmpty)
                 .distinct()
                 .collect(Collectors.toList());
-
-        // 获取客户列表,并选择一个客户
         String keyFormat = "ad:engine:customer:layer:info:%s:" + userLayer;
         List<HotRankFeatureInfo> customerFeature = this.multiGetFeature(customers, keyFormat);
         String customer = this.choose(customerFeature);
 
         // 从当前客户的所有创意中,选择一个创意
-        List<String> customerCreativeIds = recallCreativeList.stream()
-                .filter(c -> StringUtils.equals(c.getCustomer(), customer))
-                .map(AdPlatformCreativeDTO::getCreativeId)
+        List<String> customerCreativeIds = rankItems.stream()
+                .filter(c -> StringUtils.equals(c.getExt().getOrDefault(CUSTOMER_FIELD_NAME, "").toString(), customer))
+                .map(AdRankItem::getAdId)
                 .map(Objects::toString)
                 .collect(Collectors.toList());
         String cidKeyFormat = "ad:engine:cid:layer:info:%s:" + userLayer;
         List<HotRankFeatureInfo> creativeFeature = this.multiGetFeature(customerCreativeIds, cidKeyFormat);
-        String chooseCreativeId = this.choose(creativeFeature);
+        String chooseCreativeIdStr = this.choose(creativeFeature);
+        Long chooseCreativeId = Long.parseLong(chooseCreativeIdStr);
+
+        Map<String, HotRankFeatureInfo> allCustomerFeatureMap = customerFeature.stream()
+                .collect(Collectors.toMap(HotRankFeatureInfo::getLabel, Function.identity(), (o1, o2) -> o1));
+
+        Map<Long, HotRankFeatureInfo> allCreativeFeatureInfoMap = creativeFeature.stream()
+                .collect(Collectors.toMap(i -> Long.parseLong(i.getLabel()), Function.identity(), (o1, o2) -> o1));
+
+        Map<String, String> sceneFeature = this.handleSceneFeature(System.currentTimeMillis() / 1000);
+        Map<String, String> reqFeature = this.getReqFeature(scoreParam, request);
+
+        List<AdRankItem> result = new ArrayList<>(rankItems.size());
+        for (int i = 1; i < rankItems.size(); i++) {
+            AdRankItem rankItem = rankItems.get(i);
+            // 补充特征信息
+            this.fullMetaFeature(rankItem, userLayer, allCustomerFeatureMap, allCreativeFeatureInfoMap, feature);
+            this.putMetaFeature(rankItem, feature, reqFeature, sceneFeature, request);
+            if (Objects.equals(rankItem.getAdId(), chooseCreativeId)) {
+                result.add(0, rankItem);
+            } else {
+                result.add(rankItem);
+            }
+        }
 
-        return null;
+        return result;
     }
 
     private String getUserLayer(String mid) {
@@ -117,13 +152,11 @@ public class RankStrategyBy687 extends RankStrategyBasic {
         return hotRankFeatureInfos;
     }
 
-    private void fullCustomerInfo(Map<String, Map<String, Map<String, String>>> cidFeature, List<AdPlatformCreativeDTO> dtoList) {
-        for (AdPlatformCreativeDTO dto : dtoList) {
-            Map<String, Map<String, String>> feature = cidFeature.getOrDefault(String.valueOf(dto.getCreativeId()), new HashMap<>());
-            Map<String, String> basicInfo = feature.getOrDefault("alg_cid_feature_basic_info", new HashMap<>());
-            String customer = basicInfo.getOrDefault("customer", "");
-            dto.setCustomer(customer);
-        }
+    private void fullCustomerInfo(Map<String, Map<String, Map<String, String>>> cidFeature, AdRankItem rankItem) {
+        Map<String, Map<String, String>> feature = cidFeature.getOrDefault(String.valueOf(rankItem.getAdId()), new HashMap<>());
+        Map<String, String> basicInfo = feature.getOrDefault("alg_cid_feature_basic_info", new HashMap<>());
+        String customer = basicInfo.getOrDefault(CUSTOMER_FIELD_NAME, "");
+        rankItem.getExt().put("customer", customer);
     }
 
     private String choose(List<HotRankFeatureInfo> hotRankFeatureInfos) {
@@ -133,25 +166,26 @@ public class RankStrategyBy687 extends RankStrategyBasic {
         // 按照曝光拆分
         List<HotRankFeatureInfo> highView = new ArrayList<>();
         List<HotRankFeatureInfo> tailView = new ArrayList<>();
+        int highIdx = 0, tailIdx = 0;
         for (HotRankFeatureInfo hotRankFeatureInfo : hotRankFeatureInfos) {
             if (hotRankFeatureInfo.getView() >= hotRankViewThreshold) {
+                hotRankFeatureInfo.setRank(highIdx++);
                 highView.add(hotRankFeatureInfo);
             } else {
+                hotRankFeatureInfo.setRank(tailIdx++);
                 tailView.add(hotRankFeatureInfo);
             }
         }
 
-        if (CollectionUtils.isNotEmpty(highView)) {
-            // 高曝光中CPM最大的设置初始权重
-            this.calcFirstItemWeight(highView, tailView, true);
-            // 计算高曝光列表中其他的权重
-            this.calcListOtherWeight(highView);
-        }
+        // 设置高曝光列表的初始权重
+        this.calcFirstItemWeight(highView, tailView, true);
+        // 计算高曝光列表中其他的权重
+        this.calcListOtherWeight(highView);
 
-        if (CollectionUtils.isNotEmpty(tailView)) {
-            this.calcFirstItemWeight(highView, tailView, false);
-            this.calcListOtherWeight(tailView);
-        }
+        // 设置低曝光列表的初始权重
+        this.calcFirstItemWeight(highView, tailView, false);
+        // 计算低曝光列表中其他的权重
+        this.calcListOtherWeight(tailView);
 
         List<WeightRandom.ItemWithWeight<String>> itemWithWeights = new ArrayList<>(hotRankFeatureInfos.size());
         for (HotRankFeatureInfo hotRankFeatureInfo : hotRankFeatureInfos) {
@@ -163,9 +197,18 @@ public class RankStrategyBy687 extends RankStrategyBasic {
     }
 
     private void calcFirstItemWeight(List<HotRankFeatureInfo> high, List<HotRankFeatureInfo> tail, boolean isHigh) {
-        if (isHigh) {
+        if (CollectionUtils.isEmpty(high) && CollectionUtils.isEmpty(tail)) {
+            return;
+        }
+
+        // 设置高曝光的初始权重
+        if (isHigh && CollectionUtils.isNotEmpty(high)) {
             high.get(0).setWeight(Math.max(1, hotRankMaxWeight));
-        } else {
+            return;
+        }
+
+        // 设置低曝光的初始权重,从高曝光列表中找到第一个CPM小于等于低曝光最高CPM的元素权重
+        if (!isHigh && CollectionUtils.isNotEmpty(tail)) {
             HotRankFeatureInfo firstTail = tail.get(0);
             double firstCpm = firstTail.getCpm();
             for (HotRankFeatureInfo info : high) {
@@ -198,6 +241,23 @@ public class RankStrategyBy687 extends RankStrategyBasic {
         }
     }
 
+    private void fullMetaFeature(AdRankItem rankItem, String userLayer, Map<String, HotRankFeatureInfo> allCustomerFeatureMap, Map<Long, HotRankFeatureInfo> allCreativeFeatureMap, Feature feature) {
+        String customer = rankItem.getExt().getOrDefault(CUSTOMER_FIELD_NAME, "").toString();
+        if (StringUtils.isNotBlank(customer) && allCustomerFeatureMap.containsKey(customer)) {
+            HotRankFeatureInfo customerFeatureInfo = allCustomerFeatureMap.get(customer);
+            rankItem.getMetaFeatureMap().put("customerFeature", customerFeatureInfo.covertToFeatureMap());
+        }
+
+        if (allCreativeFeatureMap.containsKey(rankItem.getAdId())) {
+            HotRankFeatureInfo customerFeatureInfo = allCreativeFeatureMap.get(rankItem.getAdId());
+            rankItem.getMetaFeatureMap().put("creativeFeature", customerFeatureInfo.covertToFeatureMap());
+        }
+
+        Map<String, String> midFeature = new HashMap<>(4);
+        midFeature.put("userLayer", userLayer);
+        rankItem.getMetaFeatureMap().put("midFeature", midFeature);
+    }
+
     @Data
     @NoArgsConstructor
     @AllArgsConstructor
@@ -209,5 +269,16 @@ public class RankStrategyBy687 extends RankStrategyBasic {
         private int view;
 
         private double weight = 1;
+
+        private int rank;
+
+        public Map<String, String> covertToFeatureMap() {
+            Map<String, String> featureMap = new HashMap<>(4);
+            featureMap.put("rank", String.valueOf(this.getRank()));
+            featureMap.put("cpm", String.valueOf(this.getCpm()));
+            featureMap.put("view", String.valueOf(this.getView()));
+            featureMap.put("weight", String.valueOf(this.getWeight()));
+            return featureMap;
+        }
     }
 }