title: 热门列表的实现思路整理
date: 2018-09-09
tags: [工作笔记]
热门的规则
对于热门文章的定义是:
单位时间内,活跃度(”分享“数 + ”点赞“数 + ”评论“数的总和)大于某特定值的文章,被视为热门文章。
热门文章的列表是由后台动态生成的,而且在每次生成的时候,产生的数据不一定是相同的。为了减轻系统的压力和提高api的响应速度,该计算任务使用celery 进行后台任务调度。
后台定时任务循环执行,任务执行时向缓存数据库中插入当前计算出的符合规则的热门文章的索引值,缓存数据库采用的是redis。
定时任务的实现
- 将新增的热门文章索引写入缓存数据库中,插入的时候,
score
值取当前时间戳。 - 清除一定时间前的热门文章。
新增热门文章
计算热门文章sql
语句实现如下(暂时不考虑分享的数据):
SELECT result.user_publish_id FROM (
SELECT a.user_publish_id, COUNT(*) AS count FROM
(
SELECT p.user_publish_id
FROM user_publish AS p
JOIN user_like AS l
ON
l.for_obj = p.user_publish_id AND l.like_type = 0 AND l.created_at > '{0}'
WHERE p.status = 'VISIBLE'
UNION ALL
SELECT p.user_publish_id
FROM user_publish AS p
JOIN user_comments AS c
ON
p.user_publish_id = c.publish_id AND c.status = 'VISIBLE' AND c.created_at > '{0}'
WHERE p.status = 'VISIBLE'
) AS a
WHERE a.user_publish_id not in ("{2}")
GROUP BY a.user_publish_id
) AS result
WHERE result.count >= {1}
(user_publish
用户发布文章信息表,user_like
用户点赞表,user_comments
用户评论表)
以上sql语句完成了对符合热门条件的文章的筛选,返回的结果集中将不包含应已经在缓存数据库的中索引。
将以上返回的文章索引插入redis:
pipeline.zadd(ALL_HOT_KEYS_CACHE, time.time(), item)
(ALL_HOT_KEYS_CACHE
redis 中有序集合的键)
清除一定时间前的热门文章
热门文章进入缓存之后,需要在一定的时间内清除,这是因为被写入redis
的之后,score
不会被改动。定时任务需要将距离当前较远的缓存数据删除以减轻缓存的压力。
后端的实现
热门类别的分页没有上一页与下一页之说。客户端在请求的时候,有两种参数情况:
-
count
:要多少条数据 -
publish_ids
:客户端已经缓存的文章id
列表
客户端如果仅传入count
参数,后端将返回最新的count
条数据信息。
如果传入count
和publish_ids
,后端返回的count
数据中,publish_ids
中包含的文章信息将不会被缓存。
这样保证了客户端数据的不重复问题。但是随着客户端浏览的数据越来越多,把么客户端请求的publish_ids
列表也越大,后端去重的时候复杂度较高。但是解决这个问题得力于redis
的集合操作方法。
# redis_utils.py
def get_redis_sorted_set_diffs(uid, items, count):
user_key = USER_HOT_KEYS_CACHE.format(uid)
user_hot_key_cache(items, user_key)
dest = USER_HOT_KEYS_DESTINATION_CACHE.format(uid)
redis_store.zunionstore(dest, {ALL_HOT_KEYS_CACHE: 1, user_key: 0}, 'MIN')
x = redis_store.zrevrangebyscore(dest, '+inf', 1)[:count]
redis_store.delete(user_key)
redis_store.delete(dest)
return x
返回的数据排序按照redis
返回的集合顺序。
客户端相关的任务
- 用户首次进入列表界面时,请求不要携带
publish_ids
。 - 用户下拉刷新的操作同首次进入列表界面的操作。
- 用户上拉浏览列表的时候,需要携带
publish_ids
,用于后端管理去重。
存在的问题
- 客户端访问时需要携带大量的已经缓存的文章
id
。 - 后端获取数据时的去重,随着
publish_ids
越来越繁琐。 - 客户端处理较为繁琐
社区排行榜和热门列表的实现思路对比
相同:
- 顺序都是动态变化的
- 都需要额外的资源来保证需求的实现
- 客户端处理比较繁琐
不同:
- 社区排行榜是有序的,热门列表是设置门槛的。
- 社区排行榜是需要记录关注人数的,热门不需要记录活跃度点赞数和评论数均取实时的。
- 社区有分页参数,热门列表是没有上一页下一页的概念的,仅需要声明
count
的大小