一、Window

1.Window 概述

         Streaming 流式计算是一种被设计用于处理无限数据集的数据处理引擎,而无限数据集是指一种不断增长的本质上无限的数据集,而 window 是一种切割无限数据为有限块进行处理的手段。
        Window 是无限数据流处理的核心,Window 将一个无限的 stream 拆分成有限大小的”buckets”桶,我们可以在这些桶上做计算操作。

2..Window类型

   Window 可以分成两类:

  • CountWindow:按照指定的数据条数生成一个 Window,与时间无关。
  • TimeWindow:按照时间生成 Window。

       对于 TimeWindow,可以根据窗口实现原理的不同分成三类:滚动窗口( TumblingWindow)、滑动窗口(Sliding                       Window)和会话窗口(Session Window)。

(1)滚动窗口(Tumbling Windows)

         将数据依据固定的窗口长度对数据进行切片。

         特点:时间对齐,窗口长度固定,没有重叠。

Flink 的 TumblingEventTimeWindow用法 flink countwindowall_滑动窗口

适用场景:适合做 BI 统计等(做每个时间段的聚合计算)。

(2)滑动窗口(Sliding Windows)

         滑动窗口是固定窗口的更广义的一种形式,滑动窗口由固定的窗口长度和滑动间隔组成。

         特点:时间对齐,窗口长度固定,可以有重叠。

Flink 的 TumblingEventTimeWindow用法 flink countwindowall_数据_02

适用场景:对最近一个时间段内的统计(求某接口最近 5min 的失败率来决定是否要报警)。

(3)会话窗口(Session Windows)

         特点:时间无对齐。

Flink 的 TumblingEventTimeWindow用法 flink countwindowall_数据_03

二、Window API

       TimeWindow 是将指定时间范围内的所有数据组成一个 window,一次对一个 window 里面的所有数据进行计算。

1. 滚动窗口

Flink 默认的时间窗口根据 Processing Time 进行窗口的划分,将 Flink 获取到的数据根据进入 Flink 的时间划分到不同的窗口中。

val minTempPerWindow = dataStream

.map(r => (r.id, r.temperature))

.keyBy(_._1)

.timeWindow(Time.seconds(15))

.reduce((r1, r2) => (r1._1, r1._2.min(r2._2)))

2. 滑动窗口(SlidingEventTimeWindows)

       滑动窗口和滚动窗口的函数名是完全一致的,只是在传参数时需要传入两个参数,一个是 window_size,一个是 sliding_size。下面代码中的 sliding_size 设置为了 5s,也就是说,窗口每 5s 就计算一次,每一次计算的 window 范围是 15s 内的所有元素。

val minTempPerWindow: DataStream[(String, Double)] = dataStream

.map(r => (r.id, r.temperature))

.keyBy(_._1)

.timeWindow(Time.seconds(15), Time.seconds(5))

.reduce((r1, r2) => (r1._1, r1._2.min(r2._2)))

.window(EventTimeSessionWindows.withGap(Time.minutes(10))

     时间间隔可以通过 Time.milliseconds(x),Time.seconds(x),Time.minutes(x)等其中的一个来指定。

三、CountWindow

       CountWindow 根据窗口中相同 key 元素的数量来触发执行,执行时只计算元素数量达到窗口大小的 key 对应的结果。

       注意:CountWindow 的 window_size 指的是相同 Key 的元素的个数,不是输入的所有元素的总数。

1 滚动窗口

      默认的 CountWindow 是一个滚动窗口,只需要指定窗口大小即可,当元素数量达到窗口大小时,就会触发窗口的执行。

val minTempPerWindow: DataStream[(String, Double)] = dataStream

.map(r => (r.id, r.temperature))

.keyBy(_._1)

.countWindow(5)

.reduce((r1, r2) => (r1._1, r1._2.max(r2._2)))

2 滑动窗口

   滑动窗口和滚动窗口的函数名是完全一致的,只是在传参数时需要传入两个参数,一个是 window_size,一个是 sliding_size。

  下面代码中的 sliding_size 设置为了 2,也就是说,每收到两个相同 key 的数据就计算一次,每一次计算的 window 范围是5 个元素。

val keyedStream: KeyedStream[(String, Int), Tuple] = dataStream.map(r => (r.id, r.temperature)).keyBy(0)

//每当某一个 key 的个数达到 2 的时候,触发计算,计算最近该 key 最近 10 个元素的内容 val windowedStream: WindowedStream[(String, Int), Tuple, GlobalWindow] = keyedStream.countWindow(10,2)
val sumDstream: DataStream[(String, Int)] = windowedStream.sum(1)

四、window function

package com.flink.windowfun

import com.flink.bean.SensorReading
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time
/**
  * @Author :star
  * @Date :2020/7/7 20:21
  * @Version :1.0
  */
object WindowFunc {
  def main(args: Array[String]): Unit = {
    //environment
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //source
    val socketStream = env.socketTextStream("localhost",8588)
    //tramsform
    val data: DataStream[SensorReading] = socketStream.map(
      data => {
        val sensorData: Array[String] = data.split(",")
        SensorReading(sensorData(0).trim, sensorData(1).trim.toLong, sensorData(2).trim.toDouble)
      }
    )
    val minTemPerWindowStream: DataStream[(String, Double)] = data.map(x => (x.id, x.temprature))
      .keyBy(0)
      .timeWindow(Time.seconds(10))
      .reduce((x, y) => (x._1, x._2.min(y._2)))
    minTemPerWindowStream.print("minTemPerWindowStream")
    data.print("data")
    env.execute() 
  }
}