窗口 API 概览

1.按键分区(Keyed)和非按键分区(Non-Keyed)

介绍

在定义窗口操作之前,首先需要确定,到底是基于按键分区(Keyed)的数据流 KeyedStream
来开窗,还是直接在没有按键分区的 DataStream 上开窗。也就是说,在调用窗口算子之前,
是否有 keyBy()操作。

(1)按键分区窗口(Keyed Windows)

经过按键分区 keyBy()操作后,数据流会按照 key 被分为多条逻辑流(logical streams),这
就是 KeyedStream。基于 KeyedStream 进行窗口操作时, 窗口计算会在多个并行子任务上同时
执行。相同 key 的数据会被发送到同一个并行子任务,而窗口操作会基于每个 key 进行单独的
处理。所以可以认为,每个 key 上都定义了一组窗口,各自独立地进行统计计算。
在代码实现上,我们需要先对DataStream调用keyBy()进行按键分区,然后再调用window()
定义窗口。

stream.keyBy(...)
 .window(...)

(2)非按键分区(Non-Keyed Windows)

如果没有进行 keyBy(),那么原始的 DataStream 就不会分成多条逻辑流。这时窗口逻辑只
能在一个任务(task)上执行,就相当于并行度变成了 1。所以在实际应用中一般不推荐使用
这种方式。
在代码中,直接基于 DataStream 调用 windowAll()定义窗口。

stream.windowAll(...)

这里需要注意的是,对于非按键分区的窗口操作,手动调大窗口算子的并行度也是无效的,
96
windowAll 本身就是一个非并行的操作。

2. 代码中窗口 API 的调用

有了前置的基础,接下来我们就可以真正在代码中实现一个窗口操作了。简单来说,窗口
操作主要有两个部分:窗口分配器(Window Assigners)和窗口函数(Window Functions)。

stream.keyBy(<key selector>)
 .window(<window assigner>)
 .aggregate(<window function>)

其中.window()方法需要传入一个窗口分配器,它指明了窗口的类型;而后面的.aggregate()
方法传入一个窗口函数作为参数,它用来定义窗口具体的处理逻辑。窗口分配器有各种形式,
而窗口函数的调用方法也不只.aggregate()一种,我们接下来就详细展开讲解。
另外,在实际应用中,一般都需要并行执行任务,非按键分区很少用到,所以我们之后都
以按键分区窗口为例;如果想要实现非按键分区窗口,只要前面不做 keyBy(),后面调用
window()时直接换成 windowAll()就可以了。

窗口分配器(Window Assigners)

介绍

定义窗口分配器(Window Assigners)是构建窗口算子的第一步,它的作用就是定义数据
应该被“分配”到哪个窗口。而窗口分配数据的规则,其实就对应着不同的窗口类型。所以可
以说,窗口分配器其实就是在指定窗口的类型。
窗口分配器最通用的定义方式,就是调用 window()方法。这个方法需要传入一个
WindowAssigner 作为参数,返回 WindowedStream。如果是非按键分区窗口,那么直接调用
windowAll()方法,同样传入一个 WindowAssigner,返回的是 AllWindowedStream。
窗口按照驱动类型可以分成时间窗口和计数窗口,而按照具体的分配规则,又有滚动窗口、
滑动窗口、会话窗口、全局窗口四种。除去需要自定义的全局窗口外,其他常用的类型 Flink
中都给出了内置的分配器实现,我们可以方便地调用实现各种需求

1. 时间窗口

时间窗口是最常用的窗口类型,又可以细分为滚动、滑动和会话三种。

(1)滚动处理时间窗口

窗口分配器由类 TumblingProcessingTimeWindows 提供,需要调用它的静态方法 of()。

stream.keyBy(...)
.window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
.aggregate(...)

这里 of()方法需要传入一个 Time 类型的参数 size,表示滚动窗口的大小,我们这里创建
了一个长度为 5 秒的滚动窗口。
另外,of()还有一个重载方法,可以传入两个 Time 类型的参数:size 和 offset。第一个参
数当然还是窗口大小,第二个参数则表示窗口起始点的偏移量。

(2)滑动处理时间窗口

窗口分配器由类 SlidingProcessingTimeWindows 提供,同样需要调用它的静态方法 of()。

stream.keyBy(...)
.window(SlidingProcessingTimeWindows.of(Time.seconds(10), Time.seconds(5)))
.aggregate(...)

这里 of()方法需要传入两个 Time 类型的参数:size 和 slide,前者表示滑动窗口的大小,
后者表示滑动窗口的滑动步长。我们这里创建了一个长度为 10 秒、滑动步长为 5 秒的滑动窗
口。
滑动窗口同样可以追加第三个参数,用于指定窗口起始点的偏移量,用法与滚动窗口完全
一致。

(3)处理时间会话窗口

窗口分配器由类 ProcessingTimeSessionWindows 提供,需要调用它的静态方法 withGap()
或者 withDynamicGap()。

stream.keyBy(...)
.window(ProcessingTimeSessionWindows.withGap(Time.seconds(10)))
.aggregate(...)

这里.withGap()方法需要传入一个 Time 类型的参数 size,表示会话的超时时间,也就是最
小间隔 session gap。我们这里创建了静态会话超时时间为 10 秒的会话窗口。

.window(ProcessingTimeSessionWindows.withDynamicGap(new 
SessionWindowTimeGapExtractor[(String, Long)] {
 override def extract(element: (String, Long)) { 
// 提取 session gap 值返回, 单位毫秒
 element._1.length * 1000
 }
}))

这里 withDynamicGap()方法需要传入一个 SessionWindowTimeGapExtractor 作为参数,用
来定义 session gap 的动态提取逻辑。在这里,我们提取了数据元素的第一个字段,用它的长
度乘以 1000 作为会话超时的间隔。

(4)滚动事件时间窗口

窗口分配器由类 TumblingEventTimeWindows 提供,用法与滚动处理事件窗口完全一致。

stream.keyBy(...)
.window(TumblingEventTimeWindows.of(Time.seconds(5)))
.aggregate(...)

这里 of()方法也可以传入第二个参数 offset,用于设置窗口起始点的偏移量。

(5)滑动事件时间窗口

窗口分配器由类 SlidingEventTimeWindows 提供,用法与滑动处理事件窗口完全一致。

stream.keyBy(...)
.window(SlidingEventTimeWindows.of(Time.seconds(10), Time.seconds(5)))
.aggregate(...)

(6)事件时间会话窗口

窗口分配器由类 EventTimeSessionWindows 提供,用法与处理事件会话窗口完全一致。

stream.keyBy(...)
.window(EventTimeSessionWindows.withGap(Time.seconds(10)))
.aggregate(...)

2. 计数窗口

计数窗口概念非常简单,本身底层是基于全局窗口(Global Window)实现的。Flink为我们提供了非常方便的接口:直接调用countWindow()方法。根据分配规则的不同,又可以分为滚动计数窗口和滑动计数窗口两类,下面我们就来看它们的具体实现。

(1)滚动计数窗口

滚动计数窗口只需要传入一个长整型的参数size,表示窗口的大小。

stream.keyBy(...)
.countWindow(10)

我们定义了一个长度为 10 的滚动计数窗口,当窗口中元素数量达到 10 的时候,就会触发
计算执行并关闭窗口。

(2)滑动计数窗口

与滚动计数窗口类似,不过需要在 countWindow()调用时传入两个参数:size 和 slide,前
者表示窗口大小,后者表示滑动步长。

stream.keyBy(...)
.countWindow(103)

我们定义了一个长度为 10、滑动步长为 3 的滑动计数窗口。每个窗口统计 10 个数据,每
隔 3 个数据就统计输出一次结果.

3. 全局窗口

全局窗口是计数窗口的底层实现,一般在需要自定义窗口时使用。它的定义同样是直接调
用 window(),分配器由 GlobalWindows 类提供。

stream.keyBy(...)
.window(GlobalWindows.create())

需要注意使用全局窗口,必须自行定义触发器才能实现窗口计算,否则起不到任何作用。

  • 22
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值