Elasticsearch:ES 倒排索引爲什麼查詢速度會這麼快

https://www.jianshu.com/p/addefe15f3e9

 

0. 前言

Elasticsearch 是一個分佈式可擴展的實時搜索和分析引擎,它建立在全文搜索引擎 Apache Lucene™ 的基礎上。Elasticsearch 之所以可以實現近乎實時的檢索,依靠的技術手段是非常多的,本文將從 反向索引、Term Index 兩塊知識點入手,分析 Elasticsearch 之所以那麼快的原因。

1. 反向索引

1.1. 正向索引

  • 什麼是正向索引
    在解釋反向索引之前,需要先了解一下什麼是正向索引,這也將解釋倒排索引之所以會出現的背景原因。
    所謂正向索引,其結構就是每個文檔和關鍵字做關聯,每個文檔都有與之對應的關鍵字,記錄關鍵字在文檔中出現的位置和次數,用戶查詢的時候是根據關鍵字去查詢的。
    例如,搜索引擎在處理網頁文檔的時候,會從網頁中提取出來一些特殊關鍵詞,比如文章標題、文本內容、作者、單位、網頁閱讀數、點贊數、評論數等等,同時統計關鍵詞出現的次數、位置、格式等信息,之後將這些提取的詞組成一個集關鍵詞合。
    這樣,網頁文檔與關鍵詞之間的映射關係是 一個網頁文件對應多個關鍵詞,被存儲進搜索引擎的索引庫,其所實現的是一個 “文檔-關鍵詞” 矩陣, 如下表展示:
網頁 關鍵詞
web_1 馬雲, 馬雲, 馬化騰,...
web_2 馬雲, 汽車, 飛機, ...
... ...
web_x_1 火星, 金星, ...
... ...
web_x_2 火星, 火星, 木星, ...
... ...
web_n ...

在上表所展示的 “文檔-關鍵詞” 矩陣索引中,如果用戶使用搜索引擎查找目標關鍵字(比如 火星),搜索引擎就會從索引庫中所有的關鍵字包含 火星 的文檔,也就是 web_x_1、web_x_2,並根據網頁文件自身的價值評分高低(比如關鍵詞出現的次數)按順序展示給用戶,用戶得到的就是 按順序 展示的 web_x_2web_x_1 兩個網頁。這就是正向索引實現的大致流程。

  • 正向索引的問題
    這個過程存在一個致命的問題,那就是在海量的網頁裏找到所有的關鍵詞包含 火星 的網頁,將是一個漫長的過程,在上面的例子中,如果總共有 1000億個網頁,並且有100萬個包含火星,那麼需要的計算量是驚人的。
    實際上,受制於時間、內存、處理器等等資源的限制,技術上正向索引是不能實現的。
    在這種背景下,倒排索引出現了。

1.2. 反向索引

  • 什麼是反向索引
    反向索引(Inverted Index),也叫倒排索引,相比於正向索引,其採用的是 “關鍵詞-文檔” 矩陣,關鍵詞與網頁文檔之間的映射關係是 一個關鍵詞對應多個網頁文檔,如下圖所示:
關鍵詞 網頁
馬雲 web_1, web_2
馬化騰 web_1
汽車 web_2
飛機 web_2
... ...
火星 web_x_2, web_x_1
... ...
金星 web_x_1
木星 web_x_2
... ...

在這個矩陣中,火星 關鍵詞對應的所有網頁都被提前找到,甚至網頁文檔的權重都被提前計算好並排序,當用戶輸入 火星 關鍵詞時,就會立刻到 web_x_2, web_x_1 的反饋結果。
這裏有些人會有疑問,關鍵詞數量會不會太多,以至於超過網頁問的數量,這樣效率不會反而變低了麼,其實不然,人類的語言詞彙數量是相對有限、且固定的,但網頁數量卻沒有上限。比如漢語中,漢字30000個、詞彙大概40萬,但漢語網站數量卻遠遠不止這麼些。
需要注意的是,由於每個字或詞對應的文檔數量在動態變化,所以倒排表的建立和維護都較爲複雜,但是在查詢的時候由於可以一次得到查詢關鍵字所對應的所有文檔,所以效率高於正排表。

2. Term Index

2.1. Term & Posting List

  • 在上面的例子中,創建的是一個簡單的反向索引,但 Elasticsearch 的索引結構實際上並不表現爲這種形態,首先網頁文檔在索引中只表現爲一個 int 類型的 文檔di,而且索引中用於查找網頁文檔的只有 關鍵詞 一項,實際我們在做業務中需要面對的情況要複雜得多。
    下面展示了一個商品信息的二維數據表樣例:
id Name Color Rate
1 iphone 666 plus black high
2 Huawei mate 98k blue high
3 Chuzi game over black middle

針對這個表,Elasticsearch 會創建如下的索引:
索引一:Name

Term Posting List
iphone 666 plus 1
Hauwei mate 98k 2
Chuzi game over 3

索引二:Color

Term Posting List
black [1, 3]
blue 2

索引三:Rate

Term Posting List
high [1, 2]
middle 3

在這個索引中,Name、Color、Rate 這些字段被稱爲 filed, iphone 666 plus、blue、middle 這些被稱作 Term,而 Term 對應的所有商品的 id 比如 [1, 3] 就是 Posting List
當用戶要查找 Color=blue 的商品時,通過索引三的 Term 和 Posting List 很快就可以找到,目標是 id 爲 2 的商品,進而通過索引一找到商品 Name 爲 華爲 mate 98k。

2.2. Term Dictionary

上面簡單解釋了 Term 和 Posting List,但實際生產中 Elasticsearch 需要面對的是數以億計的數據記錄,數據的 Term 的數量是驚人的,這樣往往需要花費大量時間才能命中,而且多數時候查找是多條件查找,這就需要多次進行重複查找,效率仍然不高。
這時就需要對 Term 進行優化排序,即使用 二分查找 查找 Term,這種查找方法類似於通過字典查找,被稱爲 Term Dictionary 。
同樣是上面的例子,Name、Color、Rate 三個索引下所有的 Term,按照 首字母在英語字母表中位置 排序後如下:

Term Posting List
black [1, 3]
blue 2
Chuizi game over 3
high [1, 2]
Huawei mate 98k 2
iphone 666 plus 1
middle 3

當用戶想要查找 rate 爲 high 的商品時,通過二分法很快就可以查到,查找過程的時間複雜度爲 log N,這樣就大大提高了查找的速度。關於二分查找,細節這裏就不做贅述了,如果不清楚的朋友們可以自行百度,或點擊 二分查找 獲取更多信息。

2.3. Term Index

到這裏很多人會有疑問,那這和傳統的 B-tree 有什麼區別呢,這就需要引入另一個概念 Term Index。
Term Index 其實也可以理解爲一個樹形結構,從 Term 的第一個字母開始進行第一層排序,如果有多個 Term 首字母相同,則從該字母爲起始點進行第二層排序,如果以該字母爲首的只有一個 Term,則不再進行第二次排序。
同樣是上面的例子,其 Term Index 如下圖所示:

 

image.png

在上圖中,字母 b 爲首的 Term 有兩個,分別爲 blue 和 black,這時就需要進行第二層排序,即對第二位字母進行排序,這時我們發現兩個 Term 的第二位字母都爲 l,於是進行第三層排序,第三層排序的結果是 bla、blu ,分別對應 black、blue 兩個 Term,並對應 [1, 3]、2 兩個 Posting List。對應關係如下圖所示:

image.png

在 Term Index 中需要保存的是 Term 的前面部分字段,以及與 Term Dictionary 之間的映射關係,這使得存儲的信息量減少。再結合 FST(Finite State Transducer)壓縮技術,Term Iindex 可以被壓縮到足夠小,以至於可以被緩存進服務器內存中。這樣,在用戶查找的時候,先在內存裏從 Term Index 找到 Term Dictionary 中的位置映射關係,然後再去磁盤上找對應的 Term,進而查找對應的 Posting List,這就大大減少了磁盤的讀取次數,也就提高了效率和速度。

2.4. FST(Finite State Transducer)

關於 FST 壓縮技術,請參考這篇文章:https://www.shenyanchao.cn/blog/2018/12/04/lucene-fst/,英語好的可以看下這篇論文https://cs.nyu.edu/~mohri/pub/fla.pdf,裏面對FST有詳細的解釋。

這裏先埋一個坑,將來有時間再來填。



 

 

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