首页 > 解决方案 > PySpark 使用统计信息写入 Parquet 二进制列 (signed-min-max.enabled)

问题描述

我发现这张 apache-parquet 票https://issues.apache.org/jira/browse/PARQUET-686被标记为parquet-mr1.8.2 已解决。我想要的功能是在(或) 列min/max的镶木地板元数据中计算的。stringBINARY

并引用这是一封电子邮件https://lists.apache.org/thread.html/%3CCANPCBc2UPm+oZFfP9oT8gPKh_v0_BF0jVEuf=Q3d-5=ugxSFbQ@mail.gmail.com%3E 使用scala而不是pyspark作为示例:

     Configuration conf = new Configuration();
        + conf.set("parquet.strings.signed-min-max.enabled", "true");
     Path inputPath = new Path(input);
     FileStatus inputFileStatus =
       inputPath.getFileSystem(conf).getFileStatus(inputPath);
     List<Footer> footers = ParquetFileReader.readFooters(conf, inputFileStatus, false);

我一直无法设置这个值pyspark(也许我把它设置在错误的地方?)


示例数据框

import random
import string
from pyspark.sql.types import StringType    

r = []
for x in range(2000):
    r.append(u''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10)))

df = spark.createDataFrame(r, StringType())

我尝试了几种不同的方法来设置此选项:

df.write.format("parquet").option("parquet.strings.signed-min-max.enabled", "true").save("s3a://test.bucket/option")
df.write.option("parquet.strings.signed-min-max.enabled", "true").parquet("s3a://test.bucket/option")
df.write.option("parquet.strings.signed-min-max.enabled", True).parquet("s3a://test.bucket/option")

但是所有保存的 parquet 文件都缺少 BINARY 列的 ST/STATS。以下是其中一个 parquet 文件的元数据示例输出:

creator:     parquet-mr version 1.8.3 (build aef7230e114214b7cc962a8f3fc5aeed6ce80828)
extra:       org.apache.spark.sql.parquet.row.metadata = {"type":"struct","fields":[{"name":"value","type":"string","nullable":true,"metadata":{}}]}

file schema: spark_schema
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
value:       OPTIONAL BINARY O:UTF8 R:0 D:1

row group 1: RC:33 TS:515
---------------------------------------------------------------------------------------------------

此外,基于此电子邮件链https://mail-archives.apache.org/mod_mbox/spark-user/201410.mbox/%3C9DEF4C39-DFC2-411B-8987-5B9C33842974@videoamp.com%3E和问题:Specify Parquet属性 pyspark

我尝试通过 pyspark 私有 API 潜入配置:

spark.sparkContext._jsc.hadoopConfiguration().setBoolean("parquet.strings.signed-min-max.enabled", True)

所以我仍然无法设置这个conf parquet.strings.signed-min-max.enabledparquet-mr或者它被设置了,但其他地方出了问题)

  1. 是否可以parquet-mr从 pyspark进行配置
  2. pyspark 2.3.x 是否支持 BINARY 列统计信息?
  3. 如何利用 PARQUET-686 功能为min/maxparquet 文件中的字符串列添加元数据?

标签: python-2.7apache-sparkpysparkparquetparquet-mr

解决方案


由于历史上 Parquet 编写者为 UTF-8 字符串编写了错误的最小/最大值,因此新的 Parquet 实现在读取期间会跳过这些统计信息,除非parquet.strings.signed-min-max.enabled已设置。所以这个设置是一个读取选项,它告诉 Parquet 库相信最小/最大值,尽管它们已知有缺陷。唯一可以安全启用此设置的情况是字符串仅包含 ASCII 字符,因为这些字符的相应字节永远不会是负数。

由于您parquet-tools用于转储统计信息并且 parquet-tools它本身使用 Parquet 库,因此默认情况下它将忽略字符串最小/最大统计信息。尽管文件中似乎没有最小值/最大值,但实际上它们在那里,但被忽略了。

这个问题的正确解决方案是PARQUET-1025,它引入了新的统计字段min-valuemax-value. 这些可以正确处理 UTF-8 字符串。


推荐阅读