Skip to main content

Crate dowse

Crate dowse 

Source
Expand description

Windows 本地全文搜索引擎的核心库。

索引层基于 tantivy 倒排索引,内容分词用 tokenizer 模块把文本按“汉字/ 非汉字“切段:汉字段接 jieba 按中文习惯分词,非汉字段按字母数字切词并统一 小写。extract 模块负责文本抽取——纯文本用 chardetng/encoding_rs 探测 编码,另外支持 PDF、Office(docx/xlsx/pptx)等常见格式。ocr/ocr_worker 模块接入 Windows 系统自带的 OCR 引擎,让截图和图片里的文字也能被搜到 (仅 Windows;其余平台是诚实报“不可用“的桩实现)。mft/usn 模块在 NTFS 卷 + 管理员权限下走 MFT 快速枚举和 USN Journal 增量监听,跳过全盘 目录遍历;拿不到这个前提条件就诚实降级到基于 walkdir + notify 的目录 遍历/文件监听,两条路径产出的索引结果完全一致,调用方感知不到差别。

docs.rs 在 Linux 构建机上生成本页文档,cfg(windows) 之后的 API(OCR、 NTFS MFT/USN 快速索引)不会出现在这里;要看到完整 API,在 Windows 上本地 跑 cargo doc 即可。

§核心入口

§示例

建一次索引,然后在“文档类“扩展名里搜索、按修改时间从新到旧排,最后读出 每条命中的字段:

use std::path::Path;
use dowse::{Searcher, SortMode, display_path, ext_group_by_name, rebuild_index};

let index_dir = Path::new("./my-index");
let target_dir = Path::new("./my-documents");

// 全量建一次索引,拿到收录 / 跳过 / 耗时统计。
let stats = rebuild_index(index_dir, target_dir)?;
println!(
    "收录 {} 个文件,跳过 {},耗时 {:.1}s",
    stats.indexed, stats.skipped, stats.seconds
);

// 打开只读句柄开始搜索。
let searcher = Searcher::open(index_dir)?;

// 只在文档类扩展名(md/txt/pdf/docx…)里搜,按修改时间从新到旧排。
let hits = searcher.search_advanced(
    "季度 报告",
    20,
    ext_group_by_name(Some("doc")),
    SortMode::MtimeDesc,
)?;

for hit in &hits {
    // display_path 剥掉 Windows 的 `\\?\` 扩展长度前缀,只用于展示。
    println!(
        "[{}] {} —— {} 处高亮",
        hit.ext,
        display_path(&hit.path),
        hit.highlighted.len()
    );
    println!("{}", hit.snippet);
}

Structs§

AddRootStats
添加根的统计结果,跟 IndexStats(全量重建)同一口径:收录/跳过文件数。
BatchOutcome
一批增量更新的处理结果,给日志/调试看。
Debouncer
防抖队列:500ms 静默窗口内合并同一 path 的多次事件,只保留最终状态; 水位到 WATER_LEVEL 就提示宿主强制刷批。纯内存逻辑,不碰时钟也不碰磁盘—— 时间窗口由宿主的事件循环(watch.rs)用 recv 超时驱动。
IndexProgress
单次进度汇报:累计处理数(收录 + 跳过),和刚处理完的那个文件路径。
IndexStats
一次重建索引的统计结果,CLI 拿去打报告。
IndexStatus
索引的只读状态快照,给 CLI/MCP 的 index_status 一类查询用。
IndexUpdater
增量更新器:持有索引的写入端 IndexWriter,把防抖后的一批变更落进索引, 一批只 commit 一次(tantivy 的 commit 是重操作,绝不能一个文件一次)。
NotifyEventSource
基于 notify 库的跨平台事件源。把各平台原生事件翻译成 WatchEvent。
OcrDrainStats
drain_ocr_queue 一次运行的统计结果。
OcrPipeline
OCR 后台管线句柄:持有 worker 线程,stop() 时等待它们干净退出(当前正在跑的 那一张 OCR 会跑完,不会被中途打断留下半张写坏的文档)。
OcrQueue
OCR 队列:图片的 (path,mtime,size) 待处理表 + 已处理结果缓存,随索引目录持久化 在 <index_dir>-ocr-queue.json(跟 meta.rs 的 <index_dir>-meta.json 同一个 “索引目录旁的兄弟文件“套路,不塞进 tantivy 自己管理的索引目录里)。
PendingChange
防抖合并后交给更新器的一条变更。
PreviewHit
按路径取的预览内容,字段契约和 SearchHit 的 snippet/highlighted 一致, 只是窗口更大(约 1500 字而不是摘要用的 160 字)。
ReconcileStats
一次启动对账的差异统计。
RemoveRootStats
移除根的统计结果:从索引里删掉的文档数。
SearchHit
一条搜索命中。
Searcher
一个索引的只读搜索句柄。

Enums§

PendingOp
一个 path 在防抖窗口内合并后的最终意图。
SortMode
结果排序方式。相关性是默认值——不传排序参数、或者从前端传来的字符串 没解析出已知档位时都落回这里。其余三档对应浮窗“排序器“下拉的三个非默认项, 底层用 tantivy TopDocs::order_by_fast_field 系列 API 在 mtime/size 这两个 v0.5.0 补了 FAST 属性的字段上排(见 lib.rs 的 build_schema)。
WatchEvent
文件系统监听的原始事件。事件源(notify,或将来里程碑 6 的 USN Journal) 把各平台的原生事件归一成这几类再喂进防抖队列。刻意只带路径、不带时间戳/inode 等平台细节,让防抖/合并逻辑是纯函数,不依赖真实文件系统。
WatchProgress
监听循环对外汇报的进度,给 CLI 打日志、给托盘端刷新状态用。

Constants§

DEFAULT_WORKERS
CLI/托盘启动 OCR 管线时的默认线程数。

Traits§

EventSource
文件系统事件源抽象。里程碑 3 用 notify 做第一个实现;里程碑 6 的 NTFS USN Journal 快速路径只要再实现这个 trait,就能接进同一条“防抖 → 更新“流水线, 上层的 run_watch 完全不用改。
WatchGuard
监听句柄:留住它监听就继续,drop 掉就停。

Functions§

add_root
添加一个根:不动现有索引,对新根做一次“目录树 upsert“(遍历 + 先删后加, 幂等),完成后把根追加进 meta。不需要进度直播的调用方走这个薄封装。
add_root_with_progress
add_root,多一个进度回调,直播这个根的目录树 upsert 进度——设计文档 “进度直播复用现有整套“要求这条路径也能像全量重建一样把过程推给前端。
display_path
剥掉 Windows 扩展长度路径语法(\\?\/\\?\UNC\)的前缀,只给展示层用。
drain_ocr_queue
同步跑完 OCR 队列直到清空(dowse index 这类一次性命令用):建完文本索引后 紧接着启动 worker 池处理图片,直到队列见底再返回,让命令结束时索引就是完整 可搜的状态,而不是留一堆图片在后台“回头再说“——常驻的托盘程序不需要这个, 那边图片交给后台 worker 池慢慢消化就行(见设计文档“独立于文本管线“一节)。
ext_group_by_name
按名字取预设分组的扩展名集合。"all"None、未知名字都表示不筛选—— 浮窗前端传字符串过来,未知输入宽松地当“全部“处理,不报错。
index_status
读索引的只读状态:文档数、已注册根、落盘体积、最近更新时间。
is_available
探测系统是否有可用的 OCR 语言包。管线整体启用与否的开关,UI 侧也可以拿它 提前决定要不要显示“OCR 不可用“的引导文案。
normalize_ranges
把 tantivy SnippetGenerator 吐出的命中区间整理成有序且互不重叠的序列。
ntfs_fast_path_available
供集成测试用的权限护栏:这个路径能不能走 NTFS 快速路径(MFT 枚举 + USN Journal)。跟 dowse::is_available()(OCR 语言包探测)是同一个 用途——测试开头先探测一次,探测不到就打印原因跳过,不需要管理员权限的 测试永远能跑,需要的测试在非管理员机器/CI 上不会把构建搞红。
rebuild_index
v0 策略:全量重建。删掉旧索引目录,从头扫一遍。 增量更新是里程碑 3 的事,现在先把“能搜“跑通。
rebuild_index_with_progress
rebuild_index,多一个进度回调:每处理 PROGRESS_INTERVAL 个文件就报一次 累计处理数和当前文件路径。CLI 的 dowse index 和浮窗的“建索引“都走这个, 一份实现两处消费,避免两端各自维护一份遍历+回调逻辑。
rebuild_root
重建单根 = 移除根 + 添加根的组合,全部复用上面两个操作(设计文档“核心 操作语义“一节)。给已经注册过的根一次干净的重新收录,而不用先手动移除 再手动添加。
rebuild_root_with_progress
rebuild_root,多一个进度回调,直播添加阶段的目录树 upsert 进度。
reconcile
启动对账:程序没跑的时候文件照样在变,启动时把索引追平文件系统的实际状态。
reconcile_orphans
孤儿文档清理(多根索引,里程碑 7):索引里若存在 path 不属于 roots 任一根的文档,直接删除。
registered_roots
已注册的索引根目录列表,供启动对账和文件监听使用。 顺带校验 schema 版本——版本不对时直接报错,不返回一份不可信的根列表。
remove_dir_all_retrying
删整个目录,撞上 PermissionDenied 时按指数退避重试几次再放弃。
remove_root
移除一个根:前缀圈选删除该根名下的全部文档,OCR 队列 compact 掉该根的 条目,roots 里移除这一项。root 必须是 registered_roots 返回值里的 原样一项(不做 canonicalize/存在性校验)——移除本来就要覆盖“根所在目录 已经从磁盘上消失“这种场景,不能要求它此刻还能被 stat 到。
run_watch
监听主循环:把事件源 → 防抖队列 → 增量更新器串起来,阻塞运行直到 stop 置位。
watch_roots_auto
按卷判定自动选监听路径的入口(里程碑 6):每个根探测 NTFS + 管理员权限, 拿得到就走 MFT/USN 快车道,拿不到就走现有的 walkdir + notify 慢车道 (设计文档第一节)。CLI 的 dowse watch 和托盘常驻程序的监听线程都应该 调这个函数替代直接调 run_watch(NotifyEventSource, ...)——这是“上层 完全不用感知快慢车道差别“在代码上的落地:调用方只需要把原来的 run_watch(NotifyEventSource, &roots, ...) 换成 watch_roots_auto(index_dir, &roots, ...),其余逻辑不用动。