文章目录
本文主要讨论了:
一. 使用关系查询处理流的讨论
传统关系代数与流处理在流入数据、执行和结果输出的区别:
物化视图与即时视图维护,提供了关系查询处理流的思路
即时视图维护和流上的SQL查询之间的联系:
上面主要表达了:通过将数据库的binlog消费为stream,用SQL查询作为物化视图,并通过changelog更新物化视图。
二. 动态表 & 连续查询(Continuous Query)
动态表是随时间变化的,查询动态表将生成连续查询,查询结果会生成一个动态表,并且查询会不断更新生成的动态表。
需要注意的是,连续查询的结果在语义上总是等价于以批处理模式在输入表快照上执行的相同查询的结果。
流、动态表和连续查询之间的关系:
注意: 动态表首先是一个逻辑概念。在查询执行期间不一定(完全)物化动态表。
三. 在流上定义表
流转换为表
为了使用关系查询处理流,必须将其转换成 Table。
1. 连续查询
- 动态表上进行连续查询将生成一个新的动态表
- 连续查询不会终止,会根据输入表的更新,更新结果表
- 在任何时候,连续查询的结果在语义上与以批处理模式在输入表快照上执行的相同查询的结果相同。
例子1:基于 user 字段对 clicks 表进行分组,并统计访问的 URL 的数量。
例子2:将 clicks 分组至每小时滚动窗口中,然后计算 url 数量。
两个查询的不同
2. 查询限制
2.1. 维护状态
连续查询在无界流上计算,通常应该运行数周或数月。因此,连续查询处理的数据总量可能非常大。这里flink要维护需要保存结果的行(字段),以便能够及时更新它们。例如,第一个查询示例需要一直存储每个用户的 URL 计数,以便能够增加该计数并在输入表接收新行时发送新结果。
SELECT user, COUNT(url)
FROM clicks
GROUP BY user;
2.2. 计算更新
有些查询需要重新计算和更新大量已输出的结果行,即使只添加或更新一条输入记录。显然,这样的查询不适合作为连续查询执行(ing)。下面的查询就是一个例子,它根据最后一次单击的时间为每个用户计算一个 RANK。一旦 click 表接收到一个新行,用户的 lastAction 就会更新,并必须计算一个新的排名。然而,由于两行不能具有相同的排名,所以所有较低排名的行也需要更新。
SELECT user, RANK() OVER (ORDER BY lastAction)
FROM (
SELECT user, MAX(cTime) AS lastAction FROM clicks GROUP BY user
);
但是我们可以设置一些参数可以用来在维持状态的大小和获得结果的准确性之间做取舍。
四. 表到流的转换
动态表可以像普通数据库表一样通过 INSERT、UPDATE 和 DELETE 来不断修改。
在将动态表转换为流或将其写入外部系统时,需要对这些更改进行编码。Flink的 Table API 和 SQL 支持三种方式来编码一个动态表的变化:
1. Append-only 流
仅通过 INSERT 操作修改的动态表可以通过输出插入的行转换为流。
2. Retract 流
retract 流包含两种类型的 message: add messages 和 retract messages 。通过
3. Upsert 流
upsert 流包含两种类型的 message: upsert messages 和delete messages。
转换为 upsert 流的动态表需要(可能是组合的)唯一键。
消费流的算子需要知道唯一键的属性,以便正确地应用 message。
下图显示了将动态表转换为 upsert 流的过程。
与 retract 流的主要区别在于 UPDATE 操作是用单个 message 编码的,因此效率更高。
请注意,在将动态表转换为 DataStream 时,只支持 append 流和 retract 流。
参考:
https://nightlies.apache.org/flink/flink-docs-release-1.18/zh/docs/dev/table/concepts/dynamic_tables/#table-to-stream-conversion