跳至内容
15.5 混合检索与排序验证

15.5 混合检索与排序验证

混合检索的价值来自失败互补,不来自方法数量。每加一路候选,都同时增加 召回机会、查询成本和排序污染。

本节先保留每路独立排名,再用只依赖名次的 RRF 合并;最后用同一标注集找出 收益与退化。

15.5.1 词法、模糊和语义候选合并

每一路先独立成立

本章先建三个排名视图:

lexical_ranking
fuzzy_ranking
vector_exact_ranking

共同输出:

query_id
product_id
result_rank
score

向量视图还保留 distance。每路都使用相同资格条件:

p.active
AND (
  q.category_filter IS NULL
  OR p.category = q.category_filter
)

如果三路过滤不同,融合后的差异既可能来自检索能力,也可能来自候选资格, 指标无法解释。授权、租户和生命周期过滤应在每路都保持同一语义。

source rank 是融合接口

本章把每路前四名规范成:

SELECT
  query_id,
  product_id,
  'lexical' AS source_name,
  result_rank,
  1.0 AS source_weight
FROM shop_ch15.lexical_ranking
WHERE result_rank <= 4

UNION ALL
...

为什么用 UNION ALL

  • 同一商品被多路召回是有价值的支持证据;
  • 普通 UNION 会按整行去重,但 source/rank 不同,本来也不会合并;
  • 后续应显式按 (query_id, product_id) 聚合,而不是让 set operator 隐式决定。

每路只提供 candidate,不应在视图内部偷偷调用另一路。这样才能:

  • 单独关闭某一路;
  • 比较增量质量;
  • 观察每路延迟;
  • 定位失败;
  • 给最终结果解释 source。

候选深度是资源预算

本章:

source_depth = 4
final_depth  = 3

它只适合 17 行夹具。生产候选深度影响:

recall ceiling
union cardinality
dedup/sort work_mem
re-ranker cost
network payload
tail latency

应按 query segment 做曲线:

depth = 10,20,50,100
  -> Recall@final_K
  -> NDCG@final_K
  -> P95/P99
  -> candidate count after dedupe

当一条 source 加深只增加重复/低质量对象而不提高最终 recall,就没有继续 扩大的理由。

空结果与低分结果不同

全文视图只输出 @@ 命中对象,所以 q02/q07 没有行。

模糊视图对全部合格对象排名,即使低分也有行。这是评估 fixture 的有意设计, 生产则应加候选门槛。否则:

no lexical evidence
+ zero fuzzy evidence
+ weak vector evidence

仍可能被融合成一个看似精确的总排名。

候选接口应区分:

source unavailable
source returned no qualified candidate
source timed out
source returned candidates

超时不能被当作“该方法认为没有相关结果”,否则线上质量诊断会混淆能力与 故障。

去重后的 evidence 仍要保留

一个商品多路出现时,最终记录应能表达:

product 1:
  lexical rank 1
  fuzzy rank 1
  vector rank 3

本章 hybrid_rrf_ranking.sources 用 text array 保存 source 名称,完整排名 仍可回查原视图。生产可把细节写进响应 trace、审计表或离线日志,不必塞进 业务表永久保存。

SQL 内混合的边界

在 PostgreSQL 内完成候选和融合有明显优势:

  • 与事务快照、状态和权限过滤同处一处;
  • 少一次跨系统网络与数据同步;
  • SQL 可以直接被 EXPLAIN、统计和审计;
  • 小中规模问题结构简单。

但如果模型推理、复杂学习排序、跨多源索引或独立扩缩容占主导,融合可能更 适合应用/检索服务。决策标准不是“SQL 能不能写”,而是:

failure domain
data freshness
latency budget
operational ownership
quality evidence
exit cost

15.5.2 分数归一、倒数排名融合与重排

为什么不能直接加原始分数

本章三路原始值:

ts_rank_cd(..., 32)  -> bounded cosmetic score
trigram similarity  -> character overlap in 0..1
vector L2 distance  -> non-negative distance, lower is better

即使都变换到 0–1,也没有共同概率含义。下面只是拍脑袋:

0.4 * lexical_score
+ 0.3 * fuzzy_score
+ 0.3 * (1 / (1 + vector_distance))

它会隐含:

  • 三种尺度的形状可比;
  • 一单位变化意义相同;
  • 权重对所有 query segment 相同;
  • 极值与分布稳定;
  • 模型升级后仍适用。

若要线性加分,应使用标注数据做 calibration/learning-to-rank,并在 fresh holdout 上验证。

RRF 只比较名次

Reciprocal Rank Fusion 对 document (d):

[ RRF(d)=\sum_{s \in sources} \frac{w_s}{k+rank_s(d)} ]

其中:

  • (rank_s(d)) 是 document 在 source (s) 中的名次;
  • 未出现在 source candidate depth 内就没有该项;
  • (w_s) 是可选 source 权重;
  • (k) 平滑头部名次差。

本章:

k = 60
w_lexical = w_fuzzy = w_vector = 1
source_depth = 4

SQL:

SELECT
  query_id,
  product_id,
  sum(
    source_weight / (60.0 + result_rank)
  )::double precision AS score,
  array_agg(source_name ORDER BY source_name) AS sources
FROM source_rank
GROUP BY query_id, product_id;

再:

row_number() OVER (
  PARTITION BY query_id
  ORDER BY score DESC, product_id
)

pgvector 官方 Hybrid Search 小节也把 RRF 或 cross-encoder 列为融合路径; 参见 pgvector 0.8.4 Hybrid Search

k 不等于返回 K

RRF 中的小写 (k) 是平滑常数,不是最终结果数。增大它会让头部第 1 与 第 4 的单路差距变小,多路共同支持相对更重要;减小它会放大头部名次差。

不要因为经典示例常用 60 就把它当数学常数。本章用 60 是显式 proposal 参数。调参时要同时版本化:

rrf_k
source weights
source candidate depths
tie breaker
final K

并报告每个 query segment 的变化。

RRF 的优点与盲区

优点:

  • 不要求原始 score 同尺度;
  • 一个 document 被多路高排会自然加分;
  • 实现与解释简单;
  • source 新旧版本可独立。

盲区:

  • 丢失 source 内分数差距:第 1 比第 2 好很多或只好一点都看不出来;
  • candidate depth 外信息完全消失;
  • 弱 source 也会投票;
  • 不直接使用业务新鲜度、库存、质量、安全等 feature;
  • 不会自动学会 query-dependent weight。

所以 RRF 是可靠 baseline,不是排序终点。

source weight 要谨慎

加权 RRF:

source_weight / (k + rank)

很容易实现,但“vector 权重 1.5”必须由指标支持。若某一路只在错拼 query 有帮助,更合理的方向可能是:

  • query segment 路由;
  • 以置信门槛启用;
  • 学习排序;
  • 或扩大/收窄该路 candidate depth。

全局权重会把局部收益和局部伤害平均掉。

两阶段重排

当候选生成需要快、最终质量需要更多 feature:

stage 1:
  FTS/trigram/ANN -> union top 100

stage 2:
  exact vector
  + structured business features
  + cross-encoder or learned ranker
  -> top 10

关键合同:

  • 第一阶段 recall 必须足够;被漏掉的对象无法被重排救回;
  • 第二阶段有独立超时与 fallback;
  • 重排模型有版本、输入与许可证;
  • fallback 次序仍经过评估;
  • 在线日志保留 candidate pool 与最终选择。

外部 cross-encoder 可能最贵、最慢、最敏感,不要让数据库事务长时间等待 网络推理。常见做法是在数据库取候选后结束事务,再用版本化快照数据重排; 若新鲜度要求更高,需要明确一致性策略。

精确重排近似候选

ANN 常用模式:

WITH candidate AS MATERIALIZED (
  SELECT product_id, embedding
  FROM product
  ORDER BY embedding <-> :q
  LIMIT 100
)
SELECT product_id
FROM candidate
ORDER BY embedding <-> :q, product_id
LIMIT 10;

第二层用原向量精确重排 candidate,可以修正量化/子向量/relaxed ordering 内部次序,却不能召回第一层没选中的对象。最终仍要用 exact-relative recall 评估 candidate generator。

15.5.3 用标注集比较质量,不用单个“好看案例”

结果表只是起点

运行:

PG36_EVIDENCE_DIR="$PWD/evidence/ch15" \
  ./static/labs/ch15/task.sh evaluate

得到 quality-summary.csv

strategy,queries,precision@3,recall@3,mrr@3,mean_ndcg@3,min_ndcg@3
fuzzy,8,0.916667,0.916667,1.000000,0.942881,0.842828
hybrid_rrf,8,1.000000,1.000000,1.000000,0.962929,0.759192
lexical,8,0.291667,0.291667,0.750000,0.613043,0.000000
vector_exact,8,1.000000,1.000000,1.000000,0.817314,0.631039

平均值显示 hybrid 在本集合上 mean NDCG 最高,但不能到此结束。

看每个 query 的退化

quality-detail.csv 暴露:

q02:
  fuzzy NDCG@3      = 0.842828
  hybrid NDCG@3     = 0.759192

q02/q07:
  lexical result_count = 0
  lexical NDCG@3       = 0

q02 的前三名:

fuzzy: 1,3,2
hybrid: 3,2,1

商品 1 是 grade 3,纯 fuzzy 放第一;混合受到另外两路名次影响,把 grade 2 商品 3 放第一。因此:

mean improved
does not imply every intent improved

生产 release gate 应同时有:

  • aggregate threshold;
  • 关键 query segment threshold;
  • worst-case/低分位保护;
  • 不允许退化的 canary query;
  • filter/security hard assertions。

四种策略各告诉了什么

全文

high precision when exact lexical evidence exists
zero results for two typo queries

它不是“差”,而是 candidate role 较窄。单独 NDCG 低不等于应删除;它可能 提供最可解释、最精确的头部证据。

模糊

excellent typo recovery on this title corpus
misses one relevant result in q04 and q06

它证明字符相似的价值,也暴露业务邻近但字面不近的盲区。

精确向量

all three relevant objects recalled for every query
mean NDCG lower because grade ordering is imperfect

这是“召回好、排序不够好”的典型 candidate generator。

RRF

full recall and best mean NDCG
one typo query worse than fuzzy

它是当前 proposal baseline,而不是普遍胜者。

8 个查询没有统计外推力

本章数字可以证明:

  • SQL 指标计算可复现;
  • fixture 改动会被发现;
  • 策略之间确有可解释差异;
  • 反例和 filter guard 可持续回归。

不能证明:

  • 真实流量的总体质量;
  • 各语言/用户/类别公平;
  • 指标提升具有统计显著性;
  • 点击、转化或任务完成提高;
  • 线上 P95/P99;
  • embedding 模型优劣。

真实评估集应从代表性查询日志和业务任务构建,保留 fresh holdout。对线上 A/B:

pre-register primary metric and guardrails
randomize at a safe unit
control novelty and carry-over
track no-result and latency
audit exposure/authorization
set stop conditions

离线相关性是上线前门槛,不是用户价值的最终替代。

指标 SQL 也要审校

本章 quality_per_query 明确建立所有策略 × 所有查询的 grid,再 LEFT JOIN 返回结果。这样没有返回行的 query 仍有 0 分;若从 ranking 表直接 GROUP BY, 空 query 会消失,平均值被悄悄抬高。

它还:

  • 固定前三;
  • 分母使用 3,不使用实际 result count;
  • 对未标注 result 记 grade 0;
  • 用 grade 计算 DCG 与 ideal DCG;
  • 稳定按 grade/product id 生成理想排序。

审查 retrieval 指标实现时,重点找:

missing queries silently dropped
precision denominator changed
unjudged treated inconsistently
ties unstable
ideal ranking calculated from retrieved set
approximate results used as truth

这些 bug 往往比检索算法差异更大。

发布结论的正确句式

可以写:

ch15-search-v1 的 8 个冻结查询、24 条分级标注和精确向量 golden 下,等权 RRF 的 mean NDCG@3 为 0.962929,并覆盖全部标注相关对象; q02 相对纯 fuzzy 退化,必须保留分段监控。结果不外推到真实语料。

不要写:

混合检索准确率 96%,优于其他方案。

后一句把 NDCG 当 accuracy,把小合成集当总体,也隐去了反例。


上一节:可复现的向量检索 · 返回本章目录 · 下一节:扩展部署与运行代价 · 查看全书目录 · 查看索引中心

最后更新于