排查 Azure AI 搜索中的 OData 集合筛选器问题

若要根据 Azure AI 搜索中的集合字段进行筛选,可以结合 Lambda 表达式使用 anyall 运算符。 Lambda 表达式是应用到每个集合元素的子筛选器。

并非每个筛选表达式功能都可在 Lambda 表达式中使用。 可用的功能因要筛选的集合字段的数据类型而异。 如果你尝试在 Lambda 表达式中使用该上下文不支持的某个功能,可能会导致错误。 如果你在尝试基于集合字段编写复杂的筛选器时遇到此类错误,本文可帮助你排查问题。

常见的集合筛选器错误

下表列出了在尝试执行集合筛选器时可能会遇到的错误。 使用 Lambda 表达式中不支持的筛选表达式功能时,将发生这些错误。 每个错误提供了有关如何重写筛选器以避免该错误的一些指导。 表格中还包含了本文相关部分的链接,其中提供了有关如何避免该错误的详细信息。

错误消息 场景 详细信息
函数 ismatch 没有任何参数绑定到范围变量“s”。 Lambda 表达式中仅支持绑定的字段引用('any' 或 'all')。 但可以更改筛选器,使 ismatch 函数位于 Lambda 表达式的外部,然后重试。 在 Lambda 表达式中使用 search.ismatchsearch.ismatchscoring 有关筛选复杂集合的规则
Lambda 表达式无效。 找到了一个相等性或不相等性测试,但循环访问 Collection(Edm.String) 类型的的字段的 Lambda 表达式预期需要相反的测试。 对于 'any',请使用 'x eq y' 或 'search.in(...)' 格式的表达式。 对于 'all',请使用 'x ne y'、'not (x eq y)' 或 'not search.in(...)' 格式的表达式。 根据 Collection(Edm.String) 类型的字段进行筛选 有关筛选字符串集合的规则
Lambda 表达式无效。 找到了不受支持格式的复杂布尔表达式。 对于 'any',请使用“AND 的 OR”格式(也称为析取范式)的表达式。 例如 (a and b) or (c and d),其中 a、b、c 和 d 是比较或相等子表达式。 对于 'all',请使用“OR 的 AND”格式(也称为合取范式)的表达式。 例如 (a or b) and (c or d),其中 a、b、c 和 d 是比较或不等子表达式。 比较表达式的示例:'x gt 5'、'x le 2'。 相等性表达式的示例:'x eq 5'。 不相等性表达式的示例:'x ne 5'。 根据 Collection(Edm.DateTimeOffset)Collection(Edm.Double)Collection(Edm.Int32)Collection(Edm.Int64) 类型的字段进行筛选 有关筛选可比较集合的规则
Lambda 表达式无效。 在循环访问 Collection(Edm.GeographyPoint) 类型的字段的 Lambda 表达式中找到 geo.distance() 或 geo.intersects() 的不受支持用法。 对于 'any',请确保使用 'lt' 或 'le' 运算符比较 geo.distance(),并确保不要对 geo.intersects() 的任何用法进行求反。 对于 'all',请确保使用 'gt' 或 'ge' 运算符比较 geo.distance(),并确保对 geo.intersects() 的任何用法进行求反。 根据 Collection(Edm.GeographyPoint) 类型的字段进行筛选 有关筛选 GeographyPoint 集合的规则
Lambda 表达式无效。 循环访问 Collection(Edm.GeographyPoint) 类型的字段的 Lambda 表达式中不支持复杂布尔表达式。 对于“any”,请使用“or”联接子表达式;不支持“and”。 对于“any”,请使用“and”联接子表达式;不支持“or”。 根据 Collection(Edm.String)Collection(Edm.GeographyPoint) 类型的字段进行筛选 有关筛选字符串集合的规则

有关筛选 GeographyPoint 集合的规则
Lambda 表达式无效。 找到比较运算符(一个 'lt'、'le'、'gt' 或 'ge')。 循环访问 Collection(Edm.String) 类型的字段的 Lambda 表达式中只允许相等性运算符。 对于 'any',请使用 'x eq y' 格式的表达式。 对于 'all',请使用 'x ne y' 或 'not (x eq y)' 格式的表达式。 根据 Collection(Edm.String) 类型的字段进行筛选 有关筛选字符串集合的规则

如何编写有效的集合筛选器

有关编写有效集合筛选器的规则对于每种数据类型各不相同。 以下部分通过示例介绍了这些规则,其中指出了支持和不支持的筛选器功能:

有关筛选字符串集合的规则

在字符串集合的 Lambda 表达式中,只能使用 eqne 比较运算符。

注意

Azure AI 搜索不支持对字符串使用 lt/le/gt/ge 运算符,无论字符串是在 Lambda 表达式的内部还是外部。

只能在 any 的正文中测试相等性,只能在 all 的正文中测试不相等性。

还可以通过 any 正文中的 or,以及通过 all 正文中的 and,来合并多个表达式。 由于 search.in 函数等效于将相等性检查与 or 相结合,因此,any 的正文中也允许该函数。 相比之下,all 的正文中允许 not search.in

例如,允许以下表达式:

  • tags/any(t: t eq 'books')
  • tags/any(t: search.in(t, 'books, games, toys'))
  • tags/all(t: t ne 'books')
  • tags/all(t: not (t eq 'books'))
  • tags/all(t: not search.in(t, 'books, games, toys'))
  • tags/any(t: t eq 'books' or t eq 'games')
  • tags/all(t: t ne 'books' and not (t eq 'games'))

不允许以下表达式:

  • tags/any(t: t ne 'books')
  • tags/any(t: not search.in(t, 'books, games, toys'))
  • tags/all(t: t eq 'books')
  • tags/all(t: search.in(t, 'books, games, toys'))
  • tags/any(t: t eq 'books' and t ne 'games')
  • tags/all(t: t ne 'books' or not (t eq 'games'))

有关筛选布尔集合的规则

类型 Edm.Boolean 仅支持 eqne 运算符。 因此,允许使用 and/or 将检查相同范围变量的子句组合起来没有多大意义,因为这始终会导致赘述或矛盾。

下面是允许的根据布尔集合进行筛选的一些示例:

  • flags/any(f: f)
  • flags/all(f: f)
  • flags/any(f: f eq true)
  • flags/any(f: f ne true)
  • flags/all(f: not f)
  • flags/all(f: not (f eq true))

与字符串集合不同,布尔集合对于可在哪种类型的 Lambda 表达式中使用哪个运算符不设限制。 在 anyall 的正文中可以使用 eqne

布尔集合不允许如下所示的表达式:

  • flags/any(f: f or not f)
  • flags/any(f: f or f)
  • flags/all(f: f and not f)
  • flags/all(f: f and f eq true)

有关筛选 GeographyPoint 集合的规则

集合中 Edm.GeographyPoint 类型的值不能直接相互比较。 必须将它们用作 geo.distancegeo.intersects 函数的参数。 然后,必须使用 ltlegtge 比较运算符将 geo.distance 函数与距离值进行比较。 这些规则也适用于非集合 Edm.GeographyPoint 字段。

与字符串集合一样,Edm.GeographyPoint 集合在如何在不同类型的 Lambda 表达式中使用与合并地理空间函数方面也实施了一些规则:

  • 可在 geo.distance 函数中使用哪些比较运算符取决于 Lambda 表达式的类型。 对于 any,只能使用 ltle。 对于 all,只能使用 gtge。 可将涉及 geo.distance 的表达式求反,但必须更改比较运算符(geo.distance(...) lt x 更改为 not (geo.distance(...) ge x)geo.distance(...) le x 更改为 not (geo.distance(...) gt x))。
  • all 的正文中,必须将 geo.intersects 函数求反。 相反,在 any 的正文中,不得将 geo.intersects 函数求反。
  • any 的正文中,可以使用 or 来合并地理空间表达式。 在 all 的正文中,可以使用 and 来合并此类表达式。

之所以存在上述限制,是因为字符串集合存在类似的相等性/不相等性限制。 若要深入了解这些原因,请参阅了解 Azure AI 搜索中的 OData 集合筛选器

下面是允许的根据 Edm.GeographyPoint 集合进行筛选的一些示例:

  • locations/any(l: geo.distance(l, geography'POINT(-122 49)') lt 10)
  • locations/any(l: not (geo.distance(l, geography'POINT(-122 49)') ge 10) or geo.intersects(l, geography'POLYGON((-122.031577 47.578581, -122.031577 47.678581, -122.131577 47.678581, -122.031577 47.578581))'))
  • locations/all(l: geo.distance(l, geography'POINT(-122 49)') ge 10 and not geo.intersects(l, geography'POLYGON((-122.031577 47.578581, -122.031577 47.678581, -122.131577 47.678581, -122.031577 47.578581))'))

Edm.GeographyPoint 集合不允许如下所示的表达式:

  • locations/any(l: l eq geography'POINT(-122 49)')
  • locations/any(l: not geo.intersects(l, geography'POLYGON((-122.031577 47.578581, -122.031577 47.678581, -122.131577 47.678581, -122.031577 47.578581))'))
  • locations/all(l: geo.intersects(l, geography'POLYGON((-122.031577 47.578581, -122.031577 47.678581, -122.131577 47.678581, -122.031577 47.578581))'))
  • locations/any(l: geo.distance(l, geography'POINT(-122 49)') gt 10)
  • locations/all(l: geo.distance(l, geography'POINT(-122 49)') lt 10)
  • locations/any(l: geo.distance(l, geography'POINT(-122 49)') lt 10 and geo.intersects(l, geography'POLYGON((-122.031577 47.578581, -122.031577 47.678581, -122.131577 47.678581, -122.031577 47.578581))'))
  • locations/all(l: geo.distance(l, geography'POINT(-122 49)') le 10 or not geo.intersects(l, geography'POLYGON((-122.031577 47.578581, -122.031577 47.678581, -122.131577 47.678581, -122.031577 47.578581))'))

有关筛选可比较集合的规则

本部分适用于以下所有数据类型:

  • Collection(Edm.DateTimeOffset)
  • Collection(Edm.Double)
  • Collection(Edm.Int32)
  • Collection(Edm.Int64)

Edm.Int32Edm.DateTimeOffset 等类型支持所有六个比较运算符:eqneltlegtge。 这些类型的集合上的 Lambda 表达式可以包含使用上述任一运算符的简单表达式。 这适用于 anyall。 例如,允许以下筛选器:

  • ratings/any(r: r ne 5)
  • dates/any(d: d gt 2017-08-24T00:00:00Z)
  • not margins/all(m: m eq 3.5)

但是,在如何在 Lambda 表达式中将此类比较表达式合并成更复杂的表达式方面存在一些限制:

  • 适用于 any 的规则:
    • 简单的不相等性表达式不能有效地与任何其他表达式合并。 例如,允许以下表达式:

      • ratings/any(r: r ne 5)

      但不允许以下表达式:

      • ratings/any(r: r ne 5 and r gt 2)

      尽管允许此表达式,但由于条件重叠,此表达式没有作用:

      • ratings/any(r: r ne 5 or r gt 7)
    • 涉及 eqltlegtge 的简单比较表达式可与 and/or 合并。 例如:

      • ratings/any(r: r gt 2 and r le 5)
      • ratings/any(r: r le 5 or r gt 7)
    • 使用 and(合取)合并的比较表达式可以通过 or 进一步合并。 此格式在布尔逻辑中称为“析取范式” (DNF)。 例如:

      • ratings/any(r: (r gt 2 and r le 5) or (r gt 7 and r lt 10))
  • 适用于 all 的规则:
    • 简单的相等性表达式不能有效地与任何其他表达式合并。 例如,允许以下表达式:

      • ratings/all(r: r eq 5)

      但不允许以下表达式:

      • ratings/all(r: r eq 5 or r le 2)

      尽管允许此表达式,但由于条件重叠,此表达式没有作用:

      • ratings/all(r: r eq 5 and r le 7)
    • 涉及 neltlegtge 的简单比较表达式可与 and/or 合并。 例如:

      • ratings/all(r: r gt 2 and r le 5)
      • ratings/all(r: r le 5 or r gt 7)
    • 使用 or(析取)合并的比较表达式可以通过 and 进一步合并。 此格式在布尔逻辑中称为“合取范式” (CNF)。 例如:

      • ratings/all(r: (r le 2 or gt 5) and (r lt 7 or r ge 10))

有关筛选复杂集合的规则

基于复杂集合的 Lambda 表达式支持的语法比基于基元类型的集合的 Lambda 表达式更灵活。 可在外部使用的任何筛选器构造也可以在此类 Lambda 表达式内部使用,只存在两种例外情况。

第一,Lambda 表达式中不支持 search.ismatchsearch.ismatchscoring 函数。 有关详细信息,请参阅了解 Azure AI 搜索中的 OData 集合筛选器

第二,不允许引用未绑定到范围变量(所谓的“自由变量”)的字段。 例如,考虑以下两个等效的 OData 筛选表达式:

  1. stores/any(s: s/amenities/any(a: a eq 'parking')) and details/margin gt 0.5
  2. stores/any(s: s/amenities/any(a: a eq 'parking' and details/margin gt 0.5))

允许第一个表达式,而第二种格式则被拒绝,因为 details/margin 未绑定到范围变量 s

此规则还会延伸到在外部范围中绑定了变量的表达式。 此类变量的显示范围是自由的。 例如,允许第一个表达式,但不允许第二个等效的表达式,因为 s/name 相对于范围变量 a 的范围是自由的:

  1. stores/any(s: s/amenities/any(a: a eq 'parking') and s/name ne 'Flagship')
  2. stores/any(s: s/amenities/any(a: a eq 'parking' and s/name ne 'Flagship'))

在实践中,此限制应该不是一个问题,因为始终可以构造筛选器,使 Lambda 表达式只包含绑定的变量。

集合筛选器规则速查表

下表汇总了有关为每个集合数据类型构建有效筛选器的规则。

数据类型 any 的 lambda 表达式中允许的功能 all 的 lambda 表达式中允许的功能
Collection(Edm.ComplexType) search.ismatchsearch.ismatchscoring 外的所有内容 相同
Collection(Edm.String) 使用 eqsearch.in 进行比较

使用 or 组合子表达式
使用 nenot search.in() 进行比较

使用 and 组合子表达式
Collection(Edm.Boolean) 使用 eqne 进行比较 相同
Collection(Edm.GeographyPoint) geo.distanceltle 配合使用

geo.intersects

使用 or 组合子表达式
geo.distancegtge 配合使用

not geo.intersects(...)

使用 and 组合子表达式
Collection(Edm.DateTimeOffset)Collection(Edm.Double)Collection(Edm.Int32)Collection(Edm.Int64) 使用 eqneltgtlege 进行比较

使用 or 将比较与其他子表达式组合

使用 and 将除 ne 以外的比较与其他子表达式组合

在析取范式 (DNF) 中使用 andor 组合的表达式
使用 eqneltgtlege 进行比较

使用 and 将比较与其他子表达式组合

使用 or 将除 eq 以外的比较与其他子表达式组合

在合取范式 (CNF) 中使用 andor 组合的表达式

有关如何为每个用例的构建有效筛选器的示例,请参阅如何编写有效的集合筛选器

如果你经常编写筛选器,那么与仅仅是记住规则相比,从首要原理上理解规则将能够带来更大的帮助,请参阅了解 Azure AI 搜索中的 OData 集合筛选器

后续步骤