| 
					
				 | 
			
			
				@@ -0,0 +1,176 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+package com.tzld.longarticle.recommend.server.service.recommend.rank.strategy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.tzld.longarticle.recommend.server.common.enums.aigc.PublishPlanInputSourceTypesEnum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.tzld.longarticle.recommend.server.common.enums.recommend.ScoreStrategyEnum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.tzld.longarticle.recommend.server.model.dto.Content; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.tzld.longarticle.recommend.server.model.entity.crawler.Article; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.tzld.longarticle.recommend.server.repository.crawler.ArticleRepository; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.tzld.longarticle.recommend.server.service.recommend.config.AccountContentPoolConfigService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.tzld.longarticle.recommend.server.service.recommend.config.StrategyIndexScoreWeightService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.tzld.longarticle.recommend.server.service.recommend.rank.*; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.tzld.longarticle.recommend.server.service.recommend.score.AccountIndexReplacePoolConfig; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.tzld.longarticle.recommend.server.service.recommend.score.ScoreResult; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.tzld.longarticle.recommend.server.service.recommend.score.ScoreService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.tzld.longarticle.recommend.server.util.CommonCollectionUtils; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import lombok.extern.slf4j.Slf4j; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.apache.commons.collections4.CollectionUtils; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.apache.commons.lang3.RandomUtils; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.beans.factory.annotation.Autowired; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.beans.factory.annotation.Value; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.stereotype.Service; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.*; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.stream.Collectors; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Slf4j 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+public class RankV19Strategy implements RankStrategy { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Autowired 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private ScoreService scoreService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Autowired 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private RankService rankService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Autowired 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private AccountContentPoolConfigService accountContentPoolConfigService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Autowired 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private ArticleRepository articleRepository; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Autowired 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private StrategyIndexScoreWeightService weightService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @ApolloJsonValue("${touliu.account.ghIds:[\"gh_93e00e187787\", \"gh_ac43e43b253b\", \"gh_68e7fdc09fe4\",\"gh_77f36c109fb1\", \"gh_b181786a6c8c\", \"gh_1ee2e1b39ccf\"]}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private List<String> touliuAccountGhIds; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Value("${topProducePlanId:}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private String topProducePlanId; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public RankResult rank(RankParam param) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        List<Content> result = new ArrayList<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ScoreResult scoreResult = scoreService.score(RankStrategy.convertToScoreParam(param)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Map<String, Map<String, Double>> scoreMap = scoreResult.getScoreMap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        String[] contentPools = accountContentPoolConfigService.getContentPools(param.getAccountName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Map<Integer, AccountIndexReplacePoolConfig> indexReplacePoolConfigMap = accountContentPoolConfigService.getContentReplacePools(param.getAccountName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        List<RankItem> items = CommonCollectionUtils.toList(param.getContents(), c -> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            RankItem item = new RankItem(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            item.setContent(c); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            c.setScoreMap(scoreMap.get(c.getId())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            item.setScoreMap(scoreMap.get(c.getId())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            double score; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int index = weightService.getIndex(item.getContent().getContentPoolType(), contentPools); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (contentPools[0].equals(item.getContent().getContentPoolType()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    || contentPools[1].equals(item.getContent().getContentPoolType())) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                score = item.getScore(ScoreStrategyEnum.SIMILARITY.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        * weightService.getWeight(param.getStrategy(), param.getGhId(), index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        ScoreStrategyEnum.SIMILARITY.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        + item.getScore(ScoreStrategyEnum.CATEGORY.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        * weightService.getWeight(param.getStrategy(), param.getGhId(), index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        ScoreStrategyEnum.CATEGORY.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        + item.getScore(ScoreStrategyEnum.HIS_FISSION_OPEN_RATE.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        * weightService.getWeight(param.getStrategy(), param.getGhId(), index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        ScoreStrategyEnum.HIS_FISSION_OPEN_RATE.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        + item.getScore(ScoreStrategyEnum.FLOW_CTL_DECREASE.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        + item.getScore(ScoreStrategyEnum.CRAWLER_DAYS_DECREASE_STRATEGY.value()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (item.getScore(ScoreStrategyEnum.PUBLISH_TIMES.value()) >= 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    score += item.getScore(ScoreStrategyEnum.VIEW_COUNT_RATE.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            * weightService.getWeight(param.getStrategy(), param.getGhId(), index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            ScoreStrategyEnum.VIEW_COUNT_RATE.value()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                score = item.getScore(ScoreStrategyEnum.SIMILARITY.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        * weightService.getWeight(param.getStrategy(), param.getGhId(), index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        ScoreStrategyEnum.SIMILARITY.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        + item.getScore(ScoreStrategyEnum.CATEGORY.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        * weightService.getWeight(param.getStrategy(), param.getGhId(), index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        ScoreStrategyEnum.CATEGORY.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        + item.getScore(ScoreStrategyEnum.ACCOUNT_PRE_DISTRIBUTE.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        + item.getScore(ScoreStrategyEnum.PUBLISH_TIMES.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        + item.getScore(ScoreStrategyEnum.CRAWLER_DAYS_DECREASE_STRATEGY.value()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        + item.getScore(ScoreStrategyEnum.FLOW_CTL_DECREASE.value()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            c.setScore(score); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            item.setScore(score); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return item; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 相似度评分为0 报警返回 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        List<Article> hisPublishFirstArticleList = articleRepository.getByGhIdAndItemIndexAndTypeEqualsAndStatusEquals( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                param.getGhId(), 1, param.getType(), 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (RankStrategy.SimilarityScoreZero(items, param, hisPublishFirstArticleList)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return new RankResult(result); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 安全分降权 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        RankService.safeScoreDecrease(items); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 1 排序 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Collections.sort(items, (o1, o2) -> -Double.compare(o1.getScore(), o2.getScore())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 2 相似去重 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        List<Content> contents = CommonCollectionUtils.toList(items, RankItem::getContent); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 3 文章按照内容池分组 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Map<String, List<Content>> contentMap = new HashMap<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (Content c : contents) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            List<Content> data = contentMap.computeIfAbsent(c.getContentPoolType(), k -> new ArrayList<>()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            data.add(c); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 4 选文章 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        String[] publishPool = Arrays.copyOf(contentPools, contentPools.length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 头 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        List<Content> pool1 = contentMap.get(contentPools[0]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (CollectionUtils.isNotEmpty(pool1)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            pool1 = RankService.contentSourceTypeFilter(param.getStrategy(), pool1, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        RankService.printSortLog(param.getStrategy(), param.getAccountName(), "头条", pool1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (CollectionUtils.isNotEmpty(pool1)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (topProducePlanId.equals(pool1.get(0).getProducePlanId())) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                int i = RandomUtils.nextInt(0, 2); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (i == 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    for (Content content : pool1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (!topProducePlanId.equals(content.getProducePlanId())) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            result.add(content); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (CollectionUtils.isEmpty(result)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                result.add(pool1.get(0)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            RankStrategy.sendFeishuFirstPoolEmpty(param, contentPools[0]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return new RankResult(result); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 次 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        RankService.commonAddSecondContent(param, result, publishPool, contentPools, contentMap, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                indexReplacePoolConfigMap, param.getStrategy()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 3-8 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // RankService.commonAdd38Content(param, result, contentPools, contentMap, param.getStrategy()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        List<Content> pool = contentMap.get(contentPools[2]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        RankService.printSortLog(param.getStrategy(), param.getAccountName(), "3-8", pool); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (CollectionUtils.isNotEmpty(pool)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Integer videoSourceType = PublishPlanInputSourceTypesEnum.longArticleVideoPoolSource.getVal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Queue<Content> videoPoolQueue = pool.stream().filter(o -> Objects.equals(o.getSourceType(), videoSourceType)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .collect(Collectors.toCollection(LinkedList::new)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Queue<Content> otherPoolQueue = pool.stream().filter(o -> !Objects.equals(o.getSourceType(), videoSourceType)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .collect(Collectors.toCollection(LinkedList::new)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (int i = 3; i < param.getSize() + 1; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Integer sourceType = RankService.getStrategyPoolSourceType(param.getStrategy(), i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (Objects.equals(sourceType, videoSourceType) && !videoPoolQueue.isEmpty()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    result.add(videoPoolQueue.poll()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } else if (!otherPoolQueue.isEmpty()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    result.add(otherPoolQueue.poll()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        rankService.checkPublishContentStatus(result, contentMap, publishPool); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        RankStrategy.deduplication(result, contentMap, publishPool); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return new RankResult(result); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |