前言
這個月做的事情還是蠻多的。上線了一個百臺規(guī)模的ES集群,還設(shè)計開發(fā)了一套實時推薦系統(tǒng)。 標(biāo)題有點長,其實是為了突出該推薦系統(tǒng)的三個亮點,一個是實時,一個是基于用戶畫像去做的,一個是異步化。
*** 實時主要體現(xiàn)在三個層面:***
-
用戶畫像中的的短期興趣模型實時構(gòu)建。
也就是你看完一個視頻,這個視頻幾秒內(nèi)就影響了你的短期興趣模型,并且反應(yīng)到你下次的推薦中。
-
候選集實時變更。
在我設(shè)計的推薦系統(tǒng)中,候選集的概念是不同類型的待推薦給用戶的視頻庫,一個用戶并不能看到某個候選集的全部,而是能夠看到經(jīng)過匹配算法處理完后的候選集的一部分。 候選集的更新周期直接影響用戶能夠看到的視頻的實時性。候選集可以有很多,通過不同的候選集解決不同的推薦場景問題。比如結(jié)合最新候選集和最近N小時最熱候選集,我們可以做到類似今日頭條的推薦效果。新內(nèi)容候選集的產(chǎn)生基本就是實時的,而最近N小時熱門視頻候選集則可能是分鐘級別就可以得到更新。還有比如協(xié)同就可以做視頻的相關(guān)推薦,而熱門候選集則可以從大家都關(guān)心的內(nèi)容里進(jìn)一步篩出用戶喜歡的內(nèi)容。
-
推薦效果指標(biāo)的實時呈現(xiàn)。
上線后你看到的一些比較關(guān)鍵的指標(biāo)例如點擊轉(zhuǎn)化率,都可以在分鐘級別得到更新。推薦系統(tǒng)有個比較特殊的地方,就是好不好不是某個人說了算,而是通過一些指標(biāo)來衡量的。比如點擊轉(zhuǎn)化率。
*** 用戶畫像和視頻畫像 ***
用戶畫像則體現(xiàn)在興趣模型上。通過構(gòu)建用戶的長期興趣模型和短期興趣模型可以很好的滿足用戶興趣愛好以及在用戶會話期間的需求。做推薦的方式可以很多,比如協(xié)同,比如各種小trick,而基于用戶畫像和視頻畫像,起步難度會較大,但是從長遠(yuǎn)角度可以促進(jìn)團(tuán)隊對用戶和視頻的了解,并且能夠支撐推薦以外的業(yè)務(wù)。
*** 異步化 ***
推薦的計算由用戶刷新行為觸發(fā),然后將用戶信息異步發(fā)送到Kafka,接著Spark Streaming程序會消費并且將候選集和用戶進(jìn)行匹配計算,計算結(jié)果會發(fā)送到Redis 的用戶私有隊列。接口服務(wù)只負(fù)責(zé)取推薦數(shù)據(jù)和發(fā)送用戶刷新動作。新用戶或者很久沒有過來的用戶,它的私有隊列可能已經(jīng)過期,這個時候異步會產(chǎn)生問題。前端接口一旦發(fā)現(xiàn)這個問題,有兩種解決方案:
- 會發(fā)送一個特殊的消息(后端接的是Storm集群), 接著hold住,等待異步計算結(jié)果
- 自己獲取用戶興趣標(biāo)簽,會按一定的規(guī)則分別找協(xié)同,然后到ES檢索,填充私有隊列,并迅速給出結(jié)果。(我們采用的方案)
除了新用戶,這種情況總體是少數(shù)。大部分計算都會被異步計算cover住。
流式技術(shù)對推薦系統(tǒng)的影響
我之前寫了很多文章鼓吹流式技術(shù),最露骨的比如 數(shù)據(jù)天生就是流式的。 當(dāng)然主要和我這一兩年部門的工作主體是構(gòu)建
流式流水線(Pipline),解決實時日志計費等相關(guān)問題。流式計算對推薦系統(tǒng)的影響很大,可以完全實現(xiàn)
在推薦系統(tǒng)中,除了接口服務(wù)外,其他所有計算相關(guān)的,包括但不限于:
- 新內(nèi)容預(yù)處理,如標(biāo)簽化,存儲到多個存儲器
- 用戶畫像構(gòu)建 如短期興趣模型
- 新熱數(shù)據(jù)候選集
- 短期協(xié)同
- 推薦效果評估指標(biāo)如點擊轉(zhuǎn)化率
這些流程都是采用Spark Streaming來完成。對于長期協(xié)同(一天以上的數(shù)據(jù)),用戶長期興趣模型等,則是采用Spark 批處理。因為采用了StreamingPro這個項目,可以做到所有計算流程配置化,你看到的就是一堆的描述文件,這些描述文件構(gòu)成了整個推薦系統(tǒng)的核心計算流程。
這里還值得提的三點是:
推薦效果評估,我們采用Spark Streaming + ElasticSearch的方案。也就是Spark Streaming 對上報的曝光點擊數(shù)據(jù)進(jìn)行預(yù)處理后存儲到ES,然后ES提供查詢接口供BI報表使用。這樣避免預(yù)先計算指標(biāo)導(dǎo)致很多指標(biāo)實現(xiàn)沒有考慮到而不斷變更流式計算程序。
復(fù)用現(xiàn)有的大數(shù)據(jù)基礎(chǔ)設(shè)施。整個推薦系統(tǒng)只有對外提供API的服務(wù)是需要單獨部署的,其他所有計算都使用Spark跑在Hadoop集群上。
所有計算周期和計算資源都是可以方便調(diào)整的,甚至可以動態(tài)調(diào)整(Spark Dynamic Resource Allocatioin)。這點非常重要,我完全可以放棄一定的實時性來節(jié)省資源或者在閑暇時讓出更多資源給離線任務(wù)。當(dāng)然這些都益于Spark 的支持。
推薦系統(tǒng)的體系結(jié)構(gòu)
整個推薦系統(tǒng)的結(jié)構(gòu)如圖:
看起來還是挺簡單的。分布式流計算主要負(fù)責(zé)了五塊:
- 點擊曝光等上報數(shù)據(jù)處理
- 新視頻標(biāo)簽化
- 短期興趣模型計算
- 用戶推薦
- 候選集計算,如最新,最熱(任意時間段)
存儲采用的有:
- Codis (用戶推薦列表)
- HBase (用戶畫像和視頻畫像)
- Parquet(HDFS) (歸檔數(shù)據(jù))
- ElasticSearch (HBase的副本)
下面這張圖則是對流式計算那塊的一個細(xì)化:
用戶上報采用的技術(shù)方案:
- Nginx
- Flume (收集Nginx日志)
- Kafka (接收Flume的上報)
對于第三方內(nèi)容(全網(wǎng)),我們自己開發(fā)了一個采集系統(tǒng)。
個性化推薦示
所有候選集都是實時更新的。
這里我們說下參數(shù)配置服務(wù)器的概念。
假設(shè)我有三個算法A,B,C ,他們分別由三個流式程序完成,各個程序是互相獨立的,最后都會算出各自的結(jié)果集。因為不同候選集和算法算出的內(nèi)容數(shù)據(jù)量和頻度都會有差異,假設(shè)A算出的結(jié)果集過大,B算出的結(jié)果集很小,但是質(zhì)量很好,這個時候他們在發(fā)送到用戶推薦隊列的時候,需要將自己的情況提交給參數(shù)配置服務(wù)器,并且由參數(shù)服務(wù)器決定最后能夠發(fā)送到隊列的量。參數(shù)服務(wù)器也可以控制對應(yīng)頻度。比如A算法距離上次推薦結(jié)果才10s就有新的要推薦了,參數(shù)服務(wù)器可以拒絕他的內(nèi)容寫入到用戶推薦隊列。
上面是一種多算法流程的控制。其實還有一種,就是我希望A,B的結(jié)果讓一個新的算法K來決定混合的規(guī)則,因為所有算法都是StreamingPro中的一個可配置模塊,這個時候A,B,K 會被放到一個Spark Streaming應(yīng)用中。K可以周期性調(diào)用A,B進(jìn)行計算,并且混合結(jié)果,最后通過參數(shù)服配置服務(wù)器的授權(quán)寫入到用戶推薦隊列。
一些感悟
我14,15年做的一次推薦系統(tǒng),那個時候還沒有流式計算的理念,而且也不能復(fù)用一些已有的技術(shù)體系,導(dǎo)致系統(tǒng)過于復(fù)雜,產(chǎn)品化也會比較困難。而且推薦的效果也只能隔日看到,導(dǎo)致效果改良的周期非常長。當(dāng)時整個開發(fā)周期超過了一個多月。然而現(xiàn)在基于StreamingPro,兩三人沒人么天只能投入兩三小時,僅僅用了兩個禮拜就開發(fā)出來了。后續(xù)就是對用戶畫像和視頻畫像的進(jìn)一步深入探索,核心是構(gòu)建出標(biāo)簽體系,然后將這些標(biāo)簽打到用戶和視頻身上。我們組合了LDA,貝葉斯等多種算法,獲得不少有益的經(jīng)驗。