Flink从入门到实战五[Window]-1-Window窗口

窗口
Windows是处理无限流的核心,Windows是将无限流通过一定条件切割为有限流的一种方式,它会将流数据分发到有限大小的桶(bucket)中进行分析。一个Window代表有限对象的集合,基于这个有限数据集合,进行计算。

窗口的生命周期
当属于该窗口的第一个元素到达时,就会创建一个窗口,当时间超过其结束时间戳加上用户指定的允许延迟时(这是Watermark的概念,后续章节会介绍),该窗口将被完全删除。

窗口分类
主要分为时间窗口、计数窗口、全局窗口,其中时间窗口和计数窗口又可以细分,如下:
• 时间窗口(Time Window)
➢ 滚动时间窗口
➢ 滑动时间窗口
➢ 会话窗口
• 计数窗口(Count Window)
➢ 滚动计数窗口
➢ 滑动计数窗口
• 全局窗口(Global Windows)

理解各种窗口
滚动窗口(Tumbling Windows)
依据固定的窗口长度对数据进行切分
时间对齐,窗口长度固定,没有重叠

API示例:

DataStream<T> input = ...;

// 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>);

滑动窗口(Sliding Windows)
可以按照固定的长度向后滑动固定的距离
滑动窗口由固定的窗口长度和滑动间隔组成
可以有重叠(是否重叠和滑动距离有关系)
滑动窗口是固定窗口的更广义的一种形式,滚动窗口可以看做是滑动窗口的一种特殊情况(即窗口大小和滑动间隔相等)

API示例:

DataStream<T> input = ...;

// 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>);

会话窗口(Session Windows)
由一系列事件组合一个指定时间长度的timeout间隙组成,也就是一段时间没有接收到新数据就会生成新的窗口
特点:时间无对齐

API 示例:

DataStream<T> input = ...;

// event-time session windows with static gap
input
    .keyBy(<key selector>)
    .window(EventTimeSessionWindows.withGap(Time.minutes(10)))
    .<windowed transformation>(<window function>);
    
// event-time session windows with dynamic gap
input
    .keyBy(<key selector>)
    .window(EventTimeSessionWindows.withDynamicGap((element) -> {
        // determine and return session gap
    }))
    .<windowed transformation>(<window function>);

// processing-time session windows with static gap
input
    .keyBy(<key selector>)
    .window(ProcessingTimeSessionWindows.withGap(Time.minutes(10)))
    .<windowed transformation>(<window function>);
    
// processing-time session windows with dynamic gap
input
    .keyBy(<key selector>)
    .window(ProcessingTimeSessionWindows.withDynamicGap((element) -> {
        // determine and return session gap
    }))
    .<windowed transformation>(<window function>);

全局窗口(Global Windows)
所有元素都分配到同一个窗口。

API示例:

DataStream<T> input = ...;

input
    .keyBy(<key selector>)
    .window(GlobalWindows.create())
    .<windowed transformation>(<window function>);

Window API
window分为基于key的window和不基于key的window。
用.window()来定义一个窗口,然后基于这个window去做一些聚合或者其他处理操作,window()方法必须在keyBy之后才能使用。
用.windowAll()来定义一个窗口,则创建了一个不基于key的窗口。

Flink提供了更加简单的.timeWindow()和.countWindow()方法,用于定义时间窗口和计数窗口。

DataStream<Tuple2<String,Double>> minTempPerWindowStream = 
  datastream
  .map(new MyMapper())
  .keyBy(data -> data.f0)
  .timeWindow(Time.seconds(15))
  .minBy(1);

窗口函数分类
增量聚合函数
增量聚合函数,特点即每次数据过来都处理,但是到了窗口临界才输出结果。
1.ReduceFunction
增量聚合,输入输出元素类型相同。
2.AggregateFunction
增量聚合,输入输出元素类型可以不相同。

全窗口函数 (WindowFunction和ProcessWindowFunction,后者更全面)
全窗口函数,特点即数据过来先不处理,等到窗口临界再遍历、计算、输出结果。
ProcessWindowFunction
  一些业务场景,我们需要收集窗口内所有的数据进行计算,例如计算窗口数据的中位数,或者计算窗口数据中出现频率最高的值。这样的需求,使用ReduceFunction和AggregateFunction就无法实现了。这个时候就需要ProcessWindowFunction了。

WindowFunction是就版本API使用的,目前保留在API里,推荐还是使用ProcessWindowFunction。

到此对窗口已经有了一个整体的了解,接下来会详细介绍窗口的使用方法。