我看着这个问题:Question about joining dataframes in Spark,并根据我的观察回答了。
确实是一个有趣的问题,正如我指出的那样,在将Scala与Scala配合使用或与pyspark配合使用时,进行左(外部联接)的物理计划有所不同。
现在,我注意到pyspark与酸洗之间存在差异,但是我会认为-正如最近在一次采访中告诉我的那样,这可能是一个棘手的问题-Catalyst会在引擎盖下尝试实施相同的物理计划基本上。
为什么会有所不同?
例如,用于JOIN的分区数量和分区的结果数量如链接中所示,在处理(结果)方面有所不同。
我本来以为语法可能会有所不同,但是下面的层对于pyspark和Spark是很常见的。我的猜测是,酸洗与此或分区有关。顺便说一句,查询没有任何实际意义,只是人为的。
以下是基本相同内容的物理计划:
Pyspark
df4 = df1.join(df2, on=['key1', 'key2', 'time'], how='left').explain()
==身体计划==
*(5) Project [key1#474L, key2#475L, time#476L]
+- SortMergeJoin [key1#474L, key2#475L, time#476L], [key1#480L, key2#481L, time#482L], LeftOuter
:- *(2) Sort [key1#474L ASC NULLS FIRST, key2#475L ASC NULLS FIRST, time#476L ASC NULLS FIRST], false, 0
: +- Exchange hashpartitioning(key1#474L, key2#475L, time#476L, 3)
: +- *(1) Scan ExistingRDD[key1#474L,key2#475L,time#476L]
+- *(4) Sort [key1#480L ASC NULLS FIRST, key2#481L ASC NULLS FIRST, time#482L ASC NULLS FIRST], false, 0
+- Exchange hashpartitioning(key1#480L, key2#481L, time#482L, 3)
+- *(3) Filter ((isnotnull(key1#480L) && isnotnull(key2#481L)) && isnotnull(time#482L))
+- *(3) Scan ExistingRDD[key1#480L,key2#481L,time#482L]
斯卡拉
val df4 = df1.join(df2, Seq("key1", "key2", "time"), "left").explain()
==身体计划==
*(1) Project [key1#647, key2#648, time#649]
+- *(1) BroadcastHashJoin [key1#647, key2#648, time#649], [key1#671, key2#672, time#673], LeftOuter, BuildRight, false
:- Exchange RoundRobinPartitioning(3)
: +- LocalTableScan [key1#647, key2#648, time#649]
+- BroadcastExchange HashedRelationBroadcastMode(ArrayBuffer(input[0, int, false], input[1, int, false], input[2, int, false]))
+- Exchange RoundRobinPartitioning(3)
+- LocalTableScan [key1#671, key2#672, time#673]