|
@@ -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;
|
|
|
+ }
|
|
|
}
|
|
|
}
|