【发布时间】:2019-03-14 13:51:50
【问题描述】:
here 提出了类似的问题,但它没有正确解决我的问题。我有近 100 个 DataFrame,每个至少有 200,000 行,我需要加入它们,方法是基于列 ID 进行 full 连接,从而创建一个带有列的 DataFrame - ID, Col1, Col2,Col3,Col4, Col5..., Col102。
只是为了说明,我的 DataFrames 的结构 -
df1 = df2 = df3 = ..... df100 =
+----+------+------+------+ +----+------+ +----+------+ +----+------+
| ID| Col1| Col2| Col3| | ID| Col4| | ID| Col5| | ID|Col102|
+----+------+-------------+ +----+------+ +----+------+ +----+------+
| 501| 25.1| 34.9| 436.9| | 501| 22.33| | 503| 22.33| | 501| 78,1|
| 502| 12.2|3225.9| 46.2| | 502| 645.1| | 505| 645.1| | 502| 54.9|
| 504| 754.5| 131.0| 667.3| | 504| 547.2| | 504| 547.2| | 507| 0|
| 505|324.12| 48.93| -1.3| | 506| 2| | 506| 2| | 509| 71.57|
| 506| 27.51| 88.99| 67.7| | 507| 463.7| | 507| 463.7| | 510| 82.1|
.
.
+----+------+------|------| |----|------| |----|------| |----|------|
我开始加入这些 DataFrame,方法是在所有数据帧上依次加入 full。自然,这是一个计算密集型过程,必须努力减少不同工作节点之间的shuffles 数量。因此,我首先使用repartition() 将基于ID 的DataFrame df1 划分为30 个分区-
df1 = df1.repartition(30,'ID')
现在,我在df1 和df2 之间进行full 连接。
df = df1.join(df2,['ID'],how='full')
df.persist()
由于df1 已经是hash-partitioned,所以我预计上面的join 会跳过洗牌并保持df1 的partitioner,但我注意到shuffle 确实发生了并且它将df 上的分区数量增加到200。现在,如果我通过如下所示的函数调用它们继续加入后续的 DataFrame,我会收到错误 java.io.IOException: No space left on device -
def rev(df,num):
df_temp = spark.read.load(filename+str(num)+'.csv')
df_temp.persist()
df = df.join(df_temp,['ID'],how='full')
df_temp.unpersist()
return df
df = rev(df,3)
df = rev(df,4)
.
.
df = rev(df,100)
# I get the ERROR here below, when I call the first action count() -
print("Total number of rows: "+str(df.count()))
df.unpersist() # Never reached this stage.
更新:错误信息 -
Py4JJavaError: An error occurred while calling o3487.count.
: org.apache.spark.SparkException: Job aborted due to stage failure: Task 42 in stage 255.0 failed 1 times, most recent failure: Lost task 42.0 in stage 255.0 (TID 8755, localhost, executor driver): java.io.IOException: No space left on device
at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
at sun.nio.ch.FileDispatcherImpl.write(FileDispatcherImpl.java:60)
问题: 1、为什么我们在做第一个join的时候没有维护df1的partitioner?
2.如何有效地加入这些多个表并避免No space left on device 问题?用户@silvio here 建议使用.bucketBy(),但他也提到了分区器将被维护的事实,但这并没有发生。因此,我不确定加入这些多个 DataFrame 的有效方法是什么。
任何建议/提示将不胜感激。
【问题讨论】:
-
尝试在每个加入的数据帧上使用
coalesce()方法,以保持较少数量的分区,coalesce_repartition -
不是原始问题的答案。但是只有 200,000 行,您可以在一秒钟内在 pandas 中完成此操作。
df = df1; df = df.set_index('ID'); df2 = df2.set_index('ID'); df['col4'] = df2['col4'], ... 等等。希望有人可以将其添加到 pyspark 中。 -
嗯,这只是一个例子......我们的想法是了解 Spark 如何在集群上进行分发以及如何有效地完成负载平衡。
标签: apache-spark pyspark hadoop-partitioning