跳转至

Apache Parquet 文件格式(File Format)

概述

本文件与 Thrift 定义应结合阅读,以便深入理解 Parquet 文件格式。

文件结构

Parquet 文件的基本结构如下:

    4 字节魔数 "PAR1"
    <列 1 - 块 1>
    <列 2 - 块 1>
    ...
    <列 N - 块 1>
    <列 1 - 块 2>
    <列 2 - 块 2>
    ...
    <列 N - 块 2>
    ...
    <列 1 - 块 M>
    <列 2 - 块 M>
    ...
    <列 N - 块 M>
    文件元数据
    4 字节小端序的元数据长度(字节)
    4 字节魔数 "PAR1"

在上述示例中,表格包含 N 个列,并被拆分为 M 个行组(Row Groups)。
文件元数据(Metadata)记录了所有列块(Column Chunk)的起始位置。
更多关于元数据内容的细节,可以在 Thrift 定义中找到。

元数据与数据分离的设计

  • 写入顺序:文件元数据是在所有数据写入后追加到文件末尾的,以支持单次遍历写入
  • 读取顺序:读取器(Reader)应先读取文件元数据,以确定所需的列块位置,然后按顺序读取这些列块。
  • 优势
  • 这种格式设计使得元数据与数据分离,可以实现:
    • 跨多个文件拆分列存储,提高灵活性。
    • 使用单个元数据文件引用多个 Parquet 文件,适用于分布式存储。

最佳实践

  1. 优化列存储
  2. 由于 Parquet 采用列式存储,在写入时尽可能按列批量处理数据,以减少 I/O 负担。
  3. 例如,在 Spark 或 Pandas 处理中,先对数据按照列进行批量分割再写入 Parquet。

  4. 合理控制行组(Row Group)大小

  5. 小行组(Row Group) 会导致过多的元数据索引,影响查询性能。
  6. 大行组(Row Group) 则可能导致单个读取任务过大,影响并行处理效率。
  7. 建议:

    • 典型的行组大小:128MB - 512MB,根据具体查询场景调整。
  8. 利用字典编码与压缩

  9. Parquet 支持字典编码(Dictionary Encoding)和多种压缩算法(如 Snappy、Gzip、ZSTD)
  10. 建议:

    • 重复值较多的列,启用字典编码。
    • 选择适合的压缩算法,例如:
    • Snappy(默认):解压快,适用于查询密集型任务。
    • Gzip:压缩率高,但解压速度较慢,适合存储优化场景。
  11. 合理选择分区(Partitioning)

  12. Parquet 可以结合 Hive 风格的分区存储(如 /year=2024/month=02/data.parquet)。
  13. 建议

    • 选择查询频繁的字段作为分区键(如 datecategory)。
    • 避免过度分区,过小的分区可能导致过多小文件,影响查询性能。
  14. 使用 Predicate Pushdown(谓词下推)

  15. Parquet 支持谓词下推,即查询引擎会根据元数据过滤不必要的数据块,减少扫描的数据量。
  16. 示例(SQL 方式)sql SELECT * FROM orders WHERE order_date >= '2024-01-01'
  17. 建议:
    • 尽量使用基于列的过滤条件(如 WHERE column = 'value'),让查询引擎更高效地跳过无关数据。