Lucene字典的實現原理
1 Lucene字典
使用lucene進行查詢不可避免都會使用到其提供的字典功能,即根據給定的term找到該term所對應的倒排文件id列表等資訊。實際上lucene索引檔案字尾名為tim和tip的檔案實現的就是lucene的字典功能。
怎麼實現一個字典呢?我們馬上想到排序陣列,即term字典是一個已經按字母順序排序好的陣列,陣列每一項存放著term和對應的倒排文件id列表。每次載入索引的時候只要將term陣列載入記憶體,通過二分查詢即可。這種方法查詢時間複雜度為Log(N),N指的是term數目,佔用的空間大小是O(N*str(term))。排序陣列的缺點是消耗記憶體,即需要完整儲存每一個term,當term數目多達上千萬時,佔用的記憶體將不可接受。
2 常用字典資料結構
很多資料結構均能完成字典功能,總結如下。
資料結構 | 優缺點 |
排序列表Array/List | 使用二分法查詢,不平衡 |
HashMap/TreeMap | 效能高,記憶體消耗大,幾乎是原始資料的三倍 |
Skip List | 跳躍表,可快速查詢詞語,在lucene、redis、Hbase等均有實現。相對於TreeMap等結構,特別適合高併發場景(Skip List介紹) |
Trie | 適合英文詞典,如果系統中存在大量字串且這些字串基本沒有公共字首,則相應的trie樹將非常消耗記憶體(資料結構之trie樹) |
Double Array Trie | 適合做中文詞典,記憶體佔用小,很多分詞工具均採用此種演算法(深入雙陣列Trie) |
Ternary Search Tree | 三叉樹,每一個node有3個節點,兼具省空間和查詢快的優點(Ternary Search Tree) |
Finite State Transducers (FST) | 一種有限狀態轉移機,Lucene 4有開源實現,並大量使用 |
3 FST原理簡析
lucene從4開始大量使用的資料結構是FST(Finite State Transducer)。FST有兩個優點:1)空間佔用小。通過對詞典中單詞字首和字尾的重複利用,壓縮了儲存空間;2)查詢速度快。O(len(str))的查詢時間複雜度。
下面簡單描述下FST的構造過程(工具演示:http://examples.mikemccandless.com/fst.py?terms=&cmd=Build+it%21)。我們對“cat”、 “deep”、 “do”、 “dog” 、“dogs”這5個單詞進行插入構建FST(注:必須已排序)。
1)插入“cat”
插入cat,每個字母形成一條邊,其中t邊指向終點。
2)插入“deep”
與前一個單詞“cat”進行最大字首匹配,發現沒有匹配則直接插入,P邊指向終點。
3)插入“do”
與前一個單詞“deep”進行最大字首匹配,發現是d,則在d邊後增加新邊o,o邊指向終點。
4)插入“dog”
與前一個單詞“do”進行最大字首匹配,發現是do,則在o邊後增加新邊g,g邊指向終點。
5)插入“dogs”
與前一個單詞“dog”進行最大字首匹配,發現是dog,則在g後增加新邊s,s邊指向終點。
最終我們得到了如上一個有向無環圖。利用該結構可以很方便的進行查詢,如給定一個term “dog”,我們可以通過上述結構很方便的查詢存不存在,甚至我們在構建過程中可以將單詞與某一數字、單詞進行關聯,從而實現key-value的對映。
4 FST使用與效能評測
我們可以將FST當做Key-Value資料結構來進行使用,特別在對記憶體開銷要求少的應用場景。Lucene已經為我們提供了開源的FST工具,下面的程式碼是使用說明。
FST壓縮率一般在3倍~20倍之間,相對於TreeMap/HashMap的膨脹3倍,記憶體節省就有9倍到60倍!(摘自:把自動機用作 Key-Value 儲存),那FST在效能方面真的能滿足要求嗎?
下面是我在蘋果筆記本(i7處理器)進行的簡單測試,效能雖不如TreeMap和HashMap,但也算良好,能夠滿足大部分應用的需求。
相關文章
- Python 字典實現原理Python
- 深度解析 Lucene 輕量級全文索引實現原理索引
- Lucene查詢原理
- 筆記-集合NSSet、字典NSDictionary的底層實現原理筆記
- Lucene底層原理和最佳化經驗分享(1)-Lucene簡介和索引原理索引
- 從根上理解elasticsearch(lucene)查詢原理(2)-lucene常見查詢型別原理分析Elasticsearch型別
- 基於Lucene查詢原理分析Elasticsearch的效能Elasticsearch
- Python實現建立字典Python
- Python 雜湊表的實現——字典Python
- 後端技術雜談3:Lucene基礎原理與實踐後端
- Elasticsearch Lucene 資料寫入原理 | ES 核心篇Elasticsearch
- 字典樹及其C++實現C++
- python進階(24)Python字典的底層原理以及字典效率Python
- 基於Lucene的全文檢索實踐
- [Redis原始碼閱讀]dict字典的實現Redis原始碼
- python根據字典內的值實現排序Python排序
- Golang 中字典的 Comma Ok 是如何實現的Golang
- Category的實現原理Go
- Vitepress 的實現原理Vite
- synchronized 的實現原理synchronized
- ACID的實現原理
- LinkedList 的實現原理
- python字典合併運算子的原理Python
- 字典樹(字首樹)簡單實現
- Redis設計於實現之字典Redis
- Redis 字典結構實現分析BTRedis
- python如何使用字典實現switchPython
- Redis 設計與實現 4:字典Redis
- Lucene 中的 VInt
- python中的字典賦值操作怎麼實現?Python賦值
- 如何實現不完全字典比較的 helper
- Spring AOP的實現原理Spring
- 前端路由的實現原理前端路由
- React Router 的實現原理React
- Docker的核心實現原理Docker
- 堆的原理與實現
- block實現原理BloC
- ReentrantLock實現原理ReentrantLock
- synchronized實現原理synchronized