假设我有一个Double值流,我想每十秒计算一次平均值。我怎样才能有一个滑动窗口,不需要重新计算平均值,而是更新它,比如说,删除最旧的十秒部分,只添加新的10秒值?
答案 0 :(得分:1)
TL;DR:使用reduceByWindow
及其两个函数参数(跳转到代码段的最后一段)
您的问题有两种解释,具体的解释(如何获得一小时的运行平均值,每2秒更新一次)和一般的解释(如何获得更新状态的计算?稀疏的方式)。这是普通人的答案。
首先,请注意有一种方法可以表示您的数据,以便根据windowed DStream轻松计算您的平均更新数据:这表示您的数据是流的增量构造,具有最大值分享。但是,正如你所指出的那样,重新计算每批产品的平均值在计算上效率较低。
如果你确实想要更新一个可逆的复杂有状态计算,但又不想触及流的构造,那就有updateStateByKey
- 但Spark并没有&# 39; t帮助您反映流中计算的增量方面,您必须自己管理它。
在这里,你确实有一些简单易懂的东西,而且你没有钥匙的概念。您可以使用reduceByWindow
及其反向减少参数,使用通常的函数来计算增量平均值。
val myInitialDStream: DStream[Float]
val myDStreamWithCount: DStream[(Float, Long)] =
myInitialDStream.map((x) => (x, 1L))
def addOneBatchToMean(previousMean: (Float, Long), newBatch: (Float, Long)): (Float, Long) =
(previousMean._1 + newBatch._1, previousMean._2 + newBatch._2)
def removeOneBatchToMean(previousMean: (Float, Long), oldBatch: (Float, Long)): (Float, Long) =
(previousMean._1 - oldBatch._1, previousMean._2 - oldBatch._2)
val runningMeans = myDStreamWithCount.reduceByWindow(addOneBatchToMean, removeOneBatchToMean, Durations.seconds(3600), Duractions.seconds(2))
你得到一个单元素RDD
的流,每个元素包含一对(m,n),其中m是你在1h窗口上的运行总和,n是1h中元素的数量 - 窗口。只需返回(或map
至)m / n即可获得均值。