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. sqlplus执行startup出现ORA-00119,ORA-00132错误

    安装好了oracle后,执行如下操作: 执行startup后出现如下错误: ORA-00119: invalid specification for system parameter LOCAL_LI ...

  2. 解题:CTSC 2008 祭祀

    题面 洛谷要求输出方案,懒得写了,但是还是放一下链接看看吧 (虽然现在二分图已经过气了=.=) 要求最长反链,最长反链=最小链覆盖,先Floyd传递闭包之后链覆盖就变成了边覆盖,然后最小边覆盖=总点数 ...

  3. SPOJ6340 ZUMA - ZUMA

    题意:n个珠子排成一排,都有各自的颜色. 你可以选择不少于w个连续同色的珠子消掉,也可以先放着.你还可以任意插入任意颜色的珠子. 求全部消掉至少要插入几个珠子. 解: 什么毒瘤东西...... 有个十 ...

  4. div 内table 居中实现代码

    有时候在一个div里面添加一个表格,如想让它居住排列,需要做如下的操作. css代码:   代码如下: #dlgReply { /*display: table-cell; text-align: c ...

  5. Redis数据类型和常用命令

    Redis相较于其它的数据库虽然简单,但是要熟记所有命令的用法也并非易事.一个简单的技巧是通过要操作的数据类型来将这些命令进行结构化. 数据类型和对应命令 所有存储于redis中的数据都对应于一个键值 ...

  6. PHP-PSR-[0-4]代码规范

    PHP-FIG 在说啥是PSR-[0-4]规范的之前,我觉得我们有必要说下它的发明者和规范者:PHP-FIG,它的网站是:www.php-fig.org.就是这个联盟组织发明和创造了PSR-[0-4] ...

  7. 前三章 man手册 查看文件

    1 – 3章 1.1 man手册: 分1 - 9个区域,可以认为是一个一个小节 把man手册理解为一本书 第一节:可执行程序或shell命令 第二节:系统调用 第三节:库调用 第四节:特殊文件 第五节 ...

  8. shell 判断脚本参数

    测试登陆脚本 ./test.sh -p 123 -P 3306 -h 127.0.0.1 -u root #!/bin/sh ];then echo "USAGE: $0 -u user - ...

  9. expect 交互

    expect expect 是一种自动交互语言,能实现在shell脚本中为scp和ssh等自动输入密码自动登录. exp_continue # 多个spawn命令时并行 interact # 执行完成 ...

  10. Linux - sed 常用操作

    sed 文本常用操作方式 sed 10q # 显示文件中的前10行 (模拟"head") sed -n '$=' # 计算行数(模拟 "wc -l") sed ...