混合搜索
自 Milvus 2.4 版本开始,我们引入了多向量支持和混合搜索框架,这意味着用户可以将多个向量字段(最多达到 10 个)引入单个集合中。不同的向量字段可以代表不同的方面、不同的嵌入模型,甚至是表征同一实体的不同数据模态,极大地扩展了信息的丰富性。这一特性在综合搜索场景中特别有用,比如基于各种属性(如图片、声音、指纹等)识别向量库中最相似的人。
混合搜索使得可以在各种向量字段上执行搜索请求,并利用重新排序策略(如 Reciprocal Rank Fusion(RRF)和加权评分)合并结果。要了解更多有关重新排序策略的信息,请参考 重新排序。
在本教程中,您将学习如何:
-
为不同向量字段上的相似性搜索创建多个
AnnSearchRequest
实例; -
配置重新排序策略,以合并和重新排序来自多个
AnnSearchRequest
实例的搜索结果; -
使用
hybrid_search()
方法执行混合搜索。
本页上的代码片段使用 PyMilvus ORM 模块 与 Milvus 进行交互。将很快提供使用新的 MilvusClient SDK 的代码片段。
准备工作
在开始混合搜索之前,请确保您有一个包含多个向量字段的集合。
以下是一个示例,展示了如何创建一个名为 test_collection
的集合,其中包含两个向量字段 filmVector
和 posterVector
,并向其中插入随机实体。
from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType
import random
# 连接到 Milvus
connections.connect(
host="10.102.7.3", # 请替换为您的 Milvus 服务器 IP
port="19530"
)
# 创建模式
fields = [
FieldSchema(name="film_id", dtype=DataType.INT64, is_primary=True),
FieldSchema(name="filmVector", dtype=DataType.FLOAT_VECTOR, dim=5), # 电影向量的向量字段
FieldSchema(name="posterVector", dtype=DataType.FLOAT_VECTOR, dim=5)] # 海报向量的向量字段
schema = CollectionSchema(fields=fields,enable_dynamic_field=False)
# 创建集合
collection = Collection(name="test_collection", schema=schema)
# 为每个向量字段创建索引
index_params = {
"metric_type": "L2",
"index_type": "IVF_FLAT",
"params": {"nlist": 128},
}
collection.create_index("filmVector", index_params)
collection.create_index("posterVector", index_params)
# 生成随机实体进行插入
entities = []
for _ in range(1000):
# 为模式中的每个字段生成随机值
film_id = random.randint(1, 1000)
film_vector = [ random.random() for _ in range(5) ]
poster_vector = [ random.random() for _ in range(5) ]
# 为每个实体创建一个字典
entity = {
"film_id": film_id,
"filmVector": film_vector,
"posterVector": poster_vector
}
# 将实体添加到列表中
entities.append(entity)
collection.insert(entities)
第一步:创建多个 AnnSearchRequest 实例
多向量搜索使用 hybrid_search()
API 在单个调用中执行多个近似最近邻(ANN)搜索请求。每个 AnnSearchRequest
表示对特定向量字段进行的单个搜索请求。
以下示例创建了两个 AnnSearchRequest
实例,以在两个向量字段上执行各自的相似度搜索。
from pymilvus import AnnSearchRequest
# 为 filmVector 创建 ANN 搜索请求 1
query_filmVector = [[0.8896863042430693, 0.370613100114602, 0.23779315077113428, 0.38227915951132996, 0.5997064603128835]]
search_param_1 = {
"data": query_filmVector, # 查询向量
"anns_field": "filmVector", # 向量字段名称
"param": {
"metric_type": "L2", # 此参数值必须与集合模式中使用的值相同
"params": {"nprobe": 10}
},
"limit": 2 # 在此 AnnSearchRequest 中返回的搜索结果数量
}
request_1 = AnnSearchRequest(**search_param_1)
# 为 posterVector 创建 ANN 搜索请求 2
query_posterVector = [[0.02550758562349764, 0.006085637357292062, 0.5325251250159071, 0.7676432650114147, 0.5521074424751443]]
search_param_2 = {
"data": query_posterVector, # 查询向量
"anns_field": "posterVector", # 向量字段名称
"param": {
"metric_type": "L2", # 此参数值必须与集合模式中使用的值相同
"params": {"nprobe": 10}
},
"limit": 2 # 在此 AnnSearchRequest 中返回的搜索结果数量
}
request_2 = AnnSearchRequest(**search_param_2)
# 将这两个请求存储为 `reqs` 中的列表
reqs = [request_1, request_2]
参数:
-
AnnSearchRequest
(对象)表示一个 ANN 搜索请求的类。每个混合搜索可以同时包含 1 到 1,024 个
ANNSearchRequest
对象。 -
data
(列表)要在单个
AnnSearchRequest
中搜索的查询向量。当前,此参数接受包含单个查询向量的列表,例如[[0.5791814851218929, 0.5792985702614121, 0.8480776460143558, 0.16098005945243, 0.2842979317256803]]
。将来,此参数将扩展为接受多个查询向量。 -
anns_field
(字符串)在单个
AnnSearchRequest
中使用的向量字段的名称。 -
param
(字典)单个
AnnSearchRequest
的搜索参数字典。这些搜索参数与单向量搜索的参数相同。有关更多信息,请参阅搜索参数。 -
limit
(整数)在单个
ANNSearchRequest
中包含的最大搜索结果数量。 这个参数仅影响在单个ANNSearchRequest
中返回的搜索结果数量,并不决定hybrid_search
调用返回的最终结果。在混合搜索中,最终结果是通过合并和重新排名来自多个ANNSearchRequest
实例的结果来确定的。
步骤2:配置重新排名策略
创建AnnSearchRequest
实例后,配置一个重新排名策略来合并和重新排名结果。目前有两个选项:WeightedRanker
和RRFRanker
。有关重新排名策略的更多信息,请参阅Reranking。
-
使用加权评分
WeightedRanker
用于为每个向量字段搜索结果分配指定权重的重要性。如果您优先考虑某些向量字段,WeightedRanker(value1, value2, ..., valueN)
可以在组合搜索结果中反映这一点。from pymilvus import WeightedRanker
# 使用WeightedRanker来使用指定权重合并结果
# 将0.8的权重分配给文本搜索,0.2分配给图像搜索
rerank = WeightedRanker(0.8, 0.2)使用
WeightedRanker
时,请注意:- 每个权重值的范围从0(最不重要)到1(最重要),影响最终的聚合分数。
- 在
WeightedRanker
中提供的权重值总数应等于您创建的AnnSearchRequest
实例的数量。
-
使用倒数秩融合(RFF)
# 或者,使用RRFRanker进行倒数秩融合重新排名
from pymilvus import RRFRanker
rerank = RRFRanker()
步骤3:执行混合搜索
设置了AnnSearchRequest
实例和重新排名策略后,使用hybrid_search()
方法执行混合搜索。
# 在进行混合搜索之前,将集合加载到内存中。
collection.load()
res = collection.hybrid_search(
reqs, # 在步骤1中创建的AnnSearchRequest列表
rerank, # 步骤2中指定的重新排名策略
limit=2 # 返回的最终搜索结果数量
)
print(res)
参数:
-
reqs
(list)一个搜索请求列表,其中每个请求都是一个
ANNSearchRequest
对象。每个请求可以对应不同的向量字段和不同的搜索参数集。 -
rerank
(object)用于混合搜索的重新排名策略。可能的值:
WeightedRanker(value1, value2, ..., valueN)
和RRFRanker()
。有关重新排名策略的更多信息,请参阅Reranking。
-
limit
(int)在混合搜索中返回的最终结果的最大数量。
输出类似于以下内容:
["['id: 844, distance: 0.006047376897186041, entity: {}', 'id: 876, distance: 0.006422005593776703, entity: {}']"]
限制
-
通常,每个集合默认允许最多有4个向量字段。但是,您可以调整
proxy.maxVectorFieldNum
配置以扩展集合中向量字段的最大数量,最大限制为每个集合最多10个向量字段。更多信息请参阅代理相关配置。 -
集合中部分索引或加载的向量字段将导致错误。
-
目前,混合搜索中每个
AnnSearchRequest
只能携带一个查询向量。