日均處理數(shù)億推薦請求,平均耗時(shí)30毫秒,58同城推薦系統(tǒng)是怎么做到的?
58 同城作為中國最大的分類信息網(wǎng)站,向用戶提供找房子、找工作、二手車和黃頁等多種生活信息。在這樣的場景下,推薦系統(tǒng)能夠幫助用戶發(fā)現(xiàn)對自己有價(jià)值的信息,提升用戶體驗(yàn),本文將介紹 58 同城智能推薦系統(tǒng)的技術(shù)演進(jìn)和實(shí)踐。
58 同城智能推薦系統(tǒng)大約誕生于 2014 年(C++實(shí)現(xiàn)),該套系統(tǒng)先后經(jīng)歷了招聘、房產(chǎn)、二手車、黃頁和二手物品等產(chǎn)品線的推薦業(yè)務(wù)迭代,但該系統(tǒng)耦合性高,難以適應(yīng)推薦策略的快速迭代。
58 同城 APP 猜你喜歡推薦和推送項(xiàng)目在 2016 年快速迭代,產(chǎn)出了一套基于微服務(wù)架構(gòu)的推薦系統(tǒng)(Java 實(shí)現(xiàn)),該系統(tǒng)穩(wěn)定、高性能且耦合性低,支持推薦策略的快速迭代,大大提高了推薦業(yè)務(wù)的迭代效率。
此后,我們對舊的推薦系統(tǒng)進(jìn)行了重構(gòu),將所有業(yè)務(wù)接入至新的推薦系統(tǒng),最終成功打造了統(tǒng)一的 58 同城智能推薦系統(tǒng)。
下面我們將對 58 同城智能推薦系統(tǒng)展開進(jìn)行介紹,首先會(huì)概覽整體架構(gòu),然后從算法、系統(tǒng)和數(shù)據(jù)三方面做詳細(xì)介紹。
推薦系統(tǒng)的整體架構(gòu)
首先看一下 58 同城推薦系統(tǒng)整體架構(gòu),一共分?jǐn)?shù)據(jù)層、策略層和應(yīng)用層三層,基于 58 平臺(tái)產(chǎn)生的各類業(yè)務(wù)數(shù)據(jù)和用戶積累的豐富的行為數(shù)據(jù),我們采用各類策略對數(shù)據(jù)進(jìn)行挖掘分析,最終將結(jié)果應(yīng)用于各類推薦場景。
數(shù)據(jù)層
主要包括業(yè)務(wù)數(shù)據(jù)和用戶行為日志數(shù)據(jù)。業(yè)務(wù)數(shù)據(jù)主要包含用戶數(shù)據(jù)和帖子數(shù)據(jù),用戶數(shù)據(jù)即 58 平臺(tái)上注冊用戶的基礎(chǔ)數(shù)據(jù),這里包括 C 端用戶和企業(yè)用戶的信息,帖子數(shù)據(jù)即用戶在 58 平臺(tái)上發(fā)布的帖子的基礎(chǔ)屬性數(shù)據(jù)。
這里的帖子是指用戶發(fā)布的房源、車源、職位、黃頁等信息,為方便表達(dá),后文將這些信息統(tǒng)稱為帖子。
用戶行為日志數(shù)據(jù)來源于在前端和后臺(tái)的埋點(diǎn),例如用戶在 APP 上的篩選、點(diǎn)擊、收藏、打電話、微聊等各類操作日志。
這些數(shù)據(jù)都存在兩種存儲(chǔ)方式,一種是批量存儲(chǔ)在 HDFS 上以用作離線分析,一種是實(shí)時(shí)流向 Kafka 以用作實(shí)時(shí)計(jì)算。
策略層
基于離線和實(shí)時(shí)數(shù)據(jù),首先會(huì)開展各類基礎(chǔ)數(shù)據(jù)計(jì)算,例如用戶畫像、帖子畫像和各類數(shù)據(jù)分析。
在這些基礎(chǔ)數(shù)據(jù)之上便是推薦系統(tǒng)中最重要的兩個(gè)環(huán)節(jié):召回和排序。
召回環(huán)節(jié)包括多種召回源的計(jì)算,例如熱門召回、用戶興趣召回、關(guān)聯(lián)規(guī)則、協(xié)同過濾、矩陣分解和 DNN 等。
我們采用機(jī)器學(xué)習(xí)模型來做推薦排序,先后迭代了 LR、FM、GBDT、融合模型以及 DNN,基于這些基礎(chǔ)機(jī)器學(xué)習(xí)模型,我們開展了點(diǎn)擊率、轉(zhuǎn)化率和停留時(shí)長多指標(biāo)的排序。
這一層的數(shù)據(jù)處理使用了多種計(jì)算工具,例如使用 MapReduce 和 Hive 做離線計(jì)算,使用 Kylin 做多維數(shù)據(jù)分析,使用 Spark、DMLC 做大規(guī)模分布式機(jī)器學(xué)習(xí)模型訓(xùn)練,使用 theano 和 tensorflow 做深度模型訓(xùn)練。
應(yīng)用層
我們通過對外提供 rpc 和 http 接口來實(shí)現(xiàn)推薦業(yè)務(wù)的接入。58 同城的推薦應(yīng)用大多是向用戶展示一個(gè)推薦結(jié)果列表,屬于 topN 推薦模式,這里介紹下 58 同城的幾個(gè)重要的推薦產(chǎn)品:
猜你喜歡:58 同城最重要的推薦產(chǎn)品,推薦場景包括 APP 首頁和不同品類的大類頁,目標(biāo)是讓用戶打開 APP 或進(jìn)入大類頁時(shí)可以快速找到他們想要的帖子信息,這主要根據(jù)用戶的個(gè)人偏好進(jìn)行推薦。
詳情頁相關(guān)推薦:用戶進(jìn)入帖子詳情頁,會(huì)向用戶推薦與當(dāng)前帖子相關(guān)的帖子。該場景下用戶意圖較明顯,會(huì)采用以當(dāng)前帖子信息為主、用戶偏好信息為輔的方式進(jìn)行推薦。
搜索少無結(jié)果推薦:用戶會(huì)通過品類列表頁上的篩選項(xiàng)或搜索框進(jìn)入品類列表頁獲取信息,若當(dāng)前篩選項(xiàng)或搜索條件搜索出的結(jié)果較少或者沒有結(jié)果,便會(huì)觸發(fā)推薦邏輯進(jìn)行信息推薦。
此時(shí)會(huì)結(jié)合當(dāng)前搜索條件的擴(kuò)展以及用戶偏好信息進(jìn)行推薦。
個(gè)性化推送(Push):在用戶打開 APP 前,將用戶感興趣的信息推送給他們,促使用戶點(diǎn)擊,提高用戶活躍度。這里包含推送通知的生成和推送落地頁上帖子列表的生成兩個(gè)推薦邏輯。
值得一提的是推送是強(qiáng)制性的推薦,會(huì)對用戶形成騷擾,因此如何降低用戶騷擾并給用戶推薦真正感興趣的信息尤為重要。
Feed 流推薦:我們的推薦產(chǎn)品在某些推薦場景下是以 Feed 流的形式展現(xiàn)的,例如 APP 消息中心的今日推薦場景、推送落地頁場景。
用戶可以在這些頁面中不斷下拉刷新消費(fèi)信息,類似時(shí)下火熱的各大資訊 Feed 流推薦。
推薦系統(tǒng)是一個(gè)復(fù)雜的工程,涉及算法策略、工程架構(gòu)和效果數(shù)據(jù)評(píng)估三方面的技術(shù),后文將分別從這三方面介紹 58 同城推薦系統(tǒng)。
推薦系統(tǒng)的算法
推薦涉及了前端頁面到后臺(tái)算法策略間的各個(gè)流程,我們將推薦流程抽象成如下圖所示的召回、排序、規(guī)則和展示四個(gè)主要環(huán)節(jié):
- 召回環(huán)節(jié),使用各種算法邏輯從海量的帖子中篩選出用戶感興趣的帖子候選集合,一般集合大小是幾十到上百。
- 排序環(huán)節(jié),對候選集合中的帖子進(jìn)行打分排序,這里一般會(huì)使用機(jī)器學(xué)習(xí)排序模型,排序環(huán)節(jié)會(huì)生成一個(gè)排序列表。
- 規(guī)則環(huán)節(jié),我們可能對排序列表采取一定的規(guī)則策略,最終生成一個(gè)包含 N 條結(jié)果的列表。
- 例如在規(guī)則環(huán)節(jié),我們可能會(huì)采取不同的去重策略,如文本去重、圖片去重、混合去重等,可能會(huì)采取不同的列表打散策略,可能會(huì)迭代產(chǎn)品經(jīng)理提出的各種規(guī)則邏輯。
- 由于推薦系統(tǒng)的最終評(píng)價(jià)是看統(tǒng)計(jì)效果,因此各種人為的規(guī)則都會(huì)影響最終結(jié)果,我們抽象出規(guī)則環(huán)節(jié)后便可以對任何邏輯做線上 ABTest,最終評(píng)價(jià)相關(guān)邏輯是否合理。
- 展示環(huán)節(jié),生成 N 條推薦結(jié)果列表后,不同的前端展示方式也會(huì)影響最終的推薦效果。
例如不同的 UI 設(shè)計(jì),采用大圖模式還是小圖模式,頁面上展示哪些字段都會(huì)影響用戶在推薦列表頁上的點(diǎn)擊,因此在推薦產(chǎn)品迭代過程中不同的展示樣式迭代也很重要。
在上述的四個(gè)環(huán)節(jié)中,召回和排序是推薦系統(tǒng)最重要的兩個(gè)環(huán)節(jié)。規(guī)則和展示樣式一般變化周期較長,而召回和排序有很大的挖掘空間,會(huì)被不斷的迭代,我們的推薦算法工作也主要是圍繞召回和排序進(jìn)行。
下圖是我們推薦算法的整體框架,主要包括基礎(chǔ)數(shù)據(jù)的計(jì)算以及上層的召回策略和排序模型的迭代。
基礎(chǔ)數(shù)據(jù)計(jì)算主要包括用戶標(biāo)簽和帖子標(biāo)簽的挖掘,這部分工作由用戶畫像、搜索和推薦多個(gè)團(tuán)隊(duì)共同完成,最終各團(tuán)隊(duì)共享數(shù)據(jù)。
基于用戶注冊時(shí)填寫的基礎(chǔ)屬性信息和用戶行為日志,可以挖掘出用戶人口屬性和興趣偏好信息,如用戶的年齡、性別、學(xué)歷、收入等基礎(chǔ)屬性,用戶感興趣的地域商圈、二手房均價(jià)、廳室、裝修程度等偏好信息。
帖子標(biāo)簽挖掘包括提取帖子的固定屬性、挖掘衍生屬性以及計(jì)算動(dòng)態(tài)屬性。固定屬性直接從帖子數(shù)據(jù)庫提取即可,如分類、地域、標(biāo)題、正文、圖片、房源價(jià)格、廳室、小區(qū)等。
我們還會(huì)基于貼子信息是否完備、價(jià)格是否合理、圖片質(zhì)量好壞、發(fā)帖人質(zhì)量等多個(gè)維度來計(jì)算帖子質(zhì)量分。
基于用戶行為日志數(shù)據(jù)可以計(jì)算帖子的 PV、UV、點(diǎn)擊率、轉(zhuǎn)化率、停留時(shí)長等動(dòng)態(tài)屬性。這些數(shù)據(jù)最終會(huì)在召回環(huán)節(jié)和排序環(huán)節(jié)使用,例如基于用戶標(biāo)簽和帖子標(biāo)簽可以進(jìn)行興趣召回,將用戶標(biāo)簽和帖子標(biāo)簽作為特征迭代機(jī)器學(xué)習(xí)模型。
召回主要負(fù)責(zé)生成推薦的候選集,我們采用多種召回源融合的方式來完成該過程。我們先后迭代了如下各類召回策略:
- 熱門召回。基于曝光和點(diǎn)擊日志,我們會(huì)計(jì)算不同粒度的熱門數(shù)據(jù)。以二手車業(yè)務(wù)線為例,從粗粒度到細(xì)粒度的數(shù)據(jù)包括:城市下的熱門商圈、商圈下的熱門車系和品牌、特定車系和品牌下的熱門車源等。
每一個(gè)車源的熱度,我們通過最近一段時(shí)間內(nèi)帖子的 PV、UV、CTR 等指標(biāo)來衡量,這里的 CTR 會(huì)通過貝葉斯和 COEC 做平滑處理。熱門召回策略會(huì)在冷啟動(dòng)時(shí)被大量采用。
- 地域召回。58 同城是向用戶提供本地生活服務(wù)類信息,用戶的每次訪問都會(huì)帶上地域信息,如選擇的城市、定位的地點(diǎn)等。我們主要結(jié)合地域信息和熱門數(shù)據(jù)做召回,如附近最新或最熱帖子召回、城市熱門帖子召回等。
- 興趣召回。基于帖子基礎(chǔ)屬性字段和帖子標(biāo)簽信息,我們構(gòu)建了一套帖子檢索系統(tǒng),通過該系統(tǒng)能夠以標(biāo)簽或?qū)傩宰侄螜z索出最新發(fā)布的帖子。在用戶畫像中,我們計(jì)算了每個(gè)用戶的興趣標(biāo)簽。
因此基于用戶興趣標(biāo)簽便能在檢索系統(tǒng)中檢索出一批帖子,這可以作為一種召回源。
此外,在帖子詳情頁相關(guān)推薦場景中,我們也可以利用當(dāng)前帖子的屬性和標(biāo)簽信息去檢索系統(tǒng)中檢索出相關(guān)帖子作為召回?cái)?shù)據(jù)源。這兩種檢索召回就是我們常說的基于內(nèi)容的推薦。
- 關(guān)聯(lián)規(guī)則。這里并非直接采用傳統(tǒng) Apriori、FP-growth 關(guān)聯(lián)規(guī)則算法,而是參考關(guān)聯(lián)規(guī)則思想,將最近一段時(shí)間中每個(gè)用戶點(diǎn)擊所有物品當(dāng)做一次事務(wù),由此計(jì)算兩兩物品之間的支持度,并在支持度中融入時(shí)間衰減因子。
最終可以得到每個(gè)物品的 topK 個(gè)關(guān)聯(lián)性強(qiáng)的物品。這種召回方式類似協(xié)同過濾中的 item 相似度矩陣計(jì)算,我們主要將其應(yīng)用在詳情頁相關(guān)推薦中。
- 協(xié)同過濾。我們使用 Spark 實(shí)現(xiàn)了基于 User 和基于 Item 的批量協(xié)同過濾計(jì)算,由于數(shù)據(jù)量大,批量計(jì)算會(huì)較消耗時(shí)間,我們又實(shí)現(xiàn)了基于 Item 的實(shí)時(shí)協(xié)同過濾算法。
通常情況下,我們會(huì)直接將用戶的推薦結(jié)果列表作為一種召回源,而在詳情頁相關(guān)推薦場景,我們還會(huì)使用協(xié)同過濾計(jì)算出的 Item 相似度矩陣,將帖子最相似的 topK 個(gè)帖子也作為一種召回源。
- 矩陣分解。我們引入了 SVD 算法,將用戶對帖子的點(diǎn)擊、收藏、分享、微聊和電話等行為操作看作用戶對帖子進(jìn)行不同檔次的評(píng)分,從而構(gòu)建評(píng)分矩陣數(shù)據(jù)集來做推薦。
- DNN召回。Google 在 YouTube 視頻推薦上使用了 DNN 來做召回,我們也正在進(jìn)行相關(guān)嘗試,通過 DNN 來學(xué)習(xí)用戶向量和帖子向量,并計(jì)算用戶最相近的 topK 個(gè)帖子做為召回源。
上述不同的召回算法都產(chǎn)生出了一部分推薦候選數(shù)據(jù),我們需要將不同的召回?cái)?shù)據(jù)融合起來以提高候選集的多樣性和覆蓋率。
這里我們主要使用兩種召回融合策略:
- 分級(jí)融合。設(shè)置一個(gè)候選集目標(biāo)數(shù)量值,然后按照效果好壞的次序選擇候選物品,直至滿足候選集大小。
假設(shè)召回算法效果好壞的順序是 A、B、C、D,則優(yōu)先從 A 中取數(shù)據(jù),不足候選集目標(biāo)數(shù)量時(shí)則從 B 中取數(shù)據(jù),依次類推。
我們的系統(tǒng)支持分級(jí)融合策略的配置化,不同召回算法的先后順序可以靈活配置。
這里的效果好壞順序是根據(jù)離線評(píng)價(jià)和線上評(píng)價(jià)來決定的,例如離線我們會(huì)比較不同召回算法的召回率和準(zhǔn)確率,線上我們會(huì)比較最終點(diǎn)擊或轉(zhuǎn)化數(shù)據(jù)中不同召回算法的覆蓋率。
- 調(diào)制融合。按照不同的比例分別從不同召回算法中取數(shù)據(jù),然后疊加產(chǎn)生最終總的候選集。
我們的系統(tǒng)也支持調(diào)制融合策略的配置化,選擇哪些召回算法、每種召回算法的選擇比例均可以靈活配置。這里的比例主要根據(jù)最終線上點(diǎn)擊或轉(zhuǎn)化數(shù)據(jù)中不同召回算法的覆蓋率來設(shè)置。
召回環(huán)節(jié),新召回源的添加或者新融合策略的上線,例如開發(fā)了一種新召回算法、需要修改調(diào)制融合策略中的配比等,我們都會(huì)做線上 ABTest,最終通過比較不同策略的效果來指導(dǎo)我們的迭代。
值得一提的是,召回環(huán)節(jié)我們還會(huì)有一些過濾規(guī)則,例如過濾低質(zhì)量帖子、在某些特定場景下對召回算法產(chǎn)生的結(jié)果加一些條件限制等。
排序環(huán)節(jié),我們主要采用 Pointwise 方法,為每個(gè)帖子打分并進(jìn)行排序,通過使用機(jī)器學(xué)習(xí)模型預(yù)估帖子的點(diǎn)擊率、轉(zhuǎn)化率和停留時(shí)長等多指標(biāo)來做排序。
早期,我們主要優(yōu)化點(diǎn)擊率,目前我們不僅關(guān)注點(diǎn)擊率外,還會(huì)注重轉(zhuǎn)化率的提高。在 58 同城的產(chǎn)品場景中,轉(zhuǎn)化主要指用戶在帖子詳情頁上的微聊、打電話操作。
排序離線流程主要包括樣本生成和選擇、特征抽取、模型訓(xùn)練和評(píng)價(jià):
- 首先對埋點(diǎn)日志中的曝光、點(diǎn)擊、轉(zhuǎn)化和停留時(shí)長等數(shù)據(jù)做抽取解析,如基于曝光序列號(hào)關(guān)聯(lián)各類操作、解析埋點(diǎn)參數(shù)(例如日志中記錄的實(shí)時(shí)特征)、解析上下文特征等,并同時(shí)打上 label,生成模型樣本。
- 然后對樣本進(jìn)行過濾,例如過濾惡意用戶樣本、過濾無效曝光樣本等。然后對樣本做特征抽取,生成帶特征的樣本,我們主要從用戶、帖子、發(fā)帖人和上下文四個(gè)維度做特征工程。
- 之后,按照一定正負(fù)樣本比例做采樣,最終進(jìn)行模型訓(xùn)練和評(píng)估,離線評(píng)估指標(biāo)主要參考 AUC,離線效果有提升后會(huì)進(jìn)行 ABTest 上線,逐步迭代。
我們先后迭代上線了如下排序策略:
- 規(guī)則序。早期未上線機(jī)器學(xué)習(xí)模型時(shí),對候選集中的帖子會(huì)直接使用刷新時(shí)間、統(tǒng)計(jì) CTR 或者一些產(chǎn)品規(guī)則來做排序。
- 單機(jī)器學(xué)習(xí)模型。我們最早實(shí)踐的是 LR 模型,它是線性模型,簡單高效、可解釋性好,但對特征工程要求較高,需要我們自己做特征組合來增強(qiáng)模型的非線性表達(dá)能力,早期我們使用 LibLinear 來訓(xùn)練模型,后來遷移到了 Spark 上。
之后我們引入了 XGBoost 樹模型,它非線性表達(dá)能力強(qiáng)、高效穩(wěn)定,是目前開源社區(qū)里最火熱的模型之一,最初我們采用單機(jī)版本訓(xùn)練,后期將 XGBoost 部署在我們的 yarn 集群上,使用分布式版本進(jìn)行訓(xùn)練。
同時(shí),我們應(yīng)用了 FM 模型,相比于 LR 模型它引進(jìn)了特征組合,能夠解決大規(guī)模稀疏數(shù)據(jù)下的特征組合問題,我們主要使用分布式 FM (DiFacto,F(xiàn)M on Yarn)來進(jìn)行模型訓(xùn)練。
上述這些模型都是批量更新,通常是一天更新一次,為了快速捕捉用戶行為的變化,我們還引入 Online Learning 模型,主要嘗試應(yīng)用 FTRL 方式去更新 LR 模型,在某些場景下獲得了穩(wěn)定的效果提升。
- 融合模型。類似 Facebook、Kaggle 的做法,我們實(shí)踐了 GBDT+LR 和 GBDT+FM 的模型融合方案。
首先利用 XGBoost 對原始特征做處理生成高階特征,然后輸入到 LR 和 FM 模型中,目前我們的點(diǎn)擊率預(yù)估模型中效果最佳的是 GBDT+LR 融合模型,轉(zhuǎn)化率預(yù)估模型中效果最佳的是 GBDT+FM 融合模型。
此外,我們還會(huì)嘗試將某個(gè)單指標(biāo)(如點(diǎn)擊率)下多個(gè)模型的預(yù)測結(jié)果進(jìn)行融合(如相加或相乘等),也會(huì)將多個(gè)指標(biāo)(點(diǎn)擊率、轉(zhuǎn)化率和停留時(shí)長)的模型進(jìn)行融合(如相乘)以觀察效果。
- 深度模型。深度學(xué)習(xí)正逐漸被各大公司應(yīng)用于推薦系統(tǒng)中,我們也正在進(jìn)行嘗試。目前,我們已將 FNN(Factorisation machine supported neuralnetwork)模型應(yīng)用在我們的推薦排序中。
相比單機(jī)器學(xué)習(xí)模型,F(xiàn)NN 有較穩(wěn)定的效果提升,但比融合模型效果要稍差,目前我們正在進(jìn)行深度模型的調(diào)優(yōu),并在嘗試引入Wide&Deep等其他深度模型。
基于上述基礎(chǔ)機(jī)器學(xué)習(xí)工具,目前我們主要會(huì)迭代點(diǎn)擊率、轉(zhuǎn)化率和停留時(shí)長預(yù)估模型,線上會(huì) ABTest 上線單指標(biāo)模型、多指標(biāo)融合模型,以提高推薦效果。
推薦系統(tǒng)的后臺(tái)架構(gòu)
對于推薦系統(tǒng)來說,一套支撐算法策略高效迭代的推薦后臺(tái)系統(tǒng)至關(guān)重要,我們基于微服務(wù)架構(gòu)設(shè)計(jì)了推薦后臺(tái)系統(tǒng),它擴(kuò)展性好、性能高。
系統(tǒng)架構(gòu)如下圖所示,系統(tǒng)分為數(shù)據(jù)層、邏輯層和接入層,數(shù)據(jù)層提供各類基礎(chǔ)數(shù)據(jù)的讀取,邏輯層實(shí)現(xiàn)召回和排序策略并支持不同策略的 ABTest,接入層對外提供了通用的訪問接口。
數(shù)據(jù)層提供推薦邏輯所需要的各類數(shù)據(jù),這些數(shù)據(jù)存儲(chǔ)在 WRedis、文件、WTable 等多種設(shè)備上,我們將所有數(shù)據(jù)的讀取都封裝成 RPC 服務(wù),屏蔽了底層的存儲(chǔ)細(xì)節(jié)。
這里包括檢索服務(wù)、召回源讀取服務(wù)、帖子特征中心和用戶特征中心:
- 檢索服務(wù)。我們搭建了一套搜索引擎用做召回檢索,支持基于各類搜索條件去檢索數(shù)據(jù),例如可以檢索出價(jià)格在 200 萬至 300 萬之間的回龍觀兩室的房源、檢索出中關(guān)村附近的最新房源。
該服務(wù)主要應(yīng)用于這幾類場景:在猜你喜歡推薦場景中基于用戶標(biāo)簽去檢索帖子、在相關(guān)推薦場景中基于當(dāng)前帖子屬性去檢索相關(guān)帖子、冷啟動(dòng)時(shí)基于地域信息召回附近的帖子等。
- 召回源讀取服務(wù)。提供各類召回源數(shù)據(jù)的讀取,這些召回源數(shù)據(jù)通過離線或?qū)崟r(shí)計(jì)算的到,包括熱門數(shù)據(jù)、協(xié)同過濾數(shù)據(jù)、關(guān)聯(lián)規(guī)則數(shù)據(jù)、矩陣分解結(jié)果等。該服務(wù)設(shè)計(jì)得較靈活,支持任意召回源的增加。
- 帖子特征中心。提供帖子所有屬性字段的讀取,在召回、排序和推薦主體邏輯中會(huì)使用到這些帖子屬性,一般情況我們會(huì)在召回環(huán)節(jié)讀取出所有帖子屬性,然后應(yīng)用于排序和規(guī)則邏輯中。
召回得到的候選集大小一般是幾十到幾百,為了支持高性能的批量讀取,我們選擇使用 WRedis 集群存儲(chǔ)帖子屬性,并通過多線程并發(fā)讀取、緩存、JVM 調(diào)優(yōu)等多項(xiàng)技術(shù)保證服務(wù)性能。
目前,該服務(wù)每天承接數(shù)億級(jí)請求,平均每次讀取 150 條數(shù)據(jù),耗時(shí)保證在 2ms 之內(nèi)。
- 用戶特征中心。UserProfile 數(shù)據(jù)包括用戶離線/實(shí)時(shí)興趣標(biāo)簽、人口屬性等,該數(shù)據(jù)會(huì)在召回環(huán)節(jié)使用,例如使用用戶興趣標(biāo)簽去檢索帖子作為一種召回源,也會(huì)在排序環(huán)節(jié)使用,例如將用戶標(biāo)簽作為機(jī)器學(xué)習(xí)排序模型的特征。
邏輯層實(shí)現(xiàn)了詳細(xì)的推薦策略,包括推薦主體服務(wù)、召回服務(wù)、排序服務(wù)和 ABTest 實(shí)驗(yàn)中心。
這些服務(wù)由不同的開發(fā)人員維護(hù),保證了推薦策略的高效迭代,例如召回和排序是我們經(jīng)常迭代的環(huán)節(jié),由不同的算法人員來完成,召回服務(wù)和排序服務(wù)的分離降低了耦合,提高了迭代效率。
- 推薦主體服務(wù)。接收推薦請求,解析推薦場景參數(shù),調(diào)用用戶特征中心獲取用戶信息,請求 ABTest 實(shí)驗(yàn)中心獲取對應(yīng)場景的 ABTest 實(shí)驗(yàn)參數(shù),如召回策略號(hào)、排序算法號(hào)、規(guī)則號(hào)和展示號(hào)。
然后將推薦場景參數(shù)、ABTest 實(shí)驗(yàn)參數(shù)等發(fā)送至召回服務(wù)獲得候選集列表,之后再調(diào)用排序服務(wù)對候選集進(jìn)行排序,最終對排序列表做相關(guān)規(guī)則處理,將結(jié)果列表封裝返回。
- 召回服務(wù)。接收場景參數(shù)和召回策略號(hào)參數(shù),調(diào)用檢索服務(wù)和召回源讀取服務(wù)讀取各類召回?cái)?shù)據(jù),并進(jìn)行分級(jí)融合或調(diào)制融合。
我們實(shí)現(xiàn)了召回策略的配置化,一個(gè)召回號(hào)對應(yīng)一種召回策略,策略采用哪種融合方式、每種融合方式下包含哪些召回源、不同召回源的數(shù)量均通過配置來完成。
我們將召回配置進(jìn)行 Web 化,算法或產(chǎn)品人員只需在 Web 頁面上配置即可生效策略。此外,召回層還包括一些過濾規(guī)則,例如過濾低質(zhì)量信息、過濾用戶歷史瀏覽記錄、過濾產(chǎn)品指定的符合某些特定條件的數(shù)據(jù)等。
- 排序服務(wù)。接收場景參數(shù)、用戶信息、候選集列表和排序算法號(hào)等參數(shù),調(diào)用機(jī)器學(xué)習(xí)排序模塊,對候選集列表做排序。
我們設(shè)計(jì)了一套通用的特征提取框架,保證機(jī)器學(xué)習(xí)離線模型訓(xùn)練和線上排序共用相同的特征提取代碼,并靈活支持不同模型之間的特征共享。
在排序服務(wù)中上線一種模型成本很低,只需要提供模型文件和特征配置文件即可,后續(xù)我們將會(huì)對排序配置進(jìn)行 Web化,簡化上線流程。
目前,我們的排序服務(wù)中運(yùn)行了基于 LR、XGBoost、FM、XGBoost+LR、XGBoost+FM、DNN 的幾十個(gè)排序模型。
- ABTest 實(shí)驗(yàn)中心。我們設(shè)計(jì)了一套靈活通用的 ABTest 實(shí)驗(yàn)平臺(tái)(內(nèi)部稱作“日晷”)來支持推薦系統(tǒng)的策略迭代,它包括流量控制、實(shí)時(shí)效果數(shù)據(jù)統(tǒng)計(jì)和可視化等功能,支持用戶在 Web 頁面上配置實(shí)驗(yàn)和流量,并能展示實(shí)時(shí)效果數(shù)據(jù)。
這套實(shí)驗(yàn)平臺(tái)不僅可以應(yīng)用于推薦系統(tǒng),還可以用于任何其他需要做 ABTest 實(shí)驗(yàn)的業(yè)務(wù)系統(tǒng)中,它支持多層 ABTest 實(shí)驗(yàn),能充分利用每份流量去完成業(yè)務(wù)迭代。
例如我們的推薦系統(tǒng) ABTest 實(shí)驗(yàn)就包含召回、排序、規(guī)則和展示四層,不同層之間實(shí)現(xiàn)了流量的重新打散,保證了不同層之間實(shí)驗(yàn)的正交性。
當(dāng)請求到達(dá)我們的推薦系統(tǒng)時(shí),推薦主體服務(wù)便請求“日晷”以獲得該請求對應(yīng)的召回號(hào)、排序號(hào)、規(guī)則號(hào)和展示號(hào)等實(shí)驗(yàn)參數(shù)。
之后該請求便會(huì)被這些實(shí)驗(yàn)參數(shù)打上標(biāo)記,貫穿于后續(xù)的推薦流程,決定每層中將走哪部分邏輯,最終這些實(shí)驗(yàn)參數(shù)會(huì)記錄到后臺(tái)和客戶端埋點(diǎn)日志中,用于最終的實(shí)驗(yàn)效果統(tǒng)計(jì)。
接入層直接和客戶端交互,從客戶端接收請求并調(diào)用推薦主體服務(wù)獲得推薦帖子 ID 列表,然后查詢出帖子詳細(xì)屬性返回給客戶端做展示。
在大部分推薦場景中,接入層由業(yè)務(wù)方維護(hù),可能是 PHP 或 Java 實(shí)現(xiàn)的 http 接口;也有少部分場景的接入層是我們自主維護(hù),我們采用 58 自研的 MVC 框架 WF 實(shí)現(xiàn)了相關(guān) http 接口。
我們采用 58 自研的 RPC 框架 SCF 實(shí)現(xiàn)了上述微服務(wù)架構(gòu)的推薦系統(tǒng),采用 58 自研的監(jiān)控系統(tǒng) WMonitor 實(shí)現(xiàn)了推薦系統(tǒng)的立體監(jiān)控,整個(gè)技術(shù)棧是 Java。
我們采用多線程、異步、緩存、JVM 調(diào)優(yōu)、降級(jí)、限流等措施保證了推薦系統(tǒng)的穩(wěn)定和高可用,目前我們的推薦系統(tǒng)日均處理數(shù)億的推薦請求,平均耗時(shí)約 30 毫秒。
推薦系統(tǒng)的數(shù)據(jù)
這里的數(shù)據(jù)主要指推薦埋點(diǎn)數(shù)據(jù)和推薦效果數(shù)據(jù):
- 埋點(diǎn)數(shù)據(jù)是推薦系統(tǒng)的基石,模型訓(xùn)練和效果數(shù)據(jù)統(tǒng)計(jì)都基于埋點(diǎn)數(shù)據(jù),需保證埋點(diǎn)數(shù)據(jù)的正確無誤。
- 效果數(shù)據(jù)是對推薦系統(tǒng)的評(píng)價(jià),指引推薦策略的迭代,構(gòu)建完備的效果數(shù)據(jù)體系至關(guān)重要。
我們的推薦埋點(diǎn)日志數(shù)據(jù)包括曝光日志、點(diǎn)擊日志、轉(zhuǎn)化日志和頁面停留時(shí)長日志等,這些日志數(shù)據(jù)都需要客戶端通過埋點(diǎn)來產(chǎn)生。
這里簡單解釋一下這些操作的含義:
- 客戶端請求一次推薦接口得到推薦結(jié)果列表叫做一次曝光。
- 用戶點(diǎn)擊推薦結(jié)果列表上的某條帖子進(jìn)入帖子詳情頁叫做一次點(diǎn)擊。
- 用戶在帖子詳情頁上進(jìn)行微聊、打電話、收藏等操作叫做轉(zhuǎn)化。
- 用戶在帖子詳情頁上的閱讀時(shí)間叫做頁面停留時(shí)長。這里的曝光、點(diǎn)擊和轉(zhuǎn)化是一個(gè)漏斗,操作數(shù)量是逐漸遞減的趨勢。
由于 58 同城上用戶對帖子的訪問可能來源于推薦、搜索和運(yùn)營活動(dòng)頁等場景,為了標(biāo)識(shí)出推薦產(chǎn)生的點(diǎn)擊/轉(zhuǎn)化/停留時(shí)長,我們需要在埋點(diǎn)中加入推薦相關(guān)的參數(shù)。
我們將埋點(diǎn)參數(shù)設(shè)計(jì)成一個(gè)固定格式的字符串,它包含了曝光唯一序列號(hào)、推薦位標(biāo)識(shí)、召回號(hào)、排序號(hào)、規(guī)則號(hào)、展示號(hào)、帖子 ID 列表、帖子 ID 等字段,這些字段將會(huì)作用于機(jī)器學(xué)習(xí)模型訓(xùn)練樣本生成和推薦效果統(tǒng)計(jì)中。
埋點(diǎn)參數(shù)主要分為列表參數(shù)和單貼參數(shù)兩類:
- 推薦接口返回一個(gè)帖子列表,會(huì)對應(yīng)返回一個(gè)列表參數(shù),包含了曝光序列號(hào)、推薦位標(biāo)識(shí)、召回號(hào)、排序號(hào)、規(guī)則號(hào)、展示號(hào)、帖子 ID 列表等字段。
- 返回的帖子列表中,每個(gè)帖子會(huì)對應(yīng)返回一個(gè)單貼參數(shù),包含曝光序列號(hào)、推薦位標(biāo)識(shí)、召回號(hào)、排序號(hào)、規(guī)則號(hào)、展示號(hào)、帖子ID等字段。
客戶端得到推薦接口返回的埋點(diǎn)參數(shù)后,會(huì)將列表參數(shù)埋入到曝光日志中,將單貼參數(shù)埋入到點(diǎn)擊日志、轉(zhuǎn)化日志和停留時(shí)長日志當(dāng)中,注意這里埋點(diǎn)時(shí)需要推薦列表頁向帖子詳情頁傳遞單貼參數(shù),一般需要通過修改跳轉(zhuǎn)協(xié)議來實(shí)現(xiàn)。
最終埋點(diǎn)日志中有了這些參數(shù)后,我們便可基于曝光唯一序列號(hào)將曝光、點(diǎn)擊、轉(zhuǎn)化、時(shí)長數(shù)據(jù) Join 起來,產(chǎn)生模型訓(xùn)練樣本以及漏斗效果數(shù)據(jù)。
值得一提的是,我們采取透傳的方式在推薦后臺(tái)、接入層、客戶端間傳遞埋點(diǎn)參數(shù)字符串,所有埋點(diǎn)參數(shù)由推薦系統(tǒng)后臺(tái)生成,接入層和客戶端均不做任何處理。
埋點(diǎn)參數(shù)僅由我們推薦一方負(fù)責(zé),這樣能夠避免多方改動(dòng)埋點(diǎn)參數(shù),從而減少埋點(diǎn)錯(cuò)誤的可能性,由于是透傳處理,也便于今后埋點(diǎn)參數(shù)的擴(kuò)展。
埋點(diǎn)數(shù)據(jù)是推薦系統(tǒng)的基石,不能有遺漏或者錯(cuò)誤,這就要求我們嚴(yán)格把控開發(fā)測試流程,尤其是 APP 上的埋點(diǎn),若發(fā)版之后發(fā)現(xiàn)有錯(cuò)誤,便要等到下一次發(fā)版時(shí)解決。
客戶端開發(fā)和測試同事不清楚埋點(diǎn)參數(shù)的含義但熟練掌握測試環(huán)境部署及擁有 Android 和 IOS 測試機(jī),而推薦后臺(tái)同事清楚埋點(diǎn)參數(shù)含義但對測試環(huán)境較生疏并缺乏測試機(jī)。
因此我們總結(jié)出了測試同事負(fù)責(zé)環(huán)境部署、推薦后臺(tái)同事負(fù)責(zé)檢驗(yàn)埋點(diǎn)參數(shù)的測試流程,詳細(xì)流程如下圖所示。
此外,58 同城上的 APP 開發(fā)比較復(fù)雜,不同產(chǎn)品線各自開發(fā)自己的 APP 業(yè)務(wù)模塊,APP 平臺(tái)方開發(fā)主模塊,每次發(fā)版前都有一個(gè)集成階段,合并所有業(yè)務(wù)方提交的代碼,產(chǎn)生最終的 APP 包,集成階段很可能會(huì)發(fā)生業(yè)務(wù)方埋點(diǎn)未生效的情況。
因此,我們的埋點(diǎn)測試包括業(yè)務(wù)方內(nèi)部測試和集成測試兩個(gè)階段,以保證埋點(diǎn)萬無一失。
我們的推薦效果數(shù)據(jù)是一個(gè)多維數(shù)據(jù)集,我們主要關(guān)注推薦位上的點(diǎn)擊、轉(zhuǎn)化、停留時(shí)長等指標(biāo)。
日常工作中我們需要從不同業(yè)務(wù)線、不同客戶端、不同推薦位、不同推薦算法等多個(gè)維度去分析這些指標(biāo)數(shù)據(jù)。
例如
我們會(huì)觀察房產(chǎn)和車在相同推薦位上的數(shù)據(jù)對比、猜你喜歡場景上不同召回或排序算法的數(shù)據(jù)對比、二手房詳情頁在 Android 和 iPhone 上數(shù)據(jù)對比等。
各種數(shù)據(jù)分析對比能幫助我們優(yōu)化推薦策略,甚至能發(fā)現(xiàn)某些業(yè)務(wù)線功能邏輯上的隱藏 Bug。
在我們推薦項(xiàng)目攻堅(jiān)階段,我們通過分析比較二手房詳情頁在 Android 和 iPhone 兩端的推薦效果,發(fā)現(xiàn)了 iPhone 上詳情頁瀏覽回退的 Bug,最終反饋給業(yè)務(wù)方并解決了該問題,該 Bug 的解決使得我們在二手房詳情頁推薦位上的推薦點(diǎn)擊量提高了數(shù)十萬。
我們從離線和實(shí)時(shí)兩方面構(gòu)建推薦效果數(shù)據(jù),數(shù)據(jù)統(tǒng)計(jì)流程如下圖所示:
早期,離線效果數(shù)據(jù)統(tǒng)計(jì)是通過 MapReduce + Hive + MySQL 來實(shí)現(xiàn)的。
我們首先會(huì)編寫 MapReduce 程序?qū)υ悸顸c(diǎn)日志進(jìn)行抽取生成 Hive 表,然后會(huì)編寫大量的 Hive SQL 來統(tǒng)計(jì)各類指標(biāo)數(shù)據(jù),并將結(jié)果數(shù)據(jù)寫入 MySQL 數(shù)據(jù)表,最終做可視化展示和郵件報(bào)表。
由于我們比較的維度和指標(biāo)多,Hive SQL 語句的編寫消耗了我們不少人力。在數(shù)據(jù)平臺(tái)部門部署了 Kylin 多維分析系統(tǒng)后,我們將效果數(shù)據(jù)統(tǒng)計(jì)工作遷移到了 Kylin 上。
我們只需要設(shè)計(jì)好 Hive 源數(shù)據(jù)表,并設(shè)置好維度和度量,Kylin 便能根據(jù)維度和度量來自動(dòng)預(yù)計(jì)算結(jié)果數(shù)據(jù),這省去了我們編寫 Hive SQL的工作,大大提高了效率。
實(shí)時(shí)效果數(shù)據(jù),我們采用 Storm + HBase 來計(jì)算,實(shí)時(shí)效果數(shù)據(jù)主要用于異常埋點(diǎn)監(jiān)控、新上線推薦算法效果快速反饋、模型異常監(jiān)控等。
我們實(shí)現(xiàn)了一個(gè)包含較少維度的多維數(shù)據(jù)統(tǒng)計(jì),今后我們將嘗試引入 Druid 等實(shí)時(shí)多維分析系統(tǒng)來完善推薦實(shí)時(shí)效果數(shù)據(jù)的建設(shè)。
總結(jié)
本文介紹了 58 同城智能推薦系統(tǒng)在算法、工程和數(shù)據(jù)三方面的技術(shù)演進(jìn)。我們在最近一年加快了推薦業(yè)務(wù)的迭代速度,接入了房產(chǎn)、車等業(yè)務(wù)線在 APP、PC、M 三端共計(jì)近百個(gè)推薦位。
我們的推薦點(diǎn)擊占比指標(biāo)(推薦位上產(chǎn)生的點(diǎn)擊量在總體點(diǎn)擊量中的占比)相比一年之前提高了 2~3 倍,達(dá)到了 20%~30%,每天能夠產(chǎn)生數(shù)千萬的推薦點(diǎn)擊量,為業(yè)務(wù)線帶來了流量提升。
任何推薦系統(tǒng)的發(fā)展必會(huì)經(jīng)歷推薦位擴(kuò)充和推薦算法深入優(yōu)化兩個(gè)階段,流量指標(biāo)可以通過擴(kuò)充推薦位來快速提高,當(dāng)推薦位穩(wěn)定之后,就需要依賴更加深入的算法優(yōu)化來繼續(xù)提高指標(biāo),而此時(shí)的效果提升也會(huì)相對緩慢。
目前,我們的流量指標(biāo)已相對穩(wěn)定,我們會(huì)更進(jìn)一層去關(guān)注轉(zhuǎn)化指標(biāo),提高用戶進(jìn)入帖子之后與發(fā)帖人進(jìn)行微聊或電話溝通的可能性,幫助用戶找到真正有用的信息。