真正做过企业级 RAG / 向量检索的人一定会遇到双引擎架构的核心难点:
Redis 先召回 → ES 再过滤,如果全部被过滤掉怎么办?
这叫:
Post-filter Recall Collapse(后过滤召回塌陷)
也是 Redis + ES 架构必须解决的问题。
下面我按 问题本质 → 为什么会发生 → 解决方案→兜底策略 讲清楚。
一、问题本质(发生了什么)
流程:
RedisSearch KNN Top50
↓
ES 权限过滤
↓
0 条结果 ❌
原因不是 Redis 搜错。
而是:
Top50 ≠ Top50 可访问文档
换句话说:
👉 语义最近 ≠ 用户有权限
举个真实例子
系统里:
| 文档 | 相似度 | 部门 |
|---|---|---|
| A | 0.99 | CEO |
| B | 0.98 | CEO |
| C | 0.97 | CEO |
| ... | ... | ... |
| Z | 0.80 | Finance |
用户是 Finance。
Redis 返回:
Top50 = 全是 CEO 文档
ES 一过滤:
空
二、为什么这是 ANN 系统天然问题
ANN(HNSW)目标只有一个:
最相似
它不知道权限。
所以:
权限分布越不均匀,问题越严重。
企业知识库里非常常见:
- 高层文档语义集中
- 普通员工权限少
三、工业界标准解法(⭐重点)
解决思路只有一个核心:
不要一次只召回固定 TopK
而是:
动态扩大召回范围
方案 1⭐:Oversampling + 回填机制 ✅
这是最常见方案。
Step 1:Redis 多召回
不要:
Top50
而是:
Top200 / Top500
因为你知道会被过滤。
Step 2:ES 过滤
假设:
200 → 只剩 8 条
Step 3:检测数量
如果:
result < target_k
触发:
二次召回
Step 4:扩大搜索范围
例如:
第一次 ef_runtime = 100
第二次 ef_runtime = 300
TopK = 500
再过滤一次。
在 HNSW 算法中,从 ef_runtime = 100 增加到 300,查询耗时通常不会线性增加 3 倍,但会表现出明显的延迟增长。根据在 RedisSearch 环境下的实测经验,增加比例通常在 1.5倍 到 2.5倍 之间。
TopK 仅决定返回数量,而 ef_runtime 决定 HNSW 的搜索深度。后过滤召回塌陷的根因是搜索空间不足,因此扩大 ef_runtime 比单纯增加 TopK 更有效。
伪代码
java
k = 50
recall = 200
while(true){
candidates = redis.knn(recall)
results = es.filter(candidates)
if(results.size >= k)
break
recall *= 2
}
✅ 优点:
- 简单
- 稳定
- 工业标准
方案 2⭐:权限感知 Oversampling
观察:
不同用户过滤比例不同。
例如:
| 用户 | 过滤率 |
|---|---|
| admin | 5% |
| 普通员工 | 80% |
| 外包 | 95% |
于是:
动态计算:
recall_k = target_k / (1 - filter_ratio)
例:
目标50
预计过滤80%
→ 50 / 0.2 = 250
Redis 直接召回 250。
必须同时保证:ef_runtime ≥ recall_k
方案 3⭐:权限预分桶(工业优化)
核心思想:
不要让 Redis 完全不知道权限。
但又不能破坏 HNSW。
怎么办?
做"软隔离"索引
例如:
Redis 建多个索引:
doc_idx_public
doc_idx_finance
doc_idx_hr
查询时:
finance 用户 → 优先搜 finance index
必要时 fallback 全局索引。
好处:
✅ 不破坏图结构
✅ 召回稳定
✅ ES过滤压力下降
方案 4⭐:Filter-aware ANN(权限感知向量空间)
在 embedding 中加入权限特征:(1.向量拼接;2.训练模型)
embedding = semantic + access embedding
通过将权限信息编码进向量空间,使可访问文档在语义空间中天然更接近查询,从而减少后过滤带来的召回浪费,本质是将"过滤问题"转化为空间几何问题。
让:
无权限文档在向量空间更远
等于:
ANN 自然避开。
但实现复杂,有向量污染风险,权限维度过强,会导致语义被破坏,搜索质量下降。
四、Safety Fallback(安全兜底策略)
Fallback 1:降低 keyword 约束(放宽条件)
原查询
部门=财务
AND
关键词=报销流程2024新版
可能太严格:
0结果
fallback 做什么?
逐步放松条件:
部门=财务
AND
关键词=报销流程
再不行:
关键词=报销
本质:
Precision ↓
Recall ↑
先保证有结果。
✅ 类似 Google:
你搜错字时:
"Showing results for ..."
Fallback 2:返回"权限允许的次优语义"
这是向量检索里的核心兜底。
情况:
最相似文档 → 无权限
过滤后:
空
fallback 做法:
扩大语义范围:
Top50 → Top300 → Top1000
只要:
语义还算相关 + 有权限
就返回。
例子:
用户问:
差旅报销标准
最相关文档是总部制度(无权限)。
fallback 返回:
部门差旅制度(相似但次优)
目标:
有用 > 完美
Fallback 3(RAG ⭐)
不是只靠检索。
而是改变 LLM回答策略。
当系统检测:
高置信文档不存在
不要让 AI 硬答。
而是生成:
未找到完全匹配内容,
但以下相关制度可能有帮助:
然后引用次相关文档。
这叫:Graceful Degradation(优雅降级)
用户体验从:
❌
没找到。
变成:
✅
没完全匹配,但这些可能相关。