让我说我有一堆RDD,可能是RDD[Int]
,我有一个函数定义一个int序列的操作并返回一个int,就像一个fold: f: Seq[Int] => Int
。
如果我有一系列RDD,Seq[RDD[Int]]
,我该如何应用该函数并返回一个带有结果值的新RDD?我似乎没有在Spark中找到zipPartitions
方法来完成此任务。
答案 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)
}
}