|
@@ -1,17 +1,17 @@
|
|
|
package com.tzld.piaoquan.recommend.server.service.rank.strategy;
|
|
|
|
|
|
|
|
|
-import com.alibaba.fastjson.JSONObject;
|
|
|
import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
|
|
|
-import com.google.common.reflect.TypeToken;
|
|
|
import com.tzld.piaoquan.recommend.server.model.Video;
|
|
|
import com.tzld.piaoquan.recommend.server.service.rank.RankParam;
|
|
|
import com.tzld.piaoquan.recommend.server.service.rank.RankResult;
|
|
|
import com.tzld.piaoquan.recommend.server.service.rank.RankService;
|
|
|
import com.tzld.piaoquan.recommend.server.service.rank.extractor.RankExtractorFeature;
|
|
|
+import com.tzld.piaoquan.recommend.server.service.rank.processor.RankProcessorBoost;
|
|
|
import com.tzld.piaoquan.recommend.server.service.rank.processor.RankProcessorDensity;
|
|
|
+import com.tzld.piaoquan.recommend.server.service.rank.processor.RankProcessorInsert;
|
|
|
import com.tzld.piaoquan.recommend.server.service.rank.processor.RankProcessorTagFilter;
|
|
|
-import com.tzld.piaoquan.recommend.server.util.JSONUtils;
|
|
|
+import com.tzld.piaoquan.recommend.server.service.rank.extractor.RankExtractorItemTags;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.collections4.CollectionUtils;
|
|
|
import org.apache.commons.lang3.RandomUtils;
|
|
@@ -21,132 +21,107 @@ import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
- * @author zhangbo
|
|
|
- * @desc 带密度控制的后处理 排序实验
|
|
|
+ * @author zhangbo sunxiaoyi
|
|
|
+ * @desc 后处理规则 + roc池flow池的合并
|
|
|
+ * 后处理参考文档:https://w42nne6hzg.feishu.cn/wiki/MYaGwCnF1iTFXUkSddAcA6CanFe
|
|
|
+ * roc池flow池的合并 文档: 暂无
|
|
|
*/
|
|
|
@Service
|
|
|
@Slf4j
|
|
|
public class RankStrategy4Density extends RankService {
|
|
|
@ApolloJsonValue("${RankStrategy4DensityFilter:}")
|
|
|
- private Map<String,Map<String, Map<String, String>>> filterRules;
|
|
|
+ private Map<String,Map<String, Map<String, String>>> filterRules = new HashMap<>();
|
|
|
@Override
|
|
|
- public RankResult mergeAndSort(RankParam param, List<Video> rovRecallRank, List<Video> flowPoolRank) {
|
|
|
+ public RankResult mergeAndSort(RankParam param, List<Video> rovVideos, List<Video> flowVideos) {
|
|
|
|
|
|
- if (CollectionUtils.isEmpty(rovRecallRank)) {
|
|
|
- if (param.getSize() < flowPoolRank.size()) {
|
|
|
- return new RankResult(flowPoolRank.subList(0, param.getSize()));
|
|
|
+ //1 兜底策略,rov池子不足时,用冷启池填补。直接返回。
|
|
|
+ if (CollectionUtils.isEmpty(rovVideos)) {
|
|
|
+ if (param.getSize() < flowVideos.size()) {
|
|
|
+ return new RankResult(flowVideos.subList(0, param.getSize()));
|
|
|
} else {
|
|
|
- return new RankResult(flowPoolRank);
|
|
|
- }
|
|
|
- }
|
|
|
- // 1 读取多样性密度控制规则------------------
|
|
|
-// String appType = String.valueOf(param.getAppType());
|
|
|
-// String ruleStr = this.redisTemplate.opsForValue().get("TAGS_FILTER_RULE_V1_JSON");
|
|
|
-// Map<String, Integer> densityRules = new HashMap<>();
|
|
|
-// if (ruleStr != null){
|
|
|
-// Map<String, Map<String, Object>> ruleOrigin = JSONUtils.fromJson(ruleStr,
|
|
|
-// new TypeToken<Map<String, Map<String, Object>>>() {},
|
|
|
-// Collections.emptyMap());
|
|
|
-// for (Map.Entry<String, Map<String, Object>> entry : ruleOrigin.entrySet()){
|
|
|
-// String k = entry.getKey();
|
|
|
-// if (!entry.getValue().containsKey(appType)){
|
|
|
-// continue;
|
|
|
-// }
|
|
|
-// JSONObject jb = (JSONObject) entry.getValue().get(appType);
|
|
|
-// try{
|
|
|
-// if (jb.containsKey("density") && jb.get("density") instanceof Integer){
|
|
|
-// densityRules.put(k, jb.getInteger("density"));
|
|
|
-// }
|
|
|
-// }catch (Exception e){
|
|
|
-// log.error("parse densityRules is wrong:", e);
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
- Map<String, Integer> densityRules = new HashMap<>();
|
|
|
- String abCode = param.getAbCode();
|
|
|
- if (this.filterRules != null && this.filterRules.containsKey(abCode)){
|
|
|
- Map<String, Map<String, String>> rule = this.filterRules.get(abCode);
|
|
|
- for (Map.Entry<String, Map<String, String>> entry : rule.entrySet()){
|
|
|
- String key = entry.getKey();
|
|
|
- Map<String, String> value = entry.getValue();
|
|
|
- if (value.containsKey("density")){
|
|
|
- densityRules.put(key, Integer.valueOf(value.get("density")));
|
|
|
- }
|
|
|
+ return new RankResult(flowVideos);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ //2 根据实验号解析阿波罗参数。
|
|
|
+ String abCode = param.getAbCode();
|
|
|
+ Map<String, Map<String, String>> rulesMap = this.filterRules.getOrDefault(abCode, new HashMap<>(0));
|
|
|
|
|
|
- // 2 读取video的tags------------------
|
|
|
- List<Long> videoIds = new ArrayList<>();
|
|
|
- for (Video v : rovRecallRank) {
|
|
|
- videoIds.add(v.getVideoId());
|
|
|
- }
|
|
|
- for (Video v : flowPoolRank) {
|
|
|
- videoIds.add(v.getVideoId());
|
|
|
- }
|
|
|
- Map<Long, List<String>> videoTagDict = RankExtractorFeature.getVideoTags(this.redisTemplate, videoIds);
|
|
|
- for (Video v : rovRecallRank) {
|
|
|
- v.setTags(videoTagDict.getOrDefault(v.getVideoId(), new ArrayList<>()));
|
|
|
+ //3 标签读取
|
|
|
+ if (rulesMap != null && !rulesMap.isEmpty()){
|
|
|
+ RankExtractorItemTags extractorItemTags = new RankExtractorItemTags(this.redisTemplate);
|
|
|
+ extractorItemTags.processor(rovVideos, flowVideos);
|
|
|
}
|
|
|
- for (Video v : flowPoolRank) {
|
|
|
- v.setTags(videoTagDict.getOrDefault(v.getVideoId(), new ArrayList<>()));
|
|
|
+ //6 合并结果时间卡控
|
|
|
+ if (rulesMap != null && !rulesMap.isEmpty()){
|
|
|
+ RankProcessorTagFilter.processor(rovVideos, flowVideos, rulesMap);
|
|
|
}
|
|
|
|
|
|
- // 3 读取过滤规则,根据tag和过滤规则进行过滤------------------
|
|
|
- if (this.filterRules != null && this.filterRules.containsKey(abCode)){
|
|
|
- Map<String, Map<String, String>> rule = this.filterRules.get(abCode);
|
|
|
- RankProcessorTagFilter.tagFitlter(rovRecallRank, flowPoolRank, rule);
|
|
|
- }
|
|
|
+ //4 rov池提权功能
|
|
|
+ RankProcessorBoost.boostByTag(rovVideos, rulesMap);
|
|
|
+
|
|
|
+ //5 rov池强插功能
|
|
|
+ RankProcessorInsert.insertByTag(param, rovVideos, rulesMap);
|
|
|
|
|
|
- // 4 流量池按比例强插---------------------
|
|
|
+ //7 流量池按比例强插
|
|
|
List<Video> result = new ArrayList<>();
|
|
|
- for (int i = 0; i < param.getTopK() && i < rovRecallRank.size(); i++) {
|
|
|
- result.add(rovRecallRank.get(i));
|
|
|
+ for (int i = 0; i < param.getTopK() && i < rovVideos.size(); i++) {
|
|
|
+ result.add(rovVideos.get(i));
|
|
|
}
|
|
|
-
|
|
|
double flowPoolP = getFlowPoolP(param);
|
|
|
int flowPoolIndex = 0;
|
|
|
int rovPoolIndex = param.getTopK();
|
|
|
-
|
|
|
for (int i = 0; i < param.getSize() - param.getTopK(); i++) {
|
|
|
double rand = RandomUtils.nextDouble(0, 1);
|
|
|
log.info("rand={}, flowPoolP={}", rand, flowPoolP);
|
|
|
if (rand < flowPoolP) {
|
|
|
- if (flowPoolIndex < flowPoolRank.size()) {
|
|
|
- result.add(flowPoolRank.get(flowPoolIndex++));
|
|
|
+ if (flowPoolIndex < flowVideos.size()) {
|
|
|
+ result.add(flowVideos.get(flowPoolIndex++));
|
|
|
} else {
|
|
|
break;
|
|
|
}
|
|
|
} else {
|
|
|
- if (rovPoolIndex < rovRecallRank.size()) {
|
|
|
- result.add(rovRecallRank.get(rovPoolIndex++));
|
|
|
+ if (rovPoolIndex < rovVideos.size()) {
|
|
|
+ result.add(rovVideos.get(rovPoolIndex++));
|
|
|
} else {
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- if (rovPoolIndex >= rovRecallRank.size()) {
|
|
|
- for (int i = flowPoolIndex; i < flowPoolRank.size() && result.size() < param.getSize(); i++) {
|
|
|
- result.add(flowPoolRank.get(i));
|
|
|
+ if (rovPoolIndex >= rovVideos.size()) {
|
|
|
+ for (int i = flowPoolIndex; i < flowVideos.size() && result.size() < param.getSize(); i++) {
|
|
|
+ result.add(flowVideos.get(i));
|
|
|
}
|
|
|
}
|
|
|
- if (flowPoolIndex >= flowPoolRank.size()) {
|
|
|
- for (int i = rovPoolIndex; i < rovRecallRank.size() && result.size() < param.getSize(); i++) {
|
|
|
- result.add(rovRecallRank.get(i));
|
|
|
+ if (flowPoolIndex >= flowVideos.size()) {
|
|
|
+ for (int i = rovPoolIndex; i < rovVideos.size() && result.size() < param.getSize(); i++) {
|
|
|
+ result.add(rovVideos.get(i));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 3 进行密度控制------------------
|
|
|
- Set<Long> videosSet = result.stream().map(r-> r.getVideoId()).collect(Collectors.toSet());
|
|
|
- List<Video> rovRecallRankNew = rovRecallRank.stream().filter(r -> !videosSet.contains(r.getVideoId())).collect(Collectors.toList());
|
|
|
- List<Video> flowPoolRankNew = flowPoolRank.stream().filter(r -> !videosSet.contains(r.getVideoId())).collect(Collectors.toList());
|
|
|
- List<Video> resultWithDnsity = RankProcessorDensity.mergeDensityControl(result,
|
|
|
+ //8 合并结果密度控制
|
|
|
+ Map<String, Integer> densityRules = new HashMap<>();
|
|
|
+ if (rulesMap != null && !rulesMap.isEmpty()) {
|
|
|
+ for (Map.Entry<String, Map<String, String>> entry : rulesMap.entrySet()) {
|
|
|
+ String key = entry.getKey();
|
|
|
+ Map<String, String> value = entry.getValue();
|
|
|
+ if (value.containsKey("density")) {
|
|
|
+ densityRules.put(key, Integer.valueOf(value.get("density")));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Set<Long> videosSet = result.stream().map(Video::getVideoId).collect(Collectors.toSet());
|
|
|
+ List<Video> rovRecallRankNew = rovVideos.stream().filter(r -> !videosSet.contains(r.getVideoId())).collect(Collectors.toList());
|
|
|
+ List<Video> flowPoolRankNew = flowVideos.stream().filter(r -> !videosSet.contains(r.getVideoId())).collect(Collectors.toList());
|
|
|
+ List<Video> resultWithDensity = RankProcessorDensity.mergeDensityControl(result,
|
|
|
rovRecallRankNew, flowPoolRankNew, densityRules);
|
|
|
-// log.info("zhangbo22 old={}, new={}", JSONUtils.toJson(result),
|
|
|
-// JSONUtils.toJson(resultWithDnsity));
|
|
|
- return new RankResult(resultWithDnsity);
|
|
|
+
|
|
|
+ return new RankResult(resultWithDensity);
|
|
|
}
|
|
|
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
|
|
|
|
|
|
// public Video getTestVideo(Long id, String s){
|
|
@@ -156,6 +131,26 @@ public class RankStrategy4Density extends RankService {
|
|
|
// return a1;
|
|
|
// }
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
+// 1 读取多样性密度控制规则------------------
|
|
|
+// String appType = String.valueOf(param.getAppType());
|
|
|
+// String ruleStr = this.redisTemplate.opsForValue().get("TAGS_FILTER_RULE_V1_JSON");
|
|
|
+// Map<String, Integer> densityRules = new HashMap<>();
|
|
|
+// if (ruleStr != null){
|
|
|
+// Map<String, Map<String, Object>> ruleOrigin = JSONUtils.fromJson(ruleStr,
|
|
|
+// new TypeToken<Map<String, Map<String, Object>>>() {},
|
|
|
+// Collections.emptyMap());
|
|
|
+// for (Map.Entry<String, Map<String, Object>> entry : ruleOrigin.entrySet()){
|
|
|
+// String k = entry.getKey();
|
|
|
+// if (!entry.getValue().containsKey(appType)){
|
|
|
+// continue;
|
|
|
+// }
|
|
|
+// JSONObject jb = (JSONObject) entry.getValue().get(appType);
|
|
|
+// try{
|
|
|
+// if (jb.containsKey("density") && jb.get("density") instanceof Integer){
|
|
|
+// densityRules.put(k, jb.getInteger("density"));
|
|
|
+// }
|
|
|
+// }catch (Exception e){
|
|
|
+// log.error("parse densityRules is wrong:", e);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|