|
@@ -1,6 +1,7 @@
|
|
package com.tzld.piaoquan.recommend.server.service.rank;
|
|
package com.tzld.piaoquan.recommend.server.service.rank;
|
|
|
|
|
|
|
|
|
|
|
|
+import com.google.common.reflect.TypeToken;
|
|
import com.tzld.piaoquan.recommend.feature.domain.video.base.ItemFeature;
|
|
import com.tzld.piaoquan.recommend.feature.domain.video.base.ItemFeature;
|
|
import com.tzld.piaoquan.recommend.feature.domain.video.base.RequestContext;
|
|
import com.tzld.piaoquan.recommend.feature.domain.video.base.RequestContext;
|
|
import com.tzld.piaoquan.recommend.feature.domain.video.base.UserFeature;
|
|
import com.tzld.piaoquan.recommend.feature.domain.video.base.UserFeature;
|
|
@@ -10,6 +11,8 @@ import com.tzld.piaoquan.recommend.server.model.MachineInfo;
|
|
import com.tzld.piaoquan.recommend.server.model.Video;
|
|
import com.tzld.piaoquan.recommend.server.model.Video;
|
|
import com.tzld.piaoquan.recommend.server.remote.FeatureRemoteService;
|
|
import com.tzld.piaoquan.recommend.server.remote.FeatureRemoteService;
|
|
import com.tzld.piaoquan.recommend.server.service.flowpool.FlowPoolConstants;
|
|
import com.tzld.piaoquan.recommend.server.service.flowpool.FlowPoolConstants;
|
|
|
|
+import com.tzld.piaoquan.recommend.server.service.rank.extractor.RankExtractorFeature;
|
|
|
|
+import com.tzld.piaoquan.recommend.server.service.rank.processor.RankProcessorDensity;
|
|
import com.tzld.piaoquan.recommend.server.service.recall.RecallResult;
|
|
import com.tzld.piaoquan.recommend.server.service.recall.RecallResult;
|
|
import com.tzld.piaoquan.recommend.server.service.recall.strategy.*;
|
|
import com.tzld.piaoquan.recommend.server.service.recall.strategy.*;
|
|
import com.tzld.piaoquan.recommend.server.service.score.ScoreParam;
|
|
import com.tzld.piaoquan.recommend.server.service.score.ScoreParam;
|
|
@@ -75,7 +78,13 @@ public class RankService {
|
|
JSONUtils.toJson(flowPoolRank));
|
|
JSONUtils.toJson(flowPoolRank));
|
|
|
|
|
|
// 融合排序
|
|
// 融合排序
|
|
- return mergeAndSort(param, rovRecallRank, flowPoolRank);
|
|
|
|
|
|
+ String abCode = param.getAbCode();
|
|
|
|
+ switch (abCode){
|
|
|
|
+ case "60098":
|
|
|
|
+ return this.mergeAndSort4Density(param, rovRecallRank, flowPoolRank);
|
|
|
|
+ default:
|
|
|
|
+ return mergeAndSort(param, rovRecallRank, flowPoolRank);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
private List<Video> mergeAndRankRovRecall(RankParam param) {
|
|
private List<Video> mergeAndRankRovRecall(RankParam param) {
|
|
@@ -125,6 +134,31 @@ public class RankService {
|
|
rovRecallRank.addAll(extractAndSort(param, ReturnVideoRecallStrategy.PUSH_FORM));
|
|
rovRecallRank.addAll(extractAndSort(param, ReturnVideoRecallStrategy.PUSH_FORM));
|
|
removeDuplicate(rovRecallRank);
|
|
removeDuplicate(rovRecallRank);
|
|
|
|
|
|
|
|
+ // 融合排序
|
|
|
|
+ List<String> videoIdKeys = rovRecallRank.stream()
|
|
|
|
+ .map(t -> param.getRankKeyPrefix() + t.getVideoId())
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
+ List<String> videoScores = redisTemplate.opsForValue().multiGet(videoIdKeys);
|
|
|
|
+ log.info("rank mergeAndRankRovRecall videoIdKeys={}, videoScores={}", JSONUtils.toJson(videoIdKeys),
|
|
|
|
+ JSONUtils.toJson(videoScores));
|
|
|
|
+ if (CollectionUtils.isNotEmpty(videoScores)
|
|
|
|
+ && videoScores.size() == rovRecallRank.size()) {
|
|
|
|
+ for (int i = 0; i < videoScores.size(); i++) {
|
|
|
|
+ rovRecallRank.get(i).setSortScore(NumberUtils.toDouble(videoScores.get(i), 0.0));
|
|
|
|
+ }
|
|
|
|
+ Collections.sort(rovRecallRank, Comparator.comparingDouble(o -> -o.getSortScore()));
|
|
|
|
+ }
|
|
|
|
+ }else if(param.getAbCode().equals("60098")) {
|
|
|
|
+
|
|
|
|
+ int sizeNew = param.getSize();
|
|
|
|
+ removeDuplicate(rovRecallRank);
|
|
|
|
+ rovRecallRank = rovRecallRank.size() <= sizeNew ? rovRecallRank: rovRecallRank.subList(0, sizeNew);
|
|
|
|
+
|
|
|
|
+ // merge sim recall 和 return recall
|
|
|
|
+ rovRecallRank.addAll(extractAndSort(param, SimHotVideoRecallStrategy.PUSH_FORM));
|
|
|
|
+ rovRecallRank.addAll(extractAndSort(param, ReturnVideoRecallStrategy.PUSH_FORM));
|
|
|
|
+ removeDuplicate(rovRecallRank);
|
|
|
|
+
|
|
// 融合排序
|
|
// 融合排序
|
|
List<String> videoIdKeys = rovRecallRank.stream()
|
|
List<String> videoIdKeys = rovRecallRank.stream()
|
|
.map(t -> param.getRankKeyPrefix() + t.getVideoId())
|
|
.map(t -> param.getRankKeyPrefix() + t.getVideoId())
|
|
@@ -359,4 +393,98 @@ public class RankService {
|
|
return new RankResult(result);
|
|
return new RankResult(result);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private RankResult mergeAndSort4Density(RankParam param, List<Video> rovRecallRank, List<Video> flowPoolRank) {
|
|
|
|
+ if (CollectionUtils.isEmpty(rovRecallRank)) {
|
|
|
|
+ if (param.getSize() < flowPoolRank.size()) {
|
|
|
|
+ return new RankResult(flowPoolRank.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;
|
|
|
|
+ }
|
|
|
|
+ String str = (String) entry.getValue().get(appType);
|
|
|
|
+ Map<String, Object> tmp = JSONUtils.fromJson(str,
|
|
|
|
+ new TypeToken<Map<String, Object>>() {},
|
|
|
|
+ Collections.emptyMap());
|
|
|
|
+ if (tmp.containsKey("density") && tmp.get("density") instanceof Integer){
|
|
|
|
+ densityRules.put(k, (Integer)tmp.get("density"));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 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<>()));
|
|
|
|
+ }
|
|
|
|
+ for (Video v : flowPoolRank) {
|
|
|
|
+ v.setTags(videoTagDict.getOrDefault(v.getVideoId(), new ArrayList<>()));
|
|
|
|
+ }
|
|
|
|
+ // ------------------读取video的tags完成---------------------
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ List<Video> result = new ArrayList<>();
|
|
|
|
+ for (int i = 0; i < param.getTopK() && i < rovRecallRank.size(); i++) {
|
|
|
|
+ result.add(rovRecallRank.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++));
|
|
|
|
+ } else {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if (rovPoolIndex < rovRecallRank.size()) {
|
|
|
|
+ result.add(rovRecallRank.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 (flowPoolIndex >= flowPoolRank.size()) {
|
|
|
|
+ for (int i = rovPoolIndex; i < rovRecallRank.size() && result.size() < param.getSize(); i++) {
|
|
|
|
+ result.add(rovRecallRank.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 3 进行密度控制
|
|
|
|
+ Set<Long> videosSet = result.stream().map(r-> r.getVideoId()).collect(Collectors.toSet());
|
|
|
|
+ rovRecallRank = rovRecallRank.stream().filter(r -> !videosSet.contains(r.getVideoId())).collect(Collectors.toList());
|
|
|
|
+ flowPoolRank = flowPoolRank.stream().filter(r -> !videosSet.contains(r.getVideoId())).collect(Collectors.toList());
|
|
|
|
+ List<Video> resultWithDnsity = RankProcessorDensity.mergeDensityControl(result,
|
|
|
|
+ rovRecallRank, flowPoolRank, densityRules);
|
|
|
|
+ return new RankResult(resultWithDnsity);
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|