RDD编程中的RDD连接(表连接)问题

在spark的rdd编程的时候,我们经常想做一些表连接的操作。
对rdd理解不深的时候我们可能会写出如下代码:

   val temp1 = sc.textFile("C://Users/802/Desktop/1.txt").map(_.split(",")).map(k =>
      (k(0).toInt,k(1).toInt))
   val temp2 = sc.textFile("C://Users/802/Desktop/2.txt").map(_.split(",")).map(k =>
      (k(0).toInt,k(1).toInt))
   val temp4 = temp1.flatMap(k => {
      var temp = List[(Int,Int,Double)]
      temp2.foreach(i =>{
        if(i._1 == k._1)
           temp = temp.::((k._1,k._2,i._2))
      })
      temp
    })
    temp4.foreach(println(_))

运行以后spark会报错,spark会提示你不能用如下格式:
rdd1.map(k => { rdd2.foreach()}
就是说我们在一个rdd的操作中不能加入另一个rdd的操作,原因很好理解,rdd的惰性特点让他不能这样内嵌计算,这是一个最基本的抽象原理。那我们如何做表连接呢?

有两个方法:

1.map端的表连接(适用于一大一小两个表的连接)

我们可以通过spark中的broadcast将两个表中较小的一个表通过broadcast机制广播到各个节点,然后通过大表的map操作就可以进行相应的表连接,示例代码如下:(这里说一点,广播机制只能广播实体,不能广播rdd这种抽象的东西,所以我们需要先collect rdd然后再进行广播)

   val temp1 = sc.textFile("C://Users/802/Desktop/1.txt").map(_.split(",")).map(k =>
      (k(0).toInt,k(1).toInt))
   val temp2 = sc.textFile("C://Users/802/Desktop/2.txt").map(_.split(",")).map(k =>
      (k(0).toInt,k(1).toInt))

   val bc_temp2 = sc.broadcast(temp2.collect()).value

   val temp4 = temp1.flatMap(k => {
      var temp = List[(Int,Int,Double)]
      bc_temp2.foreach(i =>{
        if(i._1 == k._1 && i._2 == k._2)
           temp = temp.::((k._1,k._2,i._2))
      })
      temp
    })
    temp4.foreach(println(_))

2.reduce端的表连接(适用于两个表都不大的情况)

这里的表连接我们使用join方法,因为join方法类似于reduce,所以数据shuffle通信消耗比较大,当两张表都非常大的时候不推荐使用,代码如下:

   val temp1 = sc.textFile("C://Users/802/Desktop/1.txt").map(_.split(",")).map(k =>
      (k(0).toInt,k(1).toInt))
   val temp2 = sc.textFile("C://Users/802/Desktop/2.txt").map(_.split(",")).map(k =>
      (k(0).toInt,k(1).toInt))

   val temp4 = temp1.join(temp2).map(k => {
      (k._1,k._2._1,k._2._2)
    })
    temp4.foreach(println(_))

转载请注明出处:http://blog.csdn.net/utopia_1919/article/details/52038189

你可能感兴趣的:(spark)