本章节是关于在event time上执行的程序的。想获取更多关于event time,processing time和ingestion time的信息,请参考:事件时间介绍。
为了与event time结合使用,流程序需要相应地设置一个时间特性。
Java代码:
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
Scala代码:
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
指定时间戳(Assigning Timestamps)
为了使用event time,Flink需要知道事件的时间戳,也就是说数据流中的元素需要分配一个事件时间戳。这个通常是通过抽取或者访问事件中某些字段的时间戳来获取的。
时间戳的分配伴随着水印的生成,告诉系统事件时间中的进度。
这里有两种方式来分配时间戳和生成水印:
1、直接在数据流源中进行
2、通过timestamp assigner和watermark generator生成:在Flink中,timestamp 分配器也定义了用来发射的水印。
注意:timestamp和watermark都是通过从1970年1月1日0时0分0秒到现在的毫秒数来指定的。
有Timestamp和Watermark的源函数(Source Function with Timestamps And Watermarks)
数据流源可以直接为它们产生的数据元素分配timestamp,并且他们也能发送水印。这样做的话,就没必要再去定义timestamp分配器了,需要注意的是:如果一个timestamp分配器被使用的话,由源提供的任何timestamp和watermark都会被重写。
为了通过源直接为一个元素分配一个timestamp,源需要调用SourceContext中的collectWithTimestamp(...)方法。为了生成watermark,源需要调用emitWatermark(Watermark)方法。
下面是一个简单的(无checkpoint)由源分配timestamp和产生watermark的例子:
Java 代码:
@Override
public void run(SourceContext ctx) throws Exception {
while (/* condition */) {
MyType next = getNext();
ctx.collectWithTimestamp(next, next.getEventTimestamp());
if (next.hasWatermarkTime()) {
ctx.emitWatermark(new Watermark(next.getWatermarkTime()));
}
}
}
Scala 代码:
override def run(ctx: SourceContext[MyType]): Unit = {
while (/* condition */) {
val next: MyType = getNext()
ctx.collectWithTimestamp(next, next.eventTimestamp)
if (next.hasWatermarkTime) {
ctx.emitWatermark(new Watermark(next.getWatermarkTime))
}
}
}
TimeStamp分配器和Watermark生成器(Timestamp Assigners / Watermark Gen