知識(shí)分享|超詳細(xì):完整的推薦系統(tǒng)架構(gòu)設(shè)計(jì)
發(fā)布時(shí)間:2023-09-15 15:12:00
架構(gòu)設(shè)計(jì)概述
架構(gòu)設(shè)計(jì)是一個(gè)很大的話題,這里只討論和推薦系統(tǒng)相關(guān)的部分。更具體地說(shuō),我們主要關(guān)注的是算法以及其他相關(guān)邏輯在時(shí)間和空間上的關(guān)系——這樣一種邏輯上的架構(gòu)關(guān)系。
在前面的章節(jié)中我們講到了很多種算法,每種算法都是用來(lái)解決整個(gè)推薦系統(tǒng)流程中的某個(gè)問(wèn)題的。我們的最終目標(biāo)是將這些算法以合理的方式組合起來(lái),形成一整套系統(tǒng)。在這個(gè)過(guò)程中,可用的組合方式有很多,每種方式都有舍有得,但每種組合方式都可被看作一種架構(gòu)。這里要介紹的就是一些經(jīng)過(guò)實(shí)踐檢驗(yàn)的架構(gòu)層面的最佳實(shí)踐,以及對(duì)這些最佳實(shí)踐在不同應(yīng)用場(chǎng)景下的分析。除此之外,還希望能夠通過(guò)把各種推薦算法放在架構(gòu)的視角和場(chǎng)景下重新審視,讓讀者對(duì)算法間的關(guān)系有更深入的理解,從全局的角度看待推薦系統(tǒng),而不是只看到一個(gè)個(gè)孤立的算法。
架構(gòu)設(shè)計(jì)的本質(zhì)之一是平衡和妥協(xié)。一個(gè)推薦系統(tǒng)在不同的時(shí)期、不同的數(shù)據(jù)環(huán)境、不同的應(yīng)用場(chǎng)景下會(huì)選擇不同的架構(gòu),在選擇時(shí)本質(zhì)上是在平衡一些重要的點(diǎn)。下面介紹幾個(gè)常用的平衡點(diǎn)。
1. 個(gè)性化 vs 復(fù)雜度
個(gè)性化是推薦系統(tǒng)作為一個(gè)智能信息過(guò)濾系統(tǒng)的安身立命之本,從最早的熱榜,到后來(lái)的公式規(guī)則,再到著名的協(xié)同過(guò)濾算法,最后到今天的大量使用機(jī)器學(xué)習(xí)算法,其主線之一就是為用戶提供個(gè)性化程度越來(lái)越高的體驗(yàn),讓每個(gè)人看到的東西都盡量差異化,并且符合個(gè)人的喜好。為了達(dá)到這一目的,系統(tǒng)的整體復(fù)雜度越來(lái)越高,具體表現(xiàn)為使用的算法越來(lái)越多、算法使用的數(shù)據(jù)量和數(shù)據(jù)維度越來(lái)越多、機(jī)器學(xué)習(xí)模型使用的特征越來(lái)越多,等等。同時(shí),為了更好地支持這些高復(fù)雜度算法的開(kāi)發(fā)、迭代和調(diào)試,又衍生出了一系列對(duì)應(yīng)的配套系統(tǒng),進(jìn)一步增加了整個(gè)系統(tǒng)的復(fù)雜度??梢哉f(shuō)整個(gè)推薦邏輯鏈條上的每一步都被不斷地細(xì)化分析和優(yōu)化,這些不同維度的優(yōu)化橫縱交織,構(gòu)造出了一個(gè)整體復(fù)雜度非常高的系統(tǒng)。從機(jī)器學(xué)習(xí)理論的角度來(lái)類(lèi)比,如果把推薦系統(tǒng)整體看作一個(gè)巨大的以區(qū)分用戶為目標(biāo)的機(jī)器學(xué)習(xí)模型,則可以認(rèn)為復(fù)雜度的增加對(duì)應(yīng)著模型中特征維度的增加,這使得模型的 VC 維不斷升高,對(duì)應(yīng)著可分的用戶數(shù)不斷增加,進(jìn)而提高了整個(gè)空間中用戶的個(gè)性化程度。這條通過(guò)不斷提高系統(tǒng)復(fù)雜度來(lái)提升用戶個(gè)性化體驗(yàn)的路線,也是近年來(lái)推薦系統(tǒng)發(fā)展的主線之一。
2. 時(shí)效性 vs 計(jì)算量
推薦系統(tǒng)中的時(shí)效性概念體現(xiàn)在實(shí)時(shí)服務(wù)的響應(yīng)速度、實(shí)時(shí)數(shù)據(jù)的處理速度以及離線作業(yè)的運(yùn)行速度等幾個(gè)方面。這幾個(gè)速度從時(shí)效性角度影響著推薦系統(tǒng)的效果,整體上講,運(yùn)行速度越快,耗時(shí)越少,得到的效果越好。這是因?yàn)轫憫?yīng)速度越快,意味著對(duì)用戶行為、物品信息變化的感知越快,感知后的處理速度越快,處理后結(jié)果的反饋就越快,最終體現(xiàn)到用戶體驗(yàn)上,就是系統(tǒng)更懂用戶,更快地對(duì)用戶行為做出了反應(yīng),從而產(chǎn)生了更好的用戶體驗(yàn)。但這些時(shí)效性的優(yōu)化,帶來(lái)的是更大的計(jì)算量,計(jì)算量又對(duì)應(yīng)著復(fù)雜的實(shí)現(xiàn)邏輯和更多的計(jì)算資源。在設(shè)計(jì)得當(dāng)?shù)那疤嵯?,這樣的付出通常是值得的。如同前面章節(jié)中介紹過(guò)的,時(shí)效性優(yōu)化是推薦系統(tǒng)中非常重要的一類(lèi)優(yōu)化方法和優(yōu)化思路,但由此帶來(lái)的計(jì)算壓力和系統(tǒng)設(shè)計(jì)的復(fù)雜度也是必須要面對(duì)的。
3. 時(shí)間 vs 空間
時(shí)間和空間之間的平衡關(guān)系可以說(shuō)是計(jì)算機(jī)系統(tǒng)中最為本質(zhì)的關(guān)系之一,在推薦系統(tǒng)中也不例外。時(shí)間和空間這一對(duì)矛盾關(guān)系在推薦系統(tǒng)中的典型表現(xiàn),主要體現(xiàn)在對(duì)緩存的使用上。緩存通常用來(lái)存儲(chǔ)一些計(jì)算代價(jià)較高以及相對(duì)靜態(tài)變化較少的數(shù)據(jù),例如用戶的一些畫(huà)像標(biāo)簽以及離線計(jì)算的相關(guān)性結(jié)果等。但是隨著越來(lái)越多的實(shí)時(shí)計(jì)算的引入,緩存的使用也越來(lái)越廣泛,常常在生產(chǎn)者和消費(fèi)者之間起到緩沖的作用,使得二者可以解耦,各自異步進(jìn)行。例如實(shí)時(shí)用戶興趣計(jì)算這一邏輯,如果沒(méi)有將之前計(jì)算的興趣緩存起來(lái),那么在每次需要用戶興趣時(shí)都要實(shí)時(shí)計(jì)算一次,并要求在較短的時(shí)間內(nèi)返回結(jié)果,這對(duì)計(jì)算性能提出了較高的要求。但如果中間有一層緩存作為緩沖,則需求方可以直接從緩存中取來(lái)結(jié)果使用。這在結(jié)果的實(shí)時(shí)性和新鮮度上雖然做了一定的妥協(xié),但卻能給性能提升帶來(lái)極大的幫助。這樣就將生產(chǎn)和消費(fèi)隔離開(kāi)來(lái),生產(chǎn)者可以根據(jù)具體情況選擇生產(chǎn)的方式和速度。當(dāng)然,仍然可以努力提高生產(chǎn)速度,生產(chǎn)速度越快,緩存給時(shí)效性帶來(lái)的損失就越小,消費(fèi)者不做任何改動(dòng)就可以享受到這一提升效果。所以說(shuō),這種利用緩存來(lái)解耦系統(tǒng),帶來(lái)性能上的提升以及開(kāi)發(fā)的便利,也是在推薦系統(tǒng)架構(gòu)設(shè)計(jì)中需要掌握的一種通用的思路。
上面介紹的一些基本性原則貫穿著推薦系統(tǒng)架構(gòu)設(shè)計(jì)的方方面面,是一些具有較高通用性的思路,掌握這些思路,可以產(chǎn)生出很多具體的設(shè)計(jì)和方法;反過(guò)來(lái),每一種設(shè)計(jì)技巧或方法,也都可以映射到一個(gè)或幾個(gè)這樣的高層次抽象原則上來(lái)。這種自頂向下的思維學(xué)習(xí)方法對(duì)于推薦系統(tǒng)的架構(gòu)設(shè)計(jì)是非常重要的,并且可以推廣到很多其他系統(tǒng)的設(shè)計(jì)中。
系統(tǒng)邊界和外部依賴
架構(gòu)設(shè)計(jì)的第一步是確定系統(tǒng)的邊界。所謂邊界,就是區(qū)分什么是這個(gè)系統(tǒng)要負(fù)責(zé)的,也就是邊界內(nèi)的部分,以及什么是這個(gè)模型要依賴的,也就是邊界外的部分。劃分清楚邊界,意味著確定了功能的邊界以及團(tuán)隊(duì)的邊界,能夠讓后期的工作都專(zhuān)注于核心功能的設(shè)計(jì)和實(shí)現(xiàn)。反之,如果系統(tǒng)邊界沒(méi)有清晰的定義,可能會(huì)在開(kāi)發(fā)過(guò)程中無(wú)意識(shí)地侵入其他系統(tǒng)中,形成冗余甚至矛盾,或者默認(rèn)某些功能別人會(huì)開(kāi)發(fā)而將其忽略掉。無(wú)論哪種情況,都會(huì)影響系統(tǒng)的開(kāi)發(fā)乃至最終的運(yùn)轉(zhuǎn)。
系統(tǒng)邊界的確定,簡(jiǎn)單來(lái)說(shuō),就是在輸入方面確定需要?jiǎng)e人給我提供什么,而在輸出方面確定我要給別人提供什么。在輸入方面,就是判斷什么輸入是需要?jiǎng)e人提供給我的,要把握的主要原則包括:
這個(gè)數(shù)據(jù)或服務(wù)是否與我的業(yè)務(wù)強(qiáng)相關(guān)。在推薦業(yè)務(wù)中用到的每個(gè)東西,并不是都與推薦業(yè)務(wù)強(qiáng)相關(guān),例如電商推薦系統(tǒng)中的商品信息,只有與推薦業(yè)務(wù)強(qiáng)相關(guān)的服務(wù)才應(yīng)該被納入推薦系統(tǒng)的邊界中。
這個(gè)數(shù)據(jù)或服務(wù)除了我的業(yè)務(wù)在使用,是否還有其他業(yè)務(wù)也在使用。例如上面說(shuō)到的商品信息服務(wù),除了推薦系統(tǒng)在使用,其他子系統(tǒng)也在廣泛使用,那么顯然它應(yīng)該是一個(gè)外部依賴。也有例外情況,例如推薦系統(tǒng)要用到一些其他系統(tǒng)都用不到的商品信息,這時(shí)候,雖然理論上應(yīng)該升級(jí)商品信息服務(wù)來(lái)支持推薦系統(tǒng),但由于其他地方都用不到這些信息,因此很多時(shí)候可能需要推薦系統(tǒng)的負(fù)責(zé)團(tuán)隊(duì)來(lái)實(shí)現(xiàn)這樣一個(gè)定制化服務(wù)。
依照此原則,圖 11-1 展示了推薦系統(tǒng)的主要外部依賴。
圖 11-1 推薦系統(tǒng)的主要外部依賴
1. 數(shù)據(jù)依賴
推薦系統(tǒng)作為一個(gè)典型的數(shù)據(jù)算法系統(tǒng),數(shù)據(jù)是其最重要的依賴。這里面主要包括用戶行為數(shù)據(jù)和物品數(shù)據(jù)兩大類(lèi),前面介紹的各種算法幾乎都是以這兩種數(shù)據(jù)作為輸入進(jìn)行計(jì)算的。這些數(shù)據(jù)除了為推薦系統(tǒng)所用,它們也是搜索、展示等其他重要系統(tǒng)的輸入數(shù)據(jù),所以作為通用的公共數(shù)據(jù)和服務(wù),顯然不應(yīng)該在推薦系統(tǒng)的邊界內(nèi)部,而應(yīng)該是外部依賴。需要特別指出的是,雖然有專(zhuān)門(mén)的團(tuán)隊(duì)負(fù)責(zé)行為數(shù)據(jù)的收集,但是收集到的數(shù)據(jù)是否符合推薦系統(tǒng)的期望卻不是一件可以想當(dāng)然的事情。例如,對(duì)于結(jié)果展示的定義,數(shù)據(jù)收集團(tuán)隊(duì)認(rèn)為前端請(qǐng)求到了結(jié)果就是展示,但對(duì)于推薦系統(tǒng)來(lái)說(shuō),只有用戶真正看見(jiàn)了才是真實(shí)的展示。其中的原因在于數(shù)據(jù)收集團(tuán)隊(duì)并不直接使用數(shù)據(jù),那么他們就無(wú)法保證數(shù)據(jù)的正確性,這時(shí)就需要具體使用數(shù)據(jù)的業(yè)務(wù)方,在這里是推薦團(tuán)隊(duì),來(lái)和他們一起確認(rèn)數(shù)據(jù)收集的邏輯是正確的。如果數(shù)據(jù)收集的邏輯不正確,后面的算法邏輯就是在做無(wú)用功。花在確保數(shù)據(jù)正確上的精力和資源,幾乎總是有收益的。
2. 平臺(tái)工具依賴
推薦系統(tǒng)是一個(gè)計(jì)算密集型的系統(tǒng),需要對(duì)各種形態(tài)的數(shù)據(jù)做各種計(jì)算處理,在此過(guò)程中,需要一整套計(jì)算平臺(tái)工具的支持,典型的如機(jī)器學(xué)習(xí)平臺(tái)、實(shí)時(shí)計(jì)算平臺(tái)、離線計(jì)算平臺(tái)、其他平臺(tái)工具等。在一個(gè)較為理想的環(huán)境中,這些平臺(tái)工具都是由專(zhuān)門(mén)的團(tuán)隊(duì)來(lái)構(gòu)建和維護(hù)的。而在一些場(chǎng)景下,推薦系統(tǒng)可能是整個(gè)組織中最早使用這些技術(shù)的系統(tǒng),推薦業(yè)務(wù)也還沒(méi)有重要和龐大到需要老板專(zhuān)門(mén)配備一個(gè)平臺(tái)團(tuán)隊(duì)為之服務(wù)的程度,在這種情況下,其中的一些平臺(tái)工具就需要推薦系統(tǒng)的團(tuán)隊(duì)自己負(fù)責(zé)來(lái)構(gòu)建和維護(hù)了。為了簡(jiǎn)化邏輯,下面我們假設(shè)這些平臺(tái)工具都是獨(dú)立于推薦系統(tǒng)存在的,屬于推薦系統(tǒng)的外部依賴。
在對(duì)外輸出方面,系統(tǒng)邊界的劃定會(huì)根據(jù)公司組織的不同有所差異。例如,在一些公司中,推薦團(tuán)隊(duì)負(fù)責(zé)的是與推薦相關(guān)的整個(gè)系統(tǒng),在輸出方面的體現(xiàn)就是從算法邏輯到結(jié)果展示,這時(shí)候系統(tǒng)的邊界就要延伸到最終的結(jié)果展示。而在另外一些公司中,前端展示是由一個(gè)大團(tuán)隊(duì)統(tǒng)一負(fù)責(zé)的,這時(shí)候推薦系統(tǒng)只需要給出要展示的物品 ID 和相關(guān)展示信息即可,前端團(tuán)隊(duì)會(huì)負(fù)責(zé)統(tǒng)一展示這些物品信息。這兩種模式?jīng)]有絕對(duì)的好壞之分,重要的是要與整個(gè)技術(shù)團(tuán)隊(duì)的規(guī)劃和架構(gòu)相統(tǒng)一。在本書(shū)中,為了敘述簡(jiǎn)便,我們不討論前端展示涉及的內(nèi)容,只專(zhuān)注于推薦結(jié)果的生產(chǎn)邏輯。
推薦系統(tǒng)的效果和性能在一定程度上取決于這些依賴系統(tǒng),所以在尋求推薦系統(tǒng)的優(yōu)化目標(biāo)時(shí),目光不能只看到推薦系統(tǒng)本身,很多時(shí)候這些依賴系統(tǒng)也是重要的效果提升來(lái)源。例如,物品信息的變更如果能被更快地通知到推薦系統(tǒng),那么推薦系統(tǒng)的時(shí)效性就會(huì)更好,給到用戶的結(jié)果也就會(huì)更好;再如,用戶行為數(shù)據(jù)收集的準(zhǔn)確性能有所提高的話,對(duì)應(yīng)的相關(guān)性算法的準(zhǔn)確性也會(huì)隨之提高。在有些情況下,外部系統(tǒng)升級(jí)會(huì)比優(yōu)化算法有更大的效果提升。當(dāng)然,推薦系統(tǒng)的問(wèn)題也可能來(lái)自這些外部的依賴系統(tǒng)。例如,前端渲染展示速度的延遲會(huì)導(dǎo)致用戶點(diǎn)擊率的顯著下降,因?yàn)檫@會(huì)讓用戶失去耐心。所以,當(dāng)推薦系統(tǒng)指標(biāo)出現(xiàn)下降時(shí),不光要從內(nèi)部找問(wèn)題,也要把思路拓展到系統(tǒng)外部,從全局的角度去找問(wèn)題。綜合來(lái)講,外部依賴的存在啟發(fā)我們要從全鏈條、全系統(tǒng)的角度來(lái)看問(wèn)題,找問(wèn)題,以及設(shè)計(jì)優(yōu)化方法。
離線層、在線層和近線層架構(gòu)
架構(gòu)設(shè)計(jì)有很多不同的切入方式,最簡(jiǎn)單也是最常用的一種方式就是先決定某個(gè)模塊或邏輯是運(yùn)行在離線層、在線層還是近線層。這三層的對(duì)比如表 11-1 所示。
任何使用非實(shí)時(shí)數(shù)據(jù)、提供非實(shí)時(shí)服務(wù)的邏輯模塊,都可以被定義為離線模塊。其典型代表是離線的協(xié)同過(guò)濾算法,以及一些離線的標(biāo)簽挖掘類(lèi)算法。離線層通常用來(lái)進(jìn)行大數(shù)據(jù)量的計(jì)算,由于計(jì)算是離線進(jìn)行的,因此用到的數(shù)據(jù)也都是非實(shí)時(shí)數(shù)據(jù),最終會(huì)產(chǎn)出一份非實(shí)時(shí)的離線數(shù)據(jù),供下游進(jìn)一步處理使用。與離線層相對(duì)的是在線層,也常被稱為服務(wù)層,這一層的核心功能是對(duì)外提供服務(wù),實(shí)時(shí)處理調(diào)用方的請(qǐng)求。這一層的典型代表是推薦系統(tǒng)的對(duì)外服務(wù)接口,接受實(shí)時(shí)調(diào)用并返回結(jié)果。在線層提供的服務(wù)是實(shí)時(shí)的,但用到的數(shù)據(jù)卻不一定局限于實(shí)時(shí)數(shù)據(jù),也可以使用離線計(jì)算好的各種數(shù)據(jù),例如相關(guān)性數(shù)據(jù)或標(biāo)簽數(shù)據(jù)等,但前提是這些數(shù)據(jù)已經(jīng)以對(duì)實(shí)時(shí)友好的形態(tài)被存儲(chǔ)起來(lái)。
近線層則處于離線層和在線層的中間位置,是一個(gè)比較奇妙的層。這一層的典型特點(diǎn)就是:使用實(shí)時(shí)數(shù)據(jù)(也會(huì)使用非實(shí)時(shí)數(shù)據(jù)),但不提供實(shí)時(shí)服務(wù),而是提供一種近實(shí)時(shí)的服務(wù)。所謂近實(shí)時(shí)指的是越快越好,但并不強(qiáng)求像在線層一樣在幾十毫秒內(nèi)給出結(jié)果,因?yàn)橥ǔT诮€層計(jì)算的結(jié)果會(huì)寫(xiě)入緩存系統(tǒng),供在線層讀取,做了一層隔離,因此對(duì)時(shí)效性無(wú)強(qiáng)要求。其典型代表是我們前面講過(guò)的實(shí)時(shí)協(xié)同過(guò)濾算法,該算法通過(guò)用戶的實(shí)時(shí)行為計(jì)算最新的相關(guān)性結(jié)果,但這些計(jì)算結(jié)果并不是實(shí)時(shí)提供給用戶的,而是要等到用戶發(fā)起請(qǐng)求時(shí)才會(huì)把最新的結(jié)果提供給他使用。
下面詳細(xì)介紹每一層的特點(diǎn)、案例和具體分析。
離線層架構(gòu)
離線層是推薦系統(tǒng)中承擔(dān)最大計(jì)算量的一個(gè)部分,很大一部分的相關(guān)性計(jì)算、標(biāo)簽挖掘以及用戶畫(huà)像挖掘工作都是在這一層進(jìn)行的。這一層的任務(wù)具有的普遍特點(diǎn)是使用大量數(shù)據(jù)以及較為復(fù)雜的算法進(jìn)行計(jì)算和挖掘。所謂大量數(shù)據(jù),通常指的是可以使用較長(zhǎng)時(shí)間段的用戶行為數(shù)據(jù)和全量的物品數(shù)據(jù);而在算法方面,可以使用較為復(fù)雜的模型或算法,對(duì)性能的壓力相對(duì)較小。對(duì)應(yīng)地,離線層的任務(wù)也有缺點(diǎn),就是在時(shí)間上存在滯后性。由于離線任務(wù)通常是按天級(jí)別運(yùn)行的,用戶行為或物品信息的變更也要等一天甚至更久才能夠被反映到計(jì)算結(jié)果中。在離線層雖然進(jìn)行的是離線作業(yè),但其生產(chǎn)出來(lái)的數(shù)據(jù)通常是被實(shí)時(shí)使用的,因此離線數(shù)據(jù)在生產(chǎn)出來(lái)之后還需要同步到方便在線層讀取的地方,例如數(shù)據(jù)庫(kù)、在線緩存等。
在具體實(shí)踐中,經(jīng)常放在離線層執(zhí)行的任務(wù)主要包括:協(xié)同過(guò)濾等行為類(lèi)相關(guān)性算法計(jì)算、用戶標(biāo)簽挖掘、物品標(biāo)簽挖掘、用戶長(zhǎng)期興趣挖掘、機(jī)器學(xué)習(xí)模型排序等。仔細(xì)分析這些任務(wù),會(huì)發(fā)現(xiàn)它們都符合上面提到的特點(diǎn)。這些任務(wù)的具體流程各不相同,但大體上都遵循一個(gè)共同的邏輯流程,如圖 11-2 所示。
圖 11-2 離線層邏輯架構(gòu)圖
在這個(gè)邏輯架構(gòu)圖中,離線算法的數(shù)據(jù)來(lái)源主要有兩大類(lèi):一類(lèi)是 HDFS/Hive 這樣的分布式文件系統(tǒng),通常用來(lái)存儲(chǔ)收集到的用戶行為日志以及其他服務(wù)器日志;另一類(lèi)是 RDBMS 這樣的關(guān)系數(shù)據(jù)庫(kù),通常用來(lái)存儲(chǔ)商品等物品信息。離線算法會(huì)從輸入數(shù)據(jù)源獲取原始數(shù)據(jù)并進(jìn)行預(yù)處理,例如,協(xié)同過(guò)濾算法會(huì)先把數(shù)據(jù)處理成兩個(gè)倒排表,LDA 算法會(huì)先對(duì)物品文本做分詞處理,等等,我們將預(yù)處理后的數(shù)據(jù)統(tǒng)一稱為訓(xùn)練數(shù)據(jù)(雖然有些離線算法并不是機(jī)器學(xué)習(xí)算法)。預(yù)處理這一步值得單獨(dú)拿出來(lái)講,這是因?yàn)楹芏嗨惴ㄓ玫降念A(yù)處理是高度類(lèi)似的,例如,文本標(biāo)簽類(lèi)算法需要先對(duì)原始文本進(jìn)行分詞或詞性標(biāo)注,行為類(lèi)相關(guān)性算法需要先將行為數(shù)據(jù)按用戶聚合,點(diǎn)擊率模型需要先將數(shù)據(jù)按照點(diǎn)擊/展示進(jìn)行聚合整理,等等。所以在設(shè)計(jì)離線挖掘的整體架構(gòu)時(shí),有必要有針對(duì)性地將數(shù)據(jù)預(yù)處理流程單獨(dú)提煉出來(lái),以方便后面的流程使用,做到更好的可擴(kuò)展性和可復(fù)用性。下一步是各種推薦算法或機(jī)器學(xué)習(xí)模型基于各自的訓(xùn)練數(shù)據(jù)進(jìn)行挖掘計(jì)算,得到挖掘結(jié)果。離線計(jì)算用到的工具通常包括 Hadoop、Spark 等,結(jié)果可能是一份協(xié)同過(guò)濾相關(guān)性數(shù)據(jù),可能是物品的文本主題特征,也可能是結(jié)果排序模型。接下來(lái),為了讓挖掘結(jié)果能夠被后面的流程所使用,需要將挖掘結(jié)果同步到不同的存儲(chǔ)系統(tǒng)中。一般來(lái)說(shuō),如果挖掘結(jié)果要被用作下游離線流程的輸入,是一份中間結(jié)果,那么通常它會(huì)被再次同步到 Hive 或 HDFS 這樣的分布式文件系統(tǒng)中;如果挖掘結(jié)果要被最終的推薦服務(wù)在線實(shí)時(shí)使用,那么它就需要被同步到 Redis 或 RDBMS 這樣對(duì)實(shí)時(shí)訪問(wèn)更為友好的存儲(chǔ)系統(tǒng)中。至此,一個(gè)完整的離線挖掘流程就完成了。
上面講到離線任務(wù)通常以天為單位來(lái)執(zhí)行,但是在很多情況下,提高作業(yè)的運(yùn)行頻率以及對(duì)應(yīng)的數(shù)據(jù)同步頻率,例如從一天一次提升到一天多次,都會(huì)對(duì)推薦系統(tǒng)的效果有提升作用,因?yàn)檫@些都可以被理解為在做時(shí)效性方面的優(yōu)化。一種極限的思想是,當(dāng)我們把作業(yè)的運(yùn)行頻率提高到極致時(shí),例如每分鐘甚至每幾秒鐘運(yùn)行一次作業(yè),離線任務(wù)就變成了近線任務(wù)。當(dāng)然,在這種情況下就需要對(duì)離線算法做相應(yīng)的修改以適應(yīng)近線計(jì)算的要求,例如前面介紹過(guò)的實(shí)時(shí)協(xié)同過(guò)濾算法就是對(duì)原始協(xié)同過(guò)濾算法的修改,以及將機(jī)器學(xué)習(xí)的模型訓(xùn)練過(guò)程從離線改為在線。
所以,雖然我們會(huì)把某些任務(wù)放到離線層來(lái)執(zhí)行,但并不代表這些任務(wù)就只能是離線任務(wù)。我們要深入理解為什么將這些任務(wù)放在離線層來(lái)執(zhí)行,在什么情況下可以提高其運(yùn)行頻率,甚至變?yōu)榻€任務(wù),以及這樣做的好處和代價(jià)是什么。只有做到這一點(diǎn),才能夠做到融會(huì)貫通,不被當(dāng)前的表象迷住眼睛。一種典型的情況是,當(dāng)實(shí)時(shí)計(jì)算或流計(jì)算平臺(tái)資源不足,或者開(kāi)發(fā)人力資源不足時(shí),我們傾向于把更多的任務(wù)放到離線層來(lái)執(zhí)行,因?yàn)殡x線計(jì)算對(duì)時(shí)效性要求較低,出錯(cuò)之后影響也較小。綜合來(lái)說(shuō),就是容錯(cuò)度較高,適合在整體資源受限的情況下優(yōu)先選擇。而隨著平臺(tái)的不斷完善,以及人力資源的不斷補(bǔ)充,就可以把一些對(duì)時(shí)效敏感的任務(wù)放到近線層來(lái)執(zhí)行,以獲得更好的收益。
近線層架構(gòu)
有了上面的鋪墊,近線層的存在理由和價(jià)值就比較明確了,從生產(chǎn)力發(fā)展的角度來(lái)看,可以認(rèn)為它是實(shí)時(shí)計(jì)算平臺(tái)工具發(fā)展到一定程度對(duì)離線計(jì)算的自然改造;而從推薦系統(tǒng)需求的角度來(lái)看,它是各種推薦算法追求實(shí)時(shí)化效果提升的一種自然選擇。
近線層和離線層最大的差異在于,它可以獲取到實(shí)時(shí)數(shù)據(jù),并有能力對(duì)實(shí)時(shí)數(shù)據(jù)進(jìn)行實(shí)時(shí)或近實(shí)時(shí)的計(jì)算。也正是由于這個(gè)特點(diǎn),近線層適合用來(lái)執(zhí)行對(duì)時(shí)效比較敏感的計(jì)算任務(wù),例如實(shí)時(shí)的數(shù)據(jù)統(tǒng)計(jì)等,以及實(shí)時(shí)執(zhí)行能夠獲得較大效果提升的任務(wù),例如一些實(shí)時(shí)的相關(guān)性算法計(jì)算或標(biāo)簽提取算法計(jì)算。近線層在計(jì)算時(shí)可使用實(shí)時(shí)數(shù)據(jù),也可使用離線生成的數(shù)據(jù),在提供服務(wù)時(shí),由于無(wú)須直接響應(yīng)用戶請(qǐng)求,因此也不用提供實(shí)時(shí)服務(wù),而是通常會(huì)將數(shù)據(jù)寫(xiě)入對(duì)實(shí)時(shí)服務(wù)友好的在線緩存中,方便實(shí)時(shí)服務(wù)讀取,同時(shí)也會(huì)同步到離線端做備份使用。
通常放在近線層執(zhí)行的任務(wù)包括實(shí)時(shí)指標(biāo)統(tǒng)計(jì)、用戶的實(shí)時(shí)興趣計(jì)算、實(shí)時(shí)相關(guān)性算法計(jì)算、物品的實(shí)時(shí)標(biāo)簽挖掘、推薦結(jié)果的去重、機(jī)器學(xué)習(xí)模型統(tǒng)計(jì)類(lèi)特征的實(shí)時(shí)更新、機(jī)器學(xué)習(xí)模型的在線更新等,這些任務(wù)通常會(huì)以如下兩種方式進(jìn)行計(jì)算。
個(gè)體實(shí)時(shí):所謂個(gè)體實(shí)時(shí),指的是每個(gè)實(shí)時(shí)數(shù)據(jù)點(diǎn)到來(lái)時(shí)都會(huì)觸發(fā)一次計(jì)算,做到真正意義上的實(shí)時(shí)。典型的工具代表是 Storm 和 Flink。
批量實(shí)時(shí):很多時(shí)候并不需要到來(lái)一個(gè)實(shí)時(shí)數(shù)據(jù)點(diǎn)就計(jì)算一次,因?yàn)檫@會(huì)帶來(lái)大量的計(jì)算和 I/O,而是可以將一定的時(shí)間窗口或一定數(shù)量的數(shù)據(jù)收集起來(lái),以小批次為單位進(jìn)行計(jì)算,這可以有效減少 I/O 量。這種妥協(xié)對(duì)于很多應(yīng)用來(lái)說(shuō),只要時(shí)間窗口不太大,就不會(huì)帶來(lái)效果的顯著下降。典型的工具代表是 Spark Streaming。
圖 11-3 展示了典型的近線層計(jì)算架構(gòu)圖。
圖 11-3 典型的近線層計(jì)算架構(gòu)圖
從數(shù)據(jù)源接入的角度來(lái)看,近線層主要使用實(shí)時(shí)數(shù)據(jù)進(jìn)行計(jì)算,這就引出了近線層和離線層的一個(gè)主要區(qū)別:近線層的計(jì)算通常是事件觸發(fā)的,而離線層的計(jì)算通常是時(shí)間觸發(fā)的。事件觸發(fā)意味著對(duì)計(jì)算擁有更多的主動(dòng)權(quán)和選擇權(quán),但時(shí)間觸發(fā)則無(wú)法主動(dòng)做出選擇。事件觸發(fā)意味著每個(gè)事件發(fā)生之后都會(huì)得到通知,但是否要計(jì)算以及計(jì)算什么是可以自己選擇的。例如,可以選擇只捕捉滿足某種條件的事件,或者等事件累積到一定程度時(shí)再計(jì)算,等等。所以,當(dāng)某個(gè)任務(wù)的觸發(fā)條件是某個(gè)事件發(fā)生之后進(jìn)行計(jì)算,那么這個(gè)任務(wù)就很適合放在近線層來(lái)執(zhí)行。例如推薦結(jié)果的去重,需要在用戶瀏覽過(guò)該物品之后將其加入一個(gè)去重集合中,這就是一個(gè)典型的事件觸發(fā)的計(jì)算任務(wù)。此外,近線層的計(jì)算是可以使用離線數(shù)據(jù)的,但前提是需要提前將這些數(shù)據(jù)同步到對(duì)實(shí)時(shí)計(jì)算友好的存儲(chǔ)系統(tǒng)中。
在近線層中執(zhí)行的典型任務(wù)包括但不限于:
特征的實(shí)時(shí)更新。例如,根據(jù)用戶的實(shí)時(shí)點(diǎn)擊行為實(shí)時(shí)更新各維度的點(diǎn)擊率特征。
用戶實(shí)時(shí)興趣的計(jì)算。根據(jù)用戶實(shí)時(shí)的喜歡和不喜歡行為計(jì)算其當(dāng)下實(shí)時(shí)興趣的變化。
物品實(shí)時(shí)標(biāo)簽的計(jì)算。例如,在第 6 章用戶畫(huà)像系統(tǒng)中介紹過(guò)的實(shí)時(shí)提取標(biāo)簽的流程。
算法模型的在線更新。通過(guò)實(shí)時(shí)消息隊(duì)列接收和拼接實(shí)時(shí)樣本,采用 FTRL 等在線更新算法來(lái)更新模型,并將更新后的模型推送到線上。
推薦結(jié)果的去重。用戶兩次請(qǐng)求之間是有時(shí)間間隔的,所以無(wú)須在處理實(shí)時(shí)請(qǐng)求時(shí)進(jìn)行去重,而是可以將這個(gè)信息通過(guò)消息隊(duì)列發(fā)送給一個(gè)專(zhuān)門(mén)的服務(wù),在近線層中處理。
實(shí)時(shí)相關(guān)性算法計(jì)算。典型的如實(shí)時(shí)協(xié)同過(guò)濾算法,按照其原理,也可以把隨機(jī)游走等行為類(lèi)算法改寫(xiě)為實(shí)時(shí)計(jì)算,放到近線層中執(zhí)行。
總結(jié)起來(lái),凡是可以和實(shí)時(shí)請(qǐng)求解耦,但需要實(shí)時(shí)或近實(shí)時(shí)計(jì)算結(jié)果的任務(wù),都可以放到近線層中執(zhí)行。
近線層的實(shí)時(shí)計(jì)算雖然沒(méi)有響應(yīng)時(shí)間的要求,但卻存在數(shù)據(jù)堆積的壓力。具體來(lái)說(shuō),近線層計(jì)算用到的數(shù)據(jù)大部分是通過(guò) Kafka 這樣的消息隊(duì)列實(shí)時(shí)發(fā)送過(guò)來(lái)的,在接收到每一個(gè)消息或消息窗口之后,如果對(duì)消息或消息窗口的計(jì)算速度不夠快,就會(huì)導(dǎo)致后面的消息堆積。這就像大家都在排隊(duì)辦理業(yè)務(wù),如果一個(gè)業(yè)務(wù)辦理得太慢,那么排的隊(duì)就會(huì)越來(lái)越長(zhǎng),長(zhǎng)到一定程度就會(huì)出問(wèn)題。所以,近線層的計(jì)算邏輯不宜過(guò)于復(fù)雜,而且近線層讀取的外部數(shù)據(jù),例如離線同步好的 Redis 中的數(shù)據(jù),也不宜過(guò)多,還有 I/O 次數(shù)不宜過(guò)多。這就要求近線層的計(jì)算邏輯和用到的數(shù)據(jù)結(jié)構(gòu)都要經(jīng)過(guò)精心的設(shè)計(jì),共同保證近線層的計(jì)算效率,以免造成數(shù)據(jù)堆積。
除了純數(shù)據(jù)統(tǒng)計(jì)類(lèi)型的任務(wù),以及結(jié)果去重這樣的無(wú)數(shù)據(jù)產(chǎn)出的任務(wù),近線層的大多數(shù)任務(wù)在離線層都有對(duì)應(yīng)的部分,二者有著明顯的優(yōu)勢(shì)和劣勢(shì),因此應(yīng)該結(jié)合起來(lái)使用。典型的如實(shí)時(shí)協(xié)同過(guò)濾算法,由于引入了實(shí)時(shí)性,使得它在一些新物品和新用戶上的效果比原始的協(xié)同過(guò)濾算法的效果好;但由于它只使用實(shí)時(shí)數(shù)據(jù),所以在稀疏性和不穩(wěn)定性方面的問(wèn)題也是比較大的,要使用離線版本的協(xié)同過(guò)濾算法作為補(bǔ)充,才能形成更全面的覆蓋。再比如在近線層執(zhí)行的用戶實(shí)時(shí)興趣預(yù)測(cè),能夠捕捉到用戶最新鮮的興趣,準(zhǔn)確率會(huì)比較高;但由于短期興趣易受展示等各種因素影響發(fā)生較大的波動(dòng),如果完全根據(jù)短期興趣來(lái)進(jìn)行推薦的話,則很有可能會(huì)陷入局部的信息繭房,產(chǎn)生高度同質(zhì)的結(jié)果,影響用戶的整體體驗(yàn)。而如果將離線計(jì)算的長(zhǎng)期興趣和短期興趣相結(jié)合,就可以有效避免這個(gè)問(wèn)題,既能利用實(shí)時(shí)數(shù)據(jù)取得高相關(guān)性,又能利用長(zhǎng)期數(shù)據(jù)取得穩(wěn)定性和多樣性。從這些例子可以看出,離線層和近線層之間并沒(méi)有不可逾越的鴻溝,二者更多的是在效率、效果、穩(wěn)定性、稀疏性等多個(gè)因素之間進(jìn)行權(quán)衡得到的不同選擇,一個(gè)優(yōu)秀的工程師應(yīng)該做到“碼中有層,心中無(wú)層”,才算是對(duì)算法和架構(gòu)做到了融會(huì)貫通。
上面講到離線層的任務(wù)在一定條件下可以放到近線層來(lái)執(zhí)行,那么類(lèi)似地,近線層的任務(wù)是否可以放到在線層來(lái)執(zhí)行呢?這個(gè)問(wèn)題其實(shí)涉及離線層、近線層這兩層作為整體和在線層的關(guān)系。如果把推薦系統(tǒng)比作一支打仗的軍隊(duì),那么在線層就是在前方?jīng)_鋒陷陣的士兵,直接面對(duì)敵人的攻擊,而離線層和近線層就是提供支持的支援部門(mén),離線層就像是生產(chǎn)糧食和軍火的大后方,近線層就像是搭橋修路的前方支援部門(mén),二者的本質(zhì)都是讓前線士兵能夠最高效、最猛烈地打擊敵人,但其業(yè)務(wù)本質(zhì)導(dǎo)致它們無(wú)法到前線去殺敵。離線層和近線層是推薦系統(tǒng)的生產(chǎn)者,在線層是推薦系統(tǒng)的消費(fèi)者(也會(huì)承擔(dān)一定的生產(chǎn)責(zé)任),它們有著截然不同的分工和定位,是無(wú)法互換的。
在線層架構(gòu)
在線層與離線層、近線層最大的差異在于,它是直接面對(duì)用戶的,所有的用戶請(qǐng)求都會(huì)發(fā)送到在線層,而在線層需要快速給出結(jié)果。如果抽離掉其他所有細(xì)節(jié),這就是在線層最本質(zhì)的東西。在線層最本質(zhì)的東西并不是在線計(jì)算部分,因?yàn)樵跇O端情況下,在接收到用戶請(qǐng)求之后,在線層可以直接從緩存或數(shù)據(jù)庫(kù)中取出結(jié)果,返回給用戶,而不做任何額外計(jì)算。而事實(shí)上,早年還沒(méi)有引入機(jī)器學(xué)習(xí)等復(fù)雜的算法技術(shù)時(shí),絕大多數(shù)計(jì)算都是在離線層進(jìn)行的,在線層就起到一個(gè)數(shù)據(jù)傳遞的作用,很多推薦系統(tǒng)基本都是這么做的,甚至?xí)r至今日,這種做法仍然是一種極端情況下的降級(jí)方案。
推薦系統(tǒng)發(fā)展到現(xiàn)在,尤其是各種機(jī)器學(xué)習(xí)算法的引入,使得我們可以使用的信息越來(lái)越多,可用的算法也越來(lái)越復(fù)雜,給用戶的推薦結(jié)果通常是融合了多種召回策略,并且又加了重排序之后的結(jié)果,而融合和重排序現(xiàn)在通常是在在線層做的。那么問(wèn)題來(lái)了:這些復(fù)雜計(jì)算一定要放到在線層做嗎?為了回答這個(gè)問(wèn)題,不妨假設(shè):如果將所有計(jì)算都放在離線層做,在線層只負(fù)責(zé)按照用戶 ID 查詢返回結(jié)果,是否可行?如果將所有計(jì)算都放在離線層做,由于不知道明天會(huì)有哪些用戶來(lái)訪問(wèn)系統(tǒng),所以就需要為每個(gè)用戶都計(jì)算出推薦結(jié)果,這要求我們計(jì)算出全平臺(tái)所有用戶的推薦結(jié)果,而對(duì)于那些明天沒(méi)有來(lái)訪問(wèn)系統(tǒng)的用戶,今天的計(jì)算就浪費(fèi)掉了。但這仍然不夠,因?yàn)槊魈爝€會(huì)有新來(lái)的用戶,這些用戶的信息在當(dāng)前計(jì)算時(shí)是拿不到的,所以,即使今天離線計(jì)算出了所有當(dāng)前用戶的推薦結(jié)果,明天也還會(huì)有大量覆蓋不到的用戶。這就是將上面提到的復(fù)雜計(jì)算一定要放在在線層做的第一個(gè)主要原因:只有按需實(shí)時(shí)計(jì)算才能覆蓋到所有用戶,并且不會(huì)產(chǎn)生計(jì)算的浪費(fèi)。從另一個(gè)角度來(lái)看,如果今天就把用戶的推薦結(jié)果完全計(jì)算出來(lái),若用戶明天的實(shí)時(shí)行為表達(dá)出來(lái)的興趣和今天的不相符,或者機(jī)器學(xué)習(xí)模型中一些關(guān)鍵特征的取值發(fā)生了變化,那么推薦結(jié)果就會(huì)不準(zhǔn)確,并且無(wú)法及時(shí)調(diào)整。例如,用戶昨天看的是手機(jī),今天打算買(mǎi)衣服,但我們昨天計(jì)算出的推薦結(jié)果是以手機(jī)為主的,那么用戶今天的需求是無(wú)法滿足的。這就是需要在在線層做復(fù)雜計(jì)算的第二個(gè)主要原因:只有在線實(shí)時(shí)計(jì)算,才能夠充分利用用戶的實(shí)時(shí)信息,包括實(shí)時(shí)興趣、實(shí)時(shí)特征以及其他近線層計(jì)算的結(jié)果等。除此以外,還有其他原因,比如實(shí)時(shí)處理可以快速應(yīng)對(duì)實(shí)時(shí)發(fā)生的業(yè)務(wù)請(qǐng)求等。以上這些原因共同決定了在線層存在的意義。