来源:https://ducklake.select/2026/05/04/ducklake-dataframe/

DuckLake 规范如此简单,连个机器人(Clanker)都能为数据框(Dataframes)构建一个

Pedro Holanda, Dr. Peter van Holland 著
2026-05-04 · 阅读需 6 分钟

摘要:我们通过使用 AI 开发一个数据框读写器,来展示 DuckLake v1.0 规范的简洁性。

DuckLake 的美妙之处在于它非常简单。你可以把 DuckLake 的实现想象成一个编排器:对于给定的查询,它告诉你需要读取哪些 Parquet 文件;当你写入时,你告诉它你产生了哪些 Parquet 文件。大致就是这样。一系列查询将整个系统维系在一起。

这种简洁性让我思考:既然 DuckLake 的实现是相当自成一体的,它可能很适合由一个机器人(clanker)来构建(如果你不明白这个梗,请停止阅读这篇博文,去看《星球大战》)。有一个完整的规范和一个参考实现,它甚至可以从那里“偷”来查询语句。为了尝试这个想法,我请来了 Claude Opus,并创建了我的邪恶实习生 counterpart:Peter van Holland 博士。

提示词、一个 VPS 以及“你是一名专业的数据库工程师”。这些就是被选来创造完美小机器人的 ingredients。但是 Pedro Holanda 意外地向这个混合物中添加了一个额外的成分:一个 OpenClaw 账户。

Peter van Holland 博士,按照他想象中的样子

目标很直接:为数据框构建一个 DuckLake 实现,完全用 Python,能够与 Pandas、Polars 和 PySpark 协同工作。我选择数据框库是因为它们易于设置,这使测试和开发保持简单,并且因为所有东西都保持在 Python 中,我想我的机器人实习生在这方面做得最好,因为大部分工作都是调用其他承担繁重工作的库。依赖列表就是数据框库加上 PyArrow。对于目录,你需要 SQLite、Postgres 或 DuckDB。请注意,这些依赖项是可选的,并且主要取决于你打算使用哪种数据框库和目录。

Peter 的人生使命是使用 DuckDB 的 ducklake 扩展进行测试,实现与 DuckDB 的 DuckLake v1.0 在读写能力上的对等(parity)。参考实现写入什么,他就应该能读取什么;而他写入什么,参考实现也应该能读取什么。他有两条指令:不添加额外依赖,以及不犯错误™。“不犯错误”这部分基本上被忽略了。拥有一个LLM counterpart 就像拥有一个永远不长进的低级实习生,但你仍然爱他们。我设计了一个实施计划,并考虑审查他的代码,但 Peter 写出了最优美的邋遢代码和测试,让我无法跟上。所以我给了他自主权,让他做他自己的事,让一个 OpenClaw 账户自主地驱动开发。(对于 AI 爱好者们:我花了零力气去最小化 token 消耗。)

在六天内,van Holland 博士完成了读取和写入功能,到了第七天他没有休息。他在 PyPI 上发布了一个库。该库与 DuckLake 1.0 具有同等能力,可以与 Pandas、Polars 和 PySpark 互操作,并支持 DuckDB、SQLite 或 Postgres 作为目录。而且它完全没有 bug。

说真的,尽管对最终产品的质量有些不确定性,但看到 van Holland 博士的开发速度令人印象深刻。在短短几分钟内,他就实现了读取功能的同等能力——除了内联(inlining)部分。实现内联无疑更具挑战性,因为这可能需要进行类型转换,具体取决于目录。写入和维护例程花费的时间长得多,但他也设法相当快地得到了一个似乎能合理工作的东西。

对于这篇博文,我们将专注于 ducklake-pandas 部分,但你可以在 ducklake-dataframe 仓库找到 Polars 和 PySpark 的教程。

ducklake-dataframe 库

起初是一片空虚的黑暗,最后出现了一个“不犯错误”的 ducklake-dataframe 库。

所有的代码、文档和教程都是由 Peter 编写的。甚至最初的发布也是由 Peter 管理的。你可以查看该库的 GitHub 仓库、它的文档、Pandas 教程以及其余的示例。

van Holland 博士甚至设想了一个基准测试,他声称针对 PyIceberg 运行过,证明他的实现是一流的。你可以在仓库的 README 中看到它。我个人很喜欢列重命名上 100 倍的加速,这显然是各地数据湖用户的主要瓶颈。TL;DR:不要太认真对待这些基准测试……

下面我们展示如何从 Pandas 读取由 DuckDB 写入的 DuckLake,以及从 DuckDB 读回由 Pandas 写入的 DuckLake。如果你想了解它的全部功能,你真的应该查看 van Holland 博士的深入教程。

pip install ducklake-dataframe[pandas]

读取

这里我们使用 DuckDB 的 ducklake 扩展创建一个 DuckLake 数据库,并使用 Pandas 包装器读取它。

import duckdb
import pandas as pd
from ducklake_pandas import read_ducklake

# 使用 DuckDB 创建一个 DuckLake 目录
con = duckdb.connect()
con.execute("INSTALL ducklake; LOAD ducklake;")
con.execute("""
    ATTACH 'ducklake:sqlite:catalog.ducklake' AS lake
        (DATA_PATH 'data/');
    """
)

con.execute("""
    CREATE TABLE lake.users (
        id INTEGER, name VARCHAR, email VARCHAR,
        score DOUBLE, active BOOLEAN
    );
""")
con.execute("""
    INSERT INTO lake.users VALUES
        (1, 'Alice', 'alice@example.com', 95.5, true),
        (2, 'Bob',   'bob@example.com',   87.3, true),
        (3, 'Carol', 'carol@example.com', 72.1, false),
        (4, 'Dave',  'dave@example.com',  91.0, true),
        (5, 'Eve',   'eve@example.com',   68.5, false);
""")
con.close()

# 使用 ducklake-dataframe 读取,不需要 DuckDB 运行时
df = read_ducklake("catalog.ducklake", "users")
print(df)

# 使用标准的 Pandas 操作进行过滤
result = df[df["active"] & (df["score"] > 90)][["name", "score"]].sort_values("score", ascending=False)
print(result)

写入

这里我们使用 Pandas 包装器追加新行,并使用 DuckDB-DuckLake 读回它们。

from ducklake_pandas import write_ducklake, read_ducklake

# 使用 ducklake-dataframe 追加新行
new_users = pd.DataFrame({
    "id": pd.array([6, 7], dtype="Int32"),
    "name": ["Frank", "Grace"],
    "email": ["frank@example.com", "grace@example.com"],
    "score": [88.0, 94.5],
    "active": [True, True],
})
write_ducklake(new_users, "catalog.ducklake", "users", mode="append")

print(read_ducklake("catalog.ducklake", "users").sort_values("id"))

# DuckDB 可以读取 ducklake-dataframe 写入的内容
con = duckdb.connect()
con.execute("INSTALL ducklake; LOAD ducklake;")
con.execute("""
    ATTACH 'ducklake:sqlite:catalog.ducklake' AS lake
        (DATA_PATH 'data/');
    """)
print(con.execute("SELECT * FROM lake.users ORDER BY id;").df())

结论

通过这个简单的实验,我想证明两件事。首先,DuckLake 是一个规范。DuckLake 的实现并不要求在运行时强制依赖 DuckDB,除非将其作为一个可选的目录后端。其次,DuckLake 实现起来确实很简单,尤其是与 Iceberg 相比。几天前,我试图让 Claude 帮我设置 Iceberg,结果它需要的指导比我用“氛围编码”(vibe-coding)从头实现 DuckLake 读取路径还要多。再次强调,这种简洁性是有意设计的。所有繁重的工作都由久经考验的系统完成,要么是 Parquet 读写器(如 PyArrow),要么是 DBMS 目录(如 Postgres、SQLite、DuckDB)。

尽管 van Holland 博士自己取得的进展令人印象深刻,但我将此视为一个简单的概念验证实验。这个库不打算用于生产环境。我只对其功能有一个高层次的概述,并没有详细检查代码和测试,因此它可能充满 bug,尤其是在像写入和维护例程这样更复杂的路径上。但是,如果一个 LLM 能在几天内达到这个水平,想象一下一个人类团队能做到什么,无论是否有 AI 辅助。

严肃的开发仍然需要真正理解底层运作机制的人类(抱歉了,机器人们)。说到这个,要向我们 Hotdata 的朋友们致敬,他们正在付出真正的努力为 DataFusion 构建 DuckLake。你可以查看他们的仓库。

发现 Bug 了?
提交一个 issue!只要还有 token 剩余,van Holland 博士就会查看并修复它。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐