【免费下载链接】fsearch
Whole-disk file search for macOS: fuzzy names, typo tolerance, indexed content grep. ~1 ms over 8M files.
fsearch 是 macOS 上的全盘文件搜索引擎:模糊匹配文件名、容忍一个拼写错误、基于倒排索引搜索文件内容,在 800 万文件上约 1 ms 返回结果。它是完整的 Rust 文件搜索工具,既可嵌入为Rust Crate(fsearch::Engine),也可通过JSON Lines Unix Socket或fsearch stdio从任意语言调用。本文是该项目的开发者完整参考,覆盖 API 快速上手、协议字段、查询语法与常见坑点 🚀
🧭 30 秒理解架构:一个引擎,两种集成
fsearch 的核心是一个后台引擎:启动时全量爬盘约 20 秒,之后靠 FSEvents 增量维护,名字索引存于单个 mmap 文件、内容搜索用 trigram(三元组)倒排索引。两种集成方式共用同一份索引:
| 集成方式 | 适用场景 | 入口 |
|---|---|---|
| Rust Crate | 写 Rust 应用,直接进程内搜索 | src/engine.rs 的Engine |
| JSON Lines Socket | 任意语言(Python/JS/Shell)跨进程调用 | src/server.rs 的守护进程 |
fsearch stdio | 命令行管道、脚本内快速查询 | src/main.rs#L126-L145 |
对外导出集中在 src/lib.rs#L14-L16:Engine、Options、Query、Grep、GrepResult等,模块划分清晰(engine/query/content/index/live/walk)。
📦 第一部分:Rust Crate API 快速上手
1. 三个核心类型与启动引擎
整个 API 围绕三个类型展开,定义在 src/engine.rs:
| 类型 | 作用 | 源码位置 |
|---|---|---|
Options | 索引目录dir、用户主目录home、黑名单skip | engine.rs#L33-L41 |
Engine | 搜索引擎本体,Clone后可跨线程共享 | engine.rs#L73-L75 |
Query | 解析自人类查询语言,驱动名字搜索 | query.rs#L52-L66 |
最小集成(依赖本仓库 crate 即可,Engine::start后台建索引并立即返回):
let home = std::env::var("HOME")?; let engine = fsearch::Engine::start(fsearch::Options { dir: fsearch::default_dir(&home), // ~/Library/Application Support/FSearch home: home.clone(), skip: None, })?; let q = fsearch::Query::parse("fsearch main", &home)?; for f in engine.search(&q)? { println!("{}", f.path.display()); }⚠️ 索引未就绪(首次全量爬盘约 20 秒)时,search/grep会返回Err("indexing (first run scans the whole disk, ~20s)"),轮询status()的ready字段即可。
2. 日常四方法:search / grep / status / save
| 方法 | 签名要点 | 说明 |
|---|---|---|
Engine::search | &Query → Vec<Found> | 名字模糊搜索,返回带评分的结果 |
Engine::grep | (&Query, &Grep) → (GrepResult, bool) | 内容搜索;bool表示由内容索引回答还是回退扫描 |
Engine::status | → Status | 索引规模、内存占用、内容索引进度、是否 owner |
Engine::save | 无参 | 请求后台压缩并落盘名字索引 |
结果结构:Found { path, kind, size, mtime, score }(engine.rs#L44-L51),kind低 2 位区分 file/dir/link;Status(engine.rs#L53-L70)含entries、content_docs、full_disk_access、owner等字段。
内容搜索用Grep::new(pattern, mode)构造,三种模式:Literal(默认,smart-case 自动忽略大小写)、Regex、Symbol(只找定义处,如fn apply_dir),见 content.rs#L915-L932。可调max_per_file(默认每文件 5 条)与budget(默认 250 ms 时间预算):
let g = fsearch::Grep::new("apply_dir", fsearch::GrepMode::Symbol)?; let (res, indexed) = engine.grep(&q, &g)?; // res.files: Vec<FileMatches { path, lines: Vec<(行号, 文本)> }> // res.complete == false 表示时间预算用完,结果按排名截断3. 查询语言速查:模糊词 + 12 个过滤器
Query::parse(query.rs#L98-L111)支持 fzf 风格模糊匹配,5 个字母以上的词容忍一个拼写错误(mian.rs能找到main.rs):
| 写法 | 含义 |
|---|---|
main rs | 模糊词,文件名或路径中按序匹配 |
'exact/^prefix/suffix$ | 精确 / 前缀 / 后缀 |
!exclude | 排除 |
ext:rs,rs、type:image、kind:dir | 扩展名、类型(image/video/code/doc 等)、种类 |
in:~/Developer、size:>5mb、mtime:<7d | 目录范围、大小、修改时间 |
re:/path: | 文件名 / 全路径正则 |
grep:/regex:/sym: | 文件内容搜索(字面 / 正则 / 符号定义) |
limit:20 | 返回条数(默认 50) |
评分细节(fzf 风格子序列打分 + 词边界/驼峰加分 + 错别字惩罚)在 query.rs#L407-L471。
4. 多进程共享一份索引:Owner / Follower 机制
这是最容易忽略的设计:索引目录里有一把flock文件锁,同一时间只有一个进程写索引(owner),其余进程跟随(follower)。你的 App 和 CLI 可以同时运行、共享一份索引;owner 退出后 follower 自动接管(try_upgrade,engine.rs#L345-L357)。因此嵌入时不需要额外做单实例逻辑。
其他实用函数:
fsearch::default_dir(home)— 默认数据目录(engine.rs#L655-L657)fsearch::has_full_disk_access()— 检查 Full Disk Access(engine.rs#L381-L383)fsearch::gated(home)— 无 FDA 时自动跳过的隐私受保护目录列表(engine.rs#L375-L377)fsearch::no_materialize()— 防止索引时触发 iCloud 占位文件下载
🔌 第二部分:JSON Lines Socket 协议参考
1. 连接方式:socket 路径与自动拉起
守护进程监听~/Library/Application Support/FSearch/fsearch.sock(server.rs#L12-L14),协议为每行一个 JSON 对象、请求一行对应响应一行:
fsearch stdio # 把 stdin/stdout 透传到守护进程,最适合脚本任何语言也可直接连 Unix socket——若守护进程没在跑,fsearch客户端会自动spawn它再重试(server.rs#L188-L211)。Python 示例:
import os, socket, json s = socket.socket(socket.AF_UNIX) s.connect(os.path.expanduser("~/Library/Application Support/FSearch/fsearch.sock")) s.sendall(b'{"q": "fsearch main", "limit": 5}\n') print(json.loads(s.recv(65536)))2. 五种 op 请求速查表
| op | 请求示例 | 说明 |
|---|---|---|
ping | {"op": "ping"} | 连通性测试 |
status | {"op": "status"} | 索引状态;未就绪时返回 error |
search(默认) | {"q": "fsearch main", "limit": 20} | 名字搜索;省略op即 search |
grep | {"op": "grep", "pattern": "apply_dir", "in": "~/Developer"} | 内容搜索 |
save | {"op": "save"} | 请求后台压缩落盘 |
补充细节(见 server.rs#L70-L112):
id字段:请求里带的任意id会原样回显到响应,方便并发多路复用;- 自动识别内容搜索:
q中出现grep:/regex:/sym:/content:/symbol:时自动按 grep 处理(server.rs#L72-L74); - 过滤器可拆成独立字段:
{"q": "main", "ext": "rs", "in": "~/Developer"}等价于写在q里(server.rs#L160-L176); - grep 专属参数:
mode(literal/regex/symbol)、per_file、budget_ms(server.rs#L117-L133)。
3. 响应字段逐条解读
search 响应(server.rs#L91-L109):
{"ok": true, "took_us": 1234, "id": "r1", "hits": [{"path": "/Users/me/main.rs", "kind": "file", "size": 4821, "mtime": 1760000000, "score": 142}]}grep 响应(server.rs#L146-L155):
| 字段 | 含义 |
|---|---|
source | index(trigram 索引命中)或scan(名字索引选文件后直读) |
candidates/read | 候选文件数 / 实际打开读取数 |
complete | false表示 250 ms 预算用完,结果按排名截断(先返回最相关的) |
indexing | 内容索引尚在后台处理的文件数 |
files[].matches | [{line, text}]逐条匹配行 |
status 响应:即Status序列化(engine.rs#L54-L70),entries(索引条目数)、content_docs、index_bytes、owner(本进程是否写索引)等。
⚡ 性能基线与常见坑点
在 M4 Max、770 万文件的实测(README.md):
| 指标 | 数值 |
|---|---|
| 全盘按名字找文件 | p50 ≈ 1.3 ms |
| 文件内容搜索 | p50 ≈ 9 ms |
| 新文件/改名/删除反映到结果 | ~0.1 s |
| 首次全量爬盘 | ~20 s(仅一次) |
| 守护进程内存 | 30–135 MB |
五个最常见的坑:
- 启动后立即搜索报错— 首次运行在爬盘,
indexing错误属正常,轮询status即可; - grep 结果不全—
complete: false是时间预算截断,需要全量时传更大的budget_ms; - 搜不到某些目录— 无 Full Disk Access 时会自动跳过 Desktop、Documents 等受保护目录(不弹窗),给
~/.local/bin/fsearch授予 FDA 后用fsearch install --login注册开机自启; - 只起一个守护进程—
socket.lock保证每目录单守护进程(server.rs#L20-L24),但多个嵌入Engine的进程可安全共存; mtime是秒—Found.mtime与响应字段均为u32Unix 秒,不是毫秒。
📌 源码位置速查表
| 关注点 | 文件 |
|---|---|
| 对外 API 汇总 | src/lib.rs |
| 引擎、Owner/Follower、索引压缩 | src/engine.rs |
| 查询解析与模糊打分 | src/query.rs |
| trigram 内容索引、Grep 实现 | src/content.rs |
| 索引二进制格式、mmap 布局 | src/index.rs |
| FSEvents 增量跟踪 | src/fsevents.rs、src/live.rs |
| 全盘扫描(getattrlistbulk) | src/walk.rs |
| 守护进程与 JSON Lines 协议 | src/server.rs |
| CLI / stdio / install / bench | src/main.rs |
| 构建配置(opt-level 3 + fat LTO) | Cargo.toml |
| 与 fff 的基准测试脚本 | demo/vs_fff.py |
总结:Rust 项目直接Engine::start三行接入,享受毫秒级模糊搜索 + 内容 grep;其他语言走 JSON Lines socket,五种 op 覆盖全部能力。两种路径共享同一份实时索引,这正是 fsearch 作为文件搜索基础设施的集成精髓。
【免费下载链接】fsearch
Whole-disk file search for macOS: fuzzy names, typo tolerance, indexed content grep. ~1 ms over 8M files.
相关推荐
BilldDesk Pro API完全指南:从入门到精通的远程桌面开发集成手册
BilldDesk Pro API完全指南:从入门到精通的远程桌面开发集成手册 BilldDesk是基于Vue3 + WebRTC + Nodejs + Flu
桌面应用前端音视频网络Riot搜索引擎API参考手册:完整接口调用指南
Riot搜索引擎API参考手册:完整接口调用指南 Riot是一款基于Go语言的开源分布式全文搜索引擎,以其简单高效的特性受到开发者青睐。本指南将为您详细介绍Ri
全文检索后端Remote benefits
Remote benefits Flexible working hours Home office stipend Annual retreat Applic
数据集
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考