Scala Azure Databricks将文件写入Azure DataLake Gen 2
我有一个Azure Data Lake gen1和一个Azure Data Lake gen2(Blob存储和分层存储),我正在尝试创建一个DataRicks笔记本(Scala),它可以读取2个文件,并将一个新文件写回Data Lake。在Gen1和Gen2中,我遇到了相同的问题,即我指定的输出csv的文件名被保存为一个目录,并且在该目录中,它正在写入4个文件“提交、启动、成功和部分-00000-tid”- 就我个人而言,我不明白为什么它会这样做,而不是将csv保存到该位置。 下面是我编写的代码示例。如果我在df_join数据帧上执行.show(),它将输出正确的结果。但是.write无法正常工作Scala Azure Databricks将文件写入Azure DataLake Gen 2,scala,azure,azure-data-lake,databricks,azure-databricks,Scala,Azure,Azure Data Lake,Databricks,Azure Databricks,我有一个Azure Data Lake gen1和一个Azure Data Lake gen2(Blob存储和分层存储),我正在尝试创建一个DataRicks笔记本(Scala),它可以读取2个文件,并将一个新文件写回Data Lake。在Gen1和Gen2中,我遇到了相同的问题,即我指定的输出csv的文件名被保存为一个目录,并且在该目录中,它正在写入4个文件“提交、启动、成功和部分-00000-tid”- 就我个人而言,我不明白为什么它会这样做,而不是将csv保存到该位置。 下面是我编写的代
val df_names = spark.read.option("header", "true").csv("/mnt/datalake/raw/names.csv")
val df_addresses = spark.read.option("header", "true").csv("/mnt/datalake/raw/addresses.csv")
val df_join = df_names.join(df_addresses, df_names.col("pk") === df_addresses.col("namepk"))
df_join.write
.format("com.databricks.spark.csv")
.option("header", "true")
.mode("overwrite")
.save("/mnt/datalake/reports/testoutput.csv")
之所以要创建一个包含多个文件的目录,是因为每个分区都是单独保存并写入数据湖的。要保存单个输出文件,需要重新分区数据帧 让我们使用DataFrameAPI
confKey = "fs.azure.account.key.srcAcctName.blob.core.windows.net"
secretKey = "==" #your secret key
spark.conf.set(confKey,secretKey)
blobUrl = 'wasbs://MyContainerName@srcAcctName.blob.core.windows.net'
合并您的数据帧
df_join.coalesce(1)
.write
.format("com.databricks.spark.csv")
.option("header", "true")
.mode("overwrite")
.save("blobUrl" + "/reports/")
更改文件名
files = dbutils.fs.ls(blobUrl + '/reports/')
output_file = [x for x in files if x.name.startswith("part-")]
dbutils.fs.mv(output_file[0].path, "%s/reports/testoutput.csv" % (blobUrl))
之所以要创建一个包含多个文件的目录,是因为每个分区都是单独保存并写入数据湖的。要保存单个输出文件,需要重新分区数据帧 让我们使用DataFrameAPI
confKey = "fs.azure.account.key.srcAcctName.blob.core.windows.net"
secretKey = "==" #your secret key
spark.conf.set(confKey,secretKey)
blobUrl = 'wasbs://MyContainerName@srcAcctName.blob.core.windows.net'
合并您的数据帧
df_join.coalesce(1)
.write
.format("com.databricks.spark.csv")
.option("header", "true")
.mode("overwrite")
.save("blobUrl" + "/reports/")
更改文件名
files = dbutils.fs.ls(blobUrl + '/reports/')
output_file = [x for x in files if x.name.startswith("part-")]
dbutils.fs.mv(output_file[0].path, "%s/reports/testoutput.csv" % (blobUrl))
如果我正确理解您的需求,您只需要将Spark数据帧数据写入一个名为
testoutput.csv
的csv文件到Azure data Lake中,而不是一个名为testoutput.csv
的目录和一些分区文件
因此,您无法通过使用这些Spark函数(如DataFrameWriter.save
)直接实现它,因为实际上DataFrameWriter基于Azure data Lake将数据写入HDFS。HDFS将数据持久化为名为您的目录和一些分区文件。请参阅一些有关HDFS的文档,以了解它
然后,根据我的经验,您可以尝试在Scala程序中使用Azure Data Lake SDK for Jave直接将数据帧作为单个文件写入Azure Data Lake。您可以参考一些示例。如果我正确理解您的需要,您只需将Spark DataFrame数据写入名为
testout的单个csv文件将.csv
放入Azure Data Lake,而不是名为testoutput.csv的目录,其中包含一些分区文件
因此,您无法通过使用这些Spark函数(如DataFrameWriter.save
)直接实现它,因为实际上DataFrameWriter基于Azure data Lake将数据写入HDFS。HDFS将数据持久化为名为您的目录和一些分区文件。请参阅一些有关HDFS的文档,以了解它
然后,根据我的经验,您可以尝试在Scala程序中使用Azure Data Lake SDK for Jave将数据从DataFrame直接写入Azure Data Lake作为单个文件。您可以参考一些示例。谢谢您的评论。这会将一个csv文件保存到Data Lake中,但不会以指定的名称保存。它仍然会忽略s是文件名,只将文件“part-00000-tid…”写入目录名。做了进一步的研究后,我认为不可能用特定的文件名保存到数据湖。这对我来说仍然很奇怪。如果你要走这条路,你应该使用.coalesce(1)
而不是.repartition(1)
减少节点之间的数据移动。重新分区将对所有节点的数据执行完全洗牌,然后再将其减少为单个分区。@DavidP您是100%正确的。我将相应地更改答案。感谢您的评论。这会将一个csv文件保存到数据池中,但不会以指定的名称保存。它仍然忽略重新设置文件名,并仅使用“part-00000-tid…”文件写入目录名。在做了进一步的研究后,我认为不可能使用特定的文件名保存到data lake。这对我来说仍然很奇怪。如果你要走这条路,你应该使用.coalesce(1)
而不是.repartition(1)
减少节点之间的数据移动。重新分区将对所有节点的数据执行完全洗牌,然后再将其减少为单个分区。@DavidP您完全正确。我将相应地更改答案。