Spark Join *无*洗牌

时间:2018-12-08 03:37:00

标签: scala apache-spark

我正在尝试优化我的Spark应用程序工作。

我试图理解以下问题的要点:How to avoid shuffles while joining DataFrames on unique keys?

  1. 我已确保必须进行联接操作的键分布在同一分区内(使用我的自定义分区程序)。

  2. 我也无法进行广播加入,因为根据情况我的数据可能很大。

  3. 在上述问题的答案中,重新分区仅优化了联接,但我需要的是联接而没有任何准备。在分区内的键的帮助下进行联接操作我就很好。

有可能吗?如果不存在类似功能,我想实现类似joinperpartition的功能。

2 个答案:

答案 0 :(得分:3)

  

重新分区只会优化联接,但我需要的是联接而没有任何麻烦

这不是事实。分区不仅可以“优化”联接。重新分区将Partitioner绑定到您的RDD,这是地图端连接的关键组件。

  

我确保必须进行联接操作的键分布在同一分区中

火花必须知道这一点。使用适当的API构建您的DataFrame,使其具有相同的Partitioner,而spark将负责其余的工作。

答案 1 :(得分:2)

只是先前的好答案的补充。 如果您在整个pyspark应用程序中多次加入一个大数据框,则将该表另存为存储桶表,然后将其作为数据框读回pyspark。这样,您就可以避免在连接过程中多次混洗,因为数据已经被预先混洗和排序了。

因此,当Spark选择在两个大型数据帧上进行排序合并联接时,它将在联接操作期间跳过排序和混洗阶段。 (您可以在spark UI中通过查看Wholecodegen进行确认)

df_data_1.coalesce(1).write.format('orc').bucketBy(20, 'joincolumn').sortBy("sortcolumn").mode("overwrite").saveAsTable('bucketed_table1')

df_data_2.coalesce(1).write.format('orc').bucketBy(20, 'joincolumn').sortBy("sortcolumn").mode("overwrite").saveAsTable('bucketed_table2')

df_bucket_table_1 = spark.table("bucketed_table1");
df_bucket_table_2 = spark.table("bucketed_table2");

spark.conf.set("spark.sql.autoBroadcastJoinThreshold", -1)
spark.conf.set("spark.sql.join.preferSortMergeJoin","true")

 #creating alias for the dataframes:
from pyspark.sql.functions import *

df1 = df_bucket_table_1.alias('df1')
df2 = df_bucket_table_2.alias('df2')


DfInnerJoin = df1.join(df2, df1.joincolumn == df2.joincolumn,'inner').select('df1.*')

上面的联接将不会进行改组,但这仅在您必须在整个应用程序中多次联接同一数据帧时才有用。