嵌套内部命中的 Elasticsearch 聚合

Elasticsearch aggregations on nested inner hits

我在 Elasticsearch 中获取了大量数据。我的文档有一个名为 "records" 的嵌套字段,其中包含具有多个字段的对象列表。

我希望能够从记录列表中查询特定对象,因此我在查询中使用了 inner_hits 字段,但这没有帮助,因为聚合使用大小 0,所以没有返回结果.

我没有成功使聚合只对 inner_hits 有效,因为无论查询如何,聚合 returns 都会对记录中的所有对象产生结果。

这是我正在使用的查询: (每个文档有first_timestamp和last_timestamp字段,记录列表中的每个对象都有时间戳字段)

curl -XPOST 'localhost:9200/_msearch?pretty' -H 'Content-Type: application/json' -d'    
{
    "index":[
        "my_index"
    ],
    "search_type":"count",
    "ignore_unavailable":true
}
{
    "size":0,
    "query":{
        "filtered":{
             "query":{
                 "nested":{
                     "path":"records",
                     "query":{
                         "term":{
                             "records.data.field1":"value1"
                         }
                     },
                     "inner_hits":{}
                 }
             },
             "filter":{
                 "bool":{
                     "must":[
                     {
                         "range":{
                             "first_timestamp":{
                                 "gte":1504548296273,
                                 "lte":1504549196273,
                                 "format":"epoch_millis"
                             }
                         }
                     }
                     ],
                 }
             }
         }
     },
     "aggs":{
         "nested_2":{
             "nested":{
                 "path":"records"
             },
             "aggs":{
                 "2":{
                     "date_histogram":{
                          "field":"records.timestamp",
                          "interval":"1s",
                          "min_doc_count":1,
                          "extended_bounds":{
                              "min":1504548296273,
                              "max":1504549196273
                          }
                     }
                }
           }
      }
   }
}'

您的查询非常复杂。 简而言之,这是您请求的查询:

{
  "size": 0,
  "aggregations": {
    "nested_A": {
      "nested": {
        "path": "records"
      },
      "aggregations": {
        "bool_aggregation_A": {
          "filter": {
            "bool": {
              "must": [
                {
                  "term": {
                    "records.data.field1": "value1"
                  }    
                }
              ]
            }
          },
          "aggregations": {
            "reverse_aggregation": {
              "reverse_nested": {},
              "aggregations": {
                "bool_aggregation_B": {
                  "filter": {
                    "bool": {
                      "must": [
                        {
                          "range": {
                            "first_timestamp": {
                              "gte": 1504548296273,
                              "lte": 1504549196273,
                              "format": "epoch_millis"
                            }
                          }
                        }
                      ]
                    }
                  },
                  "aggregations": {
                    "nested_B": {
                      "nested": {
                        "path": "records"
                      },
                      "aggregations": {
                        "my_histogram": {
                          "date_histogram": {
                            "field": "records.timestamp",
                            "interval": "1s",
                            "min_doc_count": 1,
                            "extended_bounds": {
                              "min": 1504548296273,
                              "max": 1504549196273
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

现在,让我通过聚合的名称来解释每一步:

  • 大小:0 -> 我们对命中不感兴趣,只对聚合感兴趣
  • nested_A -> data.field1 正在记录中,因此我们将范围扩大到记录
  • bool_aggregation_A -> 按 data.field1 筛选:value1
  • reverse_aggregation -> first_timestamp 不在嵌套文档中,我们需要从记录
  • 中排除范围
  • bool_aggregation_B -> 按 first_timestamp 范围过滤
  • nested_B -> 现在,我们再次将 timestamp 字段(位于记录下)
  • 的记录范围
  • my_histogram -> 最后,按 timestamp 字段
  • 聚合日期直方图

Inner_hits 弹性搜索不支持聚合。其背后的原因是 inner_hits 是一个非常昂贵的操作,在 inner_hits 上应用聚合就像操作复杂性呈指数增长。 Here is the github link of the issue.

如果您想在 inner_hits 上聚合,您可以使用以下方法:

  1. 进行灵活的查询,您只从弹性中获得所需的命中并对其进行聚合。重复多次以获得所有命中并同时聚合。这种方法可能会导致您进行多个搜索查询,这是不可取的。
  2. 您可以通过编写智能聚合解析器和 运行 这些解析器来处理来自 elasticsearch 的响应的聚合逻辑。这种方法稍微好一些,但是您需要根据不断变化的需求维护解析器。

我个人建议您更改 elasticsearch 中的数据映射样式,以便您能够 运行 对其进行聚合。

你也可以这样查看代码

PUT records
{
  "mappings": {
    "properties": {
      "records": {
        "type": "nested"
      }
    }
  }
}

POST records/_doc
{
  "records": [
    {
      "data": "test1",
      "value": 1
    },
    {
      "data": "test2",
      "value": 2
    }
  ]
}

GET records/_search
{
  "size": 0,
  "aggs": {
    "all_nested_count": {
      "nested": {
        "path": "records"
      },
      "aggs": {
        "bool_aggs": {
          "filter": {
            "bool": {
              "must": [
                {
                  "term": {
                    "records.data": "test2"
                  }    
                }
              ]
            }
          },
          "aggs": {
            "filtered_aggs": {
              "sum": {
                "field": "records.value"
              }
            }
          }
        }
      }
    }
  }
}

参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/inner-hits.html