ES倒排索引原理
Elasticsearch倒排索引結構
一切設計都是為了提高搜尋的效能
倒排索引(Inverted Index)也叫反向索引,有反向索引必有正向索引。通俗地來講,正向索引是通過key找value,反向索引則是通過value找key。
先來回憶一下我們是怎麼插入一條索引記錄的:
curl -X PUT "localhost:9200/user/_doc/1" -H 'Content-Type: application/json' -d' { "name" : "Jack", "gender" : 1, "age" : 20 } '
其實就是直接PUT一個JSON的物件,這個物件有多個欄位,在插入這些資料到索引的同時,Elasticsearch還為這些欄位建立索引——倒排索引,因為Elasticsearch最核心功能是搜尋。
那麼,倒排索引是個什麼樣子呢?
首先,來搞清楚幾個概念,為此,舉個例子:
假設有個user索引,它有四個欄位:分別是name,gender,age,address。畫出來的話,大概是下面這個樣子,跟關係型資料庫一樣
Term(單詞):一段文字經過分析器分析以後就會輸出一串單詞,這一個一個的就叫做Term(直譯為:單詞)
Term Dictionary(單詞字典):顧名思義,它裡面維護的是Term,可以理解為Term的集合
Term Index(單詞索引):為了更快的找到某個單詞,我們為單詞建立索引
Posting List(倒排列表):倒排列表記錄了出現過某個單詞的所有文件的文件列表及單詞在該文件中出現的位置資訊,每條記錄稱為一個倒排項(Posting)。根據倒排列表,即可獲知哪些文件包含某個單詞。(PS:實際的倒排列表中並不只是存了文件ID這麼簡單,還有一些其它的資訊,比如:詞頻(Term出現的次數)、偏移量(offset)等,可以想象成是Python中的元組,或者Java中的物件)
(PS:如果類比現代漢語詞典的話,那麼Term就相當於詞語,Term Dictionary相當於漢語詞典本身,Term Index相當於詞典的目錄索引)
我們知道,每個文件都有一個ID,如果插入的時候沒有指定的話,Elasticsearch會自動生成一個,因此ID欄位就不多說了
上面的例子,Elasticsearch建立的索引大致如下:
name欄位:
age欄位:
gender欄位:
address欄位:
Elasticsearch分別為每個欄位都建立了一個倒排索引。比如,在上面“張三”、“北京市”、22 這些都是Term,而[1,3]就是Posting List。Posting list就是一個數組,儲存了所有符合某個Term的文件ID。
只要知道文件ID,就能快速找到文件。可是,要怎樣通過我們給定的關鍵詞快速找到這個Term呢?
當然是建索引了,為Terms建立索引,最好的就是B-Tree索引(PS:MySQL就是B樹索引最好的例子)。
首先,讓我們來回憶一下MyISAM儲存引擎中的索引是什麼樣的:
我們查詢Term的過程跟在MyISAM中記錄ID的過程大致是一樣的
MyISAM中,索引和資料是分開,通過索引可以找到記錄的地址,進而可以找到這條記錄
在倒排索引中,通過Term索引可以找到Term在Term Dictionary中的位置,進而找到Posting List,有了倒排列表就可以根據ID找到文件了
(PS:可以這樣理解,類比MyISAM的話,Term Index相當於索引檔案,Term Dictionary相當於資料檔案)
(PS:其實,前面我們分了三步,我們可以把Term Index和Term Dictionary看成一步,就是找Term。因此,可以這樣理解倒排索引:通過單詞找到對應的倒排列表,根據倒排列表中的倒排項進而可以找到文件記錄)
為了更進一步理解,下面從網上摘了兩張圖來具現化這一過程:
龍捲風之殤