如何通过.map在另一个RDD中传递一个RDD

时间:2016-01-16 05:08:53

标签: scala apache-spark

我有两个rdd,我想对rdd1的每个项目的RDD2项目进行一些计算。所以,我在用户定义的函数中传递RDD2,如下所示,但我得到的错误如rdd1 cannot be passed in another rdd。如果我想在两个rdd上执行操作,我可以知道如何实现这个目标吗?

例如:

RDD1.map(line =>function(line,RDD2))

1 个答案:

答案 0 :(得分:3)

Spark不支持嵌套RDD,因为错误说明了这一点。通常你必须通过重新设计算法来绕过它。

如何做到这取决于实际用例,function中究竟发生了什么以及它的输出是什么。

有时候RDD1.cartesian(RDD2),每个元组执行操作然后按键减少都会有效。有时,如果您有(K,V)类型,则两者之间的连接都可以正常工作。

如果RDD2很小,您可以随时在驱动程序中收集它,使其成为广播变量,并在function而不是RDD2中使用该变量。

@Edit:

例如,让我们假设您的RDD包含字符串,function将计算RDDRDD2的给定记录发生的次数:

def function(line: String, rdd: RDD[String]): (String, Int) = {
   (line, rdd.filter(_ == line).count)
} 

这将返回RDD[(String, Int)]

Idea1

您可以尝试使用RDD的cartesian方法cartesian product

val cartesianProduct = RDD1.cartesian(RDD2) // creates RDD[(String, String)]
                           .map( (r1,r2) => (r1, function2) ) // creates RDD[(String, Int)]
                           .reduceByKey( (c1,c2) => c1 + c2 ) // final RDD[(String, Int)]

此处function2需要r1r2(它们是字符串),如果相等则返回1,如果不相等则返回0。最终的地图会产生一个RDD,它会有一个元组,其中的密钥是来自r1的记录,而值将是总数。

问题1:如果你在RDD1中有重复的字符串,这将不起作用。你必须考虑一下。如果RDD1记录有一些完美的唯一ID。

问题2:这确实创造了很多对(对于两个RDD中的1mln记录,它会创建大约500bln对),会很慢并且很可能导致很多shuffling

<强> Idea2

我不理解你对RDD2大小lacs的评论,所以这可能会或可能不会有效:

val rdd2array = sc.broadcast(RDD2.collect())
val result = RDD1.map(line => function(line, rdd2array))

问题:这可能会炸毁你的记忆。在collect()上调用driverall的{​​{1}}条记录将被加载到驱动程序节点的内存中。

Idea3

根据用例的不同,还有其他方法可以解决这个问题,例如brute force algorithm for Similarity Search与您的用例类似(不是意图)。其中一个替代解决方案是Locality Sensitive Hashing