|
@@ -0,0 +1,140 @@
|
|
|
+package com.tzld.piaoquan.recommend.server.service.recall.strategy;
|
|
|
+
|
|
|
+import com.tzld.piaoquan.recommend.server.model.Video;
|
|
|
+import com.tzld.piaoquan.recommend.server.service.filter.FilterParam;
|
|
|
+import com.tzld.piaoquan.recommend.server.service.filter.FilterResult;
|
|
|
+import com.tzld.piaoquan.recommend.server.service.filter.FilterService;
|
|
|
+import com.tzld.piaoquan.recommend.server.service.recall.FilterParamFactory;
|
|
|
+import com.tzld.piaoquan.recommend.server.service.recall.RecallParam;
|
|
|
+import com.tzld.piaoquan.recommend.server.service.recall.RecallStrategy;
|
|
|
+import com.tzld.piaoquan.recommend.server.util.FeatureUtils;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.collections4.CollectionUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Qualifier;
|
|
|
+import org.springframework.data.redis.core.RedisTemplate;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Component
|
|
|
+@Slf4j
|
|
|
+public class ChannelROVRecallStrategy implements RecallStrategy {
|
|
|
+ private final String CLASS_NAME = this.getClass().getSimpleName();
|
|
|
+ @Autowired
|
|
|
+ private FilterService filterService;
|
|
|
+ @Autowired
|
|
|
+ @Qualifier("redisTemplate")
|
|
|
+ public RedisTemplate<String, String> redisTemplate;
|
|
|
+
|
|
|
+ private static final String channelRegex = "(longArticles_|dyyjs_|touliu_tencent_|touliu_tencentgzh_|touliu_tencentGzhArticle_|GzhTouLiu_Articles_gh)";
|
|
|
+ private static final Pattern channelPattern = Pattern.compile(channelRegex);
|
|
|
+
|
|
|
+ public static final String PUSH_FORM = "recall_strategy_channel";
|
|
|
+ public static final String redisKeyPrefix = "channel_recall";
|
|
|
+ public static final String channelGroupPrefix = "alg_recsys_user_channel_group";
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String pushFrom() {
|
|
|
+ return PUSH_FORM;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<Video> recall(RecallParam param) {
|
|
|
+ List<Video> videosResult = new ArrayList<>();
|
|
|
+ try {
|
|
|
+ if (!FeatureUtils.firstLevel(param.getUserShareDepth())) {
|
|
|
+ return videosResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ String channelName = getChannelName(param.getRootSourceId());
|
|
|
+ if (channelName.isEmpty()) {
|
|
|
+ return videosResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ String key = String.format("%s:%s", redisKeyPrefix, channelName);
|
|
|
+ String value = redisTemplate.opsForValue().get(key);
|
|
|
+ if (null == value || value.isEmpty()) {
|
|
|
+ return videosResult;
|
|
|
+ }
|
|
|
+ List<Long> vidList = parseVidList(param.getVideoId(), value);
|
|
|
+ fillVideoResult(param, vidList, videosResult);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("recall is wrong in {}, error={}", CLASS_NAME, e);
|
|
|
+ }
|
|
|
+ return videosResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<Long> parseVidList(Long headVid, String data) {
|
|
|
+ List<Long> vidList = new ArrayList<>();
|
|
|
+ if (null != data && !data.isEmpty()) {
|
|
|
+ String[] pair = data.split("\t");
|
|
|
+ if (2 == pair.length) {
|
|
|
+ Set<Long> hit = new HashSet<>();
|
|
|
+ hit.add(headVid);
|
|
|
+ List<Long> ids = Arrays.stream(pair[0].split(",")).map(Long::valueOf).collect(Collectors.toList());
|
|
|
+ if (!ids.isEmpty()) {
|
|
|
+ for (Long id : ids) {
|
|
|
+ if (!hit.contains(id)) {
|
|
|
+ hit.add(id);
|
|
|
+ vidList.add(id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return vidList;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void fillVideoResult(RecallParam param, List<Long> vidList, List<Video> videosResult) {
|
|
|
+ FilterParam filterParam = FilterParamFactory.create(param, vidList);
|
|
|
+ FilterResult filterResult = filterService.filter(filterParam);
|
|
|
+ if (filterResult != null && CollectionUtils.isNotEmpty(filterResult.getVideoIds())) {
|
|
|
+ List<Long> filterIds = filterResult.getVideoIds();
|
|
|
+ int n = filterIds.size();
|
|
|
+ for (int i = 0; i < n; i++) {
|
|
|
+ Video video = new Video();
|
|
|
+ video.setVideoId(filterIds.get(i));
|
|
|
+ video.setRovScore(n - i);
|
|
|
+ video.setPushFrom(pushFrom());
|
|
|
+ videosResult.add(video);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private String getChannelName(String s) {
|
|
|
+ if (null != s && !s.isEmpty()) {
|
|
|
+ Matcher matcher = channelPattern.matcher(s);
|
|
|
+ if (matcher.find()) {
|
|
|
+ switch (matcher.group(0)) {
|
|
|
+ case "longArticles_":
|
|
|
+ return getChannelType(s);
|
|
|
+ case "dyyjs_":
|
|
|
+ return "公众号代运营-即转";
|
|
|
+ case "touliu_tencent_":
|
|
|
+ return "小程序投流";
|
|
|
+ case "touliu_tencentgzh_":
|
|
|
+ case "touliu_tencentGzhArticle_":
|
|
|
+ case "GzhTouLiu_Articles_gh":
|
|
|
+ return "公众号投流";
|
|
|
+ default:
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getChannelType(String s) {
|
|
|
+ String key = String.format("%s:%s", channelGroupPrefix, s);
|
|
|
+ String value = redisTemplate.opsForValue().get(key);
|
|
|
+ if (null != value && value.equals("公众号买号")) {
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+ return "公众号代运营-Daily";
|
|
|
+ }
|
|
|
+}
|