YAOTU INSIGHTS

x-cmd ondb Python 库:加载 TSV 日志并查询实体关系图的完整实践

x-cmd ondb Python 库:加载 TSV 日志并查询实体关系图的完整实践
CLI开发工具AI Agent人工智能包管理器【免费下载链接】x-cmdPosix Shell 工具库项目地址https://gitcode.com/x-cmd/x-cmd点击查看免费下载ondb 是 x-cmd 中以「追加写 TSV 日志」为存储协议的知识图谱工具支持用 AWK、Python、JS、SQLite 等多种语言直接读取同一份日志。本文以 mod/ondb/lib/py/README.md 为骨架讲清 ondb Python 库的完整用法从加载 TSV 日志、实体查询、关系遍历到 schema 校验与自定义图查询并结合 ondb_core.py 的源码逐方法解释每个 API 的解析逻辑与边界行为以及它与x ondbCLI 后端的集成方式。ondb Python 库的定位ondb 的核心设计是「TSV 日志即协议」所有变更都以add、set、rm、link、unlink五种指令逐行追加到ondb.tsv任何语言只要能按行解析 TSV就可以成为查询引擎见 SKILL.md。仓库为 ondb 内置了多套后端环境推荐后端原因默认无特殊依赖AWK零依赖2000 实体时最快有 PythonPython速度/功能平衡最好数据结构丰富有 Node.js/BunJS (Bun)现代 JS启动快已存在ondb.dbSQLite直接 SQL索引查询Python 库适合200010000 量级实体的场景这也是 README 给出的选型建议它用dict/list/set这类原生数据结构承载实体与关系方便嵌入 Python 生态的复杂逻辑与 AI 管线同时避免 AWK 回放在大日志上变慢。从源码结构看整个库只有两个核心文件ontology.py入口文件将ondb_core所在目录加入sys.path后导出Ondb类__all__ [Ondb]ondb_core.py解析 TSV 并提供全部查询方法。TSV 日志格式load() 的输入理解 Python 库之前先明确它读的是什么。ondb 的日志每行是一条以制表符分隔的指令#开头为注释空行忽略add Person pers_001 1716816000000 name Alice email aliceexample.com add Project proj_001 1716816000001 name Website Redesign status active add Task task_001 1716816000002 title Fix bug status open priority high link proj_001 has_task task_001 1716816000003 link pers_001 assigned_to task_001 1716816000004 set task_001 1716816000005 status done rm task_002 1716816000006 unlink proj_001 has_task task_002 1716816000007指令字段含义addtype, id, epoch_ms, key val 对…创建带属性的实体setid, epoch_ms, key val 对…更新实体属性rmid, epoch_ms删除实体linkfrom, rel, to, epoch_ms, key val 对…创建关系unlinkfrom, rel, to, epoch_ms删除关系ondb_core.py 中的load()L11-L27逐行rstrip后按cols[0]分发到五个内部方法_do_add/_do_set/_do_rm/_do_link/_do_unlink时间戳字段统一int()转为毫秒级 epoch 整数。属性部分由_parse_props()L29-L36按下标两两一组(k, v)解析成字典尾部落单的 key 会被丢弃。Quick Start加载、列表、获取与关系遍历README 给出的完整快速上手示例如下from ontology import Ondb ondb Ondb() with open(ondb.tsv) as f: ondb.load(f) # List all Task entities for eid, etype, name in ondb.ls(Task): print(eid, name) # Get entity entity ondb.get(t1) print(entity[type], entity[props]) # Get related entities for rel in ondb.related(t1, depends_on, outgoing): print(rel[relation], rel[entity][id], rel[entity][props]) # Validate for err in ondb.validate(): print(ERROR:, err)注意import的来源ontology模块位于x ondb libpath py指向的目录即仓库中mod/ondb/lib/py。libpath 子命令的源码确认了py|python参数会输出$___X_CMD_ROOT_MOD/ondb/lib/py因此实际使用时需要先把该目录加入sys.pathSKILL.md 中的标准写法LIBPATH$(x ondb libpath py) python3 -c import sys; sys.path.insert(0, $LIBPATH) from ontology import Ondb ondb Ondb() with open(ondb.tsv) as f: ondb.load(f) print(ondb.ls(Task)) 下面逐方法对照源码讲清楚每个 API 的真实行为。load(lines)纯追加语义下的幂等重放load()接收任意文件迭代器open()返回的文件对象即可不需要预先读入内存。它在__init__中初始化四份内部状态L5-L9self.entities {} # id - {type, ctime, mtime, alive, props, order} self.links [] # [{from, rel, to, epoch, props}] self._entity_order [] # 保持实体插入顺序 self._link_map {} # (from, rel, to) - link用于去重各指令的内部处理带有明确的幂等与容错语义_do_addL38-L46若 id 已存在直接返回重复add不会覆盖已有实体新实体的ctime与mtime均取该行的 epoch并按首次出现顺序记入_entity_order这保证了ls()的输出顺序与日志写入顺序一致。_do_setL48-L60实体不存在或已被rmaliveFalse时静默忽略属性值为空串表示删除该属性e[props].pop(k, None)否则覆盖写入并刷新mtime。这与 example.sh 中第 13 节的测试相互印证x ondb set --id t2 -- priority之后get结果中priority不再出现而statusopen仍在。_do_rmL62-L65只把alive置为False不物理删除。日志是 append-only 的重放时rm之后的行可能仍引用该实体软删除标记让后续set/查询都能正确处理。_do_linkL67-L74以(from, rel, to)三元组为键去重重复link直接跳过——对应 example.sh 中「重复 link 应被静默跳过」的断言。_do_unlinkL76-L80从_link_map弹出并把from置Nonelinks列表保留占位后续所有遍历都会跳过from is None的记录。这套「重放即状态」的语义意味着无论日志经过多少次compact快照 增量日志只要把快照与增量行按序喂给load()得到的内存状态完全一致。ls(etypeNone)按类型列出存活实体def ls(self, etypeNone): out [] for eid in self._entity_order: e self.entities[eid] if not e[alive]: continue if etype and e[type] ! etype: continue out.append((eid, e[type], e[props].get(name, ))) return out源码见 L82-L91。要点返回[(eid, type, name), ...]其中 name 取自props[name]缺失时为空串只返回存活实体aliveTrue已rm的实体不会出现在结果中迭代顺序是日志中的首次出现顺序基于_entity_order而非字典哈希顺序etype传None或空串时列出全部类型。query(etype)是ls(etype)的别名L125-L126。get(id)取单个实体的完整快照def get(self, eid): e self.entities.get(eid) if not e or not e[alive]: return None return { id: eid, type: e[type], ctime: e[ctime], mtime: e[mtime], props: dict(e[props]) }源码见 L115-L123。返回值为None表示 id 不存在或已被删除返回的props是副本dict(e[props])外部修改不会影响内部状态。ctime/mtime是毫秒级 epoch 整数分别来自add行和最后一次set行的时间戳。linked(id, rel, direction) 与 related(id, rel, direction)两者都基于links列表线性遍历direction取值为outgoing默认from eid、incomingto eid或bothlinked / relatedlinked返回[(rel, target, type, props), ...]即「关系元数据 对端实体 id 对端类型 关系自身属性」。注意它不过滤已删除的对端实体——对端不存在或已rm时 type 返回空串这保留了「悬空链接」的信息供校验使用。related返回[{relation, direction, entity: {id, type, props}}, ...]携带对端实体的完整属性但会跳过已删除/不存在的对端L147-L148适合直接做业务展示。关系属性props来自link行尾部的 key val 对例如 SKILL.md 中的x ondb link --from ev1 --rel attended_by --to p2 -- rolefacilitator产生的链接会带有{role: facilitator}。validate()悬空链接检测def validate(self): Basic validation: check dangling links. errors [] for link in self.links: if link[from] is None: continue if link[from] not in self.entities or not self.entities[link[from]][alive]: errors.append(fdangling_from: link from{link[from]} rel{link[rel]} to{link[to]}) if link[to] not in self.entities or not self.entities[link[to]][alive]: errors.append(fdangling_to: link from{link[from]} rel{link[rel]} to{link[to]}) return errors源码见 L160-L170。Python 库内置的validate()是图完整性检查返回错误字符串列表区分dangling_from源实体缺失或已删除与dangling_to目标实体缺失或已删除空列表表示图谱一致。需要区分的是CLI 的x ondb validate在提供schema.tsv时还会额外校验必填属性、禁写属性、枚举值、关系端点类型、基数与无环约束——这些 schema 级校验 Python 库本身不包含需自行实现见下节示例。Schema 检查示例必填属性与枚举值README 的第二个示例演示了如何用 Python 实现 schema 级检查mod/ondb/lib/py/README.mdfrom ontology import Ondb ondb Ondb() with open(ondb.tsv) as f: ondb.load(f) # Check required properties for eid, e in ondb.entities.items(): if not e[alive]: continue if e[type] Task: if title not in e[props]: print(f{eid}: missing required property title) if status in e[props] and e[props][status] not in (open, done): print(f{eid}: invalid status) # Check dangling links for err in ondb.validate(): print(ERROR:, err)这里的模式是直接遍历内部字典ondb.entitiesid → 实体记录手动跳过aliveFalse的记录然后按自己定义的 schema 规则如 Task 必须有title、status只能取open/done逐条检查。ondb 的 schema 指令本身是扁平 TSVtype/req/enum/rel/rcard/racyclic等写在schema.tsv中由 CLI 的 validate 消费在 Python 侧把约束表达为普通if判断即可这正是 README 选择 Python 做「AI 集成/复杂逻辑」的原因——检查规则可以完全动态化。自定义图查询组合 related() 做多跳推理README 的第三个示例展示了库的核心价值——用几行 Python 表达内置命令覆盖不了的图逻辑。示例本身是「找出被 open 任务阻塞的任务」这里再结合 SKILL.md 中两个可直接复制的实战查询# 示例 1README所有 blocks 出边指向谁 for eid, e in ondb.entities.items(): if e[type] Task and e[props].get(status) open: for rel in ondb.related(eid, blocks, outgoing): blocked rel[entity] print(f{eid} blocks {blocked[id]} ({blocked[props].get(name, )})) # 示例 2SKILL.md找出没有父项目的孤儿任务 for eid, e in ondb.entities.items(): if e[type] Task: parents ondb.related(eid, has_task, incoming) if not parents: print(fOrphaned: {eid})注意示例 2 用incoming方向查has_task关系是Project --has_task-- Task所以对 Task 而言父项目出现在入边。这类「多跳 方向 过滤」的组合例如 Endpoint → handled_by → Class → belongs_to → Module正是 ondb 文档反复强调的推理场景Python 库的 dict/list 结构让这类代码保持直白。与 x ondb CLI 的集成Python 库不只是独立可用的查询工具它也是x ondb命令的可选后端之一。从 main 中的___x_cmd_ondb_backend_resolve()L24-L45可以看到后端解析优先级显式指定环境变量___X_CMD_ONDB_BACKEND取sqlite|python|awk|js时直接采用自动探测SQLite 就绪 → Python需___X_CMD_ONDB_PY_MODE1且系统存在python3→ AWK 兜底。即 Python 后端需要显式开启___X_CMD_ONDB_PY_MODE1才会被自动选中___X_CMD_ONDB_BACKENDpython则无条件走 Python。库目录下的五个薄脚本展示了「库 → 子进程 → TSV 输出」的接入范式它们都从stdin读日志、向 stdout 打 TSV可直接被 shell 管道调用脚本用法说明ls.py--typeTask复用Ondb.ls()输出id \t type \t nameget.py--idt1输出id/type/ctime/mtime/prop kv行query.py--typeTask复用Ondb.query()即ls别名linked.py--id --rel --datadir复用Ondb.linked()关系属性值中的\、tab、换行会被转义compact.py无参数重放日志后把当前状态输出为快照 TSV存活实体的add 必要时set mtime行 存活link行例如用compact.py手工执行一次压缩cat work/ondb.tsv | python3 $(x ondb libpath py)/compact.py work/snapshot.new这与 CLIx ondb compact的产物语义一致快照包含当前状态的全部 TSV 指令之后新变更追加到log.epoch_ms。验证与端到端测试ondb 模块附带了端到端冒烟测试 mod/ondb/lib/example.sh覆盖了 add/link/set/get/query/compact/ls/linked/unlink/rm/属性删除/JSON 输出/validate 全链路其中多个断言与 Python 库源码语义一一对应可作为行为契约的参照「重复 link 应被静默跳过」↔_do_link的三元组去重「set 到不存在的实体应失败」↔_do_set对缺失/已删实体的早退「set -- priority后get不再含priority」↔_do_set中「空值即删属性」的分支validate对一致图谱应返回 0 错误 ↔validate()返回空列表。跑法仅查看不修改仓库sh mod/ondb/lib/example.sh适用边界与限制结合 README 与源码明确 Python 后端的适用前提规模README 推荐 200010000 实体linked/related/validate均为对links的线性扫描O(links)更大规模应使用 SQLite 物化视图x ondb dbpath获取路径更小规模 AWK 回放即可只读查询库只解析日志、不提供写回所有变更仍应通过x ondb add/set/link/rm/unlink追加写保持 append-only 规则schema 校验需自写内置validate()只查悬空链接schema.tsv中的req/enum/rcard/racyclic等约束需要按前文模式自行编码或直接调用 CLIx ondb validate --schema schema.tsv顺序敏感load()的结果依赖日志行的先后后写的set覆盖先写的属性rm之后的行被软删屏蔽因此喂给load()的输入必须是「快照 增量日志」的有序拼接CLI 侧由 main 中的___x_cmd_ondb_logpath_read()L83-L99负责按此规则生成cat snapshot log读取命令。延伸阅读mod/ondb/SKILL.md 给出了 ondb 的完整概念模型、目录结构与各后端工作流mod/ondb/lib/awk/README.md、mod/ondb/lib/js/README.md 与 mod/ondb/lib/sqlite/README.md 分别是另外三套后端的 API 文档可按 mod/ondb/lib/libpath 子命令定位路径。赞分享CLI开发工具AI Agent人工智能包管理器【免费下载链接】x-cmdPosix Shell 工具库项目地址https://gitcode.com/x-cmd/x-cmd点击查看免费下载相关推荐x-cmd ondb AWK 库零依赖读取与查询 TSV 知识图谱日志的实现详解x cmd ondb AWK 库零依赖读取与查询 TSV 知识图谱日志的实现详解 本文以 mod/ondb/lib/awk/README.md https:/CLI开发工具AI Agent人工智能包管理器x-cmd ondb用 TSV 追加日志构建可验证知识图谱的完整实战指南x cmd ondb用 TSV 追加日志构建可验证知识图谱的完整实战指南 Ondb 是 x cmd 工具库一个 Posix Shell 工具库中内置的“逻CLI开发工具AI Agent人工智能包管理器x-cmd ondb 的 JS (Bun) 库用 JavaScript 读取、查询与校验 TSV 图数据x cmd ondb 的 JS Bun 库用 JavaScript 读取、查询与校验 TSV 图数据 本文讲解 x cmd 仓库中 ondb 模块的 JavaCLI开发工具AI Agent人工智能包管理器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考