1. 程式人生 > 實用技巧 >Elasticsearch 之 基礎介紹及索引原理分析 【轉】

Elasticsearch 之 基礎介紹及索引原理分析 【轉】

基本概念

Elasticsearch是面向文件型資料庫,一條資料就是一個文件,用JSO作為文件序列化的格式,比如下面的使用者資料。

  1. {
  2. "name" : "John",
  3. "sex" : "Male",
  4. "age" : 25,
  5. "birthDate": "1990/05/01",
  6. "about" : "I love to go rock climbing",
  7. "interests": [ "sports", "music" ]
  8. }

在MySql中資料儲存想到建立一個Use表,key代表為資料庫中的欄位,在Elasticsearch中這裡就表示一個文件,當然這個文件會屬於一個User型別,各式各樣的型別儲存於一個索引中。

一個簡易的Elasticsearch和Mysql的對照表。

  1. 關係資料庫=》資料庫=》表=》行=》列
  2. Elasticsearch=》索引=》型別=》文件=》欄位。

Elasticsearch是如何做到快速查詢的

Elasticsearch使用的倒排索引比MySql的B+Tree的索引更快,為什麼?

關係型資料庫的B+Tree索引,二叉樹的查詢效率是LogN,插入新節點不用移動全部節點,兼顧插入和查詢效能。具體的查詢效能優化後續用單獨的篇章來描述。

倒排索引:是通過欄位中的內容來進行來建立倒排索引,假如對下面的資料進行索引

  1. | ID | Name | Age | Sex |
  2. | -- |:------------:| -----:| -----:|
  3. | 1 | Kate | 24 | Female
  4. | 2 | John | 24 | Male
  5. | 3 | Bill | 29 | Male

對三個欄位分別做倒排索引,結果看到為

  1. Name:
  2. | Term | Posting List |
  3. | -- |:----:|
  4. | Kate | 1 |
  5. | John | 2 |
  6. | Bill | 3 |
  7. Age:
  8. | Term | Posting List |
  9. | -- |:----:|
  10. | 24 | [1,2] |
  11. | 29 | 3 |
  12. Sex:
  13. | Term | Posting List |
  14. | -- |:----:|
  15. | Female | 1 |
  16. | Male | [2,3] |

Posting List 就是一個Int的陣列,儲存了所有符合term的文件ID。當隨著資料量的上漲,Term的資料量也會上漲,如何來提高查詢效率呢?

Term Dictionary與Term Index Elasticsearch採用B數相同的思路,直接通過記憶體查詢Term,但是如果Term太多,Term Dictionary也會很大,放在記憶體不現實,所以有了Term Index,類似欄位的索引頁。Term Index儲存的是term的字首,然後結合FST(Finite sTATE Transducers)壓縮技術,可以是term Index快取到記憶體中,然後通過term index查詢到term Dictionar的位置,然後再去磁碟上找Postion List。FST的原理請參照:FST原理

假設我們現在要將mop, moth, pop, star, stop and top(term index裡的term字首)對映到序號:0,1,2,3,4,5(term dictionary的block位置)。最簡單的做法就是定義個Map<string, integer="">,大家找到自己的位置對應入座就好了,但從記憶體佔用少的角度想想,有沒有更優的辦法呢?答案就是:FST(理論依據在此,但我相信99%的人不會認真看完的)

⭕️表示一種狀態

-->表示狀態的變化過程,上面的字母/數字表示狀態變化和權重

將單詞分成單個字母通過⭕️和-->表示出來,0權重不顯示。如果⭕️後面出現分支,就標記權重,最後整條路徑上的權重加起來就是這個單詞對應的序號。

這裡我還沒有完全搞懂,如何在建立這個FST的時候,標記權重。

壓縮的技巧

Elasticsearch裡除了上面說到用FST壓縮term index外,對posting list也有壓縮技巧。如果索引列的的欄位內容區分度很小,就會造成posting list的陣列非常大,比如性別只有男、女。如果有上千萬個學生,那Postint list 至少有5百萬左右的文件id。Elasticsearch採用Frame Of Reference(增量編碼壓縮,將大數變小數,按位元組儲存),首先要求Posting list是有序的,方便進行壓縮。例如delta encoding,他是將順序的數值進行壓縮,只儲存一個增量數字,1000,1001,1002,1003儲存成 1000,1,2,3 壓縮數值大小,結合變長壓縮等講小數字佔用位數降下來,達到減小佔用空間的效果,詳細的解釋清看這裡:Elasticsearch 的效能優化

  • 第一步:增量編碼就是從第二個數開始每個數儲存與前一個id的差值,即300-73=227302-300=2,...,一直到最後一個數;
  • 第二步:就是將這些差值放到不同的區塊,Lucene使用256個區塊,下面示例為了方便展示使用了3個區塊,即每3個數一組;
  • 第三步:位壓縮,計算每組3個數中最大的那個數需要佔用bit位數,比如30、11、29中最大數30最小需要5個bit位儲存,這樣11、29也用5個bit位儲存,這樣才佔用15個bit,不到2個位元組,壓縮效果很好。

Frame Of Reference 壓縮演算法對於倒排表來說效果很好,但對於需要儲存在記憶體中的Filter快取等不太合適,兩者之間有很多不同之處:倒排表儲存在磁碟,針對每個詞都需要進行編碼,而Filter等記憶體快取只會儲存那些經常使用的資料,而且針對Filter資料的快取就是為了加速處理效率,對壓縮演算法要求更高;這就產生了下面針對記憶體快取資料可以進行高效壓縮解壓和邏輯運算的roaring bitmaps演算法。

Roaring bitmaps,先從bitmap說起。Bitmap是一種資料結構,假設有某個posting list:

[3,1,4,7,8]

對應的Bitmap就是:

[0,1,0,1,1,0,0,1,1]

非常直觀,用0/1表示某個值是否存在,比如8這個值就對應第8位,對應的bit值是1,這樣用一個位元組就可以代表8個文件id(1B = 8bit),舊版本(5.0之前)的Lucene就是用這樣的方式來壓縮的。但這樣的壓縮方式仍然不夠高效,Bitmap自身就有壓縮的特點,其用一個byte就可以代表8個文件,所以100萬個文件只需要12.5萬個byte。但是考慮到文件可能有數十億之多,在記憶體裡儲存Bitmap仍然是很奢侈的事情。而且對於個每一個filter都要消耗一個Bitmap,比如age=18快取起來的話是一個Bitmap,18<=age<25是另外一個filter快取起來也要一個Bitmap。

Bitmap的缺點是儲存空間隨著文件個數線性增長,所以祕訣就在於需要有一個數據結構打破這個魔咒,那麼就一定要用到某些指數特性:

  • 可以很壓縮地儲存上億個bit代表對應的文件是否匹配filter;
  • 這個壓縮的Bitmap仍然可以很快地進行AND和 OR的邏輯操作。

Lucene使用的這個資料結構叫做Roaring Bitmap

其壓縮的思路其實很簡單。與其儲存100個0,佔用100個bit。還不如儲存0一次,然後宣告這個0重複了100遍。

這兩種合併使用索引的方式都有其用途。Elasticsearch 對其效能有詳細的對比,可閱讀Frame of Reference and Roaring Bitmaps

聯合索引:

上面說了半天都是單欄位索引,如果多個欄位聯合查詢,如何快速查詢,有下面兩種方案。

1)利用跳錶(skip list)的資料結構快速做與預算

2)利用上面提到的bitset按位與。

如果使用跳錶方案,對最短的posting list的每個id在另外的兩個多的posting list中查詢是否存在,最後得到交集。

如果使用bitset就更加直觀了,直接按位與,得到的結果就是交集。

最後總結與思考:

1、Elasticsearch的索引思路:儘量講磁碟中的東西搬進記憶體,減少磁碟IO,結合各種壓縮技巧,用苛刻的態度使用記憶體。

2、使用Elasticsearch建立索引的注意事情:1)不需要索引的欄位,一定要明確定義,因為預設是建立索引的 2)對於String欄位,不需要analysis的需要明確定義,因為預設是analysis 3)選擇有規律的ID很重要,隨機性太大的ID不利於查詢。

3、(存有疑惑待研究)可能是最影響查詢效能的,應該是最後通過Posting list裡的ID到磁碟中查詢Document資訊的那步,因為Elasticsearch是分Segment儲存的,根據ID這個大範圍的Term定位到Segment的效率直接影響了最後查詢的效能,如果ID是有規律的,可以快速跳過不包含該ID的Segment,從而減少不必要的磁碟讀次數,具體可以參考這篇如何選擇一個高效的全域性ID方案(評論也很精彩)

文章參考轉載:

1)https://www.520mwx.com/view/44635Elasticsearch 的效能優化

2)https://www.cnblogs.com/dreamroute/p/8484457.htmlElasticsearch-基礎介紹及索引原理分析

3)https://blog.csdn.net/qq_31828515/article/details/56853478 資料結構點陣圖

4)https://blog.csdn.net/yizishou/article/details/78342499RoaringBitmap資料結構及原理