Apache Parquet 文件组织结构

简要概述

Apache Parquet 是一个开源列式存储文件格式,最初由 Twitter 与 Cloudera 联合开发,旨在提供高效的压缩与编码方案以支持大规模复杂数据的快速分析与处理。Parquet 文件采用分离式元数据设计 —— 在数据写入完成后,再追加文件级元数据(包括 Schema、Row Group 与 Column Chunk 的偏移信息等),使得写入过程只需一次顺序扫描,同时读取端只需先解析元数据即可随机访问任意列或任意 Row Group。其核心结构包括:

  1. Header(魔数“PAR1”)
  2. 若干 Row Group(行组)
  3. Footer(文件级元数据 + 魔数“PAR1”)

文件格式总体布局

1. Header(文件头)

  • 文件以4字节的魔数 PAR1 开始,标识这是一个 Parquet 文件格式。

2. Row Group(行组)

  • Row Group 是水平切分的数据分片,每个 Row Group 包含表中若干行,通常大小在几十 MB 到几百 MB 之间,以兼顾并行处理与内存使用。
  • 每个 Row Group 内部再按列拆分为若干 Column Chunk,支持对单个列或多个 Row Group 进行跳过式读取。

3. Column Chunk(列区块)

  • Column Chunk 即某一列在某个 Row Group 中的数据块,它是 Parquet 最基本的物理存储单元之一。
  • 每个 Column Chunk 中又分成多个Page,以便更细粒度地管理压缩与解压效率。

4. Page(页)

  • Page 是 Column Chunk 中的最小读写单元,主要有三种类型:
    • Dictionary Page:存放字典编码字典。
    • Data Page:存放实际列数据(可进一步分为 Data Page V1/V2)。
    • Index Page(可选):存放 Page-level 索引,加速定位。
  • 通过 Page 级别的压缩与编码,Parquet 能够对不同类型的数据采用最优策略,极大提升 I/O 性能。

5. Footer(文件尾)

  • 写入完全部 Row Group 后,接着写入File Metadata,其中包含:
    • Schema 定义
    • 每个 Row Group 的偏移及长度
    • 每个 Column Chunk 的偏移、页信息、编码与压缩算法
  • 最后再写入 4 字节魔数 PAR1,完整标识文件结束。

元数据管理

  • Thrift 定义:Parquet 使用 Apache Thrift 描述元数据结构(Schema、Row Group 元信息、Column Chunk 元信息、Page Header 等),以保证跨语言支持。
  • 单次写入:由于元数据紧跟数据之后写入,写入端无需回写或多次扫描,保证单次顺序写入效率。
  • 快速读取:读端先读取文件末尾的 Footer,加载所有元数据后即可随机、并行地读取任意列与任意 Row Group,极大减少磁盘 I/O 与网络传输开销。

编码与压缩技术

字典编码(Dictionary Encoding)

  • 针对低基数(unique values 较少)的列,自动开启字典编码,将原值映射到字典索引,从而显著减少存储量。

混合 RLE + Bit-Packing

  • Parquet 对整数类型实现了混合 RLE(Run-Length Encoding)与Bit-Packing,根据数据分布动态选择最佳方案,例如对于长串相同值使用 RLE,对于小整数值使用 Bit-Packing。

其它压缩算法

  • 支持 Snappy、Gzip、LZO、Brotli、ZSTD、LZ4 等多种压缩格式,可按列灵活选择。

写入过程原理

  1. Schema 序列化:将 DataFrame/表结构映射为 Thrift Schema。
  2. Row Group 切分:按预设行数或大小切分成多个 Row Group。
  3. Column Chunk 生成:对每个列分别收集数据,分 Page 编码与压缩。
  4. 顺序写入:先写 Header → 各 Row Group 的 Column Chunk(含 Page)→ Footer(含全部元数据)→ 终止魔数。

读取过程原理

  1. 读取 Footer:读取文件末尾 8 字节(4 字节元数据长度 + 4 字节魔数),定位并加载全部元数据。
  2. 筛选元数据:根据查询列与过滤条件,决定需要加载的 Column Chunk 与 Page 位置。
  3. 随机/并行读取:直接跳转到各 Column Chunk 的偏移位置,按需加载并解压 Page。
  4. 重建记录:将各列 Page 解码后重组成行,供上层引擎消费。

实践示例:使用 Python 创建并写入 Parquet

下面示例演示如何用 pandas+pyarrow 将一个简单表格写入 Parquet,并简要注释写入过程:

import pandas as pd# 1. 创建 DataFrame
df = pd.DataFrame({"user_id": [1001, 1002, 1003],"event": ["login", "purchase", "logout"],"timestamp": pd.to_datetime(["2025-04-20 10:00:00","2025-04-20 10:05:00","2025-04-20 10:10:00"])
})# 2. 写入 Parquet(默认 row_group_size=64MB,可通过 partition_cols 分区)
df.to_parquet("events.parquet", engine="pyarrow", compression="snappy")
  • pandas 在内部将 DataFrame Schema 转为 Thrift Schema;
  • 按列生成 Column Chunk 并分 Page 编码;
  • 最后输出 Header、Column Chunk、Footer 以及魔数字段。

1. Row Group 的概念与分割原则

  • Row Group 是 Parquet 中最小的水平切分单元,表示若干行的完整切片。一个 Parquet 文件由一个或多个 Row Group 依次组成,每个 Row Group 内部再按列拆分为若干 Column Chunk,支持列式读写与跳过式扫描。
  • 选择合适的 Row Group 大小,是在I/O 效率(大块顺序读更快)和并行度/内存占用(小块更易并行、占用更少)间的权衡。

2. Row Group 的“大小”度量方式

Parquet 对 Row Group 的大小有两种常见度量:

  1. 未压缩字节数(uncompressed bytes)
  2. 行数(number of rows)
  • Parquet-Java(Hadoop/Spark 常用)中,ParquetProperties.DEFAULT_ROW_GROUP_SIZE 默认为 128 MiB(未压缩),并以字节为单位控制切分。
  • PyArrow(Python 生态)中,row_group_size 参数实际上是以行数为单位;若不指定(None),默认值已被调整为 1 Mi 行(绝对最大值仍为 64 Mi 行)。

3. 不同实现中的默认值与推荐配置

实现 / 场景默认值推荐范围说明
Parquet-Java128 MiB(未压缩)512 MiB – 1 GiB(未压缩)与 HDFS 块大小对齐,一般 HDFS 块也应设为 1 GiB,以便一组 Row Group 刚好填满一个块
Spark/HDFSspark.sql.files.maxPartitionBytes 默认 128 MiB同上Spark 会将每个 Row Group 当作一个分区,读写时以此并行
PyArrow1 Mi 行视数据表宽度换算成字节若表宽为 10 列、每列单元假设 4 字节,1 Mi 行 ≈ 40 MiB(未压缩)
其他工具(如 DuckDB/Polars)通常基于“每行最大允许字节数”来推算,默认约 1 Mi 行需参考各自文档如 Polars 中 row_group_size_bytes 默认 122 880 KiB(≈ 120 MiB)

4. Row Group 在文件中的物理结构

一个 Row Group 在文件中的布局可以抽象为:

+--------------------------------------------+
|                Row Group                  |
|  ┌───────────────────────────────────────┐ |
|  │ Column Chunk for Column 0            │ │
|  │  ┌── Page 1 (Dictionary Page?)       │ │
|  │  │   - Page Header                    │ │
|  │  │   - 字典或数据块                    │ │
|  │  └── Page 2 (Data Page v1/v2)         │ │
|  │      - Page Header                    │ │
|  │      - 压缩/编码后的列数据             │ │
|  │  …                                    │ │
|  └───────────────────────────────────────┘ │
|  ┌───────────────────────────────────────┐ │
|  │ Column Chunk for Column 1            │ │
|  │   …                                   │ │
|  └───────────────────────────────────────┘ │
|                    ⋮                       |
|  ┌───────────────────────────────────────┐ │
|  │ Column Chunk for Column N            │ │
|  │   …                                   │ │
|  └───────────────────────────────────────┘ │
+--------------------------------------------+

同时,文件末尾的 Footer 中包含了每个 Row Group 的元数据(Thrift 定义),主要字段有:

  • total_byte_size:该 Row Group 内所有 Column Chunk 未压缩数据总字节数
  • num_rows:该 Row Group 包含的行数
  • columns: list<ColumnChunk>:每个 ColumnChunk 的偏移、长度、编码、压缩算法、Page 统计等

读写时,写端按序将上述 Row Group 数据写入磁盘,待所有 Row Group 完成后再写 Footer 与尾部魔数;读端则先读 Footer,加载元数据后即可随机定位到任意 Row Group 和任意字段的 Column Chunk 进行解压与解码。


5. 举例说明

假设有一个表 10 列,每列单元平均占用 4 字节,我们若以 1 Mi 行为 Row Group(PyArrow 默认值),则:

  • 未压缩 Row Group 大小 ≈ 1 Mi × 10 列 × 4 B ≈ 40 MiB
  • 压缩后:若使用 Snappy,通常可压缩到 1/2 – 1/4,大约 10 MiB – 20 MiB
  • 如果改为 Parquet-Java 默认 128 MiB(未压缩),则 Row Group 行数可按上述公式反算:128 MiB ÷ (10 × 4 B) ≈ 3.3 Mi 行。

小结

  • Row Group 大小既可以用字节也可以用行数度量,具体含义取决于所用写入器与参数;
  • Parquet-Java 默认 128 MiB(未压缩),官方推荐 512 MiB – 1 GiB;
  • PyArrow 默认 1 Mi 行,且新版已调整绝对最大 64 Mi 行;
  • 结构上,Row Group 包含多列的 Column Chunk,每个 Column Chunk 又由若干 Page 组成;
  • 选取合适的 Row Group 大小,可在 顺序 I/O 性能并行度/内存占用 之间取得平衡。
import pandas as pd
import pyarrow as pa
import pyarrow.parquet as pq# 1. 创建示例 DataFrame
df = pd.DataFrame({"user_id": [1001, 1002, 1003, 1004],"event": ["login", "purchase", "logout", "login"],"timestamp": pd.to_datetime(["2025-04-20 10:00:00","2025-04-20 10:05:00","2025-04-20 10:10:00","2025-04-20 10:15:00"])
})# 2. 写入 Parquet(指定 row_group_size 为 2 行,以演示多个 Row Group)
pq.write_table(pa.Table.from_pandas(df), 'events.parquet', row_group_size=2)# 3. 读取 Parquet 元数据并提取 Row Group 信息
pq_file = pq.ParquetFile('events.parquet')
row_groups = []
for i in range(pq_file.num_row_groups):rg = pq_file.metadata.row_group(i)row_groups.append({"row_group_id": i,"num_rows": rg.num_rows,"total_byte_size": rg.total_byte_size})# 4. 展示 Row Group 元数据
rg_df = pd.DataFrame(row_groups)
import ace_tools as tools; tools.display_dataframe_to_user("Row Group Metadata", rg_df)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/77520.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IntelliJ IDEA 2025.1 发布 ,默认 K2 模式 | Android Studio 也将跟进

2025.1 版本已经发布&#xff0c;在此之前我们就聊过该版本的 《Terminal 又发布全新重构版本》&#xff0c;而现在 2025.1 中的 K2 模式也成为了默认选项。 可以预见&#xff0c;这个版本可能会包含不少大坑&#xff0c;为下个 Android Studio 祈祷。 首先有一点可以确定&…

云效部署实现Java项目自动化部署图解

前言 记录下使用云效部署Java项目&#xff0c;实现java项目一键化自动化部署。 云效流程说明&#xff1a; 1.云效拉取最新git代码后 2.进行maven编译打包后&#xff0c;上传到指定服务器目录 3.通过shell脚本&#xff0c;先kill java项目后&#xff0c;通过java -jar 启动项…

国际数据加密算法(IDEA)详解

以下是修正后的准确版本,已解决原文中的术语、符号及技术细节问题: ​国际数据加密算法(IDEA)​ IDEA是一种分组加密算法,由Xuejia Lai(来学嘉)和James Massey于1990年设计。IDEA使用128位密钥对64位明文分组进行加密,经过8轮迭代运算后生成64位密文分组。其安全性基于…

TensorFlow介绍

TensorFlow 是由 Google 开发 的开源机器学习框架&#xff0c;主要用于构建、训练和部署机器学习模型。它支持深度学习、传统机器学习和数值计算&#xff0c;适用于图像识别、自然语言处理&#xff08;NLP&#xff09;、推荐系统、强化学习等多种任务。 核心特性 基于 数据流…

百级Function架构集成DeepSeek实践:Go语言超大规模AI工具系统设计

一、百级Function系统的核心挑战 1.1 代码结构问题 代码膨胀现象&#xff1a;单个文件超过2000行代码路由逻辑复杂&#xff1a;巨型switch-case结构维护困难依赖管理失控&#xff1a;跨Function依赖难以追踪 // 传统实现方式的问题示例 switch functionName { case "fu…

嵌入式芯片中的 SRAM 内容细讲

什么是 RAM&#xff1f; RAM 指的是“随机存取”&#xff0c;意思是存储单元都可以在相同的时间内被读写&#xff0c;和“顺序访问”&#xff08;如磁带&#xff09;相对。 RAM 不等于 DRAM&#xff0c;而是一类统称&#xff0c;包括 SRAM 和 DRAM 两种主要类型。 静态随机存…

标准的JNI (Java Native Interface) 加载函数 JNI_OnLoad

1.JNI_OnLoad 在 Android Native 开发中&#xff0c;JNI_OnLoad 是动态注册本地方法的标准入口点。以下是一个标准实现示例及其说明&#xff1a; JNI_OnLoad 标准实现 #include <jni.h> #include <string>// 声明本地方法对应的 C/C 函数 jint native_add(JNIEnv…

算法导论思考题

2-1 在归并排序中对小数组采用插入排序 c. 假定修改后的算法的最坏情况运行时间为 Θ \Theta Θ(nknlg(n/k))&#xff0c;要使修改后的算法与标准的归并排序具有相同的运行时间&#xff0c;作为n的一个函数&#xff0c;借助 Θ \Theta Θ记号&#xff0c;k的最大值是什么&#…

JavaScript 性能优化

JavaScript 性能优化是提高 Web 应用性能的关键步骤,特别是在处理大量数据、复杂计算或频繁的 DOM 操作时。以下是一些常见的 JavaScript 性能优化技巧和策略: 文章目录 @[TOC]一、代码层面优化1. **减少全局变量**2. **避免使用 `with` 语句**3. **使用局部变量**4. **减少 …

NLP高频面试题(四十七)——探讨Transformer中的注意力机制:MHA、MQA与GQA

MHA、MQA和GQA基本概念与区别 1. 多头注意力(MHA) 多头注意力(Multi-Head Attention,MHA)通过多个独立的注意力头同时处理信息,每个头有各自的键(Key)、查询(Query)和值(Value)。这种机制允许模型并行关注不同的子空间上下文信息,捕捉复杂的交互关系。然而,MHA…

51单片机的原理图和PCB绘制

51单片机最小系统原理图 加了两个led灯和按键检测电路。 PCB中原件摆放位置 成品 资源链接&#xff1a;https://download.csdn.net/download/qq_61556106/90656365

使用注解方式整合ssm时,启动tomcat扫描不到resource下面的xxxmapper.xml

解决org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.xxx.mapper.方法 在Spring与Mybatis整合时&#xff0c;可能会遇到这样的报错 原因&#xff1a; 其原因为mapper路径的映射错误&#xff0c;表示在尝试执行某个 Mapper 接口的方法时…

提示词设计:动态提示词 标准提示词

提示词设计:动态提示词 标准提示词 研究背景:随着人工智能与司法结合的推进以及裁判文书公开数量增多,司法摘要任务愈发重要。传统司法摘要方法生成质量有待提升,大语言模型虽有优势,但处理裁判文书时存在摘要结构信息缺失、与原文不一致等问题。研究方法 DPCM方法:分为大…

Jenkins 多分支管道

如果您正在寻找一个基于拉取请求或分支的自动化 Jenkins 持续集成和交付 (CI/CD) 流水线&#xff0c;本指南将帮助您全面了解如何使用 Jenkins 多分支流水线实现它。 Jenkins 的多分支流水线是设计 CI/CD 工作流的最佳方式之一&#xff0c;因为它完全基于 git&#xff08;源代…

跨境电商管理转型:日事清通过目标管理、流程自动化助力智优美科技项目管理升级与目标落地复盘

1.客户背景介绍 深圳市智优美科技有限公司是一家专业从事外贸B2C的电子商务公司&#xff0c;公司总部位于深圳市宝安区&#xff0c;旗下拥有三家子公司。目前销售的品类有&#xff1a;家居用品、电子产品、电子配件产品等&#xff0c;在深圳外贸电商行业销售额稳居行业前10名。…

基于Docker+k8s集群的web应用部署与监控

项目架构图 server ip master 192.168.140.130 node1 192.168.140.131 node2 192.168.140.132 ansible 192.168.140.166 jumpserver 192.168.100.133 firewall 192.168.1.86 nfs 192.168.140.157 harbor 192.168.140.159 Promethethus 192.168.140.130 Jen…

量子计算与经典计算融合:开启计算新时代

一、引言 随着科技的飞速发展&#xff0c;计算技术正迎来一场前所未有的变革。量子计算作为前沿技术&#xff0c;以其强大的并行计算能力和对复杂问题的高效处理能力&#xff0c;吸引了全球科技界的关注。然而&#xff0c;量子计算并非要完全取代经典计算&#xff0c;而是与经典…

【HarmonyOS 5】makeObserved接口详解

【HarmonyOS 5】makeObserved接口详解 一、makeObserved接口是什么&#xff1f; makeObserved 接口&#xff08;API version 12 起可用&#xff09;用于将非观察数据转为可观察数据&#xff0c;适用于三方包类、Sendable 装饰的类、JSON.parse 返回的对象、collections.Array…

豆瓣图书数据采集与可视化分析(二)- 豆瓣图书数据清洗与处理

文章目录 前言一、查看数据基本信息二、拆分pub列三、日期列处理四、价格列处理五、出版社列处理六、评价人数列处理七、缺失值处理八、重复数据处理九、异常值处理十、完整代码十一、清洗与处理后的数据集展示 前言 豆瓣作为国内知名的文化社区&#xff0c;拥有庞大且丰富的图…

Wasm -WebAssembly简介

WebAssembly 是什么&#xff1f; WebAssembly/wasm WebAssembly 或者 wasm 是一个可移植、体积小、加载快并且兼容 Web 的全新格式 WebAssembly&#xff08;简称 Wasm&#xff09;是一种二进制指令格式&#xff0c;设计用于在现代 Web 浏览器中高效运行程序。它可以被认为是一…