You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Pandas和PyArrow读取含超24小时时间值的Parquet文件失败

问题分析与解决方案

1. Parquet.NET是否创建了无效列类型?

是的,这里存在类型映射错误。Parquet中的TIME逻辑类型严格遵循SQL标准,要求时间值必须在00:00:00到23:59:59.999区间内,而你要存储的是超过24小时的时长间隔,并非时刻类型的time。

你在.NET代码中用new DataField<DateTime>("duration")定义列,但DateTime代表的是具体时间点,不是时长。当你把超过24小时的数值存入该字段时,Parquet.NET会将其映射为TIME_MILLIS类型,这直接违反了Parquet TIME类型的规范,最终导致PyArrow读取时触发合法性校验报错。

2. 能否让PyArrow按原始类型而非逻辑类型加载列?

可以,通过PyArrow的低级API绕过逻辑类型解析,直接读取原始INT32值,再手动转换为Python的timedelta或Pandas的timedelta64类型:

实现代码示例

import pyarrow.parquet as pq
import pandas as pd

# 读取Parquet文件
parquet_file = pq.ParquetFile('myfile.parquet')
schema = parquet_file.schema

# 定位duration列的索引
duration_col_idx = schema.get_field_index('duration')

# 读取原始INT32数据
raw_duration = []
for batch in parquet_file.iter_batches():
    raw_col = batch.column(duration_col_idx).to_pandas()
    raw_duration.append(raw_col)
raw_duration = pd.concat(raw_duration)

# 转换为毫秒级timedelta
timedelta_duration = pd.to_timedelta(raw_duration, unit='ms')

# 读取其他列并合并到DataFrame
other_columns = [name for name in schema.names if name != 'duration']
df = parquet_file.read(columns=other_columns).to_pandas()
df['duration'] = timedelta_duration

3. 更优的源头解决方法

直接修正.NET代码中的字段定义,用时间间隔类型替代DateTime存储时长:

Parquet.NET支持TimeSpan类型,对应Parquet的标准间隔类型,或者也可以直接存储为毫秒数(INT64类型),两种方式都能被PyArrow正确识别为timedelta类型:

.NET代码修正示例

// 方式1:使用TimeSpan类型直接映射为Parquet间隔类型
var durationField = new DataField<TimeSpan>("duration");

// 方式2:直接存储毫秒数(INT64),兼容性更强
var durationField = new DataField<long>("duration");

用这种方式导出的Parquet文件,直接执行pd.read_parquet('myfile.parquet', engine="pyarrow")就能自动将duration列识别为timedelta64[ns]类型,无需额外处理。


内容的提问来源于stack exchange,提问作者Wouter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 09:48:13