☰
fsearch开发者指南:全盘文件搜索引擎的 Rust Crate API 与 JSON Lines Socket 集成完整参考
2026/10/10 13:56:51 网站建设 项目流程

【免费下载链接】fsearch

Whole-disk file search for macOS: fuzzy names, typo tolerance, indexed content grep. ~1 ms over 8M files.

项目地址:https://gitcode.com/gh_mirrors/fsea/fsearch
点击查看免费下载

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、黑名单skipengine.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):

字段含义
sourceindex(trigram 索引命中)或scan(名字索引选文件后直读)
candidates/read候选文件数 / 实际打开读取数
completefalse表示 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

五个最常见的坑:

  1. 启动后立即搜索报错— 首次运行在爬盘,indexing错误属正常,轮询status即可;
  2. grep 结果不全—complete: false是时间预算截断,需要全量时传更大的budget_ms;
  3. 搜不到某些目录— 无 Full Disk Access 时会自动跳过 Desktop、Documents 等受保护目录(不弹窗),给~/.local/bin/fsearch授予 FDA 后用fsearch install --login注册开机自启;
  4. 只起一个守护进程—socket.lock保证每目录单守护进程(server.rs#L20-L24),但多个嵌入Engine的进程可安全共存;
  5. 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 / benchsrc/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.

项目地址:https://gitcode.com/gh_mirrors/fsea/fsearch
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询