seekdb 混合检索 RAG
目标
帮助开发者把“文档进入 seekdb、能被正确召回、性能可解释”这条链路做完整。优先给出可执行的 SQL、可验证的质量指标和明确的失败原因,不用模糊的“调大参数试试”。
适用边界
适用:
- 新建 seekdb 知识库、语义搜索或 RAG 检索层。
- 已有向量检索,但召回差、延迟高、过滤后结果异常。
- 需要同时使用向量、全文和标量条件。
- 需要在嵌入式、单机 server、Docker 或 OceanBase 分布式模式之间做选择。
不适用:
- 与向量检索无关的一般 MySQL 慢查询优化。
- 训练或微调 embedding 模型。
- 把 seekdb 当成纯内存向量库,只做进程内数组检索。
先定四个参数
动手写表之前,先确认以下信息。缺一项就可能导致后面返工:
| 项目 | 必须确认 | 常见错误 | | --- | --- | --- | | 部署形态 | 嵌入式、单机 server、Docker 或 OceanBase 分布式 | 本地 demo 用了嵌入式,上线却按 server 方式连接 | | 向量维度 | embedding 模型实际输出维度 | 建表写 384,模型输出 768 | | 距离度量 | 与模型和归一化策略一致 | 索引用 l2,查询却按 cosine 理解 | | 质量目标 | Recall@K、延迟、数据量、过滤条件 | 只看单条 demo 结果,没有查询集 |
向量维度在建表时固定。距离度量和 embedding 的归一化方式必须成套使用,不能只改其中一处。
最小数据模型
以下 schema 适合作为知识库起点。字段按业务增删,但 id、content、embedding 三个核心字段不要省。
CREATE TABLE articles (
id BIGINT PRIMARY KEY,
title VARCHAR(512),
content TEXT,
embedding VECTOR(384),
author_id BIGINT,
created_at DATETIME,
FULLTEXT INDEX idx_fts (content) WITH PARSER ik,
VECTOR INDEX idx_vec (embedding)
WITH (DISTANCE=l2, TYPE=hnsw, LIB=vsag)
) ORGANIZATION = HEAP;
实施要点:
VECTOR(384)中的 384 必须等于实际 embedding 维度。FULLTEXT ... WITH PARSER ik依赖实例可用的分词器。建表失败时先确认分词器是否已启用;不要假设所有部署都带ik。- 向量索引的
DISTANCE与查询函数必须一致。l2索引配l2_distance。 - 文档 ID 必须稳定。不要把数据库自增 ID 当作唯一的业务定位依据,除非写入和查询共用同一映射。
写入与切片
- 先清洗文本,再去重;重复文档会挤占 Top-K。
- 切片要保留可独立回答问题的语义,并记录
doc_id、chunk_index、标题、来源和权限字段。 - 批量写入,避免一行一次往返。
- embedding 在写入前完成,确认维度、类型和空值处理一致。
- 写入后立即抽一条新文档做检索,确认索引刷新和可见性符合预期。
如果业务要求“写入即可查”,不要用离线重建索引的思路设计;seekdb 的增量索引链路可以让新写入尽快可检索,但仍应实测写入到可查的延迟。
混合检索
纯向量检索
SELECT id, title,
l2_distance(embedding, '[0.12, 0.34, ...]') AS dist
FROM articles
ORDER BY dist APPROXIMATE
LIMIT 10;
向量 + 标量过滤
SELECT id, title,
l2_distance(embedding, '[0.12, 0.34, ...]') AS dist
FROM articles
WHERE author_id = 42
AND created_at > '2026-01-01'
ORDER BY dist APPROXIMATE
LIMIT 10;
向量 + 全文 + 标量
SELECT id, title,
l2_distance(embedding, '[0.12, 0.34, ...]') AS dist
FROM articles
WHERE MATCH(content) AGAINST('quarterly report')
AND author_id = 42
ORDER BY dist APPROXIMATE
LIMIT 10;
使用规则:
- 近似向量排序使用
ORDER BY <distance> APPROXIMATE,不要漏掉APPROXIMATE后再把结果当成 HNSW 性能。 - 先固定召回质量,再比较延迟。不能通过缩小候选集、降低 K 或跳过过滤条件来“优化”。
- 过滤条件的选择性会显著影响结果。分别测试“无过滤、宽过滤、窄过滤”,不要只测最好的一条。
- 需要同时比较语义和关键词时,优先让 seekdb 在同一查询里完成向量与全文条件,而不是客户端各查一次再手工拼结果。
HNSW 起点与调参
可以把以下值当作基线,而不是通用最优值:
M = 16
ef_construction = 256
ef_search = 200
调参顺序:
- 先用基线测 Recall@K 和 P95 延迟。
- 召回不足时,优先提高
ef_search,观察延迟代价。 - 构建质量不足时,再评估提高
ef_construction;它会增加构建成本。 M影响图连接密度和内存占用,不要和ef_search一起盲调。- 每次只改一个参数,记录数据量、维度、过滤条件和构建时间。
如果数据量、维度或过滤分布发生变化,旧参数不能直接复用。
质量与性能验证
至少准备 100 条真实查询;数据量很小或上线风险高时,用 300 到 500 条更稳。
- 用精确近邻或离线暴力计算生成 Top-K 真值。
- 对同一批查询计算
Recall@K = 命中真值的数量 / K。 - 分别记录无过滤、宽过滤、窄过滤下的召回率和延迟。
- 记录 P50、P95、QPS 和数据规模。
- 重复运行,保留原始结果,不只报最快一次。
- 每次改 schema、索引参数、切片策略或 embedding 模型后重新跑同一套查询集。
最低验收组合:
| 指标 | 作用 | | --- | --- | | Recall@K | 证明没有为了速度牺牲检索质量 | | P95 延迟 | 比平均值更能暴露尾延迟 | | 过滤后召回 | 暴露条件下推或候选集缩小的问题 | | 写入到可查延迟 | 证明增量写入和索引刷新符合业务 | | 索引构建耗时 | 评估重建和扩容成本 |
常见故障
| 现象 | 优先检查 |
| --- | --- |
| 插入报维度错误 | VECTOR(n)、模型输出维度、空向量 |
| 检索结果完全不相关 | embedding 是否同一模型、是否归一化、距离度量是否一致 |
| 有数据但查不到 | 写入是否提交、索引是否刷新、过滤字段值是否正确 |
| 过滤后结果变少且质量骤降 | 过滤条件选择性、候选集是否足够、执行计划是否下推 |
| 延迟远高于预期 | 是否误用了非近似排序、Top-K 是否过大、是否每次重建连接 |
| 建表失败 | ik 分词器是否可用、索引语法版本是否匹配 |
| 召回率虚高 | 查询集与文档重叠、真值集被泄漏、只测了简单查询 |
排查时先保留最小复现:同一批向量、同一查询、同一索引参数。不要同时改模型、切片和索引。
交付检查
提交或上线前确认:
- [ ] 部署方式、seekdb 版本和连接方式已写明。
- [ ] embedding 模型、维度、归一化方式和距离度量已写明。
- [ ] 建表 SQL、索引参数和分词器配置可复现。
- [ ] 有至少一组真实查询和 Recall@K 结果。
- [ ] 有无过滤、宽过滤、窄过滤三组延迟数据。
- [ ] 有写入后立即可查的验证记录。
- [ ] 已说明 CPU/内存、数据量、Top-K 和测试环境。
- [ ] 没有通过减少数据、降低 K 或删除过滤条件来制造性能提升。
参考
- seekdb 仓库:https://github.com/oceanbase/seekdb
- seekdb 文档:https://docs.seekdb.ai/
- pyseekdb:https://github.com/oceanbase/pyseekdb
微信扫一扫