使用DuckDB与PyArrow统计NYC出租车数据集行数遇InvalidInputException
问题分析与解决建议
核心原因推测
这个Unsupported cast from string to null using function cast_null错误,本质是分区数据的列类型不一致,导致DuckDB在全局扫描(比如count(*))时无法统一列类型,触发强制转换失败。
具体来说:
- 你按
year和month分区存储数据,部分分区的某个字段(可能是分区列或其他列)的类型与其他分区冲突——比如某几个早期分区里的某列是string类型,而其他分区该列是null或其他类型,DuckDB自动推断schema时尝试将string转为null,触发不支持的转换。 - 当你加
where year > 2008时,过滤掉了存在类型冲突的分区(比如可能有命名错误的2008年分区),所以能正常执行;而count(vendor_id)是统计非空值,DuckDB会跳过类型冲突的列的转换逻辑,所以也能执行,但因为要逐行判断非空,耗时更长。
具体排查与解决步骤
定位异常分区
执行以下查询,找出哪个分区无法正常读取:SELECT year, month, COUNT(*) FROM nyc_dataset GROUP BY year, month ORDER BY year, month;执行时如果报错,就能定位到出问题的
year/month分区,直接检查对应路径下的Parquet文件。强制指定表Schema
手动定义统一的Schema,避免DuckDB自动推断时的类型冲突。比如用PyArrow先定义Schema,再让DuckDB读取:import pyarrow as pa import duckdb # 定义NYC出租车数据集的标准Schema(根据实际列调整) schema = pa.schema([ ('vendor_id', pa.string()), ('pickup_datetime', pa.timestamp('ns')), ('dropoff_datetime', pa.timestamp('ns')), ('passenger_count', pa.int64()), # 其他列按实际情况补充 ('year', pa.int64()), ('month', pa.int64()) ]) # 用指定Schema读取数据 con = duckdb.connect() con.execute(""" CREATE OR REPLACE VIEW nyc_dataset AS SELECT * FROM parquet_scan('C:\\data\\nyc-taxi\\', schema=?) """, [schema])这样强制统一所有分区的列类型,就能避免类型转换错误。
检查并修复损坏文件
对定位到的异常分区,用PyArrow验证文件完整性:import pyarrow.parquet as pq # 替换为异常分区的文件路径 table = pq.read_table('C:\\data\\nyc-taxi\\year=2009\\month=1\\xxx.parquet') print(table.schema)如果文件损坏,替换为正常的数据源;如果是类型不一致,用PyArrow修改该文件的列类型后重新存储。
版本兼容性调整
你当前用的DuckDB 1.1.1和PyArrow 17.0.0可能存在兼容性问题,尝试:- 升级DuckDB到最新稳定版(比如2.0.x)
- 降级PyArrow到16.1.0版本(DuckDB 1.x对PyArrow 16的支持更稳定)
补充说明
count(*)和count(vendor_id)的差异:
count(*)是统计所有行数,DuckDB需要扫描所有列的元数据来确认行数,遇到类型冲突就会报错;count(vendor_id)只统计vendor_id非空的行数,DuckDB会跳过其他列的类型校验,所以能执行,但需要逐行判断非空,因此耗时更长。
内容的提问来源于stack exchange,提问作者sigint
相关产品推荐
相关产品推荐

