我正在创建一个管道,该管道吸收无限制的数据源并进行聚合计算。根据事件时间在10分钟的窗口中进行计算,并为延迟到达的事件在5分钟的缓冲区内进行计算。 我想让聚合的结果在经过10分钟的窗口和5分钟的缓冲区之后仅发出一次。
我不知道如何使窗口只发出一次结果。我相信正确的方法是使用AfterWatermark
触发器,但是如果我使用的是withLateFirings()
,则在经过窗口之后和经过较晚的触发时间之后,结果将发出两次。如果不使用延迟触发,则延迟事件将不包含在计算中,这不能满足我的要求。
public class WindowFactory {
private static final Duration FIVE_MINUTES = Duration.standardMinutes(5);
public static Window<Message> getMessageFixedWindow(Duration duration) {
return Window.<Message>into(FixedWindows.of(duration))
.triggering(
AfterWatermark
.pastEndOfWindow()
.withLateFirings(
AfterProcessingTime
.pastFirstElementInPane()
.plusDelayOf(FIVE_MINUTES)))
.discardingFiredPanes()
.withAllowedLateness(FIVE_MINUTES);
}
}
请建议我一个好方法,仅在10分钟的窗口和5分钟的缓冲后才能产生1个结果。
答案 0 :(得分:0)
您现在设置的内容将触发两次,一次是在水印通过窗口末尾时发生,另一次是在后期数据缓冲区窗口关闭时发生。
仅通过触发器无法禁用窗口结尾处的第一次触发。但是,您可以检测到您正在看到第一个点火并忽略它。通过检查Pane.IsLast()。
@ProcessElement
public void processElement(ProcessContext c) {
if (!c.pane().isLast()) {
return;
}
}
对于没有最新数据的情况,您无法在窗口末尾触发系统。系统不知道是否有延迟数据到达这一点。虽然,我认为您并不是专门问这个问题,我只是想提一提。
答案 1 :(得分:0)
尝试从this帖子中找到解决方案:
// We first specify to never emit any panes
.triggering(Never.ever())
// We then specify to fire always when closing the window. This will emit a
// single final pane at the end of allowedLateness
.withAllowedLateness(FIVE_MINUTES, Window.ClosingBehavior.FIRE_ALWAYS)
.discardingFiredPanes())
如代码注释中所述,您首先使用Never.ever()
触发器,以使窗口永远不会触发,因此,当水印通过窗口末尾时将不会触发。使用将覆盖触发器的关闭行为Window.ClosingBehavior.FIRE_ALWAYS
,可以确保在允许的延迟之后,始终在关闭窗口时触发窗格。
这将导致在10分钟的窗口+ 5分钟的延迟缓冲后触发1个窗格。