1.热点文章整体思路
- 定时计算热点文章
- 定时任务每天凌晨1点,查询前5天的文章
- 计算每个文章的分值,其中不同的行为设置不同的权重(阅读:1,点赞:3,评论:5,收藏:8)
- 按照分值排序,给每个频道找出分值较高的30条数据,存入缓存中为什么要按照频道缓存?
- 实时采集文章行为
- 行为微服务,用户阅读或点赞了某一篇文章(目前实现这两个功能),发送消息给rabbitMQ
- 文章微服务,接收行为消息,使用redis中list结构存储实时的行为数据
- 定时更新热度值
- 文章微服务,接收聚合之后的消息,计算文章分值(当日分值计算方式,在原有权重的基础上再*3)
- 根据当前文章的频道id查询缓存中的数据
- 当前文章分值与缓存中的数据比较,如果当前分值大于某一条缓存中的数据,则直接替换
- 新数据重新设置到缓存中
- 更新数据库文章的行为数量
查询热点文章列表
1. 首先查询前5天的 (已上架、未删除) 文章数据
1. 计算所查询所有文章的热度值,根据权重计算分值
1. 为每一个频道缓存热点较高的30条文章,若为推荐频道则缓存所有文章热度值排名前30的文章
1. 按照文章热度降序 排序 截取前30条文章
3.实时采集文章行为
- 所用技术: Redis MQ
- 实现思路: 因为之前已经有一个定时任务负责采集近期(5天内)的热点文章数据,但是当天也会有 用户对文章进行操作,阅读点赞等,所以需要利用MQ进行监控,一旦有用户对某个文章进 行了操作,就需要用MQ发送消息,将文章行为保存到Redis,再对数据做后续处理.
- 在文章的各种行为方法中利用MQ发消息,并且在Redis中缓存一个list用于存储文章的各种行为 例: {文章id,对于文章的操作行为,行为的增减量}
4.近实时更新文章热度分值(重要)
- 所用技术: XXL-Job Redis MQ
- 实现思路: 利用定时任务实现每过十秒检测一次Redis中是否有用户操作的数据,对于行为数据他 的发生频率非常高 可能1篇文章 最近10s被阅读了几万次,所以我们不可能每次都去 修改数据库,需要把最近一段时间内该文章的所有行为先进行统计,然后再更新文章 的相关热度信息
1. 从Redis中获取数据后,要对数据进行处理
1. 获取数据的总数,利用Redis的管道操作命令,分别读取指定长度的数据,而后删除取出的数据保留剩余数据,
2. 按照文章id对行为数据进行分组 [{articleId:1,add:1,type:view}{articleId:1,add:1,type:likes}] ==> {articleId:1, view:1,like:1}
1. 按照文章id分组 key: 文章id value: 文章行为数据List
key 文章id 1 value: List<> 3
2. 遍历分组 对每个分组进行聚合运算,每个分组统计出一个 ArticleVisitStreamMess.根据文章的状态,将文章中相同的操作进行聚合运算
messMap.forEach((articleId,messList) -> {
// 按照文章分组 对每个分组进行聚合运算 , 每个分组统计出一个 ArticleVisitStreamMess
// 映射 将每一条行为数据 都转化为 ArticleVisitStreamMess聚合对象
Optional<ArticleVisitStreamMess> reduce = messList.stream()
.map(mess -> {
ArticleVisitStreamMess articleVisitStreamMess = new ArticleVisitStreamMess();
articleVisitStreamMess.setArticleId(articleId);
switch (mess.getType()) {
case LIKES:
articleVisitStreamMess.setLike(mess.getAdd()); //点赞行为
break;
case VIEWS:
articleVisitStreamMess.setView(mess.getAdd()); //阅读行为
break;
case COMMENT:
articleVisitStreamMess.setComment(mess.getAdd()); //评论行为
break;
case COLLECTION:
articleVisitStreamMess.setCollect(mess.getAdd()); //收藏行为
break;
}
return articleVisitStreamMess;
})
.reduce(new BinaryOperator<ArticleVisitStreamMess>() {
/**
* 归并运算 将流中的数据进行两两运算
* @param a1
* @param a2
* @return
*/
@Override
public ArticleVisitStreamMess apply(ArticleVisitStreamMess a1, ArticleVisitStreamMess a2) {
a1.setView(a1.getView() + a2.getView());
a1.setLike(a1.getLike() + a2.getLike());
a1.setComment(a1.getComment() + a2.getComment());
a1.setCollect(a1.getCollect() + a2.getCollect());
return a1;
}
});
3. 修改文章分值 {articleId:1, view:1,like:1}
1. 根据 文章id查询出文章数据
1. 更新文章 各个行为的值
1. 计算文章得分
1. 判断文章是否是今日发布 如果是整体热度*3
1. 查询对应频道热点文章,替换分值较低文章
1. 重新对热点文章进行排序 并截取前30条热点文章
6. 查询推荐频道热点文章,替换分值较低文章
5.APP文章列表查询接口改造
- 若APP查询的是第一页,那么就去Redis中查询热点文章,并返回
- 若查询的不是第一页,则去数据库中查询普通文章