Spark将多个目录读入多个数据帧

时间:2017-02-06 08:14:05

标签: scala apache-spark amazon-s3 apache-spark-sql orc

我在S3上有一个目录结构,如下所示:

foo
  |-base
     |-2017
        |-01
           |-04
              |-part1.orc, part2.orc ....
  |-A
     |-2017
        |-01
           |-04
              |-part1.orc, part2.orc ....
  |-B
     |-2017
        |-01
           |-04
              |-part1.orc, part2.orc ....

这意味着对于目录foo,我根据作业的时间戳在给定路径中有多个输出表baseAB等。< / p>

我希望基于时间戳和主目录left join全部foo,在这种情况下base。这意味着将每个输出表ABleft join等读入可以应用base的新单独输入表中。全部以val dfs: Seq[DataFrame] = spark.read.orc("foo/*/2017/01/04/*") val base: DataFrame = spark.read.orc("foo/base/2017/01/04/*") val result = dfs.foldLeft(base)((l, r) => l.join(r, 'id, "left")) 表为起点

这样的事情(不工作的代码!)

A

有人能指出我如何获得DataFrames序列的正确方向吗?甚至可能值得将读取视为惰性或顺序,因此在应用连接时仅读取BAnimal表以减少内存需求。

注意:目录结构不是最终的,这意味着如果符合解决方案,它可以更改。

2 个答案:

答案 0 :(得分:1)

据我所知,Spark使用底层的Hadoop API读入数据文件。因此,继承的行为是将您指定的所有内容读取到一个RDD / DataFrame中。

要实现您的目标,您可以先获得目录列表:

    import org.apache.hadoop.conf.Configuration
    import org.apache.hadoop.fs.{ FileSystem, Path }

    val path = "foo/"

    val hadoopConf = new Configuration()
    val fs = FileSystem.get(hadoopConf)
    val paths: Array[String] = fs.listStatus(new Path(path)).
      filter(_.isDirectory).
      map(_.getPath.toString)

然后将它们加载到单独的数据帧中:

    val dfs: Array[DataFrame] = paths.
      map(path => spark.read.orc(path + "/2017/01/04/*"))

答案 1 :(得分:0)

这是一个直截了当的解决方案(我认为)您尝试做的事情,而不使用Hive或内置分区功能等额外功能:

import spark.implicits._

// load base
val baseDF = spark.read.orc("foo/base/2017/01/04").as("base")

// create or use existing Hadoop FileSystem - this should use the actual config and path
val fs = FileSystem.get(new URI("."), new Configuration())

// find all other subfolders under foo/
val otherFolderPaths = fs.listStatus(new Path("foo/"), new PathFilter {
  override def accept(path: Path): Boolean = path.getName != "base"
}).map(_.getPath)

// use foldLeft to join all, using the DF aliases to find the right "id" column
val result = otherFolderPaths.foldLeft(baseDF) { (df, path) =>
  df.join(spark.read.orc(s"$path/2017/01/04").as(path.getName), $"base.id" === $"${path.getName}.id" , "left") }