Elasticsearch按时间倒序查询并去重同game_id数据的DSL修改指导
Elasticsearch按时间倒序查询且同一game_id仅返回最新记录的DSL修正
需求说明
我是Elasticsearch初学者,有一个存储游戏信息的es_game索引,需要实现以下查询需求:
- 按时间倒序返回所有游戏数据
- 同一
game_id仅返回最新的一条记录
当前使用的DSL返回的不是最新数据,推测是先排序再聚合导致排序失效,需要指导修改DSL。
原错误DSL
{ "size": 0, "query": { "filter": [ { "range": { "create_time": { "gte": "2023-05-01 11:56:45", "lte": "2023-05-31 11:56:45" } } } ] }, "sort": [ { "create_time": { "order": "desc" } } ], "aggs": { "group_by_game": { "terms": { "field": "game_id" }, "aggs": { "sort_by_create_time": { "top_hits": { "sort": [ { "create_time": { "order": "desc" } } ], "size": 1 } } } } } }
Java实体类
class Game { private Integer gameId; private String createTime; // 省略getter、setter及其他字段 }
问题分析
原DSL存在两个核心问题:
- 外层的
sort配置完全无效——聚合操作基于查询过滤后的数据集分组,外层排序不会影响聚合内部的结果顺序 terms聚合默认按分组内文档数量降序排列,而非按最新记录的时间倒序,导致整体返回的分组顺序不符合需求
修正后的DSL
{ "size": 0, "query": { "filter": [ { "range": { "create_time": { "gte": "2023-05-01 11:56:45", "lte": "2023-05-31 11:56:45" } } } ] }, "aggs": { "group_by_game": { "terms": { "field": "game_id", // 关键:指定按子聚合的最新时间倒序排列分组 "order": { "latest_create_time": "desc" } }, "aggs": { // 新增max聚合:获取当前game_id的最新时间,用于外层分组排序 "latest_create_time": { "max": { "field": "create_time" } }, "latest_game_record": { "top_hits": { "sort": [ { "create_time": { "order": "desc" } } ], "size": 1, // 可选:指定需要返回的字段,减少数据传输 "_source": ["game_id", "create_time"] } } } } } }
修正点说明
- 移除了无效的外层
sort配置 - 新增
max类型的子聚合latest_create_time,用于获取每个game_id对应的最新时间,供外层terms聚合排序使用 - 在
terms聚合的order中,指定按max聚合的结果倒序,确保整体分组按最新记录的时间从新到旧排列 - 保留
top_hits聚合并维持按create_time倒序取1条,确保每个分组返回最新的那条记录
Java代码解析示例
拿到ES返回的聚合结果后,遍历分组桶提取最新记录:
// 假设已获取到SearchResponse对象 Aggregation aggregation = response.getAggregations().get("group_by_game"); Terms termsAgg = (Terms) aggregation; for (Terms.Bucket bucket : termsAgg.getBuckets()) { // 获取top_hits聚合的结果 TopHits topHits = bucket.getAggregations().get("latest_game_record"); SearchHit[] hits = topHits.getHits().getHits(); if (hits.length > 0) { // 将JSON解析为Game实体 Game latestGame = new ObjectMapper().readValue(hits[0].getSourceAsString(), Game.class); // 业务处理逻辑 } }
内容的提问来源于stack exchange,提问作者mario
相关产品推荐
相关产品推荐

