基於標籤的實時短視頻推薦系統(三十)

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"寫在前面:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"大家好,我是強哥,一個熱愛分享的技術狂。目前已有 12 年大數據與AI相關項目經驗, 10 年推薦系統研究及實踐經驗。平時喜歡讀書、暴走和寫作。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"業餘時間專注於輸出大數據、AI等相關文章,目前已經輸出了40萬字的推薦系統系列精品文章,今年 6 月底會出版「構建企業級推薦系統:算法、工程實現與案例分析」一書。如果這些文章能夠幫助你快速入門,實現職場升職加薪,我將不勝歡喜。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"想要獲得更多免費學習資料或內推信息,一定要看到文章最後喔。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"內推信息","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你正在看相關的招聘信息,請加我微信:liuq4360,我這裏有很多內推資源等着你,歡迎投遞簡歷。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"免費學習資料","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你想獲得更多免費的學習資料,請關注同名公衆號【數據與智能】,輸入“資料”即可!","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"學習交流羣","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你想找到組織,和大家一起學習成長,交流經驗,也可以加入我們的學習成長羣。羣裏有老司機帶你飛,另有小哥哥、小姐姐等你來勾搭!加小姐姐微信:epsila,她會帶你入羣。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者在《基於內容的推薦算法》中對基於內容的推薦算法做了比較詳細的講解,其中一類非常重要的內容推薦算法是基於標籤的倒排索引算法,也是工業界用得比較多的算法,特別是新聞資訊類、短視頻類產品大量採用該類算法。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在本章中作者會結合某貓的業務場景及工程實踐經驗來詳細講解基於標籤的倒排索引算法的原理及工程落地方案細節。希望讀者學完本章,可以完整地瞭解基於標籤的倒排索引算法的產品形態、算法原理、工程實現方案,並且能夠基於本文的思路,具備從零開始搭建一套基於標籤的算法體系的能力。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"某貓有長視頻和短視頻各6大類,長視頻對實時性要求相對沒有那麼高,所以本章主要以短視頻的實時個性化推薦爲例來講解。本章會從基於標籤的推薦算法應用場景、基於標籤的推薦算法原理介紹、整體架構及工程實現、召回與排序策略、冷啓動策略、未來優化方向等6個方面來介紹基於標籤的實時短視頻推薦系統。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.1 基於標籤的推薦算法應用場景","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在講具體的算法原理及工程實踐之前,我們先對基於標籤的推薦算法可行的產品形態做簡單介紹,讓讀者知道該類算法可以用到哪些業務場景中,從而有一個直觀的印象,方便更好地理解後續講解的內容。這些產品形態電視貓都落地到了真實業務場景中,下面的圖例也是拿電視貓的產品形態來舉例說明的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在《基於內容的推薦算法》5.3節中我們簡單描述了基於內容的推薦算法的應用場景,而基於標籤的推薦是內容推薦的一種,應用場景也是類似的:完全個性化推薦、標的物關聯標的物推薦(相似視頻推薦)、主題推薦這3類應用場景都是可行的,我們下面對這3大業務場景簡單一一說明。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.1.1 完全個性化推薦","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"完全個性化推薦是爲每個用戶生成不一樣的推薦結果,某貓小視頻實時個性化推薦,基於用戶的(標籤)興趣畫像,爲用戶推薦跟他興趣偏好相似的視頻,用戶可以無限右滑(由於某貓是客廳端的視頻軟件,靠遙控器交互,所以產品交互方式上跟頭條等手機端APP的下拉交互是不一樣的)獲取自己感興趣的推薦結果,整個算法會根據用戶的興趣變化實時爲用戶更新推薦結果。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.1.2 標的物關聯標的物推薦(相似視頻推薦)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"短視頻相似推薦基於視頻標籤構建視頻之間的相似度,爲每個視頻推薦相似的視頻。下圖是某貓短視頻的相似推薦,採用的產品形態是連播推薦的形式,當用戶播放完當前短視頻後,相關聯的相似視頻會按照相似度列表的順序連續播放,最大程度提升用戶體驗、提升內容分發。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.1.3 主題推薦","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"主題推薦根據用戶播放行爲歷史,構建用戶興趣畫像,這裏是基於節目的標籤來構建用戶畫像的,基於用戶畫像標籤爲用戶推薦最感興趣的標籤關聯的節目。下圖是某貓音樂頻道的主題推薦,根據作者最近看過的音樂視頻,爲作者推薦了“","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"國語","attrs":{}},{"type":"text","text":"”和“","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"器樂教學","attrs":{}},{"type":"text","text":"”兩個主題相關的音樂短視頻。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"講解完了基於標籤的推薦產品形態,相信讀者對基於標籤的推薦有了較直觀的認知,那麼我們在實際業務中怎麼實現這些產品形態、怎麼構建合適的基於標籤的推薦算法呢?在下節我們會詳細講解算法基本原理。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.2 基於標籤的推薦算法原理介紹","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們在基於內容的推薦算法》中對基於標籤的個性化推薦算法原理已經做過初略介紹,讀者應該有印象,忘記了也沒關係,本節我們會對上節提到的三個產品形態:個性化推薦、相似視頻推薦、主題推薦的算法實現原理做細緻的介紹,方便讀者深入理解算法的實現細節。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.2.1 個性化推薦(完全個性化範式)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於標籤的個性化推薦算法具體推薦過程見下面圖4:從用戶畫像中獲取用戶的興趣標籤,基於用戶的興趣標籤從","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"標籤->節目","attrs":{}},{"type":"text","text":"倒排索引表中獲取該標籤對應的節目,這樣就可以從用戶關聯到節目了。其中用戶的每個興趣標籤及標籤關聯到的節目都是有權重的。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fb/fbab2379719f38f9f26b4089cd7074f8.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"圖4:基於倒排索引的視頻推薦","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假設用戶的興趣標籤及對應的標籤權重如下,其中","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ac/ac44d6d8ef4620e4bf71092c2c3fac68.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"是標籤,","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ae/ae03f9a4ffec4cd94e90f647d3bb5ccd.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"是用戶對標籤的偏好權重。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/62/62711cf06e32ca175e631a3b3fb36d0a.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假設標籤","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/43/43de4e11ebf4d6f2467360b4fa8d1067.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關聯的視頻分別爲:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/82/823ea0402c2ace033731f648e14f0cf3.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/00/0091e9448a0be0a4188e3d1f2f42f0b7.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"......","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8a/8aa76f27fb14b15c1a1329fe7c22e1da.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b1/b1d358738718e22329445ca17699482d.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"、","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/cb/cb79e150797e9f8aef9e6e945656778e.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"分別是標的物及對應的權重,那麼","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/01/01ee6b21f77ab4d32b35b590747a4ef1.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上式中U是用戶對視頻的偏好集合,我們這裏將視頻","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b1/b1d358738718e22329445ca17699482d.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"看成向量空間的基,所以有上面的公式。不同的標籤可以關聯到相同的視頻(因爲不同的視頻可以有相同的標籤),上式中最後一個等號右邊需要合併同類項,將相同基前面的係數相加。合併同類項後,視頻(基)前面的數值就是用戶對該視頻的偏好程度了,我們對這些偏好程度降序排列,就可以爲用戶做topN推薦了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面只是基於用戶興趣畫像來爲用戶做推薦的算法原理,實際業務中,用戶的興趣有長期興趣、短期興趣,同時還需要考慮給用戶提供多樣性的推薦及根據用戶播放過程中的實時反饋調整推薦結果,所以實際工程上會非常複雜,這一塊我們會在28.3節的架構及工程實現、28.4節的召回和排序中詳細說明。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.2.2 視頻相似推薦(標的物關聯標的物範式)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在本節我們先來講解怎麼利用視頻的標籤來計算兩個視頻之間的相似度,有了視頻之間的相似度就很容易做視頻的相似推薦了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假設視頻集合是","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/5d/5d751fa556d7e7e31fac2e5334713948.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":",其中","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/be/be2e0aed0088b8669f44a671167e3bad.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"是對應的視頻。假設所有視頻標籤集合是","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a4/a4405070ac9558e1ea13c26bb581eb0c.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":",其中","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/5a/5a7531d28b2d6e0be2208153ba31bb8a.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"是對應的標籤。一般n和m都是非常大的數,從幾十萬到上百萬,甚至更大。每個視頻只有很少的標籤,所以將視頻表示成標籤的向量的話,一定是稀疏向量,我們可以採用視頻的標籤向量表示的餘弦相似度來計算兩個視頻之間的相似度,具體計算過程如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假設兩個視頻","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f2/f2053f40286404280dacd154ae4a86d5.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"的向量表示如下(我們按照","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a4/a4405070ac9558e1ea13c26bb581eb0c.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"中標籤的順序來編碼向量),","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ee/eec013762769135cbacb275b230e2829.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"是對應的權重,如果採用n-hot編碼,","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/cb/cb79e150797e9f8aef9e6e945656778e.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"=0 或者","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/cb/cb79e150797e9f8aef9e6e945656778e.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"=1,如果標籤是有權重的,","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/cb/cb79e150797e9f8aef9e6e945656778e.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"就是對應標籤的權重。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/bd/bde2596a72a13494d6b56dd2253c6054.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a1/a1529eda20d543c49221dffb10263370.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們可以採用如下cosine餘弦相似度公式來計算","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f2/f2053f40286404280dacd154ae4a86d5.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之間的相似度:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/98/98951dcb7e606b8c9df12dffcf842cf2.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們可以計算出","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fc/fc89b6153915a068a6ea9ebd01d0a6ce.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"與所有其他視頻(除去","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fc/fc89b6153915a068a6ea9ebd01d0a6ce.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"自身)的相似度:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a2/a209aaf872098f81747fafd7b4ffe9ea.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fc/fc89b6153915a068a6ea9ebd01d0a6ce.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"的相似推薦就可以利用上述列表降序排列後取topN作爲最終推薦列表。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.2.3 主題推薦","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有了28.2.1中介紹的個性化推薦的算法原理,就很容易說明怎麼做主題推薦了。首先我們根據用戶畫像獲取用戶的幾個最感興趣的標籤,每個興趣標籤就是一個主題,將每個興趣標籤關聯的節目推薦給用戶就可以了,下面簡要說明一下。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假設用戶的興趣標籤及對應的標籤權重如下,其中","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ac/ac44d6d8ef4620e4bf71092c2c3fac68.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"是標籤,","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ae/ae03f9a4ffec4cd94e90f647d3bb5ccd.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"是用戶對標籤的偏好權重。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/62/62711cf06e32ca175e631a3b3fb36d0a.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們可以將上述集合按照權重降序排序,選擇k個權重最大(用戶最喜歡)的標籤","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/07/078de905220f6f6e6f268f051c9aec5d.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作爲待推薦的主題。再從每個標籤關聯的節目(在實際工程實現上,我們會事先構建","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"標籤->節目","attrs":{}},{"type":"text","text":"的倒排索引表,方便從標籤關聯到節目)中選擇對應的節目推薦給用戶。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面我們簡要講解了三類基於標籤的推薦算法的算法原理,下面我們會結合電視貓的實踐經驗來講解這三類推薦產品在工程上是怎麼實現的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.3 整體架構及工程實現","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本節我們來詳細講解28.2節中介紹的三類推薦算法的整體架構、核心功能模塊及工程實現。這裏我們重點只講解個性化推薦和相似視頻推薦兩種推薦產品的架構和實現,主題推薦跟個性化推薦非常相似,我們會簡單說明一下。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"電視貓基於標籤的個性化短視頻推薦是基於Spark平臺來實現的,其中流式處理採用Spark Streaming組件,離線處理採用Spark,整個代碼工程整合到了Doraemon框架中了(關於Doraemon框架作者在《推薦系統的工程實現》18.4節中已經做過介紹)。下面講到的架構圖中的每一個處理邏輯都抽象爲一個算子了,並封裝在Doraemon框架中,便於業務的複用、拓展和工程維護。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了讓各個模塊之間解耦,我們大量採用消息隊列(RabbitMQ和Kafka)來傳輸消息(數據),讓整個推薦系統更加模塊化、結構化。只要定義好兩個模塊(算子)之間的(數據)交互協議,就可以獨立對各個子模塊進行優化升級而不會互相影響。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"節目倒排索引及用戶畫像是存儲在HBase集羣中,方便算法分佈式讀取,HBase的數據結構如下圖,不熟悉的讀者可以網上搜索瞭解一下。最終的推薦結果存儲在CouchBase及Redis中,個性化推薦、主題推薦這類爲每個用戶都生成一個推薦結果的產品形態,數據量會更大,推薦結果存儲在CouchBase中(一個分佈式文檔數據庫,可以方便橫向擴容),而相似視頻數據量相對較小存儲在Redis這類key-value內存數據庫中(Redis也能橫向擴容,但是Redis的數據都是放在內存中,成本更高,所以個性化推薦的結果放到CouchBase中了)。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/00/007773ff4775fa2ebf832fec9b01d6f1.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"圖5:HBase數據結構","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有了上面的背景知識介紹,現在我們來正式介紹各類算法的工程實現細節,我們先講解個性化推薦。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.3.1 個性化推薦","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"個性化推薦分爲離線模塊和實時模塊兩部分,離線部分每天更新一次,爲全量用戶生成推薦結果,而實時部分基於用戶實時的行爲實時更新推薦列表。離線推薦和實時推薦相互配合,”交替進行“(嚴格不是交替進行,在離線任務運行過程中,只要有用戶在使用產品,實時推薦也是在運行的,只不過離線一般在凌晨跑,跑的時間也不會很長,這時用戶比較少,其他時間都是實時推薦在起作用,所以簡述爲交替進行),爲用戶提供全天候的推薦服務(見下面圖6)。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fc/fc8137317d83efcc792805dd6bdcf7dc.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"圖6:離線推薦&實時推薦”交替“,離線每天更新一次,兩次離線推薦之間採用實時推薦","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下圖是基於標籤的個性化推薦的整體架構,分兩條線,一條線從媒資系統生成節目標籤的倒排索引,另一條線從用戶行爲日誌生成基於標籤的用戶興趣畫像,最終倒排索引和用戶畫像供推薦程序(算子5)使用,爲用戶生成推薦。這裏爲了簡單起見,我們只考慮基於用戶畫像來爲用戶做推薦,不考慮其他的各種召回策略,更多的召回策略放到第四節來講解。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/52/529ed880cdbbad4f504e3e7935c98516.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"圖7:基於標籤的個性化推薦整體架構","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"整個算法實現主要包括大5核心模塊(對應上圖中標註1、2、3、4、5的5個算子),每個算子是作爲一個獨立程序運行的,互不影響,其中算子5是最核心的推薦模塊。我們來分別描述一下各個模塊的核心功能及工程實現。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(1) 新增節目及標籤注入","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"媒資系統是視頻行業的內容管理系統,負責所有內容的管理、運營、輸出。推薦系統依賴媒資系統的內容來源。基於標籤的視頻推薦系統從消息隊列中獲取新增/修改的節目及標籤信息,利用這些消息來構建","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"標籤節目","attrs":{}},{"type":"text","text":"倒排索引表。該模塊將推薦需要依賴的信息通過消息的方式發送到消息隊列的固定topic中,後續模塊通過監聽該topic來獲取新的消息做進一步處理。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面圖7給出了消息的一個簡化版本,消息通過json的方式來組織,包括type(是新入庫的節目還是對老節目標籤的更新)、sid(節目唯一標識)、title(節目標題)、tags(標籤)。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b2/b21c7df900d38427e9612f52e672b27f.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"圖8:消息隊列中消息的結構","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"標籤也是有唯一識別標識的,即是上圖中的tid,類似視頻的sid,在構建倒排索引及用戶畫像過程中通過使用標籤的tid可以簡化比較及處理邏輯,減少存儲空間。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"標籤是有層級結構的,電視貓的標籤就有","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"分類標籤、欄目標籤、內容標籤","attrs":{}},{"type":"text","text":"三級體系,從粗到細,這個層級結構跟行業有很大關係,不同行業有不同的分級策略和方法。標籤也是有權重的,權重衡量標籤對節目的重要程度。在實際做算法時可以整合這些信息,讓算法更加精準。本文爲了簡化起見,不考慮分級的標籤,只考慮平展化的一級標籤。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過消息隊列來獲取消息的好處有兩點:首先,可以將媒資系統跟推薦系統解耦(一般是兩個不同的團隊來負責),方便兩邊系統獨立擴展和升級,只要保持消息格式不變,不影響兩邊業務。其次,通過消息隊列來傳輸信息,可以讓系統做到更加實時。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在該項目中(1)對接的消息隊列採用RabbitMQ,這一模塊可以由媒資團隊來提供基礎服務,由媒資團隊來維護,算法團隊可以給媒資團隊提需求,按照推薦算法需要的字段及規範提供數據即可。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(2) 生成標籤節目倒排索引","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"該步驟(近)實時從消息隊列中獲取節目的標籤信息,爲每個節目構建","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"標籤節目","attrs":{}},{"type":"text","text":"的倒排索引,方便從節目關聯到標籤及從標籤關聯到節目。我們採用Spark Streaming流式處理組件來構建倒排索引,做到實時更新索引,索引存儲到HBase集羣中,方便後續實時處理程序分佈式讀取。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"標籤->節目倒排索引具體的數據存儲格式如下,其中tid是標籤的唯一識別碼(編號)、sid是節目的編號、publishTime是節目的發佈時間,hot(新聞)、game(遊戲)、sports(體育)是不同的短視頻類型,節目->標籤的倒排索引結構類似。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3e/3e7820bda69583d548f4bc9608fdbd6c.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"圖9:標籤->節目的HBase存儲結構","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於圖8中消息隊列中的數據結構,算子2(Spark Streaming程序)近實時(一個時間窗口幾秒鐘)處理消息隊列中新增的節目,對標籤進行簡單處理,獲得標籤與節目的對應關係,並更新到標籤->節目的倒排索引表中。由於處理操作很簡單,這裏不細說。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(3) 用戶行爲ETL並注入消息隊列","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用戶行爲日誌通過簡單的ETL處理,提取關鍵信息,並將該信息插入對應的消息隊列,供後續的構建用戶畫像模塊生成用戶畫像。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用戶行爲日誌的核心信息裏面一定要包括用戶唯一識別碼和節目sid及用戶對節目的偏好(可以用用戶觀看時長來衡量)(見下面圖10),通過節目sid我們可以從","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"節目->標籤","attrs":{}},{"type":"text","text":"倒排索引表中查到對應的標籤。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/23/23d12dc76aa4726cc2e6e75ec08b5281.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"圖10:用戶核心行爲信息","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏對接用戶行爲日誌的組件,我們採用的是Kafka,整個電視貓的日誌分爲批和流兩條鏈路,批日誌按小時通過ETL入數據倉庫,流日誌接入Kafka,供後端的實時處理業務(如實時推薦、實時報表、業務監控等)消費。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(4) 生成用戶畫像&播放歷史","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"該模塊通過從消息隊列中實時獲取用戶行爲數據,爲用戶生成基於標籤的用戶畫像及播放歷史記錄。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了能夠反映用戶長期和短期興趣,我們可以生成多個不同時間階段的畫像,如長期畫像(根據用戶過去幾個月或者更長期的行爲)、中期用戶畫像(一天到幾天時間)、短期用戶畫像(幾分鐘到幾個小時)。長期、中期用戶畫像可以採用批處理的方式,每天定時生成一次。而短期用戶畫像最好採用流式處理,實時捕捉用戶興趣變化。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用戶的歷史記錄用於記錄下用戶播放過的或者跳過的內容,這些內容對用戶來說是沒有價值的、用戶不喜歡的內容。記錄下來是爲了方便在最終推薦時過濾掉這些內容,提升用戶體驗。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面圖11是短期用戶畫像和用戶歷史行爲的HBase數據結構,算子4通過從Kafka讀取實時用戶行爲日誌,從日誌中獲取節目sid、標籤等,最終生成實時的用戶畫像和更新用戶的播放歷史記錄。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲避免誤解,這裏簡單提一下,圖7只展示了利用Spark Streaming實時的從消息隊列生成用戶畫像的流程,而離線生成畫像的部分並未展示,離線用戶畫像是利用Spark直接從數倉讀取離線行爲數據,通過類似的處理生成用戶中長期畫像的(存放在不同的HBase用戶畫像表中)。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/65/651c74714d1a20a6c1873405184302d3.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"圖11:短期用戶畫像(Persona)和用戶歷史行爲(action) HBase數據結構","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(5) 基於用戶畫像和標籤節目倒排索引爲用戶做推薦","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有了基於標籤的用戶畫像及","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"標籤->節目","attrs":{}},{"type":"text","text":"倒排索引,就可以爲用戶實時生成推薦結果了。通過用戶畫像可以獲取用戶的偏好標籤,再基於","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"標籤->節目","attrs":{}},{"type":"text","text":"倒排索引,就可以爲用戶關聯到節目了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏我們簡單介紹一下利用Spark爲用戶","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"離線","attrs":{}},{"type":"text","text":"計算推薦的方法(實時推薦在第28.4節介紹),首先Spark從HBase中讀取所有用戶行爲數據,我們將用戶分爲N個Partition,爲每個Partition內的用戶更新個性化推薦(具體流程參考下面圖12),將最終推薦結果通過Kafka插入CouchBase集羣,供推薦接口調用,返回前端展示給用戶。將用戶分爲N個Partition的目的是方便做分佈式計算,將推薦結果通過Kafka插入CouchBase是爲了將推薦過程跟接口提供服務過程解耦合。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中爲單個用戶生成個性推薦(28.2.1中的個性化推薦算法)我們可以封裝成獨立算子,每個Partition循環調用該算子,爲該Partition中的所有用戶生成個性化推薦。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3b/3bc104510704ab79df6c4fa59391036c.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"圖12:基於Spark Streaming爲用戶計算推薦業務流","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"順便說一下,最終的推薦結果除了要插入CouchBase外,還需要插入一份到HBase中,方便實時推薦模塊基於該推薦結果實時調整用戶興趣。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏的難點是怎麼基於用戶不同時間階段的興趣畫像來爲用戶生成個性化推薦,以及怎麼保證內容的多樣性,並且要整合用戶實時的反饋,爲用戶提供近實時的個性化推薦。詳細的分析我們會在下一節的召回、排序、實時更新策略中講解。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.3.2 相似視頻推薦","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下圖是相似視頻推薦的整體架構,包含3個部分(對應下圖1、2、3三個算子),其中1、2跟個性化推薦完全一樣,這裏不再講解。下面只針對3來說明。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/66/66345943b16881de20259774f444d377.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"圖13:基於標籤的相似視頻推薦整體架構","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(1) 基於倒排索引生成相似推薦","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在前面一節我們已經講解過怎麼計算視頻相似度了,在這裏我們簡單描述一下計算視頻相似度的業務流程。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當消息隊列中有新視頻注入時,從節目倒排索引表中將所有節目及其標籤取出,與新注入的節目計算相似度,得到最終的TopN最相似的節目。這個相似推薦列表會插入HBase一份(具體的數據結構見下面圖14),同時通過Kafka消息隊列插入一份到Redis,插入Redis的這份作爲最終推薦結果,供接口調用返回前端提供給用戶。插入HBase的這份相似推薦,會用於實時個性化推薦,根據用戶實時行爲更新用戶推薦列表,具體怎麼用會在下一節實時更新策略中講解。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/76/76698b1359238d10c3a334708e6cf806.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"圖14:相似視頻在HBase的數據結構","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面我們針對單個節目怎麼利用Spark Streaming來計算topN相似度做簡單說明。首選將所有需要與節目A計算相似度的節目取出存放到一個RDD中,在計算時,所有節目分佈在N個Partition中,我們分別計算A與每個Partition中節目的topN相似度,最終將N個Partition中topN相似度合併,獲得最終的topN推薦,整個過程參考下面圖15。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1a/1ab36cc8b783091c26d73cf1415181ab.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"圖15:基於Spark Streaming計算topN相似度算法邏輯","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於新聞、體育等時效性要求高的短視頻,沒必要將庫中所有的視頻都取出來,只需要取最近幾天的就可以了,這樣可以大大減少計算量。即使取出來了也可以先過濾掉不包含A節目的標籤的節目(因爲是基於標籤計算相似度,如果B節目的標籤跟A節目的標籤都不一樣,相似度肯定爲0),再計算相似度,也會少好多計算量(因爲標籤是稀疏的)。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了上面的計算外,還需要處理一種情況:我們需要更新已經計算過相似度的視頻的相似度列表,這是因爲新加入的節目A可能與節目B的相似度比B的相似度列表中的節目相似度更大,這時更新B的相似度列表是必要的。具體更新策略我們這裏不講,在下一章《基於Erlang語言的相似視頻推薦系統》中有很詳細的講解,用Spark做這個更新的過程是類似的,只是實現方式不一樣。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面講的整體架構是實時爲新視頻生成相似推薦列表。當我們第一次啓動工程或者爲新的短視頻類型做相似推薦時,是需要一次性計算所有的視頻相似度的。可行的方法有兩個:一是將所有視頻導入到消息隊列中採用實時的計算相似度程序計算,另外一種方式是實現一套離線的計算相似度的程序,只用於工程啓動或者新增視頻類型第一次計算相似度的情形。第一種方法可能一段時間導致隊列堆積,特別是視頻總量比較大的情況下,我們團隊是採用的第二種方案。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.3.3 主題推薦","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲用戶生成主題推薦的整體架構跟個性化推薦類似,我們需要獲取用戶的一批偏好標籤,通過標籤再關聯到一組節目。唯一的不同是,個性化推薦會將所有標籤及標籤關聯的節目根據權重合並在一起形成一個彙總的推薦列表,而主題推薦將每個偏好標籤形成一個主題,而每個標籤關聯的節目就是這個主題的推薦。主題推薦相比於個性化推薦,工程實現更加簡單,這裏不再贅述。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.4 個性化推薦的召回與排序策略","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在上一節整體架構介紹中,我們講解了怎麼基於用戶畫像和節目標籤倒排索引爲用戶做個性化推薦,重點聚焦在怎麼根據用戶興趣偏好來爲用戶生成滿足用戶興趣偏好的推薦。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在本節我們來深入介紹一下怎麼利用更多的召回策略來爲用戶生成更加多樣性的推薦,覆蓋用戶多樣性的興趣需要,同時講解怎麼實時捕捉用戶的興趣變化。由於短視頻每條時長短,提供多樣性的推薦的策略是很有必要的。只根據用戶興趣推薦會導致“越推薦越窄”的現象,不利於內容的分發及用戶體驗的升級。通過推薦多樣性的內容,既可以拓展用戶的興趣空間,也更利於內容分發。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下圖是短視頻推薦召回和排序的流程,首先通過多種召回策略來爲用戶生成推薦,通過排序策略來將這些內容糅合在一起推薦給用戶。下面我們分別對召回策略和排序策略進行講解。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/9a/9a5b0d076546e6a7c1b2e90aa7a7caf7.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"圖16:個性化推薦召回與排序","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.4.1 召回策略","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於短視頻來說,除了基於用戶的興趣來爲用戶做推薦外,還可以通過多種方式來爲用戶做推薦,具體來說,可行的召回策略至少有如下6類:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(1) 基於用戶近期興趣的召回","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於短視頻來說,特別是新聞,用戶的興趣是隨着時間變化的,用戶的興趣也會受到熱點事件的影響,所以我們有必要基於過去較短時間(幾天甚至更短時間內)生成用戶的興趣畫像,在推薦中整合用戶的近期興趣。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(2)基於用戶長期興趣的召回","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用戶的興趣也是穩定及緩慢變化的,這要求我們可以爲用戶生成較長期(幾個月或者更長)的興趣畫像,在推薦中整合用戶長期興趣。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(3)基於用戶地域的召回","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在電視貓APP我們根據用戶IP是知道用戶所在地區的,很多內容是有地域屬性的,用戶也傾向於關注本地相關的信息,所以我們可以基於用戶的地域,爲用戶召回匹配特定地域的內容(部分內容是有地域標籤的,即使沒有地域標籤,我們也可以統計某個地區播放top榜,進而獲得該地區的熱門節目)。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(4) 基於用戶最後一個節目的關聯召回","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用戶最後喜歡的的節目(用戶看完了、有強烈的喜歡偏好),代表了用戶最近的興趣點,那麼我們完全有理由猜測用戶喜歡該節目的相似節目,所以我們可以將該節目相似的節目推薦給用戶作爲召回。電視貓實時個性化推薦採用了該召回策略。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(5) 基於新熱的召回","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"人對未知的好奇的特性決定了人對新的東西會感興趣,而人從衆的一面又決定了我們很大概率會喜歡大家都喜歡的東西。所以爲用戶召回出新熱內容是一種非常保險的策略。一般這類召回也會作爲新用戶的默認推薦,用於解決冷啓動問題。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(6) 基於差異化類別的召回","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了避免給用戶推薦的內容太窄,我們有必要爲用戶推薦多樣性的內容,挖掘用戶新的興趣點。我們可以將內容按照標籤分成多類(分類要滿足不同類的內容差異性較大),從每類中隨機篩選出幾個節目彙總起來形成一個“大雜燴”,作爲一種滿足用戶多樣化需求的召回策略。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於某些產品,如果有關注某個頻道或者某個作者的功能,這些頻道或者作者來源的內容也可以作爲一種召回策略。另外,時間對用戶的興趣也是有影響的,不同的內容可能適合在不同時段觀看,所以也可以基於時間爲用戶生成相關的推薦作爲一種召回策略。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.4.2 排序策略","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面介紹完了各種可行的召回策略,那麼這麼多的召回方案召回的節目怎麼推薦給用戶呢?肯定是不可能一股腦兒都推薦給用戶的。我們需要對這些召回的內容進行整合、過濾、篩選、排序形成一個更加精細化的列表推薦給用戶,這就是排序策略需要解決的問題。排序策略最終的目的是爲了提升推薦列表的點擊率,提升用戶的體驗。一般來說說排序策略可以分爲基於規則的排序和基於模型的排序,我們在這裏分別做簡單介紹。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(1) 基於規則的排序","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於規則的排序主要是基於運營或者人工策略來進行排序,比較主觀,需要一定的業務常識和行業經驗。比如可以從上面的6種召回策略中每種取一個,循環選取,直到達到最終給用戶推薦的數目爲止。假設下面","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/eb/eb0be1d2b9acdd3cbba45b2730c263d2.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"是六個召回列表,那麼","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"就是按照上面循環排序的策略。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ae/aee1cb1a3f01f4b0de7845fee82a270d.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ab/ab48d03155028b9bedb88044977dcb8f.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8f/8f94c5386af48d2f233a13b011b37b2a.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/39/39099fdde16806c1838cee1d4694c6e4.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/88/88d039040ac4762a9e60ba9df1136055.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/07/070310fff301914f05e7523d5b6fdf41.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6e/6e38782bdf76c584753f73837bc39703.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面只是給出了一種最直觀簡單的排序策略,根據不同的產品形態及業務形式還有其他各種不同的排序和合並策略,比如,可以給不同的隊列不同的權重,採用一定的概率選擇一個隊列,不同隊列也可以選擇不同數量的節目。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(2) 基於模型的排序","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於模型的排序,方法跟上面的規則不一樣,通過用戶行爲數據訓練一個機器學習模型(logistic迴歸、深度學習等),該模型可以爲每個用戶、節目對輸出一個用戶對該節目偏好的概率或者評分,最終會根據所有召回隊列中節目的概率或者評分來降序排列,並將排在前面的TopN推薦給用戶。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於模型的方法更加客觀可靠,不會受到很多主觀因素的影響,可以整合用戶在產品上的所有行爲數據及用戶自身和標的物的數據,一般來說效果會更好。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不同召回策略可能會召回重複的內容,我們在排序階段還需要考慮過濾掉重複的內容。排序策略還跟具體的產品交互方式有關,比如今日頭條APP採用下滑的方式,每次下滑更新12條新的內容,這12條新內容即是根據各類召回策略來爲用戶統一提供推薦。對於電視貓這類OTT端的採用遙控器交互的產品,我們採用圖1這種“無限”右滑的方式來跟用戶交互。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"講解完了召回和排序策略,下面針對電視貓短視頻個性化推薦,我們來詳細講解怎麼基於用戶實時行爲爲用戶近實時更新推薦列表。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.4.3 電視貓個性化推薦實時更新策略","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面我們對電視貓短視頻實時個性化推薦的排序方案進行簡單描述,供讀者參考。電視貓的推薦分爲離線推薦和實時推薦兩部分。在離線階段,每天會根據上述基於規則的方式生成推薦列表,爲用戶推薦200個節目。當用戶在使用過程中會實時更新用戶的推薦列表,整合用戶實時的興趣變化。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"某貓實時更新的架構圖,算子1根據用戶行爲日誌生成實時用戶行爲信息並同步到消息隊列,算子2從消息隊列獲取待更新的用戶及操作行爲,按照一定的規則來更新原來的推薦列表。推薦列表備份一份在HBase中,在具體更新某個用戶的推薦時讀取HBase中該用戶的推薦列表,對推薦列表進行調整整合用戶實時興趣變化,調整完後更新到HBase中,同時再通過Kafka同步一份到CouchBase中,供推薦接口返回前端展示給用戶,這樣用戶的推薦列表就真正更新了,用戶就可以感知到推薦的實時變化了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們來說說具體怎麼根據用戶最近的行爲更新推薦列表的。我們將給用戶推薦的200個視頻看成是一個環,每20個節目看成一頁,當用戶起播時,根據用戶在第一頁的播放行爲(第一頁20個節目中用戶會播自己感興趣的,不感興趣的會跳過,每一頁的內容是根據離線階段用不同的召回策略及規則排序策略生成的推薦)。我們採用Spark Streaming來處理,假設5秒是一個窗口(Window),當在下一個窗口計算時,在第二頁最前面插入用戶在第一頁感興趣的節目的相似節目,插入的節目數量跟用戶在第一個窗口播放過的加上跳過的一樣多,同時第一個窗口播放過的和跳過的節目從環中剔除,由於刪除的和插入的一樣多,總隊列還是保持200個。這時從當前用戶播放的位置開始是新的第一頁,回到了隊列最初的狀態,整個過程是一個可以“無限右滑”的環。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.5 冷啓動策略","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於標籤的相似視頻推薦可以很好地規避冷啓動問題,因爲任何新注入的視頻都是包含標籤的,並且我們是近實時爲新節目計算相似視頻,在極短的時間內就會爲新節目計算出相似推薦。本節我們來說說實時個性化推薦冷啓動問題。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲是基於內容的推薦,冷啓動問題沒有那麼嚴重,只要用戶看過一個視頻,這個視頻的標籤就是用戶的興趣標籤,我們可以爲用戶推薦具備該標籤的節目。但是,如果用戶一個節目都沒看,那要怎麼爲用戶做推薦呢?我們可以採用如下3大策略:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(1) 利用新熱節目作爲推薦;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(2) 基於用戶特徵(比如用戶地域)來爲用戶生成相關推薦列表;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(3) 從所有視頻中選擇具備不同類別標籤的視頻推薦給用戶,總有一款是用戶喜歡的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.6 未來優化方向","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於標籤的推薦算法在電視貓APP上整體效果還不錯,人均播放節目數近100個,人均播放時長近1小時,但是還有很多地方是可以做得更好的,現在列舉一些可能的優化點,作爲後續優化的方向,也供讀者參考。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.6.1 增加模型排序模塊","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"雖然該算法有很多召回策略,但是最終排序展示給用戶時是根據人工規則進行的,實時更新也是基於規則的,多少有一些主觀,可行的優化方向是增加一層實時模型排序算法,將多個人工召回策略丟給排序模塊進行算法排序,將排序好的結果推薦給用戶。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於模型的排序策略是根據用戶點擊行爲及各類特徵進行訓練的,可以更好地反應用戶點擊情況,增加用戶的點擊概率。Google提出的","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"FTRL","attrs":{}},{"type":"text","text":"(Follow-the-regularized-Leader)算法可以有效地構建實時的排序模型,對多類召回結果進行排序,目前在國內互聯網公司有大量應用案例,有興趣的讀者可以參考文獻11。目前很多深度學習算法(如Wide & Deep)也大量用於推薦排序中。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.6.2 對重複的節目做過濾","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"特別是新聞、短視頻類APP,會從不同源獲取相關內容,不同來源的內容有可能是重複的,簡單的方法是通過標題來判定兩個內容是否重複,雖然相對簡單一些,但是某些時候不一定可靠,比如兩個視頻標題差別較大,但是實際上內容是很重複的。這時就需要通過視頻內容來判定是否重複了,但是這樣處理成本相對太高。所以,通過標題來區分代價相對較小,精度還可以接受。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"處理重複的方法一般有兩種:事先處理和事後處理。事先處理就是在新視頻入庫時,從所有節目庫中排查是否有重複的節目,如果有就丟棄,否則插入。一般可以採用爲每個視頻生成信息指紋,方便做比對。事後處理就是在生成推薦列表後,再做一次過濾,將重複的視頻去掉只保留其中一個。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.6.3 整合用戶負反饋","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果用戶播放某個視頻直接切換到下一個,或者播放很短時間就不播放了,這是一個用戶不喜歡的信號。那麼在基於標籤的算法中,我們怎麼整合這種負反饋呢?一種可行的策略是,對該視頻包含的標籤做負向處理,即如果用戶畫像中包含該標籤,那麼我們可以從該標籤的權重中減去一個數值,代表對該標籤的懲罰。目前在電視貓的短視頻推薦算法中是沒有整合負反饋機制的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"28.6.4 針對標籤的優化","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於標籤的推薦算法,標籤的質量直接關係到推薦的質量。在實際業務中標籤是存在一些問題的,主要表現爲如下幾個方面:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(1) 標籤之間是有相關關係的,比如恐怖和驚悚就有相似的含義;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(2) 有些標籤出現特別頻繁而有些又出現特別稀少;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"針對(1),我們可以儘量將意思相近的標籤合併,讓不同標籤意思有一定的區分度。針對(2),我們可以剔除掉出現非常稀少的標籤(比如只有幾個視頻纔有的標籤),這些標籤有可能是髒數據,對計算相似度幫助不大,對於出現太過頻繁的標籤(非常多的節目具備該標籤),這類標籤區分度也不大,建議也可以剔除掉,不參與計算推薦。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"到此爲止,基於標籤的實時視頻推薦系統講完了,整個算法及工程實現細節基本上是基於作者在電視貓短視頻推薦的經驗總結而成(當前電視貓的短視頻推薦算法已經有了重大升級,不過大體思路還是類似的,所以本章現在也具備較大的參考價值)。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於標籤的算法是一類非常常用的推薦算法,算法原理簡單,可解釋性強,也易於實現實時個性化推薦,所以在真實業務中得到大量使用。通過作者團隊使用經驗,基於標籤的推薦算法效果還是很不錯的,今日頭條的推薦也是將基於標籤的推薦算法作爲核心模塊之一。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於標籤的推薦算法最大的問題是強依賴於標籤的質量,標籤質量的好壞直接影響算法效果。如果要做好標籤推薦,需要根據相關業務事先定義好一套完善的標籤體系,需要投入極大的人力成本,並且對團隊NLP方面的技術也有較高的要求。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"參考文獻","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. Real-Time Top-N Recommendation in Social Streams","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. TencentRec- Real-time Stream Recommendation in Practice","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. Real-time Video Recommendation Exploration","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4. Tag-aware recommender systems based on deep neural networks","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5. Tag-aware recommender systems by fusion of collaborative filtering algorithms","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"6. Tag-Aware Personalized Recommendation Using a Hybrid Deep Model","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"7. Content-based recommendation in social tagging systems  ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"8. Real-time Attention Based Look-alike Model for Recommender System","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"9. 【書】Big Data Principles and Best Practices of Scalable Realtime Data Systems","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"10. Real-time Personalization using Embeddings for Search Ranking at Airbnb","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"11. Ad Click Prediction- a View from the Trenches","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章