如何用pandas read_parquet高效读取分区Parquet文件并解决日期过滤问题?
解决方案
1. 修正分层分区的过滤逻辑
你的问题出在过滤条件的逻辑组合错误:默认多个条件是AND关系,导致year>=2021且month>8会把2022年1-7月的数据排除。需要用OR逻辑组合不同条件分支,pandas的filters参数支持嵌套列表表示OR关系:
import pandas as pd pd.read_parquet( "s3://my-bucket/", filters=[ # 2022年及以后的所有数据 [("year", ">", 2021)], # 2021年9-12月的数据 [("year", "==", 2021), ("month", ">", 8)], # 若需精确到日(比如2021-08-25之后),可添加此分支 [("year", "==", 2021), ("month", "==", 8), ("day", ">", 31)] ] )
这个逻辑会完整覆盖2021-08-31之后的所有数据,不会遗漏2022年的早期月份。
2. 改用PyArrow Dataset API实现精准分区裁剪
pandas的read_parquet底层依赖PyArrow,直接用PyArrow的Dataset API能更灵活地控制分区过滤,性能也更优:
import pyarrow.dataset as ds import pandas as pd # 定义数据集 dataset = ds.dataset("s3://my-bucket/", format="parquet") # 构建日期范围过滤表达式 filter_expr = ( (ds.field("year") > 2021) | ((ds.field("year") == 2021) & (ds.field("month") > 8)) | ((ds.field("year") == 2021) & (ds.field("month") == 8) & (ds.field("day") > 31)) ) # 读取过滤后的数据并转为DataFrame df = dataset.to_table(filter=filter_expr).to_pandas()
PyArrow会直接在对象存储层面做分区裁剪,只读取符合条件的分区,避免不必要的文件夹列举和文件读取。
3. 优化分区结构平衡数量与灵活性
如果担心单日期分区文件夹过多,同时想简化过滤逻辑,可以采用以下两种优化结构:
- 年-月-周分层:
10年的文件夹数量约为600个(10125),远少于单日期的3650个,过滤时可按周范围筛选,兼顾性能和灵活性。s3://my-bucket/year=2021/month=08/week=35/SOME-HASH-VAL.parquet - 年-月分层+内部日期字段:
将每日数据合并存储在对应月的文件夹下,同时在Parquet文件内部保留dt字段(非分区键):
这种结构仅120个文件夹(10*12),读取时先按年-月裁剪分区,再在文件内部过滤s3://my-bucket/year=2021/month=08/SOME-HASH-VAL.parquetdt>='2021-09-01',大幅减少分区列举开销。
4. 直接通过S3前缀限制读取范围
对于固定日期范围的读取场景,可直接构造符合条件的S3前缀列表,完全跳过无关分区:
pd.read_parquet( [ "s3://my-bucket/year=2021/month=09/", "s3://my-bucket/year=2021/month=10/", "s3://my-bucket/year=2021/month=11/", "s3://my-bucket/year=2021/month=12/", "s3://my-bucket/year=2022/", # ... 后续年份前缀 ] )
这种方式性能最优,但需要手动构造前缀列表,适合范围固定的读取需求。
内容的提问来源于stack exchange,提问作者user3595632
相关产品推荐
相关产品推荐

