在spark中加入两个RDD

时间:2015-10-24 18:18:59

标签: scala apache-spark

我有两个rdd一个rdd只有一列其他有两列加入两个RDD上的键我已经添加了虚拟值0,有没有其他有效的方法使用join这样做?

val lines = sc.textFile("ml-100k/u.data")
val movienamesfile = sc.textFile("Cml-100k/u.item")

val moviesid = lines.map(x => x.split("\t")).map(x => (x(1),0))
val test = moviesid.map(x => x._1)
val movienames = movienamesfile.map(x => x.split("\\|")).map(x => (x(0),x(1)))
val shit = movienames.join(moviesid).distinct()

修改

让我在SQL中转换这个问题。比方说我有table1 (moveid)table2 (movieid,moviename)。在SQL中我们写了类似的东西:

select moviename, movieid, count(1)
from table2 inner join table table1 on table1.movieid=table2.moveid 
group by ....

这里的SQL table1只有一列,其中table2有两列,join仍在工作,同样,Spark可以加入来自两个RDD的键。

1 个答案:

答案 0 :(得分:8)

仅在PairwiseRDDs上定义了连接操作,这与SQL中的关系/表完全不同。 PairwiseRDD的每个元素都是Tuple2,其中第一个元素是key,第二个元素是value。只要key提供有意义的hashCode

,两者都可以包含复杂对象

如果您想在SQL-ish中考虑这一点,您可以考虑使用密钥,因为ON子句和value包含所选列的所有内容。

SELECT table1.value, table2.value
FROM table1 JOIN table2 ON table1.key = table2.key

虽然这些方法乍一看看起来很相似,但你可以用另一种表达方法,但有一个根本区别。当您查看SQL表并忽略约束时,所有列都属于同一对象类,而key中的valuePairwiseRDD具有明确的含义。

回到您的问题以使用join,您需要keyvalue。可以说比使用0作为占位符更清洁的是使用null单例,但实际上没有办法绕过它。

对于小数据,您可以使用与广播连接类似的方式使用过滤器:

val moviesidBD = sc.broadcast(
  lines.map(x => x.split("\t")).map(_.head).collect.toSet)

movienames.filter{case (id, _) => moviesidBD.value contains id}

但如果您真的想要SQL-ish加入,那么您应该只使用SparkSQL。

val movieIdsDf = lines
   .map(x => x.split("\t"))
   .map(a => Tuple1(a.head))
   .toDF("id")

val movienamesDf = movienames.toDF("id", "name")

// Add optional join type qualifier 
movienamesDf.join(movieIdsDf, movieIdsDf("id") <=> movienamesDf("id"))