我有一个看起来像
的管道pipeline.apply(PubsubIO.read.subscription("some subscription"))
.apply(Window.into(SlidingWindow.of(10 mins).every(20 seconds)
.triggering(AfterProcessingTime.pastFirstElementInPane()
.plusDelayOf(20 seconds))
.withAllowedLateness(Duration.ZERO)
.accumulatingFiredPanes()))
.apply(RemoveDuplicates.create())
.apply(Window.discardingFiredPanes()) // this is suggested in the warnings under https://cloud.google.com/dataflow/model/triggers#window-accumulation-modes
.apply(Count.<String>globally().withoutDefaults())
此管道显着地超过了不同的值(20倍正常值)。最初,我怀疑默认触发器可能导致了这个问题。我已经调整使用触发器,它不允许延迟/丢弃触发窗格/使用处理时间,所有这些都有类似的过度计数问题。
我也试过ApproximateUnique.globally
:它在管道构建期间失败了,因为看起来像是异常
Default values are not supported in Combine.globally() if the output PCollection is not windowed by GlobalWindows.
似乎无法向其添加withoutDefaults
(就像我们对Count.globally
所做的那样)。
是否建议以合理的精度在数据流/波束流管道中执行COUNT(DISTINCT)
?
P.S。我正在使用Java Dataflow SDK 1.9.0。
答案 0 :(得分:2)
您的代码看起来不错;它不应该超额计算。请注意,您将每个元素放置在30个窗口中,因此如果您有一个不知道窗口的接收器(相当于折叠所有滑动窗口),那么您可以期望精确到30倍的元素。如果您可以显示更多的管道或如何观察计数,那可能会有所帮助。
除此之外,我对管道提出了一些建议:
RemoveDuplicates
的触发器更改为AfterPane.elementCountAtLeast(1)
;这将在较低的延迟时间内获得相同的结果,因为后来的元素到达将没有任何影响。此触发器和您当前的触发器将永远不会重复触发。因此,无论您设置accumulatingFiredPanes()
还是discardingFiredPanes()
,实际上并不重要。这很好,因为没有人可以使用你的其他管道。Count
之前安装新触发器。原因有点技术性,但我会尝试描述它:
RemoveDuplicates
的触发器的“延续触发器”)记录第一个元素的到达时间,并等待它收到在或之前生成的所有元素处理时间,由上游工作人员测量。有一些不确定性,因为它会影响当地的处理时间和其他工人的处理时间。RemoveDuplicates
的触发器,则继续触发器将为AfterPane.elementCountAtLeast(1)
,因此它将始终尽快发出计数,然后丢弃更多数据,这非常错。