
史上最全干货!Flink SQL 成神之路(四)
作者 | antigeneral了呀
来源 | 大数据羊说(ID:young_say)
作者 | antigeneral了呀
4.SQL 能力扩展篇
4.1.SQL UDF 扩展 - Module
在介绍 Flink Module 具体能力之前,我们先来聊聊博主讲述的思路:
- ⭐ 背景及应用场景介绍
- ⭐ Flink Module 功能介绍
- ⭐ 应用案例:Flink SQL 支持 Hive UDF
4.1.1.Flink SQL Module 应用场景
兄弟们,想想其实大多数公司都是从离线数仓开始建设的。相信大家必然在自己的生产环境中开发了非常多的 Hive UDF。随着需求对于时效性要求的增高,越来越多的公司也开始建设起实时数仓。很多场景下实时数仓的建设都是随着离线数仓而建设的。实时数据使用 Flink 产出,离线数据使用 Hive/Spark 产出。
那么回到我们的问题:为什么需要给 Flink UDF 做扩展呢?可能这个问题比较大,那么博主分析的具体一些,如果 Flink 扩展支持 Hive UDF 对我们有哪些好处呢?
博主分析了下,结论如下:
站在数据需求的角度来说,一般会有以下两种情况:
- ⭐ 以前已经有了离线数据链路,需求方也想要实时数据。如果直接能用已经开发好的 hive udf,则不用将相同的逻辑迁移到 flink udf 中,并且后续无需费时费力维护两个 udf 的逻辑一致性。
- ⭐ 实时和离线的需求都是新的,需要新开发。如果只开发一套 UDF,则事半功倍。
因此在 Flink 中支持 Hive UDF(也即扩展 Flink 的 UDF 能力)这件事对开发人员提效来说是非常有好处的。
4.1.2.Flink SQL Module 功能介绍
Module 允许 Flink 扩展函数能力。它是可插拔的,Flink 官方本身已经提供了一些 Module,用户也可以编写自己的 Module。
例如,用户可以定义自己的函数,并将其作为加载进入 Flink,以在 Flink SQL 和 Table API 中使用。
再举一个例子,用户可以加载官方已经提供的的 Hive Module,将 Hive 已有的内置函数作为 Flink 的内置函数。
目前 Flink 包含了以下三种 Module:
- ⭐ CoreModule:CoreModule 是 Flink 内置的 Module,其包含了目前 Flink 内置的所有 UDF,Flink 默认开启的 Module 就是 CoreModule,我们可以直接使用其中的 UDF
- ⭐ HiveModule:HiveModule 可以将 Hive 内置函数作为 Flink 的系统函数提供给 SQL\Table API 用户进行使用,比如 get_json_object 这类 Hive 内置函数(Flink 默认的 CoreModule 是没有的)
- ⭐ 用户自定义 Module:用户可以实现 Module 接口实现自己的 UDF 扩展 Module
在 Flink 中,Module 可以被 加载
、启用
、禁用
、卸载
Module,当 TableEnvironment 加载(见 SQL 语法篇的 Load Module) Module 之后,默认就是开启的。
Flink 是同时支持多个 Module 的,并且根据加载 Module 的顺序去按顺序查找和解析 UDF,先查到的先解析使用。
此外,Flink 只会解析已经启用了的 Module。那么当两个 Module 中出现两个同名的函数时,会有以下三种情况:
- ⭐ 如果两个 Module 都启用的话,Flink 会根据加载 Module 的顺序进行解析,结果就是会使用顺序为第一个的 Module 的 UDF
- ⭐ 如果只有一个 Module 启用的话,Flink 就只会从启用的 Module 解析 UDF
- ⭐ 如果两个 Module 都没有启用,Flink 就无法解析这个 UDF
当然如果出现第一种情况时,用户也可以改变使用 Module 的顺序。比如用户可以使用 USE MODULE hive, core
语句去将 Hive Module 设为第一个使用及解析的 Module。
另外,用户可以使用 USE MODULES hive
去禁用默认的 core Module,注意,禁用不是卸载 Module,用户之后还可以再次启用 Module,并且使用 USE MODULES core
去将 core Module 设置为启用的。如果使用未加载的 Module,则会直接抛出异常。
禁用和卸载 Module 的区别在于禁用依然会在 TableEnvironment 保留 Module,用户依然可以使用使用 list 命令看到禁用的 Module。
注意:
由于 Module 的 UDF 是被 Flink 认为是 Flink 系统内置的,它不和任何 Catalog,数据库绑定,所以这部分 UDF 没有对应的命名空间,即没有 Catalog,数据库命名空间。
- ⭐ 使用 SQL API 加载、卸载、使用、列出 Module
- ⭐ 使用 Java API 加载、卸载、使用、列出 Module
4.1.3.应用案例:Flink SQL 支持 Hive UDF
Flink 支持 hive UDF 这件事分为两个部分。
- ⭐ Flink 扩展支持 hive 内置 UDF
- ⭐ Flink 扩展支持用户自定义 hive UDF
第一部分:Flink 扩展支持 Hive 内置 UDF,比如 get_json_object
,rlike
等等。
有同学问了,这么基本的 UDF,Flink 都没有吗?
确实没有。关于 Flink SQL 内置的 UDF 见如下链接,大家可以看看 Flink 支持了哪些 UDF:https://nightlies.apache.org/flink/flink-docs-release-1.13/docs/dev/table/functions/systemfunctions/
那么如果我如果强行使用 get_json_object 这个 UDF,会发生啥呢?结果如下图。
直接报错找不到 UDF。
error
第二部分:Flink 扩展支持用户自定义 Hive UDF。
内置函数解决不了用户的复杂需求,用户就需要自己写 Hive UDF,并且这部分自定义 UDF 也想在 flink sql 中使用。
下面看看怎么在 Flink SQL 中进行这两种扩展。
- ⭐ flink 扩展支持 hive 内置 udf
步骤如下:
- ⭐ 引入 hive 的 connector。其中包含了 flink 官方提供的一个
HiveModule
。在HiveModule
中包含了 hive 内置的 udf。
- ⭐ 在
StreamTableEnvironment
中加载HiveModule
。
然后在控制台打印一下目前有的 module。
然后可以看到除了 core
module,还有我们刚刚加载进去的 default
module。
- ⭐ 查看所有 module 的所有 udf。在控制台打印一下。
就会将 default 和 core module 中的所有包含的 udf 给列举出来,当然也就包含了 hive module 中的 get_json_object。
get_json_object
然后我们再去在 Flink SQL 中使用 get_json_object 这个 UDF,就没有报错,能正常输出结果了。
使用 Flink Hive connector 自带的 HiveModule
,已经能够解决很大一部分常见 UDF 使用的问题了。
- ⭐ Flink 扩展支持用户自定义 Hive UDF
原本博主是直接想要使用 Flink SQL 中的 create temporary function
去执行引入自定义 Hive UDF 的。
举例如下:
发现在执行这句 SQL 时,是可以执行成功,将 UDF 注册进去的。
但是在后续 UDF 初始化时就报错了。具体错误如下图。直接报错 ClassCastException。
ddl hive udf error
看了下源码,Flink 流任务模式下(未连接 Hive MetaStore 时)在创建 UDF 时会认为这个 UDF 是 Flink 生态体系中的 UDF。
所以在初始化我们引入的 TestGenericUDF
时,默认会按照 Flink 的 UserDefinedFunction
强转,因此才会报强转错误。
那么我们就不能使用 Hive UDF 了吗?
错误,小伙伴萌岂敢有这种想法。博主都把这个标题列出来了(牛逼都吹出去了),还能给不出解决方案嘛。
思路见下一节。
- ⭐ Flink 扩展支持用户自定义 Hive UDF 的增强 module
其实思路很简单。
使用 Flink SQL 中的 create temporary function
虽然不能执行,但是 Flink 提供了插件化的自定义 module。
我们可以扩展一个支持用户自定义 Hive UDF 的 module,使用这个 module 来支持自定义的 Hive UDF。
实现的代码也非常简单。简单的把 Flink Hive connector 提供的 HiveModule
做一个增强即可,即下图中的 HiveModuleV2
。使用方式如下图所示:
hive module enhance
然后程序就正常跑起来了。
肥肠滴好用!
4.2.SQL 元数据扩展 - Catalog
4.2.1.Flink Catalog 功能介绍
数据处理最关键的方面之一是管理元数据。元数据可以是临时的,例如临时表、UDF。元数据也可以是持久化的,例如 Hive MetaStore 中的元数据。
Flink SQL 中是由 Catalog 提供了元数据信息,例如数据库、表、分区、视图以及数据库或其他外部系统中存储的函数和信息。对标 Hive 去理解就是 Hive 的 MetaStore,都是用于存储计算引擎涉及到的元数据信息。
Catalog 允许用户引用其数据存储系统中现有的元数据,并自动将其映射到 Flink 的相应元数据。例如,Flink 可以直接使用 Hive MetaStore 中的表的元数据,也可以将 Flink SQL 中的元数据存储到 Hive MetaStore 中。Catalog 极大地简化了用户开始使用 Flink 的步骤,提升了用户体验。
目前 Flink 包含了以下四种 Catalog:
- ⭐ GenericInMemoryCatalog:GenericInMemoryCatalog 是基于内存实现的 Catalog,所有元数据只在 session 的生命周期(即一个 Flink 任务一次运行生命周期内)内可用。
- ⭐ JdbcCatalog:JdbcCatalog 使得用户可以将 Flink 通过 JDBC 协议连接到关系数据库。PostgresCatalog 是当前实现的唯一一种 JDBC Catalog,即可以将 Flink SQL 的预案数据存储在 Postgres 中。
- ⭐ HiveCatalog:HiveCatalog 有两个用途,作为 Flink 元数据的持久化存储,以及作为读写现有 Hive 元数据的接口。注意:Hive MetaStore 以小写形式存储所有元数据对象名称。而 GenericInMemoryCatalog 会区分大小写。
- ⭐ 用户自定义 Catalog:用户可以实现 Catalog 接口实现自定义 Catalog
下面看看 Flink Catalog 提供了什么 API,以及对应 API 的使用案例:
- ⭐ 使用 SQL API 将表创建注册进 Catalog
- ⭐ 使用 Java API 将表创建注册进 Catalog
4.2.2.操作 Catalog 的 API
这里只列出了 Java 的 Catalog API,用户也可以使用 SQL DDL API 实现相同的功能。关于 DDL 的详细信息请参考之前介绍到的 SQL CREATE DDL 章节。
- ⭐ Catalog 操作
- ⭐ 数据库操作
- ⭐ 表操作
- ⭐ 视图操作
- ⭐ 分区操作
- ⭐ 函数操作
4.3.SQL 任务参数配置
关于 Flink SQL 详细的配置项及功能如下链接所示,详细内容大家可以点击链接去看,博主下面只介绍常用的性能优化参数及其功能:
https://nightlies.apache.org/flink/flink-docs-release-1.13/docs/dev/table/config/
4.3.1.参数设置方式
Flink SQL 相关参数需要在 TableEnvironment 中设置。如下案例:
具体参数分为以下 3 类:
- ⭐ 运行时参数:优化 Flink SQL 任务在执行时的任务性能
- ⭐ 优化器参数:Flink SQL 任务在生成执行计划时,经过优化器优化生成更优的执行计划
- ⭐ 表参数:用于调整 Flink SQL table 的执行行为
4.3.2.运行时参数
用于优化 Flink SQL 任务在执行时的任务性能。
其中上述参数中最常被用到为一下两种:
- ⭐ MiniBatch 聚合
具体使用场景如下链接:
- ⭐ state ttl 状态过期
4.3.3.优化器参数
Flink SQL 任务在生成执行计划时,优化生成更优的执行计划
其中上述参数中最常被用到为以下两种:
- ⭐ 两阶段优化:
在计算 count(1),sum(col) 场景汇总提效很高,因为 count(1),sum(col) 在经过本地 localAggregate 之后,每个 group by 的 key 就一个结果值。
注意!!!:此优化在窗口聚合中会自动生效,但是在 unbounded agg 中需要与 minibatch 参数相结合使用才会生效。
- ⭐ split 分桶:
注意!!!:如果有多个 distinct key,则多个 distinct key 都会被作为分桶 key。
4.3.4.表参数
4.4.SQL 性能调优
本小节主要介绍 Flink SQL 中的聚合算子的优化,在某些场景下应用这些优化后,性能提升会非常大。本小节主要包含以下四种优化:
- ⭐
(常用)
MiniBatch 聚合:unbounded group agg 中,可以使用 minibatch 聚合来做到微批计算、访问状态、输出结果,避免每来一条数据就计算、访问状态、输出一次结果,从而减少访问 state 的时长(尤其是 Rocksdb)提升性能。 - ⭐
(常用)
两阶段聚合:类似 MapReduce 中的 Combiner 的效果,可以先在 shuffle 数据之前先进行一次聚合,减少 shuffle 数据量 - ⭐
(不常用)
split 分桶:在 count distinct、sum distinct 的去重的场景中,如果出现数据倾斜,任务性能会非常差,所以如果先按照 distinct key 进行分桶,将数据打散到各个 TM 进行计算,然后将分桶的结果再进行聚合,性能就会提升很大 - ⭐
(常用)
去重 filter 子句:在 count distinct 中使用 filter 子句于 Hive SQL 中的 count(distinct if(xxx, user_id, null)) 子句,但是 state 中同一个 key 会按照 bit 位会进行复用,这对状态大小优化非常有用
上面简单介绍了聚合场景的四种优化,下面详细介绍一下其最终效果以及实现原理。
4.4.1.MiniBatch 聚合
- ⭐ 问题场景:默认情况下,unbounded agg 算子是逐条处理输入的记录,其处理流程如下:
- ⭐ 从状态中读取 accumulator;
- ⭐ 累加/撤回的数据记录至 accumulator;
- ⭐ 将 accumulator 写回状态;
- ⭐ 下一条记录将再次从流程 1 开始处理。
但是上述处理流程的问题在于会增加 StateBackend 的访问性能开销(尤其是对于 RocksDB StateBackend)。
- ⭐ MiniBatch 聚合如何解决上述问题:其核心思想是将一组输入的数据缓存在聚合算子内部的缓冲区中。当输入的数据被触发处理时,每个 key 只需要访问一次状态后端,这样可以大大减少访问状态的时间开销从而获得更好的吞吐量。但是,其会增加一些数据产出的延迟,因为它会缓冲一些数据再去处理。因此如果你要做这个优化,需要提前做一下吞吐量和延迟之间的权衡,但是大多数情况下,buffer 数据的延迟都是可以被接受的。所以非常建议在 unbounded agg 场景下使用这项优化。
下图说明了 MiniBatch 聚合如何减少状态访问的。
MiniBatch
上图展示了加 MiniBatch 和没加 MiniBatch 之前的执行区别。
- ⭐ 启用 MiniBatch 聚合的参数:
注意!!!
- ⭐
table.exec.mini-batch.allow-latency
和table.exec.mini-batch.size
两者只要其中一项满足条件就会执行 batch 访问状态操作。- ⭐ 上述 MiniBatch 配置不会对 Window TVF 生效,因为!!!Window TVF 默认就会启用小批量优化,Window TVF 会将 buffer 的输入记录记录在托管内存中,而不是 JVM 堆中,因此 Window TVF 不会有 GC 过高或者 OOM 的问题。
4.4.2.两阶段聚合
- ⭐ 问题场景:在聚合数据处理场景中,很可能会由于热点数据导致数据倾斜,如下 SQL 所示,当 color = RED 为 50000w 条,而 color = BLUE 为 5 条,就产生了数据倾斜,而器数据处理的算子产生性能瓶颈。
- ⭐ 两阶段聚合如何解决上述问题:其核心思想类似于 MapReduce 中的 Combiner + Reduce,先将聚合操作在本地做一次 local 聚合,这样 shuffle 到下游的数据就会变少。
还是上面的 SQL 案例,如果在 50000w 条的 color = RED 的数据 shuffle 之前,在本地将 color = RED 的数据聚合成为 1 条结果,那么 shuffle 给下游的数据量就被极大地减少了。
下图说明了两阶段聚合是如何处理热点数据的:
两阶段聚合
- ⭐ 启用两阶段聚合的参数:
注意!!!
- ⭐ 此优化在窗口聚合中会自动生效,大家在使用 Window TVF 时可以看到 localagg + globalagg 两部分
- ⭐ 但是在 unbounded agg 中需要与 MiniBatch 参数相结合使用才会生效。
4.4.3.split 分桶
- ⭐ 问题场景:使用两阶段聚合虽然能够很好的处理 count,sum 等常规聚合算子,但是在 count distinct,sum distinct 等算子的两阶段聚合效果在大多数场景下都不太满足预期。
因为 100w 条数据的 count 聚合能够在 local 算子聚合为 1 条数据,但是 count distinct 聚合 100w 条在 local 聚合之后的结果和可能是 90w 条,那么依然会有数据倾斜,如下 SQL 案例所示:
- ⭐ split 分桶如何解决上述问题:其核心思想在于按照 distinct 的 key,即 user_id,先做数据的分桶,将数据打散,分散到 Flink 的多个 TM 上进行计算,然后再将数据合桶计算。打开 split 分桶之后的效果就等同于以下 SQL:
下图说明了 split 分桶的处理流程:
split 聚合
- ⭐ 启用 split 分桶的参数:
注意!!!
- ⭐ 如果有多个 distinct key,则多个 distinct key 都会被作为分桶 key。比如 count(distinct a),sum(distinct b) 这种多个 distinct key 也支持。
- ⭐ 小伙伴萌自己写的 UDAF 不支持!
- ⭐ 其实此种优化很少使用,因为大家直接自己按照分桶的写法自己就可以写了,而且最后生成的算子图和自己写的 SQL 的语法也能对应的上
4.4.4.去重 filter 子句
- ⭐ 问题场景:在一些场景下,用户可能需要从不同维度计算 UV,例如 Android 的 UV、iPhone 的 UV、Web 的 UV 和总 UV。许多用户会选择 CASE WHEN 支持此功能,如下 SQL 所示:
但是如果你想实现类似的效果,Flink SQL 提供了更好性能的写法,就是本小节的 filter 子句。
- ⭐ Filter 子句重写上述场景:
Filter 子句的优化点在于,Flink 会识别出三个去重的 key 都是 user_id,因此会把三个去重的 key 存在一个共享的状态中。而不是上文 case when 中的三个状态中。其具体实现区别在于:
- ⭐ case when:total_uv、app_uv、web_uv 在去重时,state 是存在三个 MapState 中的,MapState key 为 user_id,value 为默认值,判断是否重复直接按照 key 是在 MapState 中的出现过进行判断。如果总 uv 为 1 亿,'android', 'iphone' uv 为 5kw,'wap', 'other' uv 为 5kw,则 3 个 state 要存储总共 2 亿条数据
- ⭐ filter:total_uv、app_uv、web_uv 在去重时,state 是存在一个 MapState 中的,MapState key 为 user_id,value 为 long,其中 long 的第一个 bit 位标识在计算总 uv 时此 user_id 是否来光顾哦,第二个标识 'android', 'iphone',第三个标识 'wap', 'other',因此在上述 case when 相同的数据量的情况下,总共只需要存储 1 亿条数据,state 容量减小了几乎 50%
或者下面的场景也可以使用 filter 子句进行替换。
- ⭐ 优化前:
如果能够确定 app_type 是可以枚举的,比如为 android、iphone、web 三种,则可以使用 filter 子句做性能优化:
经过上述优化之后,state 大小的优化效果也会是成倍提升的。
4.5.SQL Connector 扩展 - 自定义 Source\Sink
4.5.1.自定义 Source\Sink
4.5.2.自定义 Source\Sink 的扩展接口
Flink SQL 中除了自定义的 Source 的基础接口之外,还提供了一部分扩展接口用于性能的优化、能力扩展,接下来详细进行介绍。在 Source\Sink 中主要包含了以下接口:
- ⭐ Source 算子的接口:
- ⭐
SupportsFilterPushDown
:将过滤条件下推到 Source 中提前过滤,减少下游处理的数据量。案例可见org.apache.flink.table.filesystem.FileSystemTableSource
- ⭐
SupportsLimitPushDown
:将 limit 条目数下推到 Source 中提前限制处理的条目数。案例可见org.apache.flink.table.filesystem.FileSystemTableSource
- ⭐
SupportsPartitionPushDown
:(常用于批处理场景)将带有 Partition 属性的 Source,将所有的 Partition 数据获取到之后,然后在 Source 决定哪个 Source 读取哪些 Partition 的数据,而不必在 Source 后过滤。比如 Hive 表的 Partition,将所有 Partition 获取到之后,然后决定某个 Source 应该读取哪些 Partition,详细可见org.apache.flink.table.filesystem.FileSystemTableSource
。 - ⭐
SupportsProjectionPushDown
:将下游用到的字段下推到 Source 中,然后 Source 中只取这些字段,不使用的字段就不往下游发。案例可见org.apache.flink.connector.jdbc.table.JdbcDynamicTableSource
- ⭐
SupportsReadingMetadata
:支持读取 Source 的 metadata,比如在 Kafka Source 中读取 Kafka 的 offset,写入时间戳等数据。案例可见org.apache.flink.streaming.connectors.kafka.table.KafkaDynamicSource
- ⭐
SupportsWatermarkPushDown
:支持将 Watermark 的分配方式下推到 Source 中,比如 Kafka Source 中一个 Source Task 可以读取多个 Partition,然后为每个 Partition 单独分配 Watermark Generator,这样 Watermark 的生成粒度就是单 Partition,在事件时间下数据计算会更加准确。案例可见org.apache.flink.streaming.connectors.kafka.table.KafkaDynamicSource
- ⭐
SupportsSourceWatermark
:支持自定义的 Source Watermark 分配方式,比如目前已有的 Watermark 分配方式不满足需求,需要自定义 Source 的 Watermark 生成方式,则可以实现此接口 +在 DDL 中声明 SOURCE_WATERMARK()
来声明使用自定义 Source 的 Watermark 生成方式。案例可见org.apache.flink.table.planner.connectors.ExternalDynamicSource
- ⭐ Sink 算子的接口:
- ⭐
SupportsOverwrite
:(常用于批处理场景)支持类似于 Hive SQL 的 insert overwrite table xxx 的能力,将已有分区内的数据进行覆盖。案例可见org.apache.flink.connectors.hive.HiveTableSink
- ⭐
SupportsPartitioning
:(常用于批处理场景)支持类似于 Hive SQL 的 insert INTO xxx partition(key = 'A') xxx 的能力,支持将结果数据写入某个静态分区。案例可见org.apache.flink.connectors.hive.HiveTableSink
- ⭐
SupportsWritingMetadata
:支持将 metadata 写入到 Sink 中,比如可以往 Kafka Sink 中写入 Kafka 的 timestamp、header 等。案例可见org.apache.flink.streaming.connectors.kafka.table.KafkaDynamicSink
4.5.3.Source:SupportsFilterPushDown
- ⭐ 应用场景:将 where 中的一些过滤条件下推到 Source 中进行处理,这样不需要的数据就可以不往下游发送了,性能会有提升。
- ⭐ 优化前:如下图 web ui 算子图,过滤条件都在 Source 节点之后有单独的 filter 算子进行承接
filter 前
- ⭐ 优化方案及实现:在 DynamicTableSource 中实现 SupportsFilterPushDown 接口的方法,具体实现方案如下:
- ⭐ 优化效果:如下图 web ui 算子图,过滤条件在 Source 节点执行
filter 后
4.5.4.Source:SupportsLimitPushDown
- ⭐ 应用场景:将 limit 子句下推到 Source 中,在批场景中可以过滤大部分不需要的数据
- ⭐ 优化前:如下图 web ui 算子图,limit 条件都在 Source 节点之后有单独的 Limit 算子进行承接
limit 前
- ⭐ 优化方案及实现:在 DynamicTableSource 中实现 SupportsLimitPushDown 接口的方法,具体实现方案如下:
- ⭐ 优化效果:如下图 web ui 算子图,limit 条件在 Source 节点执行
limit 后
4.5.5.Source:SupportsProjectionPushDown
- ⭐ 应用场景:将下游用到的字段下推到 Source 中,然后 Source 中可以做到只取这些字段,不使用的字段就不往下游发
- ⭐ 优化前:如下图 web ui 算子图,limit 条件都在 Source 节点之后有单独的 Limit 算子进行承接
project 前
- ⭐ 优化方案及实现:在 DynamicTableSource 中实现 SupportsProjectionPushDown 接口的方法,具体实现方案如下:
- ⭐ 优化效果:如下图 web ui 算子图,下游没有用到的字段直接在 Source 节点过滤掉,不输出
project 后
4.5.6.Source:SupportsReadingMetadata
- ⭐ 应用场景:支持读取 Source 的 metadata,比如在 Kafka Source 中读取 Kafka 的 offset,写入时间戳等数据
- ⭐ 支持之前:比如想获取 Kafka 中的 offset 字段,在之前是不支持的
- ⭐ 支持方案及实现:在 DynamicTableSource 中实现 SupportsReadingMetadata 接口的方法,我们来看看 Flink Kafka Consumer 的具体实现方案:
- ⭐ 支持之后的效果:
在后续的 DML SQL 语句中就可以正常使用这些 metadata 字段的数据了。
4.5.7.Source:SupportsWatermarkPushDown
- ⭐ 应用场景:支持将 Watermark 的分配方式下推到 Source 中,比如 Kafka Source 中一个 Source Task 可以读取多个 Partition,Watermark 分配器下推到 Source 算子中后,就可以为每个 Partition 单独分配 Watermark Generator,这样 Watermark 的生成粒度就是 Kafka 的单 Partition,在事件时间下数据乱序会更小。
- ⭐ 支持之前:可以看到下图,Watermark 的分配是在 Source 节点之后的。
watermark 前
- ⭐ 支持方案及实现:在 DynamicTableSource 中实现 SupportsWatermarkPushDown 接口的方法,我们来看看 Flink Kafka Consumer 的具体实现方案:
- ⭐ 支持之后的效果:
watermark 前
4.5.8.Sink:SupportsOverwrite
- ⭐ 应用场景:(常用于批处理场景)支持类似于 Hive SQL 的 insert overwrite table xxx 的能力,将已有分区内的数据进行覆盖。
- ⭐ 支持方案及实现:在 DynamicTableSink 中实现 SupportsOverwrite 接口的方法,我们来看看
HiveTableSink
的具体实现方案:
- ⭐ 支持之后的效果:
支持在批任务中 insert overwrite xxx。
4.5.9.Sink:SupportsPartitioning
- ⭐ 应用场景:(常用于批处理场景)支持类似于 Hive SQL 的 insert INTO xxx partition(key = 'A') 的能力,支持将结果数据写入某个静态分区。
- ⭐ 支持方案及实现:在 DynamicTableSink 中实现 SupportsPartitioning 接口的方法,我们来看看
HiveTableSink
的具体实现方案:
- ⭐ 支持之后的效果:
4.5.9.Sink:SupportsWritingMetadata
- ⭐ 应用场景:支持将 metadata 写入到 Sink 中。举例:可以往 Kafka Sink 中写入 Kafka 的 timestamp、header 等。案例可见
org.apache.flink.streaming.connectors.kafka.table.KafkaDynamicSink
- ⭐ 支持方案及实现:在 DynamicTableSink 中实现 SupportsWritingMetadata 接口的方法,我们来看看
KafkaDynamicSink
的具体实现方案:
- ⭐ 支持之后的效果:
