• Spark3学习【基于Java】5. SparkSql联表查询JOIN


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

     传统数据库单机模式做Join的场景毕竟有限,也建议尽量减少使用Join。
    
     然而大数据领域就完全不同,Join是标配,OLAP业务根本无法离开表与表之间的关联,对Join的支持成熟度一定程度上决定了系统的性能,夸张点说,'得Join者得天下'。
    
     -- 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结果是啥吗?

  • 相关阅读:
    19凡路国庆小作业的题解集合(qwq只是我出的题,我会标明出处的)
    一个for打印99乘法表(这是一种实现方式,可以多种方式的)
    采访学长所得
    洛谷P1028 数的计算
    ccf 2019_03_2 二十四点
    ccf 201812-1 小明上学
    洛谷P3387 【模板】缩点
    洛谷P3216 [HNOI2011]数学作业
    洛谷P1471 方差
    HDU 4114 Disney's FastPass
  • 原文地址:https://www.cnblogs.com/somefuture/p/15682462.html
Copyright © 2020-2023  润新知