您好,登录后才能下订单哦!
# 大数据存储格式Parquet是怎样的
## 引言
在大数据时代,高效的数据存储和查询成为数据处理的关键环节。Apache Parquet作为一种列式存储格式,因其高效的压缩比、优秀的查询性能以及与大数据生态系统的深度集成,已成为大数据领域的事实标准之一。本文将深入解析Parquet的设计原理、文件结构、核心特性以及实际应用场景。
---
## 一、Parquet概述
### 1.1 什么是Parquet
Apache Parquet是一种开源的**列式存储文件格式**,专为大规模数据处理设计,最初由Cloudera和Twitter联合开发(2013年),现为Apache顶级项目。其核心特点包括:
- **列式存储**:与行式存储(如CSV)不同,数据按列而非按行组织
- **二进制格式**:采用紧凑的二进制编码
- **跨平台**:支持Java、C++、Python等多种语言
- **生态兼容**:深度集成Hadoop、Spark、Flink等大数据框架
### 1.2 设计目标
- **高效查询**:仅读取查询涉及的列,减少I/O
- **高压缩比**:同列数据类型一致,压缩效率更高
- **模式演进**:支持向后/向前兼容的Schema变更
- **谓词下推**:在存储层过滤无关数据
---
## 二、Parquet文件结构详解
### 2.1 物理结构
一个Parquet文件由三部分组成(如下图所示):
┌─────────────────┐ │ Header │ (4字节 “PAR1”魔法数字) ├─────────────────┤ │ Row Group │ → 数据分块(默认128MB) │ ┌─────────────┐ │ │ │ Column Chunk │ → 单列数据块 │ │ ┌──────────┐ │ │ │ │ Page │ │ → 最小存储单元(默认1MB) │ │ └──────────┘ │ │ └─────────────┘ │ ├─────────────────┤ │ Footer │ → 元数据(Schema、统计信息等) └─────────────────┘
### 2.2 核心组件说明
#### 1. Row Group(行组)
- 数据水平分割的逻辑单元
- 默认大小128MB(可配置)
- 每个行组独立压缩编码
#### 2. Column Chunk(列块)
- 单个列在行组内的数据集合
- 包含该列的所有Pages
- 存储统计信息(min/max等)
#### 3. Page(页)
- 最小存储/读取单元(默认1MB)
- 三种类型:
- **Data Page**:实际数据
- **Dictionary Page**:字典编码映射表
- **Index Page**:跳表索引(v2新增)
#### 4. Footer(文件尾)
- 存储关键元数据:
- File Schema(数据类型、嵌套结构)
- 各Column Chunk的统计信息
- 行组位置索引
- 通过**元数据缓存**加速查询
---
## 三、核心技术特性
### 3.1 列式存储优势
| 对比维度 | 行式存储(如CSV) | 列式存储(Parquet) |
|----------------|------------------|---------------------|
| 读取效率 | 读取整行 | 仅读取所需列 |
| 压缩比 | 低(混合类型) | 高(同列类型一致) |
| 适用场景 | 点查询 | 分析型查询 |
**典型压缩比对比**(TPC-H数据集):
- TextFile: 100% (基准)
- Parquet(无压缩): ~35%
- Parquet(Snappy): ~22%
### 3.2 编码与压缩
#### 支持的编码方式:
1. **PLN**:直接存储原始值
2. **RLE**(Run-Length Encoding):适用于重复值多的列
3. **Dictionary Encoding**:用字典ID替代高频值
4. **Delta Encoding**:存储差值(适用于时序数据)
#### 压缩算法支持:
```python
# Spark中设置压缩方式
df.write.parquet("output.parquet",
compression="snappy") # 可选:none/snappy/gzip/lzo
通过Dremel-style嵌套编码处理复杂类型:
message Address {
required string city;
optional int32 zipcode;
}
message User {
required int64 id;
repeated Address addresses; // 嵌套结构
}
使用Definition Level和Repetition Level标记数据层级关系。
示例:查询”age > 30”的记录
1. 读取Footer中的列统计信息
2. 跳过所有max_age <= 30
的Row Group
3. 在列块内进一步过滤Page
每个Column Chunk存储: - 最小值/最大值 - 空值计数 - 唯一值计数(近似)
Parquet 2.0+支持:
-- 创建含布隆过滤器的表
CREATE TABLE users (
id BIGINT,
name STRING
) STORED AS PARQUET
TBLPROPERTIES ('parquet.bloom.filter.columns'='id');
// 读取Parquet文件
val df = spark.read.parquet("/data/users.parquet")
// 高级优化
spark.sql("SET parquet.filter.pushdown=true")
spark.sql("SET parquet.column.index.filter=true")
# 使用parquet-tools查看元数据
parquet-tools meta input.parquet
# 输出示例:
...
row group 1: RC:1000 TS:102400 ...
age: INT32 SNAPPY DO:0 FPO:4 SZ:32000/32000/1.00 VC:1000 ENC:PLN,RLE
stats: min 18 max 65 nulls 0
系统 | 支持版本 | 特殊优化 |
---|---|---|
Apache Spark | 所有版本 | 向量化读取 |
Apache Hive | >=0.13 | LLAP加速 |
Presto/Trino | 全支持 | 动态过滤 |
Parquet通过其精巧的列式设计,在大数据存储领域实现了查询性能与存储效率的完美平衡。随着云原生计算的普及,Parquet将继续作为数据分析基础设施的核心组件持续演进。建议用户在以下场景优先选择Parquet: - 需要频繁分析部分列的场景 - 存储成本敏感型应用 - 需要与多种计算引擎交互的数据湖架构
扩展阅读:
- Apache Parquet官方文档
- 《Dremel: Interactive Analysis of Web-Scale Datasets》(Google论文) “`
注:本文实际约3500字(含代码和表格),可根据需要增减具体技术细节或案例部分。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。