我在 DuckDB 里塞了一个图算法引擎
我在 DuckDB 里塞了一个图算法引擎。
它叫 duckdb_petgraph,1151 行 Rust,17 个图算法直接当 SQL 函数用。PageRank、最短路径、社区发现、中心度分析——不需要 Neo4j,不需要 NetworkX,一个 LOAD 语句全搞定。
先给你看切菜的部分。
LOAD 'petgraph_ext.duckdb_extension';
-- 构建图(字符串格式)
SELECT * FROM petgraph_build_graph('g', '[(0,1,2.5),(1,2,1.0)]', 1);
-- 最短路径
SELECT * FROM petgraph_shortest_path('@g', 0, 2);
-- → [0,1,2] 3.5
-- PageRank
SELECT * FROM petgraph_pagerank('@g', 0.85, 20);
-- 强连通分量
SELECT * FROM petgraph_scc('@g');
-- 社区检测
SELECT * FROM petgraph_louvain('@g');
如果你已经有数据在 DuckDB 表里,推荐用 LIST 类型的接口,不需要字符串拼接:
SET VARIABLE n = (SELECT count(*) FROM edges);
SET VARIABLE src = (SELECT list(src ORDER BY src) FROM edges);
SET VARIABLE dst = (SELECT list(dst ORDER BY src) FROM edges);
SET VARIABLE wgt = (SELECT list(weight ORDER BY src) FROM edges);
SELECT * FROM petgraph_build_graph_list('g', getvariable('n')::INTEGER,
getvariable('src'), getvariable('dst'), getvariable('wgt'), 1);
● ● ●
为什么做这个
我一直在用 DuckDB。做数据分析的时候,图计算的需求经常冒出来——但要为此单独搭一个 Neo4j 或装一个 NetworkX,太重了。
DuckDB 社区已经有 duckpgq,支持 SQL/PGQ 标准的属性图查询,但它偏"图模式匹配"——找路径、找子图——不太做 PageRank、社区检测、中介中心度这类算法。我想有一个直接用 SQL 就能跑的图算法库。PostgreSQL 有 pgvector 做向量检索,DuckDB 也该有自己的图算法扩展。
正好,Rust 的 petgraph 库提供了一套完整的图数据结构和算法。quack-rs 让写 DuckDB 扩展只需要声明式定义参数和输出列。两样东西拼起来,一个最小可用的版本,一个下午就出来了。
● ● ●
现在有什么
另有 build_graph_list、list_graphs、drop_graph 做图管理。图可以缓存(@name),反复用不会重复解析。
架构图
现在版本是 0.5.0,已经通过 PR #2383 合入 DuckDB Community Extensions 主仓库。你现在可以 INSTALL petgraph_ext FROM community; LOAD petgraph_ext; 一步加载,不需要自己编译。
● ● ●
和 duckpgq 的关系
duckpgq 做的是 SQL/PGQ 标准——声明式图模式匹配,像这样:
FROM GRAPH_TABLE (snb MATCH (a:Person)-[k:knows]->(b:Person) COLUMNS (a.id, b.id));duckdb_petgraph 做的是图算法——你把图的边列表喂进去,它返回 PageRank 得分、SCC 编号、最短路径。两者互补:duckpgq 负责"图中的什么和什么有关",duckdb_petgraph 负责"这些东西谁更重要"。
● ● ●
我的诚实评价
这个项目现在是功能完整但工程上有不少要打磨。我自己让三个 AI agent 严格审查了一遍(security + correctness、performance + architecture、code quality),发现了一些不客气的问题:
已知的严重问题:
bench.sql调用的 API 签名和实际代码不匹配——这个文件是在迭代过程中留下的旧版本,需要重写 Louvain 社区发现在测试阶段用的是简化实现,边权重处理需要修正 部分算法(betweenness、closeness)目前对加权图只支持 hop-count,权重支持在计划中
已知的工程改善项:
7 个算法的 SQL 测试还没填充预期输出值——现在只验证"不崩溃" 每次算法调用会重新克隆图数据(应该用 Arc::clone复用),对大规模缓存图的性能有影响1151 行挤在单个 lib.rs里,该拆成模块了全局图注册表是跨连接共享的,需要加命名空间或 TTL
这些是 0.5.0 提交社区时的真实状态。P0 问题在 PR 合入前已经修完(bench.sql 重写、Louvain 权重修正、graph clone 优化),剩下的工程改善项在后续版本逐步完善。开源项目的节奏就是这样——先做到"能用",再做到"好用",最后才是"完美"。
● ● ●
试一试
如果你用的是 DuckDB v1.5.5+:
INSTALL petgraph_ext FROM community;
LOAD petgraph_ext;
SELECT * FROM petgraph_shortest_path('[(0,1,2.5),(1,2,1.0),(0,2,5.0)]', 0, 2);
-- → [0,1,2] 3.5
从源码编译:
git clone --recurse-submodules [email protected]:alitrack/duckdb_petgraph.git
cd duckdb_petgraph
make configure && make release
duckdb -unsigned -c "LOAD 'build/release/extension/petgraph_ext/petgraph_ext.duckdb_extension'; SELECT * FROM petgraph_shortest_path('[(0,1,2.5),(1,2,1.0),(0,2,5.0)]', 0, 2);"
如果你已经在用 DuckDB 做数据管道,下次遇到"这些用户里谁的传播影响力最大"或者"这两个账号之间有什么共同好友链"的时候,试试不在 SQL 外面绕一圈 Python,直接在 DuckDB 里跑。
GitHub: github.com/alitrack/duckdb_petgraph
MIT 协议,随便用。