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,贼是谁…
- watermark(周期性)
-
代码
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