alitrack

DuckDB 等了三年的 Hudi,一个社区扩展补上了

DuckDB 官方仓库里有一条开了三年多的讨论:能不能读 Hudi 表。

2023 年 9 月有人发帖提问,当时的结论是做不了——Hudi 没有原生 reader,也没有稳定的 API。三年过去,这条帖子在 2026 年 10 月被 Apache Hudi 的 committer 重新翻出来:hudi-rs 已经成熟到可以当 kernel 用了。

现在答案落地:hudi 扩展进了 DuckDB 社区扩展库,INSTALL hudi FROM community 一条命令可用。

● ● ●

先看它做了什么

DuckDB 此前能读湖仓三件套中的两件:Iceberg 有官方 iceberg 扩展,Delta Lake 有官方 delta 扩展。Hudi 一直是缺口,官方没有排期,社区也迟迟没人接。

hudi 扩展补的就是这块。它自己不实现任何 Hudi 逻辑——时间线解析、file slice 发现、schema 推导、COW/MOR 合并,全部交给 Apache 官方维护的 Rust 内核 hudi-rs。扩展只做一件事:把 hudi-rs 的 Arrow 输出通过 Arrow C Data Interface 桥进 DuckDB。

这个架构和官方 delta 扩展用 delta-kernel-rs 的路子完全一致。内核是唯一事实源,扩展层不含时间线或 Parquet 解析逻辑。

● ● ●

实测

以下全部在本机 DuckDB 1.5.6 上跑通,测试数据是 hudi-rs 仓库自带的样例表(v6 版本、非分区)。

读 COW 表:

INSTALL hudi FROM community;
LOAD hudi;
SELECT * FROM read_hudi('/path/to/hudi_table');

读 MOR 表(Merge-on-Read)是 hudi 扩展真正的硬骨头:base file 加 log file 的合并由 hudi-rs 内核完成,实测 4 行全对。

时间旅行,回到某个 commit 之前的快照:

SELECT * FROM read_hudi('/path/to/table',
    as_of => '20250117083125837');

增量读取,只取两个 commit 之间的变更:

SELECT * FROM read_hudi('/path/to/table',
    start => '20250117083125837', "end" => '20250117083136333');

"end" 要加引号,因为它是 SQL 保留字。as_of 和增量窗口互斥,混用会直接报错。

两个标量函数查表元数据:

SELECT hudi_info('/path/to/table');
-- Hudi table: type=MERGE_ON_READ base_format=parquet
-- latest_commit=20250117083136333 commits=2 files=2

SELECT hudi_files('/path/to/table');
-- 每个 file slice 一行:路径、COW/MOR/LOG 类型、大小、log 文件数

实测的行数对得上样例表的预期:COW 全扫 4 行,MOR 全扫 4 行,时间旅行回到第一个 commit 是 3 行,增量窗口(两个 commit 之间)是 2 行。

● ● ●

为什么是现在

这个时间点不是巧合。hudi-rs 0.5.0 在 2026 年 9 月发布,原生支持 COW 和 MOR 两种表类型,暴露 C ABI。三年前讨论里说的「没有稳定 API」的前提变了,集成才成为可能。

DuckDB 侧的收录流程也走完了:PR 经 DuckDB Labs reviewer 审查通过,期间修掉了 Windows 工具链和 protoc 依赖两块硬骨头。目前覆盖 Linux 和 macOS 三个平台,Windows 暂缺——hudi-rs 还没在 Windows 上验证过,等上游验证后再开。

● ● ●

顺带修了一个文档 bug

收录时的示例代码把函数名写错了:官网示例用的是 hudi_scan(),实际注册的函数是 read_hudi(),示例里还有个源码里根本不存在的 incremental = true 参数。照官网示例跑会直接报 binder 错误。修复 PR 已提交,合并后官网示例与真实 API 对齐。

写文章时我把 pinned ref 的源码逐行核过:表函数的参数就是 as_of / start / end / hudi_option 四个 named parameter,没有藏起来的第五个。

● ● ●

适合谁

手上有 Hudi 表、又想在本地快速查询的人。不用起 Spark 集群,不用配 JVM,DuckDB 直接读。时间旅行和增量读这两个能力让「查某个时间点的表」「只拉新增数据」变成了 SQL 里一个 named parameter 的事。

云上的表也能读:S3 路径直接传,凭证走 hudi_option => 'hoodie.s3.access_key_id=…' 透传给内核。

湖仓三件套在 DuckDB 里到齐了:Iceberg 官方、Delta 官方、Hudi 社区。嵌入式分析库读湖仓格式,这条路走通了。

● ● ●

参考来源

https://github.com/duckdb/duckdb/discussions/8925

https://github.com/duckdb/community-extensions/pull/3043

https://github.com/apache/hudi-rs

https://github.com/alitrack/duckdb-hudi