Spark保存(写入)Parquet文件只有一个文件

30

如果我写

dataFrame.write.format("parquet").mode("append").save("temp.parquet")

在temp.parquet文件夹中,我得到了与行数相同的文件编号。

我觉得我对parquet还不是很理解,这是否正常?

3个回答

28

在进行写入操作之前,请使用coalesce函数。

dataFrame.coalesce(1).write.format("parquet").mode("append").save("temp.parquet")


编辑-1

仔细查看文档后,发现文档确实警告了coalesce

然而,如果你进行了大量的合并操作,例如将numPartitions=1,则可能会导致计算在比你所希望的更少的节点上执行(例如,在numPartitions=1的情况下,在一个节点上执行)

因此,正如@Amar建议的那样, 最好使用repartition


1
我在其他地方读到,coalesce更高效。我们应该相信谁? - thebluephantom
5
尽管coalesce最小化数据移动,但生成的分区不一定(实际上很少)是相同大小,因此这实际上是在少量洗牌开销和(几乎)等大小的分区之间进行权衡。**[1]** 因此,通常情况下,最好使用coalesce,只有在观察到退化时才回退到repartition [2] 但是,在numPartitions=1的特定情况下,文档强调repartition是更好的选择。 - y2k-shubham
我的意思是洗牌,我一直认为这是最重要的方面,但我理解你的观点,而这也是我的观点。有趣。 - thebluephantom
谢谢y2k-shubham和bluephantom,我已经得到了我想要的! - Easyhyum

15

您可以将分区设置为1,以保存为单个文件

dataFrame.repartition(1).write.format("parquet").mode("append").save("temp.parquet")

10
请注意,repartition(1) 应该在 write 之前调用,因为它是 Dataset 的一个方法,而不是 DataFrameWriter 的。 - y2k-shubham

6
尽管之前的回答都是正确的,但你必须了解在重新分区或合并为单个分区后会出现的影响。所有数据都必须传输到单个工作节点,然后立即写入单个文件。
正如互联网上反复提到的那样,在这种情况下,你应该使用“repartition”,尽管执行计划中会添加洗牌步骤。这一步骤有助于利用集群的能力,而不是按顺序合并文件。
至少有一个值得一提的替代方案。你可以编写一个简单的脚本,将所有文件合并为一个文件。这样,你就可以避免向集群的单个节点生成大量网络流量。

谢谢battaio。 现在我正在搜索有关repartition和coalesce的信息!! - Easyhyum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接