一.反向索引
反向索引的概念,感興趣的可以點選檢視<<ES權威指南中關于反向索引的解釋>>
也可以檢視elasticsearch簡介和倒排序索引介紹這篇文章,寫的很清晰。
1.1 字段和反向索引的關系
首先,在es中,我們可以把一個doc(文檔)了解為資料庫中的一行資料,每個doc對應多個field(字段),例如:
PUT /employee/group/1
{
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
PUT /employee/group/2
{
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}
es中,會在_source中将資料存一份,然後,寫入資料的同時,自動生成mapping資訊,根據mapping資訊,生成字段對應的反向索引檔案。
自動生成的mapping如下:
{
"employee": {
"mappings": {
"group": {
"properties": {
"about": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"age": {
"type": "long"
},
"interests": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
}
按照字段,分别生成反向索引檔案,然後檢索字段的時候,搜尋字段對應的反向索引檔案即可,如下:
age字段:
age字段因為是long類型,整個字段無需分詞(term,token),直接按字段值做反向索引。
term詞條 | docID |
25 | 1 |
32 | 2 |
about字段本身為text類型,支援分詞,about.keyword多域字段為keyword類型,按整詞作為term詞條,是以産生about,about.keyword兩個字段的反向索引檔案。
term詞條 | docID |
i | 1,2 |
love | 1 |
to | 1,2 |
go | 1 |
rock | 1,2 |
climbing | 1 |
like | 2 |
collect | 2 |
albums | 2 |
term詞條 | docID |
I love to go rock climbing | 1 |
I like to collect rock albums | 2 |
ES檢索過程:
1.根據檢索字段,如果是text類型的,按照寫入索引時的分詞機制,進行查詢關鍵字分詞,
2.查詢字段對應的反向索引檔案,查詢term分詞,得到對應的docID
3.根據docID,獲得doc,顯示查詢結果。
提問:
1.about.keyword的作用,換而言之,keyword資料類型和text資料類型的差別?
"about":"I love to go rock climbing"
對上面的about字段,keyword資料類型隻支援精确搜尋,因為keyword建立的索引檔案的term,是全詞建立索引,沒有分詞,是以,對于檢索 about:"i",如果格式為keyword将傳回null,無搜尋結果。如果格式為text,則分詞後建立索引,搜尋 about:"i",有結果,因為有I 的term,由此可見,分詞機制對搜尋影響很大,因為term隻能完全比對,才會得到term對應的文檔。
反向索引的不足
1.反向索引,按分詞建立,建立後不可修改。
ES針對修改反向索引,使用的是再合并政策:對修改的資料建立新的,小的索引檔案,記錄時間,新的索引檔案和舊的索引檔案合并,修改的部分,按時間最新覆寫。
2.反向索引可以很快的通過分詞,得到包含分詞的文檔。但是,如果我們已知文檔,想得到文檔擁有哪些分詞,需要周遊整個反向索引檔案,影響效率。
解決辦法是引入doc_values,doc_values是文檔對應的分詞形成的索引檔案。
3.反向索引十分依賴分詞機制,分詞機制不好,則搜尋結果不理想
ES提供很多分詞機制,也支援自定義分詞機制。當然,如果不需要分詞,隻需要精準比對,直接建立keyword類型資料即可。
二.doc_values 文檔值
2.1. doc_values是什麼
doc_values是elasticsearch中,對于反向索引的部分缺點進行部分補充的功能。檢視dov_values官方解釋
反向索引很友善單項檢視 分詞對應的文檔,但是不利于反向檢視,文檔所有的分詞。doc_values可以了解為反向的反向索引,
doc_values存放的是文檔對應的分詞
2.1 doc_values的應用場景
上面說doc_values 是為了滿足反向查詢反向索引而建立的。那麼,什麼樣的情況我們需要用到doc_values呢。大緻說來,聚合,排序,都會用到doc_values,
首先,我們進行一次聚合。
//增加一條記錄
PUT /employee/group/3
{
"age" : 32,
"about" : "I like to read book",
"interests": [ "music","books" ]
}
//查詢abount中有i的,按age聚合,統計文檔數
GET /employee/_search
{
"query" : {
"match" : {
"about" : "i"
}
},
"aggs" : {
"res": {
"terms" : {
"field" : "age"
}
}
}
}
這條語句主要是為了分析,每個資料出現的次數,例如,music有多少人喜歡,sports有多少人喜歡。結果如下:
{
"aggregations": {
"res": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 32, //age=32的有兩個文檔
"doc_count": 2
},
{
"key": 25, //age=25的有一個文檔
"doc_count": 1
}
]
}
}
}
将上面的查詢聚合過程分解:
1.執行query,查詢about中包含i這個term的doc。得到文檔1,2,3
2.得到文檔1,2,3後,我們分析1,2,3的age字段,判斷每個age的有多少人。
在第2步中,如果我們隻有反向索引檔案,我們需要周遊整個反向索引,去擷取,1,2,3文檔的age索引檔案,按照age索引檔案的term(age是數值類型,整詞形成反向索引,不進行分詞),即age的值,然後合并統計文檔數。
但是如果我們有doc_values之後,就很友善統計了。
doc_values是和反向索引同時建立的。同樣按索引/類型/字段區分索引檔案,doc_value生成資料為:
文檔ID | 包含的term(不分詞的term,即字段對應的值) |
1 | 25 |
2 | 32 |
3 | 32 |
有了doc_values的查詢聚合過程如下:
1.執行query,查詢about中包含i這個term的doc。得到文檔1,2,3
2.得到文檔1,2,3後,查詢age對應的doc_values索引檔案,将age合并,計數,得到25->1,32->2,傳回結果。
搜尋和聚合是互相緊密纏繞的。搜尋使用反向索引查找文檔,聚合操作收集和聚合 doc values 裡的資料。
注意:
doc_values對不分詞的字段預設開啟,包括about.keyword這類多域字段,對分詞字段預設關閉,即about字段
#分詞字段# 從資料類型來看,text預設進行分詞,keyword,long,int,double,複雜資料類型等預設不進行分詞
剛才的描述中,經常強調doc_values存放的是 文檔對應的分詞數,這句話是容易引起歧義的,但是又是正确的,如果,該字段不允許分詞,則該字段的值,就是該文檔在這個索引檔案的唯一分詞(即term),對于能分詞的字段,doc_values是預設關閉,但是可以手動開啟,這個時候,doc_values存放的是文檔對應的分詞數 ,這句話就是正确的。
是以,對于doc_values的用途,ES官網的說法是:
Doc values 不僅可以用于聚合。 任何需要查找某個文檔包含的值的操作都必須使用它。 除了聚合,還包括排序,通路字段值的腳本,父子關系處理,參見 父-子關系文檔
#為什麼對分詞字段關閉# 沒找到官方解釋 、個人看法:對分詞字段,開啟doc_values,産生的索引檔案占用磁盤過大,處理的時候,消耗cpu資源,
doc_values的優缺點
1.doc_values 提高了聚合,排序,所有針對字段值的操作的效率,
2.doc_values加大了磁盤空間,但是ES提供了doc_values的壓縮算法,對doc_values進行了大量壓縮。而且,用不到可以禁用,節省空間。
三.Fielddata
3.1 fielddata是什麼
因為doc_values不針對分詞字段,那麼,如果一定要對分詞字段的term分詞進行聚合,該怎麼辦呢?
在es中,對分詞的field,直接執行聚合操作,會報錯,
{
"type": "illegal_argument_exception",
"reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [about] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead."
}
大概意思是說,你必須要打開fielddata,然後将正排索引資料加載到記憶體中,才可以對分詞的field執行聚合操作,而且會消耗很大的記憶體
fielddata就是滿足該需求的,但是,因為過于消耗資源,是以預設關閉。
fielddata結構和doc_values相同,差別是.fielddata運算時在記憶體中生成,純記憶體計算,doc_values放在磁盤中即可
有需求時,在mapping中打開fielddata開關。預設false關閉。
doc_values和fielddata詳細說明可以檢視部落格 elasticsearch的Doc Values 和 Fielddata
四.store存儲
字段獨立于_source,單獨存儲,
注:_source中依然會存儲該字段
優點: ES中,所有資料統一存在_source中,如果隻是查詢一個小字段,卻要把_source中的整條資料顯示後,再從_source中取出對應的字段,浪費資源。
缺點: 加大磁盤使用。
應用場景: 如果_source很大,頻繁使用的字段很小,則應該store該字段,這樣不需要每次都将_source加載完後,在查找該字段。