flink-sql所有数据类型-1.15

1. 版本说明

本文档内容基于flink-1.15.x,其他版本的整理,请查看本人博客的 flink 专栏其他文章。

2. 介绍

Flink SQL有一组丰富的本地数据类型可供用户使用。

数据类型描述表生态系统中值的逻辑类型,它可用于声明操作的输入和/或输出类型。

Flink的数据类型类似于SQL标准的数据类型,但也包含了关于值是否为空的信息,以便有效地处理标量表达式。

数据类型的例子有:

  • INT
  • INT NOT NULL
  • INTERVAL DAY TO SECOND(3)
  • ROW<myField ARRAY<BOOLEAN>, myOtherField TIMESTAMP(3)>

所有预定义的数据类型在下面列出。

2.1. Table API 中的数据类型

java/scala

基于 JVM 的用户,在使用 Table API 或者是自定义连接器、catalog、自定义函数时,可以使用 org.apache.flink.table.types.DataType 类的实例。

DataType 实例有两个职责:

  1. 声明一个逻辑类型:这并不是定义传输或存储的具体物理表示,但其定义了基于 jvm/Python 语言和表生态系统之间的边界。
  2. 可选:将数据的物理表示提示给 planner 计划器,这对于其他 API 是非常有用的。

为了流畅的使用 API ,可以在表程序开头添加 import 语句导入所有的数据类型。

java

import static org.apache.flink.table.api.DataTypes.*;
DataType t = INTERVAL(DAY(), SECOND(3));

scala

import org.apache.flink.table.api.DataTypes._
val t: DataType = INTERVAL(DAY(), SECOND(3));

2.1.1. 物理提示

基于sql的类型系统末端的表生态系统边缘需要物理提示,并且是编程代码指定的数据类型。提示表示所期望的数据格式。

例如,数据源使用 java.sql.Timestamp 类来生成逻辑时间戳值,而不是使用 java.time.LocalDateTime,后者是默认值。有了这些信息,程序运行时就可以将生成的类转换为它的内部数据格式。同时,sink 也可以声明它从运行时获取到的数据格式。

下面是一些如何声明桥接转换类的例子:

java

// 告诉运行时使用 java.sql.Timestamp 而不是 java.time.LocalDateTime 实例
DataType t = DataTypes.TIMESTAMP(3).bridgedTo(java.sql.Timestamp.class);

// 告诉运行时使用原生的 int 数组而不是包装的 integer 数组
DataType t = DataTypes.ARRAY(DataTypes.INT().notNull()).bridgedTo(int[].class);

scala

// 告诉运行时使用 java.sql.Timestamp 而不是 java.time.LocalDateTime 实例
val t: DataType = DataTypes.TIMESTAMP(3).bridgedTo(classOf[java.sql.Timestamp]);

// 告诉运行时使用原生的 int 数组而不是包装的 integer 数组
val t: DataType = DataTypes.ARRAY(DataTypes.INT().notNull()).bridgedTo(classOf[Array[Int]]);

注意:通常来说,只有在扩展 API 时才要求物理提示。用户在自定义 sources/sinks/functions 时并不需要定义这些提示。表程序中的提示(比如:field.cast(TIMESTAMP(3).bridgedTo(Timestamp.class)))将会被忽略。

下面将列出所有预定义数据类型。

默认的计划器支持下面的SQL类型

java/scala

数据类型解释
CHAR
VARCHAR
STRING
BOOLEAN
BYTES支持BINARY 和VARBINARY
DECIMAL支持固定的精度和刻度
TINYINT
SMALLINT
INTEGER
BIGINT
FLOAT
DOUBLE
DATE
TIME只支持精度:0
TIMESTAMP
TIMESTAMP_LTZ
INTERVAL只支持 interval of MONTHSECOND(3)
ARRAY
MULTISET
MAP
ROW
RAW
structured types目前仅可在自定义函数中使用

3. 列出所有数据类型

该章节会列出所有预定义的数据类型。

java/scala

对于基于 JVM 的 Table API ,在 org.apache.flink.table.api.DataTypes 中的类型都已经可以使用了。

3.1. Character Strings

3.1.1. CHAR

固定长度的character string。

SQL

CHAR
CHAR(n)

java/scala

DataTypes.CHAR(n);

桥接到JVM数据类型

Java 类型InputOutputOutput
java.lang.StringXX默认
byte[]XXUTF-8编码
org.apache.flink.table.data.StringDataXX内部数据结构

该类型可以使用CHAR(n)声明,其中n是字符的数量。n的值必须在12147,483,647之间(前后都包括)。如果没有指定长度,则n等于1。

3.1.2. VARCHAR/STRING

可变长度的character string。

SQL

VARCHAR
VARCHAR(n)

STRING

java/scala

DataTypes.VARCHAR(n);
DataTypes.STRING();

桥接到JVM数据类型

Java 类型InputOutputOutput
java.lang.StringX默认
byte[]XXUTF-8编码
org.apache.flink.table.data.StringDataXX内部数据结构

该类型可以使用VARCHAR(n)声明,其中n是最大的字符数量。N的值必须在12147,483,647之间(包括两者)。如果没有指定长度,则n等于1。

STRINGVARCHAR(2147483647)相同。

3.2. Binary Strings

BINARY

固定长度的二进制字符串,等同于字节序列。

SQL

BINARY
BINARY(n)

java/scala

DataTypes.BINARY(n);

桥接到JVM数据类型

Java 类型InputOutputOutput
byte[]XX默认

该类型可以使用BINARY(n)声明,其中n为字节数。N的值必须在12147,483,647之间(包括两者)。如果没有指定长度,则n等于1。

3.2.1. VARBINARY/BYTES

可变长度的二进制字符串,等同于字节序列。

SQL

VARBINARY
VARBINARY(n)

BYTES

java/scala

DataTypes.VARBINARY(n);
DataTypes.BYTES();

桥接到JVM数据类型

Java 类型InputOutputOutput
byte[]XX默认

该类型可以使用VARBINARY(n)声明,其中n为最大字节数。N的值必须在12147,483,647之间(包括两者)。如果没有指定长度,则n等于1。

BYTESVARBINARY(2147483647)相同。

3.3. 精确数字

3.3.1. DECIMAL

具有固定精度和比例的小数的数据类型。

SQL

DECIMAL
DECIMAL(p)
DECIMAL(p, s)

DEC
DEC(p)
DEC(p, s)

NUMERIC
NUMERIC(p)
NUMERIC(p, s)

java/scala

DataTypes.DECIMAL(p,s);

桥接到JVM数据类型

Java 类型InputOutputOutput
java.math.BigDecimalXX默认
org.apache.flink.table.data.DecimalDataXX内部数据结构

该类型可以使用DECIMAL(p, s)声明,其中p是数字(精度)的总位数,s是数字(刻度)小数点右边的位数。
P的值必须在138之间(包括两者)。S的值必须在0p之间(包括两者)。p的默认值是10。s的默认值是0。

NUMERIC(p, s)DEC(p, s)和该类型含义一样。

3.3.2. TINYINT

值从-128127,1个字节,有符号整数。

SQL

TINYINT

java/scala

DataTypes.TINYINT();

桥接到JVM数据类型

Java 类型InputOutputOutput
java.lang.ByteXX默认
byteX(X)类型为非空null时才会输出

3.3.3. SMALLINT

值从-32,76832,767,2个字节,有符号整数。

SQL

SMALLINT

java/scala

DataTypes.SMALLINT();

桥接到JVM数据类型

Java 类型InputOutputOutput
java.lang.ShortXX默认
shortX(X)类型为非空null时才会输出

3.3.4. INT

值从-2147,483,6482147,483,647,4个字节,有符号整数。

SQL

INT
INTEGER

java/scala

DataTypes.INT();

桥接到JVM数据类型

Java 类型InputOutputOutput
java.lang.IntegerXX默认
intX(X)类型为非空null时才会输出

INTEGER也表示该类型。

3.3.5. BIGINT

值从-9,223,372,036,854,775,8089,223,372,036,854,775,807,8个字节,有符号整数。

SQL

BIGINT

java/scala

DataTypes.BIGINT();

桥接到JVM数据类型

Java 类型InputOutputOutput
java.lang.LongXX默认
longX(X)类型为非空null时才会输出

3.4. 近似数字

3.4.1. FLOAT

4个字节的单精度浮点数。

与SQL标准相比,该类型不带参数。

SQL

FLOAT

java/scala

DataTypes.FLOAT();

桥接到JVM数据类型

Java 类型InputOutputOutput
java.lang.FloatXX默认
floatX(X)类型为非空null时才会输出

3.4.2. DOUBLE

8字节的双精度浮点数。

SQL

DOUBLE
DOUBLE PRECISION

java/scala

DataTypes.DOUBLE();

桥接到JVM数据类型

Java 类型InputOutputOutput
java.lang.DoubleXX默认
doubleX(X)类型为非空null时才会输出

DOUBLE PRECISION也表示该类型。

3.5. Date 和Time

注意:所有时间类型的精度 p 指的都是秒后面的小数个数。

3.5.1. DATE

日期数据类型为年-月-日,取值范围为0000-01-01 ~ 9999-12-31

与 SQL 标准相比,范围从 0000 年开始。

SQL

DATE

java/scala

DataTypes.DATE();

桥接到JVM数据类型

Java 类型InputOutputOutput
java.time.LocalDateXX默认
java.sql.DateXX
java.lang.IntegerXX描述从纪元开始经过的天数
intX(X)描述从纪元开始已经过的天数。类型为非空null时才会输出

3.5.2. TIME

无时区的时间数据类型,由时:分:秒[.小数]组成,精度可达纳秒,值范围从00:00:00.00000000023:59:59.999999999

SQL/Java/Scala

与SQL标准相比,该类型不支持闰秒(23:59:60和23:59:61),因为该类型语义更接近java.time.LocalTime。目前不支持带时区的时间。

SQL

TIME
TIME(p)

java/scala

DataTypes.TIME(p);

桥接到JVM数据类型

Java 类型InputOutputOutput
java.time.LocalTimeXX默认
java.sql.TimeXX
java.lang.IntegerXX描述当天经过的毫秒值
intX(X)描述当天经过的毫秒值
类型为非空null时才会输出
java.lang.LongXX描述当天经过的纳秒值
long(X)描述当天经过的纳秒值
类型为非空null时才会输出

该类型可以使用TIME(p)声明,其中p是秒后面小数的位数(精度)。P必须有一个介于0和9之间的值(包括两者)。如果没有指定精度,p等于0。

3.5.3. TIMESTAMP

无时区的时间戳数据类型,由年-月-日 时:分:秒[.小数]组成,精度可达纳秒,值范围从0000-01-01 00:00:00.0000000009999-12-31 23:59:59.99999999999

SQL/Java/Scala

与SQL标准相比,该类型不支持闰秒(23:59:60和23:59:61),因为该类型语义更接近java.time.LocalDateTime

不支持从BIGINT (JVM long类型)转化为该类型,也不支持从该类型转换到BIGINT (JVM long类型),因为这种转换需要时区,但是该类型是不受时区限制的。
如果需要使用到时区,则可以使用TIMESTAMP_LTZ类型。

SQL

TIMESTAMP
TIMESTAMP(p)

TIMESTAMP WITHOUT TIME ZONE
TIMESTAMP(p) WITHOUT TIME ZONE

java/scala

DataTypes.TIMESTAMP(p);

桥接到JVM数据类型

Java 类型InputOutputOutput
java.time.LocalDateTimeXX默认
java.sql.TimestampXX
org.apache.flink.table.data.TimestampDataXX内部数据结构

该类型可以使用TIMESTAMP(p)声明,其中p是秒后面小数(精度)的位数。P必须是一个介于0和9之间的值(包括两者)。如果没有指定精度,则p等于6。

TIMESTAMP(p) WITHOUT TIME ZONE也表示该类型。

3.5.4. TIMESTAMP WITH TIME ZONE

有时区的时间戳的数据类型,由年-月-日 时:分:秒[.分数]组成,精确度可达纳秒,值范围为0000-01-01 00:00:00.000000000 +14:59
9999-12-31 23:59:59.999999999 -14:59

TIMESTAMP_LTZ相比,时区偏移信息物理地存储在每个数据中。它被单独用于每一个计算、可视化以及与外部系统通信。

SQL

TIMESTAMP WITH TIME ZONE
TIMESTAMP(p) WITH TIME ZONE

java/scala

DataTypes.TIMESTAMP_WITH_TIME_ZONE(p);

桥接到JVM数据类型

Java 类型InputOutputOutput
java.time.OffsetDateTimeXX默认
java.time.ZonedDateTimeX忽略时区ID

3.5.5. TIMESTAMP_LTZ

使用本地时区的时间戳数据类型,由年-月-日 时:分:秒[.分数]组成,精度可达纳秒,值范围为0000-01-01 00:00:00.000000000 +14:59
9999-12-31 23:59:59.999999999 -14:59

该类型允许根据配置的会话时区解释UTC时间戳来填补自由时区和强制时区时间戳类型之间的空白。

SQL

TIMESTAMP_LTZ
TIMESTAMP_LTZ(p)

TIMESTAMP WITH LOCAL TIME ZONE
TIMESTAMP(p) WITH LOCAL TIME ZONE

java/scala

DataTypes.TIMESTAMP_LTZ(p);
DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE(p);

桥接到JVM数据类型

Java 类型InputOutputOutput
java.time.InstantXX默认
java.lang.IntegerXX描述从纪元开始经过的秒数
intX(X)描述从纪元开始经过的秒数
类型为非空null时才会输出
java.lang.LongXX描述从纪元开始经过的毫秒数
longX(X)描述从纪元开始经过的毫秒数
类型为非空null时才会输出
java.sql.TimestampXX描述从纪元开始经过的毫秒数
org.apache.flink.table.data.TimestampDataXX内部数据结构

可以使用TIMESTAMP_LTZ(p)声明该类型,其中p是秒后面小数(精度)的位数。P必须是一个介于0和9之间的值(包括两者)。如果没有指定精度,则p等于6。

TIMESTAMP(p) WITH LOCAL TIME ZONE是该类型的同义词。

3.5.6. INTERVAL YEAR TO MONTH

一组年-月间隔类型的数据类型。

该类型必须参数化为以下解析之一:

  • interval of years
  • interval of years to months
  • interval of months

年-月的间隔由 +year-momth 组成,取值范围为-9999-11 ~ +9999-11

比如,50个月的间隔以年到月的间隔格式表示为(使用默认的年精度):+04-02

SQL

INTERVAL YEAR
INTERVAL YEAR(p)
INTERVAL YEAR(p) TO MONTH
INTERVAL MONTH

java/scala

DataTypes.INTERVAL(DataTypes.YEAR());
DataTypes.INTERVAL(DataTypes.YEAR(p));
DataTypes.INTERVAL(DataTypes.YEAR(p),DataTypes.MONTH());
DataTypes.INTERVAL(DataTypes.MONTH());

桥接到JVM数据类型

Java 类型InputOutputOutput
java.time.PeriodXX忽略天的部分,默认
java.lang.IntegerXX描述经过的月数
intX(X)描述经过的月数
类型为非空null时才会输出

可以使用上面的组合声明类型,其中p是年份的位数(年份精度)。P的值必须在1和4之间(包括两者)。如果没有指定年份精度,则p等于2。

3.5.7. INTERVAL DAY TO SECOND

一组日间隔类型的数据类型。

该类型必须参数化为以下解析之一,精度可达纳秒:

  • interval of days
  • interval of days to hours
  • interval of days to minutes
  • interval of days to seconds
  • interval of hours
  • interval of hours to minutes
  • interval of hours to seconds
  • interval of minutes
  • interval of minutes to seconds
  • interval of seconds

day-time的间隔由 +天 时:分:秒.小数组成,取值范围为-999999 23:59:59.999999999+999999 23:59:59.999999999
例如,70秒的间隔以天到秒的间隔格式表示(具有默认精度):+00 00:01:10 000000

SQL

INTERVAL DAY
INTERVAL DAY(p1)
INTERVAL DAY(p1) TO HOUR
INTERVAL DAY(p1) TO MINUTE
INTERVAL DAY(p1) TO SECOND(p2)
INTERVAL HOUR
INTERVAL HOUR TO MINUTE
INTERVAL HOUR TO SECOND(p2)
INTERVAL MINUTE
INTERVAL MINUTE TO SECOND(p2)
INTERVAL SECOND
INTERVAL SECOND(p2)

java/scala

DataTypes.INTERVAL(DataTypes.DAY());
DataTypes.INTERVAL(DataTypes.DAY(p1));
DataTypes.INTERVAL(DataTypes.DAY(p1),DataTypes.HOUR());
DataTypes.INTERVAL(DataTypes.DAY(p1),DataTypes.MINUTE());
DataTypes.INTERVAL(DataTypes.DAY(p1),DataTypes.SECOND(p2));
DataTypes.INTERVAL(DataTypes.HOUR());
DataTypes.INTERVAL(DataTypes.HOUR(),DataTypes.MINUTE());
DataTypes.INTERVAL(DataTypes.HOUR(),DataTypes.SECOND(p2));
DataTypes.INTERVAL(DataTypes.MINUTE());
DataTypes.INTERVAL(DataTypes.MINUTE(),DataTypes.SECOND(p2));
DataTypes.INTERVAL(DataTypes.SECOND());
DataTypes.INTERVAL(DataTypes.SECOND(p2));

桥接到JVM数据类型

Java 类型InputOutputOutput
java.time.DurationXX默认
java.lang.LongXX描述毫秒值
longX(X)描述毫秒值
类型为非空null时才会输出

可以使用上面的组合声明该类型,其中p1是天数(天数精度),p2是小数秒(小数精度)。P1的值必须在1到6之间(包括1和6)。P2的值必须在0到9之间(包括两者)。
如果没有指定p1,默认值为2。如果没有指定p2,默认值为6。

3.6. Constructed结构数据类型

3.6.1. ARRAY

具有相同子类型元素的数组。

与SQL标准相比,不能指定数组的最大基数,而是固定在2,147,483,647。此外,支持任何有效类型作为子类型。

SQL

ARRAY<t>
t ARRAY

java/scala

DataTypes.ARRAY(t);

桥接到JVM数据类型

Java 类型InputOutputOutput
t[](X)(X)由子类型决定,默认
java.util.List<t> XX
java.util.List<t> 的子类X
org.apache.flink.table.data.ArrayDataXX内部数据结构

该类型可以使用ARRAY<t>声明,其中t是所包含元素的数据类型。

t ARRAY是接近SQL标准的同义词。例如,INT ARRAY等价于ARRAY<INT>

3.6.2. MAP

关联数组的数据类型,将键(包括NULL)映射到值(包括NULL)。map不能包含重复的键;每个键最多只能映射到一个值。

元素类型没有限制,需要用户确保数据key的唯一性。

map类型是对SQL标准的扩展。

SQL

MAP<kt, vt>

java/scala

DataTypes.MAP(kt,vt);

其中的ktvt都是DataType类型。

桥接到JVM数据类型

Java 类型InputOutputOutput
java.util.Map<kt, vt>XX默认
java.util.Map<kt, vt>X
org.apache.flink.table.data.MapDataXX内部数据类型

该类型可以使用MAP<kt, vt>声明,其中kt是key元素的数据类型,vt是value元素的数据类型。

3.6.3. MULTISET

multiset(=bag)数据类型。与map不同,它允许集合中的每个元素存在多个实例。每个唯一的值(包括NULL)可以保存多个。

元素类型没有限制,需要用户确保唯一性。

SQL

MULTISET<t>
t MULTISET

java/scala

DataTypes.MULTISET(t);

桥接到JVM数据类型

Java 类型InputOutputOutput
java.util.Map<t, java.lang.Integer>XX默认,给每个值分配其对应个数
java.util.Map<t, java.lang.Integer>子类X
org.apache.flink.table.data.MapDataXX内部数据类型

该类型可以使用MULTISET<t>声明,其中t是所包含元素的数据类型。

MULTISET是接近SQL标准的同义词。例如,INT MULTISET等价于MULTISET<INT>

3.6.4. ROW

字段序列的数据类型。

字段由字段名、字段类型和可选描述组成。表中数据最特殊的类型就是 row 类型,每列中 row 类型字段中的所有属性位置都和列中的位置一一对应。

与SQL标准相比,可选的字段描述简化了复杂结构的处理。

行类型类似于其他非标准兼容框架中的STRUCT类型。

SQL

ROW<n0 t0, n1 t1, ...>
ROW<n0 t0 'd0', n1 t1 'd1', ...>

ROW(n0 t0, n1 t1, ...)
ROW(n0 t0 'd0', n1 t1 'd1', ...)

java/scala

DataTypes.ROW(DataTypes.FIELD(n0,t0),DataTypes.FIELD(n1,t1),...);
        DataTypes.ROW(DataTypes.FIELD(n0,t0,d0),DataTypes.FIELD(n1,t1,d1),...);

n0为字段名称,t0为字段类型,d0为字段描述。

桥接到JVM数据类型

Java 类型InputOutputOutput
org.apache.flink.types.RowXX默认
org.apache.flink.table.data.RowDataXX内部数据结构

可以使用ROW<n0 t0 'd0', n1 t1 'd1',…>声明该类型,其中n是字段的唯一名称,t是字段的逻辑类型,d是字段的描述。

ROW(…)是接近SQL标准的同义词。例如,ROW(myField INT, myOtherField BOOLEAN)等价于ROW<myField INT, myOtherField BOOLEAN>

3.7. 用户自定义数据类型

目前还不完全支持用户自定义的数据类型。它们目前(从Flink 1.11开始)只在参数和函数返回类型中作为未注册的结构类型。

结构化类型类似于面向对象编程语言中的对象。它包含零个、一个或多个属性。每个属性由名称和类型组成。

有两种结构化类型:

  • 存储在catalog中并由catalog标识符标识的类型(如cat.db.MyType)。这些等同于结构化类型的SQL标准定义。
  • 匿名定义、未注册的类型(通常通过反射提取),由其实现类(如com.myorg.model.MyType)标识。这些类型在以编程方式定义表程序中很有用。它们允许重用现有的JVM类,而无需再次手动定义数据类型的模式。

注册的结构化类型

目前还不支持注册结构化类型。因此,它们不能存储在catalog中,也不能在CREATE TABLE DDL中引用。

未注册的结构化类型

可以使用自动反射提取从常规pojo(普通Java对象)创建未注册的结构化类型。

结构化类型的实现类必须满足以下要求:

  • 类必须是全局可访问的,这意味着它必须声明为public、static,而不是abstract
  • 类必须提供一个零参数的默认构造函数或一个赋值所有字段的完整参数的构造函数。
  • 类的所有字段必须可以通过public声明或遵循公共编码风格的getter(如getField(), isField(), field())方法读取。
  • 类的所有字段必须由public声明、有完整参数的构造函数或遵循公共编码风格的setter(如setField(…)、field(…))方法写入。
  • 所有字段必须可以通过隐式地反射提取或使用@DataTypeHint注释显式地映射到数据类型。
  • 声明为statictransient的字段将被忽略。

反射提取支持字段的任意嵌套,只要字段类型不传递性地引用自身。

声明的字段类行(例如public int age)必须在受支持的JVM桥接类列表中,例如int 为:java.lang.Integerint

对于某些类,需要一个注释来将类映射到具体的数据类型(例如@DataTypeHint("DECIMAL(10,2)")来为java.math.BigDecimal指定固定的精度和比例)。

JAVA

class User {
    // 自动抽取数据类型
    public int age;
    public String name;
    //通过注解丰富其精度信息
    public @DataTypeHint("DECIMAL(10, 2)")
    BigDecimal totalBalance;
    //强制使用RAW类型丰富提取
    public @DataTypeHint("RAW")
    Class<?> modelClass;
}
DataTypes.of(User.class);

scala

case class User(

    // 自动抽取数据类型
    age: Int,
    name: String,

    //通过注解丰富其精度信息
    @DataTypeHint("DECIMAL(10, 2)") totalBalance: java.math.BigDecimal,

    //强制使用RAW类型丰富提取
    @DataTypeHint("RAW") modelClass: Class[_]
)

DataTypes.of(classOf[User])

桥接到JVM数据类型

Java 类型InputOutputOutput
classXX输入:该类或其子类。输出:子类。
默认
org.apache.flink.types.RowXX代表row类型的结构体
org.apache.flink.table.data.RowDataXX内部数据类型

3.8. 其他数据类型

3.8.1. BOOLEAN

布尔数据类型,值为:TRUEFALSEUNKNOWN

SQL

BOOLEAN

java/scala

DataTypes.BOOLEAN();

桥接到JVM数据类型

Java 类型InputOutputOutput
java.lang.BooleanXX默认
booleanX(X)类型为非空null时才会输出

3.8.2. RAW

任意序列化类型的数据类型。这种类型是表生态系统中的黑盒,仅在边缘处进行反序列化。

该类型是对SQL标准的扩展。

SQL

RAW('class', 'snapshot')

java/scala

DataTypes.RAW(class,serializer);
DataTypes.RAW(class);

桥接到JVM数据类型

Java 类型InputOutputOutput
classXX默认。输入:原始类或子类。输出:子类
byte[]X
org.apache.flink.table.data.RawValueDataXX内部数据结构

SQL/Java/Scala

该类型可以使用RAW('class', 'snapshot')声明,其中class是原始类,snapshot是Base64编码的序列化的TypeSerializerSnapshot
通常,类型字符串不是直接声明的,而是在持久化类型时生成的。

在API中,RAW类型可以通过直接提供Class + TypeSerializer或者通过传递Class并让框架从中提取Class + TypeSerializer来声明。

3.8.3. NULL

表示非类型NULL值的数据类型。

NULL类型是对SQL标准的扩展。NULL类型除了null以外没有其他值,因此,它可以被强制转换为任何可为空的类型,类似于JVM语义。

这种类型有助于在API调用中表示未知类型,这些调用使用NULL字面量,并桥接到JSON或Avro等格式,这些格式也定义了这种类型。

这种类型在实践中不是很有用,这里只是为了完整性而提到它。

SQL

NULL

java/scala

DataTypes.NULL();

桥接到JVM数据类型

Java 类型InputOutputOutput
java.lang.ObjectXX默认
任何类(X)任何非原始类型

4. 数据类型转换CAST

Flink Table APISQL 可以将定义的输入类型转化为目标类型,不管输入值是什么,有些转化操作都会成功,但是有些转化会在运行时失败,比如无法为目标类型创建一个正确的值。
举例:通常来说,可以将一个 INT 值转化为 STRING,但是并不是什么时候都可以将 INT 值转化为 STRING

在计划期间,查询校验器在遇到校验异常时拒绝无效类型对的查询,比如尝试将 TIMESTAMP 转化为 INTERVAL 类型。查询校验器会接受可能在运行时失败的有效类型对,但是要求用户正确的处理运行失败。

Flink Table API SQL 中,转化可以使用以下两个内建函数之一来执行:

  • CAST:SQL 标准定义的常规转化函数,该函数会在转化不可靠或者是提供的输入无效时造成任务失败。类型推断将会保留输入类型的可空性(NULL)。
  • TRY_CAST:常规转换函数的扩展函数,在转换操作失败时返回 NULL 值,该函数的返回类型一直保持可空性(NULL)。

比如:

CAST('42' AS INT) --- 返回 INT NOT NULL 类型的 42
CAST(NULL AS VARCHAR) --- 返回 VARCHAR 类型的 NULL
CAST('non-number' AS INT) --- 抛出异常,并且将任务运行失败

TRY_CAST('42' AS INT) --- 返回 INT 类型的 42
TRY_CAST(NULL AS VARCHAR) --- 返回 VARCHAR 类型的 NULL
TRY_CAST('non-number' AS INT) --- 返回 INT 类型的 NULL
COALESCE(TRY_CAST('non-number' AS INT), 0) --- 返回 INT NOT NULL 类型的 0

可空性解释:在flink-1.15.x版本之前,如果你在 SQL 中使用了 ifcase when 表达式,在满足条件时,你想让结果为 NULL,此时直接写 NULL ,是无法运行的。
但在 flink-1.15.x 中,可以使用新版的转化函数,将 NULL 值转化为对应字段的类型,以此来使用 NULL

下面的表格展示了支持的可转化类型对,“Y”表示支持,“!”表示失败,“N”表示还不支持。

Input\TargetCHAR¹/VARCHAR¹/STRINGBINARY¹/VARBINARY¹/BYTESBOOLEANDECIMALTINYINTSMALLINTINTEGERBIGINTFLOATDOUBLEDATETIMETIMESTAMPTIMESTAMP_LTZINTERVALARRAYMULTISETMAPROWSTRUCTUREDRAW
CHAR/VARCHAR/STRINGY!!!!!!!!!!!!!NNNNNNN
BINARY/VARBINARY/BYTESYYNNNNNNNNNNNNNNNNNNN
BOOLEANYNYYYYYYYYNNNNNNNNNNN
DECIMALYNNYYYYYYYNNNNNNNNNNN
TINYINTYNYYYYYYYYNNNNNNNNN
SMALLINTYNYYYYYYYYNNNNNNNNN
INTEGERYNYYYYYYYYNNY⁵NNNNNN
BIGINTYNYYYYYYYYNNY⁶NNNNNN
FLOATYNNYYYYYYYNNNNNNNNNNN
DOUBLEYNNYYYYYYYNNNNNNNNNNN
DATEYNNNNNNNNNYNYYNNNNNNN
TIMEYNNNNNNNNNNYYYNNNNNNN
TIMESTAMPYNNNNNNNNNYYYYNNNNNNN
TIMESTAMP_LTZYNNNNNNNNNYYYYNNNNNNN
INTERVALYNNNNNY⁵Y⁶NNNNNNYNNNNNN
ARRAYYNNNNNNNNNNNNNNNNNNN
MULTISETYNNNNNNNNNNNNNNNNNNN
MAPYNNNNNNNNNNNNNNNNNNN
ROWYNNNNNNNNNNNNNNNNNNN
STRUCTUREDYNNNNNNNNNNNNNNNNNNN
RAWY!NNNNNNNNNNNNNNNNNNY⁴

注(下面这些数字对应表中的右上角数字):

  1. 所有转化为固定或可变长度的类型,都会根据类型定义对结果值进行截取或使用空格填充。
  2. 必须使用 TO_TIMESTAMP 和 TO_TIMESTAMP_LTZ ,而不是 CAST/TRY_CAST。
  3. 如果子类型对支持,则支持,如果子类型对不支持,则失败。
  4. 如果 RAW 类和序列化类相等,则支持。
  5. 如果 INTERVAL 在 MONTH TO YEAR 范围内,则支持。
  6. 如果 INTERVAL 在 DAY TO TIME 范围内,则支持。

另外,不管是使用 CAST 还是 TRY_CAST 函数,转化 NULL 都只会返回 NULL 值。

4.1. 旧版转化

指1.15.x之前的版本。

可以设置 table.exec.legacy-cast-behaviourenabled 来使用 Flink-1.15 之前的转化操作,在 Flink-1.15 中,该设置默认禁用。

开启该参数,将会导致:

  1. 转化为 CHAR/VARCHAR/BINARY/VARBINARY 类型时,将不会对结果值进行截取或填充。
  2. CAST 永远不会失败,而是返回 NULL ,就像是 TRY_CAST 的行为,但是不会参考正确的类型。
  3. 转化一些值为 CHAR/VARCHAR/STRING 类型时,将会产生稍微不同的结果。

我们不推荐开启该参数,并且强烈建议新的项目保持禁用该参数,并且使用新的转化行为。该参数将会在下个 flink 版本中移除。

5. 数据类型提取

在API中,Flink会尝试使用反射从类信息中自动提取数据类型,以避免重复的手动指定工作。但是,反射式提取数据类型并不总是成功的,因为可能缺少逻辑信息。
因此,可能需要在类或字段声明附近添加额外的信息,以支持提取逻辑。

下表列出了可以隐式映射到数据类型而不需要进一步添加额外信息的类。

如果你想使用Scala类,建议使用装箱类型(例如java.lang.Integer),而不是Scala的原生类。
Scala的原生类(例如IntDouble)被编译为JVM原生类(例如Int / Double),结果如下表所示,增加NOT NULL语义。

此外,Scala原生类的泛型(例如java.util.Map[Int, Double])在编译过程中会被擦除,最后结果类似于:java.util.Map[java.lang.Object, java.lang.Object]

Class数据类型
java.lang.StringSTRING
java.lang.BooleanBOOLEAN
booleanBOOLEAN NOT NULL
java.lang.ByteTINYINT
byteTINYINT NOT NULL
java.lang.ShortSMALLINT
shortSMALLINT NOT NULL
java.lang.IntegerINT
intINT NOT NULL
java.lang.LongBIGINT
longBIGINT NOT NULL
java.lang.FloatFLOAT
java.lang.FloatFLOAT
floatFLOAT NOT NULL
java.lang.DoubleDOUBLE
doubleDOUBLE NOT NULL
java.sql.DateDATE
java.time.LocalDateDATE
java.sql.TimeTIME(0)
java.time.LocalTimeTIME(9)
java.sql.TimestampTIMESTAMP(9)
java.time.LocalDateTimeTIMESTAMP(9)
java.time.OffsetDateTimeTIMESTAMP(9) WITH TIME ZONE
java.time.InstantTIMESTAMP_LTZ(9)
java.time.DurationINTERVAL SECOND(9)
java.time.PeriodINTERVAL YEAR(4) TO MONTH
byte[]BYTES
T[]ARRAY<T>
java.util.Map<K, V>MAP<K, V>
structured type T匿名 structured type T

本章节中提到的其他JVM桥接类需要 @DataTypeHint 注解。

数据类型提示可以参数化或替换单个函数参数和返回类型、结构化类或结构化类的字段的默认提取逻辑。开发者可以通过声明 @DataTypeHint 注解来选择应该在多大程度上修改默认提取逻辑。

@DataTypeHint 注解提供了一组可选的提示参数。下面的示例显示了其中一些参数。更多信息可以在注解类的文档中找到。

java

import org.apache.flink.table.annotation.DataTypeHint;

class User {
    //将java.lang.Integer类转化为 INT 数据类型
    public @DataTypeHint("INT")
    Object o1;
    // 使用显式转换类定义毫秒精度的TIMESTAMP数据类型
    public @DataTypeHint(value = "TIMESTAMP(3)", bridgedTo = java.sql.Timestamp.class)
    Object o2;
    //强制使用RAW类型来丰富类型提取
    public @DataTypeHint("RAW")
    Class<?> modelClass;
    // 定义所有出现的java.math.BigDecimal(也包括嵌套字段)将被提取为DECIMAL(12, 2)
    public @DataTypeHint(defaultDecimalPrecision = 12, defaultDecimalScale = 2)
    AccountStatement stmt;
    // 定义每当类型不能映射到数据类型时,不要抛出异常,而应始终将其视为RAW类型
    public @DataTypeHint(allowRawGlobally = HintFlag.TRUE)
    ComplexModel model;
}

scala

import org.apache.flink.table.annotation.DataTypeHint

class User {

    //将java.lang.Integer类转化为 INT 数据类型
    @DataTypeHint("INT")
    var o: AnyRef

    // 使用显式转换类定义毫秒精度的TIMESTAMP数据类型
    @DataTypeHint(value = "TIMESTAMP(3)", bridgedTo = java.sql.Timestamp.class)
    var o: AnyRef

    //强制使用RAW类型来丰富类型提取
    @DataTypeHint("RAW")
    var modelClass: Class[_]

    // 定义所有出现的java.math.BigDecimal(也包括嵌套字段)将被提取为DECIMAL(12, 2)
    @DataTypeHint(defaultDecimalPrecision = 12, defaultDecimalScale = 2)
    var stmt: AccountStatement

    // 定义每当类型不能映射到数据类型时,不要抛出异常,而应始终将其视为RAW类型
    @DataTypeHint(allowRawGlobally = HintFlag.TRUE)
    var model: ComplexModel
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

第一片心意

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值