我正在使用Chicago Traffic Tracker数据集,每15分钟发布一次新数据。当新数据可用时,它表示距离实时"实时" 10-15分钟的记录。 (example,查找_last_updt
)。
例如,在00:20,我得到数据时间戳00:10;在00:35,我从00:20开始;在00:50,我从00:40开始。所以我可以获得新数据的时间间隔"固定" (每15分钟一次),虽然时间戳的间隔略有变化。
我正在尝试在Dataflow(Apache Beam)上使用这些数据,为此我正在使用Sliding Windows。我的想法是收集和处理4个连续的数据点(4 x 15min = 60min),并且一旦新的数据点可用,理想情况下更新我的和/平均值的计算。为此,我开始使用代码:
PCollection<TrafficData> trafficData = input
.apply("MapIntoSlidingWindows", Window.<TrafficData>into(
SlidingWindows.of(Duration.standardMinutes(60)) // (4x15)
.every(Duration.standardMinutes(15))) . // interval to get new data
.triggering(AfterWatermark
.pastEndOfWindow()
.withEarlyFirings(AfterProcessingTime.pastFirstElementInPane()))
.withAllowedLateness(Duration.ZERO)
.accumulatingFiredPanes());
不幸的是,当我从输入中收到新的数据点时,我没有从GroupByKey
获得新的(更新的)结果。
我的SlidingWindows有问题吗?或者我错过了其他什么?
答案 0 :(得分:2)
一个问题可能是水印越过窗口的末尾,并丢弃所有后来的元素。您可以尝试在水印通过后几分钟:
PCollection<TrafficData> trafficData = input
.apply("MapIntoSlidingWindows", Window.<TrafficData>into(
SlidingWindows.of(Duration.standardMinutes(60)) // (4x15)
.every(Duration.standardMinutes(15))) . // interval to get new data
.triggering(AfterWatermark
.pastEndOfWindow()
.withEarlyFirings(AfterProcessingTime.pastFirstElementInPane())
.withLateFirings(AfterProcessingTime.pastFirstElementInPane()))
.withAllowedLateness(Duration.standardMinutes(15))
.accumulatingFiredPanes());
让我知道这是否有帮助。
答案 1 :(得分:1)
所以@Pablo(根据我的理解)给出了正确的答案。但我有一些不适合评论的建议。
我想问你是否需要推拉窗户?据我所知,固定窗口可以为您完成工作并且计算也更简单。由于您正在使用累积触发窗格,因此您不需要使用滑动窗口,因为您的下一个DoFn函数已经从累积窗格中进行平均。
至于代码,我对早期和晚期的触发逻辑进行了更改。我还建议增加窗口大小。由于您知道数据每15分钟一次,因此您应该在15分钟后关闭窗口而不是15分钟。但你也不想选择一个最终会与15的倍数(如20)碰撞的窗口,因为在60分钟你会遇到同样的问题。因此,选择一个与15相关的数字,例如19.也允许延迟输入。
bash script.sh -f "temp.txt"
如果能解决您的问题,请告诉我们!
修改强>
所以,我无法理解你是如何计算上面的例子的,所以我使用的是一个通用的例子。以下是通用平均函数:
PCollection<TrafficData> trafficData = input
.apply("MapIntoFixedWindows", Window.<TrafficData>into(
FixedWindows.of(Duration.standardMinutes(19))
.triggering(AfterWatermark.pastEndOfWindow()
// fire the moment you see an element
.withEarlyFirings(AfterPane.elementCountAtLeast(1))
//this line is optional since you already have a past end of window and a early firing. But just in case
.withLateFirings(AfterProcessingTime.pastFirstElementInPane()))
.withAllowedLateness(Duration.standardMinutes(60))
.accumulatingFiredPanes());
要运行它,您需要添加以下行:
public class AverageFn extends CombineFn<Integer, AverageFn.Accum, Double> {
public static class Accum {
int sum = 0;
int count = 0;
}
@Override
public Accum createAccumulator() { return new Accum(); }
@Override
public Accum addInput(Accum accum, Integer input) {
accum.sum += input;
accum.count++;
return accum;
}
@Override
public Accum mergeAccumulators(Iterable<Accum> accums) {
Accum merged = createAccumulator();
for (Accum accum : accums) {
merged.sum += accum.sum;
merged.count += accum.count;
}
return merged;
}
@Override
public Double extractOutput(Accum accum) {
return ((double) accum.sum) / accum.count;
}
}
由于您使用累积触发触发器 当前 ,这将是解决该解决方案的最简单的编码方式。
但是,如果您想使用丢弃火窗格窗口,则需要使用PCollection<Double> average = trafficData.apply(Combine.globally(new AverageFn()));
来存储之前的平均值,并将其作为旁边输入传递给下一个平均值,以便跟踪值。这在编码方面稍微复杂一些,但肯定会提高性能,因为每个窗口都会进行不断的工作,这与累积点火不同。
这是否足以让您生成自己的功能以丢弃火窗格窗口?