在 Azure AI 搜索中,可以定义包含 筛选器表达式 的矢量查询请求,以便向查询添加包含条件或排除条件。 本文介绍如何:
本文使用 REST 进行说明。 有关其他语言和包含矢量查询的端到端解决方案中的代码示例,请参阅 azure-search-vector-samples GitHub 存储库。
还可以在 Azure 门户中使用搜索资源管理器来查询矢量内容。 如果使用 JSON 视图,可以添加筛选器并指定筛选器模式。
筛选在矢量查询中的工作原理
筛选器适用于 filterable
非函数 字段(字符串或数字),以基于筛选条件包括或排除搜索文档。 虽然矢量字段本身不可筛选,但可以将筛选器添加到同一索引中的非矢量字段,以包含或排除同时包含要搜索的向量字段的文档。
筛选器将根据 vectorFilterMode
参数在查询执行之前或之后应用。
定义 筛选器
筛选器确定了矢量查询的范围。 它们被设定在索引中标记为 filterable
的非向量字符串和数值字段,并对其进行迭代。 筛选器的目的是确定矢量查询在哪些内容上执行,即在整个可搜索空间(预过滤)或搜索结果的内容(后过滤)。
如果没有包含文本或数值的源字段,请检查文档元数据(如 LastModified
或 CreatedBy
属性),这些字段在元数据筛选器中可能很有用。
2024-07-01 是此 API 的稳定版本。 此版本具有以下功能:
-
vectorFilterMode
用于预筛选(默认)或后筛选模式。 -
filter
的条件。
在以下示例中,矢量是此查询字符串的表示形式:“what Azure services support full text search”。 查询面向 contentVector
字段。 实际向量有 1,536 个嵌入项,因此为了可读性进行了剪裁。
在搜索引擎执行矢量查询之前,筛选条件将应用于可筛选文本字段(在本示例中为 category
)。
POST https://{{search-service-name}}.search.azure.cn/indexes/{{index-name}}/docs/search?api-version=2024-07-01
Content-Type: application/json
api-key: {{admin-api-key}}
{
"count": true,
"select": "title, content, category",
"filter": "category eq 'Databases'",
"vectorFilterMode": "preFilter",
"vectorQueries": [
{
"kind": "vector",
"vector": [
-0.009154141,
0.018708462,
. . .
-0.02178128,
-0.00086512347
],
"exhaustive": true,
"fields": "contentVector",
"k": 5
}
]
}
设置 vectorFilterMode
查询参数vectorFilterMode
确定筛选器是在执行矢量查询之前还是之后应用。
矢量筛选器模式的基准测试
为了了解一种筛选器模式比另一种筛选器模式表现更好的条件,我们运行了一系列测试来评估小型、中型和大型索引的查询结果。
- 小型(100,000 个文档、2.5 GB 索引、1,536 个维度)
- 中(100 万个文档,25 GB 索引,1,536 个维度)
- 大型(10 亿个文档,1.9 TB 索引,96 个维度)
对于中小型工作负荷,我们使用了具有 1 个分区和 1 个副本的标准 2 (S2) 服务。 对于大型工作负荷,我们使用了具有 12 个分区和 1 个副本的标准 3 (S3) 服务。
索引具有相同的构造:1 个键字段、1 个矢量字段、1 个文本字段和 1 个数字可筛选字段。 定义以下索引时使用 2023-11-03
语法。
def get_index_schema(self, index_name, dimensions):
return {
"name": index_name,
"fields": [
{"name": "id", "type": "Edm.String", "key": True, "searchable": True},
{"name": "content_vector", "type": "Collection(Edm.Single)", "dimensions": dimensions,
"searchable": True, "retrievable": True, "filterable": False, "facetable": False, "sortable": False,
"vectorSearchProfile": "defaulthnsw"},
{"name": "text", "type": "Edm.String", "searchable": True, "filterable": False, "retrievable": True,
"sortable": False, "facetable": False},
{"name": "score", "type": "Edm.Double", "searchable": False, "filterable": True,
"retrievable": True, "sortable": True, "facetable": True}
],
"vectorSearch": {
"algorithms": [
{
"name": "defaulthnsw",
"kind": "hnsw",
"hnswParameters": { "metric": "euclidean" }
}
],
"profiles": [
{
"name": "defaulthnsw",
"algorithm": "defaulthnsw"
}
]
}
}
在查询中,我们对前置筛选器操作和后置筛选器操作使用了相同的筛选器。 我们使用简单的筛选器来确保性能变化是由于筛选模式,而不是筛选复杂性。
结果以每秒查询(QPS)度量。
要点
前置筛选几乎总是比后置筛选慢,除非是在性能大致相同的小索引上进行筛选。
在较大的数据集上,前置筛选速度要慢几个数量级。
为什么预筛选是默认选项如果它几乎总是更慢? 前置筛选可保证返回
k
个结果(如果它们在索引中存在),其中偏向于召回率和精准率而不是速度。使用后过滤技术,如果你:
优先考虑速度而不在乎选择(筛选后返回的结果可能少于
k
个结果)。不要使用过于挑剔的筛选器。
具有足够大小的索引,使预筛选性能不可接受。
详细信息
给定具有 100,000 个矢量的数据集,其维度为 1,536:
筛选数据集的 30% 以上的内容时,前置筛选和后置筛选具有可比性。
筛选数据集的不到 0.1% 的内容时,前置筛选比后置筛选大约慢 50%。
给定具有 100 万个矢量的数据集,其维度为 1,536:
筛选数据集的 30% 以上的内容时,前置筛选大约慢 30%。
筛选数据集的不到 2% 的内容时,前置筛选大约慢 7 倍。
给定一个在维度数为 96 时矢量数为 10 亿的数据集:
筛选数据集的 5% 以上的内容时,前置筛选大约慢 50%。
筛选数据集的 10% 以下的内容时,前置筛选大约慢 7 倍。
下图显示了前置筛选器的相对 QPS,计算方式为前置筛选器 QPS 除以后置筛选器 QPS。
垂直轴表示预筛选相对于后筛选的相对性能,表示为 QPS 的比率(每秒查询数)。 例如:
- 预筛选值
0.0
比后期筛选慢 100%。 - 一个值为
0.5
的情况意味着预筛选速度慢了 50%。 - 前筛选和后筛选的值为
1.0
时是等效的。
横轴表示筛选率,或表示应用筛选器后候选文档的百分比。 例如,1.00%
的速率意味着筛选条件选择了百分之一的搜索语料库。