天天看點

一步步拆解解決 Elasticsearch 檢索模闆問題

一步步拆解解決 Elasticsearch 檢索模闆問題
連結

Elasticsearch做模版查詢的時候,在使用 terms 進行批量查詢的時候放入數組在模版中進行查詢失敗,類似于模版傳入數組該如何實作?

問題來源:死磕Elasticsearch知識星球

# 定義索引

PUT uint-2020-08-17

{

   "mappings": {

     "properties": {

       "clock": {

         "type": "date",

         "format": "epoch_second"

       },

       "itemid": {

         "type": "long"

       "ns": {

       "ttl": {

       "value": {

       }

     }

   }

}

# 添加内容

PUT uint-2020-08-17/_bulk

{ "index" : {  "_id" : "1" } }

{"itemid":1,"ns":643214179,"clock":1597752311,"value":"1123","ttl":604800}

{ "index" : {  "_id" : "2" } }

{"itemid":2,"ns":643214179,"clock":1597752311,"value":"123555","ttl":604800}

{ "index" : {  "_id" : "3" } }

{"itemid":3,"ns":643214179,"clock":1597752311,"value":"1","ttl":604800}

{ "index" : {  "_id" : "4" } }

{"itemid":4,"ns":643214179,"clock":1597752311,"value":"134","ttl":604800}

{ "index" : {  "_id" : "5" } }

{"itemid":2,"ns":643214179,"clock":1597752311,"value":"123556","ttl":604800}

查詢語句:

PUT _scripts/item_agg

 "script": {

   "lang": "mustache",

   "source": {

     "_source": [

       "value"

     ],

     "size": 0,

     "query": {

       "bool": {

         "filter": [

           {

             "terms": "{{#toJson}}statuses{{/toJson}}"

           },

             "range": {

               "clock": {

                 "gte": "{{startTime}}",

                 "lte": "{{endTime}}"

               }

             }

           }

         ]

     },

     "aggs": {

       "group_terms": {

         "terms": {

           "field": "itemid"

         },

         "aggs": {

           "avg_value": {

             "avg": {

               "field": "value"

           "max_value": {

             "max": {

         }

 }

查詢模版參數:

POST uint-*/_search/template

 "id": "item_agg",

 "params": {

   "itemid":{

     "statuses":[1,2]

   },

   "startTime":1597752309,

   "endTime":1597752333

以上内容看着很長,根據注釋拆解為:

定義索引、

插入資料、

建立模闆、

構造參數檢索

四個子部分你就不會恐慌了。

2、知識點解讀——搜尋模闆

2.1 什麼是搜尋模闆?

很多人都聽說使用過 索引模闆 index template,索引模闆的好處:

便于跨索引統一模組化;

尤其适合資料量巨大、索引字段類似的業務系統;

靈活便捷。

檢索模闆(search template)大家使用相對較少,在實戰業務場景中:每次業務請求都要構造 DSL,比如:這次查title、下次查content,除此之外的 DSL 部分 都一樣,但兩次請求:後端代碼那裡就要有相應的修改和适配。有沒有不修改、拼接DSL使用檢索的方案?這就引出了搜尋模闆。

搜尋模闆與關系資料庫中的存儲過程非常相似。可以将常用查詢定義為模闆,并且使用 Elasticsearch 的應用程式可以簡單地通過其 ID 引用查詢。

模闆接受在運作時指定參數。搜尋模闆存儲在伺服器端,可以在不更改用戶端代碼的情況下進行修改。

模闆使用Mustache模闆引擎表示。關于 Mustache 可以通路:

http://mustache.github.io/mustache.5.html

2.2 搜尋模闆舉例

根據第一部分實戰中的資料,定義了如下的模闆。

PUT _scripts/cur_search_template

     "match": {

       "{{cur_field}}": "{{cur_value}}"

   "size": "{{cur_size}}"

 "id": "cur_search_template",

   "cur_field":"itemid",

   "cur_value":1,

   "cur_size":50

該模闆:支援使用者自定義動态設定搜尋字段及搜尋參數字段。

實戰中可以通過如下_scripts 的方式,将檢索模闆定義到伺服器端。

如果想檢索别的字段:用戶端或者請求端傳遞不同的參數即可。

真正意義上的實作了:檢索和請求參數的分離。

更多原理和基礎參見官方文檔:

https://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html

2.3 search template 的文法很讓人頭腦

以下内容摘自:Wood 大叔的——Elastic認證考試心得。

按照要求寫一個search template

熟悉search template的mustache模版語言即可輕松寫出,但是很遺憾,平常沒用過search template,雖然知道個大概,但是當時寫的時候,不知道哪裡文法有問題,PUT template總是不成功。猜想可能是哪個位置的字元沒有轉譯産生非法json字元,或者哪一層嵌套有問題。總之就是調試不成功,又浪費了很多時間。

https://elasticsearch.cn/article/6133

如上引用想說明的是:search template的文法比較複雜,如果沒用過,很容易頭大。

3、問題拆解

3.1 原有DSL有錯嗎?

實戰一把,報錯如下:

 "error": {

   "root_cause": [

     {

       "type": "parsing_exception",

       "reason": "[terms] query malformed, no start_object after query name",

       "line": 1,

       "col": 67

   ],

   "type": "parsing_exception",

   "reason": "[terms] query malformed, no start_object after query name",

   "line": 1,

   "col": 67

 },

 "status": 400

3.2 哪裡出了問題?

拆解一下。

script 部分無非包括:檢索部分和聚合部分。

檢索部分是定義 search template 的核心,聚合部分無需關注。

這個時候,可以寫一個檢索 DSL驗證一下是否ok,如下:

POST /_search

 "_source": [

   "value"

 ],

 "size": 0,

 "query": {

   "bool": {

     "filter": [

       {

           "itemid": [

             1,

             2

           ]

         "range": {

           "clock": {

             "gte": 1597752309,

             "lte": 1597752333

     ]

 "aggs": {

   "group_terms": {

     "terms": {

       "field": "itemid"

       "avg_value": {

         "avg": {

           "field": "value"

       "max_value": {

         "max": {

而檢索和聚合都沒錯,那多半就是定義 search template 部分出錯了。

問題就這麼一點點拆解了。

上來直接改這個 DSL貌似也無從下手,那咱們就做:最小化處理吧。

抛去所有:_source、size、aggs、range query 部分,隻保留 terms 腳本應該怎麼正确的寫?

來吧,實戰一把:

第一步:最小化 terms 檢索模闆。

GET _search/template

 "source": "{ \"query\": { \"terms\": {{#toJson}}statuses{{/toJson}} }}",

   "statuses" : {

       "itemid": [ 1, 2 ]

用現在正确的對比第一部分出錯的,可以找到如下兩處錯誤:

錯誤1:source 裡面的内容要加:"\" 。

錯誤2:查詢模版參數中的 statuses 和 itemid 位置寫錯了。

官方文檔的說法:

The {undefined{#toJson}}parameter{undefined{/toJson}} function can be used to convert parameters like maps and array to their JSON representation:

statuses 就是個輔助參數,我們核心的參數是 itemid。

第二步:将第一步内容轉成script 形式。

POST _scripts/test_script_01

   "source": "{ \"query\": { \"terms\": {{#toJson}}statuses{{/toJson}} }}"

POST uint-*/_search/template

 "id": "test_script_01",

   "statuses": {

     "itemid": [

       1,

       2

   "startTime": 1597752309,

   "endTime": 1597752333

第三步:按照實戰要求補全參數即可。

注意補全的時候,我建議:拷貝 DSL(格式化一行的版本)到第三方文本工具如:Nodepad++,全局替換。

一步步拆解解決 Elasticsearch 檢索模闆問題

切記不要手敲,很容易出錯。

替換到模闆的 source 部分,然後再根據第一步、第二步内容修改即可。

實戰問題答案

 "source": "{\"_source\":[\"value\"],\"size\":0,\"query\":{\"bool\":{\"filter\":[{\"terms\":{{#toJson}}statuses{{/toJson}}},{\"range\":{\"clock\":{\"gte\":{{startTime}},\"lte\":{{endTime}}}}}]}},\"aggs\":{\"group_terms\":{\"terms\":{\"field\":\"itemid\"},\"aggs\":{\"avg_value\":{\"avg\":{\"field\":\"value\"}},\"max_value\":{\"max\":{\"field\":\"value\"}}}}}}",

   "params": {

      "startTime":1597752309,

拷貝 source 部分轉換為腳本格式就可以,篇幅問題,不再贅述。

4、小結

看似複雜,拆解後便不複雜。

看似很難,拆解後就很簡單。

檢索模闆用的好,前後端扯皮少、效率高很多!

你的小問題,我的大問題。

和你一起,死磕 Elasticsearch!

參考:

https://elastic-search-in-action.medcl.com/3.site_search/3.3.search_box/search_template/ https://subscription.packtpub.com/book/big_data_and_business_intelligence/9781787128453/7/ch07lvl1sec61/search-templates

推薦:

重磅 | 死磕 Elasticsearch 方法論認知清單(2020年國慶更新版)

能拿駕照就能通過 Elastic 認證考試!