在上一篇文章Flink 之 滚动窗口/滑动窗口/会话窗口/OVER窗口中分别介绍了 滚动窗口、滑动窗口、会话窗口以及OVER窗口,接下来本篇文章给大家介绍一下窗口中的最后一种:级联窗口。
一、概述
在 Flink 中,级联窗口是指多个窗口之间存在包含或重叠关系的数据处理模式。它允许我们在不同的时间范围内对数据进行聚合和分析。简单来说,就是将数据流分割成多个时间段(窗口)来处理,这些窗口可以是嵌套的,也可以是重叠的。
想象一下,我们有一个实时数据流,包含用户的点击数据。我们可能希望在不同的时间粒度上进行分析,比如每分钟、每小时和每天的点击量统计。级联窗口允许我们同时进行这些不同时间粒度的统计,而不需要多次遍历数据,这样可以复用中间计算结果,避免重复消费数据。
二、案例
请注意,Rowtime 列在经过窗口操作后,其 Event Time 属性将丢失,为了在下一个窗口继续使用水印功能,可以使用辅助函数 TUMBLE_ROWTIME 代替 TUMBLE_END,
此处以滚动窗口为例,同理:HOP_ROWTIME 代替 HOP_END ,SESSION_ROWTIME 代替 SESSION_END。
2.1 背景
假设你有一个在线购物平台的订单数据流,每条数据记录了订单的生成时间和订单金额。你希望通过级联窗口计算来实现以下目标:
- 每分钟计算订单总金额。
- 每3分钟计算前五分钟内每分钟订单总金额的平均值。
2.2 具体实现
2.2.1 代码
CREATE TEMPORARY TABLE orders (
order_id INT,
order_time TIMESTAMP(3),
amount DOUBLE,
WATERMARK FOR order_time AS order_time - INTERVAL '3' SECOND
) WITH (
'connector' = 'faker',
'fields.order_id.expression' = '#{number.numberBetween ''1'',''1000''}',
'fields.order_time.expression' = '#{date.past ''5'',''SECONDS''}',
'fields.amount.expression' = '#{number.randomDouble ''2'',''1'',''500''}'
);
CREATE TEMPORARY TABLE result1 (
window_start TIMESTAMP(3),
window_end TIMESTAMP(3),
total_amount DOUBLE
) WITH (
'connector' = 'print',
'logger'='true',
'print-identifier' = 'o1' -- 在日志中通过数据结果标识检索信息。
);
CREATE TEMPORARY TABLE result2 (
window_start_3m TIMESTAMP(3),
window_end_3m TIMESTAMP(3),
avg_amount DOUBLE
) WITH (
'connector' = 'print',
'logger'='true',
'print-identifier' = 'o2'
);
CREATE TEMPORARY VIEW orders_view
AS SELECT
TUMBLE_START(order_time, INTERVAL '1' MINUTE) AS window_start,
TUMBLE_ROWTIME(order_time, INTERVAL '1' MINUTE) AS window_end,
SUM(amount) AS total_amount
FROM orders
GROUP BY TUMBLE(order_time, INTERVAL '1' MINUTE);
;
BEGIN STATEMENT SET;
INSERT INTO result1
SELECT
window_start,
window_end,
total_amount
FROM orders_view
;
INSERT INTO result2
SELECT
TUMBLE_START(window_end, INTERVAL '3' MINUTE) AS window_start_3m,
TUMBLE_ROWTIME(window_end, INTERVAL '3' MINUTE) AS window_end_3m,
AVG(total_amount) AS avg_amount
FROM orders_view
GROUP BY TUMBLE(window_end, INTERVAL '3' MINUTE);
END;
2.2.2 结果
o1> +I[2024-08-08T00:11, 2024-08-08T00:11:59.999, 3.499849031999989E7]
o2> +I[2024-08-08T00:09, 2024-08-08T00:11:59.999, 3.499849031999989E7]
o1> +I[2024-08-08T00:12, 2024-08-08T00:12:59.999, 1.470114747000013E8]
o1> +I[2024-08-08T00:13, 2024-08-08T00:13:59.999, 1.4683286163000003E8]
o1> +I[2024-08-08T00:14, 2024-08-08T00:14:59.999, 1.472058926299993E8]
o2> +I[2024-08-08T00:12, 2024-08-08T00:14:59.999, 1.470167429866669E8]
o1> +I[2024-08-08T00:15, 2024-08-08T00:15:59.999, 1.4709021188999993E8]
o1> +I[2024-08-08T00:16, 2024-08-08T00:16:59.999, 1.470459928700004E8]
o1> +I[2024-08-08T00:17, 2024-08-08T00:17:59.999, 1.470872165200014E8]
o2> +I[2024-08-08T00:15, 2024-08-08T00:17:59.999, 1.470744737600006E8]
给大家展示前几条数据,其中, “o1” 标识的是每分钟聚合数据,“o2” 标识的是通过 “o1”数据得到的每3分钟聚合数据。
第一个“o1” 数据,它的窗口时间分别是:2024-08-08T00:11, 2024-08-08T00:11:59.999,SUM(amount) == 3.499849031999989E7;第一个“o2” 数据,它的窗口时间分别是:2024-08-08T00:09, 2024-08-08T00:11:59.999,AVG(amount) == 3.499849031999989E7,它俩窗口结束时间都是一样的,只不过 “o2”的开始时间比“o1” 早2分钟,窗口大小3分钟,而 “o1”窗口大小1分钟,符合逻辑。