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 摘要: ...
随机推荐
- linux读写锁
一.概述 读写锁与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区, ...
- LVS NAT/DR
LVS介绍:http://www.linuxvirtualserver.org/zh/lvs3.html DR 工作流: HOST发送服务请求报文(源IP为HOST IP,目的IP为VSIP) Gen ...
- vue axios的使用
详细可以看:https://www.kancloud.cn/yunye/axios/234845 这里介绍日常使用得比较多的get和post: import axios from 'axios' // ...
- JVM总结(一):概述--JVM对象探秘
这一节我们来讨论一下JVM对象建立过程. JVM对象探秘 对象的建立 对象的内存布局 对象的访问定位 JVM对象探秘 对象的建立 对象的建立过程 图一:对象建立过程 1.类加载检查. 当JVM检测 ...
- Linux(Debian)软件安装
# 配置/etc/apt/sources.list 通过root权限修改/etc/apt/sources.list $ su #输入密码进入root权限 $ chmod 0666 /etc/apt/s ...
- 织梦 dedecms 首页调用公司简介的内容
首页调用公司简介的代码: {dede:sql sql='Select content,substring(content,1,300) as content from dede_arctype whe ...
- [整理]Git使用文章整理
http://pcottle.github.io/learnGitBranching/ http://www.ruanyifeng.com/blog/2012/07/git.html
- js星星评分插件
下载:https://files.cnblogs.com/files/wordblog/%E6%98%9F%E6%98%9F%E6%8F%92%E4%BB%B6.rar
- 【干货】Linux内存数据的获取与转存 直捣密码
知识源:Unit 2: Linux/Unix Acquisition 2.1 Linux/Unix Acquistion Memory Acquisition 中的实验demo部分 小白注意,这是网 ...
- 用《舌尖2》去理解C#中的多态和开闭原则
昨天晚上看了<舌尖上的中国2>第一集,特别的感人,尤其是看到帮别人割麦子的麦客,一亩地开价200,雇主只肯给100,脸上的那种纠结和无可奈何.还有长着大眼睛的跳跳鱼,很可爱,不过最终还是被 ...