跳到主要内容

Single-Vector Search

数据插入后,接下来是发起 search 请求,寻找与查询向量相似的向量。Single-vector search 通过比较查询向量与 collection 中的其他向量,找出与之最相似的 entity,返回 entity ID 及相互间的距离。Single-vector search 也支持返回向量数据和元数据。

概述

为满足不同需求,Zilliz Cloud 提供了多种 search 类型:

  • 基础搜索(basic search):包括 single-vector search、bulk-vector search、partition search 以及使用 output_fields 进行 search。

  • Filtered search:利用过滤标量字段来精细化搜索结果。

  • Range search:查找距离查询向量一定范围内的向量。

  • Grouping search:使用 group_by_field 参数,按特定字段对搜索结果进行分组,确保结果多样性。

开始前

以下示例代码用于连接到 Zilliz Cloud 集群,快速创建 collection 和两个 partition,并向其插入数据。

# 1. Set up a Milvus client
client = MilvusClient(
uri=CLUSTER_ENDPOINT,
token=TOKEN
)

# 2. Create a collection
client.create_collection(
collection_name="quick_setup",
dimension=5,
metric_type="IP"
)

# 3. Insert randomly generated vectors
colors = ["green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey"]
data = []

for i in range(1000):
current_color = random.choice(colors)
data.append({
"id": i,
"vector": [ random.uniform(-1, 1) for _ in range(5) ],
"color": current_color,
"color_tag": f"{current_color}_{str(random.randint(1000, 9999))}"
})

res = client.insert(
collection_name="quick_setup",
data=data
)

print(res)

# Output
#
# {
# "insert_count": 1000,
# "ids": [
# 0,
# 1,
# 2,
# 3,
# 4,
# 5,
# 6,
# 7,
# 8,
# 9,
# "(990 more items hidden)"
# ]
# }

# 6.1 Create partitions
client.create_partition(
collection_name="quick_setup",
partition_name="red"
)

client.create_partition(
collection_name="quick_setup",
partition_name="blue"
)

# 6.1 Insert data into partitions
red_data = [ {"id": i, "vector": [ random.uniform(-1, 1) for _ in range(5) ], "color": "red", "color_tag": f"red_{str(random.randint(1000, 9999))}" } for i in range(500) ]
blue_data = [ {"id": i, "vector": [ random.uniform(-1, 1) for _ in range(5) ], "color": "blue", "color_tag": f"blue_{str(random.randint(1000, 9999))}" } for i in range(500) ]

res = client.insert(
collection_name="quick_setup",
data=red_data,
partition_name="red"
)

print(res)

# Output
#
# {
# "insert_count": 500,
# "ids": [
# 0,
# 1,
# 2,
# 3,
# 4,
# 5,
# 6,
# 7,
# 8,
# 9,
# "(490 more items hidden)"
# ]
# }

res = client.insert(
collection_name="quick_setup",
data=blue_data,
partition_name="blue"
)

print(res)

# Output
#
# {
# "insert_count": 500,
# "ids": [
# 0,
# 1,
# 2,
# 3,
# 4,
# 5,
# 6,
# 7,
# 8,
# 9,
# "(490 more items hidden)"
# ]
# }

发送 search 请求时,您可以指定一个或多个查询向量和请求返回的最大结果数(limit)。

根据您的实际数据和查询向量,最终返回的结果可能少于指定的最大结果数(limit),因为满足匹配条件的向量数可能小于指定的最大结果数。

Zilliz Cloud 中的 single-vector search 是最简单的 search 操作,此操作可以找出与指定查询向量最相似的向量。

进行 single-vector search 时,需指定 collection 名称、查询向量及期望返回的最大结果数(limit)。Single-vector search 将返回一个结果集,包含最相似的向量、entity ID 以及与查询向量的距离。

以下是 search 与指定查询向量最为相似的前 3 条 entity 的示例代码。

# 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", "params": {"nprobe": 10}}
)

print(res)

示例返回结果如下:

[
[
{
"id": 206,
"distance": 2.50616455078125,
"entity": {}
},
{
"id": 138,
"distance": 2.500145435333252,
"entity": {}
},
{
"id": 224,
"distance": 2.484044313430786,
"entity": {}
}
]
]

以上结果返回与查询向量最相近的 3 条 entity,包括 entity ID 和距离等信息。

Bulk-vector search 扩展了 single-vector search 的功能特性,允许您在单次请求中基于多个查询向量进行搜索。这种搜索方式适用于需要同时为多个查询向量寻找相似向量的情况,可帮助您大幅节省时间和计算资源。

进行 bulk-vector search 时,可以在 data 字段中添加多个查询向量。搜索时,系统会并行处理这些向量,并为每个查询向量返回 collection 中最接近匹配的结果集。

以下示例展示了如何从两个查询向量中搜索两组最相似 entity。

# 5. Batch-vector search
query_vectors = [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],
[0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104]
] # A list of two vectors

res = client.search(
collection_name="quick_setup",
data=query_vectors,
limit=2,
search_params={"metric_type": "IP", "params": {"nprobe": 10}}
)

print(res) # Two sets of results are to return

示例返回结果如下:

# Two sets of vectors are returned as expected

[
[
{
"id": 81,
"distance": 1.633650779724121,
"entity": {}
},
{
"id": 428,
"distance": 1.6174099445343018,
"entity": {}
}
],
[
{
"id": 972,
"distance": 1.7308459281921387,
"entity": {}
},
{
"id": 545,
"distance": 1.670518398284912,
"entity": {}
}
]
]

以上结果返回两组与查询向量最近邻的结果。

Partition search 是指将搜索范围限定在 collection 中的一个或多个 partition,此类型适用于按逻辑或类型划分的数据集。通过减少扫描的数据量,可以显著提高搜索速度。

进行 partition search 时,只需在搜索请求中的 partition_names 字段添加目标 partition 的名称即可,这样搜索操作将仅在指定 partition 内寻找相似向量。

以下是在名为 red 的 partition 内搜索 entity 的代码示例。

# 6.2 Search within a partition
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]

res = client.search(
collection_name="quick_setup",
data=[query_vector],
limit=5,
search_params={"metric_type": "IP", "params": {"nprobe": 10}},
partition_names=["red"]
)

print(res)

示例返回结果如下:

[
[
{
"id": 320,
"distance": 1.243729591369629,
"entity": {}
},
{
"id": 200,
"distance": 1.2299367189407349,
"entity": {}
},
{
"id": 154,
"distance": 1.1562182903289795,
"entity": {}
},
{
"id": 29,
"distance": 1.1135238409042358,
"entity": {}
},
{
"id": 109,
"distance": 1.0907914638519287,
"entity": {}
}
]
]

在名为 blue 的 partition 中搜索 entity:

res = client.search(
collection_name="quick_setup",
data=[query_vector],
limit=5,
search_params={"metric_type": "IP", "params": {"nprobe": 10}},
partition_names=["blue"]
)

print(res)

示例返回结果如下:

[
[
{
"id": 59,
"distance": 1.3296087980270386,
"entity": {}
},
{
"id": 139,
"distance": 1.1872179508209229,
"entity": {}
},
{
"id": 201,
"distance": 1.1474100351333618,
"entity": {}
},
{
"id": 298,
"distance": 1.117565631866455,
"entity": {}
},
{
"id": 435,
"distance": 1.0910152196884155,
"entity": {}
}
]
]

因为 partition_1 中的数据与 partition_2 中的不同,搜索结果将仅限于特定 partition,展示指定 partition 内的数据的独特性和分布情况。

使用 output_fields

在 search 时使用 output_fields 允许您在搜索请求中选择特定的输出字段,系统会将这些字段的值返回给匹配的结果向量。

您可以在请求中指定 output_fields,以返回包含特定字段的结果。

以下是返回结果中包含 color 字段值的代码示例:

# 7. Search with output fields
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]

res = client.search(
collection_name="quick_setup",
data=[query_vector],
limit=5,
search_params={"metric_type": "IP", "params": {"nprobe": 10}},
output_fields=["color"]
)

print(res)

示例返回结果如下:

[
[
{
"id": 29,
"distance": 2.6317718029022217,
"entity": {
"color": "red"
}
},
{
"id": 405,
"distance": 2.6302318572998047,
"entity": {
"color": "blue"
}
},
{
"id": 458,
"distance": 2.3892529010772705,
"entity": {
"color": "green"
}
},
{
"id": 555,
"distance": 2.350921154022217,
"entity": {
"color": "orange"
}
},
{
"id": 435,
"distance": 2.29063081741333,
"entity": {
"color": "blue"
}
}
]
]

除了最相似的 entity 外,搜索结果还会包括指定的 color 字段,为每个匹配的向量提供更详细的信息。

通过定义标量过滤条件,filtered search 可以精确调整向量搜索的结果。要了解更多关于过滤表达式的详细信息,请参阅标量过滤规则Get 和 Scalar Query

使用 like 操作符

like 操作符通过前缀、中缀和后缀匹配,显著提升了搜索特定字符串的灵活性与效率:

  • 前缀匹配:若需查找以特定前缀开头的字符串,使用语法 'like "prefix%"'

  • 中缀匹配:若需查找含特定字符序列的字符串,使用语法 'like "%infix%"'

  • 后缀匹配:若需查找以特定后缀结尾的字符串,使用语法 'like "%suffix"'

对于单字符匹配,下划线 (_) 作为单个字符的占位符,例如 'like "y_llow"',可匹配到 "yellow"

匹配包含特殊字符的字符串

在匹配本身包含下划线 (_) 或百分号(%)这类特殊字符的字符串时,由于它们通常在搜索模式中担当通配符的角色( _ 代表匹配任意单个字符,% 代表匹配任意字符序列),因此需要对这些字符进行转义,确保它们被视作字面字符处理。使用反斜杠(\)来转义特殊字符,并需要转义反斜杠本身。例如:

  • 若要搜索字面下划线(\),应使用 \_

  • 要搜索字面百分号(%),应使用 \%

因此,如果需要搜索文本 "_version_",过滤表达式应使用 'like "\_version\_"',确保下划线被视为搜索词的一部分,而非通配符,从而准确匹配目标字符串。

如果要筛选以 red 开头的 color,可以使用 'like "red%"' 表达式。

# 8. Filtered search
# 8.1 Filter with "like" operator and prefix wildcard
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]

res = client.search(
collection_name="quick_setup",
data=[query_vector],
limit=5,
search_params={"metric_type": "IP", "params": {"nprobe": 10}},
filter='color_tag like "red%"',
output_fields=["color_tag"]
)

print(res)

示例返回结果如下:

[
[
{
"id": 58,
"distance": 1.4645483493804932,
"entity": {
"color_tag": "red_8218"
}
},
{
"id": 307,
"distance": 1.4149816036224365,
"entity": {
"color_tag": "red_3923"
}
},
{
"id": 16,
"distance": 1.3404488563537598,
"entity": {
"color_tag": "red_9524"
}
},
{
"id": 142,
"distance": 1.31600022315979,
"entity": {
"color_tag": "red_4160"
}
},
{
"id": 438,
"distance": 1.315270185470581,
"entity": {
"color_tag": "red_8131"
}
}
]
]

若要筛选 color 字段值包含 ll 特定字符序列的字符串,可以参考如下示例:

# Infix match on color field
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]

res = client.search(
collection_name="quick_setup", # Replace with the actual name of your collection
data=[query_vector],
limit=5, # Max. number of search results to return
search_params={"metric_type": "IP", "params": {"level": 1}}, # Search parameters
output_fields=["color_tag"], # Output fields to return
filter='color like "%ll%"' # Filter on color field, infix match on "ll"
)

result = json.dumps(res, indent=4)
print(result)

示例返回结果如下:

[
[
{
"id": 5,
"distance": 0.7972343564033508,
"entity": {
"color": "yellow_4222"
}
}
]
]

Range search 能够帮助您找到距离查询向量在特定距离范围内的向量。

通过设置 radius,并选择性地指定 range_filter,您可以扩大搜索范围,将与查询向量相似度略有不同的向量也纳入搜索范围,以便更全面地查找可能的匹配项。

  • radius:设定搜索空间的最远边界。只有距离查询向量在这个范围内的向量才会被视为潜在的匹配项。

  • range_filter(可选):radius 定义了搜索范围的最远边界,range_filter 则用来设定内部边界,形成一个必须在这个范围内的向量才会被视为匹配的距离区间。

# Conduct a range search
search_params = {
"metric_type": "IP",
"params": {
"radius": 0.8, # Radius of the search circle
"range_filter": 1.0 # Range filter to filter out vectors that are not within the search circle
}
}

query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]

res = client.search(
collection_name="quick_setup", # Replace with the actual name of your collection
data=[query_vector],
limit=3, # Max. number of search results to return
search_params=search_params, # Search parameters
output_fields=["color_tag"], # Output fields to return
)

result = json.dumps(res, indent=4)
print(result)

示例返回结果如下:

[
[
{
"id": 136,
"distance": 2.4410910606384277,
"entity": {}
},
{
"id": 897,
"distance": 2.2852015495300293,
"entity": {}
},
{
"id": 336,
"distance": 2.2819623947143555,
"entity": {}
},
{
"id": 50,
"distance": 2.2552754878997803,
"entity": {}
},
{
"id": 462,
"distance": 2.2343976497650146,
"entity": {}
}
]
]

radiusrange_filter 的参数值设置会根据所用的度量类型而有所不同。

度量类型

特点

Range search

L2

较小的 L2 距离表示更高的相似性。

要排除结果中最近的向量,请确保:

range_filter <= distance < radius

IP

较大的 IP 距离表示更高的相似性。

要排除结果中最近的向量,请确保:

radius < distance <= range_filter

COSINE

较大的 cosine 值表示更高的相似性。

要排除结果中最近的向量,请确保:

radius < distance <= range_filter

JACCARD (Beta)

较小的 Jaccard 距离表示更高的相似性。

要排除结果中最近的向量,请确保:

range_filter <= distance < radius

HAMMING (Beta)

较小的 Hamming 距离表示更高的相似性。

要排除结果中最近的向量,请确保:

range_filter <= distance < radius

在 Zilliz Cloud 中,通过特定字段的 grouping search 能够避免结果中同一字段项的重复出现,从而获取更加多样化的结果。

假设有一个包含多个文档的 collection,每个文档都被切分成若干段落,每段落由一个向量 embedding 表示,并属于某一文档。为了寻找相关文档而不是相似段落,您可以在 search() 操作中使用 group_by_field 参数,按文档 ID 对结果进行分组。这样有助于返回最相关且独立的文档,而不是同一文档的不同段落。

📘说明

此功能目前仅适用于已升级到 Beta 版的 Zilliz Cloud 集群。

以下是一个按照指定字段执行 grouping search 的代码示例:

# Load data into collection
client.load_collection("group_search") # Collection name

# Group search results
res = client.search(
collection_name="group_search", # Collection name
data=[[0.14529211512077012, 0.9147257273453546, 0.7965055218724449, 0.7009258593102812, 0.5605206522382088]], # Query vector
search_params={
"metric_type": "L2",
"params": {"nprobe": 10},
}, # Search parameters
limit=10, # Max. number of search results to return
group_by_field="doc_id", # Group results by document ID
output_fields=["doc_id", "passage_id"]
)

# Retrieve the values in the `doc_id` column
doc_ids = [result['entity']['doc_id'] for result in res[0]]

print(doc_ids)

示例返回结果如下:

[5, 10, 1, 7, 9, 6, 3, 4, 8, 2]

在所给输出中,可以看到返回的 entity 中没有重复的 doc_id 值。

为了进行比较,我们注释掉 group_by_field 参数,然后执行一次常规搜索:

# Load data into collection
client.load_collection("group_search") # Collection name

# Search without `group_by_field`
res = client.search(
collection_name="group_search", # Collection name
data=query_passage_vector, # Replace with your query vector
search_params={
"metric_type": "L2",
"params": {"nprobe": 10},
}, # Search parameters
limit=10, # Max. number of search results to return
# group_by_field="doc_id", # Group results by document ID
output_fields=["doc_id", "passage_id"]
)

# Retrieve the values in the `doc_id` column
doc_ids = [result['entity']['doc_id'] for result in res[0]]

print(doc_ids)

示例返回结果如下:

[1, 10, 3, 10, 1, 9, 4, 4, 8, 6]

在以上的输出中,可以看到返回的 entity 存在重复 doc_id 值。

使用限制

  • 向量:当前,grouping search 不支持 BINARY_VECTOR 类型的向量字段。关于数据类型的更多信息,请参阅 Supported data types

  • 字段:当前,grouping search 仅支持单列。group_by_field 配置中不能指定多个字段名称。此外,grouping search 不支持 JSONFLOATDOUBLEARRAY 或向量字段的数据类型。

  • 性能:Grouping search 的查询性能随查询向量数增加而降低。例如,在配备 2 CPU 核和 8 GB 内存的集群中,grouping search 的执行时间会随着输入查询向量数的增加而增长。

  • 功能性:Grouping search 不支持 range search使用 iteratorshybrid search

Search 参数

以上搜索类型中,除了 range search 和 grouping search,其他搜索采用标准的 search 参数。通常,无需手动设置这些参数。

# In normal cases, you do not need to set search parameters manually
# Except for range searches.
search_parameters = {
'metric_type': 'L2',
'params': {
'nprobe': 10,
'level': 1
'radius': 1.0
'range_filter': 0.8
}
}

下表列出了 search 相关参数的可能配置:

参数

描述

metric_type

度量向量 embedding 间相似度的方法。

可选值为 IPL2COSINE。默认按已加载(load)的索引文件设定。

params.nprobe

搜索时查询的单位数。

取值范围为 [1, nlist[1]]。

params.level

Search 的精度等级。

可选值为 123,默认为 1。较高的值能提高精确度,但会降低性能。

params.radius

查询向量与候选向量间的最小相似度。

取值范围为 [1, nlist[1]]。

params.range_filter

相似度范围,可细化搜索范围,只包括在此范围内的向量。

取值范围为 [top-K[2], ∞]。

📘说明

[1] 索引后的集群单位数。建立索引时,Zilliz Cloud 会根据索引设置将向量数据分为多个集群单位。

[2] Search 结果中的 entity 数量。