Spark会在读取时保持镶木地板分区吗?

时间:2018-06-12 21:06:36

标签: scala apache-spark partitioning parquet

我在找到这个问题的答案时遇到了很多麻烦。让我们说我写了一个数据框到镶木地板,我使用repartition结合partitionBy得到一个很好的分区镶木地板文件。见下文:

df.repartition(col("DATE")).write.partitionBy("DATE").parquet("/path/to/parquet/file")

现在稍后,我想阅读镶木地板文件,所以我做了类似的事情:

val df = spark.read.parquet("/path/to/parquet/file")

数据框是否按"DATE"分区?换句话说,如果镶木地板文件被分区,火花在将其读入火花数据帧时会保持分区。还是随机分区?

此答案的原因和原因也是有帮助的。

3 个答案:

答案 0 :(得分:4)

读取作为拼花形式存储的数据时获取的分区数量遵循许多与读取分区文本相同的规则:

  1. 如果SparkContext.minPartitions> =分区在数据中计数,则将返回SparkContext.minPartitions。
  2. 如果分区中的数据大于等于SparkContext.parallelism,则将返回SparkContext.parallelism,尽管在某些分区很小的情况下,#3可能是正确的。
  3. 最后,如果数据中的分区数介于SparkContext.minPartitions和SparkContext.parallelism之间,那么通常您会看到分区反映在数据集分区中。

请注意,分区的实木复合地板文件很少具有分区的完整数据局部性,这意味着即使数据中的分区计数与读取的分区计数匹配,如果您要实现分区数据局部性以提高性能,则应在内存中对数据集重新分区。

鉴于上面的用例,如果您打算在此基础上利用本地分区操作,建议立即在“ DATE”列上重新分区。上面有关minPartitions和并行性设置的注意事项也适用于此。

val df = spark.read.parquet("/path/to/parquet/file")
df.repartition(col("DATE"))

答案 1 :(得分:0)

您将根据默认为 128MB 的 spark 配置 spark.sql.files.maxPartitionBytes 获得分区数。并且不会按照写入时使用的分区列对数据进行分区。

参考https://spark.apache.org/docs/latest/sql-performance-tuning.html

答案 2 :(得分:0)

在您的问题中,有两种方式可以说数据被“分区”,它们是:

  1. 通过 repartition,它使用哈希分区器将数据分布到特定数量的分区中。如果像您的问题一样,您没有指定数字,则使用 spark.sql.shuffle.partitions 中的值,该值具有默认值 200。调用 .repartition 通常会触发 shuffle,这意味着分区现在分布在您的执行程序池中。

  2. 通过 partitionBy,这是一种特定于 DataFrameWriter 的方法,它告诉它根据关键。这意味着写入的数据被拆分到根据您的分区列命名的子目录中,例如/path/to/parquet/file/DATE=<individual DATE value>。在此示例中,只有具有特定 DATE 值的行存储在每个 DATE= 子目录中

鉴于术语“分区”的这两种用法,在回答您的问题时有一些微妙的方面。由于您使用了 partitionBy 并询问 Spark 是否“维护分区”,我怀疑您真正好奇的是 Spark 是否会进行分区修剪,这是一种用于显着改善分区的技术对分区列具有过滤器的查询的性能。如果 Spark 知道您查找的值不能位于特定子目录中,它就不会浪费任何时间读取这些文件,因此您的查询完成得更快。

  1. 如果您读取数据的方式不知道分​​区,您将获得许多分区,类似于 bsplosion 的答案中的内容。 Spark 不会使用分区修剪,因此您不会从 Spark 自动忽略读取某些文件以加快速度1中受益。

  2. 幸运的是,在 Spark 中读取使用 parquet 写入的 partitionBy 文件是一种分区感知读取。即使没有像 Hive 这样的 Metastore 告诉 Spark 文件在磁​​盘上分区,Spark 也会自动发现分区。请参阅 partition discovery in Spark 以了解其在 parquet 中的工作原理。

我建议在 spark-shell 中测试读取您的数据集,以便您可以轻松查看 .explain 的输出,这将让您验证 Spark 是否正确找到了分区并可以修剪掉那些没有的分区t 包含您的查询中感兴趣的数据。关于此 can be found here 的一篇不错的文章。简而言之,如果您看到 PartitionFilters: [],则表示 Spark 没有进行任何分区修剪。但是,如果您看到类似 PartitionFilters: [isnotnull(date#3), (date#3 = 2021-01-01)], 的内容,Spark 仅读取一组特定的 DATE 分区,因此查询执行速度通常要快得多。

1一个单独的细节是 parquet 将有关数据的统计信息存储在文件本身的列中。如果这些统计数据可用于消除与您正在执行的任何过滤不匹配的数据块,例如在 DATE 上,即使您读取数据的方式不是分区感知的,您也会看到一些加速。这称为谓词下推。之所以有效,是因为在使用 DATE 时,磁盘上的文件仍将仅包含特定的 .partitionBy 值。 More info can be found here.