Apache Spark - 如何压缩多个RDD

时间:2014-09-18 14:24:11

标签: scala distributed-computing apache-spark

让我说我有一堆RDD,可能是RDD[Int],我有一个函数定义一个int序列的操作并返回一个int,就像一个fold: f: Seq[Int] => Int

如果我有一系列RDD,Seq[RDD[Int]],我该如何应用该函数并返回一个带有结果值的新RDD?我似乎没有在Spark中找到zipPartitions方法来完成此任务。

2 个答案:

答案 0 :(得分:4)

使用zip而不是zipPartitions的简化示例。 (我不知道你的问题描述实际上需要 zipPartitions。)棘手的部分是当你需要的是一个RDD列表时,zip想要返回一对RDD的方式。

// set up an example
val rdd1 = sc.parallelize(Array(1,2,3,4), 2)
val rdd2 = sc.parallelize(Array(11,12,13,14), 2)
val rdd3 = sc.parallelize(Array(21,22,23,24), 2)
val rdd4 = sc.parallelize(Array(31,32,33,34), 2)
val allRDDs = Seq(rdd1, rdd2, rdd3, rdd4)

// zip the RDDs into an RDD of Seq[Int]
def makeZip(s: Seq[RDD[Int]]): RDD[Seq[Int]] = {
  if (s.length == 1) 
    s.head.map(e => Seq(e)) 
  else {
    val others = makeZip(s.tail)
    val all = s.head.zip(others)
    all.map(elem => Seq(elem._1) ++ elem._2)
  }
}

// zip and apply arbitrary function from Seq[Int] to Int
def applyFuncToZip(s: Seq[RDD[Int]], f:Seq[Int] => Int): RDD[Int] = {
  val z = makeZip(s)
  z.map(f)
}

val res = applyFuncToZip(allRDDs, (s: Seq[Int]) => s.sum)
res.foreach(s => println(s))

如果你真的想避免实现列表的实现,而是想逐步应用这个函数,那么解决方案会更复杂。

答案 1 :(得分:2)

在某些时候,Seq[Int]的元素需要绑定到f的参数。是否通过创建集合(“实现列表”)或通过partial function application方式逐个绑定它们来预先发生这种情况,在某些时候需要有一个类似于集合的数据结构,其中包含所有要素。当然,一旦进入f,他们都需要在同一个地方。

这是Spiro的makeZip函数的一个稍微更实用的样式实现:

def makeZip(xs: ListBuffer[RDD[Double]]): RDD[ListBuffer[Double]] = {
  // initialize with arrays of length 1
  val init = xs(0).map { ListBuffer(_) } 
  // fold in remaining by appending to mutable list
  xs.drop(1).foldLeft(init) { 
    (rddS, rddXi) => rddS.zip(rddXi).map(sx => sx._1 += sx._2)
  }
}