Typesense — schema-first 的自托管即时搜索
已复核Typesense 是 Typesense Inc. 用 C++ 写的自托管搜索引擎,目标是 Algolia 那种「边输边出结果」的体验,但跑在自己的机器上。日常类比:先画货架标签再上货,而不是像 meilisearch 那样先倒一箱 JSON 再认字段。
固定 30.2 的入口是单二进制 + REST。默认 API 端口 8108。倒排索引用 Adaptive Radix Tree,原始 JSON 落 RocksDB。许可证是 GPL-3.0。
typesense-server --data-dir /data --api-key=xyz --api-port=8108没有 --api-key 就没有 bootstrap 管理员身份;之后的 scoped key 都从这把钥匙派生。
不读固定 30.2 源码,下面这些合同很容易被旧镜像或 DESIGN.md 带偏:
- 为什么
fields是创建 collection 的必填项,却又能写type: auto - 为什么不写
query_by会直接 400 - 5 个字母的词默认允许多少 typo
- 高可用到底是异步副本还是 Raft
核心架构与流程
Section titled “核心架构与流程”主链可以拆成五步:
- 声明 schema:
create_collection强制name和fields。enable_nested_fields默认 false。type: auto的含义是「第一个写入值决定类型」,不是可以省略 schema。 - 写入与存储:文档进 RocksDB;可搜索 token 进内存 ART。向量字段带
num_dim;关键词字段不要放进query_by,应走vector_query。 - 检索参数:
q或voice_query必填。非通配搜索在query_by为空时返回Missing query_by parameter。默认num_typos=2、min_len_1typo=4、min_len_2typo=7、prefix=true、per_page=10。 - 排序与混合检索:token 命中数、proximity 和静态 sort 字段一起工作;向量维度必须对齐
num_dim。 - 鉴权与集群:
AuthManager区分 bootstrap key 与派生 scoped key。多节点走braft:解析--nodes(host:peeringPort:apiPort),选不出 Leader 会重试。根目录DESIGN.md仍写异步副本,与当前 Raft 源码不一致。
案例 1:单节点必须带 data-dir 和 key
Section titled “案例 1:单节点必须带 data-dir 和 key”docker run -p 8108:8108 \ -v /tmp/typesense-data:/data \ typesense/typesense:30.2 \ --data-dir /data --api-key=xyztsconfig 默认端口就是 8108。旧笔记里的 27.0 镜像不能代表本页合同。本页没有实际拉镜像。
案例 2:先建 fields,再搜必须 query_by
Section titled “案例 2:先建 fields,再搜必须 query_by”curl -H "X-TYPESENSE-API-KEY: xyz" -X POST 'http://localhost:8108/collections' \ -d '{"name":"books","fields":[{"name":"title","type":"string"},{"name":"author","type":"string"}]}'curl -H "X-TYPESENSE-API-KEY: xyz" -X POST 'http://localhost:8108/collections/books/documents' \ -d '{"title":"Designing Data-Intensive Applications","author":"Martin Kleppmann"}'curl -H "X-TYPESENSE-API-KEY: xyz" \ 'http://localhost:8108/collections/books/documents/search?q=desigining&query_by=title'desigining 对 Designing 是 1 个编辑;Designing 长度 ≥ 4,默认允许 1 typo。不要省略 query_by。
案例 3:向量字段不要塞进 query_by
Section titled “案例 3:向量字段不要塞进 query_by”{ "name": "embedding", "type": "float[]", "num_dim": 384}源码在普通 query_by 碰到非 auto-embedding 向量字段时会拒绝,并要求改用 vector_query。维度必须等于 schema 里的 num_dim。
- 把
type: auto当成无 schema:collection 仍然必须提交fields;auto只推迟类型决定。 - 默认 typo 阈值和 Meilisearch 不同:Typesense 是 4 / 7,不是 5 / 9;「大约 1–2 个字符」这种说法太粗。
- 信任 DESIGN.md 的异步副本:30.2 集群路径是 Raft。
--nodes配不齐会选不出 Leader。 - 管理员 key 进浏览器:前端必须用限定 collection / action 的 scoped key。
- 改字段类型当原地 PATCH:需要 drop/reindex 或走 alter 重建;别假设类型可以热改。
适用 vs 不适用场景
Section titled “适用 vs 不适用场景”适用:
- 要 Algolia 体验、又想自托管并接受 GPL-3.0
- 希望查询字段、类型和权重在 schema 里先钉死
- 单机到小 Raft 集群,并需要关键词 + 向量混合检索
不适用:
- 想先倒 JSON、后补 mapping 的动态 schema 工作流 → 看 meilisearch
- 日志分析 / 重型聚合 → 看 elasticsearch / opensearch
- 不能把全量倒排放进内存,又不愿拆 collection
- 已深度绑定 Elasticsearch DSL,迁移成本高于收益
固定版本边界
Section titled “固定版本边界”- 本文绑定
typesense/typesense@d45d46ba...,GitHub release / tag 为v30.2。 - README 里的 RAM / QPS 数字是项目自述,未在本环境复测。
DESIGN.md只作历史动机,不以它覆盖 Raft 实现。- 本文未编译、未启动、未发请求,状态保持
UNVERIFIED。
- schema-first 换来的是可预测查询,不是零配置——少写
query_by会在引擎里直接失败。 - 默认 typo 是带长度门槛的数字,不是「大概能容错」。
- 设计文档会过期——HA 合同以
raft_server.cpp为准。 - 向量和关键词是两条 API——
num_dim字段走vector_query。
- 只传
q=iphne、不传query_by,固定 30.2 会怎样? - 词长 5 的
iphne,默认最少几个编辑距离内能进 typo 候选?它和 Meilisearch 1.53.1 的oneTypo=5一样吗? - 三节点少写一个 peer,
DESIGN.md说的「异步拉副本」还能解释当前源码吗?
检查点:
- 非通配搜索返回
Missing query_by parameter。 - 默认
min_len_1typo=4,5 字母词允许 1 typo;与 Meilisearch 的 5 / 9 门槛不同。 - 不能。当前 HA 是 braft,配不齐会选不出 Leader。
- 固定源码:typesense/typesense —— 本文绑定提交
d45d46baf3996d1de8bf96a87f375cfb43691560 - 官方文档:typesense.org/docs
- 对比阅读:meilisearch —— 同赛道、更偏动态字段的 Rust 搜索引擎
- elasticsearch —— 功能更全、运维更重的分布式搜索
- 适配器:typesense-instantsearch-adapter
- meilisearch —— 同定位的开源即时搜索;schema 策略更松
- elasticsearch —— 老牌分布式搜索;功能更全但配置更重
- milvus —— 专用向量数据库;Typesense 把向量塞进同一引擎
- postgresql —— 主存储;CDC 同步到 Typesense 做搜索是常见架构
- opensearch —— 需要重型搜索栈时的另一选项
- elasticsearch —— Elasticsearch — 分布式搜索引擎