1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
package com.tanpu.community.service;
import com.tanpu.biz.common.enums.clue.PageEnum;
import com.tanpu.biz.common.enums.community.CollectionTypeEnum;
import com.tanpu.biz.common.enums.community.TopicStatusEnum;
import com.tanpu.community.api.beans.qo.ThemeAnalysDO;
import com.tanpu.community.api.beans.qo.TopicRankQo;
import com.tanpu.community.api.beans.vo.feign.fatools.UserInfoResp;
import com.tanpu.community.cache.RedisCache;
import com.tanpu.community.dao.entity.community.ThemeEntity;
import com.tanpu.community.dao.entity.community.TopicEntity;
import com.tanpu.community.util.BizUtils;
import com.tanpu.community.util.ConvertUtil;
import com.tanpu.community.util.TimeUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.tanpu.community.api.constants.RedisKeyConstant.CACHE_FEIGN_USER_INFO;
@Service
public class RankService {
@Autowired
private ThemeService themeService;
@Autowired
private CollectionService collectionService;
@Autowired
private CommentService commentService;
@Autowired
private TopicService topicService;
@Autowired
private VisitLogService visitLogService;
@Autowired
private FeignService feignService;
@Autowired
private RedisCache redisCache;
@Resource
private RankLogService rankLogService;
//最热
private List<ThemeAnalysDO> hotestThemes = new ArrayList<>();
private List<TopicRankQo> rankTopicList = new ArrayList<>();
private List<TopicRankQo> rankTopicListTop4 = new ArrayList<>();
/**
* 计算主题热度排行
*/
public void rankThemes() {
LocalDateTime start = LocalDateTime.now();
//7天内所有主题进行热度值排序
List<ThemeEntity> themeEntities = themeService.queryRecentdays(7);
if (CollectionUtils.isEmpty(themeEntities)) {
return;
}
List<ThemeAnalysDO> themeAnalysDOS = ConvertUtil.themeEntityToAnalysDOs(themeEntities);
//批量查询
List<String> themeIds = themeAnalysDOS.stream().map(ThemeAnalysDO::getThemeId).collect(Collectors.toList());
Map<String, Integer> likeCountMap = collectionService.getCountMapByType(themeIds, CollectionTypeEnum.LIKE_THEME);
Map<String, Integer> bookCountMap = collectionService.getCountMapByType(themeIds, CollectionTypeEnum.COLLECT_THEME);
Map<String, Integer> commentCountMap = commentService.getCountMapByThemeIds(themeIds);
Map<String, Integer> forwardCountMap = themeService.getForwardCountMap(themeIds);
Map<String, Integer> visitCountMap = visitLogService.getCountMapByTargetIds(themeIds, PageEnum.COMM_VISIT_THEME.getId());
for (ThemeAnalysDO theme : themeAnalysDOS) {
String themeId = theme.getThemeId();
theme.setCommentCount(commentCountMap.getOrDefault(themeId, 0));
theme.setLikeCount(likeCountMap.getOrDefault(themeId, 0));
theme.setForwardCount(forwardCountMap.getOrDefault(themeId, 0));
theme.setCollectCount(bookCountMap.getOrDefault(themeId, 0));
theme.setViewCount(visitCountMap.getOrDefault(themeId, 0));
//查询用户质量
String authorId = theme.getAuthorId();
UserInfoResp authorInfo = redisCache.getObject(StringUtils.joinWith("_", CACHE_FEIGN_USER_INFO, authorId),
60, () -> feignService.getUserInfoById(authorId), UserInfoResp.class);
if (authorInfo == null || authorInfo.getLevelGrade() == null) {
theme.setUserWeight(0.0);
} else {
// 设置用户权重
theme.setUserWeight(authorInfo.getLevelGrade() * 1.0);
}
}
//打分
Map<ThemeAnalysDO, Double> map = themeAnalysDOS.stream().collect(Collectors.toMap(o -> o, ThemeAnalysDO::getRank));
//排序
hotestThemes = map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.map(e -> e.getKey()).collect(Collectors.toList());
//落库
rankLogService.logThemeRank(hotestThemes, start, TimeUtils.calMillisTillNow(start));
}
/**
* 计算话题热度
*
* @return
*/
public void rankTopics() {
LocalDateTime start = LocalDateTime.now();
List<TopicEntity> topicEntities = topicService.queryAll();
if (CollectionUtils.isEmpty(topicEntities)) {
return;
}
List<TopicRankQo> topicRankQos = ConvertUtil.topicEntityToHotQos(topicEntities);
List<String> topicIds = topicRankQos.stream().map(TopicRankQo::getTopicId).collect(Collectors.toList());
Map<String, Integer> topicViewMap = visitLogService.getCountMapByTargetIds(topicIds, PageEnum.COMM_VISIT_TOPIC_DETAIL.getId());
for (TopicRankQo topic : topicRankQos) {
List<String> themeIds = themeService.queryThemeIdsByTopic(topic.getTopicId());
if (CollectionUtils.isEmpty(themeIds)) {
topic.setViewCount(topicViewMap.getOrDefault(topic.getTopicId(), 0));
topic.setDisscussCount(0);
topic.setThemeWeight(0.0);
topic.setFormatViewCount(BizUtils.formatCountNumber(topic.getViewCount()));
topic.setFormatDisscussCount(BizUtils.formatCountNumber(topic.getDisscussCount()));
continue;
}
// 浏览量
Integer topicPV = topicViewMap.getOrDefault(topic.getTopicId(), 0);
Integer themePV = visitLogService.queryThemeVisit(themeIds);
topic.setViewCount(topicPV + themePV + topic.getViewCntAdjust());
//讨论数=发布主题贴数+回复总数
Integer commentCount = commentService.getTotalCountByThemeIds(themeIds);
topic.setDisscussCount(themeIds.size() + commentCount);
//帖子权重,求和
double themeSum = getHotestThemes().stream().filter(o -> topic.getTopicId().equals(o.getTopicId()))
.mapToDouble(ThemeAnalysDO::getRank)
.sum();
topic.setThemeWeight(themeSum);
//格式化浏览量、讨论量
topic.setFormatViewCount(BizUtils.formatCountNumber(topic.getViewCount()));
topic.setFormatDisscussCount(BizUtils.formatCountNumber(topic.getDisscussCount()));
}
Map<TopicRankQo, Double> map = topicRankQos.stream().collect(Collectors.toMap(o -> o, TopicRankQo::getRank));
List<TopicRankQo> rankList = map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
rankList.get(0).setType(TopicStatusEnum.HOTTEST.getCode());
this.rankTopicList = rankList;
this.rankTopicListTop4 = rankList.stream().limit(4).collect(Collectors.toList());
//落库
rankLogService.logTopicRank(rankList, start, TimeUtils.calMillisTillNow(start));
return;
}
/**
* 从排序列表中返回话题详情
*
* @param topicId 话题Id
* @return
*/
public TopicRankQo getTopicDetail(String topicId) {
if (this.rankTopicList.size() == 0) {
rankTopics();
}
List<TopicRankQo> matchTopic = this.rankTopicList.stream().filter(o -> topicId.equals(o.getTopicId())).limit(1).collect(Collectors.toList());
matchTopic.add(new TopicRankQo());
return matchTopic.get(0);
}
public List<TopicRankQo> getRankTopicList(String keyword) {
if (this.rankTopicList.size() == 0) {
this.rankTopics();
}
if (StringUtils.isEmpty(keyword)) {
return rankTopicList;
} else {
//过滤关键字
return this.rankTopicList.stream().filter(o -> o.getTopicTitle().contains(keyword)).collect(Collectors.toList());
}
}
public List<TopicRankQo> getRankTopicListTop4() {
if (this.rankTopicList.size() == 0) {
this.rankTopics();
}
return rankTopicListTop4;
}
public List<ThemeAnalysDO> getHotestThemes() {
if (this.hotestThemes.size() == 0) {
rankThemes();
}
return hotestThemes;
}
public List<String> getRankThemeListByTopic(String topicId, List<String> excludeIds) {
if (this.hotestThemes.size() == 0) {
this.rankThemes();
}
return hotestThemes.stream()
.filter(o -> topicId.equals(o.getTopicId()) && !excludeIds.contains(o.getThemeId()))
.map(ThemeAnalysDO::getThemeId)
.collect(Collectors.toList());
}
}