Facebook支撐萬億Post搜索背后的技術窺探
近日,Facebook為post搜索添加了Graph Search。我們來看幾個驚人的數字:Facebook每天約產生10億條post,post索引總數已上萬億條,數據量超700TB。為這些post建立索引和構建實時查詢系統在工程上存在非常大的挑戰,那么Facebook又是如何應對這一挑戰的?以下為譯文:
數據收集
Facebook的底層數據結構是為了滿足快速迭代網絡服務的需要,這卻也成為構建實時查詢系統所面臨的最大挑戰。增加新功能往往需要改動這些數據結構,而Facebook一貫的作風是變動不要給工程師平添煩惱。然而,由于wall post、photo、check-in等功能采用不同的數據存儲機制,對底層數據結構進行改動增加了以時間、地點和標簽進行排序的難度。當前,排序和索引的數據約有70種,其中很多種都是基于特定post類型的。此外,數據存儲在一個用于生產環境的MySQL數據庫中。這也就意味著,當數據庫同時支撐生產傳輸及數據收集時,負載將大幅度增加,因此這些過程必須被嚴格監控。
索引建立
數據收集來后,我們將其存儲在HBase集群中,然后執行Hadoop map-reduce任務,高并行地為之建立索引。為原始數據建立索引后,然后便傳輸給搜索的基礎Unicorn。我們將數據分為兩塊——文檔數據和反向索引(inverted index)。每條post的文檔數據包含用于排序的相關信息。傳統意義上搜索索引有什么,反向索引就有什么。要建反向索引需要遍歷每一條post,并確定與假設中的哪種搜索過濾器相匹配。
索引更新
為了更新索引,我們使用Wormhole技術訂閱MySQL數據庫中的變更。一旦有新post,現有post被修改、刪除或與post有關的相關數據被編輯等情況發生時,我們就會都對相關post進行更新操作。為了減少重復代碼,我們使用與在“數據收集”部分提到的相同邏輯來進行更新操作。不同之處在于,我們在收集數據時有意避開緩存,因為我們想盡量避免請求沒有緩存過的數據。當我們更新索引時,我們將會命中緩存,因為我們希望該數據是最近被訪問過,并且還在緩存中。
索引存儲
post索引要比Facebook維護的其他搜索索引大得多。在開始搜索post之前,Facebook 所有的搜索索引都存儲在RAM中。對于快速查詢來說,這再好不過了。對小型的搜索索引來說也是可行的。然而,將700多TB的數據存儲在RAM中所帶來系統開銷是難以想象的,因為它需要維護分布在多臺機器上的索引。協調存儲索引的多臺機器使它們有序地工作給系統帶來了巨大的性能損耗,Unicorn團隊為此不得不尋找存儲post索引的新方法。我們最終敲定的解決方案是用固態閃存存儲大部分的索引,用RAM存儲存取最為頻繁的數據結構,性能得以維持。
結果排序
由于索引了1萬億條post,絕大多數查詢返回的結果數量之多是任何人都讀不完的。為此,Facebook開始設計對結果進行排序。為了使對用戶有價值并與用戶相關的內容浮到上面,主要采用了兩種主要策略:查詢重寫和結果動態打分。在執行前,先重寫查詢,靈活增加子句,以確保查詢結果對用戶價值更大。為搜索結果進行打分,包括基于一系列用于排序的特征進行排序和選擇文檔。排序特征是從文檔中抽取出來的,目前一共抽取了100多項特征,結合排序模型,用于尋找最佳搜索結果。隨著用戶量的增長和用戶反饋的增多,排序模型必將得到進一步改善。
項目簡史
像 Facebook 的很多其他產品一樣,post搜索功能也是誕生于一個編程馬拉松項目。而在過去的一年中,Graph Search 團隊的幾十個人實現了post搜索的大部分功能——基礎架構、排序和產品化。