首页 > 解决方案 > Spark编写Parquet数组加载到 BigQuery 时转换为不同的数据类型

问题描述

Spark 数据框架构:

    StructType(
        [StructField("a", StringType(), False),
        StructField("b", StringType(), True),
        StructField("c" , BinaryType(), False),
        StructField("d", ArrayType(StringType(), False), True),
        StructField("e", TimestampType(), True)
        ])

当我将数据框写入 parquet 并将其加载到 BigQuery 时,它会以不同的方式解释架构。这是一个简单的 JSON 加载,并使用 spark 数据框写入 parquet。

BigQuery 架构:

            [
    {
        "type": "STRING",
        "name": "a",
        "mode": "REQUIRED"
    },
    {
        "type": "STRING",
        "name": "b",
        "mode": "NULLABLE"
    },
    {
        "type": "BYTES",
        "name": "c",
        "mode": "REQUIRED"
    },
    {
        "fields": [
        {
            "fields": [
            {
                "type": "STRING",
                "name": "element",
                "mode": "NULLABLE"
            }
            ],
            "type": "RECORD",
            "name": "list",
            "mode": "REPEATED"
        }
        ],
        "type": "RECORD",
        "name": "d",
        "mode": "NULLABLE"
    },
    {
        "type": "TIMESTAMP",
        "name": "e",
        "mode": "NULLABLE"
    }
    ]

这与 Spark 的写入方式或 BigQuery 读取镶木地板的方式有关吗?知道如何解决这个问题吗?

标签: apache-sparkpysparkgoogle-cloud-platformgoogle-bigqueryparquet

解决方案


这是由于spark-bigquery 连接器使用的中间文件格式(默认情况下为 parquet)。

连接器首先将数据写入 parquet 文件,然后使用 BigQuery Insert API 将它们加载到 BigQuery。

如果您使用 来检查中间镶木地板模式parquet-tools,您会发现类似这样的字段d(Spark 中的 ArrayType(StringType))

 optional group a (LIST) {
    repeated group list {
      optional binary element (STRING);
    }
  }

现在,如果您自己在 BigQuery 中使用bq load或直接使用 BigQuery Insert API 加载此镶木地板,您可以通过启用来告诉 BQ 忽略中间字段parquet_enable_list_inference

不幸的是,在使用 spark-bigquery 连接器时,我看不到如何启用此选项!

作为一种解决方法,您可以尝试将其orc用作中间格式。

       df
        .write
        .format("bigquery")
        .option("intermediateFormat", "orc")

推荐阅读