使用默认触发器在Windows中使用无界数据

时间:2017-01-03 12:27:56

标签: google-cloud-dataflow apache-beam

我有一个Pub/Sub主题+订阅,并希望在Dataflow中使用和聚合订阅中的无限数据。我使用固定窗口并将聚合写入BigQuery。

读写(没有窗口和聚合)工作正常。但是,当我将数据传输到固定窗口(计算每个窗口中的元素)时,窗口永远不会triggered。因此,不会写出聚合。

这是我的单词发布者(它使用examples中的kinglear.txt作为输入文件):

public static class AddCurrentTimestampFn extends DoFn<String, String> {
    @ProcessElement public void processElement(ProcessContext c) {
        c.outputWithTimestamp(c.element(), new Instant(System.currentTimeMillis()));
    }
}

public static class ExtractWordsFn extends DoFn<String, String> {
    @ProcessElement public void processElement(ProcessContext c) {
        String[] words = c.element().split("[^a-zA-Z']+");
        for (String word:words){ if(!word.isEmpty()){ c.output(word); }}
    }
}

// main:
Pipeline p = Pipeline.create(o); // 'o' are the pipeline options
p.apply("ReadLines", TextIO.Read.from(o.getInputFile()))
        .apply("Lines2Words", ParDo.of(new ExtractWordsFn()))
        .apply("AddTimestampFn", ParDo.of(new AddCurrentTimestampFn()))
        .apply("WriteTopic", PubsubIO.Write.topic(o.getTopic()));
p.run();

这是我的窗口字计数器:

Pipeline p = Pipeline.create(o); // 'o' are the pipeline options

BigQueryIO.Write.Bound tablePipe = BigQueryIO.Write.to(o.getTable(o))
        .withSchema(o.getSchema())
        .withCreateDisposition(BigQueryIO.Write.CreateDisposition.CREATE_IF_NEEDED)
        .withWriteDisposition(BigQueryIO.Write.WriteDisposition.WRITE_APPEND);

Window.Bound<String> w = Window
        .<String>into(FixedWindows.of(Duration.standardSeconds(1)));

p.apply("ReadTopic", PubsubIO.Read.subscription(o.getSubscription()))
        .apply("FixedWindow", w)
        .apply("CountWords", Count.<String>perElement())
        .apply("CreateRows", ParDo.of(new WordCountToRowFn()))
        .apply("WriteRows", tablePipe);
p.run();

上述订阅者无法使用,因为窗口似乎没有使用default trigger触发。但是,如果我手动定义触发器,则代码可以正常工作,并且计数将写入BigQuery。

Window.Bound<String> w = Window.<String>into(FixedWindows.of(Duration.standardSeconds(1)))
        .triggering(AfterProcessingTime
                .pastFirstElementInPane()
                .plusDelayOf(Duration.standardSeconds(1)))
        .withAllowedLateness(Duration.ZERO)
        .discardingFiredPanes();

我希望尽可能避免指定自定义触发器。

问题:

  1. 为什么我的解决方案无法使用Dataflow&#39; default trigger
  2. 如何使用default trigger
  3. 更改发布者或订阅者以触发窗口

1 个答案:

答案 0 :(得分:1)

你如何确定触发器永远不会触发?

您的PubSubIO.WritePubSubIO.Read转换都应使用withTimestampLabel指定时间戳标签,否则您添加的时间戳将不会写入PubSub,发布时间将为使用

无论哪种方式,管道的输入水印都将从PubSub中等待的元素的时间戳得出。一旦所有输入都被处理完毕,它将在退出实时之前保持几分钟(如果发布者有延迟)。

您可能会看到所有元素都在相同的~1秒窗口中发布(因为输入文件非常小)。这些都是相对较快地读取和处理的,但它们放入的1秒窗口在输入水印已经前进之前不会触发,表明该1秒窗口中的所有数据都已被消耗。

直到几分钟才会发生这种情况,这可能会使触发器看起来不起作用。您写入的触发器在处理时间为1秒后触发,这会触发更早,但无法保证所有数据都已处理完毕。

从默认触发器获得更好行为的步骤:

  1. 在写入和读取pubsub步骤上使用withTimestampLabel
  2. 让发布者进一步分发时间戳(例如,运行几分钟并将时间戳分散到该范围内)