你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。

了解 Azure AI 搜索中的 OData 集合筛选器的工作原理

注意

Azure AI 搜索可通过Azure门户、REST API 和Azure SDK获取。 它也是 Foundry IQ 的基础;Foundry IQ 是一个托管式知识层,可将企业内容转化为供 Microsoft Foundry 门户中的智能体使用的、可复用且具备权限感知能力的知识库。

本文为使用复杂 lambda 表达式编写高级筛选器的开发人员提供了背景信息。 本文探讨了 Azure AI 搜索如何执行这些筛选器,并据此解释了为何需要为集合筛选器创建规则。

在 Azure AI 搜索中构建基于集合字段的筛选器时,可以结合使用 any 和 all 运算符与 lambda 表达式。 Lambda 表达式是引用范围变量的布尔表达式。 在使用 lambda 表达式的筛选器中,any 和 all 运算符类似于大多数编程语言中的 for 循环,范围变量充当循环变量的角色,而 Lambda 表达式充当循环的主体。 范围变量在循环迭代期间采用集合的“当前”值。

至少在概念上它是这样运作的。 在事实上,Azure AI 搜索实现筛选器的方式与 for 循环的工作原理有很大的不同。 理想情况下,你察觉不到这种差异,但在某些情况下你会感受到这种差异。 最终结果是,在编写 Lambda 表达式时必须遵循某些规则。

注意

有关集合筛选器有哪些可用的规则(包括示例)的信息,请参阅排查 Azure AI 搜索中的 OData 集合筛选器问题。

集合筛选器为何受到限制

并非所有类型的集合都完全支持筛选器功能,这有三个根本原因:

  1. 特定的数据类型仅支持特定的运算符。 例如,使用比较运算符(如 true 和 false)来比较布尔值 lt 和 gt 是没有意义的。
  2. Azure AI 搜索 支持对类型为 Collection(Edm.ComplexType) 的字段进行关联筛选,但对这些字段执行字段级全文搜索则是非关联的。
  3. Azure AI 搜索使用倒排索引对所有类型的数据(包括集合)执行筛选器。

第一个原因只是 OData 语言和 EDM 类型系统的定义方式造成的。 本文的余下部分将更详细地解释后两个原因。

对复杂对象的集合应用多个筛选条件时,这些条件是关联的,因为它们将应用于集合中的每个对象。 例如,以下筛选器将返回至少提供一间价格低于 100 的豪华客房的酒店:

    Rooms/any(room: room/Type eq 'Deluxe Room' and room/BaseRate lt 100)

如果筛选不相关,上述筛选器可能会返回这样的酒店,其中一间客房是豪华型,而另一间客房的基本价格低于 100。 该结果没有任何意义,因为 Lambda 表达式的两个子句将应用到同一个范围变量,即 room。 这就是此类筛选器相关联的原因。

但是,对于全文搜索,无法引用特定的范围变量。 如果使用字段搜索发出如下所示的完整 Lucene 查询:

    Rooms/Type:deluxe AND Rooms/Description:"city view"

你可能会找到一些酒店,其中一间客房是豪华型,另一间客房在描述中提到了“市景”。 例如,下列包含Id和1的文档会匹配查询:

{
  "value": [
    {
      "Id": "1",
      "Rooms": [
        { "Type": "deluxe", "Description": "Large garden view suite" },
        { "Type": "standard", "Description": "Standard city view room" }
      ]
    },
    {
      "Id": "2",
      "Rooms": [
        { "Type": "deluxe", "Description": "Courtyard motel room" }
      ]
    }
  ]
}

原因在于,Rooms/Type 引用了整个文档中 Rooms/Type 字段的所有已分析字词,Rooms/Description 与此类似,如下表所示。

全文搜索中Rooms/Type的存储方式:

Rooms/Type 中的字词 文档 ID
豪华 1, 2
标准 1

全文搜索中Rooms/Description的存储方式:

Rooms/Description 中的字词 文档 ID
庭院 2
城市 1
花园 1
大 1
汽车旅馆 2
客房 1, 2
标准 1
套件 1
视图 1

简单而言,上述筛选器指出“匹配其中某间客房的 Type 等于‘豪华客房’,且同一间客房 的 BaseRate 小于 100 的文档”,而该搜索查询则与此不同,它指出“匹配其中的 Rooms/Type 包含字词‘豪华’且 Rooms/Description 包含短语‘市景’的文档”。 对于后面的查询,可关联哪些客房的字段没有概念。

倒排索引和集合

你可能会注意到,lambda 表达式对复杂集合的限制比简单集合的限制要少得多,例如 Collection(Edm.Int32) 和 Collection(Edm.GeographyPoint)。 存在这种差异,因为Azure AI 搜索将复杂集合存储为子文档的实际集合,而简单集合根本不作为集合存储。

例如,假设某个在线零售商的索引中包含类似于 seasons 的可筛选字符串集合字段。 上传到此索引的某些文档可能如下所示:

{
  "value": [
    {
      "id": "1",
      "name": "Hiking boots",
      "seasons": ["spring", "summer", "fall"]
    },
    {
      "id": "2",
      "name": "Rain jacket",
      "seasons": ["spring", "fall", "winter"]
    },
    {
      "id": "3",
      "name": "Parka",
      "seasons": ["winter"]
    }
  ]
}

seasons 字段的值存储在称作“倒排索引”的结构中,如下所示:

术语 文档 ID
春 1, 2
夏 1
秋 1, 2
冬 2、3

此数据结构旨在快速解答一个问题:给定的字词出现在哪些文档中? 解答此问题的过程更像是一个普通的相等性检查,而不是基于集合的循环。 事实上,正因如此,对于字符串集合,Azure AI 搜索仅允许使用 eq 作为 any 的 Lambda 表达式中的比较运算符。

接下来,我们将探讨如何将同一范围变量的多个相等性检查与 or 组合在一起。 此方法得益于代数原理以及限定符的分布属性。 此表达式:

    seasons/any(s: s eq 'winter' or s eq 'fall')

等效于:

    seasons/any(s: s eq 'winter') or seasons/any(s: s eq 'fall')

可以使用倒排索引有效执行两个 any 子表达式中的每一个。 另外,得益于量词的否定律,此表达式:

    seasons/all(s: s ne 'winter' and s ne 'fall')

等效于:

    not seasons/any(s: s eq 'winter' or s eq 'fall')

正因如此,我们可以将 all 与 ne 和 and 一起使用。

注意

尽管本文档并未详细介绍,但相同的原理也可以延伸到地理空间点集合的距离和交集测试。 因此,在 any 中:

  • geo.intersects 不能取反
  • 必须使用 geo.distance 或 lt 来比较 le
  • 必须使用 or 而不是 and 合并表达式

相反的规则适用于 all。

在对支持 lt、gt、le 和 ge 运算符的数据类型集合进行筛选时,可以使用更多种表达式,例如 Collection(Edm.Int32)。 具体而言,您可以在 and 和 or 中使用 any,前提是用 将基础比较表达式组合为and,然后使用 or 进一步组合这些比较。 这种布尔表达式结构称为析取范式 (DNF),也称为“AND 的 OR”。 相反,这些数据类型的all Lambda 表达式必须采用合取范式 (CNF),也称为“OR 的 AND”。 Azure AI 搜索之所以允许此类范围比较,是因为它可以有效地使用倒排索引执行这些比较,就像它可以针对字符串执行快速字词查找一样。

总结了有关 Lambda 表达式中允许的元素的经验法则如下:

  • 在 any 中,始终允许 正向检查,例如相等性、范围比较、geo.intersects,或者 geo.distance 与 lt 或 le 的比较(在检查距离时,将“靠近程度”视作与相等性类似的概念)。
  • 在 any 中,始终允许 or。 只能对可以表达范围检查的数据类型使用 and,并且只能在使用“AND 的 OR”(DNF) 时使用它。
  • 在 all 中,规则将会反转。 只允许负检查,始终可以使用 and,只能对表达为“用 AND 连接的 OR”(CNF) 的范围检查使用 or。

在实践中,你最有可能使用这些筛选器类型。 不过,了解可能性的界限仍然有帮助。

有关允许和不允许的筛选器类型的具体示例,请参阅如何编写有效的集合筛选器。

后续步骤