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,以及程序的更多相关文章

  1. 030 RDD Join中宽依赖与窄依赖的判断

    1.规律 如果JoinAPI之前被调用的RDD API是宽依赖(存在shuffle), 而且两个join的RDD的分区数量一致,join结果的rdd分区数量也一样,这个时候join api是窄依赖 除 ...

  2. java 11 移除的一些其他内容,更简化的编译运行程序,Unicode 10,移除了不太使用的JavaEE模块和CORBA技术,废除Nashorn javascript引擎,不建议使用Pack200 相关api

    移除的一些其他内容 移除项 移除了com.sun.awt.AWTUtilities 移除了sun.misc.Unsafe.defineClass, 使用java.lang.invoke.MethodH ...

  3. Spark学习摘记 —— Pair RDD转化操作API归纳

    本文参考 参考<Spark快速大数据分析>动物书中的第四章"键值对操作",由于pair RDD的一些特殊操作,没有和前面两篇的API归纳放在一起做示例 前面的几个api ...

  4. Spark学习摘记 —— RDD行动操作API归纳

    本文参考 参考<Spark快速大数据分析>动物书中的第三章"RDD编程",前一篇文章已经概述了转化操作相关的API,本文再介绍行动操作API 和转化操作API不同的是, ...

  5. 在docker中运行ASP.NET Core Web API应用程序

    本文是一篇指导快速演练的文章,将介绍在docker中运行一个ASP.NET Core Web API应用程序的基本步骤,在介绍的过程中,也会对docker的使用进行一些简单的描述.对于.NET Cor ...

  6. OpenGL FrameBufferCopy相关Api比较(glCopyPixels,glReadPixels,glCopyTexImage2D,glFramebufferTexture2D)

    OpenGL FrameBufferCopy相关Api比较 glCopyPixels,glReadPixels,glCopyTexImage2D,glFramebufferTexture2D 标题所述 ...

  7. [原创]java WEB学习笔记44:Filter 简介,模型,创建,工作原理,相关API,过滤器的部署及映射的方式,Demo

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  8. TCP/IP协议栈源码图解分析系列10:linux内核协议栈中对于socket相关API的实现

    题记:本系列文章的目的是抛开书本从Linux内核源代码的角度详细分析TCP/IP协议栈内核相关技术 轻松搞定TCP/IP协议栈,原创文章欢迎交流, byhankswang@gmail.com linu ...

  9. 某音乐类App评论相关API的分析及SQL注入尝试

    关键字:APIfen.工具使用.sql注入 涉及工具/包:Fiddler.Burpsuite.Js2Py.Closure Compiler.selenium.phantomjs.sqlmap 摘要: ...

随机推荐

  1. 【bzoj2878】 Noi2012—迷失游乐园

    http://www.lydsy.com/JudgeOnline/problem.php?id=2878 (题目链接) 题意 求基环树上以任意点为起点的简单路径期望长度. Solution 啊啊啊好丑 ...

  2. OAuth2的基本概念的理解

    书籍推荐 OAuth2 in Action -- 原理 OAuth2 Cookbook -- 实践 OAuth2 解决的问题域 开放系统间授权 社交联合登录 开放API平台 现代微服务安全 单页浏览器 ...

  3. Mysql(三)约束

    一.视图 视图是虚拟的数据表,本身不存储数据,而是提供数据的逻辑 展示.       1.创建视图 create view stu_view as select s1.id, s1.name, s2. ...

  4. 洛谷P4486 Kakuro

    题意:你有一个棋盘,某些格子是限制条件,形如"从这里开始下面所有连续空格的和为a"或"从这里开始向右的所有连续空格之和为b"一个格子可以同时拥有两个限制条件. ...

  5. KVM安装、镜像创建(一)

    环境准备 VMware Workstation Pro启动虚拟化 查看启动的系统是否支持vmx或svm grep -E '(vmx|svm)' /proc/cpuinfo 备注:操作系统centos ...

  6. Vue单页面应用阻止浏览器记住密码

    Vue单页面应用阻止浏览器记住密码 ——IT唐伯虎 摘要: Vue单页面应用阻止浏览器记住密码. 现象1:路由切换时再次提示“是否记住密码” 登录页面有个密码输入框,输入账号密码进行登录: 登录完成后 ...

  7. git clone错误 fatal: early EOF fatal: index-pack failed

    最后用ssh的方式解决了,不用http https://blog.csdn.net/fastjack/article/details/79757520 用了以下的方法还是不行 今天想 clone 一下 ...

  8. Nginx学习总结

    2017年2月23日, 星期四 Nginx学习总结 Nginx是目前比较主流的HTTP反向代理服务器(其企业版提供了基于TCP层的反向代理插件),对于构建大型分布式web应用,具有举足轻重的作用.简单 ...

  9. 公告:关注canvas的同学注意了

    因为我之前把基础大致都帮各位详细讲过了! 什么fill,line,乱七八糟的一堆.都有demo了 所以我最近写起来可能会快很多了!如果有不明白的只能请各位回顾下之前的文章了 毕竟如果按照这个进度写文章 ...

  10. 20155328 2016-2017-2 《Java程序设计》 第8周学习总结

    20155328 2016-2017-2 <Java程序设计> 第8周学习总结 教材学习内容总结 NIO与NIO2 认识NIO 相对于IO,NIO可以让你设定缓冲区容量,在缓冲区中对感兴趣 ...