文章目录
- rag检索分类
-
- (1)向量查询
- [(2) 过滤查询](#(2) 过滤查询)
- [(3) 预置查询(Named Vectors)](#(3) 预置查询(Named Vectors))
- [(4) 稀疏向量查询(Sparse Vector / BM25)](#(4) 稀疏向量查询(Sparse Vector / BM25))
- [(5) 混合查询(Hybrid Search)](#(5) 混合查询(Hybrid Search))
- 入库和检索
rag检索分类
(1)向量查询
python
# 单一向量
.query_points(query=vector, limit=10)
# 多个向量(加权平均)
.query_points(query=[vec1, vec2], query_weights=[0.7, 0.3])
(2) 过滤查询
python
.query_points(
query=vector,
query_filter=Filter(
must=[FieldCondition(key="category", match=MatchValue(value="AI"))]
),
limit=10
)
(3) 预置查询(Named Vectors)
# 如果入库时给向量起了名字
.query_points(
collection_name="docs",
query_name="document_vector", # 指定使用哪个向量字段
using="text_vector", # 使用命名的向量
with_vector=True
)
(4) 稀疏向量查询(Sparse Vector / BM25)
# 需要配置 sparse vector 索引
.query_points(
query=sparse_vector, # 稀疏向量(词袋表示)
using="sparse_text" # 指定稀疏向量字段
)
(5) 混合查询(Hybrid Search)
# 结合稠密和稀疏向量
.query_points(
prefetch=[
Prefetch(query=dense_vector, using="dense", limit=100),
Prefetch(query=sparse_vector, using="sparse", limit=100),
],
query=Filter(...), # 重排序阶段
limit=10
)
入库和检索
入库
入库
python
# 创建 collection 时配置
from qdrant_client.http.models import (
VectorParams,
HnswConfigDiff,
PayloadIndexType
)
client.create_collection(
collection_name="my_docs",
vectors_config={
"text_vector": VectorParams(
size=768, # 向量维度
distance=Distance.COSINE,
hnsw_config=HnswConfigDiff(
m=16, # 每个节点最大连接数
ef_construct=100
)
)
},
# 对 payload 字段建索引(用于过滤)
optimizers_config=OptimizersConfigDiff(
indexing_threshold=10000
)
)
# 对 payload 字段创建倒排索引(用于快速过滤)
client.create_payload_index(
collection_name="my_docs",
field_name="category",
field_type=PayloadIndexType.KEYWORD
)
# 对 text 内容建全文索引(稀疏向量/BM25)
client.create_payload_index(
collection_name="my_docs",
field_name="text_content",
field_type=PayloadIndexType.TEXT
)
混合检索工程方案
python
class HybridRetriever:
async def retrieve(self, query: str, top_k: int = 10):
# 1. 扩大召回
dense_limit = max(top_k * 3, 10)
# 2. 并行检索
dense_task = self._dense_search(query, dense_limit)
bm25_task = self._bm25_search(query, dense_limit)
dense_hits, bm25_hits = await asyncio.gather(dense_task, bm25_task)
# 3. 融合(RRF 或加权)
combined = self._reciprocal_rank_fusion(dense_hits, bm25_hits)
# 4. 重排序(Cross-Encoder)
reranked = await self._cross_encoder_rerank(query, combined[:top_k*2])
# 5. 返回最终 top_k
return reranked[:top_k]
需要注意的是混合检索不能直接采用并集,
错误代码如下,不可用于实际生产环境,(最优解应该使用加权融合)
python
results = self.client.query_points(
collection_name=self.collection_name,
prefetch=[
# 语义检索(稠密向量)
Prefetch(
query=dense_embedding,
using="dense_text", # 使用稠密向量字段
limit=recall_limit,
filter=query_filter
),
# 关键词检索(稀疏向量)
Prefetch(
query=sparse_embedding,
using="sparse_text", # 使用稀疏向量字段
limit=recall_limit,
filter=query_filter
)
],
# query参数在这里用于最终的融合和排序
# 传入None表示只做融合,不再额外检索
query=None,
limit=top_k,
with_payload=True,
with_vectors=False
)
但是以下代码又是可以的
response = client.query_points(
collection_name="my_collection",
prefetch=[
models.Prefetch(
query=models.Document(
text=query,
model="Qdrant/bm25",
),
using="sparse",
limit=20,
),
models.Prefetch(
query=models.Document(
text=query,
model="sentence-transformers/all-MiniLM-L6-v2",
),
using="dense",
limit=20,
)
],
query=models.FusionQuery(fusion=models.Fusion.RRF),
limit=10,
)