title: 熱門列表的實現(xiàn)思路整理
date: 2018-09-09
tags: [工作筆記]
熱門的規(guī)則
對于熱門文章的定義是:
單位時間內(nèi)付秕,活躍度(”分享“數(shù) + ”點贊“數(shù) + ”評論“數(shù)的總和)大于某特定值的文章叉讥,被視為熱門文章。
熱門文章的列表是由后臺動態(tài)生成的崭放,而且在每次生成的時候鬼吵,產(chǎn)生的數(shù)據(jù)不一定是相同的扣甲。為了減輕系統(tǒng)的壓力和提高api的響應(yīng)速度,該計算任務(wù)使用celery 進行后臺任務(wù)調(diào)度。
后臺定時任務(wù)循環(huán)執(zhí)行琉挖,任務(wù)執(zhí)行時向緩存數(shù)據(jù)庫中插入當前計算出的符合規(guī)則的熱門文章的索引值启泣,緩存數(shù)據(jù)庫采用的是redis。
定時任務(wù)的實現(xiàn)
- 將新增的熱門文章索引寫入緩存數(shù)據(jù)庫中示辈,插入的時候寥茫,
score
值取當前時間戳。 - 清除一定時間前的熱門文章矾麻。
新增熱門文章
計算熱門文章sql
語句實現(xiàn)如下(暫時不考慮分享的數(shù)據(jù)):
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
用戶發(fā)布文章信息表纱耻,user_like
用戶點贊表,user_comments
用戶評論表)
以上sql語句完成了對符合熱門條件的文章的篩選险耀,返回的結(jié)果集中將不包含應(yīng)已經(jīng)在緩存數(shù)據(jù)庫的中索引弄喘。
將以上返回的文章索引插入redis:
pipeline.zadd(ALL_HOT_KEYS_CACHE, time.time(), item)
(ALL_HOT_KEYS_CACHE
redis 中有序集合的鍵)
清除一定時間前的熱門文章
熱門文章進入緩存之后,需要在一定的時間內(nèi)清除甩牺,這是因為被寫入redis
的之后蘑志,score
不會被改動。定時任務(wù)需要將距離當前較遠的緩存數(shù)據(jù)刪除以減輕緩存的壓力柴灯。
后端的實現(xiàn)
熱門類別的分頁沒有上一頁與下一頁之說卖漫。客戶端在請求的時候赠群,有兩種參數(shù)情況:
-
count
:要多少條數(shù)據(jù) -
publish_ids
:客戶端已經(jīng)緩存的文章id
列表
客戶端如果僅傳入count
參數(shù),后端將返回最新的count
條數(shù)據(jù)信息旱幼。
如果傳入count
和publish_ids
查描,后端返回的count
數(shù)據(jù)中,publish_ids
中包含的文章信息將不會被緩存柏卤。
這樣保證了客戶端數(shù)據(jù)的不重復(fù)問題冬三。但是隨著客戶端瀏覽的數(shù)據(jù)越來越多,把么客戶端請求的publish_ids
列表也越大缘缚,后端去重的時候復(fù)雜度較高勾笆。但是解決這個問題得力于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
返回的數(shù)據(jù)排序按照redis
返回的集合順序桥滨。
客戶端相關(guān)的任務(wù)
- 用戶首次進入列表界面時窝爪,請求不要攜帶
publish_ids
。 - 用戶下拉刷新的操作同首次進入列表界面的操作齐媒。
- 用戶上拉瀏覽列表的時候蒲每,需要攜帶
publish_ids
,用于后端管理去重喻括。
存在的問題
- 客戶端訪問時需要攜帶大量的已經(jīng)緩存的文章
id
邀杏。 - 后端獲取數(shù)據(jù)時的去重,隨著
publish_ids
越來越繁瑣唬血。 - 客戶端處理較為繁瑣
社區(qū)排行榜和熱門列表的實現(xiàn)思路對比
相同:
- 順序都是動態(tài)變化的
- 都需要額外的資源來保證需求的實現(xiàn)
- 客戶端處理比較繁瑣
不同:
- 社區(qū)排行榜是有序的望蜡,熱門列表是設(shè)置門檻的唤崭。
- 社區(qū)排行榜是需要記錄關(guān)注人數(shù)的,熱門不需要記錄活躍度點贊數(shù)和評論數(shù)均取實時的脖律。
- 社區(qū)有分頁參數(shù)浩姥,熱門列表是沒有上一頁下一頁的概念的,僅需要聲明
count
的大小