数据处理中,经常要做异构数据的数据转化,能看到很多开源项目都有类似的模块,

比如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();