我的问题如下:
我有一个名为details
的大型数据框,其中包含900K行,另一个包含名为attributes
的80M行。
两者都有一列A
,我希望在其中进行左外连接,左侧数据框为deatils
。
数据框A
中的列details
中只有75K个唯一条目。列attributes
中的数据框A
80M唯一条目。
实现join
操作的最佳方式是什么?
我尝试了什么?
简单连接,即details.join(attributes, "A", how="left_outer")
只是超时(或内存不足)。
由于A
中的details
列中只有75K个唯一条目,因此我们并不关心attributes
中数据框中的其余内容。所以,首先我使用以下方法过滤:
uniqueA = details.select('A').distinct().collect()
uniqueA = map(lambda x: x.A, uniqueA)
attributes_filtered = attributes.filter(attributes.A.isin(*uniqueA))
我认为这会有效,因为attributes
表从80M行下降到仅75K行。但是,完成join
(它永远不会完成)仍然需要永远。
接下来,我认为分区太多,要连接的数据不在同一个分区上。虽然,我不知道如何将所有数据带到同一个分区,但我认为重新分区可能有所帮助。所以就这样了。
details_repartitioned = details.repartition("A")
attributes_repartitioned = attributes.repartition("A")
上述操作将attributes
中的分区数从70K减少到200. details
中的分区数约为1100.
details_attributes = details_repartitioned.join(broadcast(
attributes_repartitioned), "A", how='left_outer') # tried without broadcast too
毕竟,join
仍然不起作用。我还在学习PySpark,所以我可能误解了重新分区背后的基本原理。如果有人能够阐明这一点,那就太棒了。
P.S。我已经看过this个问题,但是这个问题没有回答。
答案 0 :(得分:3)
详细信息表有900k项,A列有75k个不同的条目。我认为您尝试过的A列上的过滤器是正确的方向。然而,收集并遵循地图操作
attributes_filtered = attributes.filter(attributes.A.isin(*uniqueA))
这太贵了。另一种方法是
uniqueA = details.select('A').distinct().persist(StorageLevel.DISK_ONLY)
uniqueA.count // Breaking the DAG lineage
attrJoined = attributes.join(uniqueA, "inner")
另外,如果你还没有这样做,你可能需要正确设置shuffle分区。
您的数据集中可能发生的一个问题是偏差。它可能发生在75k唯一值中,只有少数与属性表中的大量行连接。在这种情况下,加入可能需要更长的时间,可能无法完成。
要解决此问题,您需要找到A列的偏斜值并单独处理它们。