ElasticSearch Painless脚本中float值精度丢失问题求助
老哥,这问题我之前也碰到过,是典型的Elasticsearch浮点类型存储与脚本访问的精度坑,给你捋清楚原因和解决办法:
原因分析
你定义的foo字段类型是float,这是单精度浮点数,它的有效精度只有大约7位十进制数字。你存入的159944154.8644有11位数字,单精度float根本没法精确存储这么多位数,只能做近似处理。
而ES的_source里保留的是你提交的原始数据,所以能显示精确值;但doc['foo'].value是从倒排索引里读取的已经被近似存储的单精度float值,自然就会出现四舍五入的精度丢失。
解决方案
根据你的实际情况,有两种可行的解决思路:
1. 修改字段类型为double(推荐长期方案)
如果你的业务允许修改索引映射并重新索引数据,把foo的类型改成double(双精度浮点数)是最优解——双精度的有效精度能达到15-17位,完全能覆盖你这个数值的精度需求。
具体操作步骤(适配ES 5.3.0版本):
# 先关闭索引(ES 5.x修改映射需要先关索引) PUT /my-index/_close # 修改foo字段的映射类型为double PUT /my-index/_mapping/my-document { "properties": { "foo": { "type": "double" } } } # 重新打开索引 PUT /my-index/_open # 重新索引数据(把旧数据导入到更新后的索引,或者直接重新导入你的原始数据) POST _reindex { "source": { "index": "my-index" }, "dest": { "index": "my-index" } }
修改完成后,再用脚本访问doc['foo'].value就能拿到精确值了。
2. 脚本直接读取_source中的值(应急方案)
如果没法修改映射或者重新索引,那可以在脚本里直接读取_source中的foo值,绕过倒排索引的近似存储:
{ "query": { "bool": { "must": [ { "match": { "id": 42 } } ] } }, "_source": { "includes": ["id","foo"] }, "script_fields": { "foo_scripted": { "script": { "lang": "painless", "inline": "_source.foo" } } } }
这个方案能立刻拿到精确值,但要注意:读取_source的性能比读取doc字段差——doc字段是存在内存缓存里的,而_source是从磁盘读取原始文档,大量查询时可能会有性能影响。
另外提一句,ES 5.3.0是比较老的版本了,后续如果有机会升级,新版本在浮点类型处理和脚本性能上都有不少优化哦。
内容的提问来源于stack exchange,提问作者raduy
相关产品推荐
相关产品推荐

