火花RDD折叠方法的说明

时间:2015-07-17 13:11:14

标签: scala apache-spark rdd

我正在为Hadoop-2.4(本地模式)预先构建Spark-1.4.0,以计算DoubleRDD的平方和。我的Scala代码看起来像

sc.parallelize(Array(2., 3.)).fold(0.0)((p, v) => p+v*v)

它给出了令人惊讶的结果97.0

与Scala版fold

相比,这是非常直观的
Array(2., 3.).fold(0.0)((p, v) => p+v*v)

给出了预期答案13.0

由于缺乏理解,我很可能在代码中犯了一些棘手的错误。我已经了解了RDD.fold()中使用的函数应该如何通信,否则结果可能取决于分区等。例如,如果我将分区数更改为1,

sc.parallelize(Array(2., 3.), 1).fold(0.0)((p, v) => p+v*v)

代码会在我的机器上给我169.0

有人可以解释这里到底发生了什么吗?

1 个答案:

答案 0 :(得分:8)

嗯,实际上很好地解释了official documentation

  

使用给定的关联和交换函数以及中性"零值"来聚合每个分区的元素,然后聚合所有分区的结果。函数op(t1,t2)允许修改t1并将其作为结果值返回以避免对象分配;但是,它不应该修改t2。

     

这与在Scala等函数式语言中为非分布式集合实现的折叠操作略有不同。该折叠操作可以单独地应用于分区,然后将这些结果折叠成最终结果,而不是以某种定义的顺序将折叠顺序地应用于每个元素。对于不可交换的函数,结果可能与应用于非分布式集合的折叠的结果不同。

为了说明正在发生的事情,我们尝试逐步模拟正在发生的事情:

val rdd = sc.parallelize(Array(2., 3.))

val byPartition = rdd.mapPartitions(
    iter => Array(iter.fold(0.0)((p, v) => (p +  v * v))).toIterator).collect()

它为我们提供了与此Array[Double] = Array(0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 9.0)

类似的内容
byPartition.reduce((p, v) => (p + v * v))

返回97

需要注意的重要一点是,结果可能因运行而异,具体取决于组合分区的顺序。