如何使用 Qdrant 的稀疏神经检索模型 miniCOIL
miniCOIL 是一款开源的稀疏神经检索模型,它的作用就像是能够理解关键词上下文含义并据此进行结果排序的 BM25 检索器。
miniCOIL 的评分基于 BM25 公式,并根据查询词与文档中匹配关键词之间的语义相似度进行加权。$$ \text{miniCOIL}(D,Q) = \sum_{i=1}^{N} \text{IDF}(q_i) \cdot \text{Importance}^{q_i}_{D} \cdot {\color{YellowGreen}\text{Meaning}^{q_i \times d_j}} \text{,其中关键词 } d_j \in D \text{ 等于 } q_i $$
有关 miniCOIL 背后的原理,请参阅 “miniCOIL: on the road to Usable Sparse Neural Retrieval” 文章,或观看 “miniCOIL: Sparse Neural Retrieval Done Right” 演讲录像。
本教程将演示基于 miniCOIL 的稀疏神经检索与基于 BM25 的词汇检索相比表现如何。
何时使用 miniCOIL
当检索结果中必须包含精确的关键词匹配,且所有匹配项都需要根据关键词的上下文含义进行排序时。
如果结果应该在意义上相似,但表达方式不同且没有关键词重叠,你应该使用稠密嵌入(dense embeddings),或者在混合搜索设置中将其与 miniCOIL 结合使用。
设置
安装带有 fastembed 的 qdrant-client 集成。
pip install "qdrant-client[fastembed]"
然后,初始化 Qdrant 客户端。你可以使用 Qdrant Cloud 中的 免费集群 进行实验,或者通过 Docker 运行 本地 Qdrant 实例。
我们将在一组包含关键词“vector”和“search”(在不同语境下使用)的书籍和文章标题列表上运行搜索,以演示 miniCOIL 如何捕捉这些关键词的含义,这与 BM25 的方式截然不同。
数据集
documents = [
"Vector Graphics in Modern Web Design",
"The Art of Search and Self-Discovery",
"Efficient Vector Search Algorithms for Large Datasets",
"Searching the Soul: A Journey Through Mindfulness",
"Vector-Based Animations for User Interface Design",
"Search Engines: A Technical and Social Overview",
"The Rise of Vector Databases in AI Systems",
"Search Patterns in Human Behavior",
"Vector Illustrations: A Guide for Creatives",
"Search and Rescue: Technologies in Emergency Response",
"Vectors in Physics: From Arrows to Equations",
"Searching for Lost Time in the Digital Age",
"Vector Spaces and Linear Transformations",
"The Endless Search for Truth in Philosophy",
"3D Modeling with Vectors in Blender",
"Search Optimization Strategies for E-commerce",
"Vector Drawing Techniques with Open-Source Tools",
"In Search of Meaning: A Psychological Perspective",
"Advanced Vector Calculus for Engineers",
"Search Interfaces: UX Principles and Case Studies",
"The Use of Vector Fields in Meteorology",
"Search and Destroy: Cybersecurity in the 21st Century",
"From Bitmap to Vector: A Designer’s Guide",
"Search Engines and the Democratization of Knowledge",
"Vector Geometry in Game Development",
"The Human Search for Connection in a Digital World",
"AI-Powered Vector Search in Recommendation Systems",
"Searchable Archives: The History of Digital Retrieval",
"Vector Control Strategies in Public Health",
"The Search for Extraterrestrial Intelligence"
]
创建集合
让我们创建一个集合来存储和索引标题。
由于 miniCOIL 的设计考虑了 Qdrant 计算关键词逆文档频率 (IDF) 的能力,我们需要使用 IDF 修饰符 来配置 miniCOIL 稀疏向量。
client.create_collection(
collection_name="{minicoil_collection_name}",
sparse_vectors_config={
"minicoil": models.SparseVectorParams(
modifier=models.Modifier.IDF #Inverse Document Frequency
)
}
)
同理,我们也配置一个带有基于 BM25 稀疏向量的集合。
client.create_collection(
collection_name="{bm25_collection_name}",
sparse_vectors_config={
"bm25": models.SparseVectorParams(
modifier=models.Modifier.IDF
)
}
)
转换为稀疏向量并上传至 Qdrant
接下来,我们需要将标题转换为 miniCOIL 稀疏表示,并将它们 upsert(插入/更新)到已配置的集合中。
Qdrant 和 FastEmbed 的集成允许在底层隐藏推理过程。
这意味着:
- FastEmbed 从 Hugging Face 下载选定的模型;
- FastEmbed 在底层运行本地推理;
- 推理出的稀疏表示被上传到 Qdrant。
#Estimating the average length of the documents in the corpus
avg_documents_length = sum(len(document.split()) for document in documents) / len(documents)
client.upsert(
collection_name="{minicoil_collection_name}",
points=[
models.PointStruct(
id=i,
payload={
"text": documents[i]
},
vector={
# Sparse miniCOIL vectors
"minicoil": models.Document(
text=documents[i],
model="Qdrant/minicoil-v1",
options={"avg_len": avg_documents_length}
#Average length of documents in the corpus
# (a part of the BM25 formula on which miniCOIL is built)
)
},
)
for i in range(len(documents))
],
)
同理,我们转换并 upsert 基于 BM25 的稀疏向量。
#Estimating the average length of the documents in the corpus
avg_documents_length = sum(len(document.split()) for document in documents) / len(documents)
client.upsert(
collection_name="{bm25_collection_name}",
points=[
models.PointStruct(
id=i,
payload={
"text": documents[i]
},
vector={
# Sparse vector from BM25
"bm25": models.Document(
text=documents[i],
model="Qdrant/bm25",
options={"avg_len": avg_documents_length}
#Average length of documents in the corpus
# (a part of the BM25 formula)
)
},
)
for i in range(len(documents))
],
)
使用 miniCOIL 进行检索
使用查询“Vectors in Medicine”,我们将演示 miniCOIL 和基于 BM25 的检索之间的区别。
没有任何索引标题包含关键词“medicine”,因此它不会对相似度得分产生影响。
同时,单词“vector”在许多标题中都出现过一次,从基于 BM25 的检索器视角来看,它在所有标题中的作用大致相同。
然而,miniCOIL 能够捕捉到“vector”在“medicine”上下文中的含义,并匹配到“vector”用于医学相关语境的文档。
对于基于 BM25 的检索
query = "Vectors in Medicine"
client.query_points(
collection_name="{bm25_collection_name}",
query=models.Document(
text=query,
model="Qdrant/bm25"
),
using="bm25",
limit=1,
)
结果将是
QueryResponse(
points=[
ScoredPoint(
id=18, version=1, score=0.8405092,
payload={
'title': 'Advanced Vector Calculus for Engineers'
},
vector=None, shard_key=None, order_value=None)
]
)
而对于基于 miniCOIL 的检索
query = "Vectors in Medicine"
client.query_points(
collection_name="{minicoil_collection_name}",
query=models.Document(
text=query,
model="Qdrant/minicoil-v1"
),
using="minicoil",
limit=1
)
我们将得到
QueryResponse(
points=[
ScoredPoint(
id=28, version=1, score=0.7005557,
payload={
'title': 'Vector Control Strategies in Public Health'
},
vector=None, shard_key=None, order_value=None)
]
)