使用lucene進行查詢不可避免都會使用到其提供的字典功能,即根據給定的term找到該term所對應的倒排文件id列表等資訊。實際上lucene索引檔案字尾名為tim和tip的檔案實現的就是lucene的字典功能。
怎麼實現乙個字典呢?我們馬上想到排序陣列,即term字典是乙個已經按字母順序排序好的陣列,陣列每一項存放著term和對應的倒排文件id列表。每次載入索引的時候只要將term陣列載入記憶體,通過二分查詢即可。這種方法查詢時間複雜度為log(n),n指的是term數目,占用的空間大小是o(n*str(term))。排序陣列的缺點是消耗記憶體,即需要完整儲存每乙個term,當term數目多達上千萬時,占用的記憶體將不可接受。
很多資料結構均能完成字典功能,總結如下。
資料結構
優缺點排序列表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有開源實現,並大量使用
lucene從4開始大量使用的資料結構是fst(finite state transducer)。fst有兩個優點:1)空間占用小。通過對詞典中單詞字首和字尾的重複利用,壓縮了儲存空間;
2)查詢速度快。o(len(str))的查詢時間複雜度。
下面簡單描述下fst的構造過程(工具演示:
)。我們對「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的對映。
我們可以將fst當做key-value資料結構來進行使用,特別在對記憶體開銷要求少的應用場景。lucene已經為我們提供了開源的fst工具,下面的**是使用說明。
1 public static void main(string args) ;fst壓縮率一般在3倍~20倍之間,相對於treemap/hashmap的膨脹3倍,記憶體節省就有9倍到60倍!(摘自:把自動機用作 key-value 儲存),那fst在效能方面真的能滿足要求嗎?4 long outputvalues = ;
5 positiveintoutputs outputs = positiveintoutputs.getsingleton(true);
6 builderbuilder = new builder(fst.input_type.byte1, outputs);
7 bytesref scratchbytes = new bytesref();
8 intsref scratchints = new intsref();
9 for (int i = 0; i < inputvalues.length; i++)
13 fstfst = builder.finish();
14 long value = util.get(fst, new bytesref("dog"));
15 system.out.println(value); // 18
16 } catch (exception e)
19 }
下面是我在蘋果筆記本(i7處理器)進行的簡單測試,效能雖不如treemap和hashmap,但也算良好,能夠滿足大部分應用的需求。
lucene索引檔案大小優化小結
lucene join解決父子關係索引
排序學習實踐
lucene如何通過docid快速查詢field欄位以及最近距離等資訊?
字典大致實現原理
一 nsdictionary使用原理 1.nsdictionary 字典 是使用 hash 表來實現 key和 value 之間的對映和儲存的,hash 函式設計的好壞影響著資料的查詢訪問效率。void setobject id anobject forkey id akey 2.objective...
lucene字典實現原理
使用lucene進行查詢不可避免都會使用到其提供的字典功能,即根據給定的term找到該term所對應的倒排文件id列表等資訊。實際上lucene索引檔案字尾名為tim和tip的檔案實現的就是lucene的字典功能。怎麼實現乙個字典呢?我們馬上想到排序陣列,即term字典是乙個已經按字母順序排序好的陣...
Python 字典實現原理
a a key1 1 a key2 6 del a key1 python直譯器 執行 a python直譯器讀到這裡,比如會給5個連續的記憶體空間,有5個連續的記憶體位址,可以放資料 python直譯器 執行 a key1 1 這裡,python直譯器會對key1進行雜湊運算,得到乙個十位進製的雜...