如何在Spark中将数据写为单个(普通)csv文件?

时间:2017-11-01 11:26:35

标签: scala csv apache-spark spark-csv

我正在尝试将数据框保存为本地驱动器中的CSV文件。但是,当我这样做时,我会生成一个文件夹,并在该分区文件中写入。有什么建议可以克服这个问题吗?

我的要求: 获取一个普通的csv文件,其中包含代码中给出的实际名称。

代码段 dataframe.coalesce(1).write.mode("overwrite").format("com.databricks.spark.csv").option("header", "true").csv("E:/dataframe.csv")

3 个答案:

答案 0 :(得分:1)

TL:DR 您正在尝试在分发环境中强制执行顺序的核心内部概念。它不能很好地结束。

Spark不提供像这样的实用程序。为了能够以半分布式方式创建一个,您必须实现多步骤,源依赖协议,其中:

  • 你写标题。
  • 您为每个分区写入数据文件。
  • 您合并文件,并提供新名称。

由于这个应用程序有限,仅适用于较小的文件,并且对于某些来源(如对象存储)而言可能非常昂贵,因此在Spark中实现了这一点。

您当然可以收集数据,使用标准的CSV解析器(Univoicity,Apache Commons),然后将其存储到您选择的存储中。这是顺序的,需要多次数据传输。

答案 1 :(得分:0)

没有自动方法可以做到这一点。我看到两个解决方案

  • 如果本地目录安装在所有执行程序上:按原样写入文件,但随后将part-*csv文件移动/重命名为所需名称
  • 或者如果目录在所有执行者上都不可用:收集 数据帧到驱动程序,然后使用plain scala
  • 创建文件

但这两种解决方案都会破坏并行性,从而破坏火花的目标。

答案 2 :(得分:0)

这是不可能的,但你可以做这样的事情:

dataframe.coalesce(1).write.mode("overwrite").format("com.databricks.spark.csv").option("header", "true").csv("E:/data/")

import org.apache.hadoop.fs._
val fs = FileSystem.get(sc.hadoopConfiguration)
val filePath = "E:/data/"
val fileName = fs.globStatus(new Path(filePath+"part*"))(0).getPath.getName
fs.rename(new Path(filePath+fileName), new Path(filePath+"dataframe.csv"))