按术语分组并获得嵌套数组属性的计数?

时间:2019-12-13 17:09:29

标签: elasticsearch elasticsearch-aggregation

我想从一个数组项与某个值匹配的文档系列中获取计数。

我有这样的文件:

{
    "Name": "jason",
    "Todos": [{
        "State": "COMPLETED"
        "Timer": 10
        },{
        "State": "PENDING"
        "Timer": 5
    }]
}

{
    "Name": "jason",
    "Todos": [{
        "State": "COMPLETED"
        "Timer": 5
        },{
        "State": "PENDING"
        "Timer": 2
    }]
}

{
    "Name": "martin",
    "Todos": [{
        "State": "COMPLETED"
        "Timer": 15
        },{
        "State": "PENDING"
        "Timer": 10
    }]
}

我想算一下我有多少个文档具有“已完成状态”的待办事项。然后按名称分组。

因此,从以上内容我将需要获得: 杰森:2 马丁:1

通常,我使用“名称”的术语聚合,以及其他项的其他子聚合:

"aggs": {
    "statistics": {
        "terms": {
            "field": "Name"
        },
        "aggs": {
            "test": {
                "filter": {
                    "bool": {
                        "must": [{
                                "match_phrase": {
                                    "SomeProperty.keyword": {
                                        "query": "THEVALUE"
                                    }
                                }
                            }
                        ]
                    }
                },

但是由于我的数组中有项目,所以不确定在这里如何做。

1 个答案:

答案 0 :(得分:1)

Elasticsearch对数组没有问题,因为实际上flattens them by default

  

内部对象字段的数组无法按您期望的方式工作。 Lucene没有内部对象的概念,因此Elasticsearch将对象层次结构简化为一个简单的字段名称和值列表。

因此,像您发布的查询一样的查询。不过,我将对term使用keyword datatype查询:

POST mytodos/_search
{
  "size": 0,
  "aggs": {
    "by name": {
      "terms": {
        "field": "Name"
      },
      "aggs": {
        "how many completed": {
          "filter": {
            "term": {
              "Todos.State": "COMPLETED"
            }
          }
        }
      }
    }
  }
}

我假设您的映射看起来像这样:

PUT mytodos/_mappings
{
  "properties": {
    "Name": {
      "type": "keyword"
    },
    "Todos": {
      "properties": {
        "State": {
          "type": "keyword"
        },
        "Timer": {
          "type": "integer"
        }
      }

    }
  }
}

您发布的示例文档将在内部转换为如下形式:

{
  "Name": "jason",
  "Todos.State": ["COMPLETED", "PENDING"],
  "Todos.Timer": [10, 5]
}

但是,例如,如果您需要查询Todos.State Todos.Timer,则仅使用"COMPLETED"过滤Timer > 10,这种映射是不可能的,因为Elasticsearch忘记了对象数组项的字段之间的链接。

在这种情况下,您将需要使用nested datatype之类的数组,并使用特殊的nested query查询它们。

希望有帮助!