Elasticsearch聚合查询中实现自定义字段映射的最佳实践方案
可行方案(按性能从高到低排序)
1. 写入阶段预存映射字段(最优解)
直接在数据写入Elasticsearch前,通过业务代码、ETL工具(Logstash、Flink等)提前按照映射规则计算出转换后的值,新增一个字段比如foo_mapped存为keyword类型。后续聚合直接使用普通terms聚合查询该字段即可,性能和原生terms聚合完全一致。
适用场景:映射规则更新频率低,可接受规则变更时刷入历史数据的场景。
2. 优化现有terms脚本写法(改造成本最低)
你之前脚本性能极差的核心原因是每个文档执行脚本时都会重新构建HashMap并执行数百次put操作,完全属于冗余计算。把映射规则放到script的params中即可解决这个问题,params中的内容只会在请求初始化时构建一次,所有文档复用同一个Map对象,性能可提升数十倍。
优化后的查询示例:
GET /myindex/_search { "query": { "match_all": {} }, "aggs": { "myagg": { "terms": { "script": { "params": { "mapping": { "a": "A", "b": "A", "bb": "CC" // 剩余所有映射规则都放在这里 } }, "source": "params.mapping.get(doc['foo.keyword'].value)", "lang": "painless" } } } }, "size": 0 }
适用场景:映射规则更新频繁,不想修改写入流程,也不想刷历史数据的场景。
3. 用Filters聚合替代脚本聚合(性能接近原生terms)
直接按照映射后的分组做过滤聚合,完全不需要执行脚本,直接走倒排索引查询,性能比优化后的脚本还要高。
示例代码:
GET /myindex/_search { "query": { "match_all": {} }, "aggs": { "myagg": { "filters": { "filters": { "A": { "terms": { "foo.keyword": ["a", "b"] } }, "CC": { "terms": { "foo.keyword": ["bb"] } } // 剩余所有映射分组按规则补充即可 } } } }, "size": 0 }
适用场景:映射规则数量在千条以内,想要更高查询性能的场景。
内容的提问来源于stack exchange,提问作者cosimoth
相关产品推荐
相关产品推荐

