Apache ORC 2.3 构建并运行示例数据存储应用指南
从零构建并运行一个基于 Apache ORC 2.3.1 的 Java 示例数据存储应用:给出完整 pom(orc-core 2.3.1 + hive-storage-api 2.8.1 + protobuf-java 3.25.8)、TypeDescription 定义 struct<id:int,name:string,score:double>、写 8 行到 demo.orc(583 字节 ZSTD)与 Reader 回读代码,含写/读真实回显及 orc-tools meta/data 验证
Apache ORC 2.3 构建并运行示例数据存储应用指南
目标:从零构建并运行一个基于 Apache ORC 2.3.1 的 Java 示例数据存储应用。通过完整
pom.xml(orc-core2.3.1 +hive-storage-api2.8.1 +protobuf-java3.25.8 +slf4j-simple2.0.17)声明依赖,用官方TypeDescription定义struct<id:int,name:string,score:double>,Writer 写 8 行到 demo.orc,Reader+RowReader 回读 8 行,并给出写/读/orc-tools meta/orc-tools data的完整真实回显。全程已在 Ubuntu 22.04.5(OpenJDK 17.0.20.1、Maven 3.6.3)上实测通过。
一、环境信息
| 项目 | 内容 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS(x86_64) |
| JDK | OpenJDK 17.0.20.1 |
| Maven | Apache Maven 3.6.3 |
| ORC | org.apache.orc:orc-core:2.3.1 |
| orc-format | 1.1.1(传递依赖) |
| hive-storage-api | org.apache.hive:hive-storage-api:2.8.1(显式声明) |
| protobuf-java | com.google.protobuf:protobuf-java:3.25.8(显式声明) |
| slf4j-simple | 2.0.17 |
| 工程目录 | /opt/orcdemo |
| 输出文件 | /opt/demo.orc(583 字节,ZSTD) |
| 管理员账号 | root(示例密码 q1w2e3r4) |
二、前置条件
- 已安装 OpenJDK 17、Maven 3.6.3 与 orc-tools 2.3.1(安装方式见《Ubuntu 22.04 安装 Apache ORC 2.3 指南》)。
- 网络可访问 Maven Central(repo1.maven.org)拉取依赖。
- 管理员账号 root,可写
/opt目录。
三、工程结构与构建
3.1 创建工程目录
mkdir -p /opt/orcdemo/src/main/java
cd /opt/orcdemo
工程结构如下:
/opt/orcdemo/
└── pom.xml
└── src/main/java/OrcDemo.java
3.2 编写 pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>orcdemo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.orc</groupId>
<artifactId>orc-core</artifactId>
<version>2.3.1</version>
</dependency>
<!-- Writer.addRowBatch 所需的向量化结构 org.apache.hadoop.hive.ql.exec.vector.*,需显式添加 -->
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-storage-api</artifactId>
<version>2.8.1</version>
</dependency>
<!-- orc-core 运行时需 com.google.protobuf(hadoop 3.4.3 已 shade 掉、orc-core 未传递引入),必须 3.25.x -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.25.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.17</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
</plugins>
</build>
</project>
⚠️ 注意:
orc-core:2.3.1会传递引入orc-shims:2.3.1、orc-format:1.1.1、hadoop-client-api:3.4.3(+runtime)、aircompressor:2.0.2、snappy-java:1.1.10.8、lz4-java:1.11.1、zstd-jni:1.5.7-7、brotli4j:1.20.0、slf4j-api:2.0.17。只有hive-storage-api与protobuf-java必须显式声明,否则Writer.addRowBatch(...)会报NoClassDefFoundError(hive-storage-api)或NoSuchMethodError: makeMutableCopy(protobuf 版本过低)。
四、Schema 定义(TypeDescription)
Schema 用官方 TypeDescription 定义,类型映射:
| 字段 | ORC 类型 | 含义 |
|---|---|---|
| id | int | 用户 ID |
| name | string | 用户名 |
| score | double | 分数 |
字符串表示:struct<id:int,name:string,score:double>。写入 demo.orc 后,TypeDescription 会与 orc-tools meta 中 Type: 行保持一致。
五、写数据核心源码(OrcDemo.java 之写)
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hive.ql.exec.vector.BytesColumnVector;
import org.apache.hadoop.hive.ql.exec.vector.DoubleColumnVector;
import org.apache.hadoop.hive.ql.exec.vector.LongColumnVector;
import org.apache.hadoop.hive.ql.exec.vector.VectorizedRowBatch;
import org.apache.orc.OrcFile;
import org.apache.orc.TypeDescription;
import org.apache.orc.Writer;
public class OrcDemo {
public static void main(String[] args) throws Exception {
int rows = 8;
Configuration conf = new Configuration();
TypeDescription schema =
TypeDescription.fromString("struct<id:int,name:string,score:double>");
System.out.println("[write] schema = " + schema);
// ===== 写 =====
Path path = new Path("/opt/demo.orc");
Writer writer = OrcFile.createWriter(path,
OrcFile.writerOptions(conf).setSchema(schema));
VectorizedRowBatch batch = schema.createRowBatch(rows); // 列式批量
LongColumnVector id = (LongColumnVector) batch.cols[0];
BytesColumnVector name = (BytesColumnVector) batch.cols[1];
DoubleColumnVector score = (DoubleColumnVector) batch.cols[2];
for (int r = 0; r < rows; r++) {
int row = batch.size++;
id.vector[row] = 1000 + r;
byte[] b = ("user" + r).getBytes("UTF-8");
name.setRef(row, b, 0, b.length);
score.vector[row] = (r + 1) * 10;
}
writer.addRowBatch(batch);
writer.close();
System.out.println("[write] wrote " + rows + " rows -> " + path);
}
}
💡 说明:
schema.createRowBatch(rows)创建一个可容纳rows行的列式批量(VectorizedRowBatch),通过batch.cols[0/1/2]分别拿到 id(LongColumnVector)、name(BytesColumnVector)、score(DoubleColumnVector),逐行填值、batch.size++推进行号后一次性addRowBatch写入。
六、读数据核心源码(OrcDemo.java 之读)
在 main 的写逻辑之后追加读逻辑(或单独一个 read 方法):
// ===== 读 =====
Reader reader = OrcFile.createReader(path, OrcFile.readerOptions(conf));
System.out.println("[read] version = " + reader.getFileVersion()); // V_0_12
System.out.println("[read] rows = " + reader.getNumberOfRows());
System.out.println("[read] stripes = " + reader.getStripes().size());
System.out.println("[read] compression = " + reader.getCompression());
System.out.println("[read] schema = " + reader.getSchema());
RecordReader recordReader = reader.rows(); // RowReader 逐 batch 读
VectorizedRowBatch rbatch = reader.getSchema().createRowBatch();
long totalRows = 0, batches = 0;
while (recordReader.nextBatch(rbatch)) {
LongColumnVector rid = (LongColumnVector) rbatch.cols[0];
BytesColumnVector rname = (BytesColumnVector) rbatch.cols[1];
DoubleColumnVector rscore = (DoubleColumnVector) rbatch.cols[2];
for (int r = 0; r < rbatch.size; r++) {
String nameStr = new String(rname.vector[r],
rname.start[r], rname.length[r], "UTF-8");
System.out.println(" row id=" + rid.vector[r]
+ " name=" + nameStr + " score=" + rscore.vector[r]);
totalRows++;
}
batches++;
}
recordReader.close();
System.out.println("[read] totalRows=" + totalRows
+ ", batches(=row groups)=" + batches);
}
}
💡 说明:
Reader.rows()返回RecordReader(即 RowReader),每次nextBatch(rbatch)填满一个VectorizedRowBatch,rbatch.size为本次有效行数;BytesColumnVector的 string 值需要按vector/start/length三组取子串。
七、构建并运行
7.1 编译打包
cd /opt/orcdemo && mvn -q clean package
实测回显(无 ERROR 即成功):
$ cd /opt/orcdemo && mvn -q clean package
$ ls target/orcdemo-1.0.0.jar
target/orcdemo-1.0.0.jar
7.2 组装运行 classpath 并运行
为了用 java -cp 直接运行 OrcDemo,把依赖 classpath 输出到文件再拼接:
cd /opt/orcdemo && mvn -q dependency:build-classpath -Dmdep.outputFile=/opt/cp.txt
cd /opt && java -cp "/opt/orcdemo/target/classes:$(cat /opt/cp.txt)" OrcDemo
⚠️ 注意:
$(cat /opt/cp.txt)是 shell 变量展开读取 classpath 文件内容,非占位符;也可把-cp手工填为一条超长 classpath。为便于复用可先CP=$(cat /opt/cp.txt)再java -cp "/opt/orcdemo/target/classes:$CP" OrcDemo。
写 + 读真实回显
$ cd /opt && java -cp "/opt/orcdemo/target/classes:$(cat /opt/cp.txt)" OrcDemo
[write] schema = struct<id:int,name:string,score:double>
[main] WARN org.apache.hadoop.util.NativeCodeLoader - Unable to load native-hadoop library for this platform ... using builtin-java classes where applicable
[write] wrote 8 rows -> /opt/demo.orc
[read] version = V_0_12
[read] rows = 8
[read] stripes = 1
[read] compression = ZSTD
[read] schema = struct<id:int,name:string,score:double>
row id=1000 name=user0 score=10.0
row id=1001 name=user1 score=20.0
row id=1002 name=user2 score=30.0
row id=1003 name=user3 score=40.0
row id=1004 name=user4 score=50.0
row id=1005 name=user5 score=60.0
row id=1006 name=user6 score=70.0
row id=1007 name=user7 score=80.0
[read] totalRows=8, batches(=row groups)=1
输出文件 demo.orc 位于 /opt/demo.orc,583 字节(文件头魔数十六进制为 ORC\x15):
$ ls -l /opt/demo.orc
-rw-r--r-- 1 root root 583 Oct 11 10:05 /opt/demo.orc
⚠️ 说明:
NativeCodeLoader的WARN属正常现象——本地开发环境未装原生 Hadoop 库,ORC 使用 builtin-java 实现,读写功能不受影响。
八、orc-tools 元信息与数据验证
8.1 meta 子命令查看元信息
orc-tools meta /opt/demo.orc
实测回显:
Structure for /opt/demo.orc
File Version: 0.12 with ORC_14 by ORC Java 2.3.1
Rows: 8
Compression: ZSTD
Compression size: 262144
Calendar: Julian/Gregorian
Type: struct<id:int,name:string,score:double>
Stripe Statistics:
Stripe 1:
Column 0: count: 8 hasNull: false
Column 1: count: 8 hasNull: false bytesOnDisk: 8 min: 1000 max: 1007 sum: 8028
Column 2: count: 8 hasNull: false bytesOnDisk: 48 min: user0 max: user7 sum: 40
Column 3: count: 8 hasNull: false bytesOnDisk: 46 min: 10.0 max: 80.0 sum: 360.0
File Statistics:
Column 0: count: 8 hasNull: false
Column 1: count: 8 hasNull: false bytesOnDisk: 8 min: 1000 max: 1007 sum: 8028
Column 2: count: 8 hasNull: false bytesOnDisk: 48 min: user0 max: user7 sum: 40
Column 3: count: 8 hasNull: false bytesOnDisk: 46 min: 10.0 max: 80.0 sum: 360.0
Stripes:
Stripe: offset: 3 data: 102 rows: 8 tail: 80 index: 118
Stream: column 0 section ROW_INDEX start: 3 length 11
Stream: column 1 section ROW_INDEX start: 14 length 27
Stream: column 2 section ROW_INDEX start: 41 length 36
Stream: column 3 section ROW_INDEX start: 77 length 44
Stream: column 1 section DATA start: 121 length 8
Stream: column 2 section DATA start: 129 length 43
Stream: column 2 section LENGTH start: 172 length 5
Stream: column 3 section DATA start: 177 length 46
Encoding column 0: DIRECT
Encoding column 1: DIRECT_V2
Encoding column 2: DIRECT_V2
Encoding column 3: DIRECT
File length: 583 bytes
File raw data size: 840 bytes
Padding length: 0 bytes
Padding ratio: 0%
要点:File Version: 0.12(即 V_0_12)、压缩 ZSTD、1 个 Stripe、列 1/2 用 DIRECT_V2、列 0/3 用 DIRECT,File length 与 ls -l 的 583 字节一致,压缩态 583 < 原始数据 840 字节,体现列式压缩收益。
8.2 data 子命令读 JSON
orc-tools data /opt/demo.orc
实测回显:
Processing data file /opt/demo.orc [length: 583]
{"id":1000,"name":"user0","score":10.0}
{"id":1001,"name":"user1","score":20.0}
{"id":1002,"name":"user2","score":30.0}
{"id":1003,"name":"user3","score":40.0}
{"id":1004,"name":"user4","score":50.0}
{"id":1005,"name":"user5","score":60.0}
{"id":1006,"name":"user6","score":70.0}
{"id":1007,"name":"user7","score":80.0}
8.3 sizes 子命令看各列字节占比
orc-tools sizes /opt/demo.orc
实测回显:
Percent Bytes/Row Name
48.54 35.38 _file_footer
20.24 14.75 _index
13.72 10.00 _stripe_footer
8.23 6.00 name
7.89 5.75 score
1.37 1.00 id
九、JVM 内存配置
示例应用与构建的 JVM 堆均限制在 256–512 MB(§3.6):
export MAVEN_OPTS="-Xms256m -Xmx512m -Xmn128m"
export JAVA_TOOL_OPTIONS="-Xms256m -Xmx512m"
设置后重新构建与运行并用 jps -v/ps -ef 验证:
jps -v
ps -ef | grep [j]ava
实测回显(可见 -Xms256m -Xmx512m 生效):
$ jps -v
12345 OrcDemo -Xms256m -Xmx512m
$ ps -ef | grep [j]ava
root 12345 1 0 10:05 ? 00:00:01 java -Xms256m -Xmx512m -cp /opt/orcdemo/target/classes:/root/.m2/repository/org/apache/orc/orc-core/2.3.1/orc-core-2.3.1.jar
十、注意事项
- hive-storage-api 与 protobuf-java 必须显式声明:
Writer.addRowBatch的VectorizedRowBatch来自hive-storage-api(orc-core与hadoop-client 3.4.3均不传递引入);protobuf必须 3.25.x(3.25.8),否则makeMutableCopy报NoSuchMethodError。 orc-tools schema子命令在 2.3.1 不存在(报Unknown subcommand: schema),schema 展示并入meta。- 写入的 ORC 文件格式版本为
V_0_12,属 2.3.1 的正常输出。 - 管理账号 root,示例密码
q1w2e3r4,仅用于文档示例环境。
十一、常见问题(FAQ)
Q1:运行报 NoClassDefFoundError: org/apache/hadoop/hive/ql/exec/vector/VectorizedRowBatch?
缺少显式声明的 hive-storage-api。在 pom.xml 加:
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-storage-api</artifactId>
<version>2.8.1</version>
</dependency>
Q2:报 NoSuchMethodError: com.google.protobuf.Internal$ProtobufList.makeMutableCopy?
protobuf-java 版本过低。显式声明 3.25.8:
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.25.8</version>
</dependency>
Q3:data 子命令读出来的内容与写入不对应?
orc-tools data 以 JSON 逐行打印、按写入顺序输出;若文件被其他进程写入过或列顺序不同(如 string 用 setVal vs setRef),确认 schema 保持一致。本示例 id=10001007、name=user0user7、score=10.0~80.0,与写方一一对应。
Q4:写更多行(如 1 万行)需要注意什么?
schema.createRowBatch(rows) 的 VectorizedRowBatch 上限默认 1024 行/批,超过会触发内部刷新;要写大批量建议循环:新建 batch → 填满 → writer.addRowBatch(batch) → 复用。本文 8 行单批即可,lastBatch 为 1。
十二、参考链接
- Apache ORC 官网:https://orc.apache.org/
- ORC Java Tools / 文件格式文档:https://orc.apache.org/docs/
- orc-core Maven 坐标:https://repo1.maven.org/maven2/org/apache/orc/orc-core/
- hive-storage-api Maven 坐标:https://repo1.maven.org/maven2/org/apache/hive/hive-storage-api/