flink 全窗口函数 自定义Trigger flink的窗口类型_红外


Flink Windows

1、窗口概述

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

按照统计维度的不同,Flink 中的窗口可以分为

时间窗口 (Time Windows) 和 计数窗口 (Count Windows) 。

2、Time Windows (按照时间生成window)

时间窗口(Time Windows) 用于以时间为维度来进行数据聚合,具体分为以下3类:滚动窗口(Tumbling Window)、滑动窗口(Sliding Window)和会话窗口(Session Window)。

2.1 滚动窗口 (Tumbling Windows)

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

例如:每隔1小时统计过去1小时内的商品点击量,那么 1 天就只能分为 24 个窗口,每个窗口彼此之间是不存在重叠的,具体如下:

flink 全窗口函数 自定义Trigger flink的窗口类型_apache_02


滚动窗口特点:

  • 时间对齐
  • 窗口长度固定
  • 没有重叠

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

2.1.1 案例
需求:  每隔4秒钟,求出不同红外测温仪监测到的体温最高的旅客信息
结果:
    红外测温仪id  最高温度
2.1.2 源码
package com.jd.unbounded.sample_window.timewindow.a_tubling

import com.jd.unbounded.Raytek
import org.apache.flink.api.java.tuple.Tuple
import org.apache.flink.api.scala._
import org.apache.flink.streaming.api.scala.{StreamExecutionEnvironment, WindowedStream}
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow

/**
  * Description 滚动窗口演示
  *
  * @author lijun
  * @create 2020-04-01
  */
object TublingWindowTest {

  def main(args: Array[String]): Unit = {
    //1.环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    //2.获取两个无界流
    val srcDataStream = env.socketTextStream("localhost", 6666)
      .filter(_.trim.nonEmpty)
      .map(perTraveller => {
        val arr = perTraveller.split(",")
        val id = arr(0).trim
        val temperature = arr(1).trim.toDouble
        val name = arr(2).trim
        val timestamp = arr(3).trim.toLong
        val location = arr(4).trim
        Raytek(id, temperature, name, timestamp, location)
      })

    //3.每隔4秒,求出不同红外测温仪所监测到的体温最高的旅客信息
    //获得窗口流
    val ws: WindowedStream[Raytek, Tuple, TimeWindow] = srcDataStream.keyBy("id")
      .timeWindow(Time.seconds(4))

    //聚合,求最高的体温的旅客信息并显示输出
    ws.reduce((nowTraveller:Raytek,nextTraveller:Raytek)=>{
      if(nowTraveller.temperature > nextTraveller.temperature) nowTraveller
      else nextTraveller
    }).print("滚动时间窗口效果 -->")

    //4.启动
    env.execute()
  }
}
2.1.3 效果
2.1.3.1 source端

flink 全窗口函数 自定义Trigger flink的窗口类型_apache_03

2.1.3.2 控制台输出

flink 全窗口函数 自定义Trigger flink的窗口类型_flink_04

2.2 滑动窗口(Sliding Windows)

滑动窗口是固定窗口的更广义的一种形式,滑动窗口由固定的窗口长度和滑动间隔组成。
滑动窗口分配器将元素分配到固定长度的窗口中,与滚动窗口类似,窗口的大小由窗口大小参数来配置,另一个窗口滑动参数控制滑动窗口开始的频率。因此,滑动窗口如果滑动参数小于窗口大小的话,窗口是可以重叠的,在这种情况下元素会被分配到多个窗口中。

例如:每隔 6 分钟统计一次过去一小时内所有商品的点击量,那么统计窗口彼此之间就是存在重叠的,即 1天可以分为 240 个窗口。图示如下:

flink 全窗口函数 自定义Trigger flink的窗口类型_红外_05

滑动窗口特点:

  • 窗口长度固定
  • 可以有重叠

适用场景:对最近一个时间段内的统计

2.2.1 案例
需求:  每隔2秒,统计过去4秒之内,不同红外测温仪所监测到的体温最高的旅客信息
结果:
    红外测温仪id  最高温度
2.2.2 源码
package com.jd.unbounded.sample_window.timewindow.b_slide

import com.jd.unbounded.Raytek
import org.apache.flink.api.java.tuple.Tuple
import org.apache.flink.api.scala._
import org.apache.flink.streaming.api.scala.{StreamExecutionEnvironment, WindowedStream}
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow

/**
  * Description 
  *
  * @author lijun
  * @create 2020-04-01
  */
object SlideTimeWindowTest {

  def main(args: Array[String]): Unit = {
    //1.环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    //2.获取两个无界流
    val srcDataStream = env.socketTextStream("localhost", 6666)
      .filter(_.trim.nonEmpty)
      .map(perTraveller => {
        val arr = perTraveller.split(",")
        val id = arr(0).trim
        val temperature = arr(1).trim.toDouble
        val name = arr(2).trim
        val timestamp = arr(3).trim.toLong
        val location = arr(4).trim
        Raytek(id, temperature, name, timestamp, location)
      })

    //3.每隔2秒,统计过去4秒之内,不同红外测温仪所监测到的体温最高的旅客信息
    //获得窗口流
    val ws: WindowedStream[Raytek, Tuple, TimeWindow] = srcDataStream.keyBy("id")
      .timeWindow(Time.seconds(4),Time.seconds(2))

    //聚合,求最高的体温的旅客信息并显示输出
    ws.reduce((nowTraveller:Raytek,nextTraveller:Raytek)=>{
      if(nowTraveller.temperature > nextTraveller.temperature) nowTraveller
      else nextTraveller
    }).print("滑动时间窗口效果 -->")

    //4.启动
    env.execute()
  }
}
2.2.3 效果
2.2.3.1 source

flink 全窗口函数 自定义Trigger flink的窗口类型_apache_06

2.2.3.2 控制台输出

flink 全窗口函数 自定义Trigger flink的窗口类型_apache_07

2.3 窗口分配器的使用

window()方法接收的输入参数是一个WindowAssigner,WindowAssigner负责将每条输入的数据分发到正确的window中

flink 全窗口函数 自定义Trigger flink的窗口类型_flink_08

2.4 会话窗口(Session Windows)

一段时间没有接收到新数据就会生成新的窗口
想要实现这类统计,可以通过 Session Windows 来进行实现。

flink 全窗口函数 自定义Trigger flink的窗口类型_flink_09


特点:时间无对齐。

3、Count Windows:按照指定的数据条数生成一个window

计数窗口(Count Windows) 根据窗口中相同key元素的数量来触发执行,执行时只计算元素数量达到窗口大小的key,同样也分为滚动窗口和滑动窗口,滚动窗口和滑动窗口的函数名是完全一致的,实现方式也和时间窗口完全一致,只是调用的 API 不同,具体如下:

默认的CountWindow是一个滚动窗口,只需要指定窗口大小即可,当元素数量达到窗口大小时,就会触发窗口的执行
// 滚动计数窗口,每1000次点击则计算一次
countWindow(1000)
// 滑动计数窗口,每10次点击发生后,则计算过去1000次点击的情况
countWindow(1000,10)
3.1 滚动计数窗口案例
3.1.1 案例设计
需求:
    安放在北京西站各个监测口的红外测温仪每监测到三个旅客后,就求出这三个旅客中体温最高的旅客信息
3.1.2 源码
package com.jd.unbounded.sample_window.countwindow

import com.jd.unbounded.Raytek
import org.apache.flink.api.scala._
import org.apache.flink.api.java.tuple.Tuple
import org.apache.flink.streaming.api.scala.{StreamExecutionEnvironment, WindowedStream}
import org.apache.flink.streaming.api.windowing.windows.{GlobalWindow}

/**
  * Description  计数滚动窗口演示
  *
  * @author lijun
  * @create 2020-04-01
  */
object CountTublingWindowTest {

  def main(args: Array[String]): Unit = {
    //1.环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    //2.获取两个无界流
    val srcDataStream = env.socketTextStream("localhost", 6666)
      .filter(_.trim.nonEmpty)
      .map(perTraveller => {
        val arr = perTraveller.split(",")
        val id = arr(0).trim
        val temperature = arr(1).trim.toDouble
        val name = arr(2).trim
        val timestamp = arr(3).trim.toLong
        val location = arr(4).trim
        Raytek(id, temperature, name, timestamp, location)
      })

    //3.红外测温仪每监测到三个旅客后,就求出这三个旅客中体温最高的旅客信息
    //获得窗口流
    val ws: WindowedStream[Raytek, Tuple, GlobalWindow] = srcDataStream.keyBy("id")
      .countWindow(3)

    //聚合,求最高的体温的旅客信息并显示输出
    ws.reduce((nowTraveller:Raytek,nextTraveller:Raytek)=>{
      if(nowTraveller.temperature > nextTraveller.temperature) nowTraveller
      else nextTraveller
    }).print("滚动计数窗口效果 -->")

    //4.启动
    env.execute()
  }
}
3.1.3 效果
3.1.3.1 source端

flink 全窗口函数 自定义Trigger flink的窗口类型_红外_10

3.1.3.2 控制台输出

flink 全窗口函数 自定义Trigger flink的窗口类型_红外_11

3.2 滑动计数窗口案例
3.2.1 案例设计
需求:
    安放在北京西站各个监测口的红外测温仪每监测到2个旅客后,统计过去5个旅客中体温最高的旅客信息
3.2.2 源码
package com.jd.unbounded.sample_window.countwindow

import com.jd.unbounded.Raytek
import org.apache.flink.api.scala._
import org.apache.flink.api.java.tuple.Tuple
import org.apache.flink.streaming.api.scala.{StreamExecutionEnvironment, WindowedStream}
import org.apache.flink.streaming.api.windowing.windows.GlobalWindow

/**
  * Description  滑动计数窗口演示
  *
  * @author lijun
  * @create 2020-04-01
  */
object CountSlideWindowTest {
  def main(args: Array[String]): Unit = {
    //1.环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    //2.获取两个无界流
    val srcDataStream = env.socketTextStream("localhost", 6666)
      .filter(_.trim.nonEmpty)
      .map(perTraveller => {
        val arr = perTraveller.split(",")
        val id = arr(0).trim
        val temperature = arr(1).trim.toDouble
        val name = arr(2).trim
        val timestamp = arr(3).trim.toLong
        val location = arr(4).trim
        Raytek(id, temperature, name, timestamp, location)
      })

    //3.红外测温仪每监测到2个旅客后,统计过去5个旅客中体温最高的旅客信息
    //获得窗口流
    val ws: WindowedStream[Raytek, Tuple, GlobalWindow] = srcDataStream.keyBy("id")
      .countWindow(5,2)


    //聚合,求最高的体温的旅客信息并显示输出
    ws.reduce((nowTraveller:Raytek,nextTraveller:Raytek)=>{
      if(nowTraveller.temperature > nextTraveller.temperature) nowTraveller
      else nextTraveller
    }).print("滑动计数窗口效果 -->")

    //4.启动
    env.execute()
  }
}
3.2.3 效果
3.2.3.1 source端

flink 全窗口函数 自定义Trigger flink的窗口类型_红外_12

3.2.3.2 控制台输出

flink 全窗口函数 自定义Trigger flink的窗口类型_apache_13