Elasticsearch同文档数值比较:脚本查询vs专用布尔字段
同文档字段比较的高效查询方案(Elasticsearch 7.17)
直接给结论:新增a_less_than_b布尔字段是更简洁高效的方案,原因很明确:
- 性能碾压脚本查询:脚本查询(
scriptquery)要在查询阶段给每个命中的文档跑一遍计算,CPU消耗极大,数据量一大性能直接垮掉。而预计算的布尔字段是在写入时就确定的值,查询时直接做精确匹配,ES能靠倒排索引快速过滤,性能提升不是一点半点。 - 实现简单无兼容风险:在Go端结构体转文档的时候直接算好赋值,逻辑一目了然,不用维护复杂的Painless脚本,也不用担心ES版本升级带来的脚本语法兼容问题。
再说说ES端的替代方案:
如果实在不想改数据结构,Elasticsearch 7.17支持runtime fields,可以在查询时动态算出这个布尔值,但性能和脚本查询差不多,只是换了个写法:
{ "query": { "term": { "a_less_than_b": { "value": true } } }, "runtime_mappings": { "a_less_than_b": { "type": "boolean", "script": "emit(doc['A'].value < doc['B'].value)" } } }
这种方式不用改索引结构,但还是查询时实时计算,CPU开销没减少,只适合临时查数据、没法修改现有数据的场景,长期用还是预计算字段靠谱。
还有一种方法是用ingest pipeline,让ES在数据写入时自动计算这个字段,不用Go代码处理:
{ "processors": [ { "script": { "source": "ctx.a_less_than_b = ctx.A < ctx.B" } } ] }
效果和Go端预计算一样,性能也高效,适合有多个数据源往ES写数据的场景,能把计算逻辑统一放在ES端维护;但如果只有Go这一个写入渠道,直接在Go代码里处理更直接。
总的来说:
- 单数据源写入(只有Go端):优先在Go代码里加预计算布尔字段
- 多数据源写入:用ingest pipeline让ES统一计算
- 临时排查/无法修改数据:再考虑runtime fields或脚本查询
内容的提问来源于stack exchange,提问作者kbishop
相关产品推荐
相关产品推荐

