在Table API和SQL中,Flink将数据看成是一张表,流数据就是一张无限追加的表,而批数据就是一张有限的数据表。这样的无限追加的表就称之为动态表。
动态表查询
动态表的查询结果还是一个动态表,也是一张无限追加的表 动态表查询结果可以分为两种:
-
新的数据进来之后,统计所有的历史数据,然后更新结果表。这种查询需要维护更多的状态。在不设置窗口处理的时候是这种查询。
-
新的数据进来之后,统一更新的部分,并将更新之后的数据追加到结果表中
时间字段 & Watermarks
对于无限增长的动态表处理,在不设置窗口的时候,如果不设置watermarks,那么无限的数据一定会是的内存OOM。
在Table API中如何定义watermarks呢:
定义Event time
定义在表DDL中
CREATE TABLE user_actions (
user_name STRING,
data STRING,
user_action_time TIMESTAMP(3),
-- 定义user_action_time作为event time并且延时5秒产生的Watermarks,不是Watermarks宽度
WATERMARK FOR user_action_time AS user_action_time - INTERVAL '5' SECOND
) WITH (
...
);
时间字段的类型可以是TIMESTAMP和TIMESTAMP_LTZ.
TIMESTAMP: 是不带有timezone的timestampTIMESTAMP_LTZ: 是带有本地timezone的timestamp
-- 设置timezone
SET table.local-time-zone=UTC;
定义在DataStream转换成Table中
stream = inputStream.assignTimestampAndWatermarks(...);
tEnv.fromDataStream(stream, $("user_name"),...,$("time").rowtime(),...);
定义在TableSource中
重写getRowtimeAttributeDescriptors(),重写这个方法来定义时间字段的名称
使用watermarks查询
SQL:
select TUMBLE_START(time, INTERVAL '10' MINUTE),COUNT(DINSTINCT user_name)
from table_name
group by TUMBLE(time, INTERVAL '10' MINUTE)
Table API:
table.window(Tumble.over(lit(10).minutes()))
.on($("time"))
.as("myWindow")
定义Processing Time
定义在表DDL中
CREATE TABLE user_actions (
user_name STRING,
data STRING,
-- 定义user_action_time作为processing time
user_action_time AS PROCTIME()
) WITH (
...
);
定义在DataStream转换成Table中
stream = inputStream.assignTimestampAndWatermarks(...);
Table table = tEnv.fromDataStream(stream, $("user_name"), $("data"), $("user_action_time").proctime());
定义在TableSource中
重写getProctimeAttribute(),重写这个方法来定义时间字段的名称
使用watermarks查询
SQL:
select TUMBLE_START(time, INTERVAL '10' MINUTE),COUNT(DINSTINCT user_name)
from table_name
group by TUMBLE(time, INTERVAL '10' MINUTE)
Table API:
table.window(Tumble.over(lit(10).minutes()))
.on($("time"))
.as("myWindow")
Table API中的窗口
- TUMBLE(滚动窗口):TUMBLE(time, INTERVAL '1' HOURS)
- HOP(滑动窗口):HOP(time, INTERVAL '2' HOURS, INTERVAL '1' HOURS,)
- SESSION(会话窗口):SESSION(time, INTERVAL '1' MINUTE)