我想减少一个RDD [Array [Double]],以便将数组的每个元素添加到下一个数组的相同元素中。 我暂时使用此代码:
var rdd1 = RDD[Array[Double]]
var coord = rdd1.reduce( (x,y) => { (x, y).zipped.map(_+_) })
是否有更好的方法可以提高效率,因为它会造成伤害。
答案 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) }