flink 五、flink的window操作和水印机制

Flink 认为 Batch 是 Streaming 的一个特例,所以 Flink 底层引擎是一个流式引擎,在上面实现了流处理和批处理。而窗口(window)就是从 Streaming 到 Batch 的一个桥梁。Flink 提供了非常完善的窗口机制。

什么是window

在流式数据中,数据是连续的。有时我们需要根据业务做一些聚合类的操作,例如过去五分钟内用户浏览量的计算。这五分钟就是一个窗口。
窗口可以由时间或者数量来做区分
1.根据时间进行截取,比如每10分钟统计一次
2.根据消息数量进行统计,比如每100个数据统计一次

时间窗口

时间窗口又分为滚动窗口,滑动窗口,和会话窗口

滚动窗口:

时间对齐,窗口长度固定,没有重叠
滚动窗口
如图:以固定的长度进行分割,比如一个网站统计每分钟的浏览量,BI的pv,uv统计

滑动窗口

时间对齐,窗口长度固定,有重叠,展现的是数据的变化趋势
滑动窗口
如图:窗口大小为4,步长为2,每隔两秒统计仅4s的数据
适用于 股票的实时波动情况等

会话窗口

会话窗口

当流中达到多长时间没有新的数据到来,上一个会话窗口就是截至到新数据到来前接收到的最后一条数据,当新数据到来后,上一个窗口将会关闭,开启一个新的窗口。
常见于,web程序session的统计

代码实现

常见分类:keyed window和Non-keyed window
二者区分是否跟于keyBy之后

CountWindow实现
object CountWindow {
  def main(args: Array[String]): Unit = {
    val environment: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    val dataStream: DataStream[String] = environment.socketTextStream("192.168.23.171", 8989, '\n')
    //None_keyed Stream
//    dataStream.flatMap(_.split(" "))
//      .map((_,1))
//      .countWindowAll(10)
//      .sum(1)
//      .print()
    //keyed Stream
    dataStream.flatMap(_.split(" "))
      .map((_,1))
      .keyBy(0)
      .countWindow(10)
      .sum(1)
      .print()
    environment.execute("CountWindowStream")
  }
}

滚动窗口实现

object TubmlingWindow {
  def main(args: Array[String]): Unit = {
    val environment: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    val dataStream: DataStream[String] = environment.socketTextStream("node01", 8989, '\n')
    // Non-keyed 分组
//    dataStream.flatMap(_.split(" "))
//      .map((_, 1))
//      .timeWindowAll(Time.seconds(5))
//        .windowAll(TumblingProcessingTimeWindows.of(Time.seconds(5)))
//      .sum(1)
//      .print()
// keyed Stream
    dataStream.flatMap(_.split(" "))
      .map((_,1))
      .keyBy(0)
//      .timeWindow(Time.seconds(5))
      .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
      .sum(1)
      .print()
    environment.execute("StreamTubmlingWindow")
  }
}

滑动窗口实现

object SlindingWindow {
  def main(args: Array[String]): Unit = {
    val environment: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    val dataStream: DataStream[String] = environment.socketTextStream("node01", 8989, '\n')
    // Non-keyed 分组
//        dataStream.flatMap(_.split(" "))
//          .map((_, 1))
          .timeWindowAll(Time.seconds(10),Time.seconds(5))
//          .windowAll(SlidingProcessingTimeWindows.of(Time.seconds(10),Time.seconds(5)))
//          .sum(1)
//          .print()
    dataStream.flatMap(_.split(" "))
      .map((_,1))
      .keyBy(0)
//      .timeWindow(Time.seconds(10),Time.seconds(5))
      .window(SlidingProcessingTimeWindows.of(Time.seconds(10),Time.seconds(5)))
      .sum(1)
      .print()
    environment.execute("StreamSlidingWindow")
  }
}

会话窗口实现

object SessionWindow {
  def main(args: Array[String]): Unit = {
    val environment: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    val dataStream: DataStream[String] = environment.socketTextStream("node01", 8989, '\n')
    // Non-keyed 分组
    //              dataStream.flatMap(_.split(" "))
    //                .map((_, 1))
    //                .windowAll(ProcessingTimeSessionWindows.withGap(Time.seconds(5)))
    //                .sum(1)
    //                .print()ronment.socketTextStream("node01", 8989, '\n')
    dataStream.flatMap(_.split(" "))
      .map((_,1))
      .keyBy(0)
      .window(EventTimeSessionWindows.withGap(Time.seconds(5)))
      .sum(1)
      .print()
    environment.execute("StreamSessionWindow")
  }
}

Flink的水印机制

Flink流处理时间方式

  • EventTime[事件时间]

    事件发生的时间,例如:点击网站上的某个链接的时间

  • IngestionTime[进入时间]

    某个Flink节点的source operator接收到数据的时间,例如:某个source消费到kafka中的数据

  • ProcessingTime[处理时间]

    某个Flink节点执行某个operation的时间,例如:timeWindow接收到数据的时间
    设置Flink流处理的时间类型

// 设置为按照事件时间来进行计算
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
// 设置为按照处理时间来进行计算
env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime)

比如一个10分钟一个滚动窗口,统计每个时间段访问人数
10:00:00到10:00:00 为一个窗口
假设10:09:59产生了一条数据,但是因为网络延迟,进入flink已经10:10:03那么该数据该如何归类,所以此时应该使用Eventtime
使用水印可以解决这类网络延迟问题,可以理解水印就是一个时间戳,每接收处理一个消息都会添加水印
水印影响原有事件时间,当数据流添加水印后,会按照水印时间来触发窗口统计计算,当接收到的水印时间大于等于窗口的endTime,触发计算。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值