让我用一个有点人为的例子来解释我试图做的事情。想象一下,我有一系列交易,包括股票代码,股票数量和价格: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。
答案 0 :(得分:3)
我将描述两种选择。一个使用侧输入,它应该与当前版本的Dataflow(1.X)一起使用,另一个使用undoManager.registerUndo(withTarget: self) {
savedPairs.forEach { $0.id.number = $0.originalValue }
}
内的状态,它应该是即将到来的数据流(2.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.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