是否有更好的方法来减少RDD上的操作[数组[双]]

时间:2015-06-24 12:11:01

标签: scala apache-spark reduce rdd

我想减少一个RDD [Array [Double]],以便将数组的每个元素添加到下一个数组的相同元素中。 我暂时使用此代码:

var rdd1 = RDD[Array[Double]]

var coord = rdd1.reduce( (x,y) => { (x, y).zipped.map(_+_) })

是否有更好的方法可以提高效率,因为它会造成伤害。

2 个答案:

答案 0 :(得分:4)

使用zipped.map是非常低效的,因为它会创建大量的临时对象并将盒子打包成双打。

如果您使用spire,则可以执行此操作

> import spire.implicits._
> val rdd1 = sc.parallelize(Seq(Array(1.0, 2.0), Array(3.0, 4.0)))
> var coord = rdd1.reduce( _ + _)
res1: Array[Double] = Array(4.0, 6.0)

这样看起来更好,也应该 更有效率。

Spire是spark的依赖项,因此您应该能够在没有任何额外依赖项的情况下执行上述操作。至少它在这里使用火花壳为火花1.3.1。

这适用于任何可用于元素类型的AdditiveSemigroup类型类实例的数组。在这种情况下,元素类型为Double。 Spire类型类是@specialized为double,所以任何地方都不会有拳击。

如果你真的想知道发生了什么,你必须使用reify:

> import scala.reflect.runtime.{universe => u}
> val a = Array(1.0, 2.0)
> val b = Array(3.0, 4.0)
> u.reify { a + b }

res5: reflect.runtime.universe.Expr[Array[Double]] = Expr[scala.Array[Double]](
  implicits.additiveSemigroupOps(a)(
    implicits.ArrayNormedVectorSpace(
      implicits.DoubleAlgebra, 
      implicits.DoubleAlgebra,
      Predef.this.implicitly)).$plus(b))

因此添加有效,因为有一个AdditiveSemigroup for Array [Double]的实例。

答案 1 :(得分:0)

我认为你担心的是你有一个非常大的Array [Double]并且所写的转换不会分配它们的添加。如果是这样,你可以做一些像(未经测试的):

// map Array[Double] to (index, double)
val rdd2 = rdd1.flatMap(a => a.zipWithIndex.map(t => (t._2,t._1))
// get the sum for each index
val reduced = rdd2.reduceByKey(_ + _)
// key everything the same to get a single iterable in groubByKey
val groupAll = reduced.map(t => ("constKey", (t._1, t._2)
// get the doubles back together into an array
val coord = groupAll.groupByKey { (k,vs) => 
                     vs.toList.sortBy(_._1).toArray.map(_._2) }