ESearch: 58 搜索內(nèi)核設(shè)計(jì)與實(shí)踐—實(shí)時索引篇

58同城作為中國最大的分類信息網(wǎng)站芦疏,提供了房產(chǎn)、招聘微姊、黃頁和二手交易等多方面的生活服務(wù)信息酸茴,信息數(shù)據(jù)量和訪問量逐年增長,列表頁排序需求也時常變化兢交。在這樣的背景下薪捍,58搜索技術(shù)部使用C++語言自主研發(fā)了ESearch 搜索內(nèi)核,取代之前使用的 Solr,大幅提高了性能和可定制性酪穿。

經(jīng)過多年的實(shí)踐和優(yōu)化与倡,ESearch 已發(fā)展成為一個功能完善、性能優(yōu)異昆稿、運(yùn)行穩(wěn)定的搜索內(nèi)核,如今作為一個核心組件息拜,承擔(dān)了58集團(tuán)(包括58同城溉潭、趕集、安居客等)所有搜索業(yè)務(wù)少欺,承載每天幾十億的查詢流量喳瓣。ESearch的主要特性包括:

秒級實(shí)時索引:從文檔發(fā)布到能檢索出該文檔,可以做到平均一秒的時間延遲赞别。

大數(shù)據(jù)量畏陕、高并發(fā)、低延遲:基于本地緩存仿滔、自定義內(nèi)存池惠毁、自動Query改寫等多種性能優(yōu)化措施,可達(dá)到單機(jī)千萬級文檔崎页、8000 QPS鞠绰、毫秒級平均延遲。

功能豐富:支持復(fù)合條件查詢飒焦、空間查詢蜈膨、Facet查詢、分組查詢牺荠、結(jié)果去重等功能翁巍。

業(yè)務(wù)可定制:支持SKU查詢、一一抽取休雌、在線用戶實(shí)時過濾等個性化功能灶壶。

可擴(kuò)展、易復(fù)用的排序框架:支持簡單的線性加權(quán)杈曲、自定義的打分表達(dá)式例朱、基于機(jī)器學(xué)習(xí)的邏輯回歸、多決策樹等模型鱼蝉,以及多模型融合等多種排序方式洒嗤。

本文將介紹 ESearch 的整體架構(gòu),并重點(diǎn)說明其中實(shí)時索引的設(shè)計(jì)和實(shí)現(xiàn)細(xì)節(jié)魁亦。

一渔隶、整體架構(gòu)

上圖是 58 搜索系統(tǒng)的整體架構(gòu),分為應(yīng)用層和內(nèi)核層兩大部分,應(yīng)用層包括 Proxy 和 Builder 兩個模塊间唉,負(fù)責(zé)與業(yè)務(wù)相關(guān)的邏輯绞灼,內(nèi)核層就是本文重點(diǎn)介紹的 ESearch焊唬,包括 Merger 和 Searcher 兩個模塊祷肯,負(fù)責(zé)通用的檢索功能敏储。各個模塊的具體功能如下:

Proxy:查詢代理液荸,接收前端查詢請求老速,進(jìn)行意圖識別和查詢改寫等工作适室,然后發(fā)送請求到 Merger屁魏,獲取檢索結(jié)果怎茫。

Merger:基于一致性哈希算法將請求分發(fā)到多個 Searcher昨悼,然后合并結(jié)果蝗锥,并進(jìn)行一些排序調(diào)整。

Searcher:包含索引數(shù)據(jù)和排序模型率触,負(fù)責(zé)實(shí)時建索引并執(zhí)行召回终议、打分、排序等檢索流程葱蝗。

Builder:接收外部請求進(jìn)行進(jìn)行文檔構(gòu)建穴张,并將文檔發(fā)給 Searcher。

二两曼、實(shí)時索引

實(shí)時索引的設(shè)計(jì)主要需要考慮兩個需求:

文檔更新能在秒級時間內(nèi)生效:用戶信息發(fā)布或者修改更新之后陆馁,需要能盡快被檢索到。

文檔更新時不影響查詢效率:在大數(shù)據(jù)量大更新量的情況下合愈,不能影響查詢延時叮贩。

從查詢效率出發(fā),業(yè)界通常采用讀寫分離的設(shè)計(jì)佛析,即索引不提供更新功能益老,避免更新操作阻塞查詢線程。接收到新文檔之后寸莫,先與原索引數(shù)據(jù)合并為新索引捺萌,然后替換掉舊索引,從而使新文檔生效膘茎。但在文檔更新量比較大桃纯,并且索引量隨時間逐漸增大的情況下,合并時間會變得很長披坏,導(dǎo)致新文檔長時間無法生效态坦。此外還有一些搜索引擎采用了無鎖數(shù)據(jù)結(jié)構(gòu),支持索引的高并發(fā)讀寫棒拂,但實(shí)現(xiàn)相對復(fù)雜伞梯。

ESearch 也采用了讀寫分離設(shè)計(jì)玫氢,為了克服合并時間過長的問題,對合并機(jī)制做了改進(jìn)設(shè)計(jì):對每個檢索節(jié)點(diǎn)的索引數(shù)據(jù)按生命周期分為多段谜诫,每段是一份完整的小索引漾峡,包含獨(dú)立的倒排和正排索引等數(shù)據(jù)。新增的文檔數(shù)據(jù)只和最小的索引段合并喻旷,確保了索引的更新速度生逸。

在實(shí)際的應(yīng)用層面,根據(jù)自身數(shù)據(jù)量和業(yè)務(wù)特點(diǎn)且预,我們采取了以下方案:每個節(jié)點(diǎn)上索引按生命周期分為 3秒槽袄、15分鐘、6小時辣之、1天、1個月皱炉、1個月以前等6級怀估。

實(shí)時索引每3秒接收一批新文檔數(shù)據(jù),然后建成一個生命周期為3秒的小段合搅,此時這批文檔立即生效多搀,能被查詢線程召回。3秒后灾部,該段到達(dá)生命周期終點(diǎn)康铭,由一個專門負(fù)責(zé)索引段合并的線程將其與15分鐘生命周期的段合并。由于15分鐘索引段最多只包含了15分鐘內(nèi)的新增文檔赌髓,數(shù)據(jù)量較少从藤,所以合并速度非常快锁蠕,可以達(dá)到毫秒級夷野。同理,15分鐘荣倾、6小時等其他周期的段悯搔,到達(dá)各自的生命周期終點(diǎn)后,都會向上一級索引段合并舌仍。

生命周期在1天以上的段妒貌,數(shù)據(jù)量較多,合并時間較長铸豁,但其合并頻率較低灌曙,每天最多一次,可以指定其在每天凌晨進(jìn)行节芥,這是一天中訪問量和數(shù)據(jù)更新最少的時間段平匈,因此對系統(tǒng)性能影響不大。若1個月周期的數(shù)據(jù)量太大,可以在線下定期將其與1個月以前的索引合并增炭,合并好后推送到檢索節(jié)點(diǎn)忍燥,避免影響系統(tǒng)性能。

在這種分段設(shè)計(jì)下隙姿,查詢處理器可以為每個查詢分配多個線程梅垄,每個線程檢索一個段,最終將結(jié)果合并输玷。因此分段設(shè)計(jì)也便于利用并發(fā)能力降低查詢延時队丝。

如果文檔的更新和查詢的召回條件或排序均遵循時間序(例如日志索引),那么可以只檢索與查詢中的時間段相關(guān)的索引段欲鹏,提升檢索效率机久,因此這種設(shè)計(jì)很適合以時間序?yàn)橹饕判蛐枨蟮乃阉飨到y(tǒng)。

三赔嚎、索引結(jié)構(gòu)

上一節(jié)介紹了實(shí)時索引整體的設(shè)計(jì)膘盖,本節(jié)介紹索引段內(nèi)的具體結(jié)構(gòu)。

在 ESearch 中尤误,每個索引段包含四種索引結(jié)構(gòu):主鍵索引侠畔、刪除表、倒排索引和正排索引损晤。

3.1软棺、主鍵索引

為了便于高效計(jì)算,索引內(nèi)部為整個文檔集分配了從0開始遞增的doc id尤勋,倒排和正排索引均基于doc id來組織喘落,而不使用文檔的原始主鍵。為了能從文檔的原始主鍵查找到對應(yīng)的索引數(shù)據(jù)最冰,必須先將主鍵映射為doc id揖盘,主鍵索引就是為此而存在的,它本質(zhì)上是一個從主鍵映射到doc id的哈希表锌奴。

3.2兽狭、刪除表

倒排索引是為查詢優(yōu)化的,不利于原地更新和刪除鹿蜀,因此當(dāng)文檔被刪除時箕慧,我們需要一個刪除表來標(biāo)記文檔的刪除狀態(tài),它本質(zhì)上是一個bitmap茴恰。

3.3颠焦、倒排索引

倒排索引用于根據(jù)term快速查找包含該term的所有文檔。由于采用了讀寫分離設(shè)計(jì)往枣,ESearch的倒排索引數(shù)據(jù)結(jié)構(gòu)不需要支持更新伐庭,每個term對應(yīng)的doc id集合以有序數(shù)組的形式存儲即可粉渠。對于文本域,倒排數(shù)據(jù)還包含詞頻圾另、詞權(quán)霸株、位置等信息。

58的關(guān)鍵詞查詢通常需要在多個文本域中查詢集乔,比如“title:租房 OR content:租房”去件,需要召回title或者content這兩個域中包含租房的文檔。為了優(yōu)化這類常見查詢的性能扰路,同時也讓文本相關(guān)性計(jì)算更方便尤溜,ESearch支持倒排域打包功能(或稱聯(lián)合域),即自動把同一個term在多個文本域中的文檔集合并到同一個倒排鏈(Posting List)中汗唱,此功能只需在schema中稍作配置即可啟用宫莱。如此,相當(dāng)于在索引中對每個term預(yù)計(jì)算了多個域的并集哩罪。另外授霸,由于不同文本域的權(quán)重不同,進(jìn)行文本相關(guān)性打分時需要識別出一個term命中了哪些文本域识椰,因此聯(lián)合域倒排鏈中的每個doc id 還必須附帶一個微型 bitmap 來標(biāo)記其所命中的域绝葡。

下圖為把Title域和Content域合并為Fulltext域的例子:

3.4深碱、正排索引

正排索引是從doc id到文檔屬性值的映射腹鹉。在58的搜索系統(tǒng)中,正排索引除了存儲必要的文檔屬性以外敷硅,也存儲用于打分的文檔特征功咒。在檢索過程中,也有可能讀取某些正排域來進(jìn)行文檔過濾绞蹦。

ESearch 的正排索引采用列存儲設(shè)計(jì)力奋,即不同正排域的數(shù)據(jù)分開存儲。

針對58文檔的特性幽七,ESearch 提供了正排域的多種存儲形式景殷。58是一個分類信息網(wǎng)站,所有類目的信息都存在同一個數(shù)據(jù)庫中澡屡。類目不同猿挚,信息的字段差異也很大,譬如房產(chǎn)信息包含樓層驶鹉、戶型等字段绩蜻,二手交易信息包含品牌、型號等字段室埋。這些差異化的字段按統(tǒng)一格式合并存儲在同一個數(shù)據(jù)庫字段办绝,在建索引的時候伊约,仍會分別建到各自的倒排、正排域中孕蝉。但同時各類目信息也有不少通用字段屡律,例如標(biāo)題、城市ID昔驱、類目ID等疹尾。

這意味著有些域的值分布是稀疏的,例如在所有信息中骤肛,包含“手機(jī)品牌”這個字段的信息的占比可能遠(yuǎn)低于50%纳本,而有些域的值分布是緊密的,例如幾乎100%的信息都包含“類目ID”這個字段腋颠。

針對緊密型的正排域繁成,我們使用數(shù)組作為存儲形式,而針對稀疏型正排域淑玫,使用哈希表作為存儲形式巾腕,這樣能夠避免浪費(fèi)空間,也都保證了O(1)的平均查找時間復(fù)雜度絮蒿。

此外尊搬,對于布爾型的正排域,我們直接采用Bitmap 作為存儲形式土涝。

列存儲的一個缺陷是缺乏空間局部性佛寿,可能影響CPU緩存命中率。例如在給一個文檔打分時但壮,通常會從正排索引讀取多個特征值進(jìn)行計(jì)算冀泻,因此需要進(jìn)行多次查找和多處內(nèi)存訪問。針對此問題蜡饵,可以考慮使用聯(lián)合正排域弹渔,將經(jīng)常需要同時訪問的多個字段合并建到一個正排域中。

四溯祸、緩存與二次排序

為了降低檢索服務(wù)響應(yīng)時間肢专,對檢索結(jié)果進(jìn)行緩存是必需的,但緩存也會導(dǎo)致文檔字段和排序特征的更新無法立刻生效焦辅,影響實(shí)時性博杖。本節(jié)介紹 ESearch在使用了緩存的情況下如何保證召回結(jié)果和排序結(jié)果得到實(shí)時更新。

4.1氨鹏、召回結(jié)果

在實(shí)時索引中欧募,如前文所述,文檔更新時會被建入新的小索引段中仆抵。如果舊的索引段也包含此文檔跟继,那么此文檔在舊段中會被標(biāo)記刪除种冬。

ESearch 為每一個段分配了獨(dú)立的緩存,每個段各自將檢索結(jié)果從緩存中取出后舔糖,會用刪除表過濾掉已刪除的文檔娱两,從而確保只有更新后的文檔能被檢索出來。

4.2金吗、排序結(jié)果

為了便于打分排序十兢,我們會把一些文檔特征值存儲在索引中。這些特征值不會作為召回條件摇庙,因此只建在正排索引中旱物。對這類文檔屬性的更新可以不走前文所述的生成新段-段合并的更新流程,而是直接在正排索引中原地刷新卫袒,因此特征值刷新的性能遠(yuǎn)高于正常文檔更新宵呛,從而允許我們實(shí)時調(diào)整排序結(jié)果。

為了使特征值的改變能夠?qū)崟r影響排序結(jié)果夕凝,我們在從緩存中取出檢索結(jié)果后宝穗,對檢索結(jié)果會做第二次打分排序。由于緩存中的結(jié)果一般只包含Top幾百的文檔码秉,因此第二次排序耗時有限逮矛,不影響整體性能。

除了保證實(shí)時性以外转砖,這種兩階段排序也便于我們在58主站大規(guī)模應(yīng)用復(fù)雜的機(jī)器學(xué)習(xí)排序模型须鼎。

復(fù)雜的排序策略通常比較耗時,因此業(yè)界在處理海量數(shù)據(jù)的排序時堪藐,通常用“粗排-精排”兩階段排序的方式莉兰,在效果和性能之間做一個合理折中挑围,即先對海量數(shù)據(jù)進(jìn)行低代價的粗排礁竞,然后對粗排的TopN結(jié)果進(jìn)行代價較大的精排,最終整個處理過程耗時不會太大杉辙。

58分類信息的特點(diǎn)也很適合這種模式模捂,很多類目(例如租房)的信息注重時效性,時間序是主要排序因素蜘矢。在信息發(fā)布時間相近的前提下狂男,需要根據(jù)信息質(zhì)量、轉(zhuǎn)化率等其他因素進(jìn)行更精細(xì)的排序品腹。二次排序恰好可以用來實(shí)現(xiàn)這樣的流程:第一次排序?qū)θ课臋n按時間序求出 TopN 結(jié)果集保存在緩存中岖食,第二次排序使用復(fù)雜的機(jī)器學(xué)習(xí)模型來對 TopN 結(jié)果打分重排。

五舞吭、總結(jié)

本文介紹了在 58 搜索內(nèi)核 ESearch 中泡垃,如何根據(jù) 58 的數(shù)據(jù)和搜索特點(diǎn)來設(shè)計(jì)實(shí)時索引以及進(jìn)行索引存儲和查詢流程方面的優(yōu)化析珊。隨著業(yè)務(wù)的不斷發(fā)展,我們也將繼續(xù)在檢索性能蔑穴、資源利用率忠寻、排序等方面持續(xù)優(yōu)化,也歡迎感興趣的同學(xué)和我們一起交流存和。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奕剃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子捐腿,更是在濱河造成了極大的恐慌纵朋,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茄袖,死亡現(xiàn)場離奇詭異倡蝙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)绞佩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門寺鸥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人品山,你說我怎么就攤上這事胆建。” “怎么了肘交?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵笆载,是天一觀的道長。 經(jīng)常有香客問我涯呻,道長凉驻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任复罐,我火速辦了婚禮涝登,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘效诅。我一直安慰自己胀滚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布乱投。 她就那樣靜靜地躺著咽笼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪戚炫。 梳的紋絲不亂的頭發(fā)上剑刑,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天,我揣著相機(jī)與錄音双肤,去河邊找鬼施掏。 笑死层宫,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的其监。 我是一名探鬼主播萌腿,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼抖苦!你這毒婦竟也來了毁菱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤锌历,失蹤者是張志新(化名)和其女友劉穎贮庞,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體究西,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡窗慎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了卤材。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遮斥。...
    茶點(diǎn)故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖扇丛,靈堂內(nèi)的尸體忽然破棺而出术吗,到底是詐尸還是另有隱情,我是刑警寧澤帆精,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布较屿,位于F島的核電站,受9級特大地震影響卓练,放射性物質(zhì)發(fā)生泄漏隘蝎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一襟企、第九天 我趴在偏房一處隱蔽的房頂上張望嘱么。 院中可真熱鬧,春花似錦整吆、人聲如沸拱撵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至乓旗,卻和暖如春府蛇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背屿愚。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工汇跨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留务荆,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓穷遂,卻偏偏與公主長得像函匕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蚪黑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容