
創作人:駱潇龍
Elasticsearch 允許使用模闆語言 mustache 來預設搜尋邏輯,在實際搜尋時,通過參數中的鍵值,對來替換模闆中的占位符,最終完成搜尋。該方式将搜尋邏輯封閉在 Elasticsearch 中,可以使下遊服務,在不知道具體搜尋邏輯的情況下完成資料檢索。我們以 Kibana 自帶的航班資料
kibana_sample_data_flights
為基礎,以按航班号搜尋為例,簡單介紹搜尋模闆的使用。
第一步,建立 ID 為 testSearchTemplate 的搜尋模闆,語句如下
POST _scripts/testSearchTemplate
{
"script": {
"lang": "mustache", #使用 mustache 模闆語言
"source": { # 腳本内容
"query": { # 搜尋邏輯
"term": {
"FlightNum": {
"value": "{{FlightNum}}" # 占位符 FlightNum
}
}
}
}
}
}
第二步,傳參搜尋資料,語句如下
GET kibana_sample_data_flights/_search/template
{
"id": "testSearchTemplate", # 使用的模闆ID
"params": {
"FlightNum": "9HY9SWR" # 占位符替換的值
}
}
以上兩步就是使用模闆搜尋資料,該邏輯等同于下面這個搜尋
GET kibana_sample_data_flights/_search
{
"query": {
"term": {
"FlightNum": {
"value": "9HY9SWR"
}
}
}
}
API介紹
下面我們從搜尋模闆的生命周期:建立、檢視、使用、删除來展開介紹模闆搜尋相關 API。
準備
在正式介紹之前,我們先來說一說關于模闆搜尋的幾個預備知識。
首先,如果使用的 Elasticsearch 叢集開啟了安全功能,那麼角色對操作的索引必須要有
read
權限。
其次,搜尋模闆使用的文法是
Mustache
更多的關于該種腳本語言的介紹以及功能請檢視其官方 文檔 : https://mustache.github.io/mustache.5.html
最後,模闆搜尋屬于 Elasticsearch 中 Script 功能的擴充, Script 的限定及用法基本都适用于模闆搜尋。比如,叢集關于 Script 的配置也會影響模闆搜尋,配置項
script.allowed_types
可規範模闆搜尋接受的類型( inline / stored / both ),
script.allowed_contexts
也會限制模闆搜尋可進行的操作。
建立
搜尋模闆的建立與 Elasticsearch 其它腳本的建立一樣,都是發送 1 個
POST
請求即可。
如下所示:
POST _scripts/<templateId> # 1
{
"script": {
"lang": "mustache", # 2
"source": { # 3
"query": {
"term": {
"FlightNum": {
"value": "{{FlightNum}}" # 可變參數 FlightNum
}
}
}
}
}
}
- 向
發送 POST 請求來建立搜尋模闆,其中_scripts/<templateId>
是你為該模闆設定的 ID,搜尋時會用到該 ID<templateId>
- lang 參數配置的是搜尋模闆使用的腳本語言為
mustache
- source 參數配置的是搜尋模闆的具體内容,該部分的格式參照 Elasticsearch 搜尋的請求 body,需要搜尋時填充的值使用
文法,配置占位符即可,比如本例中的占位符就是mustache
{{FlightNum}}
檢視
當我們想檢視之前建立的模闆内容,或者驗證某個 ID 的模闆是否存在時,可以向
_scripts/<templateId>
發送 GET 請求來擷取模闆的具體内容。
示例如下:
GET _scripts/<templateId> # 1
{
"_id" : "testSearchTemplate", # 2
"found" : true, # 3
"script" : { # 4
"lang" : "mustache",
"source" : """{"query":{"term":{"FlightNum":{"value":"{{FlightNum}}"}}}}""",
"options" : { # 5
"content_type" : "application/json; charset=UTF-8"
}
}
}
- 請求的 path 為
,其中_scripts/<templateId>
為你要查詢的模闆 Id,請求類型為 GET<templateId>
- 傳回的 body 中,_id 屬性再次表明此次查詢的模闆 ID,本示例查詢的是之前建立的
模闆testSearchTemplate
- found 屬性表明此次查詢是否查到結果,如果模闆 ID 存在則此值為 true,反之為 false
- script 就是該搜尋模闆的具體内容與儲存時相同。核心有 lang 屬性表示腳本文法,source 屬性存放腳本具體内容
- script 屬性中的 Options 屬性是非必要其它腳本屬性,預設會有 content_type 屬性,該屬性儲存查詢時 http 請求的
,預設為content-type
application/json; charset=UTF-8
删除
在一個搜尋模闆完成了它的使命後,我們需要及時删除它,因為 Elasticsearch 預設緩存腳本的資料量是有上限的,删除的方式很簡單,發送一個
DELETE
DELETE _scripts/<templateId> #1
<templateId>
為要删除的搜尋模闆的 ID,比如
_scripts/testSearchTemplate
表示的就是删除 ID 為
testSearchTemplate
的搜尋模闆。
使用
搜尋模闆的使用就是在搜尋時,直接發送占位符的值,即可執行預設搜尋語句。由于還是在搜尋的範疇,是以發送請求的 path 是
_search/template
。
下面是關于使用搜尋模闆進行查詢的示例:
GET <index>/_search/template?<query_parameters> #1
{
"source": """{"query": {"term": {"FlightNum": {"value": "{{FlightNum}}"}}}}""", #2
"id": "testSearchTemplate", # 3
"params": { # 4
"FlightNum": "9HY9SWR"
},
"profile": true, # 5
"explain": true # 6
}
模闆搜尋發送的位址為
<index>/_search/template
,與搜尋一樣
<index>
處為選填參數,你可以指定搜尋的索引,不指定則表示搜尋全部索引。
因為本質上還是屬于搜尋的範疇,是以一些搜尋參數在模闆搜尋是也可以使用,比如:
- scroll(可選,時長):表示本搜尋需要支援遊标搜尋,遊标過期時間為配置值
- ccs_minimize_roundtrips(可選,布爾值):如果為 true 則在跨叢集搜尋時最小化叢集間互動。預設為 true
- expand_wildcards(可選,字元串):表示索引通配符作用的範圍,可配置為全部(all)、打開索引(open)、關閉索引(closed)、隐藏索引(hidden,需要與open或closed結合使用)、不允許通配符(none)
- explain(可選,布爾值):表示傳回結果是否帶計算得分的詳細資訊,預設是false
- ignore_throttled(可選,布爾值):如果為 true 則表示查詢忽略被限制的索引,被限制的索引一般指被當機(freeze)的索引,該值預設是 true
- ignore_unavailable(可選,布爾值):如果為 true 則表示關閉的索引不在搜尋範圍内,預設值為 true
- preference(可選,字元串):指定執行該操作的節點或分片,預設是随機的
- rest_total_hits_as_int(可選,布爾值):如果為 true 則 hits.total 将會是個數值而非一個對象,預設為 false
- routing(可選, 字元串):配置搜尋執行的路由
- search_type(可選,字元串):這是搜尋的類型,可選值有:query_then_fetch、dfs_query_then_fetch
- source 字段:用于配置搜尋模闆,該字段與 ID 字段沖突隻能二選一,使用 source 表示不使用儲存的模闆而使用本模闆
- id 字段:表示本次查詢使用的搜尋模闆 ID,該字段與 source 字 段沖突隻能二選一
- params 字段:配置的 key-value 值将替換模闆中的占位符執行搜尋
- profile 字段:是可選字段,表示傳回結果中是否有 Elasticsearch 執行搜尋的一些元資訊
- explain 字段:是可選字段,與 http 中搜尋參數配置的 explain 含義一樣,表示結果是否帶計算得分的詳細資訊
上述搜尋傳回結果如下:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 9.071844,
"hits" : [
{
"_shard" : "[kibana_sample_data_flights][0]",
"_node" : "ydZx8i8HQBe69T4vbYm30g",
"_index" : "kibana_sample_data_flights",
"_type" : "_doc",
"_id" : "KPRFDHkB9LctWlE3WLqj",
"_score" : 9.071844,
"_source" : {
"FlightNum" : "9HY9SWR",
"DestCountry" : "AU",
"OriginWeather" : "Sunny"
},
"_explanation" : {} # 計算得分的邏輯
}
]
},
"profile" : {} # 搜尋細節資訊
}
其它
本部分将介紹關于模闆搜尋的一些小技巧。通常情況下我們寫的搜尋模闆,往往是很難一次就配置正确的,是以需要頻繁的測試我們寫的模闆,與參數結合後是否是我們預期的搜尋語句,這時我們就可以使用以下這個請求,來校驗模闆使用是否正确。
GET _render/template # 1
{
"source": """{"query": {"term": {"FlightNum": {"value": "{{FlightNum}}"}}}}""" ,# 2
"params": { # 3
"FlightNum": "9HY9SWR"
}
}
{ # 4
"template_output" : {
"query" : {
"term" : {
"FlightNum" : {
"value" : "9HY9SWR"
}
}
}
}
}
-
發送 GET 請求來驗證模闆是否正确_render/template
- source 字段為要驗證的搜尋模闆,該字段可以省略,如果省略需要在 path 處指定模闆iID,比如
_render/template/testSearchTemplate
- params 字段為模闆使用的參數
- 此 JSON 就是該請求的傳回,
字段就是在使用此template_output
下搜尋模闆生成的查詢語句params
模闆語言 mustache 有許多功能,這裡再介紹幾個比較常見的。
比如我們使用占位符替換的不是一個字元串,而是一個對象或數組對象,那麼我們可以用
{{#toJson}}{{/toJson}}
來實作,
具體如下:
GET _render/template
{
"source": """{"query": {"term": {"FlightNum": {{#toJson}}FlightNum{{/toJson}} }}}""", # 1
"params": { # 2
"FlightNum": {
"value":"9HY9SWR"
}
}
}
{ # 3
"template_output" : {
"query" : {
"term" : {
"FlightNum" : {
"value" : "9HY9SWR"
}
}
}
}
}
在配置模闆時,我們将
FlightNum
的 value 配置為
{{#toJson}}FlightNum{{/toJson}}
,即表示占位符
FlightNum
是一個對象
在配置 params 時,我們将 FlightNum 的值設定為一個 JSON 對象
{ "value":"9HY9SWR"}
通過校驗請求的傳回,可以看到
{{#toJson}}FlightNum{{/toJson}}
被替換為對象
{ "value":"9HY9SWR"}
Mustache 還能在将變量套入模闆時做一些處理,比如将數組變量組合成字元串放入模闆、設定占位符的預設值,以及對 URL 轉碼。
示例如下
GET _render/template
{
"source": {
"query": {
"term": {
"FlightNum": "{{#join delimiter='||'}}FlightNums{{/join delimiter='||'}}", #1
"DestCountry":"{{DestCountry}}{{^DestCountry}}AU{{/DestCountry}}",#2
"Dest": "{{#url}}{{Dest}}{{/url}}"#3
}
}
},
"params": {
"FlightNums": [
"9HY9SWR",
"adf2c1"
],
"Dest":"http://www.baidu.com"
}
}
{
"template_output" : {
"query" : {
"term" : {
"FlightNum" : "9HY9SWR||adf2c1", # 4
"DestCountry" : "AU", #5
"Dest" : "http%3A%2F%2Fwww.baidu.com" # 6
}
}
}
}
第一個模闆使用
{{#join delimiter='||'}}{{/join delimiter='||'}}
設定了數組合并的分割字元為 "||",傳參時
FlightNums
配置的為
["9HY9SWR","adf2c1"]
,而生成的則是 #4 處的
9HY9SWR||adf2c1
第二個模闆使用
{{^DestCountry}}AU{{/DestCountry}}
設定了占位符 DestCountry 的預設值為 AU,這樣我們在params中并未配置 DestCountry 的值,但生成的 #5 處自動用 AU 替換了占位符
第三個模闆我們用
{{#url}}{{/url}}
聲明了此處是一個 URL,需要進行轉義,則在 #6 處配置的
http://www.baidu.com
變為了
http%3A%2F%2Fwww.baidu.com