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。因此,可以這樣理解倒排索引:通過單詞找到對應的倒排列表,根據倒排列表中的倒排項進而可以找到文檔記錄)
為了更進一步理解,下面從網上摘了兩張圖來具現化這一過程: