尧图精选

code-review-graph 全文搜索实现:FTS5虚拟表与Porter词干化的完整指南

🕒 发布时间:2026/8/31 8:50:26 📁 来源:尧图网络
code-review-graph 全文搜索实现FTS5虚拟表与Porter词干化的完整指南【免费下载链接】code-review-graphLocal-first code intelligence graph for MCP and CLI. Builds a persistent map of your codebase so AI coding tools read only what matters, with benchmarked context reductions on reviews and large-repo workflows.项目地址: https://gitcode.com/GitHub_Trending/co/code-review-graphcode-review-graph 是一个本地优先的代码智能图谱工具它为 AI 编程助手构建代码库的持久化地图其中全文搜索能力由 SQLite 的FTS5 虚拟表配合Porter 词干化stemming实现。本文面向新手用大白话讲清楚这套搜索引擎的设计虚拟表为什么能省一份数据、Porter 词干化如何让 calculating 匹配到 calculate_total以及索引如何重建、如何防注入、搜索失败时又如何自动降级兜底。为什么需要全文搜索混合检索的第一条腿AI 工具问谁在调用Context.Next这类问题时图谱不能靠猜——它需要一个精确的符号检索引擎。code-review-graph 的答案是混合搜索FTS5 BM25 全文搜索精确、快速、可解释擅长匹配符号名向量嵌入语义搜索理解自然语言意图两者结果用RRF倒数排名融合合并任何一路失效都能降级到 LIKE 关键词匹配。FTS5 就是这条精确腿的核心全部实现在 code_review_graph/search.py 中。FTS5虚拟表是什么nodes_fts 的设计打开数据库 schema你会看到这样一段定义见 docs/schema.mdCREATE VIRTUAL TABLE nodes_fts USING fts5( name, qualified_name, file_path, signature, contentnodes, content_rowidrowid, tokenizeporter unicode61 );逐行拆解三个关键细节配置含义新手视角name, qualified_name, file_path, signature参与索引的 4 个字段搜函数名、限定名、文件路径、签名都能命中contentnodes外部内容表模式FTS 表不重复存数据只存索引靠rowid回nodes表取原文省空间tokenizeporter unicode61Porter 词干化 Unicode 分词同一词的不同变形归一化后匹配详见下节这张表由数据库迁移 v5 创建代码在 code_review_graph/migrations.py_migrate_v5函数。Porter词干化为什么搜 calculating 能命中 calculate_totalPorter 词干化Porter Stemming是一种经典的英文词形归一化算法把单词削到它的词干——calculating、calculated都会被削成calculat。这意味着索引时函数calculate_total被存为词干calculat total查询时你输入 calculating同样被削成calculat于是精准命中。没有词干化时用户必须输入和代码完全一致的字面形式有了它动词进行时、过去式、复数等常见变形都能自动匹配。unicode61部分则负责正确处理各种 Unicode 字符和大小写。测试用例直观展示了这一点查询name MATCH calculate*能直接取到calculate_total见 tests/test_fts_sync.py。查询安全防注入与 BM25 排序用户输入直接拼进MATCH语句是危险操作——FTS5 查询语言自带AND、OR、NEAR等运算符恶意输入可以注入逻辑。_fts_search的解法很朴素也很有效code_review_graph/search.py把整个查询用双引号包裹内部双引号转义成——整个输入被当作一个普通文本短语运算符彻底失效。排序上FTS5 的rank列返回的是负数 BM25 分数越负越好代码里取反成越大越好方便和其他引擎的分数统一比较。BM25 是信息检索的经典算法词在越少的文档里出现、在当前文档里出现越频繁得分越高——对符号名这种稀缺词天然友好。多词查询的拼接规则在 code_review_graph/graph.py 的search_nodes中每个词独立加引号后用AND连接即所有词都必须命中。索引如何保持新鲜一次事务内的重建图谱会随代码增删改而漂移FTS 索引必须跟上。rebuild_fts_indexcode_review_graph/search.py做了三件事全部包在一个BEGIN IMMEDIATE事务里DROP TABLE IF EXISTS nodes_fts—— 清掉旧索引按 v5 schema 重新CREATE VIRTUAL TABLEINSERT INTO nodes_fts(nodes_fts) VALUES(rebuild)—— FTS5 内置命令从nodes内容表全量重建。事务包裹是为了防半截状态如果重建中途崩溃回滚后数据库里仍然有旧 FTS 表而不会出现DROP 成功但 CREATE 失败导致搜索瘫痪对应问题 #259回归测试见 tests/test_search.py。同步性由 tests/test_fts_sync.py 专门守护删掉的文件不会在索引里残留。重建的触发时机覆盖了主要写路径全量构建后code_review_graph/tools/build.py、图谱后处理code_review_graph/postprocessing.py、以及评测框架跑完后确保索引永远不空。从搜索结果到 AI 工具降级链与类型加权面向 MCP 工具的搜索入口是semantic_search_nodescode_review_graph/tools/query.py它调用hybrid_search并返回search_mode字段让 AI 明确知道结果来自哪条路径hybridFTS向量、fts、semantic、keywordLIKE 兜底或none。整条降级链FTS5 向量RRF 融合 → 单路 FTS5 → 单路向量 → LIKE 关键词 → 空结果融合后再叠一层查询意图加权detect_query_kind_boostcode_review_graph/search.py几条简单启发式PascalCase查询如OrderProcessor→ Class/Type 节点 ×1.5snake_case查询如get_users→ Function 节点 ×1.5查询含.如Context.Next→ 限定名精确命中 ×2.0让方法赢过同名类当前打开的文件列表 → 其中节点 ×1.5。这套设计让搜索对 AI 工具是透明的向量库不可用就退回 FTS5FTS5 表缺失就退回 LIKE任何一层坏了都不至于搜不到。快速上手与延伸阅读想亲手验证克隆仓库后执行一次构建即可看到 FTS 索引生效git clone https://gitcode.com/GitHub_Trending/co/code-review-graph构建完成后用semantic_search_nodes工具CLI 或 MCP 均可搜一个带时态变形的单词观察命中结果——这就是 Porter 词干化在干活。核心资料索引搜索引擎主模块code_review_graph/search.py虚拟表迁移定义code_review_graph/migrations.py数据库 Schema 说明docs/schema.md功能特性描述docs/FEATURES.mdFTS 同步测试tests/test_fts_sync.py一句话总结code-review-graph 用一张不存数据的 FTS5 虚拟表 Porter 词干化 事务化重建 多级降级把给 AI 的代码搜索做成了又省空间、又抗变形、又不会坏死的检索引擎。【免费下载链接】code-review-graphLocal-first code intelligence graph for MCP and CLI. Builds a persistent map of your codebase so AI coding tools read only what matters, with benchmarked context reductions on reviews and large-repo workflows.项目地址: https://gitcode.com/GitHub_Trending/co/code-review-graph创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →