在Elasticsearch中,如何执行嵌套子聚合?

时间:2019-06-02 02:08:29

标签: elasticsearch

在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
            }
          ]
        }
      }
    }
  }

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

1 个答案:

答案 0 :(得分:0)

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

我只是为此添加了您的解决方案。我已经使用Reverse Nested Aggregation,然后再次使用Sum Aggregation应用了Nested 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

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

希望这会有所帮助!