BM42
这里介绍的是qdrant中的bm42,qdrant版本1.10.0以上
BM42 是 Qdrant 提出的新型混合搜索算法,旨在结合经典的 BM25 和基于 Transformer 的语义搜索模型。BM42 通过保留 BM25 中最重要的部分——逆文档频率(IDF),并用 Transformer 的注意力机制取代词频来衡量词语在文档中的重要性,从而解决了现代检索系统(如 RAG)中短文档的局限性。
BM42 兼具 BM25 的简单性与 SPLADE 的语义智能,同时避免了 SPLADE 在词汇表处理和计算资源消耗方面的缺点。其主要优势在于速度快、内存占用小,并且在小文档处理、多语言支持及未知词处理上表现良好。BM42 适用于与稀疏和稠密嵌入结合的混合搜索系统。
然而实际测试中效果并没有官网说得好,还需要以结果为主。
图片来自qdrant官网,官网为:https://qdrant.tech/articles/bm42/
整体架构流程
bm42从构建索引到检索流程
1 构建索引
def stor_in_bm42_qdrant(sparse_embedding, embeddings, data, collection_name, batch_size):
dimension = embeddings.shape[1]
nums = embeddings.shape[0]
client.recreate_collection(
collection_name=collection_name,
vectors_config={
"vector": models.VectorParams(
size=dimension,
distance=models.Distance.COSINE,
)
},
sparse_vectors_config={
"bm42": models.SparseVectorParams(
modifier=models.Modifier.IDF,
)
}
)
# Prepare and upload points in batches
for start_idx in range(0, nums, batch_size):
end_idx = min(start_idx + batch_size, nums)
points = []
for i in range(start_idx, end_idx):
text= data.iloc[i, 0]
point = PointStruct(
id=i,
vector={
"vector": embeddings[i].tolist(),
"bm42": sparse_embedding[i],
},
payload={
"文本": text,
}
)
points.append(point)
# Upsert points into collection
operation_info = client.upsert(
collection_name=collection_name,
wait=True,
points=points
)
2 其中的sparse embedding为
class BM42():
def __init__(self, model_path=None):
self.embedding_model = SparseTextEmbedding(
cache_dir='/data2/machao/Qdrant/all_miniLM_L6_v2_with_attentions',# 好像没用
model_name="Qdrant/bm42-all-minilm-l6-v2-attentions"
)
def encode(self, texts: list, is_query: bool = False, max_length=256):
if is_query:
sparse_embedding = self.embedding_model.query_embed(texts)
else:
sparse_embedding = self.embedding_model.embed(texts)
res = []
for embeddings in sparse_embedding:
if hasattr(embeddings, 'indices') and hasattr(embeddings, 'values'):
sparse_vector = models.SparseVector(
indices=embeddings.indices.tolist(),
values=embeddings.values.tolist()
)
res.append(sparse_vector)
else:
raise ValueError("The embeddings object does not have 'indices' and 'values' attributes.")
return res
3 第一步中的embedding为常规嵌入模型的结果
4 接下来为检索qdrant中存储的混合向量
search_result = client.query_points(
collection_name=collection_name,
prefetch=[
models.Prefetch(
query=models.SparseVector(indices=sparse_query_embedding.indices, values=sparse_query_embedding.values),
using="bm42",
limit=topk,
),
models.Prefetch(
query=query_embedding.squeeze().tolist(),
using="vector",
limit=topk,
),
],
query=models.FusionQuery(fusion=models.Fusion.RRF),
limit=topk,
)
以上为bm42使用流程
一些试错
纯个人经验
1 要生成sparse embedding,可能需要fastembed等库,安装cpu即可,不需要gpu也很快
2 qdrant需要1.10.0以上
3 需要提前部署好qdrant服务
小结
以上是个人bm42使用经验,纯原创,不接受转载,也欢迎大佬们指认错误,各位大佬喜欢的也可以关注一下!!!