Scala ApacheSpark-如何压缩多个RDD
假设我有一堆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[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
。谢谢您的回答!不过我不想把这些清单具体化。谢谢你的回答!但是我不想具体化这些列表。我已经发布这个问题很久了:)但是正如你所说,这些列表必须具体化。谢谢。我已经发布这个问题很久了:)但正如你所说,这些清单必须具体化。谢谢