You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Elasticsearch中统计符合条件的分组聚合结果数量?

问题:统计Elasticsearch中按key分组取最新非Delete事件的总量

我需要统计Elasticsearch索引内符合以下条件的事件总量:按key字段分组取每组最新的事件,排除type为Delete的事件后计数。对应的SQL等价查询如下:

SELECT
  COUNT(1) as volume
FROM (
      SELECT
      key
    , type
    , ROW_NUMBER() OVER( PARTITION BY key ORDER BY timestamp DESC ) AS instance
  FROM event
  ) A
WHERE type != 'Delete'
AND instance = 1

我尝试了以下Elasticsearch查询,能返回分组后的最新事件详情,但我只需要最终的计数结果,且已知count API不支持聚合,希望得到最高效的实现方法:

GET /index/_search
{
  "size": 0,
  "aggs": {
    "group_by_key": {
      "terms": {
        "field": "key",
        "size": 1000000
      },
      "aggs": {
        "top_record_per_group": {
          "top_hits": {
            "sort": [
              {
                "timestamp": {
                  "order": "desc"
                }
              }
            ],
            "size": 1
          }
        }
      }
    }
  },
  "query": {
    "bool": {
      "must_not": [
        {
          "term": {
            "type": "Delete"
          }
        }
      ]
    }
  }
}

补充示例

keytypetimestamplatest?include?
1insert00:00:01
1update00:00:02
2insert00:00:03
3insert00:00:04YY
2delete00:00:05YN
4insert00:00:06
1update00:00:07YY
4update00:00:08YY

最终预期结果:volume: 3


高效实现方案

通过管道聚合可以在现有分组聚合的基础上,直接统计符合条件的分组数量,无需返回事件详情。修改后的查询如下:

GET /index/_search
{
  "size": 0,
  "aggs": {
    "group_by_key": {
      "terms": {
        "field": "key",
        "size": 1000000
      },
      "aggs": {
        "top_record_per_group": {
          "top_hits": {
            "sort": [
              {
                "timestamp": {
                  "order": "desc"
                }
              }
            ],
            "size": 1,
            "_source": ["type"] // 只返回type字段,减少数据传输开销
          }
        },
        // 筛选出top_hits中type不为Delete的分组
        "filter_valid_type": {
          "bucket_selector": {
            "buckets_path": {
              "type": "top_record_per_group.hits.hits.0._source.type"
            },
            "script": "params.type != 'Delete'"
          }
        }
      }
    },
    // 统计经过筛选后的分组数量,即最终volume
    "total_volume": {
      "bucket_count": {
        "buckets_path": "group_by_key>filter_valid_type"
      }
    }
  }
}

说明

  1. filter_valid_type 聚合通过bucket_selector脚本判断每组最新事件的type是否不为Delete,只保留符合条件的分组
  2. total_volume 聚合通过bucket_count统计筛选后的分组数量,结果直接返回在aggregations.total_volume.value字段中
  3. 优化点:在top_hits中指定_source: ["type"],只返回需要的字段,减少数据传输开销

如果你的数据量极大(超过千万级key),terms聚合的size参数可能受限于Elasticsearch的index.max_result_window设置,此时可以改用composite聚合进行分页式分组,再结合管道聚合统计总数,但对于大部分场景,上述方案已足够高效。

内容的提问来源于stack exchange,提问作者AlanTwoRings

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 08:35:40