MoteDB 是什么
纯 Rust 写的嵌入式多模态数据库,面向具身智能(机器人、AR、边缘设备):向量(DiskANN)、全文(BM25+jieba)、时序、空间四类索引 + 列存 + ACID + SQL,单进程嵌入式零依赖,MIT 协议。cargo add motedb / pip install motedb-python / npm install motedb 即用。
- GitHub: https://github.com/motedb/motedb (0.18 全家福: https://github.com/motedb/motedb/releases/tag/v0.18.0 )
- 文档: https://motedb.github.io · 10 分钟可跑的 demo notebook 在仓库
examples/motedb-demo.ipynb
-- 0.18 新语法一览
CREATE CONTINUOUS VIEW sensor_1m AS
SELECT TIME_BUCKET('1m', ts) AS minute, device,
AVG(v) AS v_avg, FIRST(v, ts) AS v_open, LAST(v, ts) AS v_close
FROM sensor GROUP BY minute, device; -- 查询时惰性刷新,当普通表用
ALTER TABLE frames DROP COLUMN legacy; -- 逻辑删除,schema 演进
ALTER TABLE frames RENAME COLUMN v TO voltage;
Rust 侧新增 Database::open_shared_readonly:一个写者 + N 个读者进程同时挂活动目录(flock SH/EX),只读会话零字节落盘(目录字节指纹验收)。
v0.18 的主线:把一笔技术债连本带利还掉
v0.17 五轮猎虫收尾时留下一个实证结论:四轮"同一谓词不同路径不同结果"类缺陷全部同根——SQL 比较语义存在于 11 个互不相识的实现里。0.18 工作流 A 就是还这笔债,做法值得写三段。
1. 先写特征测试,再动实现(PR-1)
新建 semantics.rs 作为唯一语义层:Cmp3 三值 + OrdOp + coerce_pair(Cow 零分配归一:Bool↔数值、方括号向量文本)。动代码之前先写 38 行类型对 × 8 算子的矩阵测试 + 把引擎各路径的 NULL/Kleene 现状用 12 个探针锁定——先证明"现状是什么",再谈"改成什么"。
2. 差分测试是照妖镜(PR-4)
同一份随机谓词,九条执行路径对拍(SELECT / DELETE / UPDATE / JOIN 两种写法 / 子查询 IN / 聚合 / GROUP BY+HAVING)。上线第一天就揪出 7 个预先存在的跨路径分歧,全是 0.17 就在的:
NOT (flag IN (0,1))在某条路径放行全部行——In 分支用了裸==,NULL 成员匹配了 NULL 值;- UPDATE 探针第一版用
a = a + 1000探测,忘了NULL + 1000 = NULL——行原样留下,差分器把它当分歧报出来,测试工具自己的 bug 也被差分抓了; - 最有意思的裁决:
a NOT IN (0, '7')里哈希归一把纯数字文本'7'当微秒时间戳解析(时间戳解析器 first-try 连带),与相等路线分歧。裁决是纯数字文本不再按时间戳归一——推翻了自己 PR-1 里锁定的怪癖。特征测试不是圣旨,差分对拍才是。
3. CI 棘轮:只降不升(PR-5)
src/sql 里裸值比较点从 49 处收编到清单化,门禁脚本数违规、上限写在单独文件里(当前 50),只许降不许升,行内注释可豁免。从此"再往执行器里手写一个 =="过不了 CI。
产品侧补的四个硬伤
- B1 多进程共享只读: 写者持 EX 时读者明确报错; 脏目录(WAL 非空/未干净关闭)拒绝打开——只读者永不修复,修复是写者的职责。零落盘用目录字节级指纹验收。
- B2 Schema 演进:
DROP COLUMN是逻辑删除——列段按位置存列,物理宽度绝不能收窄(dropped 槽位写 NULL 占位),bincode 位置敏感所以目录镜像链 modern→V017→V013 保跨版本兼容。 - B3 向量召回硬化: 先造测量工具(对抗数据 p50/worst 如实基线),发现真病灶是"列段写缓冲新行对索引路径不可见"——补合并层 + 新鲜度护栏(未入图占比超阈值降级暴力扫并后台重建)。诚实声明:对抗簇数据 p50 0.85-1.0 是真实水平,不藏。
- B5 连续视图: 惰性全量重算 v1,语义如实声明。开发日志里最连续的踩坑是:把视图物化结果注册进 CTE map 后,连环揪出三个预存在的 CTE bug——
WITH x AS (...) SELECT COUNT(*) FROM x之类形态此前会硬报 Table not found。新特性的测试强度反过来给老特性抓了虫。
发布工程
全量门禁 4300+ 测试从 ~2.5h 提到 ~30min(独立 release-test profile 关 LTO——300+ 测试二进制的链接时间才是大头); EXPLAIN 改为决策点实录(thread-local trace 重放执行,计划永不与实际漂移); 文档版本单源 + CI 校验(README 曾三处三个版本号); Release 页由 tag 自动生成; 发版前发现 cargo package 会把未跟踪的本地文件收进包——exclude 补 .zcode/ 后 package --list 核验归零。
给同行的三个小教训
- 差分对拍 > 特征测试。特征测试锁现状,差分测试找真相——两者冲突时(纯数字文本时间戳)信差分。
- 新功能是老代码的压力测试。连续视图把 CTE map 用满,三个陈年 bug 当场现形。给新功能写测试时,顺手把相邻老路径也拍一遍。
- 位置敏感的序列化(bincode)加字段 = 全部旧目录损坏。用镜像链在解码边界转换,别在结构体上加带默认值的尾部字段赌运气。
链接
- GitHub: https://github.com/motedb/motedb (good first issue 已挂 10 条,欢迎首贡献)
- Release Notes: https://github.com/motedb/motedb/releases/tag/v0.18.2
- 文档: https://motedb.github.io · 能力清单(每行对应实现与测试): 仓库
CAPABILITIES.md
评论区
写评论还没有评论