使用Polars读取300M Parquet文件触发PanicException问题排查
使用Polars读取Parquet文件时的错误排查问题
问题背景
尝试读取一个约300M的.parquet文件时,Polars抛出如下错误:
df1_path: /home/xxxxxxx/data/xxxxxx/60f70ff096f10d001e523ba9/655bf4495515510b763a8a03/655bf44ad172673b0636cfd3/tables/gnrl_ldgr_655bf7fbd172673b0636cfe1.parquet thread 'polars-0' panicked at crates/polars-arrow/src/compute/cast/utf8_to.rs:79:47: called `Result::unwrap()` on an `Err` value: TryFromIntError(()) note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Traceback (most recent call last): File "/home/xxxxxxx/git/moatengine/src/filter_func_v2.py", line 479, in <module> r.main() File "/home/xxxxxxx/git/moatengine/src/filter_func_v2.py", line 462, in main gl_df = self.large_join(df1_path=ldgr_path, df2_path=acct_path, save_path=ldgr_save_path, word_dict=word_dict) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/xxxxxxx/git/moatengine/src/filter_func_v2.py", line 178, in large_join df1 = pl.read_parquet(df1_path, use_pyarrow=True, columns=clean_cols) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/xxxxxxx/miniconda3/envs/moatengine_2/lib/python3.11/site-packages/polars/_utils/deprecation.py", line 134, in wrapper return function(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/xxxxxxx/miniconda3/envs/moatengine_2/lib/python3.11/site-packages/polars/_utils/deprecation.py", line 134, in wrapper return function(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/xxxxxxx/miniconda3/envs/moatengine_2/lib/python3.11/site-packages/polars/io/parquet/functions.py", line 146, in read_parquet return from_arrow( # type: ignore[return-value] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/xxxxxxx/miniconda3/envs/moatengine_2/lib/python3.11/site-packages/polars/convert.py", line 592, in from_arrow return pl.DataFrame._from_arrow( ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/xxxxxxx/miniconda3/envs/moatengine_2/lib/python3.11/site-packages/polars/dataframe/frame.py", line 581, in _from_arrow arrow_to_pydf( File "/home/xxxxxxx/miniconda3/envs/moatengine_2/lib/python3.11/site-packages/polars/_utils/construction/dataframe.py", line 1076, in arrow_to_pydf pydf = PyDataFrame.from_arrow_record_batches(tbl.to_batches()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pyo3_runtime.PanicException: called `Result::unwrap()` on an `Err` value: TryFromIntError(())
同类的半大小文件可正常读取,且能通过fastparquet获取该文件元数据,因此推测文件存在问题。
疑问
- 该问题是否确实源于文件本身?
- 如何排查这类问题,有哪些推荐的下一步操作或工具?
补充信息
- 未在Polars的Issue中提交问题,因为无法生成最小复现示例,也未找到完全匹配的错误案例。错误发生在Polars内部的
utf8_to.rs第79行,具体含义不明。 - 使用pyarrow可正常读取文件Schema:
获取到的Schema:import pyarrow.parquet as pq tabl= pq.read_table(file_path)rowid: int64 txid: int64 debit: int64 credit: int64 effective_date: date32[day] not null entered_date: date32[day] not null account: string user_id: string transaction: string memo: string total_amt: int64 -- schema metadata -- parquet.avro.schema: '{"type":"record","name":"gnrl_ldgr_655bf7fbd172673b' + 699 writer.model.name: 'avro' - 将Polars读取参数
use_pyarrow设为False时,触发段错误:Mar 19 15:05:18 xxxx kernel: [1108996.070242] polars-8[281558]: segfault at 7fd0d442d5a0 ip 00007fcb20c4ac1f sp 00007fcb111fc240 error 4 in polars.abi3.so[7fcb1fb4e000+366e000] Mar 19 15:05:51 xxxx kernel: [1109028.279971] polars-4[281611]: segfault at 7f3034a2d8a0 ip 00007f2ef0c4ac1f sp 00007f2ee547d240 error 4 in polars.abi3.so[7f2eefb4e000+366e000]
问题解答
1. 问题是否源于文件?
大概率是文件本身存在异常,但也不排除Polars处理特定数据模式时的Bug,理由如下:
- 同类小文件可正常读取,说明代码逻辑和Polars基础功能无问题;
- pyarrow能读取Schema但Polars报错,说明文件元数据合法,但数据内容可能存在不符合Schema定义的异常值(比如数值字段中藏了无法转换的内容、数值超出Polars处理范围);
- 关闭
use_pyarrow触发段错误,说明Polars原生Parquet解析器处理该文件的某些数据块时存在崩溃问题,可能是文件损坏或Polars兼容性问题。
2. 排查步骤与工具推荐
(1)验证文件完整性
- 使用
parquet-tools检查文件:# 安装工具 pip install parquet-tools # 查看文件元数据 parquet-tools inspect <你的文件路径> # 查看前100行数据,检查字段值是否符合Schema parquet-tools head <你的文件路径> --row-count 100 - 用pyarrow读取全量数据并检查数值字段:
import pyarrow.parquet as pq import pyarrow.compute as pc tbl = pq.read_table(<你的文件路径>) # 遍历所有数值字段,转换为字符串检查异常值 for col in ['rowid', 'txid', 'debit', 'credit', 'total_amt']: str_col = pc.cast(tbl[col], pc.string()) print(f"列 {col} 前100个值:") print(str_col.take(range(100)))
(2)定位错误数据块
分块读取文件,找到触发错误的具体数据块:
import pyarrow.parquet as pq import polars as pl with pq.ParquetFile(<你的文件路径>) as pf: for i, batch in enumerate(pf.iter_batches(batch_size=10000)): print(f"处理第{i}个数据块") try: df = pl.from_arrow(batch) except Exception as e: print(f"第{i}个数据块出错:{e}") # 保存出错的块到临时文件,方便后续分析 pq.write_table(batch, f"error_batch_{i}.parquet") break
(3)检查Polars版本兼容性
- 升级到最新稳定版Polars,看是否修复了相关Bug:
pip install --upgrade polars - 尝试用pyarrow读取全量文件后再转换为Polars DataFrame:
import pyarrow.parquet as pq import polars as pl tbl = pq.read_table(<你的文件路径>) df = pl.from_arrow(tbl)
(4)提交Issue(若能定位问题)
如果找到具体异常数据或可生成最小复现文件,可到Polars仓库提交Issue,附上:
- 完整错误日志;
- 异常数据块示例;
- Polars版本、Python版本、操作系统信息。
内容的提问来源于stack exchange,提问作者MikeB2019x
相关产品推荐
相关产品推荐

