PyArrow 读写 Parquet 文件时如何只读取部分列并控制写入选项
2026/9/14 11:44:34 网站建设 项目流程

PyArrow 读写 Parquet 文件时如何只读取部分列并控制写入选项

【免费下载链接】arrowApache Arrow is the universal columnar format and multi-language toolbox for fast data interchange and in-memory analytics项目地址: https://gitcode.com/GitHub_Trending/arrow3/arrow

用 PyArrow 处理 Parquet 文件时,一个常见需求是:文件里有几十列,但当前任务只需要其中几列;同时希望写入时能控制格式版本、压缩、数据页大小等选项,而不是完全依赖默认值。本文基于 Apache Arrow 官方文档中的 PyArrow Parquet 章节(docs/source/python/parquet/parquet.rst),演示如何用pq.write_table写文件、用columns参数只读取部分列,并在写入时控制常用选项,最后通过文件元数据核对写入结果。

准备环境

按 Parquet 概览文档 的说明,通过 pip 或 conda 安装的pyarrow默认自带 Parquet 支持,能直接执行下面的验证:

>>> import pyarrow.parquet as pq

如果从源码构建,则必须在编译 C++ 库时使用-DARROW_PARQUET=ON,并在构建 pyarrow 时启用 Parquet 扩展。

下面所有示例沿用文档中的数据,构造一张三列表:

>>> import numpy as np >>> import pandas as pd >>> import pyarrow as pa >>> df = pd.DataFrame({'one': [-1, np.nan, 2.5], ... 'two': ['foo', 'bar', 'baz'], ... 'three': [True, False, True]}, ... index=list('abc')) >>> table = pa.Table.from_pandas(df)

写入文件并只读取部分列

先写一个完整的 Parquet 文件:

>>> import pyarrow.parquet as pq >>> pq.write_table(table, 'example.parquet')

读取时把要保留的列名传给columns参数,即可只解码这些列。文档指出,由于列式布局,读列子集通常比读整个文件快得多:

>>> pq.read_table('example.parquet', columns=['one', 'three']) pyarrow.Table one: double three: bool ---- one: [[-1,null,2.5]] three: [[true,false,true]]

上面的输出是文档示例结果。注意如果源数据来自 pandas 且带 index,用read_table读列子集时会丢掉 index 信息;需要用read_pandas才能保留 index 列:

>>> pq.read_pandas('example.parquet', columns=['two']).to_pandas() two a foo b bar c baz

读文件的位置参数不必是路径字符串,文档说明它可以是:

  • 字符串文件路径;
  • PyArrow 的NativeFile对象;
  • Python file 对象。

性能上,文档的结论是:Python file 对象读性能最差,字符串路径或NativeFile(尤其是内存映射)表现最好。

大文件:用 iter_batches 限制列与 row group

对大文件,ParquetFile.iter_batchesRecordBatch序列流式读取,而不是把整个文件载入一张表。batch_size控制每批最大行数,row_groupscolumns参数可以限定读哪些 row group 和列:

>>> parquet_file = pq.ParquetFile('example.parquet') >>> for batch in parquet_file.iter_batches(batch_size=2): ... print(batch.num_rows) 2 1

输出是文档示例。读取函数默认多线程并行读列,可用use_threads=False关闭;线程数由 Arrow 自动推断,可用pa.cpu_count()查看。

控制写入选项

pq.write_table()提供多个控制写入行为的选项,文档逐项给出了用途:

  • version:Parquet 格式版本。'1.0'保证与旧版本读取端兼容;'2.4'及以上启用更多 Parquet 类型和编码。
  • data_page_size:控制列 chunk 内编码后数据页的大约大小,当前默认 1MB。
  • max_rows_per_page:限制列 chunk 内每个数据页的行数(默认 20000)。较小的值会降低读取时的内存占用,代价是更多页元数据。
  • flavor:设置特定 Parquet 消费方的兼容选项,如flavor='spark'会针对 Apache Spark 自动设置选项并清理 Spark SQL 不支持的字段字符。
  • sorting_columns:以SortingColumn对象序列把各 row group 数据的排序顺序记入元数据。写入器不会真正排序数据,也不校验数据是否有序,读取端可利用该元数据优化查询。

几个常用写入示例(均出自文档):

>>> pq.write_table(table, 'example.parquet', use_dictionary=False) >>> pq.write_table(table, 'example.parquet', compression='snappy') >>> pq.write_table(table, 'example.parquet', compression='gzip')

关于压缩与编码,文档的说明是:

  • use_dictionary控制是否使用字典编码。多数 Parquet 实现写入时使用字典编码,字典过大时回退到 plain 编码。
  • 数据页在编码之后会被压缩,默认使用 Snappy;也支持 Brotli、Gzip、ZSTD、LZ4 和不压缩。'lz4_raw''lz4'的别名,两者都使用 Parquet 规范定义的 LZ4_RAW 编解码器。
  • Snappy 通常性能更好,Gzip 可能得到更小的文件。
  • 压缩和字典编码可以按列设置:
>>> pq.write_table(table, 'example.parquet', compression={'one': 'snappy', 'two': 'gzip'}, ... use_dictionary=['one', 'two'])

写入 pandas 数据时省略 index

pa.Table.from_pandas默认会添加一列或多列特殊列来记录 DataFrame 的 index(行标签)。存储 index 会占额外空间,如果 index 没有保留价值,转换时传preserve_index=False

>>> table = pa.Table.from_pandas(df, preserve_index=False) >>> pq.write_table(table, 'example_noindex.parquet') >>> t = pq.read_table('example_noindex.parquet') >>> t.to_pandas() one two three 0 -1.0 foo True 1 NaN bar False 2 2.5 baz True

文档说明:可以看到 index 没有经过往返保留,读回的 index 是默认的 0、1、2。

验证写入结果:检查文件元数据

写入后可以用元数据核对文件是否符合预期。两种入口:ParquetFile.metadatapq.read_metadata

>>> parquet_file = pq.ParquetFile('example.parquet') >>> metadata = pq.read_metadata('example.parquet') >>> metadata <pyarrow._parquet.FileMetaData object at ...> created_by: parquet-cpp-arrow version ... num_columns: 4 num_rows: 3 num_row_groups: 1 format_version: 2.6 serialized_size: ...

以上为文档示例输出,其中num_columnsnum_rowsnum_row_groups是实际数值,created_byserialized_size等以...省略的部分每次运行会不同。

进一步可以下钻到 row group 和列 chunk 级别查看统计信息与压缩方式:

>>> metadata.row_group(0) <pyarrow._parquet.RowGroupMetaData object at ...> num_columns: 4 num_rows: 3 total_byte_size: 290 sorting_columns: () >>> metadata.row_group(0).column(0) <pyarrow._parquet.ColumnChunkMetaData object at ...> ... physical_type: DOUBLE num_values: 3 path_in_schema: one is_stats_set: True statistics: ... min: -1.0 max: 2.5 null_count: 1 compression: SNAPPY encodings: ('PLAIN', 'RLE', 'RLE_DICTIONARY')

同样是文档示例输出。这里可以看到one列的统计(min/max/null_count)、实际使用的压缩(SNAPPY)和编码,可以用来确认压缩和字典编码选项是否生效;写入 Bloom filter 后也可以在这里确认。

限制与适用边界

文档中几点需要留意的边界:

  • write_page_index会写入 page index,但文档明确 PyArrow 读取端目前还不使用 page index;write_page_checksum需配合读取时的page_checksum_verification=True才能检测数据损坏。
  • sorting_columns只记录排序顺序,不做排序和校验。
  • Parquet 数据需要从磁盘解码解压,无法直接内存映射,因此memory_map=True在某些系统上可能性能更好,但对常驻内存消耗帮助不大。
  • 如果要处理超过内存大小的 Parquet 数据,文档指向 dataset 和分区方案,而不是单个文件的读取接口。

完成上述操作后,你可以用pq.read_metadata输出的num_columnsnum_row_groups和列 chunk 的compressionencodings字段确认列子集读取和写入选项都已按预期落地。

【免费下载链接】arrowApache Arrow is the universal columnar format and multi-language toolbox for fast data interchange and in-memory analytics项目地址: https://gitcode.com/GitHub_Trending/arrow3/arrow

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询