Java 操作 Parquet 文件
目录
简介
Parquet 是一种列式存储格式,广泛应用于大数据处理,如 Hadoop、Spark、Flink 等。它相比传统的行存储格式(如 CSV、JSON),能够大幅减少存储空间并提高查询性能。Java 作为主流开发语言之一,Apache 提供了相应的 API 来操作 Parquet 文件。
本文将介绍如何在 Java 中读写 Parquet 文件,并探讨其最佳实践。
Parquet 文件格式概述
Parquet 采用列式存储,适用于高效的查询和数据压缩。其主要特点包括:
- 列式存储:数据按列存储,适合分析型查询。
- 高效压缩:支持多种压缩算法,如 Snappy、Gzip 等。
- 支持多种数据类型:包括基本类型(整数、浮点数、布尔值等)以及复杂类型(数组、嵌套结构等)。
- Schema 演进:支持 schema 变更,例如新增列。
Java 读取和写入 Parquet
依赖库
要在 Java 项目中使用 Parquet,需要添加以下 Maven 依赖:
<dependencies>
<!-- Parquet 依赖 -->
<dependency>
<groupId>org.apache.parquet</groupId>
<artifactId>parquet-avro</artifactId>
<version>1.12.3</version>
</dependency>
<!-- Hadoop 依赖 -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-core</artifactId>
<version>3.3.1</version>
</dependency>
</dependencies>
写入 Parquet 文件
使用 parquet-avro
生成 Parquet 文件,通常借助 AvroParquetWriter
。示例如下:
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecord;
import org.apache.parquet.hadoop.ParquetWriter;
import org.apache.parquet.hadoop.metadata.CompressionCodecName;
import org.apache.parquet.avro.AvroParquetWriter;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
public class ParquetWriteExample {
public static void main(String[] args) throws Exception {
// 定义 Avro Schema
String schemaJson = "{"
+ "\"type\": \"record\","
+ "\"name\": \"User\","
+ "\"fields\": ["
+ " {\"name\": \"id\", \"type\": \"int\"},"
+ " {\"name\": \"name\", \"type\": \"string\"}"
+ "]}";
Schema schema = new Schema.Parser().parse(schemaJson);
// 创建 ParquetWriter
Path file = new Path("users.parquet");
try (ParquetWriter<GenericRecord> writer = AvroParquetWriter.<GenericRecord>builder(file)
.withSchema(schema)
.withCompressionCodec(CompressionCodecName.SNAPPY)
.withConf(new Configuration())
.build()) {
// 创建数据
GenericRecord record = new GenericData.Record(schema);
record.put("id", 1);
record.put("name", "Alice");
writer.write(record);
record.put("id", 2);
record.put("name", "Bob");
writer.write(record);
}
System.out.println("Parquet 文件写入完成!");
}
}
读取 Parquet 文件
使用 ParquetReader
读取 Parquet 文件:
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecord;
import org.apache.parquet.avro.AvroParquetReader;
import org.apache.parquet.hadoop.ParquetReader;
import org.apache.hadoop.fs.Path;
public class ParquetReadExample {
public static void main(String[] args) throws Exception {
Path file = new Path("users.parquet");
try (ParquetReader<GenericRecord> reader = AvroParquetReader.<GenericRecord>builder(file).build()) {
GenericRecord record;
while ((record = reader.read()) != null) {
System.out.println(record);
}
}
}
}
常见实践
1. 选择合适的压缩格式
- Snappy:适用于快速压缩和解压缩,适合大多数场景。
- Gzip:压缩率高,但解压速度较慢,适合长时间存储数据。
- LZO:适用于 Hadoop 生态,但需要额外的 native 库支持。
2. 适当的 Schema 设计
- 避免嵌套过深的数据结构,减少读取开销。
- 根据查询需求优化数据类型,例如日期存储为
int
以减少存储占用。
3. 结合 Spark/Flink 进行高效分析
在 Spark 中,可以直接使用:
val df = spark.read.parquet("users.parquet")
df.show()
最佳实践
- 使用 Snappy 压缩:对于大多数查询场景,Snappy 提供良好的性能和存储优化。
- 合理的列存储:尽量减少不必要的列,以提高查询效率。
- 并行写入:如果数据量大,建议使用 Hadoop/Spark 的
parquet-mr
进行并行写入,提高吞吐量。 - Schema 兼容性:设计时考虑向前/向后兼容,避免频繁的 Schema 变更导致解析失败。
小结
本文介绍了 Parquet 文件的基本概念,并详细讲解了如何在 Java 中使用 parquet-avro
进行数据的读写。通过合理选择压缩方式、优化 Schema 以及结合大数据框架使用,可以充分发挥 Parquet 的优势,提高数据分析的效率。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)