使用Flink和基于事件时间的流计算平均值

时间:2017-12-03 07:48:06

标签: scala apache-flink flink-streaming

我想在Flink中根据历史事件计算基于窗口的平均值(或我定义的任何其他函数),因此流必须是事件时间(不是基于处理时间):

val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)

我已经找到了如何在摄取时添加时间戳:

ctx.collectWithTimestamp(Datapoint(instrument, bid, ask), time.getMillis)

但是当我进行计算(应用函数)时,当我以与没有EventTime时相同的方式进行计算时,它不起作用。我已经阅读了一些关于水印的内容,我必须设置:

val avg = stream
  .keyBy("instrument")
  .timeWindow(Time.seconds(10))
  .apply((key: Tuple, window: TimeWindow, values: Iterable[Datapoint], out: Collector[Datapoint])=>{
    val avg = values.map(_.val).sum / values.size
    val dp = Datapoint(key.getField[String](0), avg)
    out.collect(dp)
  })

avg.print()
env.execute()

有人为此做了一个简单的Scala示例吗?

的问候,
安德烈亚斯

1 个答案:

答案 0 :(得分:0)

水印实际上是一个时间戳,其断言所有具有较早时间戳的事件(可能)已经到达。基于事件时间的Windows依赖于水印来了解窗口何时完成。到目前为止,最常见的水印策略是假设事件以一定的有限延迟到达。

如果您想在数据源中(在摄取过程中)发出水印,请参阅Source Functions with Timestamps and Watermarks,但它会像

一样简单
ctx.emitWatermark(new Watermark(datapoint.getWatermarkTime))

另一方面,如果您想在源外处理此问题,请参阅Timestamp Assigners / Watermark GeneratorsAssigners allowing a fixed amount of lateness。你可以简单地做这样的事情:

stream
  .assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor[Datapoint](Time.seconds(10))( _.getTimestamp ))
  .keyBy("instrument")
  ...

我链接到的文档在Scala中有更详细的示例。