Elasticsearch 原理與實現
文件欄位
1 欄位索引
預設情況下,只有text
型別的欄位會儲存文件ID、詞頻、詞序以外,其餘型別欄位均只儲存文件ID。使用者可以在對映欄位時透過index_option
引數來設定,它的可選值為 docs、freqs、positions、offsets,編入索引l的資訊依次增加,具體含義如下:
docs:只有文件ID會被編入索引;
freqs:文件ID、詞頻會被編入索引;
positions:文件ID、詞頻和詞序會被編入索引;
offsets:文件ID、詞頻、詞序和偏移量都會被編入索引。
由此也可以看出,儘管在預設情況下所有的欄位都會被索引,但是這些欄位的原始值是不會被編入索引中的。這意味著使用者可以透過某一欄位的詞項檢索到文件,但並不能直接取到這個欄位的原始值。因為欄位的索引最多隻包含上述四項內容,並不包含欄位原始值。
2 欄位儲存
欄位原始值 _source
索引提供了一個叫_source
的欄位用於儲存整個文件的原始值。_source欄位有一個特性,那就是這個欄位在預設情況下是不會被索引的,但是每個查詢預設都會帶著_source欄位返回。如果確定不需要使用_source欄位儲存源文件,也可以在建立索引透過對映型別的_source
引數將其關閉
PUT /users
{
"mappings":{
_source":{
"enabled":false
}
}
}
於設定對映關係,_source則是控制_source欄位的開關。不推薦關閉_source欄位通常,因為_source欄位與以下一些功能相關聯:
-
使用update、update_by_query更新文件,使用reindex重新索引文件;
-
執行時高亮檢索結果;
-
在不同的Elasticsearch例項間重新索引|文件;
-
使用源文件對檢索和聚集做debug。
關閉_source欄位後,上述功能也將無法使用,所以在考慮關閉_source欄位時要權衡清楚。通常關閉_source欄位的主要原因是出於節省儲存空間,Elastic官方建議如果單純只是考慮節省儲存空間可以透過修改index.codec提高壓縮效率.
文件值 doc_values
doc_values
儲存的並非原始文件內容,而是針對文件中那些可以被用於排序、聚合、指令碼操作等的欄位(列),將其值以一種列式儲存的結構進行儲存,便於快速的資料讀取和相應的計算操作。它實際上是 Elasticsearch 為了提升查詢效能,對特定型別資料進行的一種最佳化儲存方式。例如對於數值型欄位(如文章的字數統計數值)、日期型欄位(如釋出時間)、布林型欄位等,會把這些欄位的值按照 doc_values
的方式儲存起來,方便後續快速查詢和計算分析。
所有非
text
型別的欄位都支援文件值機制,並且都是開啟的
fielddata
文件值doc_values
機制的資料結構儲存在硬碟中,而fielddata
機制則是在記憶體中構建資料結構,所以使用fielddata機制有可能導致JVM記憶體溢位。不僅如此,fielddata機制儲存的也不是欄位原始值,而是透過遍歷倒排索引建立文件與它所包含詞項的對應關係。
具體來說,Elasticsearch會在首次對欄位進行聚集、排序等請求時,遍歷所有倒排索引並在記憶體中構建起文件與詞項之間的對應關係。在預設情況下,text欄位的fielddata機制是關閉的,可以透過在對映欄位時修改fielddata引數開啟。
在開啟fielddata機制前要考慮清楚,因為這種機制顯然非常消耗資源,而且使用text型別欄位做聚集、排序也往往不是合理的需求。即便是真的有這樣的需求,也可以透過欄位多資料型別來開啟文件值機制,而儘量不要使用fielddata機制。
- 文字欄位聚合操作:對於文字型別的欄位,若要進行諸如分組統計不同詞彙出現的頻次、按關鍵詞進行分組等聚合分析時,就需要藉助
fielddata
。比如在一個電商產品索引中,對 “商品評價” 欄位進行分析,統計使用者提及最多的評價關鍵詞,這時fielddata
會幫助解析 “商品評價” 裡的文字內容並用於聚合計算。- 文字欄位排序操作:當要依據文字欄位裡的詞項順序等進行排序時,比如按照使用者搜尋關鍵詞在文件中的匹配順序來對搜尋結果排序,
fielddata
能提供相應的資料支援,讓這種基於文字內容詞項的排序得以實現。- 指令碼中基於文字詞項的操作:在自定義指令碼里,如果需要對文字欄位的詞項進行邏輯判斷、數值計算等操作(比如判斷某個關鍵詞是否在文件的文字欄位中出現,出現次數達到一定數值就進行相應處理),
fielddata
裡儲存的文字詞項相關資料就可以被指令碼訪問和使用。