为什么Spark需要折叠动作?

时间:2015-12-30 12:54:47

标签: apache-spark pyspark rdd reduce fold

我在fold中涉及PySpark和减少的愚蠢问题。我理解这两种方法之间的区别,但是,如果两者都需要应用函数是一个可交换的monoid,我就无法找出fold cannot be substituted by reduce`的例子。

此外,在fold的PySpark实现中,它使用acc = op(obj, acc),为什么使用此操作顺序而不是acc = op(acc, obj)? (这个第二个订单听起来更接近于leftFold对我来说

干杯

托马斯

1 个答案:

答案 0 :(得分:11)

清空RDD

RDD为空时无法替换:

val rdd = sc.emptyRDD[Int]
rdd.reduce(_ + _)
// java.lang.UnsupportedOperationException: empty collection at   
// org.apache.spark.rdd.RDD$$anonfun$reduce$1$$anonfun$apply$ ...

rdd.fold(0)(_ + _)
// Int = 0

您当然可以将reduceisEmpty上的条件结合起来,但它相当丑陋。

可变缓冲区

fold的另一个用例是使用可变缓冲区进行聚合。考虑遵循RDD:

import breeze.linalg.DenseVector

val rdd = sc.parallelize(Array.fill(100)(DenseVector(1)), 8)

让我们说我们想要所有元素的总和。一个天真的解决方案是简单地减少+

rdd.reduce(_ + _)

不幸的是,它为每个元素创建了一个新的向量。由于对象创建和后续垃圾收集很昂贵,因此使用可变对象可能更好。使用reduce是不可能的(RDD的不变性并不意味着元素的不变性),但可以使用fold实现如下:

rdd.fold(DenseVector(0))((acc, x) => acc += x)

这里使用零元素作为每个分区初始化一次的可变缓冲区,保持实际数据不变。

  

acc = op(obj,acc),为什么使用此操作订单而不是acc = op(acc,obj)

请参阅SPARK-6416SPARK-7683