Window可以理解为Flink中流数据的一种分组方式,它其中只定义了一个方法maxTimestamp(),表示该window时间跨度所能包含的最大时间点(用时间戳表示)。 Window类有两个子类,分别是GlobalWindow和TimeWindow。前者是全局窗口,该窗口通过单例模式保证其只存在一个实例。而后者则是定义了明确起止时间的 时间窗口,它其中还定义了一些Window的计算方法,比如判断是否有交集intersects()方法,求并集的cover()等方法。

如果对一个流进行window操作,流中的元素会以它们的key(由keyBy函数指定)和它们所属的window进行分组,位于相同key和相同窗口的一组元素称之为窗格。 在Flink中,window和window中的数据以key-value对的形式存放(形成windowState,它以HeapListState的方式储存,在WindowOperator中定义)。 每次Flink接收到一个元素,都会通过一个特定的方法获取到该元素应该属于的window集合(也就是assignWindows方法),并将该元素加入到状态表中。WindowAssigner 的主要作用之一就是通过assignWindows()方法规定应该如何根据一个元素来确定它所属的窗口集合。此外,它还包含窗口的触发机制(也就是应该何时计算窗口内的 元素)、窗口的序列化器和是否EventTime时间类型。

WindowAssigner类是一个抽象类,其中定义的方法在其中都没有具体的实现,而GlobalWindows是其的一个子类,该类用于将所有的元素分配给同一个GlobalWindow。 它的应用场景之一是为CountWindow分配元素,即每累计n个元素触发一次计算。除了GlobalWindows,还有三类主要窗口,它们在实际的生产场景中用的非常之多, 分别是滚动窗口、滑动窗口和Session窗口,它们针对ProcessingTime和EventTime都有其对应的实现。

GlobalWindows是GlobalWindow的分配器,它负责为元素分配所属的Window(也就是GlobalWindow)。它的一个典型的应用场景是CountWindow,即每累计够n个 元素就触发计算的窗口。

TumblingEventTimeWindows是基于事件时间的滚动窗口,其具有两个属性,分别是窗口的大小和偏移量(这个偏移主要用于控制窗口的起始时间),相邻窗口之间 没有重叠,一个元素一定会也只可能会属于一个窗口。而SlidingEventTimeWindows是基于事件时间的滑动窗口,其具有三个属性,分别是窗口大小、窗口每次滑动的 距离以及窗口的偏移量。在滑动窗口的场景下,一个元素可以属于多个窗口(只要窗口滑动的距离小于窗口的大小),也可以不属于任何窗口(只要窗口滑动的距离大于窗 口的大小)。

MergingWindowAssigner扩展了WindowAssigner,它能对窗口进行合并。在所有SessionWindow的实现中,都会扩展MergingWindowAssigner类并对mergeWindows() 方法进行实现,以支持对窗口的合并操作。该方法包含有一个MergeCallback对象,用于在合并窗口的时候给出通知,执行一些额外的逻辑。SessionWindow都具有 一个属性:sessionTimeout,它表示属于同一个SessionWindow的元素,其任意两个相邻的元素之间的时间差都不比它小,否则后到的元素就会进入新的窗口之中。 EventTimeSessionWindows是MergingWindowAssigner基于事件时间的扩展,从它的assignWindows()方法中可以看到,每当一个元素到来时都会创建一个新 的窗口,后面会再调用mergeWindows()方法对有重合的窗口进行合并。合并逻辑在TimeWindow.mergeWindows()方法中实现,也不是很复杂:首先对所有待合并的 窗口按照起始时间进行排序,然后创建两个变量,变量currentMerge用于存储当前合并的窗口(存放方式是一个二元组,第一个元素存放合并后的窗口,第二个元素存放 被合并的所有窗口),另一个变量merged用于存放多组合并结果(前面合并的窗口的集合)。然后对排序后的每个窗口,如果当前合并窗口为空,则不需要处理,直接放入 变量。如果已合并的窗口和待处理的窗口在时间上有交集,就取这两个窗口时间的并集,并将其赋值给currentMerge二元祖的第一个参数,将待处理窗口放入到二元组 的第二个参数集合中去。如果没有交集则将合并窗口currentMerge放入合并窗口集合merged中,其余的处理与合并窗口为空时的处理一致。如果合并窗口集合merged 中的被合并窗口数多于一个,表明窗口需要进行合并,此时需要通知窗口进行真正的合并操作。

DynamicEventTimeSessionWindows也扩展了MergingWindowAssigner类,但它的不同之处在于它的sessionTimeout是动态的,在每次调用assignWindows() 方法动态分配窗口时会先调用其内部维护的SessionWindowTimeGapExtractor类对象的extract()方法来根据进入窗口的元素和sessionTimeout的函数关系获取 sessionTimeout的取值。ProcessingTime的各种窗口分配类的处理方式与针对event time的处理方式类似,只是在assignWindows()方法中会调用WindowAssignerContext 类的getCurrentProcessingTime()获取当前的处理时间,其余的处理逻辑基本类似。