FlinkSQL-动态表和持续查询
详细说明下Flink流中表的概念,这里与关系型数据库的表进行对比。
| 关系型数据库表 | Flink流处理表 | |
|---|---|---|
| 处理的数据对象 | 字段元组的有界集合 | 字段元组的无限序列 |
| 查询Query对数据的访问 | 可以访问到完整的输入 | 无法访问到所有数据,必须持续等待流式输入 |
| 查询终止条件 | 生成固定大小的结果集后终止 | 永不停止,根据持续收到的数据不断更新结果集 |
从概念来说,关系型数据库表针对批数据进行处理,流处理表针对流式数据进行处理。
动态表
Dynamic Tables,先说说动态表的概念,动态表是Flink Table/SQL的概念,在数据流中,数据记录是源源不断的,通过流创建的数据表在不断发生动态变化,这就是动态表。
持续查询
Continuous Query,对动态表可进行查询,由于数据是不断变化的,因此对动态表的查询也是不断变化的,一致随着新数据的到来而继续执行,这样的查询被称为持续查询。持续查询的结果也是一个动态表。

持续查询的步骤:
1)流被转换为动态表
2)对动态表进行持续查询,生成新的动态表
3)生成的动态表被转换成流
持续查询结果转换成流(Stream)
- 对于简单的持续查询,例如select user,age from user_info,持续查询的结果是不会对原始数据发生变化的,这种属于追加查询,直接调用toDataStream方法将动态表转换成流
java
//查询mysql数据库test下tb1表
Table table = tabEnv.sqlQuery("select * from tb1");
//将table转换成DataStream并控制台输出
tabEnv.toDataStream(table).print()
- 对于聚合操作的持续查询,例如select user_id,count(1) from user_info,持续查询的结果会随着数据流的到来发生更新,这种属于更新查询,调用toChangelogStream方法将动态表转换成流
java
Table table = tabEnv.sqlQuery("select user_id,count(1) from test_topic group by user_id");
//table对象转换成toChangelogStream 因为涉及到更新
DataStream<Row> rowDataStream = tabEnv.toChangelogStream(table);
不同持续查询下的编码方式
动态表也可以实现INSERT、UPDATE、DELETE进行持续的操作,将动态表转换成流或者写入外部系统需要对这些编码进行处理。通过发送的编码的方式告诉外部系统要执行的操作。
- 仅追加流Apend
+I代表插入
- 撤回流Retract 包含了add消息和撤回消息
+U代表新增 -U代表删除
shell
+I[123, 1] 第一次插入 +I
-U[123, 1] 修改操作 先标识删除
+U[123, 2] 修改操作 后标识插入
-U[123, 2] .....
+U[123, 3]
-U[123, 3]
+U[123, 4]
- 更新插入流(Upsert)
时间属性
DataStreamApI时间语义上有事件时间以及处理时间,当然TableAPI也有这两个时间语义。
事件时间事项可以在DDL创建表时指定,通过增加一个字段,用Watermark语句来定义。、
sql
CREATE TABLE test_topic (
user_id BIGINT,
item_id BIGINT,
ts BIGINT,
event_time AS TO_TIMESTAMP_LTZ(ts, 3),
WATERMARK FOR event_time AS event_time - INTERVAL '60' SECOND --定义事件时间
) WITH (
'connector' = 'kafka',
'topic' = 'Test-Topic',
'properties.bootstrap.servers' = 'hb1:9092,hb2:9092,hb3:9092',
'properties.group.id' = 'flink_sql_group',
'scan.startup.mode' = 'earliest-offset',
'format' = 'json',
'json.fail-on-missing-field' = 'false',
'json.ignore-parse-errors' = 'true'
);
ts字段表示事件时间,设置水位线将延迟水位设置60s
处理时间语义呢,在DDL时通过额外声明一个字段,来保存处理时间。
sql
CREATE TABLE test_topic (
user_id BIGINT,
item_id BIGINT,
ts AS PROCTIME() --处理时间
) WITH (
'connector' = 'kafka',
'topic' = 'Test-Topic',
'properties.bootstrap.servers' = 'hb1:9092,hb2:9092,hb3:9092',
'properties.group.id' = 'flink_sql_group',
'scan.startup.mode' = 'earliest-offset',
'format' = 'json',
'json.fail-on-missing-field' = 'false',
'json.ignore-parse-errors' = 'true'
);
数据输入:{"user_id":124,"item_id":123} ...
数据输出:
