在键上加入2个无限制的Pcollect

时间:2019-04-15 20:47:31

标签: java stream google-cloud-dataflow apache-beam apache-beam-io

我正在尝试加入两个我在一个键的基础上从2个不同的kafka主题获得的无限制的PCollection。

根据文档和其他博客,仅当我们进行窗口化时,才可以加入。窗口从特定窗口中的两个流中收集消息并将其加入。这不是我所需要的。

预期结果是,一条消息中的消息以非常低的频率发送,而其他消息中的消息以高频率得到。我希望如果键的值没有同时到达两个流,则直到那时我们才进行连接,并且在到达之后再进行连接。 是否可以使用当前的光束范例?

2 个答案:

答案 0 :(得分:2)

简而言之,最好的解决方案是在Beam中使用有状态的DoFn。您可以具有每个键状态(和每个窗口,在您的情况下为全局窗口)。您可以将一个流事件保存在状态中,并且一旦另一个流中的事件使用相同的键出现,则将其与状态中的事件一起加入。这是参考文献[1]。

但是,简短的答案没有利用Beam模型的真实功效。 Beam模型提供了在延迟,成本和准确性之间取得平衡的方法。它提供了简单的API以隐藏复杂的流处理。

为什么我这么说?让我们回到简短答案的解决方案:有状态的DoFn。在有状态DoFn方法中,您缺少解决以下问题的方法:

  • 如果您为一个键缓冲了1M个事件,但又没有事件从另一个流中出现,该怎么办?您是否需要清空状态?如果您清空状态后事件立即出现怎么办?
  • 如果最终有一个事件似乎完成了JOIN,那么缓冲1M事件的成本是否可以接受JOIN中来自另一个流的单个事件?
  • 如何处理两个流中的延迟日期?假设您已从右流的<1,b>的左流加入<1, a>。稍后从左流还有另一个<1, c>,您怎么知道只需要发射<1, <c, b>>,假设这是增量模式即可输出结果。如果您开始缓冲那些已经加入的事件以获取增量,那么对于程序员来说确实变得太复杂了。

光束的窗口化,触发,对输出数据的优化,水印和延迟SLA控件旨在向您隐藏以下复杂对象:

  • 水印:告诉窗口何时完成,这样事件就不会再来了(以后的事件将被视为较晚的数据)
  • 延迟SLA控件:控制您缓存要加入的数据的时间。
  • 优化输出数据:如果允许新事件到达,则正确更新输出。

尽管Beam模型设计合理。 Beam模型的实现缺少支持您描述的联接的关键功能:

  • 窗口的灵活性不足以支持您的情况,即流具有巨大的不同频率(因此固定窗口和滑动窗口不适合)。而且您也不知道流的到达率(因此会话窗口并不适合,因为您必须在会话窗口之间留出间隔)。
  • 缺少撤消功能,因此一旦迟到事件就无法调整输出。

总而言之,Beam模型旨在处理流处理中的复杂问题,非常适合您的需求。但是该实现不足以让您现在使用它来完成您的联接用例。

[1] https://beam.apache.org/blog/2017/02/13/stateful-processing.html

答案 1 :(得分:0)

当今的Beam模型并不能很好地支持这一点,但是有几种方法可以实现。这些示例假定每个键在每个流上仅出现一次,如果不是这种情况,则需要进行调整。

一种选择是使用Global WindowStateful DoFn代替Join。全局窗口有效地关闭了窗口。有状态的DoFn可让您将有关要处理的密钥的数据存储在“状态单元”中,以备后用。收到记录时,将检查状态单元格中的值。如果找到一个,则执行联接,发出值并清除状态。如果没有任何内容,请存储当前值。

另一种选择是使用Session Windows和Join。会话窗口“ GapDuration”实际上是给定密钥的超时。只要有时间限制,您就可以在两个流中看到密钥。您还希望设置一个元素计数触发器“ AfterPane.elementCountAtLeast(2)”,这样您就不必在看到第二条数据后就等待整个超时。