Files
mnote/bugs/04-tree-domain/done/2026-05-27-local-search-query-rebuilds-index.md
T

71 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# local search query 每次重建索引导致大工作区搜索卡顿
> 状态:done
> Owner04-tree-domain / 03-rust-web
> 发现日期:2026-05-27
> 来源:Sidex 全项目 review / 本地搜索性能审查
## 现象
在 local-first 工作区中,侧边栏搜索输入虽然有前端 debounce,但后端每次 query 都会重建并写入整个 local search index。大工作区下,连续输入会触发多次递归扫描、读取 Markdown、写 `.mnote/index/search-index.json`,导致搜索和主界面卡顿。
## 证据
- `rust/crates/mnote-web/src/routes/local_search_index.rs`
- `query_local_search_index()` 第一步调用 `rebuild_local_search_index(...)`
- `rebuild_local_search_index()` 递归 `collect_markdown_documents(...)` 后写入 index。
- 前端 `sidebar-tree-runtime.js` 的搜索渲染 debounce 不能避免后端每次 query 全盘 rebuild。
- 同文件已经存在 `refresh_local_search_index_for_path(...)` 增量更新入口,说明 watcher/单文件刷新方向已有基础,但 query path 没有复用它。
## Sidex / VSCode 对照
Sidex / VSCode 搜索路径不会把每次 query 等价为全盘同步 rebuild
- quick access/search 使用 throttle、cache state 和 cancellation token。
- Rust search crate 有 max_results、ignore-aware、binary skip 和并行扫描。
- watcher 变化应驱动增量缓存更新,query 只消费当前 cache 或启动后台 refresh。
MNote 不需要照搬 VSCode 搜索 UI,但应采用同一原则:query path 不做强制全量重建。
## 期望行为
- query 优先读取已有 index。
- index 缺失、版本不匹配、rootUri/workspaceId 不匹配时,才同步 rebuild。
- index 过期但仍可读时,query 返回旧 index 结果,并后台触发 refresh。
- watcher/path event 继续调用 `refresh_local_search_index_for_path(...)` 做增量更新。
- 连续输入时,旧 query 可以被取消或自然过期,不能排队多次全盘扫描。
## 建议修复切片
1. 新增 `load_or_rebuild_local_search_index(root_path, root_uri, workspace_id)`
-`read_local_search_index(root_path)`
- 若 version/rootUri/workspaceId 匹配,直接返回 index。
- 不匹配或缺失时才调用 `rebuild_local_search_index(...)`
2.`query_local_search_index()` 改为调用 `load_or_rebuild_local_search_index(...)`
3. 保留显式 refresh API 调用 `refresh_local_search_index(...)`
4. 加单测:
- 首次 query 会创建 index。
- 第二次 query 不改写 index `built_at`
- refresh 后 query 能读到新内容。
- 单文件 `refresh_local_search_index_for_path(...)` 后 query 命中更新内容。
5. 后续中期再做后台 refresh、取消令牌和搜索 worker。
## 验收
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_search_index -- --nocapture` 通过。
- 连续两次相同 query 时,第二次不会调用 full rebuild,不更新 `built_at`
- 侧边栏连续输入 5 个字符时,不出现 5 次全盘 rebuild。
- 大目录 smoke 中搜索响应不阻塞 FileTree 展开。
## 修复记录
- 2026-05-27:新增 `load_or_rebuild_local_search_index(...)``query_local_search_index(...)` 优先读取已有匹配 version/rootUri/workspaceId 的索引;只有索引缺失、无效或 root/workspace 不匹配时才 full rebuild。
- 2026-05-27:新增回归测试 `local_search_query_reads_existing_index_without_rebuilding`,验证 query 不会看到未 refresh 的磁盘新内容,增量 refresh 后才命中新内容。
- 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web local_search_index -- --nocapture`4 passed。
## 非目标
- 不在本缺陷单实现全文搜索排序重构。
- 不引入新的搜索 UI。
- 不实现全局后台 index worker;这是后续性能设计项。