我已经阅读了很多有关如何在pyspark中进行有效联接的内容。我发现实现高效联接的方法基本上是:
最后一个是我想尝试的,但是我找不到在pyspark中做到这一点的方法。我尝试过:
df.repartition(numberOfPartitions,['parition_col1','partition_col2'])
但是它无济于事,直到我停止它仍然需要花费很长时间,因为在最后的几个工作中卡住了火花。
那么,我如何才能在pyspark中使用相同的分区程序并加快连接速度,甚至摆脱永久使用的混乱?我需要使用哪个代码?
PD :即使在stackoverflow上,我也查看了其他文章,但仍然看不到代码。
答案 0 :(得分:4)
如果适合您的需要,您还可以使用两次通过方法。首先,对数据进行重新分区,并使用分区表(dataframe.write.partitionBy())进行持久化。然后,将子分区依次循环连接,“追加”到同一最终结果表。 Sim很好地解释了这一点。参见下面的链接
two pass approach to join big dataframes in pyspark
基于上述情况,我能够在一个循环中串行连接子分区,然后将连接的数据持久保存到配置单元表中。
这是代码。
from pyspark.sql.functions import *
emp_df_1.withColumn("par_id",col('emp_id')%5).repartition(5, 'par_id').write.format('orc').partitionBy("par_id").saveAsTable("UDB.temptable_1")
emp_df_2.withColumn("par_id",col('emp_id')%5).repartition(5, 'par_id').write.format('orc').partitionBy("par_id").saveAsTable("UDB.temptable_2")
因此,如果要加入整数emp_id,则可以按ID取模数进行分区,这样您就可以在spark分区之间重新分配负载,并且类似的记录将在两个数据帧上共享相同的分区id。 然后,您可以读取并遍历每个子分区数据,并合并两个数据框并将它们持久保存在一起。
counter =0;
paritioncount = 5;
while counter<=paritioncount:
query1 ="SELECT * FROM UDB.temptable_1 where par_id={}".format(counter)
query2 ="SELECT * FROM UDB.temptable_2 where par_id={}".format(counter)
EMP_DF1 =spark.sql(query1)
EMP_DF2 =spark.sql(query2)
df1 = EMP_DF1.alias('df1')
df2 = EMP_DF2.alias('df2')
innerjoin_EMP = df1.join(df2, df1.emp_id == df2.emp_id,'inner').select('df1.*')
innerjoin_EMP.show()
innerjoin_EMP.write.format('orc').insertInto("UDB.temptable")
counter = counter +1
我已经尝试过了,并且工作正常。这只是演示两次通过方法的示例。您的加入条件可能会有所不同,分区数也取决于您的数据大小。
答案 1 :(得分:2)
谢谢@vikrantrana的回答,如果需要的话,我会尝试的。之所以说这些是因为我发现问题不在于“大”联接,问题在于联接之前的计算量。想象一下这种情况:
我读取了一个表,并将其存储在一个名为df1
的数据框中。我读取了另一个表,并将其存储在df2
中。然后,我进行了大量的计算并加入了两者,最后我得到了df1
和df2
之间的结合。这里的问题不是大小,问题是spark的执行计划很大,并且无法在内存中维护所有中间表,因此它开始写入磁盘,并且花费了很多时间。
对我有用的解决方案是在连接之前将df1
和df2
保留在磁盘上(我还保留了其他大量计算和复杂结果的中间数据帧)。