我正在尝试使用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,而无需迭代每个文件。此外,为什么要从一个文件中激活读取标头而忽略其余文件。
答案 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