Databricks读取Parquet强制Schema失败问题求助
问题:Parquet读取时强制Schema转换失败(Long转Int)
场景说明
Parquet源文件中Year列类型为long,目标表中该列定义为int。尝试通过指定目标表Schema来强制转换类型,代码如下:
df = ( spark .read .schema(spark.table(f'{CATALOG_NAME}.{BRONZE_SCHEMA}.{SLA_TARGET}').schema) .parquet(RAW_EXTERNAL_LOCATION_PATH + f"/{SLA_TARGET}/{SLA_TARGET}.parquet") )
报错信息
SchemaColumnConvertNotSupportedException: column: [Year], physicalType: INT64, logicalType: int
疑问
- 不想先读取再转换,为何无法通过指定Schema强制转换?
- 当前环境为Databricks 14.3LTS、Spark 3.5.0,按照Databricks文档,
vectorizedReader设为false仅针对decimal类型,即使设置该参数,仍出现FileReadException读取失败。
解答
原因分析
Spark读取Parquet时,指定Schema的强制类型转换仅支持安全无数据丢失的兼容转换。Long(INT64)转Int(INT32)属于可能丢失精度的转换(比如Long值超过Int最大值2147483647时会溢出),因此Parquet Reader默认禁止这种直接强制转换,避免潜在数据损坏。
解决方案
若确认源数据中Year列所有值都在Int取值范围(-2147483648 至 2147483647)内,可通过以下两种方式实现类型转换,无需先读取全量数据再处理:
方法1:自定义Schema并强制转换
手动复制目标表Schema,将Year列改为IntegerType,结合mergeSchema=false确保严格使用自定义规则:
from pyspark.sql.types import StructType, StructField, IntegerType # 复制目标表Schema并修改Year列类型 target_schema = spark.table(f'{CATALOG_NAME}.{BRONZE_SCHEMA}.{SLA_TARGET}').schema custom_schema = StructType([ StructField("Year", IntegerType(), nullable=field.nullable) if field.name == "Year" else field for field in target_schema.fields ]) df = ( spark .read .option("mergeSchema", "false") .schema(custom_schema) .parquet(RAW_EXTERNAL_LOCATION_PATH + f"/{SLA_TARGET}/{SLA_TARGET}.parquet") )
方法2:用Spark SQL直接转换写入目标表
通过DDL语句直接读取Parquet并转换类型,底层会优化执行流程,避免全量加载后转换:
CREATE TABLE {CATALOG_NAME}.{BRONZE_SCHEMA}.{SLA_TARGET} AS SELECT CAST(Year AS INT) AS Year, -- 其他列直接选择 col1, col2, ... FROM parquet.`{RAW_EXTERNAL_LOCATION_PATH}/{SLA_TARGET}/{SLA_TARGET}.parquet`
关于vectorizedReader的说明
vectorizedReader关闭仅解决Decimal类型的兼容问题,对Long转Int这类数值范围不兼容的场景无效,因此设置后依然报错是正常现象。
内容的提问来源于stack exchange,提问作者Dhruv
相关产品推荐
相关产品推荐

