【flink 床头书系列】data Types 数据类型词典
FLINK Data Types 数据类型词典
Flink SQL提供了丰富的本地数据类型供用户使用。
Data Type 数据类型
数据类型描述了表生态系统中值的逻辑类型。它可用于声明操作的输入和/或输出类型。
Flink的数据类型类似于SQL标准的数据类型术语,但还包含有关值的可空性的信息,以便有效处理标量表达式。
以下是数据类型的示例:
- INT
- INT NOT NULL
- INTERVAL DAY TO SECOND(3)
- ROW<myField ARRAY, myOtherField TIMESTAMP(3)>
下面是所有预定义数据类型的列表。
Table API中的数据类型
Java/Scala
在基于JVM的API中,用户在Table API中使用org.apache.flink.table.types.DataType的实例,或者在定义连接器、目录或用户定义函数时使用。
DataType实例有两个职责:
- 声明一个逻辑类型,它不会暗示传输或存储的具体物理表示,但定义了基于JVM/Python语言和表生态系统之间的边界。
- 可选:向规划器提供有关数据物理表示的提示,在与其他API的边缘处很有用。
对于基于JVM的语言,所有预定义数据类型都可以在org.apache.flink.table.api.DataTypes中找到。
Python
Java
建议在表程序中添加星号导入以获得流畅的API:
from org.apache.flink.table.api.DataTypes import *
然后,可以使用以下语法声明数据类型:
t = INTERVAL(DAY(), SECOND(3))
Scala
Python
物理提示
物理提示在表生态系统的边缘处需要,在这些边缘处需要编程特定的数据类型,而SQL类型系统无法满足需求。提示指示实现期望的数据格式。
例如,数据源可以使用java.sql.Timestamp类表示逻辑TIMESTAMP的值,而不是使用默认的java.time.LocalDateTime。有了这个信息,运行时可以将生成的类转换为其内部数据格式。相反,数据接收器可以声明它从运行时消耗的数据格式。
以下是如何声明桥接转换类的示例:
Java
告诉运行时不要生成或消耗java.time.LocalDateTime实例,而是使用java.sql.Timestamp:
DataType t = DataTypes.TIMESTAMP(3).bridgedTo(java.sql.Timestamp.class);
告诉运行时不要生成或消耗装箱整数数组,而是使用原始整数数组:
DataType t = DataTypes.ARRAY(DataTypes.INT().notNull()).bridgedTo(int[].class);
Scala
请注意,通常仅在扩展API时才需要物理提示。预定义的源/接收器/函数的用户无需定义此类提示。在表程序中(例如,field.cast(TIMESTAMP(3).bridgedTo(Timestamp.class))),忽略物理提示。
数据类型列表
本节列出了所有预定义的数据类型。
Java/Scala
对于基于JVM的Table API,这些类型也在org.apache.flink.table.api.DataTypes中可用。
Python
默认规划器支持以下一组SQL类型:
| 数据类型 | 数据类型备注 |
|---|---|
| CHAR | |
| VARCHAR | |
| STRING | |
| BOOLEAN | |
| BINARY | |
| VARBINARY | |
| BYTES | |
| DECIMAL | 支持固定精度和比例 |
| TINYINT | |
| SMALLINT | |
| INTEGER | |
| BIGINT | |
| FLOAT | |
| DOUBLE | |
| DATE | |
| TIME | 仅支持0位精度 |
| TIMESTAMP | |
| TIMESTAMP_LTZ | 仅支持月和秒的间隔 |
| ARRAY | |
| MULTISET | |
| MAP | |
| ROW | |
| RAW | |
| Structured types | 仅在用户定义函数中暴露 |
字符串类型
CHAR
CHAR是一个定长字符字符串的数据类型。
声明方式:
- SQL:
CHAR - Java/Scala:
- Python:
可以使用CHAR(n)声明该类型,其中n是代码点的数量。n必须介于1和2,147,483,647之间(包括两者)。如果未指定长度,则n等于1。
VARCHAR / STRING
VARCHAR / STRING是可变长度字符字符串的数据类型。
声明方式:
- SQL:
VARCHAR,VARCHAR(n),STRING - Java/Scala:
- Python:
可以使用VARCHAR(n)声明该类型,其中n是最大代码点数。n必须介于1和2,147,483,647之间(包括两者)。如果未指定长度,则n等于1。
STRING是VARCHAR(2147483647)的同义词。
二进制字符串类型
BINARY
BINARY是定长二进制字符串(字节序列)的数据类型。
声明方式:
- SQL:
BINARY,BINARY(n) - Java/Scala:
- Python:
可以使用BINARY(n)声明该类型,其中n是字节数。n必须介于1和2,147,483,647之间(包括两者)。如果未指定长度,则n等于1。
VARBINARY / BYTES
VARBINARY / BYTES是可变长度二进制字符串(字节序列)的数据类型。
声明方式:
- SQL:
VARBINARY,VARBINARY(n),BYTES - Java/Scala:
- Python:
可以使用VARBINARY(n)声明该类型,其中n是最大字节数。n必须介于1和2,147,483,647之间(包括两者)。如果未指定长度,则n等于1。
BYTES是VARBINARY(2147483647)的同义词。
精确数值类型
DECIMAL
DECIMAL是具有固定精度和比例的十进制数的数据类型。
声明方式:
- SQL:
DECIMAL,DECIMAL(p),DECIMAL(p, s),DEC,DEC(p),DEC(p, s),NUMERIC,NUMERIC(p),NUMERIC(p, s) - Java/Scala:
- Python:
可以使用DECIMAL(p, s)声明该类型,其中p是数字中的位数(精度),s是小数点右侧的数字位数(比例)。p必须介于1和38之间(包括两者)。s必须介于0和p之间(包括两者)。p的默认值为10,s的默认值为0。
NUMERIC(p, s)和DEC(p, s)是该类型的同义词。
TINYINT
TINYINT是一个1字节有符号整数,取值范围为-128到127。
声明方式:
- SQL:
TINYINT - Java/Scala:
- Python:
SMALLINT
SMALLINT是一个2字节有符号整数,取值范围为-32,768到32,767。
声明方式:
- SQL:
SMALLINT - Java/Scala:
- Python:
INT
INT是一个4字节有符号整数,取值范围为-2,147,483,648到2,147,483,647。
声明方式:
- SQL:
INT,INTEGER - Java/Scala:
- Python:
INTEGER是该类型的同义词。
BIGINT
BIGINT是一个8字节有符号整数,取值范围为-9,223,372,036,854,775,808到9,223,372,036,854,775,807。
声明方式:
- SQL:
BIGINT - Java/Scala:
- Python:
近似数值类型
FLOAT
FLOAT是一个4字节单精度浮点数。
与SQL标准相比,该类型不接受参数。
声明方式:
- SQL:
FLOAT - Java/Scala:
- Python:
DOUBLE
DOUBLE是一个8字节双精度浮点数。
声明方式:
- SQL:
DOUBLE,DOUBLE PRECISION - Java/Scala:
- Python:
DOUBLE PRECISION是该类型的同义词。
日期和时间类型
DATE
DATE是由年-月-日组成的日期数据类型,取值范围从0000-01-01到9999-12-31。
与SQL标准相比,范围从0000年开始。
声明方式:
- SQL:
DATE - Java/Scala:
- Python:
TIME
TIME是一个没有时区的时间数据类型,由小时:分钟:秒[.小数]组成,具有高达纳秒级别的精度,取值范围从00:00:00.000000000到23:59:59.999999999。
SQL/Java/Scala
与SQL标准相比,不支持闰秒(23:59:60和23:59:61),因为其语义更接近于java.time.LocalTime。不提供带时区的时间。
Python
声明方式:
- SQL:
TIME,TIME(p) - Java/Scala:
- Python:
可以使用TIME(p)声明该类型,其中p是分数秒的位数(精度)。p必须介于0和9之间(包括两者)。如果未指定精度,则p等于0。
TIMESTAMP
TIMESTAMP是一个没有时区的时间戳数据类型,由年-月-日 时:分:秒[.小数]组成,具有高达纳秒级别的精度,取值范围从0000-01-01 00:00:00.000000000到9999-12-31 23:59:59.999999999。
SQL/Java/Scala
Python
声明方式:
- SQL:
TIMESTAMP,TIMESTAMP(p),TIMESTAMP WITHOUT TIME ZONE,TIMESTAMP(p) WITHOUT TIME ZONE - Java/Scala:
- Python:
可以使用TIMESTAMP(p)声明该类型,其中p是分数秒的位数(精度)。p必须介于0和9之间(包括两者)。如果未指定精度,则p等于6。
TIMESTAMP§ WITHOUT TIME ZONE是该类型的同义词。
TIMESTAMP WITH TIME ZONE
TIMESTAMP WITH TIME ZONE是一个带有时区的时间戳数据类型,由年-月-日 时:分:秒[.小数] 时区组成,具有高达纳秒级别的精度,取值范围从0000-01-01 00:00:00.000000000 +14:59到9999-12-31 23:59:59.999999999 -14:59。
SQL/Java/Scala
Python
与TIMESTAMP_LTZ相比,每个数据存储都会物理存储时区偏移信息。它用于每个计算、可视化或与外部系统的通信。
声明方式:
- SQL:
TIMESTAMP WITH TIME ZONE,TIMESTAMP(p) WITH TIME ZONE - Java/Scala:
- Python:
TIMESTAMP_LTZ
TIMESTAMP_LTZ是一个带有本地时区的时间戳数据类型,它包含年-月-日 时:分:秒[.小数] 时区的信息,具有高达纳秒级别的精度。其取值范围从0000-01-01 00:00:00.000000000 +14:59到9999-12-31 23:59:59.999999999 -14:59。
在SQL/Java/Scala中,不支持闰秒(23:59:60和23:59:61),因为该类型的语义更接近于java.time.OffsetDateTime。
与TIMESTAMP WITH TIME ZONE相比,该类型不会在每个数据中物理存储时区偏移信息。相反,该类型在表生态系统的边缘处假设了以UTC时区的java.time.Instant语义。每个数据根据当前会话配置的本地时区进行计算和可视化解释。
在Python中,该类型填补了无时区和强制时区的时间戳类型之间的差距,允许根据配置的会话时区解释UTC时间戳。
声明方式如下:
SQL:
TIMESTAMP_LTZTIMESTAMP_LTZ(p)TIMESTAMP WITH LOCAL TIME ZONETIMESTAMP(p) WITH LOCAL TIME ZONE
Java/Scala:
- 可使用
TIMESTAMP_LTZ(p)声明该类型,其中p是小数位数(精度)的数字。p的值必须介于0和9之间(包括0和9)。如果未指定精度,则p默认为6。 TIMESTAMP(p) WITH LOCAL TIME ZONE是该类型的同义词。
Python:
- 可以使用
TIMESTAMP_LTZ(p)声明该类型,其中p是小数位数(精度)的数字。p的值必须介于0和9之间(包括0和9)。如果未指定精度,则p默认为6。 TIMESTAMP(p) WITH LOCAL TIME ZONE是该类型的同义词。
INTERVAL YEAR TO MONTH是一组年-月间隔类型的数据类型。该类型需要根据以下分辨率之一进行参数化:
- 年间隔
- 年到月间隔
- 月间隔
年-月间隔由+年-月组成,取值范围从-9999-11到+9999-11。对于所有类型的分辨率,值的表示方式相同。例如,一个月间隔为50始终以年-月间隔格式表示(具有默认年精度):+04-02。
声明方式如下:
SQL:
INTERVAL YEARINTERVAL YEAR(p)INTERVAL YEAR(p) TO MONTHINTERVAL MONTH
Java/Scala:
- 可以使用上述组合来声明该类型,其中p是年份(年精度)的位数。p的值必须介于1和4之间(包括1和4)。如果未指定年份精度,则p默认为2。
Python:
- 可以使用上述组合来声明该类型,其中p是年份(年精度)的位数。p的值必须介于1和4之间(包括1和4)。如果未指定年份精度,则p默认为2。
INTERVAL DAY TO SECOND是一组天-时间间隔类型的数据类型。该类型需要根据以下分辨率之一进行参数化,并且可以具有高达纳秒级别的精度:
- 天间隔
- 天到小时间隔
- 天到分钟间隔
- 天到秒间隔
- 小时间隔
- 小时到分钟间隔
- 小时到秒间隔
- 分钟间隔
- 分钟到秒间隔
- 秒间隔
天-时间间隔由+天 时:分:秒.小数组成,取值范围从-999999 23:59:59.999999999到+999999 23:59:59.999999999。对于所有类型的分辨率,值的表示方式相同。例如,一个秒间隔为70始终以天-秒间隔格式表示(具有默认精度):+00 00:01:10.000000。
声明方式如下:
SQL:
INTERVAL DAYINTERVAL DAY(p1)INTERVAL DAY(p1) TO HOURINTERVAL DAY(p1) TO MINUTEINTERVAL DAY(p1) TO SECOND(p2)INTERVAL HOURINTERVAL HOUR TO MINUTEINTERVAL HOUR TO SECOND(p2)INTERVAL MINUTEINTERVAL MINUTE TO SECOND(p2)INTERVAL SECONDINTERVAL SECOND(p2)
Java/Scala:
- 可以使用上述组合来声明该类型,其中p1是天数(天精度)的位数,p2是小数位数(小数精度)的位数。p1的值必须介于1和6之间(包括1和6),p2的值必须介于0和9之间(包括0和9)。如果未指定p1,则默认为2。如果未指定p2,则默认为6。
Python:
- 可以使用上述组合来声明该类型,其中p1是天数(天精度)的位数,p2是小数位数(小数精度)的位数。p1的值必须介于1和6之间(包括1和6),p2的值必须介于0和9之间(包括0和9)。如果未指定p1,则默认为2。如果未指定p2,则默认为6。
结构化数据类型
ARRAY
ARRAY是一个由相同子类型的元素组成的数组数据类型。
与SQL标准相比,数组的最大基数不能指定,而是固定为2,147,483,647。而且,任何有效的类型都可以作为子类型。
声明方式如下:
SQL:
ARRAY<t>t ARRAY
Java/Scala:
- 可以使用
ARRAY<t>来声明该类型,其中t是包含元素的数据类型。 t ARRAY是更接近SQL标准的同义词。例如,INT ARRAY等同于ARRAY<INT>。
Python:
- 可以使用
ARRAY<t>来声明该类型,其中t是包含元素的数据类型。 t ARRAY是更接近SQL标准的同义词。例如,INT ARRAY等同于ARRAY<INT>。
MAP
MAP是一种将键(包括NULL)映射到值(包括NULL)的关联数组的数据类型。一个map不能包含重复的键;每个键最多可以映射到一个值。
元素类型没有限制;确保唯一性是用户的责任。
这种map类型是对SQL标准的扩展。
声明方式如下:
SQL:
MAP<kt, vt>
Java/Scala:
- 可以使用
MAP<kt, vt>来声明该类型,其中kt是键元素的数据类型,vt是值元素的数据类型。
Python:
- 可以使用
MAP<kt, vt>来声明该类型,其中kt是键元素的数据类型,vt是值元素的数据类型。
MULTISET
MULTISET是一种多集合(bag)的数据类型。与集合不同,它允许每个元素有多个实例,并具有共同的子类型。每个唯一值(包括NULL)都会映射到某个重复度。
元素类型没有限制;确保唯一性是用户的责任。
声明方式如下:
SQL:
MULTISET<t>t MULTISET
Java/Scala:
- 可以使用
MULTISET<t>来声明该类型,其中t是包含元素的数据类型。 t MULTISET是更接近SQL标准的同义词。例如,INT MULTISET等同于MULTISET<INT>。
Python:
- 可以使用
MULTISET<t>来声明该类型,其中t是包含元素的数据类型。 t MULTISET是更接近SQL标准的同义词。例如,INT MULTISET等同于MULTISET<INT>。
ROW
ROW是一系列字段的数据类型。
一个字段由字段名称、字段类型和可选的描述组成。表行的最具体类型是行类型。在这种情况下,行的每个列对应于与列相同位置的行类型的字段。
与SQL标准相比,可选的字段描述简化了处理复杂结构的方式。
行类型类似于其他不符合标准的框架中的STRUCT类型。
声明方式如下:
SQL:
ROW<n0 t0, n1 t1, ...>ROW<n0 t0 'd0', n1 t1 'd1', ...>
Java/Scala:
- 可以使用
ROW<n0 t0 'd0', n1 t1 'd1', ...>来声明该类型,其中n是字段的唯一名称,t是字段的逻辑类型,d是字段的描述。 ROW(...)是更接近SQL标准的同义词。例如,ROW(myField INT, myOtherField BOOLEAN)等同于ROW<myField INT, myOtherField BOOLEAN>。
Python:
- 可以使用
ROW<n0 t0 'd0', n1 t1 'd1', ...>来声明该类型,其中n是字段的唯一名称,t是字段的逻辑类型,d是字段的描述。 ROW(...)是更接近SQL标准的同义词。例如,ROW(myField INT, myOtherField BOOLEAN)等同于ROW<myField INT, myOtherField BOOLEAN>。
自定义数据类型
Java/Scala:
注意:用户定义的数据类型目前(截至Flink 1.11版本)尚不完全支持。它们目前只能作为未注册的结构化类型在函数的参数和返回类型中使用。
结构化类型类似于面向对象编程语言中的对象。它包含零个、一个或多个属性。每个属性由名称和类型组成。
有两种类型的结构化类型:
- 存储在目录中并由目录标识符(例如cat.db.MyType)标识的类型,这些类型与SQL标准定义的结构化类型相同。
- 匿名定义的、未注册的类型(通常是通过反射提取得到的),这些类型由实现类(例如com.myorg.model.MyType)标识。在以编程方式定义表程序时,可以重用现有的JVM类而无需手动定义数据类型的模式。
已注册的结构化类型:
目前不支持已注册的结构化类型,因此无法将其存储在目录中或在CREATE TABLE DDL中引用。
未注册的结构化类型:
可以使用普通的POJO(Plain Old Java Objects)通过自动反射提取来创建未注册的结构化类型。
结构化类型的实现类必须满足以下要求:
- 该类必须是全局可访问的,即必须声明为public、static且非抽象的。
- 该类必须提供一个零参数的默认构造函数或者一个全构造函数,该构造函数会分配所有字段。
- 类的所有字段必须是可读的,可以通过公共声明或遵循常见的编码风格(例如getField()、isField()、field())的getter方法来访问。
- 类的所有字段必须是可写的,可以通过公共声明、完全赋值的构造函数或者遵循常见的编码风格(例如setField(…)、field(…))的setter方法进行修改。
- 所有字段都必须映射到某个数据类型,可以通过自动反射提取隐式地进行映射,也可以使用@DataTypeHint注解显式指定。
- 静态或瞬态字段将被忽略。
- 反射提取支持任意嵌套的字段,只要字段类型不会(直接或间接地)引用自身。
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);
JVM类型的桥接
| Java类型 | 输入 | 输出 | 备注 |
|---|---|---|---|
| class | X | X | 原始类或其子类(用于输入)或超类(用于输出)。默认 |
| org.apache.flink.types.Row | X | X | 将结构化类型表示为行。 |
| org.apache.flink.table.data.RowData | X | X | 内部数据结构。 |
Python:
暂不支持自定义数据类型。
其他数据类型
BOOLEAN
BOOLEAN是一个具有(可能)三值逻辑(TRUE、FALSE和UNKNOWN)的布尔类型。
声明方式如下:
SQL:
BOOLEAN
Java/Scala:
Python:
RAW
RAW是一个任意序列化类型的数据类型。该类型在表生态系统中是一个黑盒子,在边缘处只进行反序列化。
原始类型是对SQL标准的扩展。
声明方式如下:
SQL:
RAW('class', 'snapshot')
Java/Scala:
Python:
可以使用RAW('class', 'snapshot')来声明该类型,其中class是原始类,snapshot是以Base64编码的序列化TypeSerializerSnapshot。通常情况下,不直接声明类型字符串,而是在持久化类型时生成它。
在API中,可以通过直接提供Class + TypeSerializer或者传递Class来声明RAW类型,并让框架从中提取Class + TypeSerializer。
NULL
NULL是表示无类型NULL值的数据类型。
空类型是对SQL标准的扩展。空类型除了NULL之外没有其他值,因此它可以转换为任何可为空的类型,类似于JVM的语义。
这种类型有助于在使用NULL字面量的API调用中表示未知类型,并且还有助于与定义了这种类型的格式(例如JSON或Avro)进行桥接。
从实际上讲,这种类型在实践中并不常用,只是为了完整性而提到。
声明方式如下:
SQL:
NULL
Java/Scala:
Python:
Casting
Flink Table API和SQL可以在定义的输入类型和目标类型之间执行类型转换。尽管某些转换操作无论输入值如何都可以成功,但其他一些操作可能在运行时失败(例如,无法创建目标类型的值)。例如,将INT转换为STRING总是可以成功的,但不能将STRING转换为INT。
在规划阶段,查询验证器会拒绝使用无效类型对的查询,并抛出ValidationException异常,例如尝试将TIMESTAMP转换为INTERVAL。验证器接受可能在运行时失败的有效类型对,但要求用户正确处理失败。
在Flink Table API和SQL中,可以使用以下两个内置函数之一执行类型转换:
- CAST:标准SQL定义的常规转换函数。如果转换操作具有错误性质且提供的输入无效,则可能导致作业失败。类型推断将保留输入类型的可空性。
- TRY_CAST:对正常转换函数的扩展,如果转换操作失败,则返回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
下面的矩阵描述了支持的转换对,其中“Y”表示支持,“!”表示有错误性质,“N”表示不支持:
| Input\Target | CHAR/VARCHAR/STRING | BINARY/VARBINARY/BYTES | BOOLEAN | DECIMAL | TINYINT | SMALLINT | INTEGER | BIGINT | FLOAT | DOUBLE | DATE | TIME | TIMESTAMP | TIMESTAMP_LTZ | INTERVAL | ARRAY | MULTISET | MAP | ROW | STRUCTURED | RAW |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CHAR/VARCHAR/STRING | Y | ! | ! | ! | ! | ! | ! | ! | ! | ! | ! | ! | N | N | N | N | N | N | N | N | N |
| BINARY/VARBINARY/BYTES | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
| BOOLEAN | Y | N | Y | Y | Y | Y | Y | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N |
| DECIMAL | Y | N | N | Y | Y | Y | Y | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N |
| TINYINT | Y | N | Y | Y | Y | Y | Y | Y | Y | N | N | N² | N² | N | N | N | N | N | N | N | N |
| SMALLINT | Y | N | Y | Y | Y | Y | Y | Y | Y | N | N | N² | N² | N | N | N | N | N | N | N | N |
| INTEGER | Y | N | Y | Y | Y | Y | Y | Y | Y | N | N | N² | N² | Y⁵ | N | N | N | N | N | N | N |
| BIGINT | Y | N | Y | Y | Y | Y | Y | Y | Y | N | N | N² | N² | Y⁶ | N | N | N | N | N | N | N |
| FLOAT | Y | N | N | Y | Y | Y | Y | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N |
| DOUBLE | Y | N | N | Y | Y | Y | Y | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N |
| DATE | Y | N | N | N | N | N | N | N | N | Y | N | Y | Y | N | N | N | N | N | N | N | N |
| TIME | Y | N | N | N | N | N | N | N | N | N | Y | Y | Y | N | N | N | N | N | N | N | N |
| TIMESTAMP | Y | N | N | N | N | N | N | N | N | N | Y | Y | Y | Y | N | N | N | N | N | N | N |
| TIMESTAMP_LTZ | Y | N | N | N | N | N | N | N | N | N | Y | Y | Y | Y | N | N | N | N | N | N | N |
| INTERVAL | Y | N | N | N | N | Y⁵ | Y⁶ | N | N | N | N | N | N | Y | N | N | N | N | N | N | N |
| ARRAY | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | !³ | N | N | N | N | N | N |
| MULTISET | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | !³ | N | N | N | N | N |
| MAP | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | !³ | N | N | N | N |
| ROW | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | !³ | N | N |
| STRUCTURED | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | !³ | N |
| RAW | Y | ! | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | Y⁴ |
注意:
- 所有转换为定长或可变长类型的操作都会根据类型定义进行修剪和填充。
- TO_TIMESTAMP和TO_TIMESTAMP_LTZ必须用于代替CAST/TRY_CAST。
- 支持的转换取决于子类型对是否支持。如果子类型对是错误性质的,则有错误性质。
- 如果将NULL值进行转换,无论使用的函数是CAST还是TRY_CAST,结果始终为NULL。
Legacy casting
在 Flink 1.15 之前,可以通过将 table.exec.legacy-cast-behaviour 设置为 enabled 来启用旧版本的类型转换行为。但在 Flink 1.15 中,默认情况下该标志被禁用。
具体而言,这将导致以下行为:
- 对于转换为 CHAR/VARCHAR/BINARY/VARBINARY,禁用修剪/填充操作。
- CAST 操作永远不会失败,而是返回 NULL,类似于 TRY_CAST,但不会推断正确的类型。
- 对于某些转换为 CHAR/VARCHAR/STRING 的格式化操作,结果可能略有不同。
我们不建议使用此标志,并强烈建议新项目保持禁用该标志并使用新的类型转换行为。该标志将在未来的 Flink 版本中被移除。
数据类型提取
Java/Scala:
在API的许多位置,Flink尝试使用反射从类信息中自动提取数据类型,以避免重复的手动模式工作。但是,通过反射提取数据类型并不总是成功的,因为可能缺少逻辑信息。因此,可能需要在类或字段声明附近添加额外的信息来支持提取逻辑。
下表列出了可以在不需要进一步信息的情况下隐式映射到数据类型的类。
如果要在Scala中实现类,建议使用装箱类型(例如java.lang.Integer)而不是Scala的原始类型。Scala的原始类型(例如Int或Double)会被编译为JVM的原始类型(例如int/double),并导致如下表中所示的NOT NULL语义。此外,在泛型中使用的Scala原始类型(例如java.util.Map[Int, Double])在编译期间会被擦除,并导致类似于java.util.Map[java.lang.Object, java.lang.Object]的类信息。
| 类 | 数据类型 |
|---|---|
| java.lang.String | STRING |
| java.lang.Boolean | BOOLEAN |
| boolean | BOOLEAN NOT NULL |
| java.lang.Byte | TINYINT |
| byte | TINYINT NOT NULL |
| java.lang.Short | SMALLINT |
| short | SMALLINT NOT NULL |
| java.lang.Integer | INT |
| int | INT NOT NULL |
| java.lang.Long | BIGINT |
| long | BIGINT NOT NULL |
| java.lang.Float | FLOAT |
| float | FLOAT NOT NULL |
| java.lang.Double | DOUBLE |
| double | DOUBLE NOT NULL |
| java.sql.Date | DATE |
| java.time.LocalDate | DATE |
| java.sql.Time | TIME(0) |
| java.time.LocalTime | TIME(9) |
| java.sql.Timestamp | TIMESTAMP(9) |
| java.time.LocalDateTime | TIMESTAMP(9) |
| java.time.OffsetDateTime | TIMESTAMP(9) WITH TIME ZONE |
| java.time.Instant | TIMESTAMP_LTZ(9) |
| java.time.Duration | INTERVAL SECOND(9) |
| java.time.Period | INTERVAL YEAR(4) TO MONTH |
| byte[] | BYTES |
| T[] | ARRAY<T> |
| java.util.Map<K, V> | MAP<K, V> |
| 结构化类型 T | 匿名结构化类型 T |
本文档中提到的其他JVM桥接类需要使用@DataTypeHint注解。
数据类型提示可以参数化或替换单个函数参数和返回类型、结构化类或结构化类的字段的默认提取逻辑。实现者可以通过声明@DataTypeHint注解来选择在多大程度上修改默认提取逻辑。
@DataTypeHint注解提供了一组可选的提示参数。以下示例显示了其中一些参数。更多信息可以在注解类的文档中找到。
Python:
import org.apache.flink.table.annotation.DataTypeHint;
class User {
// 定义一个INT数据类型,使用默认的转换类`java.lang.Integer`
public @DataTypeHint("INT") Object o;
// 定义一个毫秒精度的TIMESTAMP数据类型,并使用显式的转换类
public @DataTypeHint(value = "TIMESTAMP(3)", bridgedTo = java.sql.Timestamp.class) Object o;
// 使用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;
}
更多推荐

所有评论(0)