Flink watermark解读

Flink watermark

  • watermark:是一种衡量Event Time进展的机制,它是数据本身的一个隐藏属性。通常基于Event Time的数据,自身都包含一个timestamp,例如1472693399700(2016-09-01 09:29:59.700),即:timestamp小于1472693396700(2016-09-01 09:29:56.700)的数据,都已经到达了。

    • 好多人绕不过去,还有很多文章画图的,看得我更晕。。。
  • watermark:是用于处理乱序事件的

    • 重点:解决乱序数据
  • 例子

    • watermark(周期性)
      • 思考了半天,想了一个例子,觉得还不错,分享一下
      • 大家应该都上课迟到过,就是这个例子,贼简单,你往下看就是了
      • window就是一个班级有多少人,人数够了,上课时间到了就开讲
      • 但是总有一些人迟到,A老师早上09:00开课,有一部分人没来怎么办,来的人占90%,不讲就耽误时间,讲的话这些人就跟不上了,影响期末考试,知道的是有人迟到,不知道的还以为教学质量有问题呢
      • A老师想了一个办法平衡一下,09:05分开始讲课,延迟了5分钟,这些人再不来,就没救了
      • 果然,有一部分人就踩着点来,贼没有时间观念,经过观察,09:05分开课的时候,已经来了98%了,这个就是watermark做的事,A老师画的水位线就是09:05
      • 下午老师又有其他课,还是晚5分钟讲,就是水位线只增不减
    • 侧输出流
      • 但是还有2%的人没有来,这个就是侧输出流,作为老师你是给学生补补课呢,还是放弃他们呢,自己决定吧(直接输出+报警邮件叫家长,狗头狗头保命)
    • watermark(指定条件)
      • 经过一段时间,学生们也学精了,知道了这个A老师每次都晚5分钟开始讲课,索性踩点再晚5分钟(老师:mmp…)
      • 于是乎B老师学习了A老师的经验,改进了一下,等满足指定条件后,再开课(真惯着他们,叫家长!!!)
      • 条件是什么呢?比如,上学期期末考试前10名的同学,已经全部到齐了,就开课。或者前30名的学生来了90%了,就开课(好费劲),剩下的全部认为是混子,没救了
      • ok,经过这么一综合,这节课教学应该还可以,整体期末考试应该就OK(窗口计算的应该准了,整体就差不多准了)
      • 就这么个玩意,贼简单…
      • 再想不明白的,按照下边的例子一步步的观察一下,就OK了
      • 搞过kafka的,结合offset想一下,贼简单…
    • 我测试的数据
      000001,1461756862000
      000001,1461756866000
      000001,1461756872000
      000001,1461756873000
      000001,1461756874000
      000001,1461756876000
      000001,1461756877000
      000001,1461756879000
      000001,1461756881000
      000001,1461756882000
      000001,1461756884000
      000001,1461756888000
      000002,1461756898000
      
    • Flink何时触发window?
      • 1、watermark时间 > Event Time(对于late element太多的数据而言)
      • 2、watermark时间 >= window_end_time(对于out-of-order以及正常的数据而言)
    • md,贼是谁…
  • 代码

import java.text.SimpleDateFormat
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor
import org.apache.flink.streaming.api.functions.{AssignerWithPeriodicWatermarks, AssignerWithPunctuatedWatermarks}
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.streaming.api.scala.function.WindowFunction
import org.apache.flink.streaming.api.watermark.Watermark
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector


object StreamingWindowWatermark {
  case class SR(id: String, timestamp: Long)
  def main(args: Array[String]): Unit = {
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)

    val dataSteam: DataStream[String] = env.socketTextStream("localhost", 7777) //nc -l 7777

    val inputMap: DataStream[SR] = dataSteam.map(f=> {
      val arr: Array[String] = f.split("\\W+")
      val code: String = arr(0)
      val time: Long = arr(1).toLong
      SR(code,time)
    })

    // 指定时间间隔的watermark
    val watermark: DataStream[SR] = inputMap.assignTimestampsAndWatermarks(new AssignerWithPeriodicWatermarks[SR] {
      var currentMaxTimestamp = 0L
      val maxOutOfOrderness = 10000L//最大允许的乱序时间是10s

      var a : Watermark = null
      val format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
      override def getCurrentWatermark: Watermark = {
        a = new Watermark(currentMaxTimestamp - maxOutOfOrderness)
        a
      }
      override def extractTimestamp(t: SR, l: Long): Long = {
        val timestamp: Long = t.timestamp
        currentMaxTimestamp = Math.max(timestamp, currentMaxTimestamp)
        println("timestamp:" + t.id +","+ t.timestamp + "|" +format.format(t.timestamp) +","+  currentMaxTimestamp + "|"+ format.format(currentMaxTimestamp) + ","+ a.toString)
        timestamp
      }
    })


    // 指定条件的watermark
//    val watermark: DataStream[SR] = inputMap.assignTimestampsAndWatermarks(new AssignerWithPunctuatedWatermarks[SR] {
//      override def checkAndGetNextWatermark(lastElement: SR, extractedTimestamp: Long): Watermark = {
//        if (extractedTimestamp % 3 == 0) new Watermark(extractedTimestamp) else null
//      }
//
//      override def extractTimestamp(element: SR, previousElementTimestamp: Long): Long = {
//        element.timestamp
//      }
//    })


    // 系统自带实现watermark方式
//    val watermark: DataStream[SR] = inputMap.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor[SR](Time.seconds(3)) {
//      override def extractTimestamp(element: SR): Long = {
//        element.timestamp * 1000
//      }
//    })

    val window: DataStream[(String, Int, String, String, String, String)] = watermark
      .keyBy(_.id)
      .window(TumblingEventTimeWindows.of(Time.seconds(3)))
      .apply(new WindowFunctionTest)

    window.print()

    env.execute()
  }

  class WindowFunctionTest extends WindowFunction[SR,(String, Int,String,String,String,String),String,TimeWindow]{
    override def apply(key: String, window: TimeWindow, input: Iterable[SR], out: Collector[(String, Int,String,String,String,String)]): Unit = {
      val list: List[SR] = input.toList.sortBy(_.timestamp)
      val format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
      out.collect(key,input.size,format.format(list.head.timestamp),format.format(list.last.timestamp),format.format(window.getStart),format.format(window.getEnd))
    }
  }


}

  • 大数据、数据分析、爬虫群: 《453908562》

  • 参考连接

    • 官网
    • https://blog.csdn.net/xorxos/article/details/80715113
    • https://www.cnblogs.com/rossiXYZ/p/12286407.html
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值