Flink(一)1.12.7或1.13.5详细介绍及本地安装部署、验证
Flink(二)1.13.5二种部署方式(Standalone、Standalone HA )、四种提交任务方式(前两种及session和per-job)验证详细步骤
Flink(三)flink重要概念(api分层、角色、执行流程、执行图和编程模型)及dataset、datastream详细示例入门和提交任务至on yarn运行
Flink(四)介绍Flink的流批一体、transformations的18种算子详细介绍、Flink与Kafka的source、sink介绍
Flink(五)source、transformations、sink的详细示例(一)
Flink(五)source、transformations、sink的详细示例(二)-source和transformation示例
Flink(五)source、transformations、sink的详细示例(三)-sink示例
Flink(六)Flink四大基石之Window详解与详细示例(一)
Flink(六)Flink四大基石之Window详解与详细示例(二)
Flink(七)Flink四大基石之Time和WaterMaker详解与详细示例(watermaker基本使用、kafka作为数据源的watermaker使用示例以及超出最大允许延迟数据的接收实现)
Flink(八)Flink四大基石之State概念、使用场景、持久化、批处理的详解与keyed state和operator state、broadcast state使用和详细示例
Flink(九)Flink四大基石之Checkpoint容错机制详解及示例(checkpoint配置、重启策略、手动恢复checkpoint和savepoint)
Flink(十)source、transformations、sink的详细示例(二)-source和transformation示例【补充示例】
Flink(十一)Flink配置flink-conf.yaml详细说明(HA配置、checkpoint、web、安全、zookeeper、historyserver、workers、zoo.cfg)
Flink(十二)Flink source和sink 的 clickhouse 详细示例
Flink(十三)Flink 的table api与sql的基本概念、通用api介绍
Flink(十四)Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性
Flink(十五)Flink 的table api与sql之流式概念-配置时间属性和如何处理更新结果
Flink(十六)Flink 的table api与sql之连接外部系统: 读写外部系统的连接器和格式
Flink(十七)Flink 的table api与sql之Table API: Table API 支持的操作
Flink(十八)Flink 的table api与sql之SQL: SQL 支持的操作和语法
Flink(十九)Flink 的table api与sql之内置函数: Table API 和 SQL 中的内置函数
Flink(二十)Flink 的table api与sql之SQL Client: 不用编写代码就可以尝试 Flink SQL,可以直接提交 SQL 任务到集群上
Flink(二十一)Flink 的table api与sql之table api与sql使用示例
本文基于flink1.17版本,介绍了flink的数据类型的全部内容,包含数据类型定义、自定义数据类型、类型转换与提取。
本文全部是说明性的,为后续的table api和sql使用奠定基础。
本文分为四个部分,即数据类型介绍、数据类型种类、数据类型转换和数据类型提取。
在 Flink 的 Table 生态系统中,数据类型 描述了数据的逻辑类型,可以用来表示转换过程中输入、输出的类型。
Flink 的数据类型类似于 SQL 标准中的术语数据类型,但包含了值的可空性,以便于更好地处理标量表达式。
以下是一些数据类型的例子:
INT
INT NOT NULL
INTERVAL DAY TO SECOND(3)
ROW<myField ARRAY<BOOLEAN>, myOtherField TIMESTAMP(3)>
可在下文中找到所有预先定义好的数据类型。
在定义 connector、catalog、用户自定义函数时,使用 JVM 相关 API 的用户可能会使用到 Table API 中基于 org.apache.flink.table.types.DataType 的一些实例。
数据类型 实例有两个职责:
对于基于 JVM 的语言,所有预定义的数据类型都可以在 org.apache.flink.table.api.DataTypes 下找到。
使用 Table API 编程时,建议使用星号引入所有相关依赖,以获得更流畅的 API 使用体验:
import static org.apache.flink.table.api.DataTypes.*;
DataType t = INTERVAL(DAY(), SECOND(3));
在Table 生态系统中,当需要将 SQL 中的数据类型对应到实际编程语言中的数据类型时,就需要有物理提示。物理提示明确了对应过程中应该使用哪种数据格式。
比如,在 source 端产生数据时,可以规定:TIMESTAMP 的逻辑类型,在底层要使用 java.sql.Timestamp 这个类表示,而不是使用默认的 java.time.LocalDateTime 类。有了物理提示,可以帮助 Flink 运行时根据提供的类将数据转换为其内部数据格式。同样在 sink 端,定义好数据格式,以便能从 Flink 运行时获取、转换数据。
下面的例子展示了如何声明一个桥接转换类:
// 告诉 Flink 运行时使用 java.sql.Timestamp 处理数据,而不是 java.time.LocalDateTime
DataType t = DataTypes.TIMESTAMP(3).bridgedTo(java.sql.Timestamp.class);
// 告诉 Flink 运行时使用基本的 int 数组来处理数据,而不是用包装类 Integer 数组
DataType t = DataTypes.ARRAY(DataTypes.INT().notNull()).bridgedTo(int[].class);
只有在扩展 API 时才需要使用到物理提示。使用预定义的 source、sink 以及 Flink 函数时,不需要用到物理提示。在使用 Table API 编写程序时,Flink 会忽略物理提示(例如 field.cast(TIMESTAMP(3).bridgedTo(Timestamp.class)))
本部分介绍所有Flink支持的预定义的数据类型,可能和Flink的版本有关,本部分介绍的是Flink 1.17版本。
所有预定义的数据类型都可以通过org.apache.flink.table.api.DataTypes来查看。
固定长度的字符串
CHAR
CHAR(n)
DataTypes.CHAR(n)
n的长度没有指定的时候,默认为1,n的范围为【1, 2,147,483,647】。
可变长度的字符串
VARCHAR
VARCHAR(n)
STRING
DataTypes.VARCHAR(n)
DataTypes.STRING()
n不指定的时候,默认为1。n的范围为【1, 2,147,483,647】。
STRING就是VARCHAR(2147483647)。
固定长度的二进制字符串,即字节的序列。n不指定的时候,默认为1。n的范围为【1, 2,147,483,647】。
BINARY
BINARY(n)
DataTypes.BINARY(n)
可变长度的二进制字符串。n不指定的时候,默认为1。n的范围为【1, 2,147,483,647】。
BYTES就是VARBINARY(2147483647)。
VARBINARY
VARBINARY(n)
BYTES
DataTypes.VARBINARY(n)
DataTypes.BYTES()
具有固定精度和小数位数的十进制数的数据类型。
DECIMAL(p, s),p是精度,即数字的位数,s是小数位位数,p范围是【1,38】,s的范围值【0,p】,不指定的时候默认p为10,s为0
NUMERIC(p, s) 和 DEC(p, s) 是一样的。
DECIMAL
DECIMAL(p)
DECIMAL(p, s)
DEC
DEC(p)
DEC(p, s)
NUMERIC
NUMERIC(p)
NUMERIC(p, s)
DataTypes.DECIMAL(p, s)
是1字节有符号的整型数值,范围是【-128,127】
TINYINT
DataTypes.TINYINT()
2字节有符号的整型数字,范围是【-32,768,32,767】。
SMALLINT
DataTypes.SMALLINT()
4字节的有符号整型数字,范围是【-2,147,483,648 , 2,147,483,647】。
INT和INTEGER一样的。
INT
INTEGER
DataTypes.INT()
8字节的有符号整型数字,范围是【 -9,223,372,036,854,775,808 , 9,223,372,036,854,775,807】。
BIGINT
DataTypes.BIGINT()
4 字节单精度浮点数的数据类型。
与 SQL 标准相比,该类型不带参数。
FLOAT
DataTypes.FLOAT()
8 字节双精度浮点数的数据类型。
DOUBLE和DOUBLE PRECISION一样。
DOUBLE
DOUBLE PRECISION
DataTypes.DOUBLE()
由年-月-日组成的日期的数据类型,其值范围从 0000-01-01 到 9999-12-31。
与 SQL 标准相比,范围从 0000 年开始。
DATE
DataTypes.DATE()
不带时区的时间的数据类型,由小时:分钟:秒[.分数]组成,精度高达纳秒,值范围为 00:00:00.0000000000 到 23:59:59.9999999999。
与 SQL 标准相比,不支持闰秒(23:59:60 和 23:59:61)。未提供时区时间。
可以使用 TIME(p) 声明类型,其中 p 是秒的小数部分(精度)的位数。p 的值必须介于 0 和 9 之间(包括 0 和 9)。如果未指定精度,则 p 等于 0。
TIME
TIME(p)
DataTypes.TIME(p)
不带时区的时间戳的数据类型,由年-月-日小时:分钟:秒[.小数]组成,精度高达纳秒,值范围从 0000-01-01 00:00:00.000000000 到 9999-12-31 23:59:59.9999999999。
与SQL标准相比,不支持闰秒(23:59:60和23:59:61),语义更接近java.time.LocalDateTime。
不支持与 BIGINT(一种 JVM 长类型)之间的转换。但是,此类型不受时区限制。有关更多java.time.Instant类语义,请使用TIMESTAMP_LTZ。
可以使用 TIMESTAMP(p) 声明类型,其中 p 是秒的小数部分(精度)的位数。p 的值必须介于 0 和 9 之间(包括 0 和 9)。如果未指定精度,则 p 等于 6。
没有时区的TIMESTAMP§是这种类型的同义词。
TIMESTAMP
TIMESTAMP(p)
TIMESTAMP WITHOUT TIME ZONE
TIMESTAMP(p) WITHOUT TIME ZONE
DataTypes.TIMESTAMP(p)
时间戳的数据类型,其时区由年-月-日小时:分钟:秒[.fractional] 区域组成,精度高达纳秒,值范围从 0000-01-01 00:00:00.000000000 +14:59 到 9999-12-31 23:59:59.9999999999 -14:59。
与TIMESTAMP_LTZ相比,时区偏移信息以物理方式存储在每个基准面中。它单独用于每次计算、可视化或与外部系统的通信。
TIMESTAMP WITH TIME ZONE
TIMESTAMP(p) WITH TIME ZONE
DataTypes.TIMESTAMP_WITH_TIME_ZONE(p)
具有本地时区的时间戳的数据类型,由年-月-日小时:分钟:秒[.fractional] 区域组成,精度高达纳秒,值范围从 0000-01-01 00:00:00.000000000 +14:59 到 9999-12-31 23:59:59.9999999999 -14:59
This type fills the gap between time zone free and time zone mandatory timestamp types by allowing the interpretation of UTC timestamps according to the configured session time zone.
可以使用 TIMESTAMP_LTZ(p) 声明类型,其中 p 是秒的小数部分(精度)的位数。p 的值必须介于 0 和 9 之间(包括 0 和 9)。如果未指定精度,则 p 等于 6。
TIMESTAMP§ WITH LOCAL TIME ZONE 是该类型的同义词。
TIMESTAMP_LTZ
TIMESTAMP_LTZ(p)
TIMESTAMP WITH LOCAL TIME ZONE
TIMESTAMP(p) WITH LOCAL TIME ZONE
DataTypes.TIMESTAMP_LTZ(p)
DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE(p)
一组年月间隔类型的数据类型。
这种类型必须按照下面中之一进行参数化:
年-月的间隔由 +年-月组成,值范围从 -9999-11 到 +9999-11。
对于所有类型的resolutions,值表示形式都是相同的。例如,50 的月份间隔始终以年到月的间隔格式表示(具有默认的年份精度):+04-02。
可以使用上述组合声明类型,其中 p 是年数(年份精度)。p 的值必须介于 1 和 4 之间(包括 1 和 4)。如果未指定年份精度,则 p 等于 2。
INTERVAL YEAR
INTERVAL YEAR(p)
INTERVAL YEAR(p) TO MONTH
INTERVAL MONTH
DataTypes.INTERVAL(DataTypes.YEAR())
DataTypes.INTERVAL(DataTypes.YEAR(p))
DataTypes.INTERVAL(DataTypes.YEAR(p), DataTypes.MONTH())
DataTypes.INTERVAL(DataTypes.MONTH())
一组day-time间隔类型的数据类型。
这种类型必须按照下面中之一进行参数化:
day-time间隔由 +天小时:月:秒.小数组成,值范围为 -999999 23:59:59.999999999 到 +999999 23:59:59.9999999999。对于所有类型的resolutions,值表示形式都是相同的。例如,秒间隔 70 始终以天到秒的间隔格式表示(具有默认精度):+00 00:01:10.000000。
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)
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))
可以使用上述组合声明类型,其中 p1 是天数的位数(日精度),p2 是秒的小数位数(小数精度)。P1 的值必须介于 1 和 6 之间(包括 1 和 6)。P2 的值必须介于 0 和 9 之间(包括 0 和 9)。如果未指定 p1,则默认情况下等于 2。如果未指定 p2,则默认情况下等于 6。
具有相同子类型的元素数组的数据类型。
与 SQL 标准相比,数组的最大基数无法指定,但固定为 2,147,483,647。此外,支持任何有效类型作为子类型。
ARRAY,其中 t 是所包含元素的数据类型。
t ARRAY 是更接近 SQL 标准的同义词。例如,INT ARRAY 等效于 ARRAY
ARRAY<t>
t ARRAY
DataTypes.ARRAY(t)
将key(包括 NULL)map到value(包括 NULL)的关联数组的数据类型。map不能包含重复的键;每个键最多可以映射到一个值。
元素类型没有限制;须确保唯一性。
map类型是 SQL 标准的扩展。
MAP<kt, vt>
DataTypes.MAP(kt, vt)
MAP
multiset(=bag)的数据类型 ,与set不同,它允许每个元素具有公共子类型的多个实例。每个唯一值(包括 NULL)都映射到某个多重性。
元素类型没有限制;须确保唯一性。
MULTISET<t>
t MULTISET
DataTypes.MULTISET(t)
MULTISET,其中 t 是所包含元素的数据类型。
t MULTISET 是更接近 SQL 标准的同义词。例如,INT MULTISET 等效于 MULTISET。
字段序列( a sequence of fields)的数据类型。
字段由字段名称、字段类型和可选描述组成。表中行的最具体类型是行类型。在这种情况下,行的每一列对应于与列具有相同序号位置的行类型的字段。
与 SQL 标准相比,可选字段描述简化了复杂结构的处理。
ROW类似于其他不符合标准的框架中已知的 STRUCT 类型。
ROW<n0 t0, n1 t1, ...>
ROW<n0 t0 'd0', n1 t1 'd1', ...>
ROW(n0 t0, n1 t1, ...>
ROW(n0 t0 'd0', n1 t1 'd1', ...)
DataTypes.ROW(DataTypes.FIELD(n0, t0), DataTypes.FIELD(n1, t1), ...)
DataTypes.ROW(DataTypes.FIELD(n0, t0, d0), DataTypes.FIELD(n1, t1, d1), ...)
可以使用 ROW
ROW(…) 是更接近 SQL 标准的同义词。例如,ROW(myField INT, myOtherField BOOLEAN) 等价于 ROW
尚不完全支持用户定义的数据类型。它们目前(从 Flink 1.11 开始)仅在函数的参数和返回类型中作为未注册的结构化类型公开。
结构化类型类似于面向对象编程语言中的对象。它包含零个、一个或多个属性。每个属性都由名称和类型组成。
有两种结构化类型,如下:
目前(1.17版本)不支持注册的结构化类型。因此,它们不能存储在目录中或在创建表 DDL 中引用。
未注册的结构化类型可以使用自动反射提取从常规 POJO(Plain Old Java Objects 普通旧 Java 对象)创建。
结构化类型的实现类必须满足以下要求:
反射提取支持字段的任意嵌套,只要字段类型不(传递地)引用自身。
声明的字段类(例如,public int age;)必须包含在为本文档中每种数据类型定义的支持的 JVM 桥接类列表中(例如.java.lang.Integer 或 int 表示 INT)。
对于某些类,需要注释才能将类映射到数据类型(例如@DataTypeHint(“DECIMAL(10,2)”)为java.math.BigDecimal分配固定的精度和小数位数)。
示例如下:
class User {
// extract fields automatically
public int age;
public String name;
// enrich the extraction with precision information
public @DataTypeHint("DECIMAL(10, 2)") BigDecimal totalBalance;
// enrich the extraction with forcing using RAW types
public @DataTypeHint("RAW") Class<?> modelClass;
}
DataTypes.of(User.class);
Data type of a boolean with a (possibly) three-valued logic of TRUE, FALSE, and UNKNOWN.
布尔值的数据类型,其(可能)三值逻辑为 TRUE、FALSE 和 UNKNOWN。
BOOLEAN
DataTypes.BOOLEAN()
Data type of an arbitrary serialized type. This type is a black box within the table ecosystem and is only deserialized at the edges.
任意序列化(arbitrary serialized)类型的数据类型。此类型是表生态系统中的黑盒,仅在边缘反序列化。
原始类型是 SQL 标准的扩展。
RAW('class', 'snapshot')
DataTypes.RAW(class, serializer)
DataTypes.RAW(class)
可以使用 RAW(‘class’, ‘snapshot’) 声明该类型,其中 class 是原始类,snapshot是 Base64 编码的序列化 TypeSerializerSnapshot。通常,类型字符串不是直接声明的,而是在保留类型时生成的。
在 API 中,可以通过直接提供类 + 类型序列化程序或传递类并让框架从那里提取类 + 类型序列化程序来声明 RAW 类型。
用于表示非类型化 NULL 值的数据类型。
NULL类型是 SQL 标准的扩展。null 类型除了 NULL 之外没有其他值,因此,它可以转换为类似于 JVM 语义的任何可空类型。
此类型有助于在使用 NULL 文本的 API 调用中表示未知类型,以及桥接到定义此类类型的格式,例如 JSON 或 Avro。
这种类型在实践中不是很有用,这里只是为了完整性而提到。
NULL
DataTypes.NULL()
Flink Table API 和 Flink SQL 支持从 输入 数据类型 到 目标 数据类型的转换。有的转换 无论输入值是什么都能保证转换成功,而有些转换则会在运行时失败(即不可能转换为 目标 数据类型对应的值)。 例如,将 INT 数据类型的值转换为 STRING 数据类型一定能转换成功,但无法保证将 STRING 数据类型转换为 INT 数据类型。
在生成执行计划时,Flink 的 SQL 检查器会拒绝提交那些不可能直接转换为 目标 数据类型的SQL,并抛出 ValidationException 异常, 例如从 TIMESTAMP 类型转化到 INTERVAL 类型。 然而有些查询即使通过了 SQL 检查器的验证,依旧可能会在运行期间转换失败,这就需要用户正确处理这些失败了。
在 Flink Table API 和 Flink SQL 中,可以用下面两个内置方法来进行转换操作:
CAST('42' AS INT) --- 结果返回数字 42 的 INT 格式(非空)
CAST(NULL AS VARCHAR) --- 结果返回 VARCHAR 类型的空值
CAST('non-number' AS INT) --- 抛出异常,并停止作业
TRY_CAST('42' AS INT) --- 结果返回数字 42 的 INT 格式
TRY_CAST(NULL AS VARCHAR) --- 结果返回 VARCHAR 类型的空值
TRY_CAST('non-number' AS INT) --- 结果返回 INT 类型的空值
COALESCE(TRY_CAST('non-number' AS INT), 0) --- 结果返回数字 0 的 INT 格式(非空)
下表展示了各个类型的转换程度,“Y” 表示支持,“!” 表示转换可能会失败,“N” 表示不支持:
备注:
所有转化到具有固长或变长的类型时会根据类型的定义来裁剪或填充数据。
使用 TO_TIMESTAMP 方法和 TO_TIMESTAMP_LTZ 方法的场景,不要使用 CAST 或 TRY_CAST。
支持转换,当且仅当用其内部数据结构也支持转化时。转换可能会失败,当且仅当用其内部数据结构也可能会转换失败。
支持转换,当且仅当用使用 RAW 的类和类的序列化器一样。
支持转换,当且仅当用使用 INTERVAL 做“月”到“年”的转换。
支持转换,当且仅当用使用 INTERVAL 做“天”到“时间”的转换。
请注意:无论是 CAST 还是 TRY_CAST,当输入为 NULL ,输出也为 NULL。
用户可以通过将参数 table.exec.legacy-cast-behaviour 设置为 enabled 来启用 1.15 版本之前的 CAST 行为。 在 Flink 1.15 版本此参数默认为 disabled。
如果设置为 enabled,请注意以下问题:
不建议 配置此参数,而是 强烈建议 在新项目中保持这个参数为默认禁用,以使用最新版本的 CAST 方法。 在下一个版本,这个参数会被移除。
在 API 中的很多地方,Flink 都尝试利用反射机制从类信息中自动提取数据类型,以避免重复地手动定义 schema。但是,通过反射提取数据类型并不总是有效的,因为有可能会缺失逻辑信息。因此,可能需要在类或字段声明的附近添加额外信息以支持提取逻辑。
下表列出了无需更多信息即可隐式映射到数据类型的类。
如果你打算在 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]。
本文档中提到的其他 JVM 桥接类需要 @DataTypeHint 注释。
数据类型 hints 可以参数化或替换单个函数参数和返回类型、结构化类或结构化类的字段的默认提取逻辑。实现者可以通过声明 @DataTypeHint 注解来选择默认提取逻辑的修改程度。
@DataTypeHint 注解提供了一组可选的 hint 参数。其中一些参数如以下示例所示。更多信息可以在注解类的文档中找到。
示例如下:
import org.apache.flink.table.annotation.DataTypeHint;
class User {
// 使用默认转换类 `java.lang.Integer` 定义 INT 数据类型
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;
}
以上,基于flink1.17版本,介绍了flink的数据类型的全部内容,包含数据类型定义、自定义数据类型、类型转换与提取。