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

3.7 KiB
Raw Permalink Blame 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 -- --nocapture4 passed。

非目标

  • 不在本缺陷单实现全文搜索排序重构。
  • 不引入新的搜索 UI。
  • 不实现全局后台 index worker;这是后续性能设计项。