Flink Window API

窗口(Window)


【1】一般真实的流都是无界的,怎么处理无界的数据?
【2】可以把无限的数据流进行切分,得到有限的数据集进行处理。也就是得到有界流。
【3】窗口(Window)就是将无限流切割为有限流的一种方式,它会将流数据分发到有限大小的桶(bucket)中进行分析。

时间窗口(Time Window)/计数窗口(Count Window)

【1】滚动时间窗口/滚动计数窗口:将数据依据固定的窗口长度等长的对数据进行切分。时间对齐,窗口长度固定,没有重叠

【2】滑动时间窗口/滑动计数窗口:固定窗口的更广义的一种形式,滑动窗口由固定的窗口长度和滑动间隔组成。窗口长度固定,可以有重叠

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

窗口分配器 Assigner【window() 方法】

我们可以用 .window() 来定义一个窗口,然后基于这个 window去做一些聚合或者其他处理操作。注意 window() 方法必须在 keyBy 之后才能用,因为 window 方法必须基于 KeyedStream。一般的 DataStream 也可以开窗,使用 windowall() 两者几乎没有区别,windowall 是在一个分区上统一处理,所以一般不推荐使用。Flink 提供了更加简单的 .timeWindow .countWindow 方法,用于定义时间窗口和计数窗口。

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

window() 方法接收的输入参数是一个 WindowAssigner。WindowAssigner 负责将每条输入的数据分发到正确的 window 中。Flink 提供了通用的 WindowAssigner:
滚动窗口(tumbling window):.timeWindow(Time.seconds(15)) Processing Time 测试代码

package com.zzx.flink

import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time

object WindowTest {
  def main(args: Array[String]): Unit = {
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    env.setParallelism(1)
    //从文件中读取数据并转换为 类
    val stream: DataStream[String] = env.socketTextStream("hadoop1",7777)
    //转换
    val dataStream: DataStream[SensorReading] = stream
      .map( data => {
        var dataArray = data.split(",")
        SensorReading(dataArray(0),dataArray(1).toLong,dataArray(2).toDouble)
      })

    //输出10秒中最小的数据
    val minTempPerWindowStream = dataStream.map(data => (data.id,data.temperature))
      .keyBy(_._1)
      .timeWindow(Time.seconds(10))//开时间窗口
      .reduce((data1,data2) => (data1._1,data1._2.min(data2._2))) //用 reduce 做增量聚合

    minTempPerWindowStream.print("min temp")
    dataStream.print("input data")

    env.execute("window test")
  }
}

结果展示:通过 nc -lk 7777 输入如下3条 SensorReading 数据集,会根据系统时间每隔10s得到最小的温度值进行输出。

滚动窗口(tumbling window):.timeWindow(Time.seconds(15)) Event Time 测试代码

package com.zzx.flink

import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time

object WindowTest {
  def main(args: Array[String]): Unit = {
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //设置使用 事件时间
    env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
    env.setParallelism(1)
    //从文件中读取数据并转换为 类
    val stream: DataStream[String] = env.socketTextStream("hadoop1",7777)
    //转换
    val dataStream: DataStream[SensorReading] = stream
      .map( data => {
        var dataArray = data.split(",")
        SensorReading(dataArray(0),dataArray(1).toLong,dataArray(2).toDouble)
      })
      //.assignAscendingTimestamps(_.timestamp*1000)  数据顺序得到的时候调用此方法设置 timestamp
      // 括号中出入的是延迟时间
      .assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor[SensorReading](Time.seconds(1)) {
        override def extractTimestamp(t: SensorReading): Long = t.timestamp * 1000
      })

    //输出10秒中最小的数据
    val minTempPerWindowStream = dataStream.map(data => (data.id,data.temperature))
      .keyBy(_._1)
      .timeWindow(Time.seconds(10))//开时间窗口
      .reduce((data1,data2) => (data1._1,data1._2.min(data2._2))) //用 reduce 做增量聚合

    minTempPerWindowStream.print("min temp")
    dataStream.print("input data")

    env.execute("window test")
  }
}

结果展示:通过 nc -lk 7777 输入如下 SensorReading 数据集,会根据输入数据中的 timestamp 相隔10s时得到最小的温度值进行输出。 同时设置了 1s的延迟。同时在第十秒的时候,输出的是前9秒的结果,因为延迟为1s钟。同时遵循左闭右开,这里的20s的数据其实也没有进行统计。

input data> SensorReading(sensor_10,1595065612212,44.84)
input data> SensorReading(sensor_10,1595065612213,44.84)
input data> SensorReading(sensor_10,1595065612214,44.86)
input data> SensorReading(sensor_10,1595065612215,44.81)
input data> SensorReading(sensor_10,1595065612216,44.86)
input data> SensorReading(sensor_10,1595065612217,44.86)
input data> SensorReading(sensor_10,1595065612218,44.86)
input data> SensorReading(sensor_10,1595065612219,44.86)
input data> SensorReading(sensor_10,1595065612220,44.86)
input data> SensorReading(sensor_10,1595065612221,44.8)
min temp> (sensor_10,44.81)

滑动窗口(sliding window) :如下多传入一个参数即可

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

结果展示:如下水位从11开始每5s输出一次因此输出时间为 15+延迟时间 1s = 16s时输出,因为输出的规则是左闭右开因此15s的数据没有拉入统筹范围。输入结果如下:

input data> SensorReading(sensor_10,1595065612211,44.84)
input data> SensorReading(sensor_10,1595065612212,44.83)
input data> SensorReading(sensor_10,1595065612213,44.82)
input data> SensorReading(sensor_10,1595065612214,44.81)
input data> SensorReading(sensor_10,1595065612215,44.8)
input data> SensorReading(sensor_10,1595065612216,44.79)
min temp> (sensor_10,44.81)

思考:第一个水位 watermark 是真么定义的?

会话窗口(session window)

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

全局窗口(global window)

创建不同类型的窗口

滚动计数窗口( tumbling count window)

.countWindow(5)

滑动计数窗口(sliding count window)

.countWindow(10,2)

窗口函数( window function)

window function 定义了要对窗口中收集的数据做的计算操作,在窗口分配器分配完窗口之后执行。可以分为两类:
【1】增量聚合函数(incremental aggregation functions):每条数据到来就进行计算,保持一个简单的状态。例如:ReduceFunctionAggregateFunction
【2】全窗口函数(full window functions):先把窗口所有的数据收集起来,等到计算的时候会遍历所有数据。例如:ProcessWindowFunction

其他可选 API

【1】.trigger:触发器:定义 window 什么时候关闭,触发计算并输出结果。
【2】.evitor:移除器:定义移除某些数据的逻辑。
【3】.sideOutputLateData:将延迟的数据放入侧输出流。
【4】.getSideOutput:获取侧输出流。
【5】.allowedLateness:允许处理迟到的数据。

window API 总览

©️2020 CSDN 皮肤主题: 鲸 设计师:meimeiellie 返回首页