热门列表的实现思路整理


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条数据信息。
如果传入countpublish_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的大小
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值