Flink Program Guide (4) -- 时间戳和Watermark生成(DataStream API编程指导 -- For Java)...

时间戳和Watermark生成

本文翻译自Generating Timestamp / Watermarks

------------------------------------------------------------------

本文是Flink在使用事件时间(Event Time)时相关内容,有关事件时间、处理时间和提取时间的介绍,请见event time introduction

 

流程序需要设置时间特征Event time,才能在程序中使用事件时间。

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.
setStreamTimeCharacteristic(TimeCharacteristic.EventTime);

 

一、时间戳赋值

为了使事件时间可以正常使用,Flink需要知道时间的时间戳,即流中的每个element都需要被赋予它自己的时间戳。Flink通常会从element的一些域访问/提取时间戳(That happens usually by accessing/extracting the timestamp from some field in the element.)。

 

时间戳的赋值通常与Watermark的生成紧密相关,其中Watermark生成负责通知系统事件时间的增长情况。

 

时间戳赋值和Watermark生成的方式有两种:

1.    直接在数据流源处进行

2.    通过一个Timestamp assigner / watermark generator:在Flink中,Timestamp assigner同样会定义watermark的发送行为

 

注意:时间戳和Watermark都是使用从Java历元(epoch “1970-01-01 T00.00.00Z”开始的毫秒数定义的

 

1.1 带有时间戳和WatermarkSource方法

流的源可以在它们生产的element中直接赋值时间戳以及发送Watermark。在此情况下,我们不需要Timestamp Assigner

要在Source方法中向element直接赋值时间戳,Source方法必须在SourceContext上调用方法collectWithTimestamp(…)。要在Source中生成WatermarkSource必须调用emitWatermark(Watermark)方法。

 

在下例的(非检查点的)Source方法中,方法直接向element赋值时间戳,并且根据特殊事件生成Watermark

@Override
public
void run(SourceContext<MyType> ctx) throws Exception {
  while (
/* condition */) {
    MyType next = getNext();
     ctx.
collectWithTimestamp(next, next.getEventTimestamp());

    if (next.hasWatermarkTime()) {
      ctx.
emitWatermark(new Watermark(next.getWatermarkTime()));
    }
  }
}

 

注意:如果流程序在已经拥有时间戳的流上继续使用TimestampAssigner,流中element的原有时间戳将被TimestampAssigner重写。类似地,Watermark也会同样被重写。

 

1.2 Timestamp Assigner / Watermark Generators

Timestamp Assigner接收一个流并且产生一个带有时间戳赋值elementWatermark的新的流。如果原有的流已经拥有了时间戳或Watermark,则Timestamp Assigner将会重写它们。

 

通常在紧接着数据源之后会定义Timestamp Assigner,但这并不是严格要求的。例如在通用的模式中,会在Timestamp Assigner之前进行parse(MapFunction)filter(FilterFunction)操作。不论在什么情况下,Timestamp Assigner都需要在第一个使用事件时间的Operation(如第一个窗口Operation)之前定义。而在流Job中使用Kafka作为数据源是一个特殊情况,Flink允许在数据源(或数据消费者consumer)内部定义Timestamp AssignerWatermark emitter,更多相关信息请见Kafka Connector documentation

 

注意:本节余下内容呈现了一个开发者创建自己的Timestamp Assigner watermark emitter所需要实现的主要接口。有关Flink自带的预先实现的extractor,请见Pre-defined Timestamp Extractors / Watermark Emitters

 

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.
setStreamTimeCharacteristic(TimeCharacteristic.EventTime);

DataStream<MyEvent> stream = env.readFile(
  myFormat, myFilePath, FileProcessingMode.
PROCESS_CONTINUOUSLY, 100,
  FilePathFilter.
createDefaultFilter(), typeInfo);

DataStream<MyEvent> withTimestampsAndWatermarks = stream
  .
filter( event -> event.severity() == WARNING )
  .
assignTimestampsAndWatermarks(new MyTimestampsAndWatermarks());

withTimestampsAndWatermarks
  .
keyBy( (event) -> event.getGroup() )
  .
timeWindow(Time.seconds(10))
  .
reduce( (a, b) -> a.add(b) )
  .
addSink(...);

 

周期性Watermark

AssignerWithPeriodicWatermark赋值时间戳并周期性生成(生成方式有可能是依靠流的element,或者纯粹基于处理时间)。

 

生成Watermark的时间周期区间(每n毫秒)的大小可以通过ExecutionConfig.setAutoWatermarkInterval(…)设置。每一次生成时,都将会调用AssignergetCurrentWatermark()方法,如果返回的Watermark是非null且大于前一个Watermark,则会发送一个新的Watermark

 

下面是两个生成周期性WatermarkTimestamp Assigner的例子

/**
* This generator generates watermarks assuming that elements come out of order to a certain degree only.
* The latest elements for a certain timestamp t will arrive at most n milliseconds after the earliest
* elements for timestamp t.
*/
public class
BoundedOutOfOrdernessGenerator extends AssignerWithPeriodicWatermarks<MyEvent> {

private final long maxOutOfOrderness = 3500; // 3.5 seconds

private long currentMaxTimestamp;

@Override
public
long extractTimestamp(MyEvent element, long previousElementTimestamp) {
  
long timestamp = element.getCreationTime();
  currentMaxTimestamp = Math.
max(timestamp, currentMaxTimestamp);
  return timestamp;
}

@Override
public Watermark
getCurrentWatermark() {
  
// return the watermark as current highest timestamp minus the out-of-orderness bound
  return new
Watermark(currentMaxTimestamp - maxOutOfOrderness);
}

}

/**
* This generator generates watermarks that are lagging behind processing time by a certain amount.
* It assumes that elements arrive in Flink after at most a certain time.
*/
public class
TimeLagWatermarkGenerator extends AssignerWithPeriodicWatermarks<MyEvent> {

private final long maxTimeLag = 5000; // 5 seconds

@Override
public
long extractTimestamp(MyEvent element, long previousElementTimestamp) {
        return element.
getCreationTime();
}

@Override
public Watermark
getCurrentWatermark() {
        
// return the watermark as current time minus the maximum time lag
        return new
Watermark(System.currentTimeMillis() - maxTimeLag);
}

}

 

带标点(punctuatedWatermark

为了在某事件下就产生Watermark,我们需要使用AssignerWithPunctuatedWatermarks。在该类中,Flink会先调用extractTimestamp(…)方法来给element赋值一个时间戳,然后针对该element即刻调用checkAndGetNextWatermark(…)方法来返回一个非nullWatermark

 

checkAndGetNextWatermark(…)方法将获得在extractTimestamp(…)方法中获得的时间戳,并决定是否生成Watermark。一旦checkAndGetNextWatermark(…)方法返回一个非nullWatermark,并且该Watermark大于最近的上一个Watermark,则发送该新的Watermark

 

public class PunctuatedAssigner extends AssignerWithPunctuatedWatermarks<MyEvent> {

@Override
public
long extractTimestamp(MyEvent element, long previousElementTimestamp) {
        return element.
getCreationTime();
}

@Override
public Watermark
checkAndGetNextWatermark(MyEvent lastElement, long extractedTimestamp) {
        return element.
hasWatermarkMarker() ? new Watermark(extractedTimestamp) : null;
}

}

 

注意:在每个事件上都生成一个Watermark是可能存在的,但是由于每个Watermark都会导致下游的计算开销,过多的Watermark会降低程序的性能

 

转载于:https://www.cnblogs.com/lanyun0520/p/5749410.html

在 Apache Flink 中,可以使用自定义的 WatermarkGenerator 来生成水位线。水位线用于衡量事件时间进展,帮助确定何时触发窗口计算。 首先,你需要实现 WatermarkGenerator 接口,并覆盖它的两个方法:getCurrentWatermark 和 onEvent。 ```java import org.apache.flink.streaming.api.functions.AssignerWithPunctuatedWatermarks; import org.apache.flink.streaming.api.watermark.Watermark; public class CustomWatermarkGenerator implements AssignerWithPunctuatedWatermarks<Event> { @Override public long extractTimestamp(Event event, long previousTimestamp) { return event.getTimestamp(); } @Override public Watermark checkAndGetNextWatermark(Event lastElement, long extractedTimestamp) { // 在这里根据需要实现水位线的生成逻辑 // 返回一个 Watermark 对象,表示当前的水位线 // 可以使用事件中的时间戳进行计算 return new Watermark(extractedTimestamp - 5000); // 示例:设置水位线为事件时间减去 5 秒 } } ``` 然后,将自定义的 WatermarkGenerator 应用到你的 Flink 程序中: ```java DataStream<Event> events = ...; // 输入事件流 // 应用水位线生成DataStream<Event> eventsWithWatermarks = events.assignTimestampsAndWatermarks(new CustomWatermarkGenerator()); ``` 通过调用 `assignTimestampsAndWatermarks` 方法,并传入自定义的 WatermarkGenerator,即可将水位线应用到事件流上。 请注意,在 `CustomWatermarkGenerator` 中,`extractTimestamp` 方法用于从事件中提取时间戳,用于生成水位线。`checkAndGetNextWatermark` 方法在每个事件到达时被调用,可以根据事件的时间戳计算出水位线。示例中的水位线设置为事件时间减去 5 秒,你可以根据实际需求来实现水位线的生成逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值