Snowflake没有扣除Parquet中按列分区

gop*_*chi 5 parquet snowflake-cloud-data-platform

我对 Snowflake 的新功能 - Infer Schema 表功能有疑问。INFER SCHEMA 函数在 parquet 文件上表现出色,并返回正确的数据类型。但是,当 parquet 文件被分区并存储在 S3 中时,INFER SCHEMA 无法像 pyspark 数据帧那样发挥作用。

在DataFrames中,分区文件夹名称和值作为最后一列读取;有没有办法在 Snowflake Infer 模式中达到相同的结果?

例子:

在此输入图像描述

@GregPavlik - 输入采用结构化镶木地板格式。当 parquet 文件存储在没有分区的 S3 中时,可以完美导出架构。

示例:{ "AGMT_GID": 1714844883, "AGMT_TRANS_GID": 640481290, "DT_RECEIVED": "20 302", "LATEST_TRANSACTION_CODE": "I" }

Snowflake 推断模式为我提供了 4 个列名称及其数据类型。

但是,如果镶木地板文件存储在分区中 - 如上图所示。

在 - LATEST_TRANSACTION_CODE =I/ 文件夹下,我会将文件作为

示例:{“AGMT_GID”:1714844883,“AGMT_TRANS_GID”:640481290,“DT_RECEIVED”:“20 302”}

在这种情况下,雪花推断模式仅提供三列;但是,读取 Pyspark 数据框中的同一文件会打印所有四列。

我想知道 Snowflake 中是否有解决方法来读取分区的镶木地板文件。

Sai*_*ish 5

在处理分区镶木地板文件时遇到了雪花的这个问题。这个问题不仅仅发生在infer_schema中,以下流程不会将按列分区推导为雪花中的列:

  • 从镶木地板复制到表中
  • 从镶木地板合并到表中
  • 从镶木地板中选择
  • 来自镶木地板的 INFER_SCHEMA

Snowflake 将 parquet 文件视为文件,并忽略文件夹名称中的元信息。Apache Spark 智能扣除分区列。

以下是处理方法,直到 Snowflake 团队处理为止。

方法一

使用Snowflake 元数据功能来处理此问题。

截至目前,Snowflake 元数据仅提供

  • METADATA$FILENAME - 当前行所属的暂存数据文件的名称。包括阶段中数据文件的路径。
  • METADATA$FILE_ROW_NUMBER - 每条记录的行号

我们可以这样做:

    select $1:normal_column_1, ..., METADATA$FILENAME  
        FROM
            '@stage_name/path/to/data/' (pattern => '.*.parquet')
    limit 5;
Run Code Online (Sandbox Code Playgroud)

这将给出一个包含分区文件完整路径的列。但我们需要处理从中推导出列。例如:它会给出类似的内容:

METADATA$FILENAME 
----------
path/to/data/year=2021/part-00020-6379b638-3f7e-461e-a77b-cfbcad6fc858.c000.snappy.parquet
Run Code Online (Sandbox Code Playgroud)

我们可以执行 regexp_replace 并将分区值作为列获取,如下所示:

METADATA$FILENAME 
----------
path/to/data/year=2021/part-00020-6379b638-3f7e-461e-a77b-cfbcad6fc858.c000.snappy.parquet
Run Code Online (Sandbox Code Playgroud)
  • 在上面的正则表达式中,我们给出了分区键。
  • 第三个参数\\1是正则表达式组匹配号。在我们的例子中,第一组比赛 - 这保存了分区值。

方法2

如果我们可以控制写入源镶木地板文件的流程。

  • 添加与按列内容分区具有相同内容的重复列
  • 这应该在写入 parquet 之前发生。因此 parquet 文件将具有此列内容。
    select 
        regexp_replace(METADATA$FILENAME, '.*\/year=(.*)\/.*', '\\1'
        ) as year
        $1:normal_column_1,  
    FROM
            '@stage_name/path/to/data/' (pattern => '.*.parquet')
    limit 5;
Run Code Online (Sandbox Code Playgroud)
  • 使用这种方法,如果我们执行此操作一次,在镶木地板的所有使用(复制、合并、选择、INFER)中,新列将开始出现。

方法3

如果我们无法控制写入源镶木地板文件的流程。

  • 这种方法更加特定于领域和数据模型。
  • 在许多用例中,我们需要对按列分区与数据的关系进行逆向工程。
  • 可以从其他列生成吗?比方说,如果数据按年份分区,其中年份是从created_by列派生的数据,那么可以再次重新生成该派生数据。
  • 可以通过连接另一个雪花表来生成吗?假设 parquet 有一个 id,可以与另一个表连接以动态地在我们的列中派生

方法 3 更针对问题/领域。我们还需要在 parquet 的所有用例(复制、合并、选择等)中处理这个问题。