跳到主要内容
版本:v3.0.x

基本向量搜索

近似近邻(ANN)搜索以记录 Embedding 排序顺序的索引文件为基础,根据接收到的搜索请求中携带的查询向量查找 Embedding 子集,将查询向量与该子集中的向量进行比较,并返回最相似的结果。通过 ANN 搜索,Milvus 提供了高效的搜索体验。本页将帮助你了解如何进行基本的 ANN 搜索。

说明

如果在创建 Collection 后添加新字段,包含这些字段的搜索会针对未显式设置值的 Entity 返回已定义的默认值或 NULL。有关详细信息,请参阅 更改 Collection Schema

概述

ANN 和 k-Nearest Neighbors (kNN) 搜索是向量相似性搜索的常用方法。在 kNN 搜索中,必须将向量空间中的所有向量与搜索请求中携带的查询向量进行比较,然后找出最相似的向量,这既耗时又耗费资源。

与 kNN 搜索不同,ANN 搜索算法要求提供一个 索引 文件,记录向量 Embedding 的排序顺序。当收到搜索请求时,可以使用索引文件作为参考,快速找到可能包含与查询向量最相似的 Embedding 的子组。然后,你可以使用指定的 度量类型 来测量查询向量与子组中的向量之间的相似度,根据与查询向量的相似度对组成员进行排序,并找出 前 K 个 组成员。

ANN 搜索依赖于预建索引,搜索吞吐量、内存使用量和搜索正确性可能会因选择的索引类型而不同。您需要在搜索性能和正确性之间取得平衡。

为了降低学习曲线,Milvus 提供了 AUTOINDEX。通过 AUTOINDEX,Milvus 可以在建立索引的同时分析 Collection 中的数据分布,并根据分析结果设置最优化的索引参数,从而在搜索性能和正确性之间取得平衡。

在本节中,你将找到有关以下主题的详细信息:

在 ANN 搜索中,单向量搜索指的是只涉及一个查询向量的搜索。根据预建索引和搜索请求中携带的度量类型,Milvus 将找到与查询向量最相似的前 K 个向量。

本节将介绍如何进行单向量搜索。搜索请求携带单个查询向量,要求 Milvus 使用内积(IP)计算查询向量与 Collection 中向量的相似度,并返回三个最相似的向量。

Python
from pymilvus import MilvusClient

client = MilvusClient(
uri="http://localhost:19530",
token="root:Milvus"
)

# 4. Single vector search
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
res = client.search(
collection_name="quick_setup",
anns_field="vector",
data=[query_vector],
limit=3,
search_params={"metric_type": "IP"}
)

for hits in res:
for hit in hits:
print(hit)

# [
# [
# {
# "id": 551,
# "distance": 0.08821295201778412,
# "entity": {}
# },
# {
# "id": 296,
# "distance": 0.0800950899720192,
# "entity": {}
# },
# {
# "id": 43,
# "distance": 0.07794742286205292,
# "entity": {}
# }
# ]
# ]

Milvus 根据搜索结果与查询向量的相似度得分从高到低排列搜索结果。相似度得分也称为与查询向量的距离,其值范围随使用的度量类型而变化。

下表列出了适用的度量类型和相应的距离范围。

度量类型

特征

距离范围

L2

值越小表示相似度越高。

[0, ∞)

IP

数值越大,表示相似度越高。

[-1, 1]

COSINE

数值越大,表示相似度越高。

[-1, 1]

JACCARD

值越小,表示相似度越高。

[0, 1]

HAMMING

值越小,表示相似度越高。

[0,dim(向量)] 批量向量搜索

同样,您也可以在一个搜索请求中包含多个查询向量。Milvus 将并行对查询向量进行 ANN 搜索,并返回两组结果。

Python
# 7. Search with multiple vectors
# 7.1. Prepare query vectors
query_vectors = [
[0.041732933, 0.013779674, -0.027564144, -0.013061441, 0.009748648],
[0.0039737443, 0.003020432, -0.0006188639, 0.03913546, -0.00089768134]
]

# 7.2. Start search
res = client.search(
collection_name="quick_setup",
data=query_vectors,
limit=3,
)

for hits in res:
print("TopK results:")
for hit in hits:
print(hit)

# Output
#
# [
# [
# {
# "id": 551,
# "distance": 0.08821295201778412,
# "entity": {}
# },
# {
# "id": 296,
# "distance": 0.0800950899720192,
# "entity": {}
# },
# {
# "id": 43,
# "distance": 0.07794742286205292,
# "entity": {}
# }
# ],
# [
# {
# "id": 730,
# "distance": 0.04431751370429993,
# "entity": {}
# },
# {
# "id": 333,
# "distance": 0.04231833666563034,
# "entity": {}
# },
# {
# "id": 232,
# "distance": 0.04221535101532936,
# "entity": {}
# }
# ]
# ]

主键搜索

如果目标 Collection 中已经存在查询向量,则可以使用主键来代替设置查询向量。

Python
res = client.search(
collection_name="quick_setup",
anns_field="vector",
ids=[551, 296, 43],
limit=3,
search_params={"metric_type": "IP"}
)

for hits in res:
for hit in hits:
print(hit)

Partition 中的 ANN 搜索

假设您在 Collection 中创建了多个 Partition,您可以将搜索范围缩小到特定数量的 Partition。在这种情况下,您可以在搜索请求中包含目标 Partition 名称,将搜索范围限制在指定的 Partition 内。减少搜索所涉及的 Partition 数量可以提高搜索性能。

下面的代码片段假定在你的 Collection 中有一个名为 PartitionA 的 Partition。

Python
# 4. Single vector search
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
res = client.search(
collection_name="quick_setup",
partition_names=["partitionA"],
data=[query_vector],
limit=3,
)

for hits in res:
print("TopK results:")
for hit in hits:
print(hit)

# [
# [
# {
# "id": 551,
# "distance": 0.08821295201778412,
# "entity": {}
# },
# {
# "id": 296,
# "distance": 0.0800950899720192,
# "entity": {}
# },
# {
# "id": 43,
# "distance": 0.07794742286205292,
# "entity": {}
# }
# ]
# ]

使用输出字段

在搜索结果中,Milvus 默认包含 top-K Embedding 的实体的主键字段值和相似性距离/分数。您可以在搜索请求中包含目标字段(包括向量和标量字段)的名称作为输出字段,以使搜索结果携带这些实体中其他字段的值。

Python
# 4. Single vector search
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],

res = client.search(
collection_name="quick_setup",
data=[query_vector],
limit=3, # The number of results to return
search_params={"metric_type": "IP"},
output_fields=["color"]
)

print(res)

# [
# [
# {
# "id": 551,
# "distance": 0.08821295201778412,
# "entity": {
# "color": "orange_6781"
# }
# },
# {
# "id": 296,
# "distance": 0.0800950899720192,
# "entity": {
# "color": "red_4794"
# }
# },
# {
# "id": 43,
# "distance": 0.07794742286205292,
# "entity": {
# "color": "grey_8510"
# }
# }
# ]
# ]

按标量字段排序搜索结果

默认情况下,Milvus 按搜索结果与查询向量的相似度得分排序。如果希望返回的实体按照标量字段排序,请在搜索请求中添加 order_by_fields

order_by_fields 中的每个项目都指定了标量字段和排序方向。升序使用 "asc",降序使用 "desc"。如果省略 order,Milvus 会按升序对字段排序。

下面的示例按 price 从低到高对搜索结果排序。如果要在响应中检查字段值,请在 output_fields 中包含排序字段。

Python
res = client.search(
collection_name="product_catalog",
data=query_vectors,
anns_field="embedding",
limit=20,
output_fields=["id", "price", "rating", "category"],
order_by_fields=[
{"field": "price", "order": "asc"}
],
)

您还可以按多个标量字段排序。Milvus 会按照你指定的顺序应用这些字段。在下面的示例中,Milvus 按 price 以升序对结果排序。对于具有相同 price 的实体,Milvus 然后按 rating 降序排序。

Python
res = client.search(
collection_name="product_catalog",
data=query_vectors,
anns_field="embedding",
limit=20,
output_fields=["id", "price", "rating", "category"],
order_by_fields=[
{"field": "price", "order": "asc"},
{"field": "rating", "order": "desc"},
],
)

对于在所有指定的 order-by 字段中具有相同值的实体,Milvus 会保持原来的相似度分数顺序。

使用限制和偏移

您可能会注意到,搜索请求中携带的参数 limit 决定了搜索结果中包含的实体数量。该参数指定了单次搜索中返回实体的最大数量,通常称为 top-K

如需分页,可以循环发送多个 Search 请求,并在每个请求中设置 LimitOffset。其中 ,Limit 表示当前页最多返回的 Entity 数量 ,Offset 表示此前已经跳过或返回的 Entity 总数。

下表展示每次返回 100 个 Entity 时,分页查询中的 LimitOffset 设置方式。

查询

每次查询要返回的实体

已返回实体总数

第 1 次 查询

100

0

第二次 查询

100

100

第三次 查询

100

200

第 n 次 查询

100

100 x (n-1)

请注意,在一次 ANN 搜索中,limitoffset 的总和应小于 16 384。

Python
# 4. Single vector search
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],

res = client.search(
collection_name="quick_setup",
data=[query_vector],
limit=3, # The number of results to return
search_params={
"metric_type": "IP",
"offset": 10 # The records to skip
}
)

如果您的 Collection 有 TIMESTAMPTZ 字段,您可以通过在搜索调用中设置 timezone 参数,为单次操作临时覆盖数据库或 Collection 的默认时区。这可以控制在操作过程中如何显示和比较 TIMESTAMPTZ 值。

timezone 的值必须是有效的 IANA 时区标识符 (例如,Asia/ShanghaiAmerica/ChicagoUTC)。有关如何使用 TIMESTAMPTZ 字段的详细信息,请参阅 TIMESTAMPTZ 字段

下面的示例展示了如何为搜索操作临时设置时区:

Python
res = client.search(
collection_name="quick_setup",
anns_field="vector",
data=[query_vector],
limit=3,
search_params={"metric_type": "IP"},
timezone="America/Havana",
)

AUTOINDEX 大大降低了 ANN 搜索的学习曲线。但是,随着 top-K 的增加,搜索结果可能并不总是正确的。通过缩小搜索范围、提高搜索结果相关性和搜索结果多样化,Milvus 实现了以下搜索增强功能。

  • 过滤搜索

您可以在搜索请求中包含过滤条件,这样 Milvus 就会在进行 ANN 搜索前进行元数据过滤,将搜索范围从整个 Collection 缩小到只搜索符合指定过滤条件的实体。

有关元数据过滤和过滤条件的更多信息,请参阅 过滤搜索过滤解释 和相关主题。

  • 范围搜索

您可以在特定范围内限制返回实体的距离或得分,从而提高搜索结果的相关性。在 Milvus 中,范围搜索涉及以与查询向量最相似的 Embedding 向量为中心画两个同心圆。搜索请求指定了两个圆的半径,Milvus 会返回所有属于外圆但不属于内圆的 Embedding。

有关范围搜索的更多信息,请参阅 范围搜索

  • 分组搜索

如果返回的实体在特定字段中持有相同的值,搜索结果可能无法代表向量空间中所有 Embedding 的分布情况。要使搜索结果多样化,可以考虑使用分组搜索。

有关分组搜索的更多信息,请参阅 分组搜索

  • 混合搜索

一个 Collection 可以包含多个向量字段,以保存使用不同 Embedding 模型生成的 Embedding。通过这种方式,可以使用混合搜索对这些向量字段的搜索结果进行 Reranker,从而提高召回率。

有关混合搜索的更多信息,请参阅 混合搜索

  • 搜索迭代器

单个 ANN 搜索最多可返回 16,384 个实体。如果需要在单次搜索中返回更多实体,请考虑使用搜索迭代器。

有关搜索迭代器的详细信息,请参阅搜索 迭代器

  • 全文搜索

全文搜索是一种在文本数据集中检索包含特定术语或短语的文档,然后根据相关性对结果进行排序的功能。该功能克服了语义搜索的局限性(语义搜索可能会忽略精确的术语),确保您获得最准确且与上下文最相关的结果。此外,它还能接受原始文本输入,自动将文本数据转换为稀疏嵌入,无需手动生成 Embedding,从而简化了向量搜索。

有关全文搜索的详细信息,请参阅 全文搜索

  • 文本匹配

Milvus 中的关键词匹配功能可根据特定术语精确检索文档。该功能主要用于满足特定条件的过滤搜索,并可结合标量过滤来完善查询结果,允许在符合标量标准的向量内进行相似性搜索。

有关关键字匹配的详细信息,请参阅 关键字匹配

  • 使用 Partition Key

在元数据过滤中涉及多个标量字段并使用相当复杂的过滤条件可能会影响搜索效率。一旦将一个标量字段设置为 Partition Key,并在搜索请求中使用涉及 Partition Key 的过滤条件,就可以帮助将搜索范围限制在与指定 Partition Key 值相对应的 Partition 内。

有关 Partition Key 的详细信息,请参阅 使用 Partition Key

  • 使用 mmap

有关 mmap 设置的详情,请参阅 使用 mmap

  • Clustering Compaction

有关详情,请参阅 Clustering Compaction

  • 使用 Reranking

有关使用 Ranker 增强搜索结果相关性的详情,请参阅 衰减 Ranker 概述Model Ranker 概述