Qdrant

Candidate Depth: How Much Retrieval Is Enough?

8.5内容质量

TL;DR · AI 摘要

候选深度优化可显著提升搜索效果,但需结合数据集规模和系统配置进行实验验证。

核心要点

  • 测试候选深度时,从100/200开始,但需根据分片数和重排序器调整实际值
  • 提升hnsw_ef前应比较近似搜索与精确搜索的召回率,避免无效延迟
  • 内存受限时优先测试量化压缩,而非直接减少候选深度

结构提纲

按章节快速跳转。

  1. 调整候选深度前需验证索引状态并建立基准线

  2. 候选深度是检索阶段传递给后续排序阶段的候选数量

  3. 通过对比不同候选深度的nDCG@10变化评估效果

  4. 根据数据集规模和系统资源选择最佳候选深度

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • 候选深度优化
    • 核心机制
      • 多阶段检索流程
      • RRF融合策略
    • 实验方法
      • nDCG@10指标
      • 分片级限制
    • 优化策略
      • 量化压缩优先
      • 召回率-延迟平衡

金句 / Highlights

值得收藏与分享的关键句。

  • 在SciFact数据集上,候选深度从10增加到500时,最佳可能得分提升0.103,而当前得分仅提升0.008

    第4段

    ⬇︎ 下载 PNG𝕏 分享到 X
  • Qdrant默认的RRF设置下,每个预取的前几名对融合得分贡献远大于尾部候选

    第5段

    ⬇︎ 下载 PNG𝕏 分享到 X
  • DBPedia-entity数据集显示,候选深度增加使最佳可能得分提升0.282,但当前得分仅提升0.003

    第4段

    ⬇︎ 下载 PNG𝕏 分享到 X
#Qdrant#检索系统#候选深度#多阶段搜索
打开原文

候选深度:多少检索量足够? - Qdrant

返回搜索质量

候选深度:多少检索量足够?

Dylan Couzon

·

2026年8月21日

在调整候选深度之前,使用调优前检查验证索引状态并建立基准线。以下所有内容均以该基准线为参照。

候选深度是检索阶段传递给后续排序阶段的候选数量。只有当后续阶段能够利用这些额外候选时,该参数才有意义。在混合搜索中,每个预取操作都带有自己的限制,嵌套预取的多阶段查询会在每个层级设置深度。在纯密集或纯稀疏搜索中,它是传递给重排序器或其他下游阶段的候选数量。

简要说明

  • 为下游排序阶段在100和200处测试限制值。将这些值视为起点而非生产默认值:限制值针对每个分片生效,重排序器会对每个候选进行评分。
  • 在提高hnsw_ef之前,将近似搜索的召回率与精确搜索进行对比。如果召回率已趋于平稳,更大的值只会增加延迟而不会提升召回率。
  • 如果内存是限制因素,请在降低候选深度前测试量化。量化覆盖集合设置。

更多候选可能提升最佳可能得分

首先测量检索到的候选与流水线返回顺序之间的差距。使用带标签的查询集对候选集进行评分,假设其完全有序。这是任何后续排序可能达到的最佳得分。将其与相同查询的当前得分进行对比。在这些混合测量中,当前得分是相同候选上的融合nDCG@10。nDCG@10对前10个结果进行评分,并对靠近顶部的相关文档给予更高权重。

假设某个查询检索到三个相关文档,融合排序将它们排在第4、30和180位。当前得分仅看到第4位的文档,因为另外两个位于前10名之外。最佳可能得分会重新排序这些候选,将三个文档都置于顶部。任何后续排序阶段都无法在已检索的候选基础上表现更好。

对于混合搜索,对密集和稀疏预取的并集进行评分。对于单预取流水线,对传递给下游阶段的候选进行评分。

每个数值表示从limit=10到500时nDCG@10的变化。

数据集 | 最佳可能变化 | 当前得分变化 --- | --- | --- SciFact | +0.103 | +0.008 ArguAna | +0.121 | +0.002 WANDS | +0.124 | +0.007 CodeSearchNet | +0.149 | +0.010 DBPedia-entity | +0.282 | +0.003

表格背后的完整分析。在所有数据集中,最佳可能得分在每个深度步骤都会上升,而融合返回的得分几乎保持平稳。

最佳可能得分的变化随着语料库规模在五个数据集上从SciFact的5,183个文档到DBPedia-entity的100,000个文档而增加,而当前得分变化保持平稳。规模和领域在这里共同变化,因此随着自己的集合增长需要重新测量差距。

使用Qdrant的默认RRF时,每个预取中的前几名对融合得分的贡献远大于尾部。提高限制值可以添加候选而不改变前10名,或替换更相关的结果。融合得分在更深的层级不一定是更高的:CodeSearchNet在limit=200时达到峰值,在500时更低,DBPedia-entity在50时达到峰值。其他融合方法可能对这些候选进行不同排序。融合调优展示了如何在自己的标签上测试它们。

初始限制值建议设置在100到200之间,随后可根据自身标签数据测试更大的值。重排序器可以使用新增的候选结果,而公式查询可以从负载字段中对这些相同候选结果进行重新评分。

提高限制值会增加检索工作量。如果后续有重排序器,也会增加重排序器需要评分的候选数量。在我们的单分片测试中,将限制值从10提升到500,使中位数延迟增加了37%至43%。这些结果指明了方向,但不构成可移植的比例关系。请在您自己的p95预算、并发量和分片扇出设置下测量实际变化。

仅在召回率仍在提升时增加hnsw_ef

对于密集向量,limit参数决定了密集阶段返回的候选数量,而hnsw_ef参数决定了HNSW图遍历的宽度,这在召回率和延迟之间进行权衡。当后续阶段能够使用更多候选时,应将limit参数与您的标签进行对比测量;将hnsw_ef参数与精确搜索进行对比,以判断遍历是否仍会遗漏邻居。

hnsw_ef参数扩大了搜索访问的节点集合,但不会增加结果数量。在此示例中,更宽泛的遍历能够找到狭窄遍历遗漏的邻居,并取代最弱的结果。

在您自己的数据上运行相同检查,将limit参数设置为密集阶段或密集预取使用的值。

code
import
time
from
qdrant_client
import
QdrantClient
,
models
client
=
QdrantClient
(
url
=
"https://YOUR-CLUSTER.cloud.qdrant.io"
,
api_key
=
"<your-api-key>"
,
)
# 您自己的查询向量,使用构建集合时的模型进行嵌入。
queries
=
[
...
]
# 您的密集阶段或密集预取使用的限制值。
LIMIT
=
100
def
top_ids
(
vector
,
**
search_params
):
return
{
point
.
id
for
point
in
client
.
query_points
(
collection_name
=
"products"
,
query
=
vector
,
using
=
"dense"
,
limit
=
LIMIT
,
search_params
=
models
.
SearchParams
(
**
search_params
),
)
.
points
}
# 全扫描是真实结果,仅运行一次:它不依赖hnsw_ef。
truth
=
[
top_ids
(
vector
,
exact
=
True
)
for
vector
in
queries
]
for
ef
in
(
16
,
64
,
128
,
256
,
512
):
found
=
0
started
=
time
.
perf_counter
()
for
vector
,
wanted
in
zip
(
queries
,
truth
):
found
+=
len
(
top_ids
(
vector
,
hnsw_ef
=
ef
)
&
wanted
)
elapsed_ms
=
(
time
.
perf_counter
()
-
started
)
/
len
(
queries
)
*
1000
print
(
ef
,
found
/
(
LIMIT
*
len
(
queries
)),
elapsed_ms
)

exact=True执行全扫描。以下两列数据来自对单分片SciFact集合的测试,覆盖50个查询,从客户端计时以包含网络往返时间:

code
hnsw_ef

精确召回率

每查询毫秒数

16

0.986

1.98

64

0.993

128

0.999

2.18

256

1.000

2.45

512

2.25

在这些五个数据集上,将hnsw_ef从16提升到64、128和512(深度为200),融合nDCG@10最多仅变化0.0022。候选集的召回率最多变化0.0040。在预取限制为200的五次混合请求中,中位数延迟在4%到49%之间增长。当图已饱和时,更宽泛的搜索预算几乎等同于纯成本。

在您的集合中,选择最低的hnsw_ef值,使其在延迟预算内达到召回率目标。当从第一个值开始召回率趋于平稳时,保持当前hnsw_ef值并确认Qdrant已构建HNSW图。Qdrant在段落通过默认索引阈值后会构建该图,较小的段落会使用穷举搜索(此时hnsw_ef无影响)。预调优检查展示了如何确认图的存在。

饱和度是您图结构本身的属性。这些集合最多包含10万份文档,以单次批量方式构建,未经过滤和量化处理。我们在完整的4635922份文档的DBPedia-entity集合上进行了相同检查,结果返回了精确前10名的95.7%:约4%的真实最近邻从未被检索回来。

如果hnsw_ef无法达到您的召回率目标,m参数会增加图结构的连接数,ef_construct参数则在构建图时扩大搜索范围。这两个参数都能提升索引可实现的召回率,且修改任一参数都会重建HNSW索引。过滤条件是限制遍历范围的另一个因素:ACORN搜索算法默认处于禁用状态,其启用标志允许在过滤条件排除直接图邻居时,搜索扩展到更远的节点。ACORN的运行速度可能比默认设置慢2到10倍,因此仅在多个严格负载过滤条件组合时才建议使用。

当内存成为限制因素时

limit是查询时的预算参数。降低该参数会减少检索工作量和后续阶段接收的候选集数量,同时保持集合在磁盘和内存中的占用空间不变。量化处理会改变这种占用空间,因此在因内存原因降低limit之前,应在您的标签数据上先测试量化效果。Qdrant的TurboQuant功能会比较不同存储类别的表现。

Int8标量量化以float32向量四分之一的存储空间保存压缩副本。我们用该方法重建了SciFact和DBPedia-entity集合,以测量密集型前10名的一致性以及对最终混合结果的影响。

设置

未量化时的密集型前10名一致性

融合结果

code
nDCG@10

变化

无重评分

0.984

-0.0001至+0.0000

code
rescore=True

0.997至1.000

,

code
oversampling=4

0.998至1.000

+0.0000至+0.0001

量化处理确实会重新排序候选列表:在未进行重评分时,密集型预取的前10名中有1.6%发生了移动,但几乎没有任何变化影响到我们的融合结果,因为默认的RRF融合使用了排名。重评分会用原始向量重新评分短名单,oversampling会为这一步骤获取额外的压缩候选以供选择,在SciFact数据集上重评分恢复了未量化版本的前10名。

该测量结果涵盖了在5000和100000份文档的单个分片上进行的int8标量量化。二值量化是一种更为激进的权衡方式,我们在此未进行测试。

将量化与降低limit进行比较。在我们的测试中,将深度从500降低到10,使中位数延迟减少了27%到30%,同时保持占用空间不变。int8量化以四分之一的存储空间保存向量,在任一方向上最多使融合nDCG@10变化0.0001。两者相比,量化是减少向量在内存中占用空间的更优选择。

当集合规模超过内存容量时,问题就不再是应该获取多少候选,而是哪些结构应该保留在内存中。内存布局和重评分在460万个向量上测量了这一边界,并解释了布局规则。

下一步需要调整的参数

最佳得分与当前得分之间的差距告诉您下一步实验应专注于排序还是检索。较大的差距意味着相关候选已存在但排名不够高。在混合搜索中,应测试融合设置;在任何包含后续阶段的流水线中,应测试是否可以通过重排序器恢复差距。较小的差距意味着排序结果已接近候选集允许的最佳水平,此时应改进候选集本身。

接下来,如果您使用混合搜索,请在您已检索到的候选集上调整融合参数。