我在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
,我根据作业的时间戳在给定路径中有多个输出表base
,A
,B
等。< / p>
我希望基于时间戳和主目录left join
全部foo
,在这种情况下base
。这意味着将每个输出表A
,B
,left 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序列的正确方向吗?甚至可能值得将读取视为惰性或顺序,因此在应用连接时仅读取B
或Animal
表以减少内存需求。
注意:目录结构不是最终的,这意味着如果符合解决方案,它可以更改。
答案 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") }