Files
zhuangang/topics/backend/elasticsearch/scenarios/kb-search-sync.md
T

4.3 KiB
Raw Blame History

id, title, type, domain, stack, tags, level, prerequisites, est_hours, related, week
id title type domain stack tags level prerequisites est_hours related week
backend.elasticsearch.scenario.kb-search-sync 知识库混合检索:数据库到 ES 的同步、权限过滤、分词词典和检索效果评估 scenario backend
elasticsearch
postgresql
mq
rag
混合检索
数据同步
CDC
outbox
权限过滤
IK 词典
召回率
intermediate
backend.elasticsearch.search-hybrid
ai.rag.hybrid-rerank
2.5
backend.elasticsearch.interview
ai.rag.scenario.permission-aware-kb
backend.mq.reliability
6
14

知识库混合检索:数据库到 ES 的同步、权限过滤、分词词典和检索效果评估

业务背景与问题

企业知识库 RAG 一开始只用了 pgvector 向量检索,问题:

  1. 用户搜产品型号、错误码、合同编号,向量检索经常找不到;
  2. 文档在后台修改后,问答仍引用旧内容;
  3. 偶尔检索到用户无权查看的部门文档;
  4. 每次调整分词或检索参数,不知道效果是变好还是变差。

约束

  • 文档的主数据在 PostgreSQL(含权限)。
  • 修改后 1 分钟内可检索到。
  • 不能引入复杂的大数据组件。

方案设计

  1. 检索层:ES 索引同时保存分块的文本(IK 分词 + 业务词典:产品型号、内部术语)和向量;查询时 BM25 和 kNN 两路检索,应用层 RRF 融合,再用重排模型取前 5。
  2. 权限:每个分块冗余 tenant_id、dept_ids、visibility 等 keyword 字段;查询时把当前用户的权限转换成 filter,两路检索都带上;返回前再按数据库做一次最终校验(防止同步延迟导致的权限变更未生效)。
  3. 同步:
    • 文档修改时在同一个数据库事务中写入 outbox 表;
    • 后台任务读取 outbox 发到消息队列;
    • 消费者重新分块、计算向量、按“文档 id + 分块序号”写入 ES(幂等),删除多余的旧分块;
    • 失败重试,超过次数进入死信并告警;
    • 每天对账:数据库与 ES 的文档版本号比对,修复差异。
  4. 变更映射:通过别名 + 新索引重建,不停机。
  5. 评估:维护一份标注集(问题 → 应该命中的文档),每次调整分词词典、权重、num_candidates 都计算召回率@K 和 MRR,比基线差就不上线。

关键代码

权限条件同时作用于两路检索:

def acl_filter(user) -> list[dict]:
    return [
        {"term": {"tenant_id": user.tenant_id}},
        {"bool": {"should": [
            {"term": {"visibility": "public"}},
            {"terms": {"dept_ids": user.dept_ids}},
        ], "minimum_should_match": 1}},
    ]

kw = es.search(index="kb", size=20, query={"bool": {"must": {"match": {"text": q}}, "filter": acl_filter(user)}})
vec = es.search(index="kb", size=20, knn={"field": "vec", "query_vector": embed(q), "k": 20,
                                          "num_candidates": 200, "filter": acl_filter(user)})
candidates = rrf(ids(kw), ids(vec))[:20]
top5 = rerank(q, candidates)[:5]

完整可运行的基础示例:examples/hybrid-search;权限设计详见权限感知知识库。

取舍

选择 优点 缺点
ES 做混合检索(本方案) 关键词能力强、过滤和聚合成熟、向量也支持 多一套集群和同步链路
只用 pgvector + PG 全文检索 组件少、强一致 中文分词和相关性调优能力弱一些
专用向量库 + ES 各自最强 两套检索系统,复杂度最高

易错点

  • 只同步新增和修改,忘记处理删除和权限变更。
  • 消费者不是幂等的,重试后出现重复分块。
  • 业务词典更新后没有重建索引(已写入的数据仍按旧分词)。
  • 只凭几个例子判断效果,没有标注集和指标。

面试怎么讲

“纯向量检索对型号、错误码这种精确词召回很差,我们引入 ES 做混合检索:IK 分词加业务词典,BM25 和 kNN 两路召回,应用层 RRF 融合后再重排。权限字段冗余到每个分块,作为 filter 同时作用于两路检索,返回前再校验一次。同步用 outbox + 消息队列,消费者按文档 id+分块号幂等写入,每天对账。每次调参都用标注集跑召回率@K 和 MRR,比基线差不上线。”