英文原文: https://qbox.io/blog/elasticsearch-search-tuning-part-2作者:Adam Vanderbush
譯者:楊振濤
目錄
- 預索引資料
- 映射
- 避免使用腳本
- 強制合并隻讀索引
Elasticsearch搜尋調優權威指南,是QBOX在其部落格上釋出的系列文章之一,本文是該系列的第二篇,主要介紹了索引預處理、mapping建立、避免腳本的使用、索引段合并等搜尋性能相關的調優方法。
本文是Elasticsearch搜尋調優系列文章3篇中的第2篇,
第1篇參考這裡(點選)。本系列教程旨在更進一步讨論針對Elasticsearch 5.0及以上版本的搜尋調優技術、政策及建議。
1.預索引資料
為了優化資料的索引方式,應當在查詢中預置一些模式。比如,如果所有文檔都有一個叫 price 的價格字段,并且大部分查詢在一個固定範圍清單上執行 range 聚合,那麼就可以通過預索引範圍到索引中并使用一個 terms 聚合,來加速該聚合。
比如有如下文檔:
curl -XPUT 'ES_HOST:ES_PORT/index/type/1
?pretty' -H 'Content-Type: application/json' -d '{
"designation": "bowl",
"price": 13
}'
以及如下搜尋請求:
curl -XGET 'ES_HOST:ES_PORT/index/_search
?pretty' -H 'Content-Type: application/json' -d '{
"aggs": {
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{ "to": 10 },
{ "from": 10, "to": 100 },
{ "from": 100 }
]
}
}
}
}'
然後就可以在索引階段增加一個 price_range 字段,該字段應該映射為一個關鍵字:
curl -XPUT 'ES_HOST:ES_PORT/index
?pretty' -H 'Content-Type: application/json' -d '{
"mappings": {
"type": {
"properties": {
"price_range": {
"type": "keyword"
}
}
}
}
}'
curl -XPUT 'ES_HOST:ES_PORT/index/type/1
?pretty' -H 'Content-Type: application/json' -d '{
"designation": "bowl",
"price": 13,
"price_range": "10-100"
}'
接下來搜尋請求就能聚合這個新的字段,而不是在 price 字段上執行一個範圍聚合。
curl -XGET 'ES_HOST:ES_PORT/index/_search
?pretty' -H 'Content-Type: application/json' -d '{
"aggs": {
"price_ranges": {
"terms": {
"field": "price_range"
}
}
}
}'
2.映射
事實上,一些數值型的資料,并不意味着總是要被映射為一個數值型字段。典型的,那些存儲為諸如 ISBN 之類的辨別符,或者任何辨別另一個資料庫中記錄的數字的字段,可能映射為關鍵字比映射為一個 integer 或 long 類型更好。
關鍵字類型用于索引結構化内容,比如 email 位址、主機名稱、狀态碼、郵政編碼或标簽。
典型地用于過濾(比如查找所有已釋出的部落格文章)、排序以及聚合。關鍵字字段隻可通過其精确值搜尋得到。
如果需要索引全文内容比如 email 内容或産品描述,可能就要使用一個文本字段。
下面是一個關鍵字字段映射的示例:
curl -XPUT 'ES_HOST:ES_PORT/my_index
?pretty' -H 'Content-Type: application/json' -d '{
"mappings": {
"my_type": {
"properties": {
"tags": {
"type": "keyword"
}
}
}
}
}'
從 2.x 版本導入的索引是不支援關鍵字的;相反,它們會試圖把 keyword 類型降級為 string 類型。這支援合并新的映射和舊的映射。長期存在的索引,必須在更新到6.x 版本前重建,但是映射降級提供了按自己的計劃實施重建的機會。
3.避免使用腳本
一般來說要盡量避免使用腳本;如果必須要使用,優先選擇 Painless 和表達式引擎。
Painless 是一門簡單安全的腳本語言,專門為在 Elasticsearch 中使用而設計,是 Elasticsearch 的預設腳本語言,可安全地用于内聯和存儲腳本。關于 Painless 文法和語言特性的更較長的描述,請參考 Painless 語言規範。
請參考 “ Painless Scripting in Elasticsearch ” 更深入地了解 Painless 腳本語言指南。
- Lucene 表達式語言
Lucene 表達式會把一個 javascript 表達式編譯為位元組碼,設計用于高性能自定義評級和排序函數,并支援 inline 和預設的存儲腳本。
- 性能
表達式相對于自定義 Lucene 代碼而言,有着更好的性能表現;其性能相對其他腳本引擎有更低的單文檔成本:表達式更加“領先”。
這就允許非常快的執行,尤其是比自己寫的本地腳本快很多。
- 文法
表達式支援一個 javascript 文法子集:一個單獨的表達式。參見表達式子產品的文檔,了解支援的操作符和函數。
表達式腳本中可通路的變量有:
- 文檔字段,比如doc['myfield'].value
- 字段所支援的變量和方法,比如doc['myfield'].empty
- 傳遞到腳本裡的參數,比如mymodifier
- 目前文檔得分,_score(僅在 script_score中使用時有效)
表達式腳本可以用于script_score、script_fields、排序腳本以及數值型聚合腳本,隻要簡單地設定參數到表達式中即可。
4.強制合并隻讀索引
隻讀索引在合并為單一的段後将會非常受益。典型的情況是基于時間的索引:隻有目前時間窗的索引會成為新文檔,同時舊索引成為隻讀。
強制合并 API 支援通過 API 強制合并一個或更多的索引。合并與每個分片中 Lucene索引的段數量有關。強制合并操作支援通過合并來減少段數量。
該調用在合并完成之前将會處于阻塞狀态。如果 http 連接配接斷掉,請求将在背景繼續,在前一個強制合并完成之前,所有新請求将會阻塞。
curl _XPOST 'ES_HOST:ES_POST/twitter/_forcemer
ge?pretty'
強制合并 API 接受下列請求參數:
- max_num_segments - 待合并的段數量。要完全合并索引,可設定為 1 。預設會簡單檢查一個合并是否需要執行,如果是,就會執行。
- only_expunge_deletes -合并流程是否僅僅擦除包含删除的段。在 Lucene 中,一個文檔并不會從一個段直接删除,隻是标記為删除。在一個段合并的過程中,一個新的段可能會被建立,這個新的段并不包含那些删除。這個标記參數支援隻合并有删除的段,且預設為false。注意,這并不會重寫門檻值 index.merge.policy.expunge_deletes_allowed。
- flush - 強制合并後是否執行 flush,預設為 true。