Streaming -- Operators -- Windows

窗口是处理无限流的核心。Windows将流分割成有限大小的"桶",我们可以在这些桶上进行计算。本文档主要介绍在Flink中如何执行窗口,以及程序员如何从它提供的功能中获得最大的好处。

窗口Flink程序的一般结构如下所示。第一个片段引用键控流,而第二个片段引用非键控流。可以看到,唯一的区别是键控流的keyBy(…)调用和非键控流的window(…)调用。这也将作为页面其余部分的路线图。

Keyed Windows
stream
       .keyBy(...)               <-  keyed versus non-keyed windows
       .window(...)              <-  required: "assigner"
      [.trigger(...)]            <-  optional: "trigger" (else default trigger)
      [.evictor(...)]            <-  optional: "evictor" (else no evictor)
      [.allowedLateness(...)]    <-  optional: "lateness" (else zero)
      [.sideOutputLateData(...)] <-  optional: "output tag" (else no side output for late data)
       .reduce/aggregate/fold/apply()      <-  required: "function"
      [.getSideOutput(...)]      <-  optional: "output tag"
Non-Keyed Windows
stream
       .windowAll(...)           <-  required: "assigner"
      [.trigger(...)]            <-  optional: "trigger" (else default trigger)
      [.evictor(...)]            <-  optional: "evictor" (else no evictor)
      [.allowedLateness(...)]    <-  optional: "lateness" (else zero)
      [.sideOutputLateData(...)] <-  optional: "output tag" (else no side output for late data)
       .reduce/aggregate/fold/apply()      <-  required: "function"
      [.getSideOutput(...)]      <-  optional: "output tag"

在上面,方括号([])中的命令是可选的。这表明,Flink允许您以许多不同的方式定制窗口逻辑,以便它最适合您的需要。

Window Lifecycle

简而言之,当应该属于该窗口的第一个元素到达时,就会创建一个窗口,当时间(事件或处理时间)经过其结束时间戳加上用户指定的允许延迟(参见允许延迟)时,该窗口将被完全删除。Flink保证只删除基于时间的窗口,而不删除其他类型的窗口,例如全局窗口(参见窗口分配程序)。例如,event-time-based窗口策略创建重叠(暴跌)窗户每5分钟,有一个允许迟到1分钟,Flink将创建一个新窗口为12点之间的间隔和12:05当第一个元素和一个时间戳,在这个间隔到来时,它会删除它当水印经过12:06时间戳。

此外,每个窗口都将具有一个触发器(请参见触发器)和一个函数(请参见ProcessWindowFunction,ReduceFunction,AggregateFunction或FoldFunction)(请参见窗口函数)。 该函数将包含要应用于窗口内容的计算,而触发器指定条件,在该条件下,可以认为该窗口已准备就绪,可以应用该函数。 触发策略可能类似于“当窗口中的元素数大于4时”或“当水印通过窗口末尾时”。 触发器还可以决定在创建和删除窗口之间的任何时间清除窗口的内容。 在这种情况下,清除仅是指窗口中的元素,而不是窗口元数据。 这意味着仍可以将新数据添加到该窗口。

除上述内容外,您还可以指定一个Evictor(请参阅Evictors),该触发器将在触发触发器后以及应用此功能之前和/或之后从窗口中删除元素。

下面我们将详细介绍上述每个组件。我们先从上面代码片段中需要的部分开始(参见Keyed vs Non-Keyed Windows, Window Assigner, and Window Function),然后再转移到可选的部分

Keyed vs Non-Keyed Windows

首先要指定的是您的流是否应该设置键控。这必须在定义窗口之前完成。使用keyBy(…)将无限流分割成逻辑键控流。如果没有调用keyBy(…),则流没有键控。

在键控流的情况下,传入事件的任何属性都可以用作键(这里有更多细节)。拥有一个键控流将允许你的窗口计算由多个任务并行执行,因为每个逻辑键控流都可以独立于其他任务进行处理。所有引用相同键的元素将被发送到相同的并行任务。

在非键控流的情况下,你的原始流不会被分割成多个逻辑流,所有的窗口逻辑将由一个任务执行,即并行度为1。

Window Assigners

在指定流是否是键控的之后,下一步是定义一个窗口分配器。窗口分配者定义如何将元素分配给窗口。这是通过在window(…)(对于键控流)或windowAll()(对于非键控流)调用中指定您选择的WindowAssigner来完成的。

WindowAssigner负责将每个传入元素分配给一个或多个窗口。Flink为最常见的用例提供了预定义的窗口分配器,即滚动窗口、滑动窗口、会话窗口和全局窗口。还可以通过扩展WindowAssigner类来实现自定义窗口分配程序。所有内置的窗口分配器(除了全局窗口)都基于时间为窗口分配元素,时间可以是处理时间或事件时间。请看看我们关于事件时间的部分,了解处理时间和事件时间的区别。

基于时间的窗口有一个开始时间戳(包含时间)和一个结束时间戳(不包含时间),它们共同描述了窗口的大小。在代码中,Flink在处理基于时间的窗口时使用TimeWindow,该窗口有查询开始和结束时间戳的方法,还有一个额外的方法maxTimestamp(),它返回给定窗口允许的最大时间戳。

下面,我们将展示Flink预定义的窗口分配器是如何工作的,以及如何在DataStream程序中使用它们。下面的图显示了每个分配人的工作。紫色的圆圈表示流的元素,这些元素由一些键(在本例中是user 1、user 2和user 3)划分,x轴表示时间的进度。

你可能感兴趣的:(Streaming -- Operators -- Windows)