Spark数据集在文件夹中加载带有标题的多个CSV文件,如果所有文件中的标题不相同,则报告不匹配

时间:2017-11-06 04:55:01

标签: hadoop apache-spark apache-spark-sql apache-spark-dataset apache-spark-2.0

我正在尝试使用Spark 2.1.0 API将多个csv文件从hdfs目录加载到spark DataSet中:

val csvData = spark.read.option("header", "true").csv("csvdatatest/")

在" csvdatatest"文件夹有多个csv文件。 Spark仅从第一个文件中选择标头,并将其生成为DataSet的Schema,忽略剩余csv文件的标头。例如

hadoop fs -ls /user/kumara91/csvdatatest
Found 2 items
/user/kumara91/csvdatatest/controlfile-2017-10-19.csv
/user/kumara91/csvdatatest/controlfile-2017-10-23.csv

hadoop fs -cat /user/kumara91/csvdatatest/controlfile-2017-10-19.csv
Delivery ID,BroadLog ID,Channel,Address,Event type,Event date,File name

hadoop fs -cat /user/kumara91/csvdatatest/controlfile-2017-10-23.csv
Delivery ID,BroadLog ID,Channel,Address,Event type,Event date,File name,dummycolumn

scala> val csvData = spark.read.option("header", "true").csv("csvdatatest/")
csvData: org.apache.spark.sql.DataFrame = [Delivery ID: string, BroadLog ID: string ... 5 more fields]

scala> csvData.schema.fieldNames
res1: Array[String] = Array(Delivery ID, BroadLog ID, Channel, Address, Event type, Event date, File name)

这里,它仅从文件" controlfile-2017-10-19.csv"中加载标题。并忽略带有额外列的标题" dummycolumn"在其他csv文件中。

但我的要求是比较文件夹中所有csv文件的标题。 仅当所有CSV文件包含相同标头时才加载文件。报告不匹配的情况和csv文件包含更多或更少或不同的标题

我可以选择使用常规的hdfs文件系统API来执行此操作。然后使用Spark API。或者使用Spark API逐个读取所有csv文件并进行比较的其他选项。

但是,我想知道是否有任何方式使用我可以实现的Spark API,而无需迭代每个文件。此外,为什么要从一个文件中激活读取标头而忽略其余文件。

2 个答案:

答案 0 :(得分:0)

如果不以某种方式迭代文件,就无法正确读取数据。在大数据中,基于文件的数据源是基于目录的,而CSV的假设是目录中的所有文件都具有相同的模式。没有相当于JSON源存在的.read.option("mergeSchema", true)

如果只想检查标题,则需要一次处理一个文件。在获得所有文件的列表后,使用您想要的任何方法,最简单的方法是使用以下方法获取标题:

val paths: Seq[String] = ...
val pathsAndHeaders: Seq[(String, String)] = paths.map { path =>
  val header = sc.textFile(path).take(1).collect.head
  (path, header)
}

更高效的版本,如果您有许多CSV,则要在群集中分发路径,但是您必须自己阅读该文件:

val paths: Seq[String] = ...
val pathsAndHeaders: Seq[(String, String)] = sc.parallelize(paths)
  .map { path =>
    val header = // read first line of file at path
    (path, header)
  }
  .collect

现在你有了路径和标题,做你需要的任何事情。例如,一旦将文件分组到具有相同标题的组中,您就可以将一系列路径传递给load()以在一次操作中读取它们。

答案 1 :(得分:-1)

它会自动合并,并显示最新的架构。 对于数据丢失,列显示为空。 我正在使用sparrk版本2.3.1