Spark:如何在需要访问另一个RDD时映射RDD

时间:2015-05-27 14:29:44

标签: scala nested apache-spark transformation rdd

给定两个大的键值对RDD(d1d2),两者都由唯一的 ID 键和 vector 值组成(例如RDD[Int,DenseVector]),我需要映射d1,以便为每个元素获取d2中最接近元素的 ID ,使用之间的欧氏距离度量标准载体

我还没有找到使用标准RDD转换的方法。我知道Spark中不允许嵌套的RDD,但是,如果可能的话,一个简单的解决方案就是:

d1.map((k,v) => (k, d2.map{case (k2, v2) => val diff = (v - v2); (k2, sqrt(diff dot diff))} 
                      .takeOrdered(1)(Ordering.by[(Double,Double), Double](_._2))      
                      ._1))

此外,如果d1很小,我可以使用Map(例如d1.collectAsMap())并遍历其每个元素,但由于数据集大小,这不是一个选项。

Spark中有这种转换的替代方案吗?

编辑1:

使用@holden和@ david-griffin建议我使用cartesian()reduceByKey()解决了这个问题。这是脚本(假设scSparkContext,并使用 Breeze 库。

val d1 = sc.parallelize(List((1,DenseVector(0.0,0.0)), (2,DenseVector(1.0,0.0)), (3,DenseVector(0.0,1.0))))
val d2 = sc.parallelize(List((1,DenseVector(0.0,0.75)), (2,DenseVector(0.0,0.25)), (3,DenseVector(1.0,1.0)), (4,DenseVector(0.75,0.0))))

val d1Xd2 = d1.cartesian(d2)
val pairDistances = d1Xd2.map{case ((k1, v1), (k2, v2)) => (k1, (k2, sqrt(sum(pow(v1-v2,2)))))}
val closestPoints = pairDistances.reduceByKey{case (x, y) => if (x._2 < y._2) x else y }

closestPoints.foreach(s => println(s._1 + " -> " + s._2._1))

获得的输出是:

1 -> 2
2 -> 4
3 -> 1

1 个答案:

答案 0 :(得分:2)

RDD上的转换只能应用于驱动程序端,因此嵌套不起作用。正如@davidgriffin指出的那样,你可以使用cartesian。对于您的使用案例,您可能希望使用reduceByKey进行操作,并在您的reduce by键中,您可以跟踪最小距离。