Elasticsearch按分组取最大ID后求和duration字段的实现方法
Elasticsearch按Workflow分组取最大ID后求和Duration的实现方法
需求与示例
需要实现:按workflow分组,先获取每组的最大id,再对该id对应所有文档的duration字段求和。
示例数据
| id | workflow | sid | duration |
|---|---|---|---|
| 1 | A | x1 | 1m |
| 1 | A | x2 | 2m |
| 2 | A | x1 | 2m |
| 2 | A | x2 | 3m |
| 1 | B | y1 | 1m |
| 1 | B | y2 | 2m |
| 2 | B | y1 | 2m |
| 2 | B | y2 | 3m |
| 3 | B | y1 | 4m |
| 3 | B | y2 | 2m |
预期结果
| id | workflow | total |
|---|---|---|
| 2 | A | 5m |
| 3 | B | 6m |
现有查询
你已经写出了分组取最大id的基础查询:
{ "size": 0, "aggs": { "my-bucket": { "terms": { "field": "workflow" }, "aggs": { "max_id": { "max": { "field": "id" } } } } } }
完整实现方案
要完成后续的求和,我们可以在现有聚合逻辑上扩展,通过多层聚合实现目标:
最终查询语句
{ "size": 0, "aggs": { "workflow_groups": { "terms": { "field": "workflow" }, "aggs": { "top_id_group": { "terms": { "field": "id", "order": { "_key": "desc" }, "size": 1 }, "aggs": { "total_duration": { "sum": { "field": "duration" } } } } } } } }
逻辑拆解
- 按Workflow分组:第一层
workflow_groups聚合将所有文档按workflow字段分成A、B两组。 - 筛选最大ID分组:第二层
top_id_group聚合在每个workflow组内,按id字段再次分组,同时设置按id降序排序、只保留1个分组,这样就直接拿到了当前workflow下最大的id对应的文档组。 - 求和Duration:第三层
total_duration聚合对选中的最大id分组内所有文档的duration字段求和,得到最终的total值。
注意事项
如果你的duration字段是字符串格式(如示例中的"1m"),Elasticsearch的sum聚合无法直接计算,需要先把它转换成数值类型:
- 方案1:修改字段映射,将
duration存储为数值(比如把"1m"转成60000毫秒或者1分钟的数值) - 方案2:在聚合中使用脚本转换,示例如下:
"total_duration": { "sum": { "script": { "source": "def dur = params._source.duration; return Integer.parseInt(dur.substring(0, dur.length()-1));" } } }
这个脚本会去掉duration值末尾的"m",将前面的数字转成整数后再求和。
内容的提问来源于stack exchange,提问作者CarolL
相关产品推荐
相关产品推荐

