知識分享-ELK介紹 (2) ===== # Agenda 1. ElasticSearch 介紹 2. Elasticsearch Index 設計 3. Elasticsearch 資料查找 4. Elasticsearch 資料統計 ![](https://i.imgur.com/IlLwUys.png) # ElasticSearch 介紹 1. [Lucene](https://zh.wikipedia.org/wiki/Lucene) 全文檢索引擎 2. 使用 Rest API 3. 使用 JSON 作為文檔資料序列化格式 4. 文件導向資料庫 - 可以存儲整個物件(Object)或文檔(Document),提供文檔資料的處理、索引、搜索、排序、過濾。 5. Near RealTime (NRT) 微小延遲接近即時 (normally 1s) 6. 分散式架構 <iframe src="https://www.facebook.com/plugins/post.php?href=https%3A%2F%2Fwww.facebook.com%2Fpermalink.php%3Fstory_fbid%3D1385281961640196%26id%3D998741260294270&show_text=true&width=500" width="500" height="712" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowfullscreen="true" allow="autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share"></iframe> # Elasticsearch Index 設計 ## Dynamic mapping and Explicit mappings 1. 動態 Mapping - Elasticsearch僅通過索引文檔即可自動添加新欄位。 :::info 使用[Dynamic templates](https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic-templates.html)來定義自定義映射,這些自定義映射將基於匹配條件動態添加欄位。 ::: 2. 明確 Mapping - 在建立index的時候創建映射類型和欄位映射,或通過mapping API添加映射類型和欄位到一個已經存在的index中。 ## 欄位資料型態 >參考 : >[mapping-types](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html) ### String datatypes 1. Text - 用於索引全文值的欄位,分析過程允許 Elasticsearch 搜索每個全文欄位中的單個單詞。 - Text 的欄位不用於排序,很少用於聚合。 2. Keyword - 用於索引結構化內容的欄位,它們通常用於過濾、排序和聚合。 - Keyword 欄位只能按其確切值進行搜索。 ### Numeric datatypes - Long: 帶符號64位元整數 (-2^64^ ~ 2^64^-1) - Integer: 帶符號32位元整數 (-2^32^ ~ 2^32^-1) - Short:帶符號16位元整數 (-2^16^ ~ 2^16^-1) - Byte:帶符號8位元整數 (-2^8^ ~ 2^8^-1) - Double: 雙精度64位元浮點數 - Float:精度32位元浮點數 - Half_float:半精度16位元浮點數 - Scaled_float:會透過 scaling factor把浮點數字變成整數 ```json= PUT my-index-000001 { "mappings": { "properties": { "number_of_bytes": { "type": "integer" }, "time_in_seconds": { "type": "float" }, "price": { "type": "scaled_float", "scaling_factor": 100 } } } } ``` ### Date datatype JSON沒有日期數據類型,因此Elasticsearch中的日期可以是: - 包含格式化日期的字符串 "2015-01-01"或"2015/01/01 12:10:30"。 - 一個自紀元以來毫秒數的數字。 - 一個自紀元以來秒數的數字。 ```json= PUT my-index-000001/_doc/1 { "date": "2015-01-01" } PUT my-index-000001/_doc/2 { "date": "2015-01-01T12:10:30Z" } PUT my-index-000001/_doc/3 { "date": 1420070400001 } ``` 日期格式可以自定義,但是如果未指定,則預設使用: :::info "strict_date_optional_time||epoch_millis" ::: ### Boolean datatype 布林欄位接受JSON true和false值,但也可以接受被解釋為true或false的字符串。 - False values: false , "false" - True valus: true, "true" ### Binary datatype 二進制類型接受二進制值作為Base64編碼的字符串。 默認情況下不存儲該欄位,並且不可搜索。 ```json= PUT my-index { "mappings" : { "properties" : { "rawdata" : { "type" : "binary" } } } } POST my-index2/_doc/ { "rawdata" : "aGVsbG93b3JsZA==" } ``` ### Range datatype Range 型態支持 - Integer_range:一個帶符號32位元Range (-2^32^ ~ 2^32^-1) - Float_range: 一個精度32位元浮點數Range - Long_range: 一個帶符號64位元Range(-2^64^ ~ 2^64^-1) - Dobule_range: 一個雙精度64位元浮點數Range - Date_range:自系統紀元以來經過的無符號64位整數毫秒。 - Ip_range: 支持IPv4或IPv6(或混合)地址的一系列ip值 **建立index 與欄位定義** ```json= PUT range_index { "mappings": { "properties": { "expected_attendees": { "type": "integer_range" }, "time_frame": { "type": "date_range", "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" } } } } ``` **新增資料** ```json= PUT range_index/_doc/1?refresh { "expected_attendees" : { "gte" : 10, "lt" : 20 }, "time_frame" : { "gte" : "2015-10-31 12:00:00", "lte" : "2015-11-01" } } ``` **範圍搜尋** ```json= GET range_index/_search { "query" : { "range" : { "time_frame" : { "gte" : "2015-10-31", "lte" : "2015-11-01", "relation" : "within" } } } } ``` ### Array datatype 在Elasticsearch中,沒有專用的Array類型。 預設情況下,任何欄位都可以包含零個或多個值,而 Array 中的所有值必須具有相同的資料類型。 例如: - 字串陣列: ["one","two"] - 數值陣列: [1,2] - 陣列的陣列: [1, [2,3]] 相當於 [1,2,3] - 物件陣列: [{"name":"Mary","age":12}, {"name":"John","age":10}] ### Object datatype - JSON文檔本質上是分層的:文檔可能包含內部物件 ```json= PUT my-index-000001/_doc/1 { "region": "US", "manager": { "age": 30, "name": { "first": "John", "last": "Smith" } } } ``` ## Index Lifecycle > 參考: >[喬叔教 Elastic - 10 - 管理 Index 的 Best Practices (2/7) - 三溫暖架構 - Hot Warm Cold Architecture](https://ithelp.ithome.com.tw/articles/10243650) 1. Hot Node - 因為會處理 Indexing 的請求,所以 JVM heap 會有一定比例拿來處理 Indexing。 2. Warm Node - 不處理 Indexing 所以只會有一半 JVM heap 拿來處理 query request,剩下的會來給 Lucene 用作暫存。 3. Cold Node - 不會處理 Indexing,而且針對 query request 所產生的 transient cache 也會一用完就盡快的釋放,減少 heap 的使用。 3. Delete - 長時間不被使用的Index,可安全被刪除。 ### 建立 Lifecycle Policy **國際卡監控使用 housekeeping policy** ```json= PUT /_ilm/policy/housekeeping_policy { "policy": { "phases": { "hot": { "min_age": "0ms", "actions": { } }, "warm": { "min_age": "30h", "actions": { } }, "cold": { "min_age": "14d", "actions": { } }, "delete": { "min_age": "35d", "actions": { "delete": { } } } } } } GET /_ilm/policy/housekeeping_policy?pretty=true ``` **alert policy** 當超過 100mb 或 200000筆資料進行滾動,替換至下一個index ```json= PUT /_ilm/policy/alert_policy { "policy": { "phases": { "hot": { "min_age": "0ms", "actions": { "rollover": { "max_size": "100mb", "max_docs": 200000 } } }, "delete": { "min_age": "7d", "actions": { "delete": { } } } } } } GET /_ilm/policy/alert_policy?pretty=true ``` ### 建立 Index Template > 參考 : > [喬叔教 Elastic - 06 - Index 建立前你該知道的 (3/5) - ES 的超前佈署 - Index Template](https://ithelp.ithome.com.tw/articles/10239736?sc=hot) **以國際卡監控 Index Template 為例** transaction_template : 1. index_patterns - 套用該 Template 的 index patterns 2. priority - Index Template 的優先順序,數字愈大愈優先 3. version - 自定義版本號 4. template - 可以包含 Aliases, Mappings, Index Settings 的設定 5. number_of_shards - 將Index細分為多個分片分散儲存在多個節點。 - 提供水平拆分/縮放資料、分片分佈及平行化操作,以提高資料操作性能及吞吐量。 6. number_of_replicas - 為防止Index大量處理資料時,造成分片及節點異常後資料的損失。 - 提供一個或多個副本的索引分片,確保分片及節點發生故障時提供高可用性,並且支持在副本上並行搜索。 7. index.lifecycle.name - 套用 Lifecycle Policy ```json= PUT /_index_template/transaction_template { "index_patterns": [ "transaction_message-*", "application_status_tree-*", "application_log-*", "batch_log-*" ], "priority": 100, "version": "00001", "template": { "settings": { "number_of_shards": 3, "number_of_replicas": 1, "index.lifecycle.name": "housekeeping_policy" } } } GET /_index_template?name=transaction_template&pretty=true ``` alert_template: - index.lifecycle.rollover_alias : 替 index 取別名 ```json= PUT /_index_template/alert_template { "index_patterns": [ "alert-*" ], "priority": 100, "version": "00001", "template": { "settings": { "number_of_shards": 1, "number_of_replicas": 1, "index.lifecycle.name": "alert_policy", "index.lifecycle.rollover_alias": "alert" } } } GET /_index_template?name=alert_template&pretty=true ``` # Elasticsearch 資料查找 ## Query DSL **Query DSL (Domain Specific Language) 提供基於JSON來定義查詢。** 由兩種類型的子句組成: - Leaf query clauses (簡單查詢) - 葉查詢子句查找特定欄位中的特定值,例如 match, term 或 range 查詢。這些查詢可以單獨使用。 - Compound query clauses (複雜查詢) - 複合查詢子句包裝其他葉查詢或複合查詢,用於以邏輯方式組合多個查詢(例如bool) ## 分詞 把全文字轉換成一系列單詞(term/token)的過程叫做分詞 ```json= GET _analyze { "analyzer": "standard", "text": "this is a test" } ``` :::info "this is a test" 進行分詞 => ["this","is","a","test"] ::: 分詞系統使用特殊符號進行分隔 標點符號可能是單詞的一部分取決於它的位置: ```json= GET /_analyze?tokenizer=standard You're my 'favorite'. ``` :::info ["You're","my","favorite"] ::: >參考 : >[ElasticSearch 分詞器,瞭解一下](https://www.gushiciku.cn/pl/pYl8/zh-tw) >[CKIP 中文斷詞](https://ckip.iis.sinica.edu.tw/resource) ## 資料欄位型別 ### text 和 keyword 區別 - text 進行分詞 - keyword 不進行分詞 ```json= GET /my-index/ { "my-index" : { "aliases" : { }, "mappings" : { "properties" : { "message" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } } } } ``` - 欄位message 為 text - 欄位message.keyword 為 keyword ## Search API ### Match And Term query Match - 提供的文本,數字,日期或布爾值匹配的文檔。 - 匹配之前對提供的文本進行分析。 - 該match查詢是用於執行全文搜索的標準查詢,其中包括模糊匹配的選項。 Term - 提供的欄位中包含確切詞語的文檔。 - 您可以使用term查詢根據精確的值(例如價格,產品ID或用戶名)查找文檔。 :::info 避免term對text欄位使用查詢。 默認情況下,Elasticsearch更改text欄位的值,作為analysis的一部分,這會使查找text欄位值的精確匹配變得困難。 要搜索text欄位值,請改用match查詢。 ::: #### match和term的區別 - match 進行分詞 - term 不進行分詞 範例 ```json= #建立資料 POST my-index/_doc/ { "message" : "this is a test" } ``` 分詞結果["this","is","a","test"] match 匹配成功 ```json= #match 查詢 GET /my-index/_search { "query": { "match": { "message":"this is a test" } } } ``` - match分詞後["this","is","a","test"],任一條件匹配即可 term 匹配失敗 ```json= #term 查詢 GET /my-index/_search { "query": { "term": { "message":"this is a test" } } } ``` - term不進行分詞,將["this is a test"]視為一個分詞條件 - 若要使term匹配,則要使用message.keyword 1. term查詢keyword欄位,需要完全匹配才可以 2. term查詢text欄位,term查詢條件必須是text欄位分詞後 3. match查詢text欄位,只要match的分詞結果和text的分詞結果有相同就匹配 4. match查詢keyword欄位,ES使用Term Analyzer,與term查詢一致 ### match_all 搜尋全部文檔 ```json= GET /my-index/_search { "query": { "match_all": {} } } ``` ### multi_match (match query)允許多欄位查詢 ```json= GET /my-index/_search { "query": { "multi_match": { "query":"this is a", "fields": ["message","name"] } } } ``` ### match_phrase match_phrase : 欄位分詞中都包含,而且順序必須相同,而且必須都是連續的 ```json= GET /my-index/_search { "query": { "match_phrase": { "message":"this is a test" } } } ``` ### match_phrase_prefix match_phrase_prefix 和match_phrase類似,只不過match_phrase_prefix 支援最後一個term字首比對 ```json= GET /my-index/_search { "query": { "match_phrase_prefix": { "message":"this is a te" } } } ``` ### range query ```json= GET /transaction_message-*/_search { "query": { "range": { "@timestamp": { "gte": "now-1d/d", "lt": "now/d" } } } } ``` ```json= GET /transaction_message-*/_search { "query": { "range": { "timestamp": { "time_zone": "+08:00", "gte": "2020-05-01T00:00:00", "lte": "now" } } } } ``` ### Bool query - Bool 查詢可以把任一個簡單查詢組合在一起,使用must、should、must_not 關鍵字處理。 |Bool query|邏輯運算式| |--|--| |must|AND| |should|OR| |must_not|NOT| ```json= GET /my-index/_search { "query": { "bool": { "must": [ { "bool": { "should": [ { "match":{"message":"this"} }, { "match":{"message":"is"} } ], "must_not": [ { "match":{"message":"test"} } ] } }, { "bool": { "must": [ { "match":{"message":"shark"} } ] } } ] } } } ``` ## Query and Filter - 查詢子句的使用行為取決於它是在查詢、還是在篩選使用: 1. Query DSL: - 查詢除了確定文檔是否匹配外,並且計算一個_score,表示文檔相對於其他文檔的匹配程度。 2. Filter DSL: - 查詢文檔是否與此查詢子句匹配,並不計算任何分數,因此篩選上下文主要用於篩選結構化資料,而Elasticsearch會自動緩存常用的篩選器,以加快性能。 ```json= GET /transaction_message-*/_search { "query": { "bool": { "must": [ { "term":{"message.mti.keyword":"0800"} } ], "filter": [ { "range": { "@timestamp": { "gte": "now-1d/d", "lt": "now/d" } } } ] } } } ``` ### From/Size - 在請求體中的查詢欄位允許使用查詢DSL定義一個查詢。透過From和Size參數控制分頁,size參數允許你配置返回結果的最大數量。 注意: from+size不能超過index.max_result_window選項,默認值是10000 ```json= #第1頁,取10筆 GET /transaction_message-*/_search { "from": 1, "size": 10, "query": { "bool": { "must": [ { "term":{"message.mti.keyword":"0800"} } ], "filter": [ { "range": { "@timestamp": { "gte": "now-1d/d", "lt": "now/d" } } } ] } } } ``` ### Sort 允許添加一個或者多個排序,每個排序都可以指定排序規則。使用欄位名的排序是定義在欄位層面的,使用_score表示按得分排序,使用_doc表示按索引時間的順序排序。 ```json= GET /transaction_message-*/_search { "from": 1, "size": 10, "sort": [ {"message.mti.keyword": "desc"}, "_score" ], "query": { "bool": { "filter": [ { "range": { "@timestamp": { "gte": "now-1d/d", "lt": "now/d" } } } ] } } } ``` ### Sort Values 排序值也作為返回結果的一部分返回 |Sort|以order選項控制| |--|--| |asc|升序| |desc|降序| |參數| 說明| |--|--| |min| 數組中最小的值作為排序值 |max| 數組中最大的值作為排序值 |sum| 數組中所有元素的總和作為排序值 |avg| 數組中所有元素的平均值作為排序值 |median| 使用所有值的中位數作為排序值 ```json= POST price/_doc/ { "name": "bbb", "price" : [1,10,51,63,20,100] } GET /price/_search { "sort": [ { "price": { "order": "desc", "mode": "min" } } ] } ``` ### Query string query 查詢使用語法運算符(例如AND 、 NOT)來解析和拆分提供的查詢字符串。 [說明](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html) ```json= GET tb_inc_internal_sync-*/_search { "size": 1, "query": { "query_string":{ "analyze_wildcard":true, "query":"tran_code:05 AND card_plan:M AND setl_flag:9" } } } ``` #### Wildcards 通配符 使用 ? 代表1個字元 使用 * 代表0到多 個字元 #### Regular expression 正規表示式 在反斜線內使用正規表示式 name:/joh?n(ath[oa]n)/ #### Fuzziness 模糊查詢 可以搜尋相近但不完全不正確的詞 查找最大兩個變化的所有術語,其中變化是單個字符的插入,刪除或替換,或者兩個相鄰字符的轉置。 ```json= quikc~ brwn~ foks~ ``` 預設的編輯距離是2,但是編輯距離1應該足以捕捉所有人類拼寫錯誤的80%。可以指定為: ```json= quikc~1 ``` ### Ranges 可以為日期,數字或字串指定範圍。 包含範圍用方括號[min TO max] 排除範圍用花括號{min TO max} ```json= 2012年所有天數: date:[2012-01-01 TO 2012-12-31] 數字1..5 count:[1至5] 於alpha和omega之間的tag,但不包括alpha和omega: tag:{alpha TO omega} 10以上的數字 count:[10 TO *] 2012年之前的日期 date:{* TO 2012-01-01} 數字1到5但不包含5 count:[1 TO 5} ``` ## SQL access ### SQL REST API 使用 SQL REST API 進行查詢 Kibana: ```json= POST /_sql?format=json { "query": """SELECT * FROM "tb_inc_internal_sync-*" ORDER BY tran_code DESC LIMIT 1""" } ``` <!-- .slide: style="font-size: 26px;" --> ### SQL Translate API 將API 語法 轉換為Elasticsearch 原生語法 ```json= POST /_sql/translate { "query": """SELECT * FROM "tb_inc_internal_sync-*" where tran_code.keyword='05' ORDER BY tran_code DESC LIMIT 1""", "fetch_size": 10 } ``` # Elasticsearch 資料統計 >參考 : >[search-aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html) Elasticsearch將聚合分為三類: 1. Bucket Aggregations - 根據field的值、範圍或其他條件將documents分組為桶。 1. Metrics Aggregations - 從field的值計算度量,如總和或平均值。 1. Pipeline Aggregations - 匯總其他聚合ouput獲取輸入。 ## Terms aggregation >參考 : >[search-aggregations-bucket-terms-aggregation](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html) - 針對某個 field 的值進行分組,field 有幾種值就分成幾組 - terms 桶在進行分組時,會爲此 field 中的每種值創建一個新的桶 ### 範例1 ```json= GET tb_inc_internal_sync-*/_search { "query": { "match_all": {} }, "size": 0, "aggs": { "my_tran_code": { "terms": { "field": "tran_code.keyword", "min_doc_count": 1, "size": 10, "order": {"_key": "asc"} } } } } ``` 參數: - min_doc_count 限制最低數量 - size 顯示 bucket 中多少筆數據,預設是 10 - order 預設是照doc_count排序 - script 可以使用腳本來組合欄位再統計數量 - include/exclude 可以藉由這兩個參數filter設定的條件 處理結果 ```json= "aggregations" : { "my_tran_code" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ { "key" : "05", "doc_count" : 245 }, { "key" : "06", "doc_count" : 31 } ] } } ``` ### 範例2 將 terms 桶搭配度量指標(avg、min、max、sum…)一起使用 ```json= GET tb_inc_internal_sync-*/_search { "query": { "match_all": {} }, "size": 0, "aggs": { "my_tran_code": { "terms": { "field": "tran_code.keyword", "min_doc_count": 0 }, "aggs": { "my_avg_amt": { "avg": { "field": "src_amt" } }, "my_sum_amt": { "sum": { "field": "src_amt" } }, "my_min_amt": { "min": { "field": "src_amt" } } } } } } ``` ```json= "aggregations" : { "my_tran_code" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ { "key" : "05", "doc_count" : 245, "my_min_amt" : { "value" : 500.0 }, "my_avg_amt" : { "value" : 2024105.7142857143 }, "my_sum_amt" : { "value" : 4.959059E8 } }, { "key" : "06", "doc_count" : 31, "my_min_amt" : { "value" : 500.0 }, "my_avg_amt" : { "value" : 3990.3225806451615 }, "my_sum_amt" : { "value" : 123700.0 } } ] } } ``` ## Filter aggregation ### 範例 ```json= GET tb_inc_internal_sync-*/_search { "size": 0, "aggs": { "my_avg_amt": { "avg": { "field": "src_amt" } }, "my_filter": { "filter": { "term": { "tran_code": "05" } }, "aggs": { "avg_price": { "avg": { "field": "src_amt" } } } } } } ``` 結果 ```json= "aggregations" : { "my_filter" : { "doc_count" : 245, "avg_price" : { "value" : 2024105.7142857143 } }, "my_avg_amt" : { "value" : 1797208.6956521738 } } ``` 使用 filters aggregation 做多重過濾 要使用多個過濾器對文檔進行分組,請使用 filters聚合。這比使用多個filter聚合要快。 ```json= POST /sales/_search?size=0&filter_path=aggregations { "aggs": { "f": { "filters": { "filters": { "hats": { "term": { "type": "hat" } }, "t_shirts": { "term": { "type": "t-shirt" } } } }, "aggs": { "avg_price": { "avg": { "field": "price" } } } } } } ``` 取代 ```json= POST /sales/_search?size=0&filter_path=aggregations { "aggs": { "hats": { "filter": { "term": { "type": "hat" } }, "aggs": { "avg_price": { "avg": { "field": "price" } } } }, "t_shirts": { "filter": { "term": { "type": "t-shirt" } }, "aggs": { "avg_price": { "avg": { "field": "price" } } } } } } ``` ## Range aggregation 在聚合過程中,將從每個存儲區範圍中檢查從每個文檔中提取的值,並“存儲”相關/匹配的文檔。 請注意,此聚合包括from值,但不包括to每個範圍的值。 ### 範例 ```json= GET tb_inc_internal_sync-*/_search { "size": 0, "aggs": { "amt_ranges": { "range": { "field": "src_amt", "ranges": [ { "to": 10000 }, { "from": 10000, "to": 20000 }, { "from": 20000 } ] } } } } ``` 結果 ```json= "aggregations" : { "amt_ranges" : { "buckets" : [ { "key" : "*-10000.0", "to" : 10000.0, "doc_count" : 94 }, { "key" : "10000.0-20000.0", "from" : 10000.0, "to" : 20000.0, "doc_count" : 46 }, { "key" : "20000.0-*", "from" : 20000.0, "doc_count" : 136 } ] } } ``` ## 範例 (國際卡日報統計) **filter 使用 時間戳記 及 message.mti 過濾** **Group by role,mti,procCode 並統計 error ,success,system_err,timeout 筆數** ```json= GET transaction_message-*/_search { "size": 0, "query": { "bool": { "filter": [ { "range": { "@timestamp": { "time_zone": "+08:00", "gte": "2021-06-10T00:00:00", "lt": "2021-06-11T00:00:00" } } }, { "query_string": { "analyze_wildcard": true, "query": "!(message.mti:0800)" } } ] } }, "aggs": { "role": { "terms": { "field": "message.role.keyword", "size": 10000 }, "aggs": { "mti": { "terms": { "field": "message.mti.keyword", "size": 10000 }, "aggs": { "pcode": { "terms": { "field": "message.procCode.keyword", "size": 10000 }, "aggs": { "error": { "filter": { "query_string": { "analyze_wildcard": true, "query": "resperr:1" } } }, "success": { "filter": { "query_string": { "analyze_wildcard": true, "query": "resperr:0" } } }, "system_err": { "filter": { "query_string": { "analyze_wildcard": true, "query": "resperr:1 AND message.respCode:(03|15|19|21|30|68|74|79|80|88|89|91|92|96|98|I1|I2|I3|I6|I7|I8|I9|IA)" } } }, "timeout": { "filter": { "query_string": { "analyze_wildcard": true, "query": "resperr:1 AND message.isTimeout:true" } } } } } } } } } } } ```