一、窗口
窗口(Window)是处理无界流的关键所在。窗口将流分成有限大小的“桶”,我们可以在其上应用算子计算。Flink可以使用window()和windowAll()定义一个窗口,二者都需要传入一个窗口分配器WindowAssigner,WindowAssigner负责分配事件到相应的窗口。
window()作用于KeyedStream上,即keyBy()之后,这样可以多任务并行计算,对窗口内的多组数据分别进行聚合;windowAll()作用于非KeyedStream上(通常指DataStream),由于所有元素都必须通过相同的算子实例,因此该操作本质上是非并行的,仅在特殊情况下(例如对齐的时间窗口)才可以并行执行。假设要计算24小时内每个用户的订单平均消费额,就需要使用window()定义窗口;如果要计算24小时内的所有订单平均消费额,则需要使用windowAll()定义窗口。
一个Flink窗口程序的大致骨架结构如下:
对KeyedStream应用window()函数进行窗口计算:
对非KeyedStream应用windowAll()函数进行窗口计算:
上面方括号([…])中的命令是可选的。也就是说,Flink 允许你自定义多样化的窗口操作来满足你的需求。
首先必须要在定义窗口前确定的是你的 stream 是 keyed 还是 non-keyed。 keyBy(…) 会将你的无界 stream 分割为逻辑上的 keyed stream。 如果 keyBy(…) 没有被调用,你的 stream 就不是 keyed。
对于 keyed stream,其中数据的任何属性都可以作为 key。 使用 keyed stream 允许你的窗口计算由多个 task 并行,因为每个逻辑上的 keyed stream 都可以被单独处理。 属于同一个 key 的元素会被发送到同一个 task。
对于 non-keyed stream,原始的 stream 不会被分割为多个逻辑上的 stream, 所以所有的窗口计算会被同一个 task 完成,也就是 parallelism 为 1。
二、窗口的分类
Flink的窗口可以分为滚动窗口、滑动窗口、会话窗口、全局窗口,且每种窗口又可分别根据事件时间和处理时间进行创建。
2.1 滚动窗口(Tumbling Windows)
滚动窗口的 assigner 分发元素到指定大小的窗口。滚动窗口的大小是固定的,且各自范围之间不重叠。 比如说,如果你指定了滚动窗口的大小为 5 分钟,那么每 5 分钟就会有一个窗口被计算,且一个新的窗口被创建(如下图所示)。
滚动窗口使用时需要指定窗口大小参数,下面的代码片段展示了如何使用滚动窗口:
滚动窗口分配器还可以使用可选的偏移(Offset)参数,该参数可用于更改窗口的对齐方式。例如,在没有偏移的情况下,时间窗口会做一个对齐,那么1小时窗口的起止时间可以是[0:00:00.000~0:59:59.999)。如果你想要一个以小时为单位的窗口流,但是窗口需要从每个小时的第15分钟开始,则可以使用偏移量,代码如下:
TumblingEventTimeWindows.of(Time.hours(1),Time.minutes(15))
那么窗口的起止时间将变为[0:15:00.000~1:14:59.999),这样你将得到起始时间在0:15:00,1:15:00,2:15:00的窗口。与此相反,如果你生活在不使用UTC±00:00时间(世界标准时间)的地方,例如中国使用UTC+08:00,中国的当地时间要设置偏移量为Time.hours(-8)。你想要一个一天大小的时间窗口,并且窗口从当地时间的每一个00:00:00开始,可以使用
TumblingEventTimeWindows.of(Time.days(1),