SparkCore算子(实例)之----实现表格连接(cartesian, cogroup, flatMap)

笛卡尔积 cartesian

笛卡尔积就是实现两个表格(数据集)的直接生硬拼接,具体过程为:对于左表的每一行数据,去拼接右表的每一行数据,将结果直接拼接。

由于笛卡尔积的连接结果与连接顺序无关,即:没有驱动表和从动表的区别,所以采用“左表”、“右表”这样的称呼,“左表”、“右表”只会影响最终的结果集中每一行记录的左右顺序,不影响整个结果的最终意义。

首先创建两个RDD数据集:

 val rdd12 = sc.parallelize(Array(("a",1), ("b",2),("c",3), ("d",4)))
 val rdd13 = sc.parallelize(Array(("a","huangbo"), ("b","xuzheng"),("c","liutao"), ("e",5)))

然后对两个RDD求笛卡尔积:

 /**
    * cartesian(otherRDD)笛卡尔积:thisRDD与otherRDD做笛卡尔积!
    *         ---- thisRDD与otherRDD可以是任意形式的RDD
    * 笛卡尔积:两张表格的生硬拼接,左表的每一行记录去连接右表的每一条记录;
    */
//RDD[((String, Int), (String, Any))]
rdd12.cartesian(rdd13).foreach(println)

运行结果如下:

	((a,1),(a,huangbo))
	((a,1),(b,xuzheng))
	((a,1),(c,liutao))
	((a,1),(e,5))
	((b,2),(a,huangbo))
	((b,2),(b,xuzheng))
	((b,2),(c,liutao))
	((b,2),(e,5))
	((c,3),(a,huangbo))
	((c,3),(b,xuzheng))
	((c,3),(c,liutao))
	((c,3),(e,5))
	((d,4),(a,huangbo))
	((d,4),(b,xuzheng))
	((d,4),(c,liutao))
	((d,4),(e,5))

cogroup 算子

cogroup(otherDataset, [numTasks])是将输入数据集(K, V)和另外一个数据集(K, W)进行cogroup,得到一个格式为(K, Seq[V], Seq[W])的数据集。
cogroup 有点类似于 groupByKey 算子,都具有将相同的 key 的元素进行分组的效果,但是与cogroup不同的是:

 1. groupByKey 是对于一个RDD中的所有元素按照 key 进行分组,而cogroup 是对于两个RDD的元素按照key 进行分组;
 2. groupByKey返回的是RDD[(key, Iterable[value])],而cogroup返回的是RDD[(key, (Iterable[value1]), Iterable[value2])]的形式;
 3. 两者的操作对象都必须是键值对形式的RDD (PairRDD);

代码如下:

/**
   * cogroup(otherDataset, [numTasks])是将输入数据集(K, V)和另外一个数据集(K, W)进行cogroup,得到一个格式为(K, Seq[V], Seq[W])的数据集。
   *
   * --- 适用场景:两个RDD中具有重叠的KEY,并且这部分相同的KEY的数据需要进行互相处理(同时区分各自所属不同的RDD)
   * ---有点类似于groupByKey:但是goupByKey是在一个由(K,V)对组成的数据集上调用,返回一个(K,Seq[V])对的数据集。
   */
 val rdd12 = sc.parallelize(Array(("a",1), ("b",2),("c",3), ("d",4), ("a",2)))
 val rdd13 = sc.parallelize(Array(("a","huangbo"), ("b","xuzheng"),("c","liutao"), ("e","lucy")))
 val cogroup: RDD[(String, (Iterable[Int], Iterable[String]))] = rdd12.cogroup(rdd13)
 cogroup.foreach(x => {
   val v1 = x._2._1.mkString("-")
   val v2 = x._2._2.mkString("-")
   println(x._1 + "\t"+ v1 +"\t" + v2)
 })

运行结果:

d	4	
e		lucy
a	1-2	huangbo
b	2	xuzheng
c	3	liutao
注意:cogroup 会返回在thisRDD、otherRDD中出现的所有的Key ,当某一种key只在其中一个RDD中存在,则返
      回的RDD中不存在该key数据的RDD对应的Iterable为空。(没有交集的效果)

使用 cogroup 实现自然连接

1. 自然连接(打印输出连接结果)
/** 自然连接:
  * 利用cogroup算子(不使用cartesian),实现自然连接(去除重复列)!!
  */
    val rdd12 = sc.parallelize(Array(("a",1), ("b",2),("c",3), ("d",4), ("a",2)))
    val rdd13 = sc.parallelize(Array(("a","huangbo"), ("b","xuzheng"),("c","liutao"), ("e","lucy")))
    val cogroup: RDD[(String, (Iterable[Int], Iterable[String]))] = rdd12.cogroup(rdd13)
    val lastResult = cogroup.foreach(x => {
      val value1: Array[Int] = x._2._1.toArray
      val value2: Array[Any] = x._2._2.toArray
      val tuples = new ListBuffer[(Int, Any)]()//构造容器
      for (aa <- value1){
        for (bb <- value2) {
          tuples += ((aa, bb))
        }
      }
      tuples.foreach( xx => {
          println(x._1, xx._1, xx._2)
      })
    })
运行结果如下:
(a,1,huangbo)
(a,2,huangbo)
(b,2,xuzheng)
(c,3,liutao)
注意:cogroup算子本身并不会自动去除那些只存在于单个RDD中的key的数据,但是注意代码中的内外for循环,
     已经实现了value1为主表,value2为从表的效果。通过两层for循环的控制,最终出现在结果集中的数据只
     是  “value1、value2”中共同拥有(key)的那部分数据;而cogroup本身已经按照相同的key分好组了,因
     此最终的效果就是自然连接的效果,key就是关联字段。
2. 自然连接(返回连接结果RDD数据集,而非仅仅打印)

概述:cogroupRDD是以相同key为单位存在的数据集,即:cogroupRDD的元素个数就是两个参与运算的RDD的 不重复key的种类。但是对于每一组数据(cogroupRDD中的一个元素),必然存在多条连接结果。因此问题的关键:怎么对于父RDD的一个元素记性处理,返回子RDD中的多个元素,即 元素数量的扩展。

普通的映射算子map如法实现元素数量的扩展,在map算子中,子RDD的元素的数量必然是<=父RDD的元素数量的。

使用flatMap能够实现对于父RDD的元素数量的扩张,且扩张是通过对于父RDD的每个元素进行处理而实现的。

其实能够实现扩张效果的算子有很多,几乎只要是func的返回值是集合、迭代器的算子都可以实现扩张的效果,但是大多数的这类算子的func的传入参数本身就是集合、迭代器,因此其处理逻辑都是针对于一堆数据(如:相同key的一组数据、一个分区的一组数据),目前只发现flatMap算子是针对于父RDD的一个元素直接进行扩张的。

代码如下:

  /**
    * 实现自然连接:返回自然连接的结果RDD,而不仅仅只是打印输出!!
    *
    * --- 使用flatMap而非 map,因为map无法实现元素个数的扩展,
    *     即:对于cogroup,只能返回与父RDD的元素数量相同的RDD,即一个KEY组只能返回一个元素!
    */
  val rdd12 = sc.parallelize(Array(("a",1), ("b",2),("c",3), ("d",4), ("a",2)))
  val rdd13 = sc.parallelize(Array(("a","huangbo"), ("b","xuzheng"),("c","liutao"), ("e","lucy")))
  val cogroup: RDD[(String, (Iterable[Int], Iterable[String]))] = rdd12.cogroup(rdd13)
  val result: RDD[(String, (Int, String))] = cogroup.flatMap(x => {
    //一组相同key的value迭代器,RDD[(String, (Iterable[Int], Iterable[Any]))]
    //将Iterable--->集合
    val list1: Array[Int] = x._2._1.toArray
    val list2: Array[String] = x._2._2.toArray
    val array = ArrayBuffer[(String,(Int,String))]()
    for(v1 <- list1){
          for(v2 <- list2){
            array.append((x._1, (v1, v2)))
          }
        }
    array
  })
  result.foreach(print)

运行结果如下:

(a,(1,huangbo))
(a,(2,huangbo))
(b,(2,xuzheng))
(c,(3,liutao))
发布了4 篇原创文章 · 获赞 1 · 访问量 2669
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览