騰訊全文檢索引擎 wwsearch 正式開源

背景

企業微信作爲典型企業服務系統,其衆多企業級應用都需要全文檢索能力,包括員工通訊錄、企業郵箱、審批、彙報、企業CRM、企業素材、互聯圈子等。下圖是一個典型的郵件檢索場景。

由於過去幾年業務發展迅速,後臺檢索架構面臨挑戰:

1. 系統在億級用戶,xxx萬企業下,如何高效+實時地檢索個人企業內數據和所在企業全局數據。

2. 業務模型衆多,如何滿足檢索條件/功能多樣化需求。

3. 數據量龐大,檢索文本幾十TB,如何節約成本。

業界有被廣泛使用的開源全文檢索引擎,比如:lucene、sphinx等。它們適用於站內檢索的場景。而在海量用戶、大規模數據量的實時檢索場景下,存在明顯缺點:

1. 無法支持細粒度切分索引,只能對全局數據構建索引 ,檢索過程需要過濾冗餘數據。

2. 不支持實時檢索,有幾十秒~分鐘級延遲。

3. 實際部署機型要求高,需要大內存機型才能支撐T級別的數據存儲。

針對已有方案的不足,並結合企業級應用場景,我們重新設計和實現一套通用的全文檢索引擎wwsearch。

自研全文檢索引擎

wwsearch爲海量用戶下的全文快速檢索而設計,底層支持可插拔的lsm tree存儲引擎,具備支持按用戶的億級分表、低延時、高效更新、索引壓縮、功能豐富、內存消耗低等特點。

目前覆蓋企業微信所有在線檢索場景, 最大業務場景有300億+條記錄,索引詞項萬億+,存儲容量幾十TB。在大規模數據下,服務運行穩定,可以爲業務增長提供穩定有力保障!

wwsearch有豐富的功能,可靈活支持業務場景:

1. 支持等值、前綴、模糊匹配,支持And、Or條件組合。

2. 實時增刪查改。

3. 支持後置過濾,包括等值、數值範圍、數組元素查找、字符串模糊匹配。

4. 支持多條件排序,類似order by語義。

5. 可擴展功能,包括聚合功能(sum/avg...)、文檔打分。

高效索引更新

企業級應用相關的數據通常需要經過多次流轉,才能達到最終狀態,比如審批業務。這意味着,檢索系統的數據寫入後也需要部分更新。

開源檢索引擎實現是基於文檔粒度對索引進行增刪,更新是一次刪除和全量插入過程,無法高效支持部分更新。

wwsearch的實現和開源不同,索引的增刪是基於詞級別的,粒度更細。主要原理:

1. 引擎記錄寫入文檔的分詞列表,更新時,通過對比更新前後的分詞列表,可以知道應該插入哪些詞、刪除哪些詞。

2. 檢索一個詞的倒排列表時,會讀取該詞多個倒排列表,並按優先級對倒排列表歸併,時間上後寫的倒排列表優先級更高。

3. 倒排列表內被刪除的DocID會隨着lsm tree文件的合併(Compact),會被逐漸淘汰。

wwsearch以倒排列表爲單位對索引進行增刪改的方案,優點如下:

1. 實時讀寫,寫入即可檢索。

2. 更新友好,高效支持部分更新。

支持億級分表

開源檢索引擎對全局數據構建索引,每次檢索需在全局索引中檢索結果,這種做法存在缺點:

1. 用戶或企業只檢索自身數據,在多用戶場景下,檢索效率低。

2. 大規模數據情況下,無法實時響應用戶請求。

通過支持細粒度分表的能力,wwsearch可以很好地解決這個問題。原理是:利用lsm tree全局有序能力,通過對正向索引、倒排索引的數據key增加特定Prefix的方式,來支持億級分表的能力。由於底層存儲採用lsm tree結構存儲,通過共享key前綴方式,我們可以忽略不計這個Prefix增加的存儲消耗。

wwsearch支持細粒度分表,優點如下:

1. 檢索性能最優、請求延時低。

2. 無需過濾冗餘數據,資源消耗最小,服務能保持很強的穩定性。

高效全文模糊匹配

模糊匹配是在有限信息情況下找到匹配的文本。這是一個比較常見的功能需求,比如用戶檢索一個用戶的手機號,輸入前幾個數字後,希望能儘快補全,又比如輸入航班號數字部分,檢索出完整航班號信息。

開源實現的不同方案:

1. 對詞進行細粒度切分,一個長度爲N個字符的詞,從該詞切分出連續2個字、3個字... 一直到N個字的的詞。這種方法缺點是有O(N^2)個詞展開。

2. 維護詞典,在模糊匹配時,遍歷詞典找到滿足匹配的詞。這種方法缺點是匹配效率差,詞典過大情況下,無法實時返回結果。

wwsearch用一種空間相對節省且檢索高效的新方案:詞按後綴展開+lsm key/value索引按詞典排序+前綴匹配檢索,詞展開僅O(N),檢索效率優。通過例子描述,假設有記錄DocID = 1,name = Michael。我們把name這個詞按後綴展開後,以下詞的倒排列表都會插入這個DocID。檢索 chae 時,通過前綴匹配找到 chael 這個詞的倒排列表,並把這個DocID返回。

詞典:

ael:1

chael:1

el: 1

hael:1

ichael:1

Michael:1

高效過濾排序

部分業務場景裏,單純按關鍵詞檢索還不能滿足用戶需求:

1. 命中結果需要特定排序,比如有些場景需要按時間倒序排列,有些場景需要按點擊數再按時間倒序排列。

2. 命中結果包含多餘數據,還需要進行二次過濾,比如用戶想檢索處於申請中的審批單據。

這些需求需要讀取排序列或者過濾列的屬性值,行存和列存各有優缺點:

1. 屬性混合存儲:這種方式無差別的把所有屬性混合爲一行記錄,打包存儲在文件裏。好處是沒有冗餘存儲,讀取一次就可獲得一條記錄所有的列值。設想一個場景,一條文本原文大小6 KB,檢索某個詞命中1萬條記錄,需要排序返回。以此推算,對1萬條記錄排序一次,需要讀取60MB數據。

2. 屬性按列存儲:這種方式適用於寬列但列值比較稀疏的數據場景,可以按列獨立操作。也有一些缺點,寫入時需要寫多列,讀取時也要按排序或過濾情況讀取多列。

過濾、排序的列通常都是數值類數據,如果能一次寫入或讀取應該是最優的。綜上,wwsearch引擎採用部分屬性混合存儲的方案。優點:讀取次數少,只需一次讀取即可得到所需屬性,配合批量讀取,可以有效降低IO消耗。

索引壓縮

有效地降低檢索系統存儲容量消耗,可以降低機器運營成本。wwsearch引擎在以下多個方面對存儲消耗進行針對性優化。

1. 支持覆蓋寫功能。針對文本只寫不改的場景,比如單據內容、郵件等,寫入倒排索引後,正向索引不會存儲分詞後的詞列表。通過這種接口寫入場景,可以大幅度減少正向信息存儲帶來的消耗。

2. 支持倒排列表壓縮。倒排列表存儲由三部分組成:頭部(Header)、倒排列表(DocIDList)、刪除列表(DeleteList)。頭部記錄編碼版本,定長爲1字節。倒排列表按DocID倒序,第一個是Base,後續每個值記錄與前一個DocID差值,用varint編碼。刪除列表記錄有刪除標記的DocID位置(相對於倒排列表),按位置升序,第一個是Base,後續每個值記錄與前一個位置差值,用varint編碼。

3. 支持主鍵映射。實際情況下業務主鍵通常是字符串,難以要求有64位無符號整數的主鍵,即使存在,其DocID在隨機生成情況下,倒排列表的壓縮方案就無法發揮很大作用。通過主鍵映射,任意業務主鍵可映射到一個唯一的64位無符號整數,從0開始,嚴格遞增,映射可逆。

wwsearch開源

現在,騰訊把wwsearch開源。我們樂於開源共享,希望wwsearch能被有相同業務場景需求的開發者使用,解決大家在全文檢索場景遇到的類似問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章