大数据场景下,联表远比微小型关系型数据库中使用的频繁。网上有句话:

  1. 传统数据库单机模式做Join的场景毕竟有限,也建议尽量减少使用Join
  1. 然而大数据领域就完全不同,Join是标配,OLAP业务根本无法离开表与表之间的关联,对Join的支持成熟度一定程度上决定了系统的性能,夸张点说,'得Join者得天下'
  1. -- SparkSQL 有必要坐下来聊聊Join 有态度的HBase/Spark/BigData (hbasefly.com)

不同数据库引擎对JOIN的实现算法一般不同,我们最常用的mysql中的join实现是Nested Loop Join (MySQL中Join算法实现原理通俗易懂_墨卿风竹的博客-CSDN博客),Spark中支持的要更广泛。

下面我们创造两个DF来进行测试。

  1. private static List<Customer> getCustomers() {
  2.     List<Customer> customerList = new ArrayList<>(3);
  3.     customerList.add(new Customer(100, "张三"));
  4.     customerList.add(new Customer(101, "张四"));
  5.     customerList.add(new Customer(102, "张五"));
  6.     System.out.println("Customer: " + customerList);
  7.     return customerList;
  8. }
  9.  
  10. private static List<Payment> getPayments() {
  11.     Random random = new Random(0);
  12.     List<Payment> paymentList = new ArrayList<>(6);
  13.     for (int a = 0; a < 6; a++) {
  14.         int i = random.nextInt(10000);
  15.         Payment p = new Payment((long) (a + 1), (long) (100+ a), (double) i);
  16.         paymentList.add(p);
  17.     }
  18.     System.out.println("Payment: " + paymentList);
  19.     return paymentList;
  20. }

Inner Join

内连接是spark默认的连接方式。通过join方法即可使用内连接:

你要这样用的话,会发现还有一个方法不用传入连接字段,猜一下输出什么:

上面这种连接只能指定一个连接字段,如果需要多字段匹配呢?spark提供了另一个方法:

这个方法的第二个参数Java没法直接提供,需要转换一下:

left join

DF没有直接提供leftJoin这样的方法,只提供了join()和crossJoin()两个。从上面的文档截图可以看到,通过传第三个参数来指定不同的连接方式。

现在对Java程序员不太友好了,每次join都要先转一次:可能这也是网上的博客、教程都用scala的原因吧。

right join

和left join类似:

outer join

全外连接是左外和右外的组合,这里不演示了。

cross join

这个上面提到了 ,有对应的方法。它产生的是笛卡尔积,会产生大量结果:

这个方法是2.1之后增加的。之前也是通过join方法实现,但是会被不小心误用,就增加了一个明确的方法。

Left-Semi-Join

左半连接和左连接比较类似,差别是结果中不包含右表字段,仅包含左表字段。

左连接不是既包含左表字段,又有右表字段,右表中不匹配的字段也显示但是为null。左半连接是右表不匹配的记录左表就不展示了,实际更应该叫semi-inner-join。它相当于关系型SQL中的子查询。

但是由于只返回左表,所以叫左半连接。同时并不提供右半连接操作,因为它就是内连接。

下面是连接方式映射

Left-anti-Join

左反连接是左半连接的取反,并不是右半连接。它展示的是左连接以后,右表是null的那些左表数据,也就是内连接以后左表的补集。相等于关系型数据库的not in。

Self Join

自连接就是DF跟自己连接,所以需要通过别名来区分两个DF。

自连接我们再Mysql中用的不少,一般用来查询层级数据,比如有父子关系的记录。为了简单,假设Payment中两个字段有父子关系,于是这样查询:

上面造的数据都不满足,所以改成这样:

运行输出是

如果把第一个参数的开始值改成98,输出就是

Null 字段匹配

假设在连接过程中(任何连接场景),连接字段出现了null会怎么样?

假设payement记录如下

默认情况下,spark会忽略这些记录,如果不想忽略可以这样:

  1. import static org.apache.spark.sql.functions.col;
  2.  
  3.  
  4. Dataset<Row> join = payment.as("c1").join(payment.as("c2"), col("c1.paymentId").eqNullSafe(col("c2.customerId")));
  5. join.show();

这里使用了方法eqNullSafe

结果如下

现在连customer也改成null看一下

两张表内连接结果如下

改成使用方法eqNullSage,结果如下

好像看起来不错,但你去把结果跟最早的结果(没比较Null的时候)对比发现,这里customerId出现了两次,而之前只出现了一次。

这里可以使用drop方法移除列:

  1. join.drop("customerId").show();
  2. join.drop(payment.col("customerId")).show();

效果可以猜一下。

JoinWith

最后说一下这个方法。从它的签名可以猜出作用:

把前面内连接的例子改成joinWith方法:

结果中每一行是一个元组,元组的两个元素分别是两个表的原始记录。

最后

已经都来到这了,你不想知道左半连接或左反连接的joinWith结果是啥吗?

Spark3学习【基于Java】5. Spark-Sql联表查询JOIN的更多相关文章

  1. SQL联表查询

    数据库中最最常用的语法----select.简单的select语法很直白: select column from table where expression: 从((from)存储数据的地方(tab ...

  2. 基于双下划线的跨表查询 (join查询)

    因为你的数据库中的查询就是重点  那么你的django提供的orm也是查询语句最重点 ,也提供的查询方法比较的多,下面我们学习下类似于MYSQL的连表(join)查询 Django 还提供了一种直观而 ...

  3. vb.net DBEntities框架联表查询 Join

    在项目中配置好DBEntities 使用两个表:主表Table, 子表Table_Item 主要是用到了委托和泛型,ForEach用的是不带返回值的委托 Sub GetDb() Dim st As N ...

  4. [慢查优化]联表查询注意谁是驱动表 & 你搞不清楚谁join谁更好时请放手让mysql自行判定

    写在前面的话: 不要求每个人一定理解 联表查询(join/left join/inner join等)时的mysql运算过程: 不要求每个人一定知道线上(现在或未来)哪张表数据量大,哪张表数据量小: ...

  5. 【转】[慢查优化]联表查询注意谁是驱动表 & 你搞不清楚谁join谁更好时请放手让mysql自行判定

    转自:http://zhengyun-ustc.iteye.com/blog/1942797 写在前面的话: 不要求每个人一定理解 联表查询(join/left join/inner join等)时的 ...

  6. 【explain】MySQL联表查询中的驱动表

    写在前面 1.不要求每个人一定理解 联表查询(join/left join/inner join等)时的mysql运算过程 2.不要求每个人一定知道线上(现在或未来)哪张表数据量大,哪张表数据量小 3 ...

  7. django orm 基于双下划线的跨表查询

    一..基于双下划线的跨表查询(join实现) key:正向查询按字段,反向查询按表明小写 1.一对多跨表查询 查询在跨表中可以有两种方式,正向查询就是关键字段在你要搜索的表,没有关键字段就是反向查询 ...

  8. Django学习——图书相关表关系建立、基于双下划线的跨表查询、聚合查询、分组查询、F查询、Q查询、admin的使用、使用脚本调用Django、Django查看源生sql

    0 图书相关表关系建立 1.5个表 2.书籍表,作者表,作者详情表(垂直分表),出版社表,书籍和作者表(多对多关系) 一对一 多对多 本质都是一对多 外键关系 3.一对一的关系,关联字段可以写在任意一 ...

  9. sql学习笔记(三)—— 联表查询

    上篇写了一些sql查询的知识,这篇接着写一下有关联表查询的知识. 既然是联表查询,那肯定得多个表啊,所以,我们先创建一个教师表,表名为 teacher,并且向表中插入数据. 准备工作: 创建表语句: ...

  10. MyBatis学习存档(5)——联表查询

    之前的数据库操作都是基于一张表进行操作的,若一次查询涉及到多张表,那该如何进行操作呢? 首先明确联表查询的几个关系,大体可以分为一对一和一对多这两种情况,接下来对这两种情况进行分析: 一.建立表.添加 ...

随机推荐

  1. ansible系列(28)--ansible的playbook异常处理

    目录 1. playbook的异常处理 1.1 Playbook错误忽略 1.2 task执行失败强制调用handlers 1.3 控制Tasks报告状态为OK 1.4 changed_when检查任 ...

  2. 【项目学习】Anchor:一种提供稳定币存款低波动收益率的去中心化的储蓄协议

    简介 基于稳定币的获利产品. 贷方人放出稳定币以供借款.借方通过抵押资产(base asset)的方式,以低于协议定义的借贷比率借入稳定币.Anchor 协议使用抵押资产进行质押以获得奖励,然后将质押 ...

  3. Windows远程连接工具有哪些

    Windows远程连接工具,一般称为远程桌面软件,更准确的叫远程访问软件或远程控制软件,可以让你从一台电脑远程控制另一台电脑.远程桌面软件允许您控制连接的计算机,就好像它就在您面前一样. 远程桌面工具 ...

  4. 推荐一个好用的.net开发框架

    企业应用开发平台(Enterprise Develop Platform),以下简称EDP.EDP是一套集完整组织架构,全面权限体系,以及各类基础功能于一体的基于.net的企业应用开发平台.其最大的特 ...

  5. IPv6 — 实践

    目录 文章目录 目录 前文列表 常用命令 开启/关闭 IPv6 支持 在 CentOS7 上配置 IPv6 地址 自动获取链路本地地址 配置静态全球唯一地址 配置临时 IPv6 地址 添加 IPv6 ...

  6. systemctl管理自定义服务模版

    一  日常工作中,有许多需要使用systemctl进行管理服务的时候 [Unit] Description=radius Release [Service] ExecStart=/etc/init.d ...

  7. powershell 设置代理

    $env:HTTP_PROXY="http://127.0.0.1:10809" $env:HTTPS_PROXY="http://127.0.0.1:10809&quo ...

  8. 彻底搞懂JavaScript原型和原型链

    基于原型编程 在面向对象的编程语言中,类和对象的关系是铸模和铸件的关系,对象总是从类创建而来,比如Java中,必须先创建类再基于类实例化对象. 而在基于原型编程的思想中,类并不是必须的,对象都是通过克 ...

  9. Java JVM——1.JVM与Java体系结构

    前言 作为Java工程师的你曾被伤害过吗?你是否也遇到过这些问题? ✘ 运行着的线上系统突然卡死,系统无法访问,甚至直接OOMM! ✘ 想解决线上JVM GC问题,但却无从下手. ✘ 新项目上线,对各 ...

  10. 用tkinter编写一个简单的登录注册界面

    代码: from tkinter import * window = Tk() window.geometry('400x300+500+150') window.title('xxx系统') Can ...