注释
prefilter
和 postfilter
已在最新的稳定 REST API 版本中正式发布。
在 Azure AI 搜索中,可以使用筛选表达式将包含或排除条件添加到矢量查询。 你还可以指定应用筛选器的筛选模式:
- 在查询执行前,称为“预筛选”。
- 在查询执行后,称为“后筛选”。
本文使用 REST 进行说明。 有关其他语言和包含矢量查询的端到端解决方案中的代码示例,请参阅 azure-search-vector-samples GitHub 存储库。
还可以在 Azure 门户中使用搜索资源管理器来查询矢量内容。 如果使用 JSON 视图,可以添加筛选器并指定筛选器模式。
筛选在矢量查询中的工作原理
筛选器适用于 filterable
非函数 字段(字符串或数字),以基于筛选条件包括或排除搜索文档。 虽然矢量字段不可筛选,但可以使用同一索引中非函数字段的筛选器来包含或排除包含要搜索的矢量字段的文档。
如果索引缺少合适的文本或数字字段,请检查在筛选中可能有用的文档元数据,例如 LastModified
或 CreatedBy
属性。
参数 vectorFilterMode
控制在矢量搜索过程中何时应用筛选器,k
设置要返回的最近邻居的最大数目。 根据筛选模式以及筛选条件的严格程度,返回的结果可能少于 k
个。
定义 筛选器
筛选器确定矢量查询的范围,并使用文档 - 搜索 Post (REST API) 进行定义。 除非想要使用预览功能,否则请使用搜索服务 REST API 的最新稳定版本来构造请求。
此 REST API 提供:
-
filter
的条件。 -
vectorFilterMode
用于预查询或查询后筛选。 有关支持的模式,请参阅 下一部分。
POST https://{search-endpoint}/indexes/{index-name}/docs/search?api-version={api-version}
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,
. . . // Trimmed for readability
-0.02178128,
-0.00086512347
],
"exhaustive": true,
"fields": "contentVector",
"k": 5
}
]
}
在此示例中,矢量嵌入面向 contentVector
字段,筛选条件应用于 category
(一个可筛选的文本字段)。 由于使用了 preFilter
模式,将在搜索引擎运行查询之前应用筛选器,因此在矢量搜索期间只会考虑 Databases
类别中的文档。
设置筛选器模式
vectorFilterMode
参数确定相对于矢量查询执行应用筛选器的时间和方式。 有三种模式:
-
preFilter
(默认值) postFilter
预筛选在查询执行之前应用筛选器,这减少了矢量搜索算法的候选集。 然后,将从此筛选后的集合中选择前 k
个结果。
在矢量查询中,preFilter
是默认模式,因为它更重视召回率和质量,而非延迟。
预筛选和后筛选的基准测试
重要
本部分适用于预筛选和后筛选,不适用于严格后筛选。
为了了解一种筛选器模式比另一种筛选器模式表现更好的条件,我们运行了一系列测试来评估小型、中型和大型索引的查询结果。
- 小型(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%
的速率意味着筛选条件选择了百分之一的搜索语料库。