概念
Window
Stream流数据是源源不断,永无止境的,而我们一般将这些流数据按照一定规则划分成一段一段的有限范围,比如按照一定数量切分,或者按照时间窗口切分。这样就将整体的无限,转化成了一段段连续(有时候会有重叠)的有限,这样我们才有能力去处理它,并且也符合实际的需求,比如每5分钟活跃人数,新增人数,转化率等等。
window function 包含了作用于window范围内数据的计算逻辑,主要有ProcessWindowFunction
, ReduceFunction
, AggregateFunction
or FoldFunction
规定了启动window function对window内容数据的计算的触发条件,比如当前window数据条数达到了一定的阈值,或者窗口允许的最大延迟数据已经到达
Window 流是否keyBy
keyBy可以提高window流数据操作的并行度,而非keyBy的则只能是单并行度。
window算子方面,keyBy是window(), 非keyBy是windowAll()
Window的类型
tumbling window
该类型window的特点是每个window划分成首尾相接,没有重叠部分,一个窗口结束后,马上开始新的窗口,任意一条数据只可能属于一个窗口,不能属于多个窗口,从下面的window示意图看,这一特点一目了然。这一点是不同于下面的sliding window的。
需要说明的是,window在指定好窗口大小后,各个窗口其实就已经划分好了,因为划分窗口的语句是,根据窗口大小,采用自然时间来划分窗口,与具体的数据无关。比如指定窗口大小为5秒后,则所有的窗口其实就已经划分好了,划分好的窗口如下所示
[1970-01-01T00:00:00.000, 1970-01-01T00:00:04.999],
[1970-01-01T00:00:05.000, 1970-01-01T00:00:09.999],
[1970-01-01T00:00:10.000, 1970-01-01T00:00:14.999],
[1970-01-01T00:00:15.000, 1970-01-01T00:00:19.999],
[1970-01-01T00:00:20.000, 1970-01-01T00:00:24.999],
....
任意一条数据来到之后,根据其数据时间,将其分派到其所属的时间窗口内,当某一条到来的数据的时间大于等于某个时间窗口的结束时间,并且该窗口还有数据的话,就启动对该窗口数据的计算,比如到来一条数据时间是1970-01-01T00:00:04.999, 则立马触发对window [1970-01-01T00:00:00.000, 1970-01-01T00:00:04.999] 的数据计算。当进来一条数据时间为1970-01-01T00:00:11,而window [1970-01-01T00:00:05.000, 1970-01-01T00:00:09.999]还未触发计算,并且其中还有数据话,则该窗口立马触发计算。
tumbling window 示例代码
val input: DataStream[T] = ...
// tumbling event-time windows
input
.keyBy(<key selector>)
.window(TumblingEventTimeWindows.of(Time.seconds(5)))
.<windowed transformation>(<window function>)
// tumbling processing-time windows
input
.keyBy(<key selector>)
.window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
.<windowed transformation>(<window function>)
// daily tumbling event-time windows offset by -8 hours.
input
.keyBy(<key selector>)
.window(TumblingEventTimeWindows.of(Time.days(1), Time.hours(-8)))
.<windowed transformation>(<window function>)
需要注意的是代码示例的最后一个例子,多了一个offset参数,该参数可以更改窗口划分时,窗口的起始时间。
sliding window
顾名思义,这是滑动窗口,该类型要比tumbling window复杂一些,它除了有window窗口时间外,还有滑动步长,当滑动步长小于窗口大小时,相邻窗口是有重叠的,这一点需要特别注意,下面是滑动窗口的示意图
sliding window 示例代码
val input: DataStream[T] = ...
// sliding event-time windows
input
.keyBy(<key selector>)
.window(SlidingEventTimeWindows.of(Time.seconds(10), Time.seconds(5)))
.<windowed transformation>(<window function>)
// sliding processing-time windows
input
.keyBy(<key selector>)
.window(SlidingProcessingTimeWindows.of(Time.seconds(10), Time.seconds(5)))
.<windowed transformation>(<window function>)
// sliding processing-time windows offset by -8 hours
input
.keyBy(<key selector>)
.window(SlidingProcessingTimeWindows.of(Time.hours(12), Time.hours(1), Time.hours(-8)))
.<windowed transformation>(<window function>)