029 RDD Join相关API,以及程序
1.数据集
  A表数据:
      1 a
      2 b
      3 c
  B表数据:
      1 aa1
      1 aa2
      2 bb1
      2 bb2
      2 bb3
      4 dd1
2.join的分类
inner join
left outer join
right outer join
full outer join
left semi join
  
3.集中join的结果
  A inner join B:
      1	a 1 aa1
      1	a 1 aa2
      2 b 2 bb1
      2 b 2 bb2
      2 b 2 bb3
  A left outer join B:
      1	a 1 aa1
      1	a 1 aa2
      2 b 2 bb1
      2 b 2 bb2
      2 b 2 bb3
      3 c null null
  A right outer join B:
      1	a 1 aa1
      1	a 1 aa2
      2 b 2 bb1
      2 b 2 bb2
      2 b 2 bb3
      null null 4 dd1
  A full outer join B:
      1	a 1 aa1
      1	a 1 aa2
      2 b 2 bb1
      2 b 2 bb2
      2 b 2 bb3
      3 c null null
      null null 4 dd1
  A left semi join B:(。。。。。注意。。。。。。)
      1 a
      2 b
4.API
def join[W](other: RDD[(K, W)]): RDD[(K, (V, W))]
    返回值是RDD,RDD中的类型是一个二元组(a),a第一个元素是KEY类型的值(join的key), a第二个元素又是二元组(b), b的第一个元素是来自调用join函数的RDD的value,
    b的第二个元素是来自参数other这个RDD的value
def leftOuterJoin[W](other: RDD[(K, W)]): RDD[(K, (V, Option[W]))]
     对于右边的数据返回的是Option类型是数据,所以如果右表数据不存在,返回的是None;否则是一个Some的具体数据
def rightOuterJoin[W](other: RDD[(K, W)]): RDD[(K, (Option[V], W))]
      对于左边的数据返回的是Option类型是数据,所以如果左表数据不存在,返回的是None;否则是一个Some的具体数据
def fullOuterJoin[W](other: RDD[(K, W)]): RDD[(K, (Option[V], Option[W]))]
      返回的value类型是Option封装后的数据,如果数据不存在, 返回的是None,存在返回的是Some具体数据

5.其他方式实现join
  
6.join程序以及非join实现join
 package com.ibeifeng.senior.join
 import org.apache.spark.{SparkConf, SparkContext}
 /**
   * RDD数据Join相关API讲解
   * Created by ibf on 02/09.
   */
 object RDDJoin {
   def main(args: Array[String]): Unit = {
     val conf = new SparkConf()
       .setMaster("local[*]")
       .setAppName("RDD-Join")
     val sc = SparkContext.getOrCreate(conf)
     // ==================具体代码======================
     // 模拟数据产生
     val rdd1 = sc.parallelize(Array(
       (1, "张三1"),
       (1, "张三2"),
       (2, "李四"),
       (3, "王五"),
       (4, "Tom"),
       (5, "Gerry"),
       (6, "莉莉")
     ), 1)
     val rdd2 = sc.parallelize(Array(
       (1, "上海"),
       (2, "北京1"),
       (2, "北京2"),
       (3, "南京"),
       (4, "纽约"),
       (6, "深圳"),
       (7, "香港")
     ), 1)
     // 调用RDD API实现内连接
     val joinResultRDD = rdd1.join(rdd2).map {
       case (id, (name, address)) => {
         (id, name, address)
       }
     }
     println("----------------")
     joinResultRDD.foreachPartition(iter => {
       iter.foreach(println)
     })
     // 调用RDD API实现左外连接
     val leftJoinResultRDd = rdd1.leftOuterJoin(rdd2).map {
       case (id, (name, addressOption)) => {
         (id, name, addressOption.getOrElse("NULL"))
       }
     }
     println("----------------")
     leftJoinResultRDd.foreachPartition(iter => {
       iter.foreach(println)
     })
     // 左外连接稍微变化一下:需要左表出现,右表不出现的数据(not in)
     println("----------------")
     rdd1.leftOuterJoin(rdd2).filter(_._2._2.isEmpty).map {
       case (id, (name, _)) => (id, name)
     }.foreachPartition(iter => {
       iter.foreach(println)
     })
     // 右外连接
     println("----------------")
     rdd1
       .rightOuterJoin(rdd2)
       .map {
         case (id, (nameOption, address)) => {
           (id, nameOption.getOrElse("NULL"), address)
         }
       }
       .foreachPartition(iter => iter.foreach(println))
     // 全外连接
     println("----------------")
     rdd1
       .fullOuterJoin(rdd2)
       .map {
         case (id, (nameOption, addressOption)) => {
           (id, nameOption.getOrElse("NULL"), addressOption.getOrElse("NULL"))
         }
       }
       .foreachPartition(iter => iter.foreach(println))
     ///////////////////////////////////////////假设rdd2的数据比较少,将rdd2的数据广播出去///////////////////////////////////////
     val leastRDDCollection = rdd2.collect()
     val broadcastRDDCollection = sc.broadcast(leastRDDCollection)     // Inner Join     rdd1
       // 过滤rdd1中的数据,只要在rdd1中出现的数据,没有出现的数据过滤掉
       .filter(tuple => broadcastRDDCollection.value.map(_._1).contains(tuple._1))
       // 数据合并,由于一条rdd1的数据可能在rdd2中存在多条对应数据,所以使用fla  tMap
       .flatMap {
       case (id, name) => {
         broadcastRDDCollection.value.filter(_._1 == id).map {
           case (_, address) => {
             (id, name, address)
           }
         }
       }
     }
       .foreachPartition(iter => iter.foreach(println))
     // 左外连接
     println("---------------------")
     rdd1
       .flatMap {
         case (id, name) => {
           // 从右表所属的广播变量中获取对应id的集合列表
           val list = broadcastRDDCollection.value.filter(_._1 == id)
           // 对应id的集合可能为空,也可能数据有多个
           if (list.nonEmpty) {
             // 存在多个
             list.map(tuple => (id, name, tuple._2))
           } else {
             // id在右表中不存在,填默认值
             (id, name, "NULL") :: Nil
           }
         }
       }
       .foreachPartition(iter => iter.foreach(println))
     // 右外连接
     /**
       * rdd2中所有数据出现,由于rdd2中的数据在driver中可以存储,可以认为rdd1和rdd2通过right join之后的数据也可以在driver中保存下
       **/
     println("---------------------")
     // 将rdd1中符合条件的数据过滤出来保存到driver中
     val stage1 = rdd1
       .filter(tuple => broadcastRDDCollection.value.map(_._1).contains(tuple._1))
       .collect()
     // 将driver中两个集合进行right join
     val stage2 = leastRDDCollection.flatMap {
       case (id, address) => {
         val list = stage1.filter(_._1 == id)
         if (list.nonEmpty) {
           list.map(tuple => (id, tuple._2, address))
         } else {
           Iterator.single((id, "NULL", address))
         }
       }
     }
     stage2.foreach(println)
     // TODO: 全外连接,不写代码,因为代码比较复杂
   
     //====================================
     // 左半连接:只出现左表数据(要求数据必须在右表中也出现过),如果左表的数据在右表中出现多次,最终结果只出现一次
     println("+++++++++++++++++")
     println("-----------------------")
     rdd1
       .join(rdd2)
       .map {
         case (id, (name, _)) => (id, name)
       }
       .distinct()
       .foreachPartition(iter => iter.foreach(println))
     println("------------------------")
     rdd1
       .filter(tuple => broadcastRDDCollection.value.map(_._1).contains(tuple._1))
       .foreachPartition(iter => iter.foreach(println))
     // 休眠为了看4040页面
         Thread.sleep(1000000)
   }
 }
6.
029 RDD Join相关API,以及程序的更多相关文章
- 030 RDD Join中宽依赖与窄依赖的判断
		
1.规律 如果JoinAPI之前被调用的RDD API是宽依赖(存在shuffle), 而且两个join的RDD的分区数量一致,join结果的rdd分区数量也一样,这个时候join api是窄依赖 除 ...
 - java 11 移除的一些其他内容,更简化的编译运行程序,Unicode 10,移除了不太使用的JavaEE模块和CORBA技术,废除Nashorn javascript引擎,不建议使用Pack200 相关api
		
移除的一些其他内容 移除项 移除了com.sun.awt.AWTUtilities 移除了sun.misc.Unsafe.defineClass, 使用java.lang.invoke.MethodH ...
 - Spark学习摘记 —— Pair RDD转化操作API归纳
		
本文参考 参考<Spark快速大数据分析>动物书中的第四章"键值对操作",由于pair RDD的一些特殊操作,没有和前面两篇的API归纳放在一起做示例 前面的几个api ...
 - Spark学习摘记 —— RDD行动操作API归纳
		
本文参考 参考<Spark快速大数据分析>动物书中的第三章"RDD编程",前一篇文章已经概述了转化操作相关的API,本文再介绍行动操作API 和转化操作API不同的是, ...
 - 在docker中运行ASP.NET Core Web API应用程序
		
本文是一篇指导快速演练的文章,将介绍在docker中运行一个ASP.NET Core Web API应用程序的基本步骤,在介绍的过程中,也会对docker的使用进行一些简单的描述.对于.NET Cor ...
 - OpenGL FrameBufferCopy相关Api比较(glCopyPixels,glReadPixels,glCopyTexImage2D,glFramebufferTexture2D)
		
OpenGL FrameBufferCopy相关Api比较 glCopyPixels,glReadPixels,glCopyTexImage2D,glFramebufferTexture2D 标题所述 ...
 - [原创]java WEB学习笔记44:Filter 简介,模型,创建,工作原理,相关API,过滤器的部署及映射的方式,Demo
		
本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...
 - TCP/IP协议栈源码图解分析系列10:linux内核协议栈中对于socket相关API的实现
		
题记:本系列文章的目的是抛开书本从Linux内核源代码的角度详细分析TCP/IP协议栈内核相关技术 轻松搞定TCP/IP协议栈,原创文章欢迎交流, byhankswang@gmail.com linu ...
 - 某音乐类App评论相关API的分析及SQL注入尝试
		
关键字:APIfen.工具使用.sql注入 涉及工具/包:Fiddler.Burpsuite.Js2Py.Closure Compiler.selenium.phantomjs.sqlmap 摘要: ...
 
随机推荐
- 【转】巧用CAT706做掉电检测
			
相信大家都会遇到这样的情况,当你正在敲一份文档或一段代码时,啪的一下停电啦,我擦……,我的代码……,我的图纸……,我刚写好的文章…….但是在嵌入式系统中也会遇到类似的情况,通常会导致嵌入式系统数据,程 ...
 - XStream--java对象与xml形式文件相互转换
			
1.pom.xml中添加依赖 <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifa ...
 - 【洛谷P2114】起床困难综合征  位运算+贪心
			
题目大意:给定 N 个操作,每个操作为按位与.或.异或一个固定的数字,现在要求从 0 到 M 中任选一个数字,使得依次经过 N 个操作后的值最大. 题解:位运算有一个重要的性质是:位运算时,无进位产生 ...
 - 【CF437C】The Child and Toy
			
题目大意:给定一个有 N 个点,M 条边的无向图,点有点权,删除一个点就要付出所有与之有联系且没有被删除的点的点权之和的代价,求将所有点删除的最小代价是多少. 题解:从图连通性的角度出发,删除所有点就 ...
 - Flink窗口介绍及应用
			
Windows是Flink流计算的核心,本文将概括的介绍几种窗口的概念,重点只放在窗口的应用上. 本实验的数据采用自拟电影评分数据(userId, movieId, rating, timestamp ...
 - Java基础-SSM之Spring和Mybatis整合案例
			
Java基础-SSM之Spring和Mybatis整合案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在之前我分享过mybatis和Spring的配置案例,想必大家对它们的 ...
 - 如何把手机app的视频下载到手机上?网页上的视频怎么下载?
			
手机上小视频怎么下载?求推荐不需要安装软件的下载方法? 如何把手机app的视频下载到手机上?比如把快手上的视频下载到手机上? 如何免费下载视频? ... 答案当然是用iiiLab提供的在线视频解析下载 ...
 - 何凯文每日一句打卡||DAY14
 - jenkins设置CSRF 协议(CRUMB值设置)
			
在关闭“”调用出现Error 403 No valid crumb was included in the request 第一种解决方式是 关闭 csrf,如上图,去掉勾就可以,但是并不推荐. 第二 ...
 - js截取图片上传(仅原理)----闲的无聊了代码就不共享了!写的难看,不好意思给你们看了(囧)
			
就算世界再坑爹,总有一些属性能带你走出绝望(伟大的absolute) 今天吐槽一下!......在我的世界里没有正统UI,所以效果图永远都是那么坑爹! 这里我要感谢有个position:absolut ...