文章目录
一、概述
窗口是无限流上一种核心机制,可以流分割为有限大小的“窗口”,同时,在窗口内进行聚合,从而把源源不断产生的数据根据不同的条件划分成一段一段有边界的数据区间,使用户能够利用窗口功能实现很多复杂的统计分析需求。
本文内容:
- Flink SQL WINDOW功能介绍
- 底层实现源码分析:StreamExecGroupWindowAggregate创建WindowOperator
- 底层实现源码分析:WindowOperator算子处理数据这两个地方源码分析。
二、Window分类
1、TimeWindow与CountWindow
Flink Window可以是时间驱动的(TimeWindow),也可以是数据驱动的(CountWindow)
由于flink-planner-blink SQL中目前只支持TimeWindow相应的表达语句(TUMBLE、HOP、SESSION),因此,本文主要介绍TimeWindow SQL示例和逻辑,CountWindow感兴趣的读者可自行分析。
2、TimeWindow子类型
Flink TimeWindow有滑动窗口(HOP)、滚动窗口(TUMBLE)以及会话窗口(SESSION)三种,所选取的字段时间,可以是系统时间(PROCTIME)或事件时间(EVENT TIME)两种,接来下依次介绍
I、Tumble Window(翻转窗口)
翻转窗口Assigner将每个元素分配给具有指定大小的窗口。翻转窗口的大小是固定的,且不会重叠。例如,指定一个大小为5分钟的翻滚窗口,并每5分钟启动一个新窗口,如下图所示
TUMBLE ROWTIME语法示例:
CREATE TABLE sessionOrderTableRowtime (
ctime TIMESTAMP,
categoryName VARCHAR,
shopName VARCHAR,
itemName VARCHAR,
userId VARCHAR,
price FLOAT,
action BIGINT,
WATERMARK FOR ctime AS withOffset(ctime, 1000),
proc AS PROCTIME()
) with (
`type` = 'kafka',
format = 'json',
updateMode = 'append',
`group.id` = 'groupId',
bootstrap.servers = 'xxxxx:9092',
version = '0.10',
`zookeeper.connect` = 'xxxxx:2181',
startingOffsets = 'latest',
topic = 'sessionsourceproctime'
);
CREATE TABLE popwindowsink (
countA BIGINT,
ctime_start TIMESTAMP,
ctime_end VARCHAR,
ctime_rowtime VARCHAR,
categoryName VARCHAR,
price_sum FLOAT
) with (
format = 'json',
updateMode = 'append',
bootstrap.servers = 'xxxxx:9092',
version = '0.10',
topic = 'sessionsinkproctime',
`type` = 'kafka'
);
INSERT INTO popwindowsink
(SELECT
COUNT(*),
TUMBLE_START(ctime, INTERVAL '5' MINUTE),
DATE_FORMAT(TUMBLE_END(ctime, INTERVAL '5' MINUTE), 'yyyy-MM-dd-HH-mm-ss:SSS'), --将TUMBLE_END转为可视化的日期
DATE_FORMAT(TUMBLE_ROWTIME(ctime, INTERVAL '5' MINUTE), 'yyyy-MM-dd-HH-mm-ss:SSS'), --这里TUMBLE_ROWTIME为TUMBLE_END-1ms,一般用于后续窗口级联聚合
categoryName,
SUM(price)
FROM sessionOrderTableRowtime
GROUP BY TUMBLE(ctime, INTERVAL '5' MINUTE), categoryName)
TUMBLE_ROWTIME、TUMBLE_PROCTIME、HOP_ROWTIME的使用介绍可参考阿里流计算相应文章:https://help.aliyun.com/document_detail/62511.html?spm=a2c4g.11186623.6.644.65ff18a0DKJzwG
TUMBLEP ROCTIME语法示例:
INSERT INTO popwindowsink
(SELECT
COUNT(*),
TUMBLE_START(proc, INTERVAL '5' MINUTE),
DATE_FORMAT(TUMBLE_END(proc, INTERVAL '5' MINUTE), 'yyyy-MM-dd-HH-mm-ss:SSS'),
DATE_FORMAT(TUMBLE_PROCTIME(proc, INTERVAL '5' MINUTE), 'yyyy-MM-dd-HH-mm-ss:SSS'), --注意这里proc字段即Source DDL中指定的PROCTIME
categoryName,
SUM(price)
FROM sessionOrderTableRowtime
GROUP BY TUMBLE(proc, INTERVAL '5' MINUTE), categoryName)
ROWTIME与PROCTIME区别:
- 在使用上: 主要是填入的ctime、proc关键字的区别,这两个字段在Source DDL中指定方式不一样
- 在实现原理上: ROWTIME模式,根据ctime对应的值,去确定窗口的start、end;PROCTIME模式,在WindowOperator处理数据时,获取本地系统时间,去确定窗口的start、end
由于生产系统中,主要使用ROWTIME来计算、聚合、统计,PROCTIME一般用于测试或对统计精度要求不高的场景,本文后续都主要以ROWTIME进行分析
II、Hop Window(滑动窗口)
滑动窗口Assigner将元素分配给多个固定长度的窗口。类似于滚动窗口分配程序,窗口的大小由窗口大小参数配置。因此,如果滑动窗口小于窗口大小,则滑动窗口可以重叠。在这种情况下,元素被分配到多个窗口。其实,滚动窗口TUMBLE是滑动窗口的一个特例。
例子,设置一个10分钟长度的窗口,以5分钟间隔滑动。这样,每5分钟就会出现一个窗口,其中包含最近10分钟内到达的事件,如下图:
HOP ROWTIME语法示例:
INSERT INTO popwindowsink
(SELECT
COUNT(*),
HOP_START(ctime, INTERVAL '5' MINUTE, INTERVAL '10' MINUTE),
DATE_FORMAT(HOP_END(ctime, INTERVAL '5' MINUTE, INTERVAL '10' MINUTE), 'yyyy-MM-dd-HH-mm-ss:SSS'),
DATE_FORMAT(HOP_ROWTIME(ctime, INTERVAL '5' MINUTE, INTERVAL '10