如何更改 datax 以支持hive 的 DECIMAL 数据类型?

简介: 如何更改 datax 以支持hive 的 DECIMAL 数据类型?

如何更改 datax 以支持hive 的 DECIMAL 数据类型?

1. JAVA 数据类型 - float/double 与 BigDecimal

大家知道,JAVA中可以用来存储小数的数字类型,主要包括:

  • 基本数据类型 float/double;
  • 基本数据类型的对应包装类 java.lang.Float/java.lang.Double;
  • java.math 包下的类 java.math.BigDecimal

一般来讲,在不需要完全精确的计算结果的场景下,可以直接使用 float 或 double 数据类型,其运算效率更高;而在需要精确计算结果的场景下,则必须使用 BigDecimal类,比如金融场景下涉及金额的计算,就必须是完全精确的计算:

  • Decimal data types store exact representations of numeric values, while DOUBLE data types store very close approximations of numeric values.
  • Decimal types are needed for use cases in which the (very close) approximation of a DOUBLE is insufficient, such as financial applications, equality and inequality checks, and rounding operations.
  • Decimal types are also needed for use cases that deal with numbers outside the DOUBLE range.

在使用 BigDecimal 时,以下细节需要注意:

  • BigDecimal 有多个构造方法,其中参数类型为 double 的构造方法的精度不能保证,其结果有一定的不可预知性,所以不推荐使用参数类型为 double 的构造方法(数值 0.1 无法准确地表示为 double数据类型);
  • BigDecimal 有多个构造方法,如果希望 BigDecimal 能够精确地表示期望的数值,那么一定要使用参数类型为 String 的构造方法,如 BigDecimal a = new BigDecimal(“0.1”) ;
  • 如果不是很在乎是否完全精确地表示,并使用了 BigDecimal(double),那么要注意 double 本身的特例,double 的规范本身定义了几个特殊的 double值 (Infinite,-Infinite,NaN),不要把这些值传给 BigDecimal,否则会抛出异常;
  • 当必须将 double 用作 BigDecimal 的数据来源时,建议先使用 Double.toString(double) 将 double 数值转换为 String,然后使用 参数类型为 String 的构造方法;
BigDecimal a = new BigDecimal(double d); //不推荐使用参数类型为 double 的构造方法,精度不能保证;
BigDecimal b= new BigDecimal(String s); //推荐使用参数类型为 String 的构造方法
static BigDecimal valueOf(double d); //也可以使用 valueOf 静态方法
DecimalFormat df = new DecimalFormat("#.##");// 可以使用 java.text.DecimalFormat 进行格式化,如这里保留2为小数
df.setRoundingMode(RoundingMode.HALF_UP);// 可以指定具体的的舍入模式枚举类 java.math.RoundingMode,默认五舍六入,如这里指定四舍五入;

2. hive 数据类型 - Double,DECIMAL,Numeric

hive 支持以下数字类数据类型,其中 FLOAT 和 DOUBLE 数据类型很早就支持了,而 Decimal 和 NUMERIC 数据类型是后续退出的:

640.png640.png


关于 hive 的 Decimal数据类型,有以下细节需要注意:

  • Decimal 数据类型是在 Hive 0.11.0 (HIVE-2693) 引入的,其后在 Hive 0.13.0 (HIVE-3976) 及进行了修改重构;
  • 在 Hive 0.13 之前版本,decimal 数据类型的数据精度是固定的38位;
  • 在 Hive 0.13 及之后版本,声明使用 DECIMAL数据类型有三种格式:DECIMAL/DECIMAL(precision)/DECIMAL(precision, scale),用户可以使用第三种格式 DECIMAL(precision, scale) 指定 decimal 的数据精度和数据刻度(小数位数);
  • 在 Hive 0.13 及之后版本,若没有指定 DECIMAL 的精度 precision,则默认精度是10(精度的最大值是38),若没有指定小数位数 scale,则默认小数位数是 0;
  • Hive 的 Decimal 数据类型底层基于 Java 的 BigDecimal,支持科学计数法和非科学计数法:
  • The DECIMAL type in Hive is based on Java's BigDecimal which is used for representing immutable arbitrary precision decimal numbers in Java.
  • All regular number operations (e.g. +, -, *, /) and relevant UDFs (e.g. Floor, Ceil, Round, and many more) handle decimal types.
  • You can cast to/from decimal types like you would do with other numeric types.
  • The persistence format of the decimal type supports both scientific and non-scientific notation. Therefore, regardless of whether your dataset contains data like 4.004E+3 (scientific notation) or 4004 (non-scientific notation) or a combination of both, DECIMAL can be used for it.


  • Double 数据类型提供了数据的近似表示与近似计算,而 Decimal 数据类型提供了数据的精确表示与精确计算,且支持的数据范围更大:
  • Decimal literals provide precise values and greater range for floating point numbers than the DOUBLE type.
  • Decimal data types store exact representations of numeric values, while DOUBLE data types store very close approximations of numeric values;
  • Decimal types are needed for use cases in which the (very close) approximation of a DOUBLE is insufficient, such as financial applications, equality and inequality checks, and rounding operations.
  • They are also needed for use cases that deal with numbers outside the DOUBLE range.

SQL 语句显示转换 decimal 数据类型示例如下:

select CAST(18446744073709001000BD AS DECIMAL(38,0));
select cast(4.004E+3 AS DECIMAL(38,0));
select cast(4004 AS DECIMAL(38,0));

3.如何更改 datax 以支持 hive 的 DECIMAL 数据类型?

  • 如上文所述,在需要对数据进行精确表示和精确运算的场景下(比如金融行业对数据准确性普遍要求较高),我们需要使用 HIVE 的 Decimal 数据类型而不是 Double 数据类型;
  • 但是一些数据同步工具并不直接支持 hive 的 decimal 数据类型,此时需要基于开源版本在内部做二次开发和增强,以支持支持 hive 的 decimal 数据类型;
  • 比如开源的 datax 在读和写上都不支持 hive 的 decimal 数据类型:

image.pngimage.png

那么怎么修改开源的 datax 源码,以增强支持 hive 的 decimal 数据类型呢?

  • 由于 datax 的插件化的机制,相关修改只涉及到 hdfsreader 和 hdfswriter 插件模块;
  • 由于 datax 在读写 hive orc 表时,底层使用的是 hive/orc/hadoop 原生的各种 api,而这些 hive/orc/hadoop 原生的api 已经支持了对 hive Decimal 数据类型的读写操作,所以 datax 的 hdfs reader 和 hdfs writer 插件模块所需的代码修改并不多;
-- datax 读写 hive orc 表时,底层使用的 hive/orc/hadoop 原生api部分列表如下:
org.apache.hadoop.hive.ql.io.orc.OrcFile;
org.apache.hadoop.hive.ql.io.orc.OrcInputFormat;
org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat;
org.apache.hadoop.hive.ql.io.orc.OrcSerde;
org.apache.hadoop.hive.ql.io.orc.Reader;
org.apache.hadoop.mapred.RecordWriter;
org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
-- hive读写 orc 文件数据时,底层调用的是 Core ORC API,这些 api 部分列表如下:
org.apache.hadoop.hive.ql.io.orc.OrcFile;
org.apache.hadoop.hive.ql.exec.vector.VectorizedRowBatch;
org.apache.hadoop.hive.ql.exec.vector.ColumnVector;
org.apache.hadoop.hive.ql.exec.vector.DecimalColumnVector;
org.apache.hadoop.hive.ql.io.orc.Reader;
org.apache.hadoop.hive.ql.io.orc.RecordReader;
org.apache.hadoop.hive.ql.io.orc.Writer;
org.apache.hadoop.hive.ql.io.orc.WriterImpl;
org.apache.hadoop.hive.serde2.io.HiveDecimalWritable;

3.1 hdfs reader 相关修改

为支持读取 hive orc 文件中的 decimal字段, 需要修改 hdfs reader插件模块中的相关类和方法,这些类和方法主要是 com.alibaba.datax.plugin.reader.hdfsreader.DFSUtil#transportOneRecord:

640.png

事实上,由于 datax 有自己的类型系统,比如 datax 的 Double 类型对应的类是 com.alibaba.datax.common.element.DoubleColumn,该类内部有 rawData 字段用来存储数据的原始内容,且可以存储的数据范围包括 java.math.BigDecimal,也包括java.lang.Double,所以我们甚至可以不修改 hdfs reader 的任何代码,直接读取 hive orc 表中的 Decimal 字段并进行数据同步:用户可以在配置作业时,在hdfsReader 部分将 hive 的 Decimal 字段指定为 datax 的 Double 数据类型,此时 hdfsReader 在底层就会调用 hive 的相关 api 读取底层 orc 文件中的相关字段,并将 orc 的 Decimal 字段隐式转换为 datax 的 Double 类型,由于 datax 的 Double 类型可以存储的数据范围包括 java.math.BigDecimal 也包括java.lang.Double,所以后续再使用 oracleWriter 等插件将 datax 的 Double 字段写到外部系统如 Oralce 时,就可以使用方法com.alibaba.datax.common.element.DoubleColumn#asBigDecimal, 基于 DoubleColumn 底层 rawData 存储的原始数据内容,将字段值转换为合适的外部数据类型,在此过程中并不会损失数据精度。

3.1 hdfs writer 相关修改

为支持写入数据到 hive orc 文件中的 decimal字段, 需要修改 hdfs writer插件模块中的相关类和方法,这些类和方法主要是:

com.alibaba.datax.plugin.writer.hdfswriter.SupportHiveDataType;
com.alibaba.datax.plugin.writer.hdfswriter.HdfsHelper#getColumnTypeInspectors;
com.alibaba.datax.plugin.writer.hdfswriter.HdfsHelper#transportOneRecord(com.alibaba.datax.common.element.Record, java.util.List<com.alibaba.datax.common.util.Configuration>, com.alibaba.datax.common.plugin.TaskPluginCollector);

640.png640.png640.png


最后概括下相关技术点:

  • datax 有自己的数据类型,比如 long/Double/String/Date/Boolean/Bytes 等;
  • datax 的 Double 类型,其对应的类不是 java.lang.Double,而是 com.alibaba.datax.common.element.DoubleColumn,该类内部有 rawData 字段用来存储数据的原始内容,可以存储的数据范围包括 java.math.BigDecimal,也包括java.lang.Doulbe;
  • datax 的 Double 类型,在内部可以使用方法 com.alibaba.datax.common.element.DoubleColumn#asBigDecimal, 基于 rawData 存储的原始内容,将数据转换为 java.math.bigDecimal 等外部类型,所以将 java.math.BigDecimal 存储在datax 的DoubleColumn中,并不会损失数据精度;
  • datax在同步数据时,会先使用 hdfsReader 等插件读取上游数据源中的数据并转换成用户指定的数据类型(如datax 内部数据类型 Double),然后再使用 hdfsWriter 等插件将存储在 datax 内部数据类型中的字段值,转换为用户指定的下游数据源的目标字段类型(如 hive 的 Decimal 类型)并写到下游如orc文件中;
  • 为支持 hive orc 中的 Decimal 数据类型,可以在 datax 的 hdfsWriter 模块相关代码中,通过调用 hive 的api org.apache.hadoop.hive.serde2.typeinfo.HiveDecimalUtils#enforcePrecisionScale() 和 org.apache.hadoop.hive.common.type.HiveDecimal#enforcePrecisionScale, 将数据转换为 hive orc 期望的精度和标度 DECIMAL(precision, scale).
相关文章
|
6月前
|
SQL 存储 HIVE
Hive中的表是如何定义的?请解释表的结构和数据类型。
Hive中的表是如何定义的?请解释表的结构和数据类型。
100 0
|
6月前
|
SQL 消息中间件 数据处理
DataX读取Hive Orc格式表丢失数据处理记录
DataX读取Hive Orc格式表丢失数据处理记录
253 0
|
3月前
|
存储 SQL 分布式计算
Hive 中有多少种数据类型?
【8月更文挑战第12天】
322 4
|
6月前
|
SQL 存储 Java
Hive 特殊的数据类型 Array、Map、Struct
在Hive中,`Array`、`Map`和`Struct`是三种特殊的数据类型。`Array`用于存储相同类型的列表,如`select array(1, &quot;1&quot;, 2, 3, 4, 5)`会产生一个整数数组。`Map`是键值对集合,键值类型需一致,如`select map(1, 2, 3, &quot;4&quot;)`会产生一个整数到整数的映射。`Struct`表示结构体,有固定数量和类型的字段,如`select struct(1, 2, 3, 4)`创建一个无名结构体。这些类型支持嵌套使用,允许更复杂的结构数据存储。例如,可以创建一个包含用户结构体的数组来存储多用户信息
521 0
|
6月前
|
SQL 存储 分布式计算
Hive【基础 01】核心概念+体系架构+数据类型+内容格式+存储格式+内外部表(部分图片来源于网络)
【4月更文挑战第6天】Hive【基础 01】核心概念+体系架构+数据类型+内容格式+存储格式+内外部表(部分图片来源于网络)
128 1
|
SQL 存储 大数据
更改 HIVE 表字段数据类型有哪些注意事项?
更改 HIVE 表字段数据类型有哪些注意事项?
|
存储 SQL HIVE
数据仓库的Hive的数据类型的复杂数据类型的map
在数据仓库领域,Hive是一个常用的工具。它提供了一种简单的方式来查询和分析大量数据。
163 0
|
6月前
|
SQL Oracle 关系型数据库
Hive中的DECIMAL类型
Hive中的DECIMAL类型
336 1
|
SQL 存储 Java
Hive教程(04)- Hive数据类型
Hive教程(04)- Hive数据类型
272 0
|
SQL 存储 关系型数据库
为什么不能使用 datax 直接读写 hive acid 事务表?
为什么不能使用 datax 直接读写 hive acid 事务表?