Scala ApacheSpark-如何压缩多个RDD

Scala ApacheSpark-如何压缩多个RDD,scala,distributed-computing,apache-spark,Scala,Distributed Computing,Apache Spark,假设我有一堆RDD,可能是RDD[Int],我有一个函数,它定义了一个Int序列上的操作并返回一个Int,比如fold:f:Seq[Int]=>Int 如果我有一个RDD序列,Seq[RDD[Int]],如何应用该函数并返回一个新的RDD和结果值?我似乎没有在Spark中找到一个zipPartitions方法来实现这一点。一个使用zip而不是zipPartitions的简化示例。(我看不出您的问题描述实际需要zipPartitions的地方。)棘手的部分是,当您需要的是列表的RDD时,zip想要

假设我有一堆RDD,可能是
RDD[Int]
,我有一个函数,它定义了一个Int序列上的操作并返回一个Int,比如fold:
f:Seq[Int]=>Int


如果我有一个RDD序列,
Seq[RDD[Int]]
,如何应用该函数并返回一个新的RDD和结果值?我似乎没有在Spark中找到一个
zipPartitions
方法来实现这一点。

一个使用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))

如果您确实希望避免列表的具体化,而是希望以增量方式应用函数,那么解决方案将更加复杂

一个使用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))

如果您确实希望避免列表的具体化,而是希望以增量方式应用函数,那么解决方案将更加复杂

在某一点上,
Seq[Int]
的元素需要绑定到
f
的参数。无论是通过创建集合(“具体化列表”)还是通过以某种方式逐个绑定它们,在某个时候都需要一个包含所有元素的类似集合的数据结构。当然,一旦进入
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)
  }
}

在某些点上,
Seq[Int]
的元素需要绑定到
f
的参数。无论是通过创建集合(“具体化列表”)还是通过以某种方式逐个绑定它们,在某个时候都需要一个包含所有元素的类似集合的数据结构。当然,一旦进入
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)
  }
}

rdd1.fold(0,f)++rdd2.fold(0,f)
这样的东西能工作吗?不,不是真的,rdd工作有点不同,我需要得到分区并在它们上面使用
f
。像
rdd1.fold(0,f)++rdd2.fold(0,f)
这样的东西能工作吗?不,不是真的,rdd工作有点不同,我需要获得分区并在其上使用
f
。谢谢您的回答!不过我不想把这些清单具体化。谢谢你的回答!但是我不想具体化这些列表。我已经发布这个问题很久了:)但是正如你所说,这些列表必须具体化。谢谢。我已经发布这个问题很久了:)但正如你所说,这些清单必须具体化。谢谢