Scala实现Hadoop父目录递归遍历:返回Array[Path]需求求助
优化递归遍历Hadoop目录获取最底层分区路径
首先,咱们先梳理下原代码存在的几个核心问题:
- 返回类型
Array[Object]不符合你预期的Array[Path],类型不严谨且不符合需求 - 递归返回的结果会形成嵌套数组(因为每次递归调用的数组会被直接yield),最终结果结构混乱
- 文件分支错误返回了父路径,而非当前文件路径(而且我们其实不需要收集文件路径)
- 每一步都调用
distinct会额外消耗性能,应该在最后统一去重
针对你的需求(收集最底层分区目录,也就是没有子目录的目录路径),我整理了优化后的代码:
import org.apache.hadoop.fs.{FileStatus, FileSystem, Path} import org.apache.spark.sql.SparkSession // 假设你已经有SparkSession实例,无实例可自行初始化 val spark: SparkSession = SparkSession.builder().getOrCreate() val parentPath = "/hadoop/parent/path" val hdfsPath: Path = new Path(parentPath) def getLeafPartitionPaths(hdfsPath: Path): Array[Path] = { val fs: FileSystem = hdfsPath.getFileSystem(spark.sessionState.newHadoopConf()) val fileStatuses = fs.listStatus(hdfsPath) fileStatuses.flatMap { f => if (f.isDirectory) { // 获取当前目录的所有子项 val children = fs.listStatus(f.getPath) // 判断当前目录是否是叶子目录:子项中没有其他目录 val isLeafDir = children.forall(!_.isDirectory) if (isLeafDir) { // 是叶子分区目录,直接返回该路径 Array(f.getPath) } else { // 不是叶子目录,递归遍历子目录,收集叶子路径 getLeafPartitionPaths(f.getPath) } } else { // 是文件,直接忽略,返回空数组 Array.empty[Path] } }.distinct // 最后统一去重 } // 调用示例 val leafPaths = getLeafPartitionPaths(hdfsPath)
关键修改说明:
- 明确返回类型:将函数返回类型改为
Array[Path],完全匹配你的需求,类型更安全 - 使用flatMap扁平化结果:用
flatMap替代原代码的for...yield,自动把递归返回的数组扁平化,彻底避免嵌套结构 - 精准判断叶子目录:新增逻辑判断当前目录是否为最底层分区——即该目录下没有任何子目录,只有文件(或空目录),这样能准确收集到你需要的日期级分区路径
- 过滤文件路径:遇到文件时直接返回空数组,不会把文件路径混入结果
- 统一去重:把
distinct移到最后,减少不必要的中间计算,提升性能 - 函数命名更语义化:将
recursiveWalk改为getLeafPartitionPaths,更清晰表达函数用途
如果你的分区目录存在空目录(即没有任何子项的目录),上面的代码也会正常收集到,因为children.forall(!_.isDirectory)对于空数组也会返回true(空集合的forall条件恒成立)。
内容的提问来源于stack exchange,提问作者dustin
相关产品推荐
相关产品推荐

