如何快速實現高併發短文檢索

1、需求緣起
某併發量很大,數據量適中的業務線須要實現一個「標題檢索」的功能:
(1)併發量較大,每秒20w次
(2)數據量適中,大概200w數據
(3)是否須要分詞:是
(4)數據是否實時更新:否數據庫

2、常見潛在解決方案及優劣
(1)數據庫搜索法
具體方法:將標題數據存放在數據庫中,使用like來檢索
優勢:方案簡單
缺點:不能實現分詞,併發量扛不住編程

(2)數據庫全文檢索法
具體方法:將標題數據存放在數據庫中,創建全文索引來檢索
優勢:方案簡單
缺點:併發量扛不住數據結構

(3)使用開源方案將索引外置
具體方法:搭建lucene,solr,ES等開源外置索引方案
優勢:性能比上面兩種好
缺點:併發量可能有風險,系統比較重,爲一個簡單的業務搭建一套這樣的系統成本較高併發

3、58龍哥的建議
問1:龍哥,58同城第一屆編程大賽的題目好像是「黃反詞過濾」,你是冠軍,當時是用DAT來實現的麼?
龍哥:是的
畫外音:什麼是DAT?
普及:DAT是double array trie的縮寫,是trie樹的一個變體優化數據結構,它在保證trie樹檢索效率的前提下,能大大減小內存的使用,常常用來解決檢索,信息過濾等問題。(具體大夥百度一下「DAT」)性能

問2:上面的業務場景可使用DAT來實現麼?
龍哥:DAT更新數據比較麻煩,不能增量優化

問3:那直接使用trie樹能夠麼?
龍哥:trie樹比較佔內存
畫外音:什麼是trie樹?
普及:trie樹,又稱單詞查找樹,是一種樹形結構,是一種哈希樹的變種。典型應用是用於統計,保存大量的字符串(但不只限於字符串),因此常常被搜索引擎系統用於文本詞頻統計。它的優勢是:利用字符串的公共前綴來減小查詢時間,最大限度地減小無謂的字符串比較,查詢效率比哈希樹高。(來源:百度百科)搜索引擎

例如:上面的trie樹就可以表示{and, as, at, cn, com}這樣5個標題的集合。索引

問4:若是要支持分詞,多個分詞遍歷trie樹,還須要合併對吧?
龍哥:沒錯,每一個分詞遍歷一次trie樹,能夠獲得doc_id的list,多個分詞獲得的list合併,就是最終的結果。內存

問5:龍哥,還有什麼更好,更輕量級的方案麼?
龍哥:用trie樹,數據會膨脹文檔數*標題長度這麼多,標題越長,文檔數越多,內存佔用越大。有個一個方案,內存量很小,和標題長度無關,很是帥氣。文檔

問6:有相關文章麼,推薦一篇?
龍哥:可能網上沒有,我簡單說一下吧,核心思想就是「內存hash + ID list」
索引初始化步驟爲:對全部標題進行分詞,以詞的hash爲key,doc_id的集合爲value
查詢的步驟爲:對查詢詞進行分詞,對分詞進行hash,直接查詢hash表格,獲取doc_id的list,而後多個詞進行合併
=====例子=====
例如:
doc1 : 我愛北京
doc2 : 我愛到家
doc3 : 到家美好
先標題進行分詞:
doc1 : 我愛北京 -> 我,愛,北京
doc2 : 我愛到家 -> 我,愛,到家
doc3 : 到家美好 -> 到家,美好
對分詞進行hash,創建hash + ID list:
hash(我) -> {doc1, doc2}
hash(愛) -> {doc1, doc2}
hash(北京) -> {doc1}
hash(到家) -> {doc2, doc3}
hash(美好) -> {doc3}
這樣,全部標題的初始化就完畢了,你會發現,數據量和標題的長度沒有關係。
用戶輸入「我愛」,分詞後變爲{我,愛},對各個分詞的hash進行內存檢索
hash(我)->{doc1, doc2}
hash(愛)->{doc1, doc2}
而後進行合併,獲得最後的查找結果是doc1+doc2。
=====例子END=====

問7:這個方法有什麼優勢呢?
龍哥:存內存操做,能知足很大的併發,時延也很低,佔用內存也不大,實現很是簡單快速

問8:有什麼不足呢?和傳統搜索有什麼區別咧?龍哥:這是一個快速過分方案,由於索引自己沒有落地,仍是須要在數據庫中存儲固化的標題數據,若是不作高可用,數據恢復起來會比較慢。固然作高可用也是很容易的,創建兩份同樣的hash索引便可。另外,沒有作水平切分,但數據量很是很是很是大時,仍是要作水平切分改進的。

相關文章
相關標籤/搜索