如何使Spark会话递归读取所有文件?

时间:2019-12-30 10:01:57

标签: regex scala apache-spark recursion

显示存储JSON文件的目录

$ tree -d try/
try/
├── 10thOct_logs1
├── 11thOct
│   └── logs2
└── Oct
    └── 12th
        └── logs3

任务是使用SparkSession读取所有日志。

是否有一种优雅的方法可以依次读取目录中的所有文件然后递归子目录

我尝试过的几个命令很容易导致意外排除。

spark.read.json("file:///var/foo/try/<exp>")

+----------+---+-----+-------+
| <exp> -> | * | */* | */*/* |
+----------+---+-----+-------+
| logs1    | y | y   | n     |
| logs2    | n | y   | y     |
| logs3    | n | n   | y     |
+----------+---+-----+-------+

您可以在上表中看到,三个表达式都没有一次与所有目录(位于3个不同深度)匹配。坦白地说,使用第三个表达式10thOct_logs1时,我并不期望排除*/*/*

这使我得出结论,将与最后/之后的表达式匹配的任何文件或目录路径都视为完全匹配,其他所有内容都将被忽略。

2 个答案:

答案 0 :(得分:4)

或者,您可以使用Hadoop listFiles递归列出所有文件路径,然后将它们传递给Spark read:

import org.apache.hadoop.fs.{Path}

val conf = sc.hadoopConfiguration

// get all file paths
val fromFolder = new Path("file:///var/foo/try/")
val logfiles = fromFolder.getFileSystem(conf).listFiles(fromFolder, true)
var files = Seq[String]()
while (logfiles.hasNext) {
       // one can filter here some specific files
       files = files :+ logfiles.next().getPath().toString
}

// read multiple paths
val df = spark.read.csv(files: _*)

df.select(input_file_name()).distinct().show(false)


+-------------------------------------+
|input_file_name()                    |
+-------------------------------------+
|file:///var/foo/try/11thOct/log2.csv |
|file:///var/foo/try/10thOct_logs1.csv|
|file:///var/foo/try/Oct/12th/log3.csv|
+-------------------------------------+

答案 1 :(得分:2)

不幸的是,Hadoop球不支持递归球。参见Querying the Filesystem#File Patterns

有一个选项可以列出每个目录级别的多个glob。

  

{a,b}交替匹配表达式a或b

您必须注意不要两次匹配同一文件,否则它将显示为重复文件。

spark.read.json("./try/{*logs*,*/*logs*,*/*/*logs*}")

您还可以加载多个数据框并对其进行合并

val dfs = List(
  spark.read.json("./try/*logs*"),
  spark.read.json("./try/*/*logs*"),
  spark.read.json("./try/*/*/*logs*")
)
val df = dfs.reduce(_ union _)