一、 数据准备

本文主要介绍 Spark SQL 的多表连接,需要预先准备测试数据。分别创建员工和部门的 Datafame,并注册为临时视图,代码如下:

val spark = SparkSession.builder().appName("aggregations").master("local[2]").getOrCreate()

val empDF = spark.read.json("/usr/file/json/emp.json")
empDF.createOrReplaceTempView("emp")

val deptDF = spark.read.json("/usr/file/json/dept.json")
deptDF.createOrReplaceTempView("dept")

两表的主要字段如下:

emp 员工表
 |-- ENAME: 员工姓名
 |-- DEPTNO: 部门编号
 |-- EMPNO: 员工编号
 |-- HIREDATE: 入职时间
 |-- JOB: 职务
 |-- MGR: 上级编号
 |-- SAL: 薪资
 |-- COMM: 奖金  
dept 部门表
 |-- DEPTNO: 部门编号
 |-- DNAME:  部门名称
 |-- LOC:    部门所在城市

注:emp.json,dept.json 可以在本仓库的resources 目录进行下载。

二、连接类型

Spark 中支持多种连接类型:

  • Inner Join : 内连接;
  • Full Outer Join : 全外连接;
  • Left Outer Join : 左外连接;
  • Right Outer Join : 右外连接;
  • Left Semi Join : 左半连接;
  • Left Anti Join : 左反连接;
  • Natural Join : 自然连接;
  • Cross (or Cartesian) Join : 交叉 (或笛卡尔) 连接。

其中内,外连接,笛卡尔积均与普通关系型数据库中的相同,如下图所示:

这里解释一下左半连接和左反连接,这两个连接等价于关系型数据库中的 INNOT IN 字句:

-- LEFT SEMI JOIN
SELECT * FROM emp LEFT SEMI JOIN dept ON emp.deptno = dept.deptno
-- 等价于如下的 IN 语句
SELECT * FROM emp WHERE deptno IN (SELECT deptno FROM dept)

-- LEFT ANTI JOIN
SELECT * FROM emp LEFT ANTI JOIN dept ON emp.deptno = dept.deptno
-- 等价于如下的 IN 语句
SELECT * FROM emp WHERE deptno NOT IN (SELECT deptno FROM dept)

所有连接类型的示例代码如下:

2.1 INNER JOIN

// 1.定义连接表达式
val joinExpression = empDF.col("deptno") === deptDF.col("deptno")
// 2.连接查询
empDF.join(deptDF,joinExpression).select("ename","dname").show()

// 等价 SQL 如下:
spark.sql("SELECT ename,dname FROM emp JOIN dept ON emp.deptno = dept.deptno").show()

2.2 FULL OUTER JOIN

empDF.join(deptDF, joinExpression, "outer").show()
spark.sql("SELECT * FROM emp FULL OUTER JOIN dept ON emp.deptno = dept.deptno").show()

2.3 LEFT OUTER JOIN

empDF.join(deptDF, joinExpression, "left_outer").show()
spark.sql("SELECT * FROM emp LEFT OUTER JOIN dept ON emp.deptno = dept.deptno").show()

2.4 RIGHT OUTER JOIN

empDF.join(deptDF, joinExpression, "right_outer").show()
spark.sql("SELECT * FROM emp RIGHT OUTER JOIN dept ON emp.deptno = dept.deptno").show()

2.5 LEFT SEMI JOIN

empDF.join(deptDF, joinExpression, "left_semi").show()
spark.sql("SELECT * FROM emp LEFT SEMI JOIN dept ON emp.deptno = dept.deptno").show()

2.6 LEFT ANTI JOIN

empDF.join(deptDF, joinExpression, "left_anti").show()
spark.sql("SELECT * FROM emp LEFT ANTI JOIN dept ON emp.deptno = dept.deptno").show()

2.7 CROSS JOIN

empDF.join(deptDF, joinExpression, "cross").show()
spark.sql("SELECT * FROM emp CROSS JOIN dept ON emp.deptno = dept.deptno").show()

2.8 NATURAL JOIN

自然连接是在两张表中寻找那些数据类型和列名都相同的字段,然后自动地将他们连接起来,并返回所有符合条件的结果。

spark.sql("SELECT * FROM emp NATURAL JOIN dept").show()

以下是一个自然连接的查询结果,程序自动推断出使用两张表都存在的 dept 列进行连接,其实际等价于:

spark.sql("SELECT * FROM emp JOIN dept ON emp.deptno = dept.deptno").show()

由于自然连接常常会产生不可预期的结果,所以并不推荐使用。

三、连接的执行

在对大表与大表之间进行连接操作时,通常都会触发 Shuffle Join,两表的所有分区节点会进行 All-to-All 的通讯,这种查询通常比较昂贵,会对网络 IO 会造成比较大的负担。

而对于大表和小表的连接操作,Spark 会在一定程度上进行优化,如果小表的数据量小于 Worker Node 的内存空间,Spark 会考虑将小表的数据广播到每一个 Worker Node,在每个工作节点内部执行连接计算,这可以降低网络的 IO,但会加大每个 Worker Node 的 CPU 负担。

是否采用广播方式进行 Join 取决于程序内部对小表的判断,如果想明确使用广播方式进行 Join,则可以在 DataFrame API 中使用 broadcast 方法指定需要广播的小表:

empDF.join(broadcast(deptDF), joinExpression).show()

参考资料

  1. Matei Zaharia, Bill Chambers . Spark: The Definitive Guide[M] . 2018-02

更多大数据系列文章可以参见 GitHub 开源项目大数据入门指南

Spark 系列(十二)—— Spark SQL JOIN 操作的更多相关文章

  1. SQL Server 2008空间数据应用系列十二:Bing Maps中呈现GeoRSS订阅的空间数据

    原文:SQL Server 2008空间数据应用系列十二:Bing Maps中呈现GeoRSS订阅的空间数据 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft SQL Se ...

  2. MySQL 系列(二) 你不知道的数据库操作

    第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 本章内容: 查看\创建\使用\删除 数据库 用户管理及授权实战 局域网 ...

  3. Alamofire源码解读系列(十二)之请求(Request)

    本篇是Alamofire中的请求抽象层的讲解 前言 在Alamofire中,围绕着Request,设计了很多额外的特性,这也恰恰表明,Request是所有请求的基础部分和发起点.这无疑给我们一个Req ...

  4. 爬虫系列(十二) selenium的基本使用

    一.selenium 简介 随着网络技术的发展,目前大部分网站都采用动态加载技术,常见的有 JavaScript 动态渲染和 Ajax 动态加载 对于爬取这些网站,一般有两种思路: 分析 Ajax 请 ...

  5. 第十二章 Python文件操作【转】

    12.1 open() open()函数作用是打开文件,返回一个文件对象. 用法格式:open(name[, mode[, buffering[,encoding]]]) -> file obj ...

  6. Web 前端开发精华文章推荐(jQuery、HTML5、CSS3)【系列十二】

    2012年12月12日,[<Web 前端开发人员和设计师必读文章>系列十二]和大家见面了.梦想天空博客关注 前端开发 技术,分享各种增强网站用户体验的 jQuery 插件,展示前沿的 HT ...

  7. struts2官方 中文教程 系列十二:控制标签

    介绍 struts2有一些控制语句的标签,本教程中我们将讨论如何使用 if 和iterator 标签.更多的控制标签可以参见 tags reference. 到此我们新建一个struts2 web 项 ...

  8. Spark系列之二——一个高效的分布式计算系统

    1.什么是Spark? Spark是UC Berkeley AMP lab所开源的类Hadoop MapReduce的通用的并行计算框架,Spark基于map reduce算法实现的分布式计算,拥有H ...

  9. Spark(十二)--性能调优篇

    一段程序只能完成功能是没有用的,只能能够稳定.高效率地运行才是生成环境所需要的. 本篇记录了Spark各个角度的调优技巧,以备不时之需. 一.配置参数的方式和观察性能的方式 额...从最基本的开始讲, ...

  10. Spark(十二)SparkSQL简单使用

    一.SparkSQL的进化之路 1.0以前:   Shark 1.1.x开始:SparkSQL(只是测试性的)  SQL 1.3.x:          SparkSQL(正式版本)+Datafram ...

随机推荐

  1. 如何在Unity中开发Leap Motion桌面版(Non-VR)APP

    最近因需要,翻出几年前的Leapmotion感测器,准备用Unity3D做个互动APP,于是连上官网下载SDK.等下载下来一安装调试,瞬间傻眼,居然要求VR设备.我们Lab倒是不缺VR,有几套VIVE ...

  2. 微信小程序 movable-view组件应用:可拖动悬浮框_返回首页

    1. movable-view组件具体内容可参考官网:微信官方文档 2. demo参考:https://github.com/ChinaFanny/YFWeappMovableView 运行效果 核心 ...

  3. OpenFOAM——气泡上升

    计算域的顶部为大气,其余部分为壁面 流体的物性参数为: 首先进行建模操作,任何建模软件均可,本算例采用ICEM直接建模,生成网格,然后利用OpenFOAM下转化网格,划分完成的网格如下: 网格比较密集 ...

  4. 拉格朗日插值法(c++)【转载】

    摘自<c++和面向对象数值计算>,代码简洁明快,采用模板函数,通用性增强,对其中代码稍加改动 #include<iostream> #include <vector> ...

  5. 浅析package.json中的devdependencies 和 dependencies

    2.devDependencies (1)内容:是一个对象,配置模块依赖的模块列表,key是模块名称,value是版本范围(2)作用:该模块中所列举的插件属于开发环境的依赖(比如:测试或者文档框架等) ...

  6. hdu1702 ACboy needs your help again![简单STL 栈 队列]

    目录 题目地址 题干 代码和解释 参考 题目地址 hdu1702 题干 代码和解释 本题很简单,只要掌握STL stack和STL vector的语法即可作答.记录本题是为了记录STL vector的 ...

  7. 第09组 Alpha冲刺(2/4)

    队名:软工9组 组长博客:https://www.cnblogs.com/cmlei/ 作业博客:http://edu.cnblogs.com/campus/fzu/SoftwareEngineeri ...

  8. session机制,浏览器禁用cookie后,怎么使用session

    sessionid是存储在cookie中的,解决方案如下: Session URL重写,保证在客户端禁用或不支持COOKIE时,仍然可以使用Session session机制.session机制是一种 ...

  9. 公网IP地址就一定是A类地址和B类地址吗?那C类地址就一定是私有地址吗?

    A,B,C三类中既有公网地址,也有私网地址:在A类地址中,10.0.0.0-10.255.255.255是私有地址.在B类地址中,172.16.0.0-172.31.255.255是私有地址.在C类地 ...

  10. 已知X,Y独立,那么X^2与Y也独立

    考虑离散情况,  P{X^2=k} => P{X=sqrt(k)} 由X,Y独立可知, P{X=Sqrt(k}  | Y=y} =P{X=Sqrt(x)}, P{X^2=k | Y=y} =P{ ...