我有两个DataFrame,并想要外连接它们。但是连接映射在另一个数据帧中。
现在我正在使用以下方式,它可行,但我希望有更有效的方法,我有> 1,000,000行
val ta = sc.parallelize(Array(
(1,1,1),
(2,2,2)
)).toDF("A", "B", "C")
scala> ta.show
+---+---+---+
| A| B| C|
+---+---+---+
| 1| 1| 1|
| 2| 2| 2|
+---+---+---+
val tb = sc.parallelize(Array(
(2,1)
)).toDF("C", "D")
scala> tb.show
+---+---+
| C| D|
+---+---+
| 2| 1|
+---+---+
val tc = sc.parallelize(Array(
(1,1,1),
(2,2,2)
)).toDF("D", "E", "F")
scala> tc.show
+---+---+---+
| D| E| F|
+---+---+---+
| 1| 1| 1|
| 2| 2| 2|
+---+---+---+
scala> val tmp = ta.join(tb, Seq("C"), "left_outer")
tmp: org.apache.spark.sql.DataFrame = [C: int, A: int, B: int, D: int]
scala> tmp.show
+---+---+---+----+
| C| A| B| D|
+---+---+---+----+
| 1| 1| 1|null|
| 2| 2| 2| 1|
+---+---+---+----+
scala> tmp.join(tc, Seq("D"), "outer").show
+----+----+----+----+----+----+
| D| C| A| B| E| F|
+----+----+----+----+----+----+
|null| 1| 1| 1|null|null|
| 1| 2| 2| 2| 1| 1|
| 2|null|null|null| 2| 2|
+----+----+----+----+----+----+
答案 0 :(得分:1)
正如Umberto所指出的,关于如何提高联盟表现的一个很好的参考是Holden Karau和Rachel Warren的High Performance Spark > Chapter 4. Joins (SQL & Core)。
从您的代码的角度来看,按照您的说明运行它或SQL等价物(如下所述)应该会产生大致相同的性能。
// Create initial tables
val ta = sc.parallelize(Array(
(1,1,1),
(2,2,2)
)).toDF("A", "B", "C")
val tb = sc.parallelize(Array(
(2,1)
)).toDF("C", "D")
val tc = sc.parallelize(Array(
(1,1,1),
(2,2,2)
)).toDF("D", "E", "F")
// _.createOrReplaceTempView
ta.createOrReplaceTempView("ta")
tb.createOrReplaceTempView("tb")
tc.createOrReplaceTempView("tc")
// SQL Query
spark.sql("
select tc.D, ta.A, ta.B, ta.C, tc.E, tc.F
from ta
left outer join tb
on tb.C = ta.C
full outer join tc
on tc.D = tb.D
")
之所以如此,是因为Spark SQL Catalyst Optimizer(如下图所示)采用DataFrame查询并构建优化的逻辑计划。开发了许多物理计划,Spark SQL Engine的成本优化器选择最佳物理计划并生成代码以生成RDD。
说到这一点,关键问题是当你处理大量占用大量内存的行时,你必须考虑到分区。例如,如果您可以确保映射DataFrame(tc
)与其他DataFrame(ta
,tb
)具有相同/相似的分区方案,那么您可以拥有< strong> co-located join (这是{4}}中的图4-3)。
如果您的三个数据框架(ta
,tb
,tc
)的分区都具有不同的分区,则表示您的DataFrame的密钥不会具有1对1分区之间的匹配。也就是说,这将导致 shuffle join (这是{4}}中的图4-2),这可能会更昂贵。
基本上,从您的查询的角度来看,关注点不仅仅是查询本身,更多的是关于DataFrames的分区方案。但在对DataFrame的分区方案进行过多尝试之前,请先试验一下您的查询,看看默认的Spark SQL / DataFrame查询是否能够自行处理分区。