PySpark 各种姿势的join连接

参考:https://sparkbyexamples.com/pyspark/pyspark-join-explained-with-examples/

1. PySpark 连接语法

PySpark SQL 连接具有以下语法,可以直接从 DataFrame 访问。


join(self, other, on=None, how=None)

join()操作接受如下参数并返回DataFrame。

  • 参数 other:连接的右侧
  • 参数 on:连接列名称的字符串
  • 参数如何:默认inner。必须是innercrossouterfullfull_outerleftleft_outerrightright_outerleft_semi, 和之一left_anti

您还可以通过在 DataFrame 上添加where()filter()方法来编写 Join 表达式,并且可以在多个列上进行 Join。

2. PySpark 连接类型

以下是 PySpark 支持的不同连接类型。

Join String Equivalent SQL Join
inner INNER JOIN
outer, full, fullouter, full_outer FULL OUTER JOIN
left, leftouter, left_outer LEFT JOIN
right, rightouter, right_outer RIGHT JOIN
cross  
anti, leftanti, left_anti  
semi, leftsemi, left_semi


PySpark 连接类型

在我们进入 PySpark SQL Join 示例之前,首先,让我们创建一个"emp""dept" DataFrames。在这里,列"emp_id"在 emp 上"dept_id"是唯一的,并且在 dept 数据集上是唯一的,并且来自 emp 的 emp_dept_id 具有对 dept 数据集上的 dept_id 的引用。


emp = [(1,"Smith",-1,"2018","10","M",3000), \
    (2,"Rose",1,"2010","20","M",4000), \
    (3,"Williams",1,"2010","10","M",1000), \
    (4,"Jones",2,"2005","10","F",2000), \
    (5,"Brown",2,"2010","40","",-1), \
      (6,"Brown",2,"2010","50","",-1) \
  ]
empColumns = ["emp_id","name","superior_emp_id","year_joined", \
       "emp_dept_id","gender","salary"]

empDF = spark.createDataFrame(data=emp, schema = empColumns)
empDF.printSchema()
empDF.show(truncate=False)

dept = [("Finance",10), \
    ("Marketing",20), \
    ("Sales",30), \
    ("IT",40) \
  ]
deptColumns = ["dept_name","dept_id"]
deptDF = spark.createDataFrame(data=dept, schema = deptColumns)
deptDF.printSchema()
deptDF.show(truncate=False)

这会将“emp”和“dept”DataFrame 打印到控制台。请参阅下面有关如何创建spark对象的完整示例。


Emp Dataset
+------+--------+---------------+-----------+-----------+------+------+
|emp_id|name    |superior_emp_id|year_joined|emp_dept_id|gender|salary|
+------+--------+---------------+-----------+-----------+------+------+
|1     |Smith   |-1             |2018       |10         |M     |3000  |
|2     |Rose    |1              |2010       |20         |M     |4000  |
|3     |Williams|1              |2010       |10         |M     |1000  |
|4     |Jones   |2              |2005       |10         |F     |2000  |
|5     |Brown   |2              |2010       |40         |      |-1    |
|6     |Brown   |2              |2010       |50         |      |-1    |
+------+--------+---------------+-----------+-----------+------+------+

Dept Dataset
+---------+-------+
|dept_name|dept_id|
+---------+-------+
|Finance  |10     |
|Marketing|20     |
|Sales    |30     |
|IT       |40     |
+---------+-------+

3. PySpark 内连接数据框

Inner join 是 PySpark 中的默认连接,它最常被使用。emp这会在键列上连接两个数据集,其中键与从两个数据集 ( & dept) 中删除的行不匹配。


empDF.join(deptDF,empDF.emp_dept_id ==  deptDF.dept_id,"inner") \
     .show(truncate=False)

当我们对数据集应用内连接时,它会从“”数据集中删除“ emp_dept_id”50,从“ emp”数据集中删除“ dept_id”30 dept(因为二者没有交集)。下面是上述 Join 表达式的结果。


+------+--------+---------------+-----------+-----------+------+------+---------+-------+
|emp_id|name    |superior_emp_id|year_joined|emp_dept_id|gender|salary|dept_name|dept_id|
+------+--------+---------------+-----------+-----------+------+------+---------+-------+
|1     |Smith   |-1             |2018       |10         |M     |3000  |Finance  |10     |
|2     |Rose    |1              |2010       |20         |M     |4000  |Marketing|20     |
|3     |Williams|1              |2010       |10         |M     |1000  |Finance  |10     |
|4     |Jones   |2              |2005       |10         |F     |2000  |Finance  |10     |
|5     |Brown   |2              |2010       |40         |      |-1    |IT       |40     |
+------+--------+---------------+-----------+-----------+------+------+---------+-------+

4. PySpark 全外连接

Outeraka fullfullouterjoin 返回两个数据集中的所有行,其中 join 表达式不匹配它在相应的记录列上返回 null 。


empDF.join(deptDF,empDF.emp_dept_id ==  deptDF.dept_id,"outer") \
    .show(truncate=False)
empDF.join(deptDF,empDF.emp_dept_id ==  deptDF.dept_id,"full") \
    .show(truncate=False)
empDF.join(deptDF,empDF.emp_dept_id ==  deptDF.dept_id,"fullouter") \
    .show(truncate=False)

从我们的“ emp”数据集的“ emp_dept_id”中,值为 50 的“ ”上没有记录,dept因此 dept 列有 null ,“ dept_id” 30 在“ ”中没有记录,emp因此您在 emp 列上看到 null(直观理解,就是并集) 。下面是上述 Join 表达式的结果。


+------+--------+---------------+-----------+-----------+------+------+---------+-------+
|emp_id|name    |superior_emp_id|year_joined|emp_dept_id|gender|salary|dept_name|dept_id|
+------+--------+---------------+-----------+-----------+------+------+---------+-------+
|2     |Rose    |1              |2010       |20         |M     |4000  |Marketing|20     |
|5     |Brown   |2              |2010       |40         |      |-1    |IT       |40     |
|1     |Smith   |-1             |2018       |10         |M     |3000  |Finance  |10     |
|3     |Williams|1              |2010       |10         |M     |1000  |Finance  |10     |
|4     |Jones   |2              |2005       |10         |F     |2000  |Finance  |10     |
|6     |Brown   |2              |2010       |50         |      |-1    |null     |null   |
|null  |null    |null           |null       |null       |null  |null  |Sales    |30     |
+------+--------+---------------+-----------+-----------+------+------+---------+-------+

5. PySpark 左外连接

Leftaka Leftouterjoin 返回左侧数据集中的所有行,无论在右侧数据集上找到匹配,当连接表达式不匹配时,它为该记录分配 null 并从右侧删除未找到匹配的记录。


  empDF.join(deptDF,empDF.emp_dept_id ==  deptDF.dept_id,"left")
    .show(truncate=False)
  empDF.join(deptDF,empDF.emp_dept_id ==  deptDF.dept_id,"leftouter")
    .show(truncate=False)

从我们的数据集中,“ emp_dept_id” 5o 在“ ”数据集上没有记录,因此,该记录在“ ”列(dept_name 和 dept_id)dept上包含空值。dept和“ ”数据集中的“ dept_id” 30 从dept结果中删除。下面是上述 Join 表达式的结果。


+------+--------+---------------+-----------+-----------+------+------+---------+-------+
|emp_id|name    |superior_emp_id|year_joined|emp_dept_id|gender|salary|dept_name|dept_id|
+------+--------+---------------+-----------+-----------+------+------+---------+-------+
|1     |Smith   |-1             |2018       |10         |M     |3000  |Finance  |10     |
|2     |Rose    |1              |2010       |20         |M     |4000  |Marketing|20     |
|3     |Williams|1              |2010       |10         |M     |1000  |Finance  |10     |
|4     |Jones   |2              |2005       |10         |F     |2000  |Finance  |10     |
|5     |Brown   |2              |2010       |40         |      |-1    |IT       |40     |
|6     |Brown   |2              |2010       |50         |      |-1    |null     |null   |
+------+--------+---------------+-----------+-----------+------+------+---------+-------+

 

更多见原文

9. PySpark 自加入

没有自连接,连接是不完整的,虽然没有可用的自连接类型,但我们可以使用上述任何一种连接类型将 DataFrame 连接到自身。下面的示例使用inner自联接。


empDF.alias("emp1").join(empDF.alias("emp2"), \
    col("emp1.superior_emp_id") == col("emp2.emp_id"),"inner") \
    .select(col("emp1.emp_id"),col("emp1.name"), \
      col("emp2.emp_id").alias("superior_emp_id"), \
      col("emp2.name").alias("superior_emp_name")) \
   .show(truncate=False)

在这里,我们将emp数据集与自身结合起来,以找出优秀的emp_idname为所有员工服务。


+------+--------+---------------+-----------------+
|emp_id|name    |superior_emp_id|superior_emp_name|
+------+--------+---------------+-----------------+
|2     |Rose    |1              |Smith            |
|3     |Williams|1              |Smith            |
|4     |Jones   |2              |Rose             |
|5     |Brown   |2              |Rose             |
|6     |Brown   |2              |Rose             |
+------+--------+---------------+-----------------+

4. 使用 SQL 表达式

由于 PySpark SQL 支持原生 SQL 语法,我们还可以在 DataFrames 上创建临时表后编写连接操作,并在spark.sql().


empDF.createOrReplaceTempView("EMP")
deptDF.createOrReplaceTempView("DEPT")

joinDF = spark.sql("select * from EMP e, DEPT d where e.emp_dept_id == d.dept_id") \
  .show(truncate=False)

joinDF2 = spark.sql("select * from EMP e INNER JOIN DEPT d ON e.emp_dept_id == d.dept_id") \
  .show(truncate=False)

5. PySpark SQL Join 多个 DataFrames

当您需要连接两个以上的表时,您可以在 DataFrame 上创建临时视图后使用 SQL 表达式,或者使用连接操作的结果与另一个 DataFrame 连接,例如链接它们。例如


df1.join(df2,df1.id1 == df2.id2,"inner") \
   .join(df3,df1.id1 == df3.id3,"inner")

示例可在GitHub项目中获得以供参考。

结论

在本 PySpark SQL 教程中,您学习了可以使用 DataFrame 的join()功能连接两个或多个 DataFrame,Join 类型语法、用法和 PySpark 示例(Spark with Python),我还建议您阅读优化 SQL 连接以了解对连接的性能影响。

posted @ 2022-08-12 10:33  bonelee  阅读(3492)  评论(0编辑  收藏  举报