指定10分钟窗口+ 5分钟延迟缓冲的正确触发仅产生1个结果

时间:2019-07-25 09:46:44

标签: google-cloud-dataflow apache-beam

我正在创建一个管道,该管道吸收无限制的数据源并进行聚合计算。根据事件时间在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个结果。

2 个答案:

答案 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个窗格。