您好,登錄后才能下訂單哦!
ElasticSearch使用Nested結(jié)構(gòu)如何進(jìn)行存儲(chǔ)KV及聚合查詢,相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。
下面將討論如何在ElasticSearch中使用nested結(jié)構(gòu)進(jìn)行數(shù)據(jù)的存儲(chǔ)、查詢和聚合,并結(jié)合K-V場(chǎng)景討論ElasticSearch針對(duì)field數(shù)量限制的解決方案。
ElasticSearch對(duì)于field的數(shù)量有限制,默認(rèn)情況下field的數(shù)量如果超過(guò)1000個(gè),寫(xiě)入時(shí)再創(chuàng)建新的fields就會(huì)報(bào)錯(cuò):
java.lang.IllegalArgumentException: Limit of total fields [1000] in index [(index_name)] has been exceeded at org.elasticsearch.index.mapper.MapperService.checkTotalFieldsLimit(MapperService.java:630)
但有些場(chǎng)景的field數(shù)量并不是我們能控制的,例如在監(jiān)控系統(tǒng)中的業(yè)務(wù)數(shù)據(jù)所攜帶的業(yè)務(wù)標(biāo)簽,其中可能包含了監(jiān)控系統(tǒng)不能預(yù)知的業(yè)務(wù)字段。
對(duì)于這種情景,可能想到的解決方案兩個(gè):
調(diào)整ElasticSearch的配置,增加field的限制數(shù)量:這種方案僅僅適用于可以預(yù)測(cè)出field數(shù)量極限的情況,治標(biāo)不治本,一旦field數(shù)量再次抵達(dá)限制,又會(huì)面臨同樣的問(wèn)題。
就是使用Pair結(jié)構(gòu)來(lái)存儲(chǔ)
假設(shè)第2種方案的數(shù)據(jù)結(jié)構(gòu)為:
{ "labels": [{ "key": "ip", "value: "127.0.0.1" }] }, { "labels": [{ "key": "ip", "value: "127.0.0.2" }] }
那么es查詢就會(huì)存在一個(gè)問(wèn)題,例如下面的查詢:
{ "query":{ "bool":{ "must":[ { "match":{ "key":"ip" } }, { "match":{ "value":"127.0.0.1" } } ] } } }
這個(gè)查詢會(huì)把例子中的的數(shù)據(jù)全部查詢出來(lái),并不符合我們的預(yù)期。這是因?yàn)閑s在存儲(chǔ)索引時(shí),對(duì)于普通object類型的field實(shí)際上是打平來(lái)存儲(chǔ)的,比如這樣:
{ "labels.key":[ "ip" ], "labels.value":[ "127.0.0.1", "127.0.0.2" ] }
可以看見(jiàn),索引打平后,對(duì)象的關(guān)聯(lián)關(guān)系丟失了。對(duì)于這種情況,ElasticSearch提供的nested結(jié)構(gòu)可以幫助我們解決類似的問(wèn)題。Nested結(jié)構(gòu)保留了子文檔數(shù)據(jù)中的關(guān)聯(lián)性,如果labels的數(shù)據(jù)格式被定義為nested,那么每一個(gè)nested object將會(huì)作為一個(gè)隱藏的單獨(dú)文本建立索引。如下:
{ "labels.key":"ip", "labels.value":"127.0.0.1" }, { "labels.key":"ip", "labels.value":"127.0.0.2" }
通過(guò)分開(kāi)給每個(gè)nested object建索引,object內(nèi)部的字段間的關(guān)系就能保持。當(dāng)執(zhí)行查詢時(shí),只會(huì)匹配’match’同時(shí)出現(xiàn)在相同的nested object的結(jié)果。
使用nested結(jié)構(gòu)非常簡(jiǎn)單,指定字段的type為nested即可。下面的例子中定義了一個(gè)名為labels的nested結(jié)構(gòu),其中包含兩個(gè)字段,分別是key和value。
"mappings": { "demoType": { "labels": { // 字段類型設(shè)置為nested "type": "nested", "properties": { "key": { "type": "keyword" }, "value": { "type": "keyword" } } } } }
nested結(jié)構(gòu)的數(shù)據(jù)查詢和普通object略有不同,nested object作為一個(gè)獨(dú)立隱藏文檔單獨(dú)建索引,因此,不能直接查詢到它們。取而代之,我們必須使用nested查詢或者nested filter。例如:
{ "query": { "bool": { "must": [ { "nested": { "path": "labels", "query": { "bool": { "must": [ { "term": { "labels.key": "ip" } }, { "term": { "labels.value": "127.0.0.1" } } ] } } } } ] } } }
這個(gè)查詢可以返回我們預(yù)期的正確結(jié)果:
[{ "labels": { "key": "ip", "value": "127.0.0.1" } }]
查詢的問(wèn)題解決了,聚合時(shí)問(wèn)題又來(lái)了,前面我們說(shuō)到,nested結(jié)構(gòu)存儲(chǔ)在一個(gè)隱藏的單獨(dú)文本索引中,那么普通的聚合查詢自然便無(wú)法訪問(wèn)到它們。因此,nested結(jié)構(gòu)在聚合時(shí),需要使用特定的nested聚合。
假設(shè)es中存儲(chǔ)如下數(shù)據(jù):
[{ "labels": [{ "key": "ip", "value": "127.0.0.1" },{ "key": "os", "value": "windows" }] }, { "labels": [{ "key": "ip", "value": "127.0.0.2" },{ "key": "os", "value": "linux" }] }]
我們要聚合所有對(duì)labels.value
進(jìn)行聚合,可以使用下面的方式:
{ "size": 0, "aggs": { "labels_nested": { "nested": { "path": "labels" }, "aggs": { "nested_value": { "terms": { "field": "labels.value" } } } } } }
這個(gè)查詢將會(huì)得到下面類似的結(jié)果:
{ "aggregations": { "labels_nested": { "doc_count": 2, "nested_value": { "buckets": [ { "doc_count": 1, "key": "127.0.0.1" }, { "doc_count": 1, "key": "127.0.0.2" }, { "doc_count": 1, "key": "windows" }, { "doc_count": 1, "key": "linux" } ] } } } }
上面的例子可以看到,其只是單純的將所有的value進(jìn)行了聚合,并沒(méi)有針對(duì)k-v中的key進(jìn)行過(guò)濾,因此導(dǎo)致labels.key
為ip
和os
的數(shù)據(jù)均被統(tǒng)計(jì)到了其中,這通常不符合我們實(shí)際場(chǎng)景中的需求。
現(xiàn)在假設(shè)要對(duì)所有labels.key
為ip
的labels.value
進(jìn)行聚合,那么可以使用如下的方式:
{ "size": 0, "aggs": { "labels_nested": { "nested": { "path": "labels" }, "aggs": { "nested_ip": { "filter": { "term": { "labels.key": "ip" } }, "aggs": { "nested_value": { "terms": { "field": "labels.value" } } } } } } } }
通過(guò)這樣的方式就可以把labels.key
不是ip
的文檔過(guò)濾掉,經(jīng)過(guò)這個(gè)查詢將得到類似如下的結(jié)果:
{ "aggregations": { "labels_nested": { "doc_count": 2, "nested_ip": { "doc_count": 2, "nested_value": { "buckets": [ { "doc_count": 1, "key": "127.0.0.1" }, { "doc_count": 1, "key": "127.0.0.2" } ] } } } } }
如果想在nested聚合下嵌套聚合其它字段,直接嵌套是不行的,這里需要使用到reverse_nested
跳出當(dāng)前nested聚合后,再進(jìn)行嵌套聚合。
注意:無(wú)論是嵌套其它nested字段還是普通字段,都需要使用reverse_nested跳出當(dāng)前nested聚合。
例如想對(duì)labels.key
為ip
聚合后,再對(duì)labels.key
為os
進(jìn)行聚合:
{ "size": 0, "aggs": { "labels_nested": { "nested": { "path": "labels" }, "aggs": { "nested_ip": { "filter": { "term": { "labels.key": "ip" } }, "aggs": { "nested_ip_value": { "terms": { "field": "labels.value" }, "aggs": { "reverse_labels": { "reverse_nested": {}, //注意這里 "aggs": { "nested_os": { "nested": { "path": "labels" }, "aggs": { "labels_os": { "filter": { "term": { "labels.key": "os" } }, "aggs": { "labels_os_value": { "terms": { "field": "labels.value" } } } } } } } } } } } } } } } }
如此,將得到類似下面的結(jié)果:
{ "aggregations": { "labels_nested": { "doc_count": 2, "nested_ip": { "nested_ip_value": { "buckets": [ { "doc_count": 1, "reverse_labels": { "doc_count": 1, "nested_os": { "labels_os": { "doc_count": 1, "labels_os_value": { "buckets": [ { "doc_count": 1, "key": "windows" } ] } }, "doc_count": 1 } }, "key": "127.0.0.1" }, { "doc_count": 1, "reverse_labels": { "doc_count": 1, "nested_os": { "labels_os": { "doc_count": 1, "labels_os_value": { "buckets": [ { "doc_count": 1, "key": "linux" } ] } }, "doc_count": 1 } }, "key": "127.0.0.2" } ] }, "doc_count": 2 } } } }
至此,關(guān)于nested結(jié)構(gòu)存儲(chǔ)K-V的用法就介紹完啦!使用nested結(jié)構(gòu)可以幫助我們保持object內(nèi)部的關(guān)聯(lián)性,借此解決elasticsearch對(duì)field數(shù)量的限制。nested結(jié)構(gòu)不僅可以應(yīng)用在K-V結(jié)構(gòu)的場(chǎng)景,還可以應(yīng)用于其它任何需要保持object內(nèi)部關(guān)聯(lián)性的場(chǎng)景。
注意:使用nested結(jié)構(gòu)也會(huì)存在一些問(wèn)題:
增加,改變或者刪除一個(gè)nested文本,整個(gè)文本必須重新建索引。nested文本越多,代價(jià)越大。
檢索請(qǐng)求會(huì)返回整個(gè)文本,而不僅是匹配的nested文本。盡管有計(jì)劃正在執(zhí)行以能夠支持返回根文本的同時(shí)返回最匹配的nested文本,但目前還未實(shí)現(xiàn)。
看完上述內(nèi)容,你們掌握ElasticSearch使用Nested結(jié)構(gòu)如何進(jìn)行存儲(chǔ)KV及聚合查詢的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。