面向 .NET 10 的嵌入式全文搜索引擎
单目录持久化、进程内运行、零外部依赖,也支持 gRPC 服务端模式。
DotSearch 是一个基于 C# / .NET 10 的全文搜索引擎,核心引擎可以直接通过 NuGet 引用, 在应用进程内运行,也可以作为 gRPC 服务端独立部署。
它适合两种典型形态:
- 嵌入式模式:直接
new InMemoryFullTextIndex(new UnicodeTokenizer()),本地使用。 - 服务器模式:通过
DotSearch服务端宿主对外提供 gRPC 接口。
仓库当前覆盖了核心引擎、可插拔分词器、混合检索融合器、gRPC 服务端宿主与示例代码。
项目边界保持清晰:
DotSearch.Core是完整的嵌入式全文检索引擎,包含倒排索引、BM25、查询 AST 与 分词器抽象。DotSearch.Tokenizers.Unicode/DotSearch.Tokenizers.Cjk/DotSearch.Tokenizers.Jieba是可插拔的分词器,按需引用。DotSearch.Hybrid把 BM25 命中与外部排序源(例如向量检索)通过 RRF 融合输出。DotSearch是 gRPC 服务端宿主,托管多个DotSearch.Core实例。
using DotSearch.Index;
using DotSearch.Query;
using DotSearch.Tokenizers.Unicode;
var index = new InMemoryFullTextIndex(new UnicodeTokenizer());
index.Index(new Document(new DocumentId("1")).Set("body", "Hello DotSearch"));
index.Index(new Document(new DocumentId("2")).Set("body", "Hello DotVector"));
var hits = index.Search(new TermQuery("body", "dotsearch"), topK: 10);
foreach (var hit in hits)
{
Console.WriteLine($"{hit.DocumentId} {hit.Score:F4}");
}using DotSearch.Tokenizers.Jieba;
var index = new InMemoryFullTextIndex(new ChineseTokenizer());
index.Index(new Document(new DocumentId("1")).Set("body", "北京天气不错"));中文分词器自带内嵌词表,构建时会编译为 DAT 二进制资源,开箱即用。
using DotSearch.Index;
using DotSearch.Query;
using DotSearch.Storage;
using DotSearch.Tokenizers.Unicode;
var index = PersistentFullTextIndex.Open("mydb.dsx", new UnicodeTokenizer());
index.Index(new Document(new DocumentId("1")).Set("body", "Hello persistent DotSearch"));
// 稍后重开同一个目录即可恢复。
var reopened = PersistentFullTextIndex.Open("mydb.dsx", new UnicodeTokenizer());
var hits = reopened.Search(new TermQuery("body", "persistent"), topK: 10);持久化索引使用单目录布局:manifest.json 记录活动段与 tombstone,segments/*.seg
是不可变段文件。更新同一文档 ID 会自动 tombstone 旧版本;段数达到阈值时会触发后台合并,
也可以显式调用 MergeSegments()。
using DotSearch.Hybrid;
using DotSearch.Index;
using DotSearch.Query;
var fullText = new FullTextRankedSource<string>(
index,
queryText => new TermQuery("body", queryText));
var vector = new DelegateRankedSource<string>(
"vector",
(queryText, topK) => externalVectorSearch(queryText, topK));
var pipeline = new HybridSearchPipeline<string>(new IRankedSource<string>[] { fullText, vector });
var fused = pipeline.Search("dotsearch", topK: 10, sourceTopK: 50);DotSearch.Hybrid 不绑定任何向量数据库;外部检索只需返回按相关性降序排列的 SearchHit 列表。
dotnet run --project src/DotSearch -- --data /var/lib/dotsearch --port 5280或通过环境变量:
export DOTSEARCH_DATA_DIR=/var/lib/dotsearch
export DOTSEARCH_PORT=5280
dotnet run --project src/DotSearch设置 DOTSEARCH_API_KEY 后,所有 gRPC 请求都需要携带 x-api-key metadata。DOTSEARCH_REQUIRE_CLIENT_CERT
是 mTLS 策略占位开关,当前用于部署配置显式化。
Docker 运行:
docker compose up --build默认容器监听 5280,数据卷挂载到 /data。
DotSearch/
├── src/
│ ├── DotSearch.Core/ # AOT 核心:索引、查询、BM25、存储抽象
│ ├── DotSearch.Tokenizers.Unicode # 默认 Unicode 分词器
│ ├── DotSearch.Tokenizers.Cjk # CJK 二元分词器(零词典)
│ ├── DotSearch.Tokenizers.Jieba # 中文分词器(内嵌词典)
│ ├── DotSearch.Hybrid # RRF 融合外部排序源
│ └── DotSearch # gRPC 服务端宿主
├── Dockerfile # 服务端镜像
├── docker-compose.yml # 本地容器运行配置
├── tests/ # 单元测试
├── benchmarks/ # BenchmarkDotNet 与 M6 验证报告
├── docs/ # 架构、磁盘格式、AOT 策略
├── protos/ # gRPC 协议定义
└── ROADMAP.md # 路线图
dotnet restore
dotnet build -c Release
dotnet test -c Release需要 .NET 10 SDK(见 global.json)。
详见 ROADMAP.md。
| Milestone | 主题 |
|---|---|
| M0 | 工程骨架 + 文档 + 设计基线 |
| M1 | 单段内存倒排索引 + BM25 + 默认分词器 |
| M2 | 持久化层(段格式 + manifest) |
| M3 | 中文分词器 DAT 词典 + 短语 / NEAR / BM25F |
| M4 | gRPC 服务端 + Docker |
| M5 | DotSearch.Hybrid 融合集成 |
| M6 | Native AOT 端到端验证 + 基准 |
MIT,见 LICENSE。