将mysql数据同步到elasticsearch时,mysql的float类型出现精度损失及解决方法

场景描述

之前将mysql数据同步到ES,采用的是如下的架构,打造的是千万级别的实时搜索系统

详情请看 https://blog.csdn.net/laoyang360/article/details/52227541#commentBox

最近运营突然找到我说有一个问题就是为什么数据库源表这种是

2.99肿么变成了这个2.990000009536743,出现了精度上面的一些问题。一开始我也是一脸懵逼,以为是ES的问题,但是一想好像不对,ES的数据类型就是浮点型,不可能是ES把2.99转换成2.990000009536743了。

于是就开始分析了。

出问题只可能是三个位置:ES、mysql、同步过程

上面首先就排除了ES的问题,然后是同步的过程,经过验证同步过程中是没有这种骚操作的。那就只可能是mysql的问题

但是特别奇怪的是通过SQL语句查询出来的数据是正常的呀。

于是查看了一下出现问题的字段类型,发现这个字段的类型居然是float(8, 2),搞得我一脸懵逼,

因为

FLOAT类型用于表示近似数值数据类型。SQL标准 允许在关键字FLOAT后面的括号内选择用位指定精度(但不能为指数范围)。MySQL还支持可选的只用于确定存储大小的精度规定。0到23的精度对应 FLOAT列的4字节单精度。24到53的精度对应DOUBLE列的8字节双精度。单精度浮点数用4字节(32bit)表示浮点数
采用IEEE754标准的计算机浮点数,在内部是用二进制表示的
如:7.22用32位二进制是表示不下的。
所以就不精确了。

好吧,看来是设计表的人的问题。哎!!!有点郁闷

表数据量已经很大了,而且数据是很敏感的数据,线上好多服务都在用,改表结果是不存在了,所以还得我想办法呀!!!

自己的解决思路很简单,查询出来的数据没有问题,但是映射到ES上面的时候出现了精度问题,肯定是mysql类型的问题导致的,所以再同步过程中,进行下类型转换即可,由于我是多表关联制作宽表进行同步的,有updatetime字段,所以是使用的sql进行同步的。我把查询出来的数据先转换成char类型然后在转换成decimal(8, 2)解决的,因为我一开始尝试转换成char同步上去是2.99字符串,所以我就在此基础上做了。可能有更好的办法,反正解决了!!!,由于表的数据量很大了,所以使用这种方式可以进行更新修改同步,原来的数据是有的,线上查询依旧可以正常使用,因为索引mapping结构没有变,至少算是一种还过得去的方法。如果表的数据量没有过亿,使用logstash-input-jdbc是可以的,过亿了,还是老老实实自己写个简单的脚本去实现吧。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章