ES-elasticsearch 查询结果保留2位小数经验分享-待完善
ES版本:6.3.2对一个double类型字段进行sum求和时,出现丢失精度问题. 4074人浏览 · 2021-11-30 00:01:24
背景:
ES版本:6.3.2
对一个double类型字段进行sum求和时,出现丢失精度问题.
查出44条数据,求和结果为1004.9, 但是ES返回结果为1004.9000000000001
由于公司内部组件进行了封装,简单索引查询无需解析结果可直接供前端使用.所以不希望内存中重新解析,逐条处理数字,而是通过ES的功能直接实现保留2位小数.
于是开始全网搜索.
截止2021年11月29日21:19:42 的方案:
索引中的数字插入时*100, 取出时 / 100
每个条明细 / 100
GET /_search
"query" : {
"match_all": {}
"script_fields" : {
"test1" : {
"script" : {
"lang": "painless",
"inline": "doc['qty'].value / 100"
"test2" : {
"script" : {
"lang": "painless",
"inline": "doc['qty'].value / factor",
"params" : {
"factor" : 100
sum结果 / 100
GET /_search
"query" : {
"match_all": {}
"aggs": {
"qty_name": {
"sum": {
"field": "qty",
"script":"(doc['qty'].value) / 100"
ES不支持直接对某一列字段加减乘除,需要借助painless 脚本语言中的 Script Fields 进行计算.
在stackoverflow找到了相同的问题,但效果都不好. stackoverflow同类问题https://stackoverflow.com/questions/36041812/how-to-round-up-double-to-2-decimal-point-elasticsearch#
https://stackoverflow.com/questions/36041812/how-to-round-up-double-to-2-decimal-point-elasticsearch#
stackoverflow例子实测
ES索引如下:
"state": "open",
"settings": {
"index": {
"creation_date": "1637576630382",
"number_of_shards": "10",
"number_of_replicas": "1",
"uuid": "-----",
"version": {
"created": "6030299"
"provided_name": "test_double"
"mappings": {
"_doc": {
"dynamic": "false",
"properties": {
"qty": {
"type": "double"
插入44条数据(从正式环境copy来的所以44条)
4.0 ,1.0 ,1.7 ,1.0 ,12.0 ,1.0 ,26.0 ,7.0 ,2.0 ,1.6 ,1.0 ,44.0 ,5.0 ,3.4 ,3.0 ,1.0 ,5.0 ,2.7 ,6.4 ,1.7 ,1.0 ,0.8 ,10.0 ,1.6 ,1.0 ,3.0 ,5.0 ,4.0 ,12.0 ,39.0 ,0.8 ,2.0 ,12.0 ,6.0 ,8.0 ,2.0 ,547.0 ,137.0 ,76.0 ,0.8 ,1.1 ,0.7 ,2.0 ,1.6
普通求和:
math_round 保留小数:
round(2)保留两位小数:. 查询报错. 后查明没有这个方法Lucene表达式语言-数字类型字段API-没有round()方法
BigDecimal保留两位小数:
BigDecimal是将44条的值都做四舍五入后进行加和, 结果与真实sum值差异较大,不能使用.
综上所有测试得出, 暂时没有办法直接将结果保留两位小数,所以只能考虑换个方式,索引中的数字*100 进行sum,取出来时再除以100。
如果大家有更好的方法,同求分享。
所有评论(0)