Spark 读取分区 - 资源成本分析

Spark read partitions - Resource cost analysis

在 Spark 中读取按列分区的数据时 spark.read.json("/A=1/B=2/C=3/D=4/E=5/") 将允许仅扫描文件夹 E=5 中的文件。

但是假设我有兴趣通过所有数据源读取 C = my_value 中的分区。该指令将是 spark.read.json("/*/*/C=my_value/").

在所描述的情况下,计算会发生什么? Spark 会直接列出 A 和 B 的分区值吗?或者它也会扫描所有叶子(实际文件)?

感谢您提出一个有趣的问题。 Apache Spark 使用 Hadoop 的 FileSystem 抽象来处理通配符模式。在源代码中,它们被称为 glob patterns

org.apache.hadoop.fs.FileSystem#globStatus(org.apache.hadoop.fs.Path)方法用于return"an array of paths that match the path pattern"。然后此函数调用 org.apache.hadoop.fs.Globber#glob 来找出 glob 模式的确切文件匹配算法。 globStatus 由 org.apache.spark.sql.execution.datasources.DataSource#checkAndGlobPathIfNecessary 调用。您可以添加一些断点,看看它是如何工作的 under-the-hood.

但长话短说:

What happens computationally in the described scenario under the hood? Spark will just list through the partition values of A and B? Or it will scan through all the leaves (the actual files) too?

Spark 会将您的 glob 分成 3 部分 ["*"、"*"、"C=my_value"]。稍后,它将使用 Hadoop org.apache.hadoop.fs.FileSystem#listStatus(org.apache.hadoop.fs.Path) 方法在每个级别列出文件。对于每个文件,它将构建一个路径并尝试将其与当前模式相匹配。匹配文件将保留为 "candidates",仅在最后一步算法将查找 "C=my_value" 时过滤掉。

除非你有很多文件,否则这个操作应该不会伤害你。这可能就是为什么您宁愿保留更少但更大的文件的原因之一("too many small files" 的著名数据工程问题)。