Milvus 2.5.10(搭配 pymilvus 2.5.6),搜索(Search)重新排序(Rerank) 是 Milvus 向量数据库中用于执行高效向量相似性搜索和优化结果排名的核心功能。搜索用于查找与查询向量最相似的记录,而重新排序则通过额外的排名算法对搜索结果进行优化,以提高相关性或满足特定业务需求。Milvus 支持 向量搜索标量过滤全文检索混合搜索,并通过重新排序机制(如 RRFRanker 或自定义排序)进一步调整结果顺序。以下基于 Milvus 2.5.10 官方文档(https://milvus.io/docs/zh/single-vector-search.md),包括定义、特性、支持的搜索类型、重新排序方法、代码示例、适用场景和注意事项。


1. 搜索(Search)概述

搜索 是 Milvus 中用于从集合(Collection)中检索与查询向量或文本最相关记录的操作。Milvus 支持多种搜索类型,包括向量搜索、全文检索和混合搜索,适用于不同场景(如推荐系统、RAG、图像检索等)。

1.1 搜索类型

  • 向量搜索(Vector Search)
    • 针对向量字段(如 FLOAT_VECTORSPARSE_FLOAT_VECTOR)。
    • 使用相似性度量(如 COSINEL2BM25)查找 Top-K 最相似的记录。
    • 依赖向量索引(如 HNSWAUTOINDEX)加速查询。
  • 标量过滤(Scalar Filtering)
    • 对标量字段(如 INT64VARCHARJSON)应用过滤条件。
    • 示例:category == "electronics"TEXT_MATCH(content, "AI")
    • 依赖标量索引(如 INVERTEDTRIE)。
  • 全文检索(Full Text Search)
    • 针对 VARCHAR 字段,使用 BM25 算法和 SPARSE_FLOAT_VECTOR
    • 通过分析器(Analyzer)分词,计算相关性得分。
  • 混合搜索(Hybrid Search)
    • 结合向量搜索(密集/稀疏向量)、全文检索和标量过滤。
    • 使用多个搜索请求(AnnSearchRequest)并通过重新排序融合结果。

1.2 搜索特性

  • 高效性:利用索引(如 HNSWAUTOINDEX)实现近似最近邻(ANN)搜索。
  • 灵活性:支持多种度量类型(COSINEL2BM25)和过滤表达式。
  • 一致性:通过 consistency_level(如 ConsistencyLevel.Strong)控制数据新鲜度。
  • 分区支持:可指定搜索的分区,减少查询范围。
  • 输出控制:通过 output_fields 指定返回字段。

1.3 搜索方法

  • 单向量搜索client.search(collection_name, data, anns_field, ...)
    • 用于单一向量字段(如 FLOAT_VECTORSPARSE_FLOAT_VECTOR)。
  • 混合搜索client.hybrid_search(collection_name, reqs, ranker, ...)
    • 结合多个搜索请求(密集向量、稀疏向量、过滤)。
  • 查询(Query)client.query(collection_name, filter, output_fields, ...)
    • 用于标量字段的精确查询,非向量搜索。

1.4 搜索参数

  • anns_field :要搜索的字段名称。如:anns_field=“vector”
  • data :搜索输入的数据。如:data=[query_vector]
  • limit : 搜索最多返回的实体数量。如:limit=5
  • filter :指定标准过滤条件。如:filter=‘color like “red%” and likes > 50’
  • output_fields :搜索结果输出包含的实体中的字段。如:output_fields=[“color”, “likes”]
  • group_by_field :指定分组查询的字段。如: group_by_field=“docId” 。默认情况下,分组搜索每个组只返回一个实体。如果要增加每个组返回结果的数量,可以使用group_size 和strict_group_size 参数进行控制。如:group_size=2, strict_group_size=True
  • search_params :可以通过search_params参数来指定额外的搜索的参数,为一个参数字典。
    • metric_type : 度量类型, 如 COSINE、L2 等。如:metric_type=“IP”
    • offset:跳过的实体数量,如:“offset”: 10 。可以使用 Limit 和 Offset 参数实现分类查询。🔗
    • hints:设置为 iterative_filter 启用迭代过滤, 如: “hints”: “iterative_filter” 。迭代过滤可以作为一种替代方法,帮助减少标量过滤的工作量。以迭代的方式执行向量搜索达到指定的 topK 结果停止。🔗
    • radius 和 range_filter :范围搜索,如:“params”:{“radius”:0.4, “range_filter”:0.6}。radius 设为0.4 ,将range_filter 设为0.6 ,这样 Milvus 就会返回与查询向量的距离或分数在0.4至0.6 范围内的所有实体。🔗
    • drop_ratio_build :控制稀疏向量索引构建时的动态剪枝比例。如:“params”: {“drop_ratio_build”: 0.2}。除了在查询时指定,构建索引时也可以指定。
    • nprobe :用于控制搜索过程中需要探查的聚类中心(Voronoi Cells)数量,如:“params”: {“nprobe”: 50} 。它的核心作用是平衡搜索精度与计算开销:增大 nprobe 会提升搜索的召回率(精度),但也会增加计算时间和资源消耗。

2. 重新排序(Rerank)概述

重新排序(Rerank) 是对搜索结果进行二次排序的过程,旨在根据特定规则或算法优化结果顺序。Milvus 的混合搜索通过 Ranker 机制实现重新排序,将多个搜索路径的结果融合为统一的 Top-K 列表。

2.1 重新排序方法

Milvus 2.5.10 支持以下重新排序方法(参考 https://milvus.io/docs/zh/reranking.md):

  • RRFRanker(Reciprocal Rank Fusion):
    • 描述:基于倒数排名融合算法,将多个搜索结果的排名进行加权合并。
    • 公式
      score ( d ) = ∑ i = 1 k 1 rank i ( d ) + c \text{score}(d) = \sum_{i=1}^{k} \frac{1}{\text{rank}_i(d) + c} score(d)=i=1kranki(d)+c1
      • rank i ( d ) \text{rank}_i(d) ranki(d):文档 d d d 在第 i i i 个搜索结果中的排名。
      • c c c:常数(默认 60),避免高排名文档过于主导。
    • 适用场景:混合搜索,融合密集向量(语义)和稀疏向量(BM25)结果。
    • 优点:简单高效,平衡多路结果。
    • 缺点:无法引入外部信号(如用户偏好)。
  • WeightedRanker
    • 描述:为每个搜索路径分配权重,计算加权分数。
    • 参数weights(列表,每个搜索请求的权重,如 [0.7, 0.3])。
    • 适用场景:需要偏向某些搜索路径(如优先语义搜索)。
    • 优点:灵活控制路径重要性。
    • 缺点:需手动调优权重。
  • Custom Reranking(未来支持):
    • Milvus 文档提到计划支持自定义重新排序(如基于机器学习模型),但 2.5.10 未完全实现。

2.2 重新排序流程

  1. 执行多路搜索
    • 每个 AnnSearchRequest 返回 Top-K 结果(如 BM25 搜索、HNSW 搜索)。
  2. 收集结果
    • 合并所有搜索路径的候选结果,去重。
  3. 重新排序
    • 应用 Ranker(如 RRFRanker)计算综合分数。
  4. 返回 Top-K
    • 按综合分数排序,返回最终结果。

3. 搜索与重新排序的配置

以下是配置搜索和重新排序的步骤,结合 Milvus 的分析器、BM25 和索引功能。

3.1 配置步骤

  1. 定义 Schema
    • 包括向量字段(FLOAT_VECTORSPARSE_FLOAT_VECTOR)、标量字段(VARCHARJSON)。
    • 为全文检索配置 FunctionType.BM25 函数。
  2. 创建索引
    • 为向量字段配置 HNSWAUTOINDEX 等。
    • 为标量字段配置 INVERTEDTRIE 等。
  3. 插入数据
    • 填充集合数据,确保向量和标量字段正确。
  4. 执行搜索
    • 单向量搜索:使用 client.search
    • 混合搜索:使用 client.hybrid_searchAnnSearchRequest
  5. 重新排序
    • 指定 Ranker(如 RRFRankerWeightedRanker)。

3.2 代码示例:搜索与重新排序

以下是综合示例,展示单向量搜索、全文检索和混合搜索,结合 RRFRanker 进行重新排序。

from pymilvus import MilvusClient, DataType, AnnSearchRequest, RRFRanker, FunctionType, Function
from pymilvus.client.constants import ConsistencyLevel
import random

# 连接 Milvus
client = MilvusClient(uri="http://localhost:19530")

try:
    # 创建数据库
    client.create_database(db_name="test_db")
    client.use_database(db_name="test_db")

    # 创建 Schema
    schema = MilvusClient.create_schema(auto_id=True)
    schema.add_field(
        field_name="pk",
        datatype=DataType.VARCHAR,
        is_primary=True,
        auto_id=True,
        max_length=100
    )
    schema.add_field(
        field_name="content",
        datatype=DataType.VARCHAR,
        max_length=65535,
        enable_analyzer=True,
        enable_match=True,
        analyzer_params={"type": "english"}
    )
    schema.add_field(field_name="sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR)
    schema.add_field(field_name="dense_vector", datatype=DataType.FLOAT_VECTOR, dim=128)
    schema.add_field(field_name="metadata", datatype=DataType.JSON)

    # 定义 BM25 函数
    bm25_function = Function(
        name="content_bm25_sparse",
        input_field_names=["content"],
        output_field_names=["sparse_vector"],
        function_type=FunctionType.BM25
    )
    schema.add_function(bm25_function)

    # 创建集合
    client.create_collection(
        collection_name="search_collection",
        schema=schema,
        consistency_level=ConsistencyLevel.Session
    )

    # 创建索引
    index_params = MilvusClient.prepare_index_params()
    index_params.add_index(
        field_name="sparse_vector",
        index_type="AUTOINDEX",
        metric_type="BM25"
    )
    index_params.add_index(
        field_name="dense_vector",
        index_type="HNSW",
        metric_type="COSINE",
        params={"M": 16, "efConstruction": 200}
    )
    index_params.add_index(field_name="content", index_type="INVERTED")
    index_params.add_index(
        field_name="metadata",
        index_type="INVERTED",
        index_name="json_category",
        params={"json_path": "metadata[\"category\"]", "json_cast_type": "varchar"}
    )
    client.create_index(collection_name="search_collection", index_params=index_params)

    # 插入数据
    data = [
        {
            "content": "Milvus supports hybrid search with BM25 and dense vectors.",
            "dense_vector": [random.random() for _ in range(128)],
            "metadata": {"category": "database"}
        },
        {
            "content": "AI applications benefit from vector databases.",
            "dense_vector": [random.random() for _ in range(128)],
            "metadata": {"category": "AI"}
        },
        {
            "content": "Vector search powers modern AI solutions.",
            "dense_vector": [random.random() for _ in range(128)],
            "metadata": {"category": "AI"}
        }
    ]
    client.insert(collection_name="search_collection", data=data)

    # 加载集合
    client.load_collection(collection_name="search_collection")

    # 1. 单向量搜索(全文检索)
    print("Single vector search (BM25):")
    results = client.search(
        collection_name="search_collection",
        data=["vector database"],
        anns_field="sparse_vector",
        limit=2,
        output_fields=["content", "metadata"],
        consistency_level=ConsistencyLevel.Strong
    )
    for result in results[0]:
        print(f"Document: {result['entity']['content']}, Score: {result['distance']}")

    # 2. 单向量搜索(语义搜索 + 标量过滤)
    print("\nSingle vector search (Dense vector + Filtering):")
    dense_query_vector = [random.random() for _ in range(128)]
    results = client.search(
        collection_name="search_collection",
        data=[dense_query_vector],
        anns_field="dense_vector",
        limit=2,
        filter="TEXT_MATCH(content, 'AI') and metadata[\"category\"] == \"AI\"",
        output_fields=["content", "metadata"],
        search_params={"metric_type": "COSINE", "params": {"ef": 64}},
        consistency_level=ConsistencyLevel.Strong
    )
    for result in results[0]:
        print(f"Document: {result['entity']['content']}, Score: {result['distance']}")

    # 3. 混合搜索(BM25 + Dense vector + Reranking)
    print("\nHybrid search with RRFRanker:")
    sparse_request = AnnSearchRequest(
        data=["vector database"],
        anns_field="sparse_vector",
        param={"metric_type": "BM25"},
        limit=2,
        expr="TEXT_MATCH(content, 'vector') and metadata[\"category\"] == \"database\""
    )
    dense_request = AnnSearchRequest(
        data=[dense_query_vector],
        anns_field="dense_vector",
        param={"metric_type": "COSINE", "params": {"ef": 64}},
        limit=2
    )
    results = client.hybrid_search(
        collection_name="search_collection",
        reqs=[sparse_request, dense_request],
        ranker=RRFRanker(),
        limit=2,
        output_fields=["content", "metadata"],
        consistency_level=ConsistencyLevel.Strong
    )
    for result in results[0]:
        print(f"Document: {result['entity']['content']}, Metadata: {result['entity']['metadata']}, Score: {result['distance']}")

except Exception as e:
    print(f"Error: {e}")

finally:
    # 清理
    client.drop_collection(collection_name="search_collection")
    client.drop_database(db_name="test_db")

输出示例

Single vector search (BM25):
Document: Milvus supports hybrid search with BM25 and dense vectors., Score: 0.912
Document: AI applications benefit from vector databases., Score: 0.745

Single vector search (Dense vector + Filtering):
Document: AI applications benefit from vector databases., Score: 0.823
Document: Vector search powers modern AI solutions., Score: 0.654

Hybrid search with RRFRanker:
Document: Milvus supports hybrid search with BM25 and dense vectors., Metadata: {'category': 'database'}, Score: 0.912
Document: AI applications benefit from vector databases., Metadata: {'category': 'AI'}, Score: 0.745

代码说明

  • Schema
    • 包含 pk(主键)、contentVARCHAR,支持全文检索和文本匹配)、sparse_vector(BM25)、dense_vector(语义搜索)、metadataJSON)。
    • 添加 FunctionType.BM25 函数,将 content 转换为 sparse_vector
  • 索引
    • sparse_vectorAUTOINDEX(BM25)。
    • dense_vectorHNSW(COSINE)。
    • contentINVERTED(文本匹配)。
    • metadataINVERTED(JSON 过滤)。
  • 搜索
    • 单向量搜索(BM25):直接查询 sparse_vector,返回 BM25 相关性得分。
    • 单向量搜索(语义+过滤):查询 dense_vector,结合 TEXT_MATCH 和 JSON 过滤。
    • 混合搜索:结合 BM25 和语义搜索,使用 RRFRanker 融合结果。
  • 重新排序
    • RRFRanker 合并稀疏和密集搜索结果,基于倒数排名优化顺序。

4. 搜索与重新排序的适用场景

  • 向量搜索
    • 推荐系统:查找与用户偏好向量相似的商品。
    • 图像检索:搜索与查询图像嵌入最相似的图片。
  • 全文检索
    • RAG(Retrieval-Augmented Generation):检索相关文档作为大模型上下文。
    • 关键词搜索:查找技术文档或电商产品。
  • 标量过滤
    • 条件筛选:筛选特定类别或价格范围的记录。
    • 精确匹配:查找包含特定关键词的文档。
  • 混合搜索
    • 多模态搜索:结合关键词(BM25)、语义(密集向量)和元数据过滤。
    • 电商搜索:综合用户查询、语义偏好和类别限制。
  • 重新排序
    • 结果优化:平衡关键词匹配和语义相关性。
    • 个性化:通过 WeightedRanker 调整语义或关键词的权重。

5. 配置建议

  • 搜索优化
    • 索引选择:密集向量用 HNSW(高精度)或 IVF_FLAT(大规模),稀疏向量用 AUTOINDEX
    • 过滤表达式:使用 TEXT_MATCHJSON_CONTAINS 等高效过滤。
    • 搜索参数:调整 ef(HNSW)或 nprobe(IVF)以平衡速度和精度。
  • 重新排序优化
    • RRFRanker:适合通用场景,自动平衡多路结果。
    • WeightedRanker:为关键路径(如语义搜索)分配更高权重(如 [0.8, 0.2])。
    • 测试权重:通过实验调整 WeightedRanker 的权重,优化业务指标。
  • 分析器
    • 使用 englishchinese 分析器优化 BM25 检索。
    • 自定义停用词列表,提升分词质量。

6. 注意事项

  • 版本兼容性
    • 确保使用 Milvus 2.5.10 和 pymilvus 2.5.6(pip show pymilvus)。
    • 混合搜索和 RRFRanker 在 2.5.x 中稳定支持。
  • 索引要求
    • 搜索前需为向量和标量字段创建索引(HNSWAUTOINDEXINVERTED)。
    • 确保 FunctionType.BM25 配置正确,避免稀疏向量为空。
  • 性能影响
    • 混合搜索涉及多路查询,增加计算开销,建议限制 limit
    • 标量过滤的复杂表达式可能降低性能,优先使用索引。
  • 错误处理
    • 检查过滤表达式语法和字段类型:
      try:
          client.hybrid_search(...)
      except Exception as e:
          print(f"Error: {e}")
      

7. 总结

Milvus 2.5.10 的 搜索(Search) 支持向量搜索、全文检索和混合搜索,通过索引(如 HNSWAUTOINDEXINVERTED)和分析器实现高效查询。重新排序(Rerank) 通过 RRFRankerWeightedRanker 优化结果顺序,特别适合混合搜索场景。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐