1、数据预备
heroes_data = [
('Deadpool', 3),
('Iron man', 1),
('Groot', 7)]
race_data = [
('Kryptonian', 5),
('Mutant', 3),
('Human', 1)]
heroes = spark.createDataFrame(heroes_data, ['name', 'id'])
+---------+---+
| name | id|
+-------- +---+
|Deadpool | 3|
|Iron man | 1|
| Groot | 7|
+---------+---+
races = spark.createDataFrame(race_data, ['race', 'id'])
+----------+---+
| race | id|
+----------+---+
|Kryptonian| 5|
| Mutant| 3|
| Human| 1|
+----------+---+
2、Cross join
笛卡尔积
这个比较好理解,就是heroes
表的数据和races
表的数据进行Join
,就是将heroes
表的每一行数据都同races
表的每一行数据进行联合。数据的数量级就是 m*n
。不考虑Join
的主键。
>>> heroes.crossJoin(races).show()
+----------+-----+-----------+----+
| name| id| race| id|
+----------+-----+-----------+----+
| Deadpool| 3| Kryptonian| 5|
| Deadpool| 3| Mutant| 3|
| Deadpool| 3| Human| 1|
| Iron man| 1| Kryptonian| 5|
| Iron man| 1| Mutant| 3|
| Iron man| 1| Human| 1|
| Groot| 7| Kryptonian| 5|
| Groot| 7| Mutant| 3|
| Groot| 7| Human| 1|
+----------+-----+-----------+----+
3、Inner join 内联合
只生成同时匹配表heroes
和表races
的记录集。
>>> heroes.join(races, on='id', how='inner').show()
+---+------------+----------+
| id| name| race|
+---+------------+----------+
| 1| Iron man| Human|
| 3| Deadpool| Mutant|
+---+------------+----------+
4、Left join / Left outer join
左外联合
left
和 left outer
是一个别名的关系。生成表heroes
的所有记录,包括在表races
里匹配的记录。如果没有匹配的,右边将是null
。就是inner Join
的结果,再加上左边的表未匹配的所有的结果。
>>> heroes.join(races, on='id', how='left').show()
>>> heroes.join(races, on='id', how='leftouter').show()
+---+------------+----------+
| id| name| race|
+---+------------+----------+
| 1| Groot| null|
| 1| Iron man| Human|
| 3| Deadpool| Mutant|
+---+------------+----------+
5、Right join / Right outer join
右外联合
right
和 right outer
是一个别名的关系。生成表heroes
的所有记录,包括在表races
里匹配的记录。如果没有匹配的,左边将是null
。就是inner Join
的结果,再加上右边的表未匹配的所有的结果。
>>> heroes.join(races, on='id', how='right').show()
>>> heroes.join(races, on='id, how='rightouter').show()
+---+------------+-----------+
| id| name| race|
+---+------------+-----------+
| 5| null| Kryptonian|
| 1| Iron man| Human|
| 3| Deadpool| Mutant|
+---+------------+-----------+
6、Full outer join
全外联合
outer
和full
也是别名关系。生成表heroes
和表races
里的记录全集,包括两边都匹配的记录。如果有一边没有匹配的,缺失的这一边为null
。
>>> heroes.join(races, on='id', how='outer').show()
>>> heroes.join(races, on='id', how='full').show()
+---+-------------+------------+
| id| name| race|
+---+-------------+------------+
| 7| Groot| null|
| 5| null| Kryptonian|
| 1| Iron man| Human|
| 3| Deadpool| Mutant|
+---+-------------+------------+
7、Left semi-join
左半连接
可以简单的看成是,inner join
之后,只保留能够Join
上的左边表数据。
>>> heroes.join(races, on='id', how='leftsemi').show()
+---+-----------+
| id| name|
+---+-----------+
| 1| Iron man|
| 3| Deadpool|
+---+-----------+
8、Left anti join
是Left semi-join
的取反操作,将左边中,没有匹配上的数据给取出。
>>> heroes.join(races, on='id', how='leftanti').show()
+---+-------+
| id| name|
+---+-------+
| 7| Groot|
+---+-------+
9、其他补充
在Join
的过程中,左边和右边都不能为None
,可以是空数据的表但是需要带Schema
,Schema
中有指定的关联主键(on
)。
使用Pyspark
中创建空的DataFrame
:
- 创建空
Schema
的空DataFrame
; - 创建带
Schema
的空DataFrame
。
def create_empty_df_without_schema():
# Create an empty RDD
emp_RDD = spark.sparkContext.emptyRDD()
# Create empty schema
columns = StructType([])
return spark.createDataFrame(data=emp_RDD,
schema=columns)
def create_empty_df_with_schema():
columns = StructType([
StructField('name', StringType(), True),
StructField('id', IntegerType(), True),
])
# emp_RDD = spark.sparkContext.emptyRDD()
return spark.createDataFrame(data=[],
schema=columns)