為什麼Lucene檢索可以比mysql快

2021-09-14 04:40:20 字數 2273 閱讀 6267

mysql只有term dictionary這一層,是以b-tree排序的方式儲存在磁碟上的。檢索乙個term需要若干次的random access的磁碟操作。而lucene在term dictionary的基礎上新增了term index來加速檢索,term index以樹的形式快取在記憶體中。從term index查到對應的term dictionary的block位置之後,再去磁碟上找term,大大減少了磁碟的random access次數。

額外值得一提的兩點是:term index在記憶體中是以fst(finite state transducers)的形式儲存的,其特點是非常節省記憶體。term dictionary在磁碟上是以分block的方式儲存的,乙個block內部利用公共字首壓縮,比如都是ab開頭的單詞就可以把ab省去。這樣term dictionary可以比b-tree更節約磁碟空間。

對於聯合查詢: 所以給定查詢過濾條件 age=18 的過程就是先從term index找到18在term dictionary的大概位置,然後再從term dictionary裡精確地找到18這個term,然後得到乙個posting list或者乙個指向posting list位置的指標。然後再查詢 gender=女 的過程也是類似的。最後得出 age=18 and gender=女 就是把兩個 posting list 做乙個「與」的合併。

這個理論上的「與」合併的操作可不容易。對於mysql來說,如果你給age和gender兩個欄位都建立了索引,查詢的時候只會選擇其中最selective的來用,然後另外乙個條件是在遍歷行的過程中在記憶體中計算之後過濾掉。那麼要如何才能聯合使用兩個索引呢?有兩種辦法:

利用 skip list 合併

以上是三個posting list。我們現在需要把它們用and的關係合併,得出posting list的交集。首先選擇最短的posting list,然後從小到大遍歷。遍歷的過程可以跳過一些元素,比如我們遍歷到綠色的13的時候,就可以跳過藍色的3了,因為3比13要小。

整個過程如下

next -> 2

advance(2) -> 13

advance(13) -> 13

already on 13

advance(13) -> 13 match!!!

next -> 17

advance(17) -> 22

advance(22) -> 98

advance(98) -> 98

advance(98) -> 98 match!!!

最後得出的交集是[13,98],所需的時間比完整遍歷三個posting list要快得多。但是前提是每個list需要指出advance這個操作,快速移動指向的位置。什麼樣的list可以這樣advance往前做蛙跳?skip list:

從概念上來說,對於乙個很長的posting list,比如:

[1,3,13,101,105,108,255,256,257]

我們可以把這個list分成三個block:

[1,3,13] [101,105,108] [255,256,257]

然後可以構建出skip list的第二層:

[1,101,255]

1,101,255分別指向自己對應的block。這樣就可以很快地跨block的移動指向位置了。

lucene自然會對這個block再次進行壓縮。其壓縮方式叫做frame of reference編碼。示例如下:

考慮到頻繁出現的term(所謂low cardinality的值),比如gender裡的男或者女。如果有1百萬個文件,那麼性別為男的posting list裡就會有50萬個int值。用frame of reference編碼進行壓縮可以極大減少磁碟占用。這個優化對於減少索引尺寸有非常重要的意義。當然mysql b-tree裡也有乙個類似的posting list的東西,是未經過這樣壓縮的。

因為這個frame of reference的編碼是有解壓縮成本的。利用skip list,除了跳過了遍歷的成本,也跳過了解壓縮這些壓縮過的block的過程,從而節省了cpu。

金為什麼可以生水?水為什麼可以生木?

五行相生,金生水 水生木 木生火 火生土 土生金,在現代人看來,有些不可理解,例如 金為什麼可以生水?水為什麼可以生木?同理,五行相剋,金剋木 木剋土 土剋水 水剋火 火剋金當中,木剋土 土剋水之類,也有點不好理解,似乎與常識有些格格不入。其實,一切產生於古代的文化,都必須用那個時代的常識或理念來解...

為什麼 比list()更快?

我最近比較了和list 的處理速度,並且驚訝地發現執行速度比list 快三倍以上。我跑了相同的測試與 和dict 結果幾乎相同 和 兩個花了大約0.128sec 百萬次,而list 和dict 大約花費每個0.428sec 萬次。後來我查了查原因,得到的結論如下 list 需要全域性查詢和函式呼叫,...

機器為什麼可以學習

機器學習 人工智慧炙手可熱,但是機器到底為什麼可以學習呢?本文將從霍夫丁不等式講到vc維,機器學習的原因所在。機器什麼時候可以學習 機器怎麼學習 如何讓機器學得更好總結 機器學習乍聽之下很厲害,這時候人就會想,這乙個普普通通的死板的機器,怎麼會學習呢?很容易地,人們舉了個簡單的問題 如下圖 x,y,...