如何使用 Elasticsearch 查询获取每个组的最新值?

问题描述 投票:0回答:4

我在 Elasticsearch 上索引了一些文档,如下示例:

{'country': 'France', 'collected': '2015-03-12', 'value': 20}
{'country': 'Canada', 'collected': '2015-03-12', 'value': 21}
{'country': 'Brazil', 'collected': '2015-03-12', 'value': 33}
{'country': 'France', 'collected': '2015-02-01', 'value': 10}
{'country': 'Canada', 'collected': '2015-02-01', 'value': 11}
{'country': 'Mexico', 'collected': '2015-02-01', 'value': 9}
...

我想构建一个查询,为每个国家/地区获取一个结果,仅获取带有

max(collected)
的结果。

因此,对于上面显示的示例,结果将类似于:

{'country': 'France', 'collected': '2015-03-12', 'value': 20}
{'country': 'Canada', 'collected': '2015-03-12', 'value': 21}
{'country': 'Brazil', 'collected': '2015-03-12', 'value': 33}
{'country': 'Mexico', 'collected': '2015-02-01', 'value': 9}

我意识到我需要对

country
进行聚合,但我无法理解如何限制
max(collected)
上的结果。

有什么想法吗?

elasticsearch
4个回答
67
投票

您可以使用

top_hits
聚合,对
country
字段进行分组,每组返回 1 个文档,并按收集的日期降序对文档进行排序:

POST /test/_search?search_type=count
{
    "aggs": {
        "group": {
            "terms": {
                "field": "country"
            },
            "aggs": {
                "group_docs": {
                    "top_hits": {
                        "size": 1,
                        "sort": [
                            {
                                "collected": {
                                    "order": "desc"
                                }
                            }
                        ]
                    }
                }
            }
        }
    }
}

2
投票

对于像 user1892775 这样遇到“默认情况下在文本字段上禁用字段数据...”的人,您可以创建一个多字段(https://www.elastic.co/guide/en/elasticsearch/reference/当前/多字段.html)。所以你可能有这样的映射:

"mapping": {
    "properties": {
      "country": {"type": "string", "fields": {"raw": {"type": "string", "index": "not_analyzed"}}}
}

那么您的查询将如下所示

POST /test/_search?search_type=count
{
    "aggs": {
    "group": {
        "terms": {
            "field": "country.raw"
        },
        "aggs": {
            "group_docs": {
                "top_hits": {
                    "size": 1,
                    "sort": [
                        {
                            "collected": {
                                "order": "desc"
                            }
                        }
                    ]
                }
            }
        }
    }
  }
}

(注意使用国家/地区。raw


2
投票

标记为正确的答案对我来说非常有用。 这是我添加一些额外过滤器的方法。这是 AWS 上的版本 7.4。

我分组的字段是一个名为标签的关键字字段。

  • 对于每个组(标签),获取按 date_uploaded 降序排序的前 3 个文档。

  • 还显示每组(标签)内的文档总数。

  • 仅考虑属于用户 22 的未删除文档。

  • 仅返回 10 组(标签),按字母顺序排序。

  • 对于每个文档,返回其 ID (book_id) 和 date_uploaded。 (默认返回所有信息。)

  • Size:0 可以防止查询返回有关所有文档的大量信息。

      {'query': {'bool': {'filter': [{'terms': {'user_id': [22]}}, {'terms': {'deleted': ['false']}}]}},
       'size': 0,
       "aggs": {
          "group": {
              "terms": {
                  "field": "tags.keyword",
                  "size":10,
                  "order":{ "_key": "asc" }
              },  
              "aggs": {
                  "group_docs": {
                      "top_hits": {
                          "size": 3,
                          "_source":["book_id","date_uploaded"],
                          "sort": [ {"date_uploaded": { "order": "desc" }}]
                      }
                  }
              }
          }
      }
    

    }

以下是如何获取每个组(在我的例子中是标签)以及每个组的文档匹配。

query_results = ... result of query
buckets = query_results["aggregations"]["group"]["buckets"]
for bucket in buckets:
    tag = bucket["key"]
    tag_doc_count = bucket["doc_count"]
    print tag, tag_total_doc_count
    tag_hits = bucket["group_docs"]["hits"]["hits"]
    for hit in tag_hits:
        source = hit["_source"]
        print source["book_id"], source["date_uploaded"]

仅供参考,“组”一词可以命名为任何名称。只要确保从查询结果中获取存储桶时使用相同的名称即可。


0
投票

使用新的 ESQL,这是一件轻而易举的事情:

FROM <index> | STATS latest=top(collected, 1 "desc") by country,value

它将返回最新收集的国家和价值

© www.soinside.com 2019 - 2024. All rights reserved.