【Flink Scala】window API

window API

Window 概述

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

image-20220328150915813

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

跳转顶部


window窗口的分类

image-20220328152407440

滚动窗口(Tumbling Windows)

image-20220328152541686

  • 将数据依据固定的窗口长度对数据进行切分

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

  • 定义的时候只需要一个参数:Window size即可


滑动窗口(Sliding Windows)

image-20220328152855613

  • 滑动窗口是固定窗口的更广义的一种形式,滑动窗口由固定的窗口长度和滑动间隔组成
  • 窗口长度固定,可以有重叠
  • 需要两个参数,一个是窗口大小和滑动的大小
  • 滑动窗口可以看作是一个特殊的滚动窗口(滑动间隔等于大小的)

会话窗口(Session Windows)

image-20220328153144855

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

跳转顶部


Window的使用

窗口分配器–Window方法

我们一般使用.window来定义一个窗口,然后基于window去做一些聚合或者其他处理操作。window必须在keyBy之后

滚动时间窗口的定义

    val resultStream = dataStream
      .map(data => (data.id, data.temperature))
      .keyBy(_._1) //按照二元组第一个元素id分组
      .window(TumblingEventTimeWindows.of(Time.seconds(10)))

滑动时间窗口的定义

    val resultStream = dataStream
      .map(data => (data.id, data.temperature))
      .keyBy(_._1) //按照二元组第一个元素id分组
      .window(SlidingEventTimeWindows.of(Time.seconds(15), Time.seconds(3)))

会话窗口

    val resultStream = dataStream
      .map(data => (data.id, data.temperature))
      .keyBy(_._1) //按照二元组第一个元素id分组
      .window(EventTimeSessionWindows.withGap(Time.seconds(15)))//间隔时间大于15秒就新建会话

上述书写的方法虽然可行,但是由于方法名称很长,很难记忆,所以可以使用下面的方法来简写

    val resultStream = dataStream
      .map(data => (data.id, data.temperature))
      .keyBy(_._1) //按照二元组第一个元素id分组
      .timeWindow(Time.seconds(15), Time.seconds(3))

参数为一个的时候就是滚动,参数为两个就是滑动


滚动基数窗口

    val resultStream = dataStream
      .map(data => (data.id, data.temperature))
      .keyBy(_._1) //按照二元组第一个元素id分组
      .countWindow(10)

滑动计算窗口

    val resultStream = dataStream
      .map(data => (data.id, data.temperature))
      .keyBy(_._1) //按照二元组第一个元素id分组
      .countWindow(10,5)

window function定义了要对窗口中收集的数据做的计算操作 ,他可以分为两类

  • 增量聚合函数(incremental aggregation functions

    • 每条数据到来就进行计算,保持一个简单的状态
    • ReduceFunction, AggregateFunction
  • 全窗口函数(full window functions

    • 先把窗口所有数据收集起来,等到计算的时候会遍历所有数据
    • ProcessWindowFunction

其他函数

  • **.trigger() —— 触发器 ,定义 window 什么时候关闭,触发计算并输出结果 **

  • .evictor()—— 移除器 ,定义移除某些数据的逻辑

  • .allowedLateness() —— 允许处理迟到的数据

  • .sideOutputLateData()—— 将迟到的数据放入侧输出流

  • .getSideOutput() —— 获取侧输出流

跳转顶部


测试

每五秒统计窗口内个传感器的温度最小值,以及最新的时间戳

package WindowAndWatermark

import Source.SensorReading
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
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 inputStream = env.socketTextStream("localhost", 7777)

    //转换成样例类
    val dataStream = inputStream
      .map(data => {
        val arr = data
          .split(",")
        SensorReading(arr(0), arr(1).toLong, arr(2).toDouble)
      })

    //每十五秒统计窗口内个传感器的温度最小值,以及最新的时间戳
    val resultStream = dataStream
      .map(data => (data.id, data.temperature, data.timeStamp))
      .keyBy(_._1) //按照二元组第一个元素id分组
      .timeWindow(Time.seconds(5))
      .reduce((CurRes, newData) => (CurRes._1, CurRes._2.min(newData._2), newData._3))

    resultStream.print("res")

    env.execute()
  }
}

window_flink
跳转顶部


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用 Flink 实现 MySQL CDC 的 Scala 代码示例: ```scala import org.apache.flink.streaming.api.scala._ import org.apache.flink.streaming.api.functions.source.SourceFunction import org.apache.flink.streaming.api.functions.AssignerWithPunctuatedWatermarks import org.apache.flink.streaming.api.watermark.Watermark import org.apache.flink.streaming.api.functions.sink.SinkFunction import org.apache.flink.streaming.api.functions.ProcessFunction import org.apache.flink.util.Collector import org.apache.flink.streaming.api.TimeCharacteristic import org.apache.flink.streaming.api.windowing.time.Time import org.apache.flink.streaming.api.scala.function.WindowFunction import org.apache.flink.streaming.api.windowing.windows.TimeWindow import org.apache.flink.api.common.functions.MapFunction import org.apache.flink.api.common.typeinfo.TypeInformation import org.apache.flink.api.java.typeutils.RowTypeInfo import org.apache.flink.types.Row import org.apache.flink.api.common.serialization.SimpleStringSchema import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011 import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer011 import org.apache.flink.streaming.connectors.kafka.KafkaSerializationSchema import org.apache.flink.streaming.connectors.kafka.KafkaContextAware import org.apache.flink.streaming.connectors.kafka.KafkaContextAware.KafkaContext import org.apache.flink.streaming.util.serialization.KeyedSerializationSchemaWrapper import java.util.Properties object MySQLCDC { def main(args: Array[String]): Unit = { val env = StreamExecutionEnvironment.getExecutionEnvironment env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime) val properties = new Properties() properties.setProperty("bootstrap.servers", "localhost:9092") properties.setProperty("group.id", "flink-group") val consumer = new FlinkKafkaConsumer011[String]("mysql-cdc", new SimpleStringSchema(), properties) val stream = env.addSource(consumer).map(new MapFunction[String, Row]() { override def map(value: String): Row = { val fields = value.split(",") Row.of(fields(0).toInt.asInstanceOf[Object], fields(1).asInstanceOf[Object], fields(2).asInstanceOf[Object]) } }).assignTimestampsAndWatermarks(new AssignerWithPunctuatedWatermarks[Row]() { override def extractTimestamp(row: Row, previousTimestamp: Long): Long = { row.getField(0).asInstanceOf[Int].toLong } override def checkAndGetNextWatermark(row: Row, extractedTimestamp: Long): Watermark = { new Watermark(extractedTimestamp) } }) val windowedStream = stream.keyBy(1).timeWindow(Time.seconds(10)).apply(new WindowFunction[Row, Row, Tuple, TimeWindow]() { override def apply(key: Tuple, window: TimeWindow, input: Iterable[Row], out: Collector[Row]): Unit = { val sortedInput = input.toList.sortBy(_.getField(0).asInstanceOf[Int]) val firstRow = sortedInput.head val lastRow = sortedInput.last out.collect(Row.of(firstRow.getField(1), firstRow.getField(2), lastRow.getField(2))) } }) val producer = new FlinkKafkaProducer011[String]("mysql-cdc-output", new KafkaSerializationSchema[String]() with KafkaContextAware[String] { var context: KafkaContext = _ override def serialize(element: String, timestamp: java.lang.Long): org.apache.kafka.clients.producer.ProducerRecord[Array[Byte], Array[Byte]] = { new org.apache.kafka.clients.producer.ProducerRecord(context.getOutputTopic(), element.getBytes()) } override def setRuntimeContext(context: KafkaContext): Unit = { this.context = context } }, properties, FlinkKafkaProducer011.Semantic.EXACTLY_ONCE) windowedStream.map(new MapFunction[Row, String]() { override def map(row: Row): String = { s"${row.getField(0)},${row.getField(1)},${row.getField(2)}" } }).addSink(producer) env.execute("MySQL CDC") } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值