You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

关键修改说明:

  1. 明确返回类型:将函数返回类型改为Array[Path],完全匹配你的需求,类型更安全
  2. 使用flatMap扁平化结果:用flatMap替代原代码的for...yield,自动把递归返回的数组扁平化,彻底避免嵌套结构
  3. 精准判断叶子目录:新增逻辑判断当前目录是否为最底层分区——即该目录下没有任何子目录,只有文件(或空目录),这样能准确收集到你需要的日期级分区路径
  4. 过滤文件路径:遇到文件时直接返回空数组,不会把文件路径混入结果
  5. 统一去重:把distinct移到最后,减少不必要的中间计算,提升性能
  6. 函数命名更语义化:将recursiveWalk改为getLeafPartitionPaths,更清晰表达函数用途

如果你的分区目录存在空目录(即没有任何子项的目录),上面的代码也会正常收集到,因为children.forall(!_.isDirectory)对于空数组也会返回true(空集合的forall条件恒成立)。

内容的提问来源于stack exchange,提问作者dustin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 22:07:34