数据类型转换
数据处理中,经常要做异构数据的数据转化,能看到很多开源项目都有类似的模块,
比如datax、canal、maxwell等。除了数据的ETL和计算外,还要处理字段类型。
复杂度
mysql的某个字段是bigint,写到hive时类型是string,这是一个非常简单的例子。
再说一个稍微复杂点的,mysql的某个字段是datetime,写入avro时是long。
我能想到最复杂的场景是mysql的某个字段是datetime,以binlog方式采集出来
写到kafka时转换为string(yyyy-MM-dd HH:mm:ss),再写到parquetfile时类型为long。
表达类型和数据类型
在Java里我们能看到的常见数据表达类型是很有限的:
boolean、int、long、float、double、string、byte[]、date、short、char
大多数情况下数据表达类型和数据类型是一致的,这里举个反例,Date类型(yyyy-MM-dd)和
DateTime类型(yyyy-MM-dd HH:mm:ss)的数据表达类型在java中都是util.Date。
无论是在存储中还是语言中,类型都可以分成数据本质类型和数据表达类型。表达类型是可以复用的。
目标
前面我们把类型转化的问题进行了分析,如果我们是根据具体需求进行硬编码,那自然是很简单的。
我们希望设计一个结构,让增加一种数据类型或者增加一种数据表达更为简单。回归到具体业务中就是,
我们可以很容易的添加一种新的数据源类型,经过一些简答的配置就可以完成全类型的匹配转换。
解决方法
结构层次
分为三层结构:数据本质类型、数据来源类型、数据输出类型
数据来源类型
可以为任意常见表达类型
public interface UFrom {
void from(final Boolean p);
void from(final Integer p);
void from(final Long p);
void from(final Float p);
void from(final Double p);
void from(final String p);
void from(final Date p);
void from(final byte[] p);
}
数据输出类型
也可以为任意常见表达类型
public interface UTo {
Boolean toBoolean();
Integer toInt();
Long toLong();
Float toFloat();
Double toDouble();
String toStr();
Date toDate();
byte[] toBytes();
}
数据本质类型
1、UAbstDate(UDate、UDateTime、UTime、UYear)
2、UBoolean
3、UInteger
4、ULong
5、UFloat
6、UDouble
7、UString
8、UBytes
部分UData代码
private UAbstFrom<U> from;
private UAbstTo<U> to;
private boolean lazy;
private LazyCall[] lazyCalls = new LazyCall[MethodType.values().length];
private int lazyCallIndex = -1;
@Override
public void from(Date p) {
if (this.lazy) {
this.lazyCallIndex = MethodType.DATE.ordinal();
if (this.lazyCalls[this.lazyCallIndex] == null) {
this.lazyCalls[this.lazyCallIndex] = new LazyCall<Date>(p, MethodType.DATE) {
@Override void exec() {
if (raw == null) {
from.setData(null);
return;
}
from.from(raw);
}
};
} else {
this.lazyCalls[this.lazyCallIndex].raw = p;
}
return;
} else {
if (p == null) {
this.from.setData(null);
return;
}
this.from.from(p);
}
}
当from和to的类型是一致的时候,在lazy模式下就不进行类型转换了,可以提高效率。
最后
UDateTime u = new UDateTime(true);
u.from("2019-11-11 00:05:01");
u.toLong();