我正在尝试优化我的Spark应用程序工作。
我试图理解以下问题的要点:How to avoid shuffles while joining DataFrames on unique keys?
我已确保必须进行联接操作的键分布在同一分区内(使用我的自定义分区程序)。
我也无法进行广播加入,因为根据情况我的数据可能很大。
在上述问题的答案中,重新分区仅优化了联接,但我需要的是联接而没有任何准备。在分区内的键的帮助下进行联接操作我就很好。
有可能吗?如果不存在类似功能,我想实现类似joinperpartition的功能。
答案 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.*')
上面的联接将不会进行改组,但这仅在您必须在整个应用程序中多次联接同一数据帧时才有用。