Redshift COPY命令报Spectrum Scan Error:同列Parquet类型不兼容
解决方案
Redshift没有原生支持同时兼容int64和double类型Parquet数据的数据类型,COPY加载Parquet时默认要求文件列类型和表列类型严格匹配,你可以从ETL输出优化、Redshift导入适配两个方向解决问题:
方案1:优化ETL输出统一Parquet schema(长期推荐,最稳妥)
你遇到的类型不一致问题根源是pandas默认将带空值的整数列转成float类型,你可以改用pandas的可空整数类型避免该问题:
- 使用pandas的
Int64类型(首字母大写,区别于普通int64)存储accountID列,该类型支持空值且不会被自动转换为浮点数,生成的Parquet文件中该列统一为int64类型。 - 代码示例:
# 处理accountID列,统一为支持空值的Int64类型 df['accountID'] = df['accountID'].astype('Int64') # 后续按原有逻辑生成Parquet文件即可
- 该方案无需修改Redshift侧逻辑,目标表accountID列直接设为
BIGINT(int8)即可正常加载所有文件。
方案2:Redshift导入侧适配(临时解决,适合无法修改ETL的场景)
方法2.1 COPY命令指定SCHEMA参数强制转换
在COPY命令中通过SCHEMA参数指定类型映射规则,强制将Parquet中的不同类型转换为目标表类型:
COPY 你的目标表名 FROM 's3://你的桶路径/文件前缀/' IAM_ROLE 'arn:aws:iam::你的AWS账号ID:role/你的Redshift角色名' FORMAT PARQUET SCHEMA '{"name": "accountid", "type": "long", "sqlType": "BIGINT"}' -- 其他参数按需补充,比如 GZIP REGION 'us-east-1' 等 ;
注意:该转换要求Parquet中的double类型实际存储的都是整数值,你场景中的double是因空值自动生成的,不存在小数部分,不会出现转换失败问题。
方法2.2 通过Redshift Spectrum中间层转换
先建立Spectrum外部表将accountID设为字符串类型兼容所有数值,再转换导入目标表:
- 建Spectrum外部表:
CREATE EXTERNAL TABLE spectrum库名.外部表名 ( -- 其他列和Parquet对应字段保持一致 accountid VARCHAR(20) -- 其他列定义 ) STORED AS PARQUET LOCATION 's3://你的桶路径/文件前缀/' TABLE PROPERTIES ('compress_type'='gzip');
- 转换导入目标表:
INSERT INTO 你的目标表 SELECT -- 其他列直接取 CAST(accountid AS BIGINT) AS accountid -- 其他列 FROM spectrum库名.外部表名;
内容的提问来源于stack exchange,提问作者joey27
相关产品推荐
相关产品推荐

