Azure AI 搜索中 $filter
、$orderby
和 $select
的 OData 语言概述
本文概述了在 Azure AI 搜索中使用 $filter
、$order-by
和 $select
表达式的 OData 表达式语言,这些表达式用于在 Azure AI 搜索中对数字和字符串(非函数)字段进行关键字搜索。
该语言按“自下而上”的顺序演示,从最基本的元素开始。 可以在查询请求中构造的 OData 表达式从简单到非常复杂,但它们全部共享通用元素。 共享元素包括:
- 字段路径:引用索引的特定字段。
- 常量:特定数据类型的文本值。
了解这些常见概念后,可以继续使用每个表达式的顶级语法:
- $filter 表达式在查询分析期间进行求值,将搜索范围限制为特定字段或添加索引扫描期间使用的匹配条件。
- $orderby 表达式作为后处理步骤应用于结果集,对返回的文档进行排序。
- $select 表达式确定要包含在结果集中的文档字段。
这些表达式的语法不同于 search 参数中使用的简单或完整查询语法,但引用字段的语法中存在一定的重叠。
注意
Azure AI 搜索中的术语在某些方面不同于 OData 标准。 Azure AI 搜索中所谓的字段在 OData 中称为属性,类似地,字段路径在 OData 中称为属性路径。 Azure AI 搜索中包含文档的索引在 OData 中更普遍地称为包含实体的实体集。 本参考文档使用 Azure AI 搜索的术语。
字段路径
以下 EBNF(扩展巴科斯-瑙尔范式)定义字段路径的语法。
field_path ::= identifier('/'identifier)*
identifier ::= [a-zA-Z_][a-zA-Z_0-9]*
下面还提供了交互式语法图:
注意
请参阅适用于 Azure AI 搜索的 OData 表达式语法参考以获取完整的 EBNF。
字段路径由斜杠分隔的一个或多个标识符组成。 每个标识符是必须以 ASCII 字母或下划线开头的一系列字符,只能包含 ASCII 字母、数字或下划线。 字母可以采用大写或小写。
标识符可以引用字段的名称,或者引用筛选器的集合表达式上下文中的某个范围变量(any
或 all
)。 范围变量类似于表示集合的当前元素的循环变量。 对于复杂集合,该变量表示某个对象,正因如此,你可以使用字段路径来引用变量的子字段。 这类似于许多编程语言中的点表示法。
下表显示了字段路径的示例:
字段路径 | 说明 |
---|---|
HotelName |
引用索引的顶级字段 |
Address/City |
引用索引中复杂字段的 City 子字段;在此示例中,Address 的类型为 Edm.ComplexType |
Rooms/Type |
引用索引中复杂集合字段的 Type 子字段;在此示例中,Rooms 的类型为 Collection(Edm.ComplexType) |
Stores/Address/Country |
引用索引中复杂集合字段的 Address 子字段的 Country 子字段;在此示例中,Stores 的类型为 Collection(Edm.ComplexType) ,Address 的类型为 Edm.ComplexType |
room/Type |
引用 room 范围变量的 Type 子字段(例如,在筛选表达式 Rooms/any(room: room/Type eq 'deluxe') 中) |
store/Address/Country |
引用 store 范围变量的 Address 子字段的 Country 子字段(例如,在筛选表达式 Stores/any(store: store/Address/Country eq 'Canada') 中) |
字段路径的含义因上下文而异。 在筛选器中,字段路径引用当前文档中某个字段的单个实例的值。 在其他上下文中(例如 $orderby、 $select,或完整 Lucene 语法中的字段搜索),字段路径引用该字段本身。 这种差异会根据你在筛选器中使用字段路径的方式而产生一些后果。
以字段路径 Address/City
为例。 在筛选器中,此字段路径引用当前文档的单个城市,例如“旧金山”。 相比之下,Rooms/Type
引用许多客房的 Type
子字段(例如,“标准”表示第一间客房,“豪华”表示第二间客房,等等)。 由于 Rooms/Type
不引用子字段 Type
的单个实例,因此不能直接在筛选器中使用。 若要根据客房类型进行筛选,请使用包含范围变量的 Lambda 表达式,如下所示:
Rooms/any(room: room/Type eq 'deluxe')
在此示例中,范围变量 room
显示在 room/Type
字段路径中。 于是,room/Type
引用当前文档中当前客房的类型。 这是 Type
子字段的单个实例,因此可以直接在筛选器中使用。
使用字段路径
Azure AI 搜索 REST API 的许多参数中使用字段路径。 下表列出了可以使用字段路径的所有位置,以及字段路径用法的任何限制:
API | 参数名称 | 限制 |
---|---|---|
创建或更新索引 | suggesters/sourceFields |
无 |
创建或更新索引 | scoringProfiles/text/weights |
只能引用可搜索字段 |
创建或更新索引 | scoringProfiles/functions/fieldName |
只能引用可筛选字段 |
搜索 | 当 queryType 为 full 时,该参数为 search |
只能引用可搜索字段 |
搜索 | facet |
只能引用可分面字段 |
搜索 | highlight |
只能引用可搜索字段 |
搜索 | searchFields |
只能引用可搜索字段 |
建议和自动完成 | searchFields |
只能引用属于建议器的字段 |
搜索、建议和自动完成 | $filter |
只能引用可筛选字段 |
搜索和建议 | $orderby |
只能引用可排序字段 |
搜索、建议和查找 | $select |
只能引用可检索字段 |
常量
OData 中的常量是给定实体数据模型 (EDM) 类型的文本值。 有关 Azure AI 搜索中受支持类型的列表,请参阅支持的数据类型。 不支持集合类型的常量。
下表显示了支持 OData 表达式的每个非函数数据类型的常量示例:
数据类型 | 示例常量 |
---|---|
Edm.Boolean |
true 、false |
Edm.DateTimeOffset |
2019-05-06T12:30:05.451Z |
Edm.Double |
3.14159 、-1.2e7 、NaN 、INF 、-INF |
Edm.GeographyPoint |
geography'POINT(-122.131577 47.678581)' |
Edm.GeographyPolygon |
geography'POLYGON((-122.031577 47.578581, -122.031577 47.678581, -122.131577 47.678581, -122.031577 47.578581))' |
Edm.Int32 |
123 、-456 |
Edm.Int64 |
283032927235 |
Edm.String |
'hello' |
转义字符串常量中的特殊字符
OData 中的字符串常量由单引号分隔。 如果需要使用本身可能包含单引号的字符串常量构造查询,则可以通过将嵌入的引号加倍来对其进行转义。
例如,带有无格式撇号的短语(如“Alice's car”)将在 OData 中表示为字符串常量 'Alice''s car'
。
重要
以编程方式构建筛选器时,请记住转义来自用户输入的字符串常量,这一点很重要。 这是为了减少注入攻击的可能性,特别是在使用筛选器实现安全修整时。
常量语法
以下 EBNF(扩展巴科斯-瑙尔范式)定义上表中所示的大多数常量的语法。 可在 Azure AI 搜索中的 OData 地理空间函数中找到地理空间类型的语法。
constant ::=
string_literal
| date_time_offset_literal
| integer_literal
| float_literal
| boolean_literal
| 'null'
string_literal ::= "'"([^'] | "''")*"'"
date_time_offset_literal ::= date_part'T'time_part time_zone
date_part ::= year'-'month'-'day
time_part ::= hour':'minute(':'second('.'fractional_seconds)?)?
zero_to_fifty_nine ::= [0-5]digit
digit ::= [0-9]
year ::= digit digit digit digit
month ::= '0'[1-9] | '1'[0-2]
day ::= '0'[1-9] | [1-2]digit | '3'[0-1]
hour ::= [0-1]digit | '2'[0-3]
minute ::= zero_to_fifty_nine
second ::= zero_to_fifty_nine
fractional_seconds ::= integer_literal
time_zone ::= 'Z' | sign hour':'minute
sign ::= '+' | '-'
/* In practice integer literals are limited in length to the precision of
the corresponding EDM data type. */
integer_literal ::= digit+
float_literal ::=
sign? whole_part fractional_part? exponent?
| 'NaN'
| '-INF'
| 'INF'
whole_part ::= integer_literal
fractional_part ::= '.'integer_literal
exponent ::= 'e' sign? integer_literal
boolean_literal ::= 'true' | 'false'
下面还提供了交互式语法图:
注意
请参阅适用于 Azure AI 搜索的 OData 表达式语法参考以获取完整的 EBNF。
基于字段路径和常量生成表达式
字段路径和常量是 OData 表达式的最基本组成部分,但它们已经是完整的表达式。 事实上,Azure AI 搜索中的 $select 参数无非就是逗号分隔的字段路径列表,而 $orderby 也并不比 $select 复杂多少。 如果你正好在索引中使用了 Edm.Boolean
类型的字段,则你甚至可以编写一个只包含该字段的路径的筛选器。 常量 true
和 false
同样是有效的筛选器。
但是,具有引用多个字段和常量的复杂表达式更为常见。 这些表达式的生成方式根据参数而异。
以下 EBNF(扩展巴科斯-瑙尔范式)定义 $filter 、$orderby 和 $select 参数的语法。 这些表达式是基于引用字段路径和常量的更简单表达式生成的:
filter_expression ::= boolean_expression
order_by_expression ::= order_by_clause(',' order_by_clause)*
select_expression ::= '*' | field_path(',' field_path)*
下面还提供了交互式语法图:
注意
请参阅适用于 Azure AI 搜索的 OData 表达式语法参考以获取完整的 EBNF。
后续步骤
$orderby 和 $select 参数都是较简单表达式的逗号分隔列表。 $filter 参数是由较简单的子表达式构成的布尔表达式。 这些子表达式是使用逻辑运算符(例如 and
、or
和 not
)、比较运算符(例如 eq
、lt
、gt
等)和集合运算符(例如 any
和 all
)合并的。
以下文章更详细地探讨了 $filter、 $orderby 和 $select 参数: