Spark Dataset的join操作

4 篇文章 0 订阅
3 篇文章 0 订阅

以下是两个具有相同列名的Dataset按照同名列相等进行join操作,join结果中同名列只会出现一个:

val df1 = Seq((1, 2, 3),(1, 1, 1)).toDF("a", "b", "c")
val df2 = Seq((1, 2, 4),(2, 2, 2)).toDF("a", "b", "c")

df1.show
+---+---+---+
|  a|  b|  c|
+---+---+---+
|  1|  2|  3|
|  1|  1|  1|
+---+---+---+

df2.show
+---+---+---+
|  a|  b|  c|
+---+---+---+
|  1|  2|  4|
|  2|  2|  2|
+---+---+---+

df1.join(df2, Seq("a","b"), "inner").show
+---+---+---+---+
|  a|  b|  c|  c|
+---+---+---+---+
|  1|  2|  3|  4|
+---+---+---+---+

df1.join(df2, Seq("a","b"), "outer").show
+---+---+----+----+
|  a|  b|   c|   c|
+---+---+----+----+
|  2|  2|null|   2|
|  1|  2|   3|   4|
|  1|  1|   1|null|
+---+---+----+----+

df1.join(df2, Seq("a","b"), "right").show
+---+---+----+---+
|  a|  b|   c|  c|
+---+---+----+---+
|  1|  2|   3|  4|
|  2|  2|null|  2|
+---+---+----+---+

df1.join(df2, Seq("a","b"), "left").show
+---+---+---+----+
|  a|  b|  c|   c|
+---+---+---+----+
|  1|  2|  3|   4|
|  1|  1|  1|null|
+---+---+---+----+

df1.join(df2, Seq("a","b"), "leftsemi").show
+---+---+---+
|  a|  b|  c|
+---+---+---+
|  1|  2|  3|
+---+---+---+

df1.join(df2, Seq("a","b"), "leftanti").show
+---+---+---+
|  a|  b|  c|
+---+---+---+
|  1|  1|  1|
+---+---+---+

以下是具有不同列名的Dataset按照不同名列相等进行join操作,join结果中两个不同名列都会出现(因为列名不同不能只保留某一列):

val df1 = Seq((1, 2, 3),(1, 1, 1)).toDF("a", "b", "c")
val df2 = Seq((1, 2, 4),(2, 2, 2)).toDF("a1", "b1", "c1")

df1.show
+---+---+---+
|  a|  b|  c|
+---+---+---+
|  1|  2|  3|
|  1|  1|  1|
+---+---+---+

df2.show
+---+---+---+
| a1| b1| c1|
+---+---+---+
|  1|  2|  4|
|  2|  2|  2|
+---+---+---+

df1.join(df2, col("a") === col("a1") && col("b") === col("b1"), "outer").show
+----+----+----+----+----+----+                                                 
|   a|   b|   c|  a1|  b1|  c1|
+----+----+----+----+----+----+
|null|null|null|   2|   2|   2|
|   1|   2|   3|   1|   2|   4|
|   1|   1|   1|null|null|null|
+----+----+----+----+----+----+

若是具有部分相同、部分不同列名的两个Dataset按照部分相同、部分不同列相等进行join操作,有以下几种方式:

val df1 = Seq((1, 2, 3),(1, 1, 1)).toDF("a", "b", "c")
val df2 = Seq((1, 2, 4),(2, 2, 2)).toDF("a", "b1", "d")

df1.show
+---+---+---+
|  a|  b|  c|
+---+---+---+
|  1|  2|  3|
|  1|  1|  1|
+---+---+---+
df2.show
+---+---+---+
|  a| b1|  d|
+---+---+---+
|  1|  2|  4|
|  2|  2|  2|
+---+---+---+
//join条件:df1("a") == df2("a") && df1("b") == df2("b1") 

//若是直接join会报错:org.apache.spark.sql.AnalysisException: Reference 'a' is ambiguous, could be:...
df1.join(df2, col("a") === col("a") && col("b") === col("b1"), "outer").show
//可以改为这样:
df1.join(df2, df1("a") === df2("a") && col("b") === col("b1"), "outer").show
+----+----+----+----+----+----+
|   a|   b|   c|   a|  b1|   d|
+----+----+----+----+----+----+
|null|null|null|   2|   2|   2|
|   1|   2|   3|   1|   2|   4|
|   1|   1|   1|null|null|null|
+----+----+----+----+----+----+

//当然也可以将其中一个Dataset的列改名,改为都相同或都不同,再用上面的方法join
df1.join(df2.withColumnRenamed("b1", "b"), Seq("a", "b"), "outer").show
+---+---+----+----+
|  a|  b|   c|   d|
+---+---+----+----+
|  2|  2|null|   2|
|  1|  2|   3|   4|
|  1|  1|   1|null|
+---+---+----+----+

//还可以用Dataset的as方法(与alias方法等效),给Dataset命名,然后消除歧义。(Dataset的别名类似SQL中表的别名)
df1.alias("df1")
    .join(df2.as("df2"), col("df1.a") === col("df2.a") && col("b") === col("b1"), "outer")
    .show
+----+----+----+----+----+----+
|   a|   b|   c|   a|  b1|   d|
+----+----+----+----+----+----+
|null|null|null|   2|   2|   2|
|   1|   2|   3|   1|   2|   4|
|   1|   1|   1|null|null|null|
+----+----+----+----+----+----+
//如果只想保留df2的a列:
val t = df1.alias("df1")
    .join(df2.as("df2"), col("df1.a") === col("df2.a") && col("b") === col("b1"), "outer")
    .drop(col("df1.a")).show
+----+----+----+----+----+
|   b|   c|   a|  b1|   d|
+----+----+----+----+----+
|null|null|   2|   2|   2|
|   2|   3|   1|   2|   4|
|   1|   1|null|null|null|
+----+----+----+----+----+

补充:
Dataset的as方法(与alias方法等效):为Dataset对象起别名,Dataset的别名类似SQL中表的别名。

val df = Seq((1, 2),(1, 1)).toDF("a", "b")
df.select("a").show
+---+
|  a|
+---+
|  1|
|  1|
+---+

df.select("df.a").show
//报错:org.apache.spark.sql.AnalysisException: cannot resolve '`df.a`' given input columns: [a, b];

df.as("df").select("df.a").show
+---+
|  a|
+---+
|  1|
|  1|
+---+

注意:
以上Dataset的as方法是指的:def as(alias: Symbol): Dataset[T]。
另外Dataset还有一个as方法:def as[U](implicit arg0: Encoder[U]): Dataset[U],这篇文章和此方法无关。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spark Scala中的join算子是一种数据转换函数,用于将两个数据集合并成一个新的数据集。在Spark中,join操作可以通过不同的方式进行,包括内连接、左连接、右连接和外连接。 内连接(inner join)是指将两个数据集合并为一个新的数据集,其中只保留两个数据集中都包含的元素。这种连接方式通常用于需要匹配两个数据集中的关键字或条件时。 左连接(left join)是指将两个数据集合并为一个新的数据集,其中保留左侧数据集中所有的元素,同时将右侧数据集中与左侧数据集匹配的元素合并到新数据集中。如果右侧数据集中没有与左侧数据集匹配的元素,则在新数据集中使用null填充。 右连接(right join)是指将两个数据集合并为一个新的数据集,其中保留右侧数据集中所有的元素,同时将左侧数据集中与右侧数据集匹配的元素合并到新数据集中。如果左侧数据集中没有与右侧数据集匹配的元素,则在新数据集中使用null填充。 外连接(outer join)是指将两个数据集合并为一个新的数据集,其中保留左侧和右侧数据集中所有的元素,同时将左侧和右侧数据集中匹配的元素合并到新数据集中。如果左侧或右侧数据集中没有与另一个数据集匹配的元素,则在新数据集中使用null填充。 在Spark Scala中,join算子通常通过调用DataFrame或Dataset API中的join函数来实现。具体实现方式取决于使用的连接方式和数据集类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值