Qdrant 中的多向量重排序表示
| 时间:30分钟 | 难度:中等 |
|---|
多向量表示(Multivector Representations)是 Qdrant 最强大的功能之一。然而,大多数人并没有有效地使用它们,导致了巨大的内存开销、缓慢的插入速度和计算资源的浪费。
在本教程中,你将了解如何有效地在 Qdrant 中使用多向量表示。
什么是多向量表示?
在大多数向量引擎中,每个文档由单个向量表示——这种方法适用于短文本,但处理较长的文档时往往比较吃力。单向量表示会对标记(token)级嵌入进行池化,这显然会导致部分信息的丢失。
多向量表示提供了一种更细粒度的替代方案,即使用多个向量(通常在标记或短语级别)来表示单个文档。这使得特定查询词与文档相关部分之间的匹配更加精确。这种匹配在像 ColBERT 这样的“后期交互”(Late Interaction)模型中尤为有效,它们保留了标记级嵌入并在查询时进行交互,从而得出相关性评分。

正如你稍后将在本教程中看到的,Qdrant 原生支持多向量,因此也原生支持后期交互模型。
为什么标记级向量很有用
有了标记级向量,ColBERT 等模型可以将特定的查询标记与文档中最相关的部分进行匹配,通过后期交互实现高精度的检索。
在后期交互中,每个文档被转换为多个标记级向量,而不是单个向量。查询也会被分词并嵌入为多个向量。然后,使用相似度函数 MaxSim 对查询向量和文档向量进行匹配。你可以在此处查看其计算方式。
在传统检索中,查询和文档被转换为单一嵌入,然后计算相似度。这属于“早期交互”,因为信息在检索前就被压缩了。
什么是重排序(Rescoring),为什么要使用它?
重排序包含两个步骤:
- 使用快速模型检索相关文档。
- 使用更准确但较慢的模型(如 ColBERT)对它们进行重排序。
为什么默认索引每个向量是一个问题
在多向量表示中(例如 ColBERT 等后期交互模型所使用的表示),单个逻辑文档会产生数百个标记级向量。在 Qdrant 中使用 HNSW 对这些向量中的每一个进行单独索引,可能导致:
- 高内存(RAM)占用
- 由于维护 HNSW 图的复杂性导致插入时间缓慢
然而,由于多向量通常用于重排序阶段(在进行第一次密集向量检索之后),因此通常不需要使用 HNSW 索引这些标记级向量。
相反,它们可以作为多向量字段存储(不使用 HNSW 索引),并在查询时用于重排序,这减少了资源开销并提高了性能。
有关此内容的更多信息,请查看 Qdrant 在我们的“使用 Qdrant 实现 PDF 检索规模化”教程中的详细分解。
使用 Qdrant,你可以完全控制索引的工作方式。你可以通过将 HNSW 的 m 参数设置为 0 来禁用索引。
from qdrant_client import QdrantClient, models
client = QdrantClient("https://:6333")
collection_name = "dense_multivector_demo"
client.create_collection(
collection_name=collection_name,
vectors_config={
"dense": models.VectorParams(
size=384,
distance=models.Distance.COSINE
# Leave HNSW indexing ON for dense
),
"colbert": models.VectorParams(
size=128,
distance=models.Distance.COSINE,
multivector_config=models.MultiVectorConfig(
comparator=models.MultiVectorComparator.MAX_SIM
),
hnsw_config=models.HnswConfigDiff(m=0) # Disable HNSW for reranking
)
}
)
通过在多向量上禁用 HNSW,你可以:
- 节省计算资源。
- 减少内存使用量。
- 加快向量上传速度。
如何使用 FastEmbed 生成多向量
让我们演示如何使用 FastEmbed 有效地使用多向量,它将 ColBERT 封装在一个简单的 API 中。
安装 FastEmbed 和 Qdrant
pip install qdrant-client[fastembed]>=1.14.2
分步指南:ColBERT + Qdrant 设置
确保 Qdrant 正在运行并创建一个客户端
from qdrant_client import QdrantClient, models
# 1. Connect to Qdrant server
client = QdrantClient("https://:6333")
1. 编码文档
接下来,编码你的文档
from fastembed import TextEmbedding, LateInteractionTextEmbedding
# Example documents and query
documents = [
"Artificial intelligence is used in hospitals for cancer diagnosis and treatment.",
"Self-driving cars use AI to detect obstacles and make driving decisions.",
"AI is transforming customer service through chatbots and automation.",
# ...
]
query_text = "How does AI help in medicine?"
dense_documents = [
models.Document(text=doc, model="BAAI/bge-small-en")
for doc in documents
]
dense_query = models.Document(text=query_text, model="BAAI/bge-small-en")
colbert_documents = [
models.Document(text=doc, model="colbert-ir/colbertv2.0")
for doc in documents
]
colbert_query = models.Document(text=query_text, model="colbert-ir/colbertv2.0")
2. 创建 Qdrant 集合
然后创建一个同时包含两种向量类型的 Qdrant 集合。请注意,我们为 dense(密集)向量保留了索引,但为将用于重排序的 colbert 向量关闭了索引。
collection_name = "dense_multivector_demo"
client.create_collection(
collection_name=collection_name,
vectors_config={
"dense": models.VectorParams(
size=384,
distance=models.Distance.COSINE
# Leave HNSW indexing ON for dense
),
"colbert": models.VectorParams(
size=128,
distance=models.Distance.COSINE,
multivector_config=models.MultiVectorConfig(
comparator=models.MultiVectorComparator.MAX_SIM
),
hnsw_config=models.HnswConfigDiff(m=0) # Disable HNSW for reranking
)
}
)
3. 上传文档(密集向量 + 多向量)
现在上传向量,设置 batch_size=8。虽然我们文档不多,但始终建议使用批处理。
points = [
models.PointStruct(
id=i,
vector={
"dense": dense_documents[i],
"colbert": colbert_documents[i]
},
payload={"text": documents[i]}
) for i in range(len(documents))
]
client.upload_points(
collection_name="dense_multivector_demo",
points=points,
batch_size=8
)
单次调用实现检索 + 重排序
现在让我们执行搜索
results = client.query_points(
collection_name="dense_multivector_demo",
prefetch=models.Prefetch(
query=dense_query,
using="dense",
),
query=colbert_query,
using="colbert",
limit=3,
with_payload=True
)
- 密集向量快速检索出前几个候选文档。
- Colbert 多向量使用标记级的
MaxSim进行细粒度精确重排序。 - 返回前 3 个结果。
结论
正确使用时,多向量搜索是向量数据库最强大的功能之一。在 Qdrant 中利用此功能,你可以:
- 原生存储标记级嵌入。
- 禁用索引以减少开销。
- 在一次 API 调用中完成快速检索和精确重排序。
- 高效扩展后期交互。
结合 FastEmbed 和 Qdrant 可以构建出生产就绪的 ColBERT 风格重排序流水线,且不会浪费资源。你可以在本地执行此操作,也可以使用 Qdrant Cloud。Qdrant 提供了易于使用的 API 来开启你的搜索引擎之旅,如果你准备好深入研究,请在 Qdrant Cloud 免费注册并开始构建。