wangyunpeng 9 mesi fa
parent
commit
80a80e956d

+ 1 - 0
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/common/enums/RankStrategyEnum.java

@@ -16,6 +16,7 @@ public enum RankStrategyEnum {
     ArticleRankV9("ArticleRankV9", "ArticleRankV9", "rankV9Strategy"),
     ArticleRankV10("ArticleRankV10", "ArticleRankV10", "rankV10Strategy"),
     ArticleRankV11("ArticleRankV11", "ArticleRankV11", "rankV9Strategy"),
+    ArticleRankV12("ArticleRankV12", "ArticleRankV12", "rankV12Strategy"),
 
     default_strategy("ArticleRankV1", "默认策略", "defaultRankStrategy"),
     ;

+ 1 - 0
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/model/Content.java

@@ -39,6 +39,7 @@ public class Content {
     private Double t0FissionByReadAvgCorrelationMean;
     private Double t0FissionByFansSumAvg;
     private Double t0FissionByReadAvgSumAvg;
+    private Double t0FissionDeWeightByReadAvgSumAvg;
 
     private Map<String, Double> scoreMap;
     private double score;

+ 2 - 0
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/repository/crawler/AccountAvgInfoRepository.java

@@ -18,6 +18,8 @@ public interface AccountAvgInfoRepository extends JpaRepository<AccountAvgInfo,
 
     List<AccountAvgInfo> getAllByStatusEquals(Integer status);
 
+    List<AccountAvgInfo> getAllByUpdateTime(String updateTime);
+
     List<AccountAvgInfo> getAllByUpdateTimeGreaterThanEqual(String updateTime);
 
     List<AccountAvgInfo> getAllByUpdateTimeLessThanEqual(String updateTime);

+ 150 - 0
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/service/rank/strategy/RankV11Strategy.java

@@ -0,0 +1,150 @@
+package com.tzld.longarticle.recommend.server.service.rank.strategy;
+
+
+import com.tzld.longarticle.recommend.server.model.Content;
+import com.tzld.longarticle.recommend.server.service.AccountContentPoolConfigService;
+import com.tzld.longarticle.recommend.server.service.rank.RankItem;
+import com.tzld.longarticle.recommend.server.service.rank.RankParam;
+import com.tzld.longarticle.recommend.server.service.rank.RankResult;
+import com.tzld.longarticle.recommend.server.service.rank.RankStrategy;
+import com.tzld.longarticle.recommend.server.service.score.AccountIndexReplacePoolConfig;
+import com.tzld.longarticle.recommend.server.service.score.ScoreResult;
+import com.tzld.longarticle.recommend.server.service.score.ScoreService;
+import com.tzld.longarticle.recommend.server.service.score.strategy.*;
+import com.tzld.longarticle.recommend.server.util.CommonCollectionUtils;
+import com.tzld.longarticle.recommend.server.util.feishu.FeishuMessageSender;
+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.stereotype.Service;
+
+import java.util.*;
+
+/**
+ * @author dyp
+ */
+@Service
+@Slf4j
+public class RankV11Strategy implements RankStrategy {
+
+    @Autowired
+    private ScoreService scoreService;
+    @Autowired
+    private AccountContentPoolConfigService accountContentPoolConfigService;
+
+    public RankResult rank(RankParam param) {
+        List<Content> result = new ArrayList<>();
+        //log.info("RankParam {}", JSONUtils.toJson(param));
+        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;
+            if (contentPools[0].equals(item.getContent().getContentPoolType())) {
+                score = item.getScore(HisFissionAvgReadRateRateStrategy.class.getSimpleName());
+                score += item.getScore(SimilarityStrategy.class.getSimpleName());
+            } else if (contentPools[1].equals(item.getContent().getContentPoolType())) {
+                score = item.getScore(SimilarityStrategy.class.getSimpleName())
+                        + item.getScore(CategoryStrategy.class.getSimpleName())
+                        + item.getScore(FlowCtlDecreaseStrategy.class.getSimpleName());
+                if (item.getScore(PublishTimesStrategy.class.getSimpleName()) >= 0) {
+                    score += item.getScore(ViewCountRateStrategy.class.getSimpleName());
+                }
+            } else {
+                score = item.getScore(SimilarityStrategy.class.getSimpleName())
+                        + item.getScore(CategoryStrategy.class.getSimpleName())
+                        + item.getScore(AccountPreDistributeStrategy.class.getSimpleName())
+                        + item.getScore(PublishTimesStrategy.class.getSimpleName())
+                        + item.getScore(FlowCtlDecreaseStrategy.class.getSimpleName());
+            }
+            c.setScore(score);
+            item.setScore(score);
+            return item;
+        });
+        // 相似度评分为0 报警返回
+        if (CollectionUtils.isNotEmpty(items) && items.get(0).getScoreMap().get(SimilarityStrategy.class.getSimpleName()) == 0) {
+            FeishuMessageSender.sendWebHookMessage("07026a9f-43f5-448b-ba40-a8d71bd6e634",
+                    "内容评分为0\n"
+                            + "ghId: " + param.getGhId() + "\n"
+                            + "账号名称: " + param.getAccountName() + "\n"
+                            + "策略: " + this.getClass().getSimpleName());
+            return new RankResult(result);
+        }
+
+        // 1 排序
+        Collections.sort(items, (o1, o2) -> -Double.compare(o1.getScore(), o2.getScore()));
+        // 2 相似去重
+        List<Content> contents = CommonCollectionUtils.toList(items, RankItem::getContent);
+//        contents = deduplication(contents);
+
+        // 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)) {
+            result.add(pool1.get(0));
+        } else {
+            FeishuMessageSender.sendWebHookMessage("07026a9f-43f5-448b-ba40-a8d71bd6e634",
+                    "内容池1为空\n"
+                            + "ghId: " + param.getGhId() + "\n"
+                            + "账号名称: " + param.getAccountName() + "\n"
+                            + "内容池: " + contentPools[0] + "\n"
+                            + "策略: " + this.getClass().getSimpleName());
+            return new RankResult(result);
+        }
+        // 次
+        List<Content> pool2 = contentMap.get(contentPools[1]);
+        if (CollectionUtils.isNotEmpty(pool2)) {
+            int i = RandomUtils.nextInt(0, Math.min(pool2.size(), 5));
+            int j = RandomUtils.nextInt(0, Math.min(pool2.size(), 5));
+            result.add(pool2.get(i));
+            // 替补 头条内容不足使用次条内容
+            if (result.size() == 1 && pool2.size() > 1) {
+                while (i == j && pool2.size() > 1) {
+                    j = RandomUtils.nextInt(0, Math.min(pool2.size(), 5));
+                    if (i != j) {
+                        publishPool[0] = contentPools[1];
+                        result.add(pool2.get(1));
+                        break;
+                    }
+                }
+            }
+        } else {
+            // 替补 根据设置替补内容池查找内容尽心替补
+            AccountIndexReplacePoolConfig replacePoolConfig = indexReplacePoolConfigMap.get(2);
+            if (Objects.nonNull(replacePoolConfig)) {
+                List<Content> pool2Replace = contentMap.get(replacePoolConfig.getContentPool());
+                if (CollectionUtils.isNotEmpty(pool2Replace)) {
+                    publishPool[1] = replacePoolConfig.getContentPool();
+                    result.add(pool2Replace.get(0));
+                }
+            }
+        }
+
+        // 3-8
+        List<Content> pool = contentMap.get(contentPools[2]);
+        if (CollectionUtils.isNotEmpty(pool) && param.getSize() > result.size()) {
+            result.addAll(pool.subList(0, Math.min(pool.size(), param.getSize() - result.size())));
+        }
+
+        RankStrategy.deduplication(result, contentMap, publishPool);
+
+        return new RankResult(result);
+    }
+
+}

+ 150 - 0
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/service/rank/strategy/RankV12Strategy.java

@@ -0,0 +1,150 @@
+package com.tzld.longarticle.recommend.server.service.rank.strategy;
+
+
+import com.tzld.longarticle.recommend.server.model.Content;
+import com.tzld.longarticle.recommend.server.service.AccountContentPoolConfigService;
+import com.tzld.longarticle.recommend.server.service.rank.RankItem;
+import com.tzld.longarticle.recommend.server.service.rank.RankParam;
+import com.tzld.longarticle.recommend.server.service.rank.RankResult;
+import com.tzld.longarticle.recommend.server.service.rank.RankStrategy;
+import com.tzld.longarticle.recommend.server.service.score.AccountIndexReplacePoolConfig;
+import com.tzld.longarticle.recommend.server.service.score.ScoreResult;
+import com.tzld.longarticle.recommend.server.service.score.ScoreService;
+import com.tzld.longarticle.recommend.server.service.score.strategy.*;
+import com.tzld.longarticle.recommend.server.util.CommonCollectionUtils;
+import com.tzld.longarticle.recommend.server.util.feishu.FeishuMessageSender;
+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.stereotype.Service;
+
+import java.util.*;
+
+/**
+ * @author dyp
+ */
+@Service
+@Slf4j
+public class RankV12Strategy implements RankStrategy {
+
+    @Autowired
+    private ScoreService scoreService;
+    @Autowired
+    private AccountContentPoolConfigService accountContentPoolConfigService;
+
+    public RankResult rank(RankParam param) {
+        List<Content> result = new ArrayList<>();
+        //log.info("RankParam {}", JSONUtils.toJson(param));
+        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;
+            if (contentPools[0].equals(item.getContent().getContentPoolType())) {
+                score = item.getScore(HisFissionDeWeightAvgReadSumRateStrategy.class.getSimpleName());
+                score += item.getScore(SimilarityStrategy.class.getSimpleName());
+            } else if (contentPools[1].equals(item.getContent().getContentPoolType())) {
+                score = item.getScore(SimilarityStrategy.class.getSimpleName())
+                        + item.getScore(CategoryStrategy.class.getSimpleName())
+                        + item.getScore(FlowCtlDecreaseStrategy.class.getSimpleName());
+                if (item.getScore(PublishTimesStrategy.class.getSimpleName()) >= 0) {
+                    score += item.getScore(ViewCountRateStrategy.class.getSimpleName());
+                }
+            } else {
+                score = item.getScore(SimilarityStrategy.class.getSimpleName())
+                        + item.getScore(CategoryStrategy.class.getSimpleName())
+                        + item.getScore(AccountPreDistributeStrategy.class.getSimpleName())
+                        + item.getScore(PublishTimesStrategy.class.getSimpleName())
+                        + item.getScore(FlowCtlDecreaseStrategy.class.getSimpleName());
+            }
+            c.setScore(score);
+            item.setScore(score);
+            return item;
+        });
+        // 相似度评分为0 报警返回
+        if (CollectionUtils.isNotEmpty(items) && items.get(0).getScoreMap().get(SimilarityStrategy.class.getSimpleName()) == 0) {
+            FeishuMessageSender.sendWebHookMessage("07026a9f-43f5-448b-ba40-a8d71bd6e634",
+                    "内容评分为0\n"
+                            + "ghId: " + param.getGhId() + "\n"
+                            + "账号名称: " + param.getAccountName() + "\n"
+                            + "策略: " + this.getClass().getSimpleName());
+            return new RankResult(result);
+        }
+
+        // 1 排序
+        Collections.sort(items, (o1, o2) -> -Double.compare(o1.getScore(), o2.getScore()));
+        // 2 相似去重
+        List<Content> contents = CommonCollectionUtils.toList(items, RankItem::getContent);
+//        contents = deduplication(contents);
+
+        // 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)) {
+            result.add(pool1.get(0));
+        } else {
+            FeishuMessageSender.sendWebHookMessage("07026a9f-43f5-448b-ba40-a8d71bd6e634",
+                    "内容池1为空\n"
+                            + "ghId: " + param.getGhId() + "\n"
+                            + "账号名称: " + param.getAccountName() + "\n"
+                            + "内容池: " + contentPools[0] + "\n"
+                            + "策略: " + this.getClass().getSimpleName());
+            return new RankResult(result);
+        }
+        // 次
+        List<Content> pool2 = contentMap.get(contentPools[1]);
+        if (CollectionUtils.isNotEmpty(pool2)) {
+            int i = RandomUtils.nextInt(0, Math.min(pool2.size(), 5));
+            int j = RandomUtils.nextInt(0, Math.min(pool2.size(), 5));
+            result.add(pool2.get(i));
+            // 替补 头条内容不足使用次条内容
+            if (result.size() == 1 && pool2.size() > 1) {
+                while (i == j && pool2.size() > 1) {
+                    j = RandomUtils.nextInt(0, Math.min(pool2.size(), 5));
+                    if (i != j) {
+                        publishPool[0] = contentPools[1];
+                        result.add(pool2.get(1));
+                        break;
+                    }
+                }
+            }
+        } else {
+            // 替补 根据设置替补内容池查找内容尽心替补
+            AccountIndexReplacePoolConfig replacePoolConfig = indexReplacePoolConfigMap.get(2);
+            if (Objects.nonNull(replacePoolConfig)) {
+                List<Content> pool2Replace = contentMap.get(replacePoolConfig.getContentPool());
+                if (CollectionUtils.isNotEmpty(pool2Replace)) {
+                    publishPool[1] = replacePoolConfig.getContentPool();
+                    result.add(pool2Replace.get(0));
+                }
+            }
+        }
+
+        // 3-8
+        List<Content> pool = contentMap.get(contentPools[2]);
+        if (CollectionUtils.isNotEmpty(pool) && param.getSize() > result.size()) {
+            result.addAll(pool.subList(0, Math.min(pool.size(), param.getSize() - result.size())));
+        }
+
+        RankStrategy.deduplication(result, contentMap, publishPool);
+
+        return new RankResult(result);
+    }
+
+}

+ 5 - 0
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/service/recall/RecallService.java

@@ -71,6 +71,8 @@ public class RecallService implements ApplicationContextAware {
 
     @Value("${recall.content.his.fieshu.enable:false}")
     private Boolean contentHisFieshuEnable;
+    @Value("${morning.noon.fission.rate:0.64}")
+    private double morningNoonFissionRate;
 
 
     @PostConstruct
@@ -395,6 +397,9 @@ public class RecallService implements ApplicationContextAware {
             if (avgReadCountSum > 0) {
                 content.setT0FissionByReadAvgSumAvg(fissionSum * 1.0 / avgReadCountSum);
             }
+            if (avgReadCountSum > 0) {
+                content.setT0FissionDeWeightByReadAvgSumAvg(fissionSum / morningNoonFissionRate / avgReadCountSum);
+            }
         }
     }
 

+ 3 - 1
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/service/score/ScoreService.java

@@ -96,7 +96,8 @@ public class ScoreService implements ApplicationContextAware {
                 || StringUtils.equals(param.getStrategy(), RankStrategyEnum.ArticleRankV8.getStrategy())
                 || StringUtils.equals(param.getStrategy(), RankStrategyEnum.ArticleRankV9.getStrategy())
                 || StringUtils.equals(param.getStrategy(), RankStrategyEnum.ArticleRankV10.getStrategy())
-                || StringUtils.equals(param.getStrategy(), RankStrategyEnum.ArticleRankV11.getStrategy())) {
+                || StringUtils.equals(param.getStrategy(), RankStrategyEnum.ArticleRankV11.getStrategy())
+                || StringUtils.equals(param.getStrategy(), RankStrategyEnum.ArticleRankV12.getStrategy())) {
             strategies.add(strategyMap.get(CategoryStrategy.class.getSimpleName()));
             strategies.add(strategyMap.get(AccountPreDistributeStrategy.class.getSimpleName()));
             strategies.add(strategyMap.get(FlowCtlDecreaseStrategy.class.getSimpleName()));
@@ -108,6 +109,7 @@ public class ScoreService implements ApplicationContextAware {
             strategies.add(strategyMap.get(HisFissionAvgReadRateRateStrategy.class.getSimpleName()));
             strategies.add(strategyMap.get(HisFissionAvgReadRateCorrelationRateStrategy.class.getSimpleName()));
             strategies.add(strategyMap.get(HisFissionAvgReadSumRateStrategy.class.getSimpleName()));
+            strategies.add(strategyMap.get(HisFissionDeWeightAvgReadSumRateStrategy.class.getSimpleName()));
         }
 
         return strategies;

+ 40 - 0
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/service/score/strategy/HisFissionDeWeightAvgReadSumRateStrategy.java

@@ -0,0 +1,40 @@
+package com.tzld.longarticle.recommend.server.service.score.strategy;
+
+import com.tzld.longarticle.recommend.server.model.Content;
+import com.tzld.longarticle.recommend.server.service.AccountIndexAvgViewCountService;
+import com.tzld.longarticle.recommend.server.service.score.Score;
+import com.tzld.longarticle.recommend.server.service.score.ScoreParam;
+import com.tzld.longarticle.recommend.server.service.score.ScoreStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+@Slf4j
+public class HisFissionDeWeightAvgReadSumRateStrategy implements ScoreStrategy {
+
+    @Autowired
+    AccountIndexAvgViewCountService accountIndexAvgViewCountService;
+
+    @Override
+    public List<Score> score(ScoreParam param) {
+        long start = System.currentTimeMillis();
+        List<Score> scores = new ArrayList<>();
+        for (Content content : param.getContents()) {
+            if (CollectionUtils.isEmpty(content.getHisPublishArticleList())) {
+                continue;
+            }
+            Score score = new Score();
+            score.setStrategy(this);
+            score.setContentId(content.getId());
+            score.setScore(content.getT0FissionDeWeightByReadAvgSumAvg());
+            scores.add(score);
+        }
+        log.info("HisFissionAvgReadSumRateStrategy cost:{}", System.currentTimeMillis() - start);
+        return scores;
+    }
+}

+ 75 - 0
long-article-recommend-service/src/test/java/com/tzld/longarticle/recommend/server/RecommendTest.java

@@ -1,14 +1,27 @@
 package com.tzld.longarticle.recommend.server;
 
+import cn.hutool.core.collection.CollectionUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
 import com.tzld.longarticle.recommend.server.repository.crawler.AccountAvgInfoRepository;
 import com.tzld.longarticle.recommend.server.repository.crawler.ArticleDetailInfoRepository;
 import com.tzld.longarticle.recommend.server.repository.crawler.ArticleRepository;
+import com.tzld.longarticle.recommend.server.repository.entity.crawler.AccountAvgInfo;
+import com.tzld.longarticle.recommend.server.repository.entity.crawler.Article;
+import com.tzld.longarticle.recommend.server.repository.entity.crawler.ArticleDetailInfo;
 import com.tzld.longarticle.recommend.server.repository.mapper.crawler.CrawlerBaseMapper;
 import com.tzld.longarticle.recommend.server.service.RecommendService;
 import com.tzld.longarticle.recommend.server.service.recall.RecallService;
+import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;
 
 import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
 
 @SpringBootTest(classes = Application.class)
 public class RecommendTest {
@@ -154,4 +167,66 @@ public class RecommendTest {
 //        }
 //    }
 
+    @Test
+    public void test() {
+        List<String> morning = Lists.newArrayList("gh_d2cc901deca7", "gh_9e559b3b94ca", "gh_e75dbdc73d80", "gh_26a307578776", "gh_4568b5a7e2fe", "gh_5ff48e9fb9ef", "gh_6d9f36e3a7be", "gh_9f8dc5b0c74e", "gh_183d80deffb8", "gh_084a485e859a", "gh_7b4a5f86d68c", "gh_660afe87b6fd", "gh_1686250f15b6", "gh_03d45c260115", "gh_57c9e8babea7", "gh_2e615fa75ffb", "gh_98ec0ffe69b3", "gh_6d3aa9d13402", "gh_7c66e0dbd2cf", "gh_bfea052b5baa", "gh_749271f1ccd5", "gh_e0eb490115f5", "gh_d5f935d0d1f2", "gh_51e4ad40466d", "gh_30816d8adb52", "gh_4c058673c07e", "gh_789a40fe7935", "gh_970460d9ccec", "gh_03d32e83122f", "gh_adca24a8f429", "gh_3e91f0624545", "gh_0e4fd9e88386", "gh_93e00e187787", "gh_95ed5ecf9363", "gh_68e7fdc09fe4", "gh_ac43e43b253b", "gh_be8c29139989", "gh_77f36c109fb1", "gh_744cb16f6e16", "gh_ac43eb24376d", "gh_c91b42649690", "gh_57573f01b2ee", "gh_008ef23062ee", "gh_de9f9ebc976b", "gh_058e41145a0c", "gh_969f5ea5fee1", "gh_e24da99dc899");
+        List<String> moon = Lists.newArrayList("gh_a2901d34f75b", "gh_1ee2e1b39ccf", "gh_ee78360d06f5", "gh_192c9cf58b13", "gh_b676b7ad9b74", "gh_3ed305b5817f", "gh_ff487cb5dab3", "gh_89ef4798d3ea", "gh_7e5818b2dd83", "gh_72bace6b3059", "gh_6d205db62f04", "gh_56ca3dae948c", "gh_5ae65db96cb7", "gh_b15de7c99912", "gh_c5cdf60d9ab4", "gh_b6f2c5332c72", "gh_6b7c2a257263", "gh_9eef14ad6c16", "gh_1d887d61088c", "gh_f902cea89e48", "gh_dd4c857bbb36", "gh_0c89e11f8bf3", "gh_bff0bcb0694a", "gh_d4dffc34ac39", "gh_1b27dd1beeca", "gh_bfe5b705324a", "gh_080bb43aa0dc", "gh_6cfd1132df94", "gh_29074b51f2b7", "gh_c69776baf2cd", "gh_f25b5fb01977", "gh_9877c8541764", "gh_d49df5e974ca", "gh_7f5075624a50");
+        String dateStr = "2024-09-12";
+        List<Article> articleList = articleRepository.getByUpdateTimeGreaterThanAndTypeEquals(1726070400L, "9");
+        articleList = articleList.stream().filter(o -> o.getItemIndex() == 1).collect(Collectors.toList());
+        Map<String, List<Article>> map = articleList.stream().collect(Collectors.groupingBy(Article::getTitle));
+        List<AccountAvgInfo> accountAvgInfoList = accountAvgInfoRepository.getAllByUpdateTime(dateStr);
+        accountAvgInfoList = accountAvgInfoList.stream().filter(o -> o.getPosition().equals("1")).collect(Collectors.toList());
+        Map<String, AccountAvgInfo> accountAvgInfoMap = accountAvgInfoList.stream().collect(Collectors.toMap(AccountAvgInfo::getGhId, o -> o));
+        List<String> wxSnList = articleList.stream().map(Article::getWxSn).collect(Collectors.toList());
+        List<ArticleDetailInfo> articleDetailInfoList = articleDetailInfoRepository.getAllByWxSnIn(wxSnList);
+        Map<String, List<ArticleDetailInfo>> articleDetailInfoMap = articleDetailInfoList.stream()
+                .collect(Collectors.groupingBy(ArticleDetailInfo::getWxSn));
+        JSONArray result = new JSONArray();
+        int sumFission0Morning = 0;
+        int sumFission0Moon = 0;
+        double readAvgMorning = 0.0;
+        double readAvgMoon = 0.0;
+        for (Article article : articleList) {
+            List<ArticleDetailInfo> articleDetailInfos = articleDetailInfoMap.get(article.getWxSn());
+            if (CollectionUtil.isEmpty(articleDetailInfos)) {
+                continue;
+            }
+            Date minDate = articleDetailInfos.stream().map(ArticleDetailInfo::getRecallDt).min(Date::compareTo).orElse(new Date());
+            AccountAvgInfo accountAvgInfo = accountAvgInfoMap.get(article.getGhId());
+            int sumFission0 = 0;
+            for (ArticleDetailInfo articleDetailInfo : articleDetailInfos) {
+                if (articleDetailInfo.getRecallDt().equals(minDate) && Objects.nonNull(articleDetailInfo.getFission0())) {
+                    if (morning.contains(article.getGhId())) {
+                        sumFission0Morning += articleDetailInfo.getFission0();
+                    }
+                    if (moon.contains(article.getGhId())) {
+                        sumFission0Moon += articleDetailInfo.getFission0();
+                    }
+                }
+            }
+            if (Objects.nonNull(accountAvgInfo)) {
+                if (morning.contains(article.getGhId())) {
+                    readAvgMorning += accountAvgInfo.getReadAvg();
+                }
+                if (moon.contains(article.getGhId())) {
+                    readAvgMoon += accountAvgInfo.getReadAvg();
+                }
+            }
+        }
+        JSONObject jsonObjectMorning = new JSONObject();
+        jsonObjectMorning.put("时间", "早上");
+        jsonObjectMorning.put("sumFission0", sumFission0Morning);
+        jsonObjectMorning.put("readAvg", readAvgMorning);
+        jsonObjectMorning.put("rate", sumFission0Morning/ readAvgMorning);
+        result.add(jsonObjectMorning);
+        JSONObject jsonObjectMoon = new JSONObject();
+        jsonObjectMoon.put("时间", "中午");
+        jsonObjectMoon.put("sumFission0", sumFission0Moon);
+        jsonObjectMoon.put("readAvg", readAvgMoon);
+        jsonObjectMoon.put("rate", sumFission0Moon/ readAvgMoon);
+        result.add(jsonObjectMoon);
+        System.out.println(JSONObject.toJSONString(result));
+    }
+
 }