[英]Merge Spark output CSV files with a single header
我想在 AWS 中創建一個數據處理管道,最終將處理后的數據用於機器學習。
我有一個 Scala 腳本,它從 S3 獲取原始數據,處理它並將其寫入 HDFS 甚至 S3 與Spark-CSV 。 如果我想使用AWS 機器學習工具來訓練預測模型,我想可以使用多個文件作為輸入。 但是如果我想使用其他東西,我認為最好是收到一個 CSV 輸出文件。
目前,由於我不想使用repartition(1)或coalesce(1)來達到性能目的,因此我使用了hadoop fs -getmerge進行手動測試,但由於它只是合並了作業輸出文件的內容,因此我遇到了一個小問題。 我需要數據文件中的一行標題來訓練預測模型。
如果我對 spark-csv 使用.option("header","true")
,那么它會將標頭寫入每個輸出文件,合並后,數據中的標頭行數與輸出文件的行數一樣多。 但是如果 header 選項為 false,那么它不會添加任何標題。
現在我找到了一個選項,可以將 Scala 腳本中的文件與 Hadoop API FileUtil.copyMerge
合並。 我用下面的代碼在spark-shell
嘗試了這個。
import org.apache.hadoop.fs.FileUtil
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
val configuration = new Configuration();
val fs = FileSystem.get(configuration);
FileUtil.copyMerge(fs, new Path("smallheaders"), fs, new Path("/home/hadoop/smallheaders2"), false, configuration, "")
但是這個解決方案仍然只是將文件相互連接起來,並不處理標題。 如何獲得只有一行標題的輸出文件?
我什至嘗試添加df.columns.mkString(",")
作為copyMerge
的最后一個參數,但這仍然多次添加標題,而不是一次。
你可以像這樣四處走動。
通過這種方式,除了單個分區的內容具有來自 headerDF 的一行標題名稱之外,所有分區都沒有標題。 當所有分區合並在一起時,文件頂部有一個標題。 示例代碼如下
//dataFrame is the data to save on disk
//cast types of all columns to String
val dataDF = dataFrame.select(dataFrame.columns.map(c => dataFrame.col(c).cast("string")): _*)
//create a new data frame containing only header names
import scala.collection.JavaConverters._
val headerDF = sparkSession.createDataFrame(List(Row.fromSeq(dataDF.columns.toSeq)).asJava, dataDF.schema)
//merge header names with data
headerDF.union(dataDF).write.mode(SaveMode.Overwrite).option("header", "false").csv(outputFolder)
//use hadoop FileUtil to merge all partition csv files into a single file
val fs = FileSystem.get(sparkSession.sparkContext.hadoopConfiguration)
FileUtil.copyMerge(fs, new Path(outputFolder), fs, new Path("/folder/target.csv"), true, spark.sparkContext.hadoopConfiguration, null)
要將文件夾中的文件合並為一個文件:
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.fs._
def merge(srcPath: String, dstPath: String): Unit = {
val hadoopConfig = new Configuration()
val hdfs = FileSystem.get(hadoopConfig)
FileUtil.copyMerge(hdfs, new Path(srcPath), hdfs, new Path(dstPath), false, hadoopConfig, null)
}
如果要將所有文件合並為一個文件,但仍位於同一文件夾中(但這會將所有數據帶到驅動程序節點):
dataFrame
.coalesce(1)
.write
.format("com.databricks.spark.csv")
.option("header", "true")
.save(out)
另一種解決方案是使用解決方案#2,然后將文件夾內的一個文件移動到另一個路徑(使用我們的 CSV 文件的名稱)。
def df2csv(df: DataFrame, fileName: String, sep: String = ",", header: Boolean = false): Unit = {
val tmpDir = "tmpDir"
df.repartition(1)
.write
.format("com.databricks.spark.csv")
.option("header", header.toString)
.option("delimiter", sep)
.save(tmpDir)
val dir = new File(tmpDir)
val tmpCsvFile = tmpDir + File.separatorChar + "part-00000"
(new File(tmpCsvFile)).renameTo(new File(fileName))
dir.listFiles.foreach( f => f.delete )
dir.delete
}
嘗試指定標題的架構並使用 spark-csv 格式錯誤的選項 drop 從文件夾中讀取所有文件。 這應該讓您讀取文件夾中的所有文件,只保留標題(因為您刪除了格式錯誤)。 示例:
val headerSchema = List(
StructField("example1", StringType, true),
StructField("example2", StringType, true),
StructField("example3", StringType, true)
)
val header_DF =sqlCtx.read
.option("delimiter", ",")
.option("header", "false")
.option("mode","DROPMALFORMED")
.option("inferSchema","false")
.schema(StructType(headerSchema))
.format("com.databricks.spark.csv")
.load("folder containg the files")
在 header_DF 中,您將只有標題的行,由此您可以按照需要的方式轉換數據幀。
我們遇到了類似的問題,按照以下方法獲取單個輸出文件-
coalesce
或repartition
(在轉換之后)的 hdfs。dataframe.write.format("csv").option("header", "true").save(hdfs_path_for_multiple_files)
coalesce(1)
寫回 hdfs 上的不同位置。dataframe = spark.read.option('header', 'true').csv(hdfs_path_for_multiple_files)
dataframe.coalesce(1).write.format('csv').option('header', 'true').save(hdfs_path_for_single_file)
這樣,您將避免在執行轉換(步驟 1)時與合並或重新分區相關的性能問題。 第二步提供帶有一個標題行的單個輸出文件。
// Convert JavaRDD to CSV and save as text file
outputDataframe.write()
.format("com.databricks.spark.csv")
// Header => true, will enable to have header in each file
.option("header", "true")
請按照有關如何編寫單個標頭的集成測試的鏈接進行操作
http://bytepadding.com/big-data/spark/write-a-csv-text-file-from-spark/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.