我在fold
中涉及PySpark
和减少的愚蠢问题。我理解这两种方法之间的区别,但是,如果两者都需要应用函数是一个可交换的monoid,我就无法找出fold cannot be substituted by
reduce`的例子。
此外,在fold
的PySpark实现中,它使用acc = op(obj, acc)
,为什么使用此操作顺序而不是acc = op(acc, obj)
? (这个第二个订单听起来更接近于leftFold
对我来说
干杯
托马斯
答案 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
您当然可以将reduce
与isEmpty
上的条件结合起来,但它相当丑陋。
可变缓冲区
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)