【问题标题】:In Elasticsearch, how do I perform nested sub-aggregations?在 Elasticsearch 中,如何执行嵌套子聚合?
【发布时间】:2019-06-02 20:27:11
【问题描述】:

在 Kibana 中,我按如下方式创建索引:

PUT cars
{  
   "mappings":{  
      "_doc":{  
         "properties":{  
            "metadata":{  
               "type":"nested",
               "properties":{  
                  "str_value":{  
                     "type":"keyword"
                  }
               }
            }
         }
      }
   }
}

然后我插入三个记录:

POST /cars/_doc/1
{
  "metadata": [
    {
      "key": "model",
      "str_value": "Ford"
    },
    {
      "key": "price",
      "int_value": 1000
    }
  ]
}
PUT /cars/_doc/2
{
  "metadata": [
    {
      "key": "model",
      "str_value": "Ford"
    },
    {
      "key": "price",
      "int_value": 2000
    }
  ]
}
PUT /cars/_doc/3
{
  "metadata": [
    {
      "key": "model",
      "str_value": "Holden"
    },
    {
      "key": "price",
      "int_value": 2500
    }
  ]
}

架构有点不合常规,但我已经这样设计索引以避免映射爆炸:

https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html

我想做的是获得我所有的汽车型号,以及这些型号的价格总和,即福特 3000 美元和霍顿 2500 美元。到目前为止,我有:

GET /cars/_search
{  
   "aggs":{  
      "metadata":{  
         "nested":{  
            "path":"metadata"
         },
         "aggs":{  
            "model_filter":{  
               "filter":{  
                  "term":{  
                     "metadata.key":"model"
                  }
               },
               "aggs":{  
                  "model_counter":{  
                     "terms":{  
                        "field":"metadata.str_value",
                        "size":1000
                     }
                  }
               }
            }
         }
      }
   }
}

这让我了解其中的一部分,因为它返回汽车型号和文档数量:

  "aggregations": {
    "metadata": {
      "doc_count": 6,
      "model_filter": {
        "doc_count": 3,
        "model_counter": {
          "doc_count_error_upper_bound": 0,
          "sum_other_doc_count": 0,
          "buckets": [
            {
              "key": "Ford",
              "doc_count": 2
            },
            {
              "key": "Holden",
              "doc_count": 1
            }
          ]
        }
      }
    }
  }

如何修改我的查询以添加一个子聚合,该子聚合将显示价格总和,即福特为 3000(两个文档的总和)和霍顿的 2500(一个文档的总和)

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    以下查询应该可以帮助您找到所需的内容。

    我只是为此添加了您的解决方案。我已经使用了Reverse Nested Aggregation,然后使用Nested Aggregation 再次应用了Sum Aggregation 帖子。

    所以你的查询层次如下:

    Nested Aggregation
    - Terms Aggregation
     - Reverse Nested Aggregation to back to parent doc
      - Nested Aggregation to enter into nested price document
       - Sum Aggregation to calculate all the prices
    

    聚合查询:

    POST <your_index_name>/_search
    {  
       "size":0,
       "aggs":{  
          "metadata":{  
             "nested":{  
                "path":"metadata"
             },
             "aggs":{  
                "model_filter":{  
                   "filter":{  
                      "term":{  
                         "metadata.key":"model"
                      }
                   },
                   "aggs":{  
                      "model_counter":{  
                         "terms":{  
                            "field":"metadata.str_value",
                            "size":1000
                         },
                         "aggs":{  
                            "reverseNestedAgg":{  
                               "reverse_nested":{},
                               "aggs":{  
                                  "metadata":{  
                                     "nested":{  
                                        "path":"metadata"
                                     },
                                     "aggs":{  
                                        "sum":{  
                                           "sum":{  
                                              "field":"metadata.int_value"
                                           }
                                        }
                                     }
                                  }
                               }
                            }
                         }
                      }
                   }
                }
             }
          }
       }
    }
    

    请注意,我添加了"size": 0,以便只返回聚合查询。您可以根据自己的要求对其进行修改。

    聚合解决方案:

    {
      "took" : 7,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 3,
          "relation" : "eq"
        },
        "max_score" : null,
        "hits" : [ ]
      },
      "aggregations" : {
        "metadata" : {
          "doc_count" : 6,
          "model_filter" : {
            "doc_count" : 3,
            "model_counter" : {
              "doc_count_error_upper_bound" : 0,
              "sum_other_doc_count" : 0,
              "buckets" : [
                {
                  "key" : "Ford",
                  "doc_count" : 2,
                  "reverseNestedAgg" : {
                    "doc_count" : 2,
                    "metadata" : {
                      "doc_count" : 4,
                      "sum" : {
                        "value" : 3000.0
                      }
                    }
                  }
                },
                {
                  "key" : "Holden",
                  "doc_count" : 1,
                  "reverseNestedAgg" : {
                    "doc_count" : 1,
                    "metadata" : {
                      "doc_count" : 2,
                      "sum" : {
                        "value" : 2500.0
                      }
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
    

    请注意,我已经在 ES 版本 7 中测试了上述查询。

    重要提示:

    如果您的文档以以下格式结束,则上述查询将不起作用。

    POST /cars/_doc/1
    {
      "metadata": [
        {
          "key": "model",
          "str_value": "Ford"
        },
        {
          "key": "price",
          "int_value": 1000
        },
        {
          "key": "something else",
          "int_value": 1000
        }
      ]
    }
    // There are three nested documents with two documents having int_value field
    

    我看到您提到您希望避免映射爆炸,因此您的架构就是这样。但是,如果发生上述情况,在这种情况下,您可能需要退后一步重新设计您的模型,或者让您的服务层处理这种聚合情况。

    希望这会有所帮助!

    【讨论】:

    • 你好,上面的答案有用吗?如果您还想要什么,请告诉我。
    猜你喜欢
    • 2015-03-25
    • 2021-12-14
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-25
    • 2021-04-25
    • 2015-11-14
    相关资源
    最近更新 更多