소스 검색

Merge branch 'feature/zhangbo_rank' of algorithm/recommend-server into master

zhangbo 1 년 전
부모
커밋
0afcde8892
13개의 변경된 파일805개의 추가작업 그리고 139개의 파일을 삭제
  1. 3 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/base/RankItem.java
  2. 3 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/Video.java
  3. 4 4
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/RecommendService.java
  4. 34 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankRouter.java
  5. 12 131
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankService.java
  6. 80 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/OfflineVlogFeatureGroup.java
  7. 92 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/OfflineVlogShareLRFeatureExtractor.java
  8. 149 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4Density.java
  9. 204 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RankModel.java
  10. 5 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score/AbstractScorer.java
  11. 76 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score/ScorerPipeline.java
  12. 142 3
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score/VlogShareLRScorer.java
  13. 1 1
      recommend-server-service/src/main/resources/feeds_score_config_baseline.conf

+ 3 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/base/RankItem.java

@@ -10,6 +10,9 @@ import java.util.Map;
 
 @Data
 public class RankItem implements Comparable<RankItem> {
+
+    // featureMap中保存所有的特征
+    public Map<String, String> featureMap = new HashMap<>();
     public long videoId;
     private double score; // 记录最终的score
     private Video video;

+ 3 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/Video.java

@@ -29,4 +29,7 @@ public class Video {
     // video的特征 tag
     private List<String> tags = new ArrayList<>();
 
+    // video的模型打分
+    private double modelScore = 0.0D;
+
 }

+ 4 - 4
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/RecommendService.java

@@ -17,7 +17,7 @@ import com.tzld.piaoquan.recommend.server.service.flowpool.FlowPoolConstants;
 import com.tzld.piaoquan.recommend.server.service.flowpool.FlowPoolService;
 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.RankRouter;
 import com.tzld.piaoquan.recommend.server.service.recall.RecallParam;
 import com.tzld.piaoquan.recommend.server.service.recall.RecallResult;
 import com.tzld.piaoquan.recommend.server.service.recall.RecallService;
@@ -68,7 +68,7 @@ public class RecommendService {
     @Autowired
     private RecallService recallService;
     @Autowired
-    private RankService rankService;
+    private RankRouter rankRouter;
     @Autowired
     private PreViewedService preViewedService;
     @Autowired
@@ -164,7 +164,7 @@ public class RecommendService {
         rankParam.setSize(request.getSize());
         rankParam.setSpecialRecommend(true);
 
-        RankResult rankResult = rankService.rank(rankParam);
+        RankResult rankResult = rankRouter.rank(rankParam);
         log.info("rankParam, rankResult {}", JSONUtils.toJson(rankParam), JSONUtils.toJson(rankResult));
 
         if (rankResult == null || CollectionUtils.isEmpty(rankResult.getVideos())) {
@@ -348,7 +348,7 @@ public class RecommendService {
                 stopwatch.elapsed(TimeUnit.MILLISECONDS));
         stopwatch.reset().start();
 
-        RankResult rankResult = rankService.rank(convertToRankParam(param, recallResult));
+        RankResult rankResult = rankRouter.rank(convertToRankParam(param, recallResult));
         log.info("rankResult={}, videoRecommend rank cost={}", rankResult,
                 stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));
 

+ 34 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankRouter.java

@@ -0,0 +1,34 @@
+package com.tzld.piaoquan.recommend.server.service.rank;
+
+import com.tzld.piaoquan.recommend.server.service.rank.strategy.RankStrategy4Density;
+import com.tzld.piaoquan.recommend.server.service.rank.strategy.RankStrategy4RankModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+@Slf4j
+public class RankRouter {
+    @Autowired
+    private RankService rankService;
+    @Autowired
+    private RankStrategy4RankModel rankStrategy4RankModel;
+    @Autowired
+    private RankStrategy4Density rankStrategy4Density;
+    public RankResult rank(RankParam param) {
+        String abCode = param.getAbCode();
+        if (abCode == null) {
+            return rankService.rank(param);
+        }
+        switch (abCode){
+            case "60101":
+                return rankStrategy4RankModel.rank(param);
+            case "60098":
+                return rankStrategy4Density.rank(param);
+            default:
+                break;
+        }
+        return rankService.rank(param);
+    }
+}
+

+ 12 - 131
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankService.java

@@ -19,6 +19,8 @@ import com.tzld.piaoquan.recommend.server.service.score.ScoreParam;
 import com.tzld.piaoquan.recommend.server.service.score.ScorerUtils;
 import com.tzld.piaoquan.recommend.server.util.CommonCollectionUtils;
 import com.tzld.piaoquan.recommend.server.util.JSONUtils;
+import lombok.Getter;
+import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.RandomUtils;
@@ -40,7 +42,7 @@ import java.util.stream.Collectors;
 @Slf4j
 public class RankService {
     @Autowired
-    private RedisTemplate<String, String> redisTemplate;
+    public RedisTemplate<String, String> redisTemplate;
     @Autowired
     private FeatureRemoteService featureRemoteService;
     @Value("${newRankSwitch:false}")
@@ -79,16 +81,9 @@ public class RankService {
                 JSONUtils.toJson(flowPoolRank));
 
         // 融合排序
-        String abCode = param.getAbCode();
-        switch (abCode){
-            case "60098":
-                return this.mergeAndSort4Density(param, rovRecallRank, flowPoolRank);
-            default:
-                return mergeAndSort(param, rovRecallRank, flowPoolRank);
-        }
-    }
+        return mergeAndSort(param, rovRecallRank, flowPoolRank);    }
 
-    private List<Video> mergeAndRankRovRecall(RankParam param) {
+    public List<Video> mergeAndRankRovRecall(RankParam param) {
         // TODO ab test
         // TODO 抽象成Strategy
         boolean hitTest = newRankSwitch
@@ -100,7 +95,7 @@ public class RankService {
         }
     }
 
-    private List<Video> mergeAndRankRovRecallOld(RankParam param) {
+    public List<Video> mergeAndRankRovRecallOld(RankParam param) {
         List<Video> rovRecallRank = new ArrayList<>();
         rovRecallRank.addAll(extractAndSort(param, RegionHRecallStrategy.PUSH_FORM));
         rovRecallRank.addAll(extractAndSort(param, RegionHDupRecallStrategy.PUSH_FORM));
@@ -182,7 +177,7 @@ public class RankService {
         return rovRecallRank;
     }
 
-    private void removeDuplicate(List<Video> rovRecallRank) {
+    public void removeDuplicate(List<Video> rovRecallRank) {
         if (CollectionUtils.isNotEmpty(rovRecallRank)) {
             Set<Long> videoIds = new HashSet<>();
             Iterator<Video> ite = rovRecallRank.iterator();
@@ -259,7 +254,7 @@ public class RankService {
         return scoreParam;
     }
 
-    private List<Video> mergeAndRankFlowPoolRecall(RankParam param) {
+    public List<Video> mergeAndRankFlowPoolRecall(RankParam param) {
         if (param.getAppType() == AppTypeEnum.LAO_HAO_KAN_VIDEO.getCode()
                 || param.getAppType() == AppTypeEnum.ZUI_JING_QI.getCode()) {
             if (param.getAbCode().equals("60054")
@@ -280,7 +275,7 @@ public class RankService {
         }
     }
 
-    private List<Video> extractAndSort(RankParam param, String pushFrom) {
+    public List<Video> extractAndSort(RankParam param, String pushFrom) {
         if (param == null
                 || param.getRecallResult() == null
                 || CollectionUtils.isEmpty(param.getRecallResult().getData())) {
@@ -299,7 +294,7 @@ public class RankService {
         return Collections.emptyList();
     }
 
-    private double getFlowPoolP(RankParam param) {
+    public double getFlowPoolP(RankParam param) {
         if (param.getAppType() == AppTypeEnum.LAO_HAO_KAN_VIDEO.getCode()
                 || param.getAppType() == AppTypeEnum.ZUI_JING_QI.getCode()) {
             return param.getFlowPoolP();
@@ -314,7 +309,7 @@ public class RankService {
         }
     }
 
-    private void removeDuplicate(RankParam param, List<Video> rovRecallRank, List<Video> flowPoolRank) {
+    public void removeDuplicate(RankParam param, List<Video> rovRecallRank, List<Video> flowPoolRank) {
         // TODO 重构 rov和流量池 融合排序
         //    去重原则:
         //        如果视频在ROV召回池topK,则保留ROV召回池,否则保留流量池
@@ -346,7 +341,7 @@ public class RankService {
         }
     }
 
-    private RankResult mergeAndSort(RankParam param, List<Video> rovRecallRank, List<Video> flowPoolRank) {
+    public RankResult mergeAndSort(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()));
@@ -394,120 +389,6 @@ public class RankService {
         return new RankResult(result);
     }
 
-    private RankResult mergeAndSort4Density(RankParam param, List<Video> rovRecallRank, List<Video> flowPoolRank) {
-        // 测试,添加数据
-//        rovRecallRank.add(0, getTestVideo(1070462L, ""));
-//        rovRecallRank.add(0, getTestVideo(1085062L, ""));
-//        rovRecallRank.add(0, getTestVideo(1102552L, ""));
-//        rovRecallRank.add(0, getTestVideo(1115929L, ""));
-//
-//        flowPoolRank = new ArrayList<>();
-//        flowPoolRank.add(getTestVideo(1263931L, "flow"));
-//        flowPoolRank.add(getTestVideo(1284797L, "flow"));
-//        flowPoolRank.add(getTestVideo(1289001L, "flow"));
-//        flowPoolRank.add(getTestVideo(1331503L, "flow"));
-
-
-        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;
-                }
-                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);
-                }
-
-            }
-        }
-        // 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());
-        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,
-                rovRecallRankNew, flowPoolRankNew, densityRules);
-        return new RankResult(resultWithDnsity);
-    }
 
-//    public Video getTestVideo(Long id, String s){
-//        Video a1 = new Video();
-//        a1.setVideoId(id);
-//        a1.setFlowPool(s);
-//        return a1;
-//    }
 
 }

+ 80 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/OfflineVlogFeatureGroup.java

@@ -0,0 +1,80 @@
+package com.tzld.piaoquan.recommend.server.service.rank.strategy;
+
+public enum OfflineVlogFeatureGroup {
+
+    machineinfo_brand,
+    machineinfo_model,
+    machineinfo_platform,
+    machineinfo_system,
+    u_1day_exp_cnt,
+    u_1day_click_cnt,
+    u_1day_share_cnt,
+    u_1day_return_cnt,
+    u_ctr_1day,
+    u_str_1day,
+    u_rov_1day,
+    u_ros_1day,
+
+    u_3day_exp_cnt,
+    u_3day_click_cnt,
+    u_3day_share_cnt,
+    u_3day_return_cnt,
+    u_ctr_3day,
+    u_str_3day,
+    u_rov_3day,
+    u_ros_3day,
+
+
+    total_time,
+
+    play_count_total,
+    i_1day_exp_cnt,
+    i_1day_click_cnt,
+    i_1day_share_cnt,
+    i_1day_return_cnt,
+    i_ctr_1day,
+    i_str_1day,
+    i_rov_1day,
+    i_ros_1day,
+
+    i_3day_exp_cnt,
+    i_3day_click_cnt,
+    i_3day_share_cnt,
+    i_3day_return_cnt,
+    i_ctr_3day,
+    i_str_3day,
+    i_rov_3day,
+    i_ros_3day,
+
+    ctx_week,
+    ctx_hour,
+    ctx_region,
+    ctx_city,
+    ;
+
+
+    private final byte[] idBytes;
+    private final byte[] nameBytes;
+
+    OfflineVlogFeatureGroup() {
+        this.idBytes = String.valueOf(ordinal()).getBytes();
+        this.nameBytes = name().toLowerCase().getBytes();
+    }
+
+    public final int getId() {
+        return ordinal();
+    }
+
+    public final String getGroupName() {
+        return name().toLowerCase();
+    }
+
+    public final byte[] getGroupNameBytes() {
+        return getGroupName().getBytes();
+    }
+
+    public final byte[] getIdBytes() {
+        return idBytes;
+    }
+
+}

+ 92 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/OfflineVlogShareLRFeatureExtractor.java

@@ -0,0 +1,92 @@
+package com.tzld.piaoquan.recommend.server.service.rank.strategy;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
+import com.tzld.piaoquan.recommend.feature.domain.video.feature.BytesGroup;
+import com.tzld.piaoquan.recommend.feature.domain.video.feature.BytesUtils;
+import com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature;
+import com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup;
+import com.tzld.piaoquan.recommend.feature.model.sample.LRSamples;
+import java.util.Map;
+import java.util.*;
+import com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature;
+
+public class OfflineVlogShareLRFeatureExtractor {
+
+    public ListMultimap<FeatureGroup, BaseFeature> featureMap = ArrayListMultimap.create();
+
+    final private BytesUtils utils;
+    final private int groupCount = OfflineVlogFeatureGroup.values().length;
+    public OfflineVlogShareLRFeatureExtractor() {
+        BytesGroup[] groups = new BytesGroup[OfflineVlogFeatureGroup.values().length];
+        OfflineVlogFeatureGroup[] var2 = OfflineVlogFeatureGroup.values();
+        int var3 = var2.length;
+
+        for(int var4 = 0; var4 < var3; ++var4) {
+            OfflineVlogFeatureGroup g = var2[var4];
+            groups[g.ordinal()] = new BytesGroup(g.ordinal(), g.getGroupName(), g.getGroupNameBytes());
+        }
+        this.utils = new BytesUtils(groups);
+    }
+    public void makeFeature(Map<String, Object> maps){
+        for (Map.Entry<String, Object> entry : maps.entrySet()){
+            OfflineVlogFeatureGroup ovf = OfflineVlogFeatureGroup.valueOf(entry.getKey());
+            Object value = entry.getValue();
+            if (value instanceof String){
+                this.makeFea(ovf, ((String)value).getBytes());
+            }else if (value instanceof Double){
+                this.makeFea(ovf, String.valueOf((Double)value).getBytes());
+            }else if (value instanceof Integer){
+                //todo
+            }else{
+                //todo
+                this.makeFea(ovf, ((String)value).getBytes());
+            }
+        }
+    }
+
+    private FeatureGroup makeGroup(OfflineVlogFeatureGroup group) {
+        FeatureGroup.Builder g = FeatureGroup.newBuilder();
+        g.setType("1");
+        g.setName(group.getGroupName());
+        g.setId(group.ordinal());
+        return g.build();
+    }
+    void makeFea(OfflineVlogFeatureGroup group, byte[] value) {
+        FeatureGroup featureGroup = this.makeGroup(group);
+        BaseFeature feature = this.utils.makeFea(group.ordinal(), value);
+        this.featureMap.put(featureGroup, feature);
+    }
+
+    public synchronized LRSamples single(Map<String, byte[]> userBytesFeature,
+                                         Map<String, byte[]> videoBytesFeature,
+                                         Map<String, byte[]> sceneFeatureMapByte) {
+        featureMap.clear();
+        // extract features todo zhangbo
+        for (Map.Entry<String, byte[]> entry : userBytesFeature.entrySet()){
+            makeFea(OfflineVlogFeatureGroup.valueOf(entry.getKey()), entry.getValue());
+        }
+        for (Map.Entry<String, byte[]> entry : videoBytesFeature.entrySet()){
+            makeFea(OfflineVlogFeatureGroup.valueOf(entry.getKey()), entry.getValue());
+        }
+        for (Map.Entry<String, byte[]> entry : sceneFeatureMapByte.entrySet()){
+            makeFea(OfflineVlogFeatureGroup.valueOf(entry.getKey()), entry.getValue());
+        }
+
+        LRSamples.Builder lr = LRSamples.newBuilder();
+        lr.setGroupNum(groupCount);
+        List<FeatureGroup> keys = new ArrayList<>(featureMap.keySet());
+        int count = 0;
+        for(FeatureGroup group : keys) {
+            List<BaseFeature> fea = featureMap.get(group);
+            GroupedFeature.Builder gf = GroupedFeature.newBuilder();
+            gf.setGroup(group);
+            gf.setCount(fea.size());
+            gf.addAllFeatures(fea);
+            count += fea.size();
+            lr.addFeatures(gf);
+        }
+        lr.setCount(count);
+        return lr.build();
+    }
+}

+ 149 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4Density.java

@@ -0,0 +1,149 @@
+package com.tzld.piaoquan.recommend.server.service.rank.strategy;
+
+
+import com.alibaba.fastjson.JSONObject;
+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.RankProcessorDensity;
+import com.tzld.piaoquan.recommend.server.service.recall.RecallResult;
+import com.tzld.piaoquan.recommend.server.service.recall.strategy.SpecialRecallStrategy;
+import com.tzld.piaoquan.recommend.server.util.JSONUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.RandomUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author zhangbo
+ * @desc 带密度控制的后处理 排序实验
+ */
+@Service
+@Slf4j
+public class RankStrategy4Density extends RankService {
+
+    public RankResult mergeAndSort(RankParam param, List<Video> rovRecallRank, List<Video> flowPoolRank) {
+        // 测试,添加数据
+//        rovRecallRank.add(0, getTestVideo(1070462L, ""));
+//        rovRecallRank.add(0, getTestVideo(1085062L, ""));
+//        rovRecallRank.add(0, getTestVideo(1102552L, ""));
+//        rovRecallRank.add(0, getTestVideo(1115929L, ""));
+//
+//        flowPoolRank = new ArrayList<>();
+//        flowPoolRank.add(getTestVideo(1263931L, "flow"));
+//        flowPoolRank.add(getTestVideo(1284797L, "flow"));
+//        flowPoolRank.add(getTestVideo(1289001L, "flow"));
+//        flowPoolRank.add(getTestVideo(1331503L, "flow"));
+
+
+        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;
+                }
+                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);
+                }
+
+            }
+        }
+        // 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());
+        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,
+                rovRecallRankNew, flowPoolRankNew, densityRules);
+        return new RankResult(resultWithDnsity);
+    }
+
+//    public Video getTestVideo(Long id, String s){
+//        Video a1 = new Video();
+//        a1.setVideoId(id);
+//        a1.setFlowPool(s);
+//        return a1;
+//    }
+
+
+
+}

+ 204 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RankModel.java

@@ -0,0 +1,204 @@
+package com.tzld.piaoquan.recommend.server.service.rank.strategy;
+
+
+import com.google.common.reflect.TypeToken;
+import com.tzld.piaoquan.recommend.server.common.base.RankItem;
+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.RankService;
+import com.tzld.piaoquan.recommend.server.service.recall.strategy.*;
+import com.tzld.piaoquan.recommend.server.service.score.ScorerUtils;
+import com.tzld.piaoquan.recommend.server.util.CommonCollectionUtils;
+import com.tzld.piaoquan.recommend.server.util.JSONUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
+import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author zhangbo
+ * @desc 模型的排序实验
+ */
+@Service
+@Slf4j
+public class RankStrategy4RankModel extends RankService {
+
+    @Value("${video.model.weight:}")
+    private Double mergeWeight;
+    final private String CLASS_NAME = this.getClass().getSimpleName();
+    @Override
+    public List<Video> mergeAndRankRovRecall(RankParam param) {
+
+        //-------------------地域内部融合-------------------
+        List<Video> rovRecallRank = new ArrayList<>();
+        rovRecallRank.addAll(extractAndSort(param, RegionHRecallStrategy.PUSH_FORM));
+        rovRecallRank.addAll(extractAndSort(param, RegionHDupRecallStrategy.PUSH_FORM));
+        rovRecallRank.addAll(extractAndSort(param, Region24HRecallStrategy.PUSH_FORM));
+        rovRecallRank.addAll(extractAndSort(param, RegionRelative24HRecallStrategy.PUSH_FORM));
+        rovRecallRank.addAll(extractAndSort(param, RegionRelative24HDupRecallStrategy.PUSH_FORM));
+
+        removeDuplicate(rovRecallRank);
+        rovRecallRank = rovRecallRank.size() <= param.getSize()
+                ? rovRecallRank
+                : rovRecallRank.subList(0, param.getSize());
+
+        //-------------------地域 sim returnv2 融合-------------------
+        rovRecallRank.addAll(extractAndSort(param, SimHotVideoRecallStrategy.PUSH_FORM));
+        rovRecallRank.addAll(extractAndSort(param, ReturnVideoRecallStrategy.PUSH_FORM));
+        removeDuplicate(rovRecallRank);
+
+        //-------------------排-------------------
+        //-------------------序-------------------
+        //-------------------逻-------------------
+        //-------------------辑-------------------
+        List<String> videoIdKeys = rovRecallRank.stream()
+                .map(t -> param.getRankKeyPrefix() + t.getVideoId())
+                .collect(Collectors.toList());
+        List<String> videoScores = this.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()));
+        }
+
+        //------------------- todo zhangbo 增加排序str模型逻辑 合并二者得分-------------------
+        List<Video> videosWithModel = model(rovRecallRank, param);
+        for (Video v : videosWithModel){
+            double mergeWeightIn = this.mergeWeight == null? 0.0D: this.mergeWeight;
+            v.setSortScore(v.getSortScore() + mergeWeightIn * v.getModelScore());
+        }
+        Collections.sort(videosWithModel, Comparator.comparingDouble(o -> -o.getSortScore()));
+        return videosWithModel;
+    }
+
+    public List<Video> model(List<Video> videos, RankParam param){
+        if (videos.isEmpty()){
+            return videos;
+        }
+
+        RedisStandaloneConfiguration redisSC = new RedisStandaloneConfiguration();
+        redisSC.setPort(6379);
+        redisSC.setPassword("Wqsd@2019");
+        redisSC.setHostName("r-bp1pi8wyv6lzvgjy5z.redis.rds.aliyuncs.com");
+        RedisConnectionFactory connectionFactory = new JedisConnectionFactory(redisSC);
+        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(connectionFactory);
+        redisTemplate.setDefaultSerializer(new StringRedisSerializer());
+        redisTemplate.afterPropertiesSet();
+
+        Map<String, String> userFeatureMap = new HashMap<>();
+        if (param.getMid() != null && !param.getMid().isEmpty()){
+            String midKey = "user_info_4video_" + param.getMid();
+            String userFeatureStr = redisTemplate.opsForValue().get(midKey);
+            if (userFeatureStr != null){
+                try{
+                    userFeatureMap = JSONUtils.fromJson(userFeatureStr,
+                            new TypeToken<Map<String, String>>() {},
+                            userFeatureMap);
+                }catch (Exception e){
+                    log.error(String.format("parse user json is wrong in {} with {}",
+                            this.CLASS_NAME, e));
+                }
+            }else{
+                return videos;
+            }
+        }
+        final Set<String> userFeatureSet = new HashSet<>(Arrays.asList(
+                "machineinfo_brand", "machineinfo_model", "machineinfo_platform", "machineinfo_system",
+                "u_1day_exp_cnt", "u_1day_click_cnt", "u_1day_share_cnt", "u_1day_return_cnt",
+                "u_ctr_1day","u_str_1day","u_rov_1day","u_ros_1day",
+                "u_3day_exp_cnt","u_3day_click_cnt","u_3day_share_cnt","u_3day_return_cnt",
+                "u_ctr_3day","u_str_3day","u_rov_3day","u_ros_3day"
+        ));
+        Iterator<Map.Entry<String, String>> iterator = userFeatureMap.entrySet().iterator();
+        while (iterator.hasNext()) {
+            Map.Entry<String, String> entry = iterator.next();
+            if (!userFeatureSet.contains(entry.getKey())) {
+                // 删除键值对
+                iterator.remove();
+            }
+        }
+
+        log.info("userFeature in model = {}", JSONUtils.toJson(userFeatureMap));
+
+        final Set<String> itemFeatureSet = new HashSet<>(Arrays.asList(
+                "total_time", "play_count_total",
+                "i_1day_exp_cnt", "i_1day_click_cnt", "i_1day_share_cnt", "i_1day_return_cnt",
+                "i_ctr_1day", "i_str_1day", "i_rov_1day", "i_ros_1day",
+                "i_3day_exp_cnt", "i_3day_click_cnt", "i_3day_share_cnt", "i_3day_return_cnt",
+                "i_ctr_3day", "i_str_3day", "i_rov_3day", "i_ros_3day"
+        ));
+
+        List<RankItem> rankItems = CommonCollectionUtils.toList(videos, RankItem::new);
+        List<Long> videoIds = CommonCollectionUtils.toListDistinct(videos, Video::getVideoId);
+        List<String> videoFeatureKeys = videoIds.stream().map(r-> "video_info_" + r)
+                .collect(Collectors.toList());
+        List<String> videoFeatures = redisTemplate.opsForValue().multiGet(videoFeatureKeys);
+        if (videoFeatures != null){
+            for (int i=0; i<videoFeatures.size(); ++i){
+                String vF = videoFeatures.get(i);
+                Map<String, String> vfMap = new HashMap<>();
+                if (vF == null){
+                    continue;
+                }
+                try{
+                    vfMap = JSONUtils.fromJson(vF, new TypeToken<Map<String, String>>() {}, vfMap);
+                    Iterator<Map.Entry<String, String>> iteratorIn = vfMap.entrySet().iterator();
+                    while (iteratorIn.hasNext()) {
+                        Map.Entry<String, String> entry = iteratorIn.next();
+                        if (!itemFeatureSet.contains(entry.getKey())) {
+                            // 删除键值对
+                            iteratorIn.remove();
+                        }
+                    }
+                    rankItems.get(i).setFeatureMap(vfMap);
+                }catch (Exception e){
+                    log.error(String.format("parse video json is wrong in {} with {}",
+                            this.CLASS_NAME, e));
+                }
+            }
+        }
+        log.info("ItemFeature = {}", JSONUtils.toJson(videoFeatures));
+
+        Map<String, String> sceneFeatureMap =  this.getSceneFeature(param);
+
+        List<RankItem> rovRecallScore = ScorerUtils.getScorerPipeline(ScorerUtils.BASE_CONF)
+                .scoring(sceneFeatureMap, userFeatureMap, rankItems);
+        log.info("mergeAndRankRovRecallNew rovRecallScore={}", JSONUtils.toJson(rovRecallScore));
+        return CommonCollectionUtils.toList(rovRecallScore, i -> {
+            // hard code 将排序分数 赋值给video的sortScore
+            Video v = i.getVideo();
+            v.setModelScore(i.getScore());
+            return v;
+        });
+    }
+
+    private Map<String, String> getSceneFeature(RankParam param) {
+        Map<String, String> sceneFeatureMap = new HashMap<>();
+        sceneFeatureMap.put("ctx_region", param.getProvince());
+        sceneFeatureMap.put("ctx_city", param.getCity());
+        Calendar calendar = Calendar.getInstance();
+
+        sceneFeatureMap.put("ctx_week", (calendar.get(Calendar.DAY_OF_WEEK) + 6) % 7 + "");
+        sceneFeatureMap.put("ctx_hour", new SimpleDateFormat("HH").format(calendar.getTime()));
+
+        return sceneFeatureMap;
+    }
+
+
+
+}

+ 5 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score/AbstractScorer.java

@@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.util.List;
+import java.util.Map;
 
 
 public abstract class AbstractScorer {
@@ -63,4 +64,8 @@ public abstract class AbstractScorer {
                                            final UserFeature userFeature,
                                            final List<RankItem> rankItems);
 
+    public abstract List<RankItem> scoring(final Map<String, String> sceneFeatureMap,
+                                           final Map<String, String> userFeatureMap,
+                                           final List<RankItem> rankItems);
+
 }

+ 76 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score/ScorerPipeline.java

@@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.*;
 
 
@@ -106,4 +107,79 @@ public class ScorerPipeline {
 
         return items;
     }
+
+    public List<RankItem> scoring(final Map<String, String> sceneFeatureMap,
+                                  final Map<String, String> userFeatureMap,
+                                  final List<RankItem> rankItems) {
+
+        if (CollectionUtils.isEmpty(scorers)) {
+            log.error("scorers is empty");
+            return rankItems;
+        }
+        List<RankItem> items = rankItems;
+
+        for (final AbstractScorer scorer : scorers) {
+            if (!scorer.isEnable()) {
+                continue;
+            }
+
+            final int beforeSize = rankItems.size();
+            final long startTime = System.currentTimeMillis();
+
+            String fullScorerName = scorer.getScorerConfigInfo().getScorerName();
+            String[] scorerNames = fullScorerName.split("\\.");
+            final String scorerName = scorerNames.length > 0 ? scorerNames[scorerNames.length - 1] : fullScorerName;
+
+            final List<RankItem> scoreRankerItems = items;
+            Callable<List<RankItem>> callable = () -> scorer.scoring(sceneFeatureMap, userFeatureMap, scoreRankerItems);
+
+            // execute score use thread to protected score worst time
+            List<RankItem> scoredItems = new ArrayList<RankItem>();
+            try {
+                List<Future<List<RankItem>>> futures = executorService.invokeAll(Arrays.asList(callable), SCORE_TIME_OUT, TimeUnit.MILLISECONDS);
+                for (Future<List<RankItem>> future : futures) {
+                    try {
+                        if (future.isDone() && !future.isCancelled() && future.get() != null) {
+                            scoredItems.addAll(future.get());
+                        } else {
+                            LOGGER.error("score task is cancelled, scorename [{}] fail items [{}]",
+                                    new Object[]{scorerName, scoreRankerItems.size()});
+                        }
+                    } catch (Exception e) {
+                        LOGGER.error("thread pool exception scorename [{}], exception [{}]",
+                                new Object[]{scorerName, ExceptionUtils.getFullStackTrace(e)});
+                    }
+                }
+            } catch (Exception e) {
+                LOGGER.error("thread pool exception uid [{}] scorename [{}], exception [{}]",
+                        new Object[]{scorerName, ExceptionUtils.getFullStackTrace(e)});
+            }
+
+            //  变更item
+            if (CollectionUtils.isNotEmpty(scoreRankerItems)) {
+                items = scoreRankerItems;
+            } else {
+                items = new ArrayList<>(items);
+            }
+
+            int position = 0;
+            for (RankItem item : items) {
+                item.getRankerIndex().put(scorerName, position++);
+                item.getRankerScore().put(scorerName, item.getScore());
+            }
+
+            //
+            long spentTime = System.currentTimeMillis() - startTime;
+            LOGGER.debug("after scorer [{}], spentTime [{}], before size [{}], remaining size [{}]",
+                    new Object[]{scorerName, spentTime, beforeSize, scoreRankerItems.size()});
+        }
+
+        int position = 0;
+        for (RankItem item : items) {
+            item.getRankerIndex().put("finalScore", position++);
+            item.getRankerScore().put("finalScore", item.getScore());
+        }
+
+        return items;
+    }
 }

+ 142 - 3
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score/VlogShareLRScorer.java

@@ -5,6 +5,7 @@ import com.tzld.piaoquan.recommend.feature.domain.video.base.*;
 import com.tzld.piaoquan.recommend.server.common.base.*;
 import com.tzld.piaoquan.recommend.feature.model.sample.*;
 import com.tzld.piaoquan.recommend.feature.domain.video.feature.VlogShareLRFeatureExtractor;
+import com.tzld.piaoquan.recommend.server.service.rank.strategy.OfflineVlogShareLRFeatureExtractor;
 import com.tzld.piaoquan.recommend.server.service.score.model.LRModel;
 
 import org.apache.commons.collections4.CollectionUtils;
@@ -12,9 +13,7 @@ import org.apache.commons.lang.exception.ExceptionUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
 import java.util.concurrent.*;
 
 
@@ -187,4 +186,144 @@ public class VlogShareLRScorer extends BaseLRModelScorer {
         }
         LOGGER.debug("Ctr Score {}, Total: {}, Cancel: {}", new Object[]{requestContext.getRequest_id(), items.size(), cancel});
     }
+    @Override
+    public List<RankItem> scoring(final Map<String, String> sceneFeatureMap,
+                                           final Map<String, String> userFeatureMap,
+                                           final List<RankItem> rankItems){
+        if (CollectionUtils.isEmpty(rankItems)) {
+            return rankItems;
+        }
+
+        long startTime = System.currentTimeMillis();
+        LRModel model = (LRModel) this.getModel();
+        LOGGER.debug("model size: [{}]", model.getModelSize());
+
+        List<RankItem> result = rankItems;
+        result = rankByJava(
+                sceneFeatureMap, userFeatureMap, rankItems
+        );
+
+        LOGGER.debug("ctr ranker time java items size={}, time={} ", result != null ? result.size() : 0,
+                System.currentTimeMillis() - startTime);
+
+        return result;
+    }
+
+    private List<RankItem> rankByJava(final Map<String, String> sceneFeatureMap,
+                                      final Map<String, String> userFeatureMap,
+                                      final List<RankItem> items) {
+        long startTime = System.currentTimeMillis();
+        LRModel model = (LRModel) this.getModel();
+        LOGGER.debug("model size: [{}]", model.getModelSize());
+        // userBytes
+        Map<String, byte[]> userFeatureMapByte = new HashMap<>();
+        for(Map.Entry<String, String> entry: userFeatureMap.entrySet()){
+            userFeatureMapByte.put(entry.getKey(), entry.getValue().getBytes());
+        }
+        //sceneBytes
+        Map<String, byte[]> sceneFeatureMapByte = new HashMap<>();
+        for(Map.Entry<String, String> entry: sceneFeatureMap.entrySet()){
+            sceneFeatureMapByte.put(entry.getKey(), entry.getValue().getBytes());
+        }
+
+        // 所有都参与打分,按照ctr排序
+        multipleCtrScore(items, userFeatureMapByte, sceneFeatureMapByte, model);
+
+        // debug log
+        if (LOGGER.isDebugEnabled()) {
+            for (int i = 0; i < items.size(); i++) {
+                LOGGER.debug("before enter feeds model predict ctr score [{}] [{}]", items.get(i), items.get(i));
+            }
+        }
+
+        Collections.sort(items);
+
+        LOGGER.debug("ctr ranker java execute time: [{}]", System.currentTimeMillis() - startTime);
+        LOGGER.debug("[ctr ranker time java] items size={}, cost={} ", items != null ? items.size() : 0,
+                System.currentTimeMillis() - startTime);
+        return items;
+    }
+
+    private void multipleCtrScore(final List<RankItem> items,
+                                  final Map<String, byte[]> userFeatureMapByte,
+                                  final Map<String, byte[]> sceneFeatureMapByte,
+                                  final LRModel model) {
+
+        List<Callable<Object>> calls = new ArrayList<Callable<Object>>();
+        for (int index = 0; index < items.size(); index++) {
+            final int fIndex = index;
+            items.get(fIndex).setScore(0.0);   //原始分为 cube中的粗打分,如果超时,为原始值存在问题, 需要置0
+            calls.add(new Callable<Object>() {
+                @Override
+                public Object call() throws Exception {
+                    try {
+                        calcScore(model, items.get(fIndex), userFeatureMapByte, sceneFeatureMapByte);
+                    } catch (Exception e) {
+                        LOGGER.error("ctr exception: [{}] [{}]", items.get(fIndex).videoId, ExceptionUtils.getFullStackTrace(e));
+                    }
+                    return new Object();
+                }
+            });
+        }
+
+        List<Future<Object>> futures = null;
+        try {
+            futures = executorService.invokeAll(calls, LOCAL_TIME_OUT, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            LOGGER.error("execute invoke fail: {}", ExceptionUtils.getFullStackTrace(e));
+        }
+
+        //等待所有请求的结果返回, 超时也返回
+        int cancel = 0;
+        if (futures != null) {
+            for (Future<Object> future : futures) {
+                try {
+                    if (!future.isDone() || future.isCancelled() || future.get() == null) {
+                        cancel++;
+                    }
+                } catch (InterruptedException e) {
+                    LOGGER.error("InterruptedException {},{}", ExceptionUtils.getFullStackTrace(e));
+                } catch (ExecutionException e) {
+                    LOGGER.error("ExecutionException {},{}", sceneFeatureMapByte.size(),
+                            ExceptionUtils.getFullStackTrace(e));
+                }
+            }
+        }
+        LOGGER.debug("Ctr Score {}, Total: {}, Cancel: {}", new Object[]{sceneFeatureMapByte.size(), items.size(), cancel});
+    }
+
+    public double calcScore(final LRModel lrModel,
+                            final RankItem item,
+                            final Map<String, byte[]> userFeatureMapByte,
+                            final Map<String, byte[]> sceneFeatureMapByte) {
+
+        LRSamples lrSamples = null;
+        OfflineVlogShareLRFeatureExtractor bytesFeatureExtractor;
+        bytesFeatureExtractor = new OfflineVlogShareLRFeatureExtractor();
+
+        try {
+
+            Map<String, byte[]> itemFeatureByte = new HashMap<>();
+            for (Map.Entry<String, String> entry: item.getFeatureMap().entrySet()){
+                itemFeatureByte.put(entry.getKey(), entry.getValue().getBytes());
+            }
+            lrSamples = bytesFeatureExtractor.single(userFeatureMapByte, itemFeatureByte, sceneFeatureMapByte);
+        } catch (Exception e) {
+            LOGGER.error("extract feature error for imei={}, doc={}, [{}]", new Object[]{"", item.getVideoId(),
+                    ExceptionUtils.getFullStackTrace(e)});
+        }
+
+
+        double pro = 0.0;
+        if (lrSamples != null && lrSamples.getFeaturesList() != null) {
+            try {
+                pro = lrModel.score(lrSamples);
+            } catch (Exception e) {
+                LOGGER.error("score error for doc={} exception={}", new Object[]{
+                        item.getVideoId(), ExceptionUtils.getFullStackTrace(e)});
+            }
+        }
+        item.setScore(pro);
+        return pro;
+    }
 }

+ 1 - 1
recommend-server-service/src/main/resources/feeds_score_config_baseline.conf

@@ -2,6 +2,6 @@ scorer-config = {
   related-score-config = {
     scorer-name = "com.tzld.piaoquan.recommend.server.service.score.VlogShareLRScorer"
     scorer-priority = 99
-    model-path = "model/model_new.txt"
+    model-path = "video_str_model/model_sharev2_20231220_change.txt"
   }
 }