"頭條文章向用戶推送避免重復(fù)推送的問題" 的一個解決思路

在鏈接 http://www.dengb.com/Javabc/1409473.html 中發(fā)現(xiàn)了一道非常有趣的題目 --- “頭條文章向用戶推送避免重復(fù)推送的問題”,基于自己的思考提出一個簡單的設(shè)計,供大家吐槽,拋磚引玉。

解決這個問題,我首先做一些假設(shè):

  1. 頭條APP每次翻頁,會加載10篇文章 (主要是為了后面的一些定量的數(shù)字描述方便)
  2. 頭條后臺擁有海量文章,比用戶閱讀的歷史文章要多得多得多

基于以上的假設(shè),我提出了一個簡單的設(shè)計思路。

1. 最樸素,最基礎(chǔ)的查詢應(yīng)該如下:(當(dāng)然,where后面還有其他的條件,如分類等)
select * from 文章表 where 文章ID not in (閱讀過的ID列表) order by rand() limit 10
2. 首先我們想辦法優(yōu)化這個查詢

閱讀過的文章列表ID會越來越多,也就是in里面的條件越來越多,當(dāng)in的條件到一定程度后,可能會不走索引導(dǎo)致效率降低 (參考文檔2);另外,in 語句后面的參數(shù)可能會有限制 (參考文檔3)

優(yōu)化思路
因為我們有假設(shè)2) 文章海量,用戶閱讀歷史比較少,所以我們可以用下面的方法優(yōu)化查詢:

select 文章ID from 文章表 order by rand() limit 200; -- 第一步,先取20頁
select 文章ID from 閱讀歷史表 where userid=用戶ID and 文章ID in (第一步取到的文章ID) -- in語句條件可控

然后再將兩步文章ID的差集作為原始數(shù)據(jù)。

3. 查詢到的數(shù)據(jù)的使用

因為有第二步中有一些文章ID會被排除掉,所以不應(yīng)該用第二步的結(jié)果直接作為查詢結(jié)果返回給前端。我們可以:

  1. 把第二步中的文章ID緩存進(jìn)redis的list中,用prefix+用戶ID作為list的key
  2. 前端每次查詢走redis,做 lpop 10 ,拿出一頁數(shù)據(jù)
  3. 做完翻頁請求后,如果 list 中的數(shù)據(jù)總量少于兩頁,就在后臺啟動任務(wù)執(zhí)行步驟2,加載一批文章ID放進(jìn)緩存。
4. 緩存預(yù)熱

當(dāng)用戶首次使用APP時,我們只需要執(zhí)行以下SQL,并將文章ID放進(jìn)redis緩存,即可完成預(yù)熱。

select 文章ID from 文章表 order by rand() limit 200;

通過以上四步,即可做到:

  1. 保證用戶不會閱讀到重復(fù)的文章;
  2. 保證前端請求的查詢效率。

大家如果有其他的設(shè)計方法,歡迎交流切磋。

參考文檔

  1. 抖音的部分面試題: http://www.dengb.com/Javabc/1409473.html
  2. in語句是否走索引: https://segmentfault.com/a/1190000023825926?utm_source=tag-newest
  3. in語句長度限制: https://blog.csdn.net/a772304419/article/details/103838176
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容