加入一个"表"在Dataflow中

时间:2017-01-10 13:40:26

标签: google-cloud-platform google-cloud-dataflow

让我用一个有点人为的例子来解释我试图做的事情。想象一下,我有一系列交易,包括股票代码,股票数量和价格:class Program { static void Main(string[] args) { int intBorder = 1900; int intN = int.Parse(Console.ReadLine()); for (int i = 0; i < intBorder; i++) { Storer.Store(Console.ReadLine().Split()); } } static class Storer { public static readonly List<int> listPoints = new List<int>(); public static readonly List<int> listRanks = new List<int>(); public static void Store(string[]data) { listPoints.Add(int.Parse(data[0])); listRanks.Add(int.Parse(data[1])); } } } 。我想用股票的名称来丰富这些事件,在这种情况下{ symbol = "GOOG", count = 30, price = 200 }

为此目的,我希望在Dataflow内部,维护一个&#34;表&#34; of symbol-&gt;由"Google"更新的名称映射,并将此交易流加入此表,产生例如PCollection<KV<String, String>>

这似乎是流处理应用程序的一个彻底的基本用例,但我很难弄清楚如何在Dataflow中实现这一点。我知道Kafka Streams可以做到这一点。

请注意,我想要使用外部数据库进行查找 - 我需要在Dataflow中解决此问题或切换到Kafka Streams。

1 个答案:

答案 0 :(得分:3)

我将描述两种选择。一个使用侧输入,它应该与当前版本的Dataflow(1.X)一起使用,另一个使用undoManager.registerUndo(withTarget: self) { savedPairs.forEach { $0.id.number = $0.originalValue } } 内的状态,它应该是即将到来的数据流(2.X)的一部分。

Dataflow 1.X的解决方案,使用侧输入

这里的一般想法是使用地图值side-input使符号 - &gt;名称映射可供所有工作人员使用。

此表需要位于全局窗口中(因此没有任何老化),需要触发每个元素(或者您希望生成新的更新),并在所有触发中累积元素。它还需要一些逻辑来为每个符号采用最新的名称。

此解决方案的缺点是每次新条目进入时都会重新生成整个查找表,并且不会立即将其推送给所有工作人员。相反,每个人都将在未来“在某个时刻”获得新的映射。

在高级别,这个管道可能看起来像(我没有测试过这段代码,所以可能有一些类型):

DoFn

请注意,我们必须在此处使用PCollection<KV<Symbol, Name>> symbolToNameInput = ...; final PCollectionView<Map<Symbol, Iterable<Name>>> symbolToNames = symbolToNameInput .apply(Window.into(GlobalWindows.of()) .triggering(Repeatedly.forever(AfterProcessingTime .pastFirstElementInPane() .plusDelayOf(Duration.standardMinutes(5))) .accumulatingFiredPanes()) .apply(View.asMultiMap()) 。这意味着我们实际上为每个符号建立了所有的名称。当我们查看时,我们需要确保在iterable中使用最新的名称。

viewAsMultiMap

Dataflow 2.X的解决方案,使用State API

此解决方案使用了一项新功能,该功能将成为即将推出的Dataflow 2.0版本的一部分。它还不是预览版本(目前是Dataflow 2.0-beta1)的一部分,但您可以观看release notes以查看它何时可用。

一般的想法是,键控状态允许我们存储与特定键相关联的一些值。在这种情况下,我们将记住我们见过的最新“名称”值。

在运行有状态PCollection<Detail> symbolDetails = ...; symbolDetails .apply(ParDo.withSideInputs(symbolToNames).of(new DoFn<Detail, AugmentedDetails>() { @Override public void processElement(ProcessContext c) { Iterable<Name> names = c.sideInput(symbolToNames).get(c.element().symbol()); Name name = chooseName(names); c.output(augmentDetails(c.element(), name)); } })); 之前,我们要将每个元素包装成一个公共元素类型(DoFn)对象。这看起来如下所示:

NameOrDetails