[英]spark aggregatebykey - sum and running average in the same call
我正在学习火花,并且没有使用hadoop的经验。
问题
我正在尝试在对AggregateByKey的同一调用中计算总和和平均值。
让我分享到目前为止我所做的尝试。
设置数据
val categoryPrices = List((1, 20), (1, 25), (1, 10), (1, 45))
val categoryPricesRdd = sc.parallelize(categoryPrices)
尝试在对AggregateByKey的同一调用中计算平均值。 这是行不通的。
val zeroValue1 = (0, 0, 0.0) // (count, sum, average)
categoryPricesRdd.
aggregateByKey(zeroValue1)(
(tuple, prevPrice) => {
val newCount = tuple._1 + 1
val newSum = tuple._2 + prevPrice
val newAverage = newSum/newCount
(newCount, newSum, newAverage)
},
(tuple1, tuple2) => {
val newCount1 = tuple1._1 + tuple2._1
val newSum1 = tuple1._2 + tuple2._2
// TRYING TO CALCULATE THE RUNNING AVERAGE HERE
val newAverage1 = ((tuple1._2 * tuple1._1) + (tuple2._2 * tuple2._1))/(tuple1._1 + tuple2._1)
(newCount1, newSum1, newAverage1)
}
).
collect.
foreach(println)
结果:每次打印不同的平均值
只需先求和,然后在单独的操作中计算平均值。 这可行。
val zeroValue2 = (0, 0) // (count, sum, average)
categoryPricesRdd.
aggregateByKey(zeroValue2)(
(tuple, prevPrice) => {
val newCount = tuple._1 + 1
val newSum = tuple._2 + prevPrice
(newCount, newSum)
},
(tuple1, tuple2) => {
val newCount1 = tuple1._1 + tuple2._1
val newSum1 = tuple1._2 + tuple2._2
(newCount1, newSum1)
}
).
map(rec => {
val category = rec._1
val count = rec._2._1
val sum = rec._2._2
(category, count, sum, sum/count)
}).
collect.
foreach(println)
每次都打印相同的结果:(1,4,100,25)
我想我了解seqOp和CombOp之间的区别。 鉴于操作可以在不同服务器上的多个分区之间拆分数据,我的理解是seqOp对单个分区中的数据进行操作,然后combOp合并从不同分区接收的数据。 如果这是错误的,请更正。
但是,有一些我不太了解的基本知识。 看起来我们无法在同一调用中同时计算总和和平均值。 如果是这样,请帮助我理解原因。
与seqOp
的average
聚合有关的计算:
val newAverage = newSum/newCount
并在combOp
:
val newAverage1 = ((tuple1._2 * tuple1._1) + (tuple2._2 * tuple2._1)) / (tuple1._1 + tuple2._1)
是不正确的。
假设前三个元素在一个分区中,最后一个元素在另一个分区中。 您的seqOp
将生成(计数,总和,平均值)元组,如下所示:
Partition #1: [20, 25, 10]
--> (1, 20, 20/1)
--> (2, 45, 45/2)
--> (3, 55, 55/3)
Partition #2: [45]
--> (1, 45, 45/1)
接下来,跨分区combOp
将合并两个分区中的2个元组,得到:
((55 * 3) + (45 * 1)) / 4
// Result: 52
从上述步骤可以看到,如果RDD元素的顺序或分区不同,则average
可能会不同。
您的第二种方法有效,因为按定义, average
是总和超过总计数,因此在先计算总和和计数值之后可以更好地进行计算。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.