真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

ElasticSearch使用Nested結(jié)構(gòu)如何進(jìn)行存儲KV及聚合查詢

ElasticSearch使用Nested結(jié)構(gòu)如何進(jìn)行存儲KV及聚合查詢,相信很多沒有經(jīng)驗(yàn)的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。

創(chuàng)新互聯(lián)主營雨花網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,手機(jī)APP定制開發(fā),雨花h5微信小程序開發(fā)搭建,雨花網(wǎng)站營銷推廣歡迎雨花等地區(qū)企業(yè)咨詢

下面將討論如何在ElasticSearch中使用nested結(jié)構(gòu)進(jìn)行數(shù)據(jù)的存儲、查詢和聚合,并結(jié)合K-V場景討論ElasticSearch針對field數(shù)量限制的解決方案。

為何要使用Nested結(jié)構(gòu)存儲KV(鍵值對)?

ElasticSearch對于field的數(shù)量有限制,默認(rèn)情況下field的數(shù)量如果超過1000個,寫入時再創(chuàng)建新的fields就會報(bào)錯:

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)

但有些場景的field數(shù)量并不是我們能控制的,例如在監(jiān)控系統(tǒng)中的業(yè)務(wù)數(shù)據(jù)所攜帶的業(yè)務(wù)標(biāo)簽,其中可能包含了監(jiān)控系統(tǒng)不能預(yù)知的業(yè)務(wù)字段。
對于這種情景,可能想到的解決方案兩個:

  1. 調(diào)整ElasticSearch的配置,增加field的限制數(shù)量:這種方案僅僅適用于可以預(yù)測出field數(shù)量極限的情況,治標(biāo)不治本,一旦field數(shù)量再次抵達(dá)限制,又會面臨同樣的問題。

  2. 就是使用Pair結(jié)構(gòu)來存儲

假設(shè)第2種方案的數(shù)據(jù)結(jié)構(gòu)為:

{
    "labels": [{
        "key": "ip",
        "value: "127.0.0.1"
     }]
},
{
    "labels": [{
        "key": "ip",
        "value: "127.0.0.2"
     }]
}

那么es查詢就會存在一個問題,例如下面的查詢:

{
    "query":{
        "bool":{
            "must":[
                {
                    "match":{
                        "key":"ip"
                    }
                },
                {
                    "match":{
                        "value":"127.0.0.1"
                    }
                }
            ]
        }
    }
}

這個查詢會把例子中的的數(shù)據(jù)全部查詢出來,并不符合我們的預(yù)期。這是因?yàn)閑s在存儲索引時,對于普通object類型的field實(shí)際上是打平來存儲的,比如這樣:

{
    "labels.key":[
        "ip"
    ],
    "labels.value":[
        "127.0.0.1",
        "127.0.0.2"
    ]
}

可以看見,索引打平后,對象的關(guān)聯(lián)關(guān)系丟失了。對于這種情況,ElasticSearch提供的nested結(jié)構(gòu)可以幫助我們解決類似的問題。Nested結(jié)構(gòu)保留了子文檔數(shù)據(jù)中的關(guān)聯(lián)性,如果labels的數(shù)據(jù)格式被定義為nested,那么每一個nested object將會作為一個隱藏的單獨(dú)文本建立索引。如下:

{
     "labels.key":"ip",
     "labels.value":"127.0.0.1"
},
{
     "labels.key":"ip",
     "labels.value":"127.0.0.2"
}

通過分開給每個nested object建索引,object內(nèi)部的字段間的關(guān)系就能保持。當(dāng)執(zhí)行查詢時,只會匹配’match’同時出現(xiàn)在相同的nested object的結(jié)果。

定義mappings

使用nested結(jié)構(gòu)非常簡單,指定字段的type為nested即可。下面的例子中定義了一個名為labels的nested結(jié)構(gòu),其中包含兩個字段,分別是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作為一個獨(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"
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

這個查詢可以返回我們預(yù)期的正確結(jié)果:

[{
    "labels": {
        "key": "ip",
        "value": "127.0.0.1"
    }
}]

分桶聚合

查詢的問題解決了,聚合時問題又來了,前面我們說到,nested結(jié)構(gòu)存儲在一個隱藏的單獨(dú)文本索引中,那么普通的聚合查詢自然便無法訪問到它們。因此,nested結(jié)構(gòu)在聚合時,需要使用特定的nested聚合。

nested聚合

假設(shè)es中存儲如下數(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"
    }]
}]

我們要聚合所有對labels.value進(jìn)行聚合,可以使用下面的方式:

{
  "size": 0,
  "aggs": {
    "labels_nested": {
      "nested": {
        "path": "labels"
      },
      "aggs": {
        "nested_value": {
          "terms": {
            "field": "labels.value"
          }
        }
      }
    }
  }
}

這個查詢將會得到下面類似的結(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)行了聚合,并沒有針對k-v中的key進(jìn)行過濾,因此導(dǎo)致labels.keyipos的數(shù)據(jù)均被統(tǒng)計(jì)到了其中,這通常不符合我們實(shí)際場景中的需求。

現(xiàn)在假設(shè)要對所有labels.keyiplabels.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"
              }
            }
          }
        }
      }
    }
  }
}

通過這樣的方式就可以把labels.key不是ip的文檔過濾掉,經(jīng)過這個查詢將得到類似如下的結(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多重聚合

如果想在nested聚合下嵌套聚合其它字段,直接嵌套是不行的,這里需要使用到reverse_nested跳出當(dāng)前nested聚合后,再進(jìn)行嵌套聚合。
注意:無論是嵌套其它nested字段還是普通字段,都需要使用reverse_nested跳出當(dāng)前nested聚合。

例如想對labels.keyip聚合后,再對labels.keyos進(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
      }
    }
  }
}

結(jié)語

至此,關(guān)于nested結(jié)構(gòu)存儲K-V的用法就介紹完啦!使用nested結(jié)構(gòu)可以幫助我們保持object內(nèi)部的關(guān)聯(lián)性,借此解決elasticsearch對field數(shù)量的限制。nested結(jié)構(gòu)不僅可以應(yīng)用在K-V結(jié)構(gòu)的場景,還可以應(yīng)用于其它任何需要保持object內(nèi)部關(guān)聯(lián)性的場景。

注意:使用nested結(jié)構(gòu)也會存在一些問題:

  • 增加,改變或者刪除一個nested文本,整個文本必須重新建索引。nested文本越多,代價越大。

  • 檢索請求會返回整個文本,而不僅是匹配的nested文本。盡管有計(jì)劃正在執(zhí)行以能夠支持返回根文本的同時返回最匹配的nested文本,但目前還未實(shí)現(xiàn)。

看完上述內(nèi)容,你們掌握ElasticSearch使用Nested結(jié)構(gòu)如何進(jìn)行存儲KV及聚合查詢的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!


新聞名稱:ElasticSearch使用Nested結(jié)構(gòu)如何進(jìn)行存儲KV及聚合查詢
分享鏈接:http://weahome.cn/article/jgogog.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部