本文档内容基于,其他版本的整理,请查看本人博客的 flink 专栏其他文章。
Flink SQL有一组丰富的本地数据类型可供用户使用。
数据类型描述表生态系统中值的逻辑类型,它可用于声明操作的输入和/或输出类型。
Flink的数据类型类似于SQL标准的数据类型,但也包含了关于值是否为空的信息,以便有效地处理标量表达式。
数据类型的例子有:
- INT
- INT NOT NULL
- INTERVAL DAY TO SECOND(3)
所有预定义的数据类型在下面列出。
java/scala:
基于 JVM 的用户,在使用 Table API 或者是自定义连接器、catalog、自定义函数时,可以使用 类的实例。
实例有两个职责:
- 声明一个逻辑类型:这并不是定义传输或存储的具体物理表示,但其定义了基于 jvm/Python 语言和表生态系统之间的边界。
- 可选:将数据的物理表示提示给 planner 计划器,这对于其他 API 是非常有用的。
为了流畅的使用 API ,可以在表程序开头添加 语句导入所有的数据类型。
java
scala
2.1.1. 物理提示
基于sql的类型系统末端的表生态系统边缘需要物理提示,并且是编程代码指定的数据类型。提示表示所期望的数据格式。
例如,数据源使用 类来生成逻辑时间戳值,而不是使用 ,后者是默认值。有了这些信息,程序运行时就可以将生成的类转换为它的内部数据格式。同时,sink 也可以声明它从运行时获取到的数据格式。
下面是一些如何声明桥接转换类的例子:
java
scala
注意:通常来说,只有在扩展 API 时才要求物理提示。用户在自定义 sources/sinks/functions 时并不需要定义这些提示。表程序中的提示(比如:)将会被忽略。
该章节会列出所有预定义的数据类型。
java/scala
对于基于 JVM 的 Table API ,在 中的类型都已经可以使用了。
默认的计划器支持下面的SQL类型
java/scala
3.1.1. CHAR
固定长度的 character string。
SQL
java/scala
桥接到JVM数据类型
该类型可以使用声明,其中是字符的数量。的值必须在和之间(前后都包括)。如果没有指定长度,则等于1。
3.1.2. VARCHAR/STRING
可变长度的 character string。
SQL
java/scala
桥接到JVM数据类型
该类型可以使用声明,其中是最大的字符数量。的值必须在和之间(包括两者)。如果没有指定长度,则等于1。
和相同。
BINARY
固定长度的二进制字符串,等同于字节序列。
SQL
java/scala
桥接到JVM数据类型
该类型可以使用声明,其中为字节数。的值必须在和之间(包括两者)。如果没有指定长度,则等于1。
3.2.1. VARBINARY/BYTES
可变长度的二进制字符串,等同于字节序列。
SQL
java/scala
桥接到JVM数据类型
该类型可以使用声明,其中为最大字节数。的值必须在和之间(包括两者)。如果没有指定长度,则等于1。
和相同。
3.3.1. DECIMAL
具有固定精度和比例的小数的数据类型。
SQL
java/scala
桥接到JVM数据类型
该类型可以使用声明,其中是数字(精度)的总位数,是数字(刻度)小数点右边的位数。
的值必须在和之间(包括两者)。的值必须在和之间(包括两者)。的默认值是10。的默认值是0。
、和该类型含义一样。
3.3.2. TINYINT
值从到,1个字节,有符号整数。
SQL
java/scala
桥接到JVM数据类型
3.3.3. SMALLINT
值从到,2个字节,有符号整数。
SQL
java/scala
桥接到JVM数据类型
3.3.4. INT
值从到,4个字节,有符号整数。
SQL
java/scala
桥接到JVM数据类型
INTEGER也表示该类型。
3.3.5. BIGINT
值从到,8个字节,有符号整数。
SQL
java/scala
桥接到JVM数据类型
3.4.1. FLOAT
4个字节的单精度浮点数。
与SQL标准相比,该类型不带参数。
SQL
java/scala
桥接到JVM数据类型
3.4.2. DOUBLE
8字节的双精度浮点数。
SQL
java/scala
桥接到JVM数据类型
也表示该类型。
注意:所有时间类型的精度 p 指的都是秒后面的小数个数。
3.5.1. DATE
日期数据类型为,取值范围为。
与 SQL 标准相比,范围从 0000 年开始。
SQL
java/scala
桥接到JVM数据类型
3.5.2. TIME
无时区的时间数据类型,由组成,精度可达纳秒,值范围从到。
SQL/Java/Scala
与SQL标准相比,该类型不支持闰秒,因为该类型语义更接近。目前不支持带时区的时间。
SQL
java/scala
桥接到JVM数据类型
类型为非空null时才会输出
类型为非空null时才会输出
该类型可以使用声明,其中p是秒后面小数的位数(精度)。P必须有一个介于0和9之间的值(包括两者)。如果没有指定精度,p等于0。
3.5.3. TIMESTAMP
无时区的时间戳数据类型,由组成,精度可达纳秒,值范围从到。
SQL/Java/Scala
与SQL标准相比,该类型不支持闰秒(23:59:60和23:59:61),因为该类型语义更接近。
不支持从 (JVM long类型)转化为该类型,也不支持从该类型转换到 (JVM long类型),因为这种转换需要时区,但是该类型是不受时区限制的。
如果需要使用到时区,则可以使用类型。
SQL
java/scala
桥接到JVM数据类型
该类型可以使用声明,其中p是秒后面小数(精度)的位数。P必须是一个介于0和9之间的值(包括两者)。如果没有指定精度,则p等于6。
也表示该类型。
3.5.4. TIMESTAMP WITH TIME ZONE
有时区的时间戳的数据类型,由组成,精确度可达纳秒,值范围为
到。
与相比,时区偏移信息物理地存储在每个数据中。它被单独用于每一个计算、可视化以及与外部系统通信。
SQL/Java/Scala
与SQL标准相比,该类型不支持闰秒(23:59:60和23:59:61),因为该类型语义更接近。
不支持从 (JVM long类型)转化为该类型,也不支持从该类型转换到 (JVM long类型),因为这种转换需要时区,但是该类型是不受时区限制的。
如果需要使用到时区,则可以使用类型。
SQL
java/scala
桥接到JVM数据类型
3.5.5. TIMESTAMP_LTZ
使用本地时区的时间戳数据类型,由组成,精度可达纳秒,值范围为
到。
SQL/Java/Scala
与SQL标准相比,该类型不支持闰秒(23:59:60和23:59:61),因为该类型语义更接近。
不支持从 (JVM long类型)转化为该类型,也不支持从该类型转换到 (JVM long类型),因为这种转换需要时区,但是该类型是不受时区限制的。
如果需要使用到时区,则可以使用类型。
该类型允许根据配置的会话时区解释UTC时间戳来填补自由时区和强制时区时间戳类型之间的空白。
SQL
java/scala
桥接到JVM数据类型
类型为非空null时才会输出
类型为非空null时才会输出
可以使用声明该类型,其中p是秒后面小数(精度)的位数。P必须是一个介于0和9之间的值(包括两者)。如果没有指定精度,则p等于6。
是该类型的同义词。
3.5.6. INTERVAL YEAR TO MONTH
一组年-月间隔类型的数据类型。
该类型必须参数化为以下解析之一:
- interval of years
- interval of years to months
- interval of months
的间隔由 组成,取值范围为 ~ 。
比如,50个月的间隔以年到月的间隔格式表示为(使用默认的年精度):。
SQL
java/scala
桥接到JVM数据类型
类型为非空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
的间隔由 组成,取值范围为到。
例如,70秒的间隔以天到秒的间隔格式表示(具有默认精度):。
SQL
java/scala
桥接到JVM数据类型
类型为非空null时才会输出
可以使用上面的组合声明该类型,其中是天数(天数精度),是小数秒(小数精度)。的值必须在1到6之间(包括1和6)。的值必须在0到9之间(包括两者)。
如果没有指定p1,默认值为2。如果没有指定p2,默认值为6。
3.6.1. ARRAY
具有相同子类型元素的数组。
与SQL标准相比,不能指定数组的最大基数,而是固定在。此外,支持任何有效类型作为子类型。
SQL
java/scala
桥接到JVM数据类型
该类型可以使用声明,其中是所包含元素的数据类型。
是接近SQL标准的同义词。例如,等价于。
3.6.2. MAP
关联数组的数据类型,将键(包括NULL)映射到值(包括NULL)。不能包含重复的键;每个键最多只能映射到一个值。
元素类型没有限制,需要用户确保数据的唯一性。
类型是对SQL标准的扩展。
SQL
java/scala
其中的和都是类型。
桥接到JVM数据类型
该类型可以使用声明,其中是key元素的数据类型,是value元素的数据类型。
3.6.3. MULTISET
(=bag)数据类型。与不同,它允许集合中的每个元素存在多个实例。每个唯一的值(包括NULL)可以保存多个。
元素类型没有限制,需要用户确保唯一性。
SQL
java/scala
桥接到JVM数据类型
该类型可以使用声明,其中t是所包含元素的数据类型。
是接近SQL标准的同义词。例如,等价于。
3.6.4. ROW
字段序列的数据类型。
字段由字段名、字段类型和可选描述组成。表中数据最特殊的类型就是 row 类型,每列中 row 类型字段中的所有属性位置都和列中的位置一一对应。
与SQL标准相比,可选的字段描述简化了复杂结构的处理。
行类型类似于其他非标准兼容框架中的类型。
SQL
java/scala
为字段名称,为字段类型,为字段描述。
桥接到JVM数据类型
可以使用声明该类型,其中是字段的唯一名称,是字段的逻辑类型,是字段的描述。
是接近SQL标准的同义词。例如,等价于。
目前还不完全支持用户自定义的数据类型。它们目前(从Flink 1.11开始)只在参数和函数返回类型中作为未注册的结构类型。
结构化类型类似于面向对象编程语言中的对象。它包含零个、一个或多个属性。每个属性由名称和类型组成。
有两种结构化类型:
- 存储在中并由标识符标识的类型(如cat.db.MyType)。这些等同于结构化类型的SQL标准定义。
- 匿名定义、未注册的类型(通常通过反射提取),由其实现类(如com.myorg.model.MyType)标识。这些类型在以编程方式定义表程序中很有用。它们允许重用现有的JVM类,而无需再次手动定义数据类型的模式。
注册的结构化类型
目前还不支持注册结构化类型。因此,它们不能存储在中,也不能在中引用。
未注册的结构化类型
可以使用自动反射提取从常规(普通Java对象)创建未注册的结构化类型。
结构化类型的实现类必须满足以下要求:
- 类必须是全局可访问的,这意味着它必须声明为,而不是。
- 类必须提供一个零参数的默认构造函数或一个赋值所有字段的完整参数的构造函数。
- 类的所有字段必须可以通过声明或遵循公共编码风格的(如getField(), isField(), field())方法读取。
- 类的所有字段必须由声明、有完整参数的构造函数或遵循公共编码风格的(如setField(…)、field(…))方法写入。
- 所有字段必须可以通过隐式地反射提取或使用注释显式地映射到数据类型。
- 声明为或的字段将被忽略。
反射提取支持字段的任意嵌套,只要字段类型不传递性地引用自身。
声明的字段类行(例如public int age)必须在受支持的JVM桥接类列表中,例如t 为:或。
对于某些类,需要一个注释来将类映射到具体的数据类型(例如")来为指定固定的精度和比例)。
JAVA
scala
桥接到JVM数据类型
默认
3.8.1. BOOLEAN
布尔数据类型,值为:、或。
SQL
java/scala
桥接到JVM数据类型
3.8.2. RAW
任意序列化类型的数据类型。这种类型是表生态系统中的黑盒,仅在边缘处进行反序列化。
该类型是对SQL标准的扩展。
SQL
java/scala
桥接到JVM数据类型
SQL/Java/Scala
该类型可以使用声明,其中是原始类,是base64编码的序列化的。
通常,类型字符串不是直接声明的,而是在持久化类型时生成的。
在API中,RAW类型可以通过直接提供或者通过传递Class并让框架从中提取来声明。
3.8.3. NULL
表示非类型NULL值的数据类型。
类型是对SQL标准的扩展。类型除了以外没有其他值,因此,它可以被强制转换为任何可为空的类型,类似于JVM语义。
这种类型有助于在API调用中表示未知类型,这些调用使用字面量,并桥接到JSON或Avro等格式,这些格式也定义了这种类型。
这种类型在实践中不是很有用,这里只是为了完整性而提到它。
SQL
java/scala
桥接到JVM数据类型
和 可以将定义的输入类型转化为目标类型,不管输入值是什么,有些转化操作都会成功,但是有些转化会在运行时失败,比如无法为目标类型创建一个正确的值。
举例:通常来说,可以将一个 值转化为 ,但是并不是什么时候都可以将 值转化为 。
在计划期间,查询校验器在遇到校验异常时拒绝无效类型对的查询,比如尝试将 转化为 类型。查询校验器会接受可能在运行时失败的有效类型对,但是要求用户正确的处理运行失败。
在和 中,转化可以使用以下两个内建函数之一来执行:
- CAST:SQL 标准定义的常规转化函数,该函数会在转化不可靠或者是提供的输入无效时造成任务失败。类型推断将会保留输入类型的可空性(NULL)。
- TRY_CAST:常规转换函数的扩展函数,在转换操作失败时返回 NULL 值,该函数的返回类型一直保持可空性(NULL)。
比如:
可空性解释:在版本之前,如果你在 SQL 中使用了 或 表达式,在满足条件时,你想让结果为 ,此时直接写 ,是无法运行的。
但在 中,可以使用新版的转化函数,将 值转化为对应字段的类型,以此来使用 。
下面的表格展示了支持的可转化类型对,“Y”表示支持,“!”表示失败,“N”表示还不支持。
注(下面这些数字对应表中的右上角数字):
- 所有转化为固定或可变长度的类型,都会根据类型定义对结果值进行截取或使用空格填充。
- 必须使用 TO_TIMESTAMP 和 TO_TIMESTAMP_LTZ ,而不是 CAST/TRY_CAST。
- 如果子类型对支持,则支持,如果子类型对不支持,则失败。
- 如果 RAW 类和序列化类相等,则支持。
- 如果 INTERVAL 在 MonTH TO YEAR 范围内,则支持。
- 如果 INTERVAL 在 DAY TO TIME 范围内,则支持。
另外,不管是使用 还是 函数,转化 都只会返回 值。
指1.15.x之前的版本。
可以设置 为 来使用 之前的转化操作,在 中,该设置默认禁用。
开启该参数,将会导致:
- 转化为 类型时,将不会对结果值进行截取或填充。
- 永远不会失败,而是返回 ,就像是 的行为,但是不会参考正确的类型。
- 转化一些值为 类型时,将会产生稍微不同的结果。
我们不推荐开启该参数,并且强烈建议新的项目保持禁用该参数,并且使用新的转化行为。该参数将会在下个 flink 版本中移除。
在API中,Flink会尝试使用反射从类信息中自动提取数据类型,以避免重复的手动指定工作。但是,反射式提取数据类型并不总是成功的,因为可能缺少逻辑信息。
因此,可能需要在类或字段声明附近添加额外的信息,以支持提取逻辑。
下表列出了可以隐式映射到数据类型而不需要进一步添加额外信息的类。
如果你想使用类,建议使用装箱类型(例如),而不是的原生类。
的原生类(例如或e)被编译为JVM原生类(例如 / ),结果如下表所示,增加语义。
此外,原生类的泛型(例如)在编译过程中会被擦除,最后结果类似于:。
本章节中提到的其他JVM桥接类需要 注解。
数据类型提示可以参数化或替换单个函数参数和返回类型、结构化类或结构化类的字段的默认提取逻辑。开发者可以通过声明 注解来选择应该在多大程度上修改默认提取逻辑。
注解提供了一组可选的提示参数。下面的示例显示了其中一些参数。更多信息可以在注解类的文档中找到。
java
scala