Elasticsearch数组字段terms聚合如何仅返回查询匹配的桶?
出现多余聚合桶的核心原因是:查询阶段的filter仅判断文档是否包含至少一个匹配的media值,过滤后的文档会保留完整的media数组,聚合阶段会对数组的所有元素分桶,因此会出现不在过滤条件内的桶。
方案1:使用支持terms lookup的terms聚合includes参数(适用于Elasticsearch 7.10及以上版本)
terms聚合的includes参数支持和查询阶段完全一致的terms lookup语法,不需要提前获取用户的favorite_media取值,直接复用查询端的配置即可,修改后的查询如下:
{ "query": { "filter": { "terms": { "media": { "index": "user_index", "id": 42, "path": "favorite_media" } } } }, "aggs": { "Posts_by_media": { "terms": { "field": "media", "size": 1000, "includes": { "index": "user_index", "id": 42, "path": "favorite_media" } } } } }
该方案会在聚合分桶阶段直接过滤掉不在lookup结果内的key,最终仅返回twitter和instagram两个符合要求的桶,仅需一次查询即可完成,性能损耗极低。
方案2:两次查询方案(兼容全版本Elasticsearch)
如果你使用的ES版本不支持includes参数的terms lookup能力,可以分两步执行:
- 先查询
user_index索引,获取id为42的用户的favorite_media值列表 - 将第一步拿到的列表作为
includes参数的值传入聚合查询,示例如下:
假设第一步获取到的列表为["twitter", "instagram"],第二步的查询语句:
{ "query": { "filter": { "terms": { "media": ["twitter", "instagram"] } } }, "aggs": { "Posts_by_media": { "terms": { "field": "media", "size": 1000, "includes": ["twitter", "instagram"] } } } }
该方案逻辑简单,无额外的聚合计算开销,兼容性最好,唯一不足是需要执行两次请求,适合对实时性要求不高的场景。
内容的提问来源于stack exchange,提问作者aethos
相关产品推荐
相关产品推荐

