弹性搜索查询/过滤嵌套数组

shi*_*ivg 0 elasticsearch

我在ES中的索引test_agg上存储了以下嵌套数据类型。

{
  "Date": "2015-10-21",
  "Domain": "abc.com",
  "Processed_at": "10/23/2015 9:47",
  "Events": [
    {
      "Name": "visit",
      "Count": "188",
      "Value_Aggregations": [
        {
          "Value": "red",
          "Count": "100"
        }
      ]
    },
    {
      "Name": "order_created",
      "Count": "159",
      "Value_Aggregations": [
        {
          "Value": "$125",
          "Count": "50"
        }
      ]
   },
 ]
}
Run Code Online (Sandbox Code Playgroud)

嵌套项的映射为

curl -XPOST localhost:9200/test_agg/nested_evt/_mapping -d '{
"nested_evt":{
"properties":{
   "Events": {
       "type": "nested"
    }
   }
  }
}'
Run Code Online (Sandbox Code Playgroud)

我正在尝试使用以下查询获取“ Events.Count”和“ Events.Value_Aggregations.Count”,其中Events.Name =“ Visit”

{
 "fields" : ["Events.Count","Events.Value_Aggregations.Count"]
  "query": {
     "filtered": {
        "query": {
            "match": { "Domain": "abc.com" }
        },
        "filter": {
            "nested": {
                "path": "Events",
                "query": {
                     "match": { "Events.Name": "visit" }
                },
              }
          }
      }
   }
 }
Run Code Online (Sandbox Code Playgroud)

而不是结果单值

Events.Count = [188] Events.Value_Aggregations.Count = [100]

它给

Events.Count = [188,159] Events.Value_Aggregations.Count = [100,50]

获得所需输出的确切查询结构是什么?

Slo*_*ens 5

因此,这里的问题在于nested您要应用的过滤器根据嵌套的子文档的属性选择文档。因此,ES会找到与您的查询匹配的父文档(基于该文档的嵌套子级)。然后,由于您已经指定了它,所以不会返回整个文档,而是仅选择您要的那些字段。这些字段恰好是嵌套字段,并且由于父文档具有两个嵌套子级,因此它将为您指定的字段分别找到两个值并返回它们。据我所知,没有办法代替子文档,至少是在体系结构上。"fields"nested

解决此问题的一种方法是改为使用父/子关系,然后可以将has_parent查询与其他过滤器结合使用,针对子类型获取所需的内容。只要架构架构不与您的其他需求冲突,这可能是一种更清洁的方法。

但是,有一种方法可以使用当前架构,嵌套聚合过滤器聚合来完成您所要查询的内容。它有点涉及(在这种情况下有点含糊;请参阅下面的说明),但这是查询:

POST /test_index/_search
{
   "size": 0,
   "query": {
      "filtered": {
         "query": {
            "match": {
               "Domain": "abc.com"
            }
         },
         "filter": {
            "nested": {
               "path": "Events",
               "query": {
                  "match": {
                     "Events.Name": "visit"
                  }
               }
            }
         }
      }
   },
   "aggs": {
      "nested_events": {
         "nested": {
            "path": "Events"
         },
         "aggs": {
            "filtered_events": {
               "filter": {
                  "term": {
                     "Events.Name": "visit"
                  }
               },
               "aggs": {
                  "events_count_terms": {
                     "terms": {
                        "field": "Events.Count"
                     }
                  },
                  "value_aggregations_count_terms": {
                     "terms": {
                        "field": "Events.Value_Aggregations.Count"
                     }
                  }
               }
            }
         }
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

返回:

{
   "took": 3,
   "timed_out": false,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 0,
      "hits": []
   },
   "aggregations": {
      "nested_events": {
         "doc_count": 2,
         "filtered_events": {
            "doc_count": 1,
            "value_aggregations_count_terms": {
               "doc_count_error_upper_bound": 0,
               "sum_other_doc_count": 0,
               "buckets": [
                  {
                     "key": "100",
                     "doc_count": 1
                  }
               ]
            },
            "events_count_terms": {
               "doc_count_error_upper_bound": 0,
               "sum_other_doc_count": 0,
               "buckets": [
                  {
                     "key": "188",
                     "doc_count": 1
                  }
               ]
            }
         }
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

警告:我不清楚您是否真的需要我在此处显示"filter": { "nested": { ... } }的内容"query"中的子句。如果此部分以有用的方式过滤掉了父文档,那么您将需要它。如果您唯一的选择是选择要从中返回字段的嵌套子文档,则此处多余,因为filter聚合工作负责该部分。

这是我用来测试的代码:

http://sense.qbox.io/gist/dcc46e50117031de300b6f91c647fe9b729a5283