Hive查询语句中关于浮点数的比较

2019-08-19  本文已影响0人  LannisterWF

/*

本文内容来自O'REILLY系列的《Programming Hive》的中文译本《Hive编程指南》的6.2.2节,我看到这里感觉十分有趣,故分享出来。

*/

在hive中,浮点数比较的一个常见陷阱出现在float和double类型进行比较的时候。考虑下面的查询语句,该语句将返回员工姓名、工资和联邦税率,过滤条件是薪水扣税超过0.2。

select name,salary,deductions['Federal Taxes'] from employees where deductions['Federal Taxes'] >0.2;

结果如下

Tywin Lannister  20000.0  0.2

Aegon Targaryen 25000.0  0.2

Robert Baratheon  15000.0  0.3

Jon Snow  10000.0  0.3

该书作者此时发出了萌萌的疑问:桥豆麻袋!为什么“deductions['Federal Taxes'] =0.2”的记录也被输出了?

然后是作者的自问自答:这个确实是hive的bug,但这也是现代计算机中所有编程语言编写的软件共同面对的问题。当用户直接写出一个浮点数0.2时,hive会将该数保存为double类型。但是之前定义deductions这个map的值的类型是float型的。因此在where比较时,hive会将税率隐式转换为double型后再进行比较。

而这样比较是不行的。数字0.2不能用float或double准确的表示,因为0.2用float型保存时具体数值是0.2000001,而用double型保存时具体数值是0.200000000001。当表中的float字段通过hive转换为double型时,其精确数值是0.200000100000,明显可以看出比double型的0.2要大。这就是为什么查询结果像是使用了>=而不是>。

这个问题是所有使用IEEE标准进行浮点数编码的系统中存在的一个普遍问题。在实际生产中,各大厂商八仙过海各显神通,提出了多种多样的解决方法。在hive中有两种规避这个方法的方法。

(1)如果是从textfile文本文件中读取数据的话,即hive从数据文件中读取字符串“0.2”并按照表模式将其转换为一个数字。那么我们可以在定义表模式的时候就将此字段规定为double型。不过这种方法会增加查询时需要的内存,并且如果存储格式是二进制文件,也不能简单的进行这样的变换。

(2)显式类型转换。在比较的时候使用cast关键字将double型转换为float型。

作者在此时又皮了一下,以下是书中原文:

/*

实际上,还有第三种解决方案,即:和钱相关的都避免使用浮点数。

*/

总结:涉及到浮点数比较时,需要保持极端谨慎的态度,要避免任何从窄类型隐式转换到广泛类型的操作。

hear me roar!

上一篇下一篇

猜你喜欢

热点阅读