hive之数据类型初探

 

前段时间在做一个将oralce代码转换hive代码项目开发时,遇到了一个问题,问题描述如下:

(A)

Hive:

Select concat(round(1/3,4)*100,'%') from v_table limit 1;

Output:33.33%

Oracle:

select concat(round(1/3,4)*100,'%') from dual;

Output:33.33%

 

(B)

Hive:

Select concat(round(4/3,4)*100,'%') from v_table limit 1;

Output:133.32999999999998%

Oracle:

select concat(round(4/3,4)*100,'%') from dual;

Output:133.33%

 

B中hive输出的字符串长度过长导致插入oracle表时出错(oracle该字段定义为VARCHAR2(13)), 想到查看hive系统函数round的源码来探个究竟。Hive所有的函数源码可以通过解压hive-0.1x-0.tar.gz(附带源码)查看(感觉是编写udf很好的参考资料):

路径: $hive_dir/src/ql/src/java/org/apache/Hadoop/hive/ql/udf,其中的UDFRound.java 中就是定义了round函数的功能,该类重载多个evaluate方法,找到对应本例中的版本:

public DoubleWritableevaluate(DoubleWritable n, IntWritable i) {
    if ((n == null) || (i == null)) {
      return null;
    }
return evaluate(n, i.get());
}

其中evaluate调用以下方法:

private DoubleWritableevaluate(DoubleWritable n, int i) {
    double d = n.get();
    if (Double.isNaN(d) || Double.isInfinite(d)){
      doubleWritable.set(d);
    } else {
      doubleWritable.set(BigDecimal.valueOf(d).setScale(i,
             RoundingMode.HALF_UP).doubleValue());
    }
    return doubleWritable;
}


hive round函数采用java类库中BigDecimal(高精度十进制浮点数)来缩减小数位,但是最终返回的是二进制浮点型double,由于二进制浮点数存在精度问题,表示某些数是近似表示,例如二进制浮点数就不能用有限位表示十进制的0.1,因此导致double的四则运算可能会出现随机的误差,如B中所示。下面代码重现了hive在AB表现的不同:

import java.math.BigDecimal;
import java.math.RoundingMode;
 
public class Test {
    public double round(double d,int i){
        double ret  = 0.0;
        if (Double.isNaN(d)|| Double.isInfinite(d)) {
          ret = d;
        } else {
          ret = BigDecimal.valueOf(d).setScale(i,RoundingMode.HALF_UP).doubleValue();
        }
        return ret;
    }
   
    public static void main(String[] args) {
        // TODO Auto-generated methodstub
        Test t = new Test();       
        System.out.println(t.round(1/3.0,4)*100);
        System.out.println(t.round(4/3.0,4)*100);
        System.out.println(1.3333*100);
        System.out.println(0.3333*100);
    }
}

Output:

33.33

133.32999999999998

33.33

133.32999999999998

高级语言如java (BigDecimal类)、python(decimal模块)等都提供了decimal表示,hive在0.11版本开始也引入decimal类型。十进制浮点数与二进制浮点数常规标准IEEE754的不同点表现在它的底数为10,因此decimal需要独立实现其四则运算算法,因此一般情况下其运算效率比较二进制浮点数也较低。


A B中Oracle的round函数并不会有这样问题,可能是oracle的内置数据类型保证其精度不会出现误差。

 

以上是我的一些简单的思考,有什么阐述不对或者有什么更加透彻的理解,欢迎交流!

 

[1] http://my.oschina.net/jackieyeah/blog/205505

[2] http://www.javaweb.cc/JavaAPI1.6/ (search BigDecimal)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值