我踩过一个有趣的观察,试图对流处理的聚合结果进行交叉检查。我创建了一个测试用例,其中将预定义的数据集输入到日记地图中,并且聚合应该填充1个结果,因为它与窗口大小/滑动度和带有预定时间戳的数据量一致。但是结果从未公布。没有发出窗口,但是执行了很少的累加/组合操作。它与实际数据的工作方式不同,但是聚合的结果始终“落后于”从源提取的数据量。我想这与水印有关吗?如何在测试用例中确保它不等待更多数据出现。允许延迟帮助吗?
答案 0 :(得分:2)
首先,我将为您介绍手册中的两个部分,它们描述水印的工作方式,并讨论流偏斜的概念:
Jet中的“当前时间”概念只有在时间戳记提前的情况下才有所发展。通常,有几个因素在起作用:
允许的延迟时间:假设您使用的是Kafka之类的分区源,这定义了每个分区的延迟。这描述了单个分区中时间戳的可容许乱序程度。如果允许的延迟为2秒,则仅当您在所有输入分区的N + 2秒处收到事件时,窗口才会关闭。
流偏斜:例如,当您有10个Kafka分区但只有3个正在产生任何事件时,就会发生这种情况。当Jet从所有分区合并水印时,这将导致流等待直到其他7个分区具有一些数据。超时后,这些分区将被视为空闲,但是默认情况下为60秒,并且当前无法在管道API中进行配置。因此,在这种情况下,除非将这些分区标记为空闲,否则您将没有任何输出。
使用测试数据时,事件量很少且分区很多是很常见的,这可能会给正确延长时间带来挑战。
答案 1 :(得分:1)
Can Gencer的答案中的点是有效的。但是为了进行测试,您也可以使用批处理源,例如Sources.list
。通过将时间戳添加到BatchStage
,可以将其转换为StreamStage
,可以在其上进行窗口聚合。 aggregate
转换将在批处理结束时发出挂起的窗口。
JetInstance inst = Jet.newJetInstance();
IListJet<TimestampedEntry<String, Integer>> list = inst.getList("data");
list.add(new TimestampedEntry(1, "a", 1));
list.add(new TimestampedEntry(1, "b", 2));
list.add(new TimestampedEntry(1, "a", 3));
list.add(new TimestampedEntry(1, "b", 4));
Pipeline p = Pipeline.create();
p.drawFrom(Sources.<TimestampedEntry<String, Integer>>list("data"))
.addTimestamps(TimestampedEntry::getTimestamp, 0)
.groupingKey(TimestampedEntry::getKey)
.window(tumbling(1))
.aggregate(AggregateOperations.summingLong(TimestampedEntry::getValue))
.drainTo(Sinks.logger());
inst.newJob(p).join();
inst.shutdown();
上面的代码打印:
TimestampedEntry{ts=01:00:00.002, key='a', value='4'}
TimestampedEntry{ts=01:00:00.002, key='b', value='6'}
请记住,当我们使用allowedLag=0
时,将您的数据按时间顺序排列在列表中。
答案对Jet 0.6.1。有效。