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

58同城作為中國(guó)最大的分類信息網(wǎng)站傻挂,提供了房產(chǎn)乘碑、招聘、黃頁(yè)和二手交易等多方面的生活服務(wù)信息金拒,信息數(shù)據(jù)量和訪問量逐年增長(zhǎng)兽肤,列表頁(yè)排序需求也時(shí)常變化。在這樣的背景下殖蚕,58搜索技術(shù)部使用C++語(yǔ)言自主研發(fā)了ESearch 搜索內(nèi)核轿衔,取代之前使用的 Solr,大幅提高了性能和可定制性睦疫。

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

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

  • 大數(shù)據(jù)量圣勒、高并發(fā)费变、低延遲:基于本地緩存、自定義內(nèi)存池圣贸、自動(dòng)Query改寫等多種性能優(yōu)化措施挚歧,可達(dá)到單機(jī)千萬級(jí)文檔、8000 QPS吁峻、毫秒級(jí)平均延遲滑负。

  • 功能豐富:支持復(fù)合條件查詢、空間查詢用含、Facet查詢矮慕、分組查詢、結(jié)果去重等功能啄骇。

  • 業(yè)務(wù)可定制:支持SKU查詢凡傅、一一抽取、在線用戶實(shí)時(shí)過濾等個(gè)性化功能肠缔。

  • 可擴(kuò)展夏跷、易復(fù)用的排序框架:支持簡(jiǎn)單的線性加權(quán)、自定義的打分表達(dá)式明未、基于機(jī)器學(xué)習(xí)的邏輯回歸槽华、多決策樹等模型,以及多模型融合等多種排序方式趟妥。

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

一披摄、整體架構(gòu)

整體架構(gòu)

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

  • Proxy:查詢代理璧函,接收前端查詢請(qǐng)求,進(jìn)行意圖識(shí)別和查詢改寫等工作基显,然后發(fā)送請(qǐng)求到 Merger蘸吓,獲取檢索結(jié)果。

  • Merger:基于一致性哈希算法將請(qǐng)求分發(fā)到多個(gè) Searcher撩幽,然后合并結(jié)果库继,并進(jìn)行一些排序調(diào)整。

  • Searcher:包含索引數(shù)據(jù)和排序模型窜醉,負(fù)責(zé)實(shí)時(shí)建索引并執(zhí)行召回宪萄、打分、排序等檢索流程酱虎。

  • Builder:接收外部請(qǐng)求進(jìn)行進(jìn)行文檔構(gòu)建雨膨,并將文檔發(fā)給 Searcher。

二读串、實(shí)時(shí)索引

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

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

  • 文檔更新時(shí)不影響查詢效率:在大數(shù)據(jù)量大更新量的情況下恢暖,不能影響查詢延時(shí)排监。

從查詢效率出發(fā),業(yè)界通常采用讀寫分離的設(shè)計(jì)杰捂,即索引不提供更新功能舆床,避免更新操作阻塞查詢線程。接收到新文檔之后嫁佳,先與原索引數(shù)據(jù)合并為新索引挨队,然后替換掉舊索引,從而使新文檔生效蒿往。但在文檔更新量比較大盛垦,并且索引量隨時(shí)間逐漸增大的情況下,合并時(shí)間會(huì)變得很長(zhǎng)瓤漏,導(dǎo)致新文檔長(zhǎng)時(shí)間無法生效腾夯。此外還有一些搜索引擎采用了無鎖數(shù)據(jù)結(jié)構(gòu),支持索引的高并發(fā)讀寫蔬充,但實(shí)現(xiàn)相對(duì)復(fù)雜蝶俱。

ESearch 也采用了讀寫分離設(shè)計(jì),為了克服合并時(shí)間過長(zhǎng)的問題饥漫,對(duì)合并機(jī)制做了改進(jìn)設(shè)計(jì):對(duì)每個(gè)檢索節(jié)點(diǎn)的索引數(shù)據(jù)按生命周期分為多段榨呆,每段是一份完整的小索引,包含獨(dú)立的倒排和正排索引等數(shù)據(jù)趾浅。新增的文檔數(shù)據(jù)只和最小的索引段合并愕提,確保了索引的更新速度馒稍。

在實(shí)際的應(yīng)用層面皿哨,根據(jù)自身數(shù)據(jù)量和業(yè)務(wù)特點(diǎn)浅侨,我們采取了以下方案:每個(gè)節(jié)點(diǎn)上索引按生命周期分為 3秒、15分鐘证膨、6小時(shí)如输、1天、1個(gè)月央勒、1個(gè)月以前等6級(jí)不见。


實(shí)時(shí)索引每3秒接收一批新文檔數(shù)據(jù),然后建成一個(gè)生命周期為3秒的小段崔步,此時(shí)這批文檔立即生效稳吮,能被查詢線程召回。3秒后井濒,該段到達(dá)生命周期終點(diǎn)灶似,由一個(gè)專門負(fù)責(zé)索引段合并的線程將其與15分鐘生命周期的段合并。由于15分鐘索引段最多只包含了15分鐘內(nèi)的新增文檔瑞你,數(shù)據(jù)量較少酪惭,所以合并速度非常快者甲,可以達(dá)到毫秒級(jí)春感。同理,15分鐘虏缸、6小時(shí)等其他周期的段鲫懒,到達(dá)各自的生命周期終點(diǎn)后,都會(huì)向上一級(jí)索引段合并刽辙。

生命周期在1天以上的段窥岩,數(shù)據(jù)量較多,合并時(shí)間較長(zhǎng)扫倡,但其合并頻率較低谦秧,每天最多一次,可以指定其在每天凌晨進(jìn)行撵溃,這是一天中訪問量和數(shù)據(jù)更新最少的時(shí)間段疚鲤,因此對(duì)系統(tǒng)性能影響不大。若1個(gè)月周期的數(shù)據(jù)量太大缘挑,可以在線下定期將其與1個(gè)月以前的索引合并集歇,合并好后推送到檢索節(jié)點(diǎn),避免影響系統(tǒng)性能语淘。

在這種分段設(shè)計(jì)下诲宇,查詢處理器可以為每個(gè)查詢分配多個(gè)線程际歼,每個(gè)線程檢索一個(gè)段,最終將結(jié)果合并姑蓝。因此分段設(shè)計(jì)也便于利用并發(fā)能力降低查詢延時(shí)鹅心。

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

三宙暇、索引結(jié)構(gòu)

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

在 ESearch 中占贫,每個(gè)索引段包含四種索引結(jié)構(gòu):主鍵索引桃熄、刪除表、倒排索引和正排索引型奥。

3.1瞳收、主鍵索引

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

3.2夹纫、刪除表

倒排索引是為查詢優(yōu)化的,不利于原地更新和刪除设凹,因此當(dāng)文檔被刪除時(shí)舰讹,我們需要一個(gè)刪除表來標(biāo)記文檔的刪除狀態(tài),它本質(zhì)上是一個(gè)bitmap闪朱。

3.3月匣、倒排索引

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

58的關(guān)鍵詞查詢通常需要在多個(gè)文本域中查詢癣诱,比如“title:租房 OR content:租房”计维,需要召回title或者content這兩個(gè)域中包含租房的文檔。為了優(yōu)化這類常見查詢的性能撕予,同時(shí)也讓文本相關(guān)性計(jì)算更方便鲫惶,ESearch支持倒排域打包功能(或稱聯(lián)合域),即自動(dòng)把同一個(gè)term在多個(gè)文本域中的文檔集合并到同一個(gè)倒排鏈(Posting List)中嗅蔬,此功能只需在schema中稍作配置即可啟用剑按。如此疾就,相當(dāng)于在索引中對(duì)每個(gè)term預(yù)計(jì)算了多個(gè)域的并集澜术。另外,由于不同文本域的權(quán)重不同猬腰,進(jìn)行文本相關(guān)性打分時(shí)需要識(shí)別出一個(gè)term命中了哪些文本域鸟废,因此聯(lián)合域倒排鏈中的每個(gè)doc id 還必須附帶一個(gè)微型 bitmap 來標(biāo)記其所命中的域。

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


3.4姑荷、正排索引

正排索引是從doc id到文檔屬性值的映射盒延。在58的搜索系統(tǒng)中,正排索引除了存儲(chǔ)必要的文檔屬性以外鼠冕,也存儲(chǔ)用于打分的文檔特征添寺。在檢索過程中,也有可能讀取某些正排域來進(jìn)行文檔過濾懈费。

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

針對(duì)58文檔的特性憎乙,ESearch 提供了正排域的多種存儲(chǔ)形式票罐。58是一個(gè)分類信息網(wǎng)站,所有類目的信息都存在同一個(gè)數(shù)據(jù)庫(kù)中泞边。類目不同该押,信息的字段差異也很大,譬如房產(chǎn)信息包含樓層阵谚、戶型等字段蚕礼,二手交易信息包含品牌、型號(hào)等字段梢什。這些差異化的字段按統(tǒng)一格式合并存儲(chǔ)在同一個(gè)數(shù)據(jù)庫(kù)字段奠蹬,在建索引的時(shí)候,仍會(huì)分別建到各自的倒排绳矩、正排域中罩润。但同時(shí)各類目信息也有不少通用字段,例如標(biāo)題翼馆、城市ID割以、類目ID等金度。

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

針對(duì)緊密型的正排域跟伏,我們使用數(shù)組作為存儲(chǔ)形式,而針對(duì)稀疏型正排域翩瓜,使用哈希表作為存儲(chǔ)形式受扳,這樣能夠避免浪費(fèi)空間,也都保證了O(1)的平均查找時(shí)間復(fù)雜度兔跌。


此外勘高,對(duì)于布爾型的正排域,我們直接采用Bitmap 作為存儲(chǔ)形式坟桅。

列存儲(chǔ)的一個(gè)缺陷是缺乏空間局部性华望,可能影響CPU緩存命中率。例如在給一個(gè)文檔打分時(shí)仅乓,通常會(huì)從正排索引讀取多個(gè)特征值進(jìn)行計(jì)算赖舟,因此需要進(jìn)行多次查找和多處內(nèi)存訪問。針對(duì)此問題夸楣,可以考慮使用聯(lián)合正排域,將經(jīng)常需要同時(shí)訪問的多個(gè)字段合并建到一個(gè)正排域中裕偿。

四、緩存與二次排序

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

4.1、召回結(jié)果

在實(shí)時(shí)索引中袋倔,如前文所述,文檔更新時(shí)會(huì)被建入新的小索引段中批狐。如果舊的索引段也包含此文檔嚣艇,那么此文檔在舊段中會(huì)被標(biāo)記刪除华弓。

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

4.2、排序結(jié)果

為了便于打分排序恳谎,我們會(huì)把一些文檔特征值存儲(chǔ)在索引中因痛。這些特征值不會(huì)作為召回條件,因此只建在正排索引中鸵膏。對(duì)這類文檔屬性的更新可以不走前文所述的生成新段-段合并的更新流程谭企,而是直接在正排索引中原地刷新,因此特征值刷新的性能遠(yuǎn)高于正常文檔更新债查,從而允許我們實(shí)時(shí)調(diào)整排序結(jié)果盹廷。

為了使特征值的改變能夠?qū)崟r(shí)影響排序結(jié)果,我們?cè)趶木彺嬷腥〕鰴z索結(jié)果后,對(duì)檢索結(jié)果會(huì)做第二次打分排序剥汤。由于緩存中的結(jié)果一般只包含Top幾百的文檔排惨,因此第二次排序耗時(shí)有限暮芭,不影響整體性能。

除了保證實(shí)時(shí)性以外畜晰,這種兩階段排序也便于我們?cè)?8主站大規(guī)模應(yīng)用復(fù)雜的機(jī)器學(xué)習(xí)排序模型瑞筐。

復(fù)雜的排序策略通常比較耗時(shí)聚假,因此業(yè)界在處理海量數(shù)據(jù)的排序時(shí),通常用“粗排-精排”兩階段排序的方式膘格,在效果和性能之間做一個(gè)合理折中瘪贱,即先對(duì)海量數(shù)據(jù)進(jìn)行低代價(jià)的粗排,然后對(duì)粗排的TopN結(jié)果進(jìn)行代價(jià)較大的精排甜害,最終整個(gè)處理過程耗時(shí)不會(huì)太大球昨。

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

五、總結(jié)

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市夸溶,隨后出現(xiàn)的幾起案子凶硅,更是在濱河造成了極大的恐慌足绅,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粹污,死亡現(xiàn)場(chǎng)離奇詭異壮吩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)鸭叙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門沈贝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宋下,“玉大人,你說我怎么就攤上這事滤奈×寐” “怎么了伺帘?”我有些...
    開封第一講書人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵伪嫁,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我帝洪,道長(zhǎng)葱峡,這世上最難降的妖魔是什么龙助? 我笑而不...
    開封第一講書人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任砰奕,我火速辦了婚禮军援,結(jié)果婚禮上胸哥,老公的妹妹穿的比我還像新娘铣缠。我一直安慰自己昆禽,他們只是感情好醉鳖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開白布盗棵。 她就那樣靜靜地躺著北发,像睡著了一般琳拨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惊畏,一...
    開封第一講書人閱讀 51,274評(píng)論 1 300
  • 那天颜启,我揣著相機(jī)與錄音浪讳,去河邊找鬼。 笑死淹遵,一個(gè)胖子當(dāng)著我的面吹牛口猜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播透揣,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了拆祈?” 一聲冷哼從身側(cè)響起倘感,我...
    開封第一講書人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤淤年,失蹤者是張志新(化名)和其女友劉穎麸粮,沒想到半個(gè)月后弄诲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體齐遵,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拓哟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年断序,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谎砾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片景图。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡亮蒋,死狀恐怖慎玖,靈堂內(nèi)的尸體忽然破棺而出趁怔,到底是詐尸還是另有隱情润努,我是刑警寧澤铺浇,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布鳍侣,位于F島的核電站倚聚,受9級(jí)特大地震影響秉沼,放射性物質(zhì)發(fā)生泄漏唬复。R本人自食惡果不足惜敞咧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一乍恐、第九天 我趴在偏房一處隱蔽的房頂上張望茵烈。 院中可真熱鬧呜投,春花似錦仑荐、人聲如沸粘招。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)子檀。三九已至,卻和暖如春亩进,著一層夾襖步出監(jiān)牢的瞬間归薛,已是汗流浹背习贫。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留幸海,地道東北人袜硫。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像憨攒,于是被迫代替她去往敵國(guó)和親肝集。 傳聞我的和親對(duì)象是個(gè)殘疾皇子杏瞻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

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