Files

71 lines
3.7 KiB
Markdown
Raw Permalink Normal View History

# 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;这是后续性能设计项。