Apache flink KeyedStream.process之后,assignTimestampsAndWatermarks不起作用

Apache flink KeyedStream.process之后,assignTimestampsAndWatermarks不起作用,apache-flink,Apache Flink,在keyBy工作之前分配时间戳和水印: datastreamtrips= env.addSource(consumer.assignTimestampsAndWatermarks(新的BoundedAutofordernessTimestampExtractor(Time.days(1)){ @凌驾 公共长提取时间戳(行程){ return trip.endTime.getTime(); } }); KeyedStream userTrips=trips.keyBy(trip->trip.use

keyBy
工作之前分配时间戳和水印

datastreamtrips=
env.addSource(consumer.assignTimestampsAndWatermarks(新的BoundedAutofordernessTimestampExtractor(Time.days(1)){
@凌驾
公共长提取时间戳(行程){
return trip.endTime.getTime();
}
});
KeyedStream userTrips=trips.keyBy(trip->trip.userId);
DataStream featureizedusertrips=userTrips.process(new featureization());
所有WindowedStream windowedUserTrips=
FeatureizedUserTrips.timeWindowAll(Time.days(7),
时间:天(1));
但不是在
keyBy
过程之后:

datastreamtrips=env.addSource(消费者);
KeyedStream userTrips=trips.keyBy(trip->trip.userId);
数据流FeatureizedUserTrips=
process(new featureization()).assignTimestampsAndWatermarks(new boundedAutofordernessTimestampExtractor(Time.days(1)){
@凌驾
公共长提取时间戳(FeatureizedTrip行程){
return trip.endTime.getTime();
}
});
所有WindowedStream windowedUserTrips=
FeatureizedUserTrips.timeWindowAll(Time.days(7),
时间:天(1));
窗口永远不会被触发


这是一个bug还是预期的行为?如果是后者,记录在哪里?

我也有类似的问题。在我的例子中,我有一个读取文件的源,它的每个实例都读取一个单独的文件。在向数据流发送一个文件的最简单测试中,只有一个源实例正在生成事件,而其他实例处于空闲状态。因此,在应用了水印赋值器之后,当我使用带有周期性水印的赋值器时,只有一个水印赋值器正在发送新的水印,而其他的没有,或者他们正在发送
Long.MIN_VALUE

应用
keyBy()
运算符后,空闲事件流与活动事件流混合。由于在任何操作符上计算水印的规则是从每个传入流中取最小值,因此链中下一个操作符的每个实例,
process()
,都保持在水印
Long.MIN\u值上。因此,应用
keyBy()

我的解决方案是在分配水印之前对事件进行洗牌。在watermarks assigner运算符上,规则正好相反–始终获取并重新发送计算出的最高水印。通过这种方式,我们可以保证水印赋值器的所有实例都在发送水印,即使某些源实例处于空闲状态:

stream.rebalance().assignTimestampsAndWatermarks(...);
这里还有一个你必须避免的陷阱。如果您决定在源实例未收集数据时将其声明为空闲,请执行以下操作:

context.markAsTemporarilyIdle();
您将发现水印再次丢失,即使上面使用
rebalance()
进行的黑客攻击已经到位。这是因为
markAsTemporarilyIdle()
将相应的流设置为空闲,并且在代码的这一部分(来自Flink 1.7):


水印已停止,因为条件
streamStatusProvider.getStreamStatus().isActive()
为false。因此,结论是不要在所描述的情况下使用
context.markAsTemporarilyIdle()

我也有类似的问题。在我的例子中,我有一个读取文件的源,它的每个实例都读取一个单独的文件。在向数据流发送一个文件的最简单测试中,只有一个源实例正在生成事件,而其他实例处于空闲状态。因此,在应用了水印赋值器之后,当我使用带有周期性水印的赋值器时,只有一个水印赋值器正在发送新的水印,而其他的没有,或者他们正在发送
Long.MIN_VALUE

应用
keyBy()
运算符后,空闲事件流与活动事件流混合。由于在任何操作符上计算水印的规则是从每个传入流中取最小值,因此链中下一个操作符的每个实例,
process()
,都保持在水印
Long.MIN\u值上。因此,应用
keyBy()

我的解决方案是在分配水印之前对事件进行洗牌。在watermarks assigner运算符上,规则正好相反–始终获取并重新发送计算出的最高水印。通过这种方式,我们可以保证水印赋值器的所有实例都在发送水印,即使某些源实例处于空闲状态:

stream.rebalance().assignTimestampsAndWatermarks(...);
这里还有一个你必须避免的陷阱。如果您决定在源实例未收集数据时将其声明为空闲,请执行以下操作:

context.markAsTemporarilyIdle();
您将发现水印再次丢失,即使上面使用
rebalance()
进行的黑客攻击已经到位。这是因为
markAsTemporarilyIdle()
将相应的流设置为空闲,并且在代码的这一部分(来自Flink 1.7):


水印已停止,因为条件
streamStatusProvider.getStreamStatus().isActive()
为false。因此,结论是不要在所描述的情况下使用
context.markasTemporaryIdle()

我不确定,但->Everywhere(flink文档和图书流媒体系统)建议在处理事件时间时,在源代码中或尽可能靠近源代码分配水印。问题是,当您的数据通过管道处理时,每个操作符都使用指定的水印,当您执行keyby操作时,您会混合数据。作为调试它的一种方法->在时间
windowAll
之后添加
.trigger(new MyTriggerFunction())
并从上下文currentWatermark获取元素和。通过这种方式,您可以看到您的水印是否及时移动(您是否接收到数据)或被阻塞。如果您决定尝试此方法,请告诉我结果,我想知道这是原因:)我不确定,但->无处不在(flink