编号 | 160 |
---|---|
原文链接 | https://google.aip.dev/160 |
状态 | 批准 |
创建日期 | 2020-02-24 |
更新日期 | 2020-02-24 |
通常在列出资源(使用AIP-132中定义的List方法或类似方法)时,需要能够过滤集合,只返回用户需要的结果。
虽然可以定义独立的结构为每个API处理更精确的过滤需求,但是过滤需求经常变化,明智的做法是使用一个字符串字段,采用非技术人员也能理解的结构化语法。这样可以透明地进行更新,无需等待界面或客户端升级。
注意 应为列表过滤器面对的是非技术人员,所以通常会借鉴口语形式,而非代码常用的模式。
指南
API 可以 在 List
方法(或类似的 Search
等查询集合方法)中向用户提供过滤功能。此时 应当 遵守本文讨论的通用过滤规范。过滤语法使用扩展巴科斯范式正式定义。
在过滤时,请求消息 应当 只有一个过滤字段,即 string filter
。过滤对象的工作遍历操作符或函数处理。
注意 列表过滤器支持模糊匹配特性,具有结果排序和评分功能。希望了解列表过滤器确定性评估的开发者,请参考CEL。
字面值
字面值(如"42"、“Hugo”)是要匹配的值。单独出现的字面值(没有指定域)通常 应当 在任何的对象域中进行匹配。
然而,服务 可以 选择只处理某些域;此时 必须 在文档中记录所处理的域。服务 可以 随时增加所处理的域,但 应当 谨慎考虑对现有用户的影响。
注意 用空格分隔的字面值可以看作
AND
的简化变体。Victor Hugo
大致等同于Victor AND Hugo
。
逻辑运算符
实现过滤功能时, 应当 提供以下二元运算符:
运算符 | 示例 | 含义 |
---|---|---|
AND | a AND b | a 、 b 都为真,则为真。 |
OR | a OR b OR c | a 、b 、 c 中任意一个为真,则为真。 |
注意 为了匹配常见的口语形式,
OR
运算符的优先级高于AND
,这与大多数编程语言不同。表达式a AND b OR c
的求值顺序为a AND (b OR c)
。API文档和示例 应当 鼓励使用显式括号,避免混淆。但 不应 强制使用显式括号。
否定运算符
实现过滤功能时, 应当 提供一元运算符 NOT
和 -
。二者可以互换使用。支持否定运算的服务 必须 同时支持两种格式。
运算符 | 示例 | 含义 |
---|---|---|
NOT | NOT a | 如果 a 不为真,则为真。 |
- | -a | 如果 a 不为真,则为真。 |
比较运算符
实现过滤功能时, 应当 为字符串、数字、时间戳和时间段提供二元比较运算符 =
、 !=
、 <
、 >
、 <=
和 >=
(但 不应 为布尔值或枚举值提供这些运算符)。
运算符 | 示例 | 含义 |
---|---|---|
= | a = true | 如果 a 为真,则为真。 |
!= | a != 42 | 除非 a 等于42,否则为真。 |
< | a < 42 | 如果 a 是低于42的数字值,则为真。 |
> | a > "foo" | 如果 a 在字典顺序上排在"foo"之后,则为真。 |
<= | a <= "foo" | 如果 a 是"foo"或在字典顺序上排在它之前,则为真。 |
>= | a >= 42 | 如果 a 是42或更高的数字值,则为真。 |
注意 和大多数编程语言不同,域名字 必须 出现在比较运算符的左侧。右侧只接受字面值和逻辑运算符。
因为过滤器是以查询字符串传递,因此需要进行类型转换,将字符串转换为适当的强类型值:
- 枚举值使用枚举的字符串表示(区分大小写)。
- 布尔值使用
true
和false
字面值。 - 数字使用标准的整数或浮点数表示。对于浮点数,支持指数表示法(如
2.997e9
)。 - 时间段使用数字表示,后跟
s
后缀(表示秒)。例如20s
,1.2s
。 - 时间戳使用RFC-3339格式的字符串(如
2012-04-21T11:30:00-04:00
)。支持UTC偏移量。
警告 标识符
true
、false
和null
仅在带类型的域引用的上下文中具有实际含义。
此外,在比较字符串相等时,服务 应当 支持使用 *
的通配符;例如 a = "*.foo"
如果 a
以".foo"结尾,则为真。
遍历操作符
实现过滤功能时, 应当 提供 .
操作符,表示遍历消息、映射或结构。
示例 | 含义 |
---|---|
a.b = true | 如果 a 有一个布尔域 b 为真,则为真。 |
a.b > 42 | 如果 a 有一个数字域 b 大于42,则为真。 |
a.b.c = "foo" | 如果 a.b 有一个字符串域 c 为"foo",则为真。 |
必须 使用资源的域名字进行遍历。如果服务希望支持某种“隐含域”, 必须 通过具有良好文档的函数实现。服务 可以 指定支持遍历的域的子集。
如果用户尝试遍历消息上未定义的域,服务 应当 返回 INVALID_ARGUMENT
错误。服务 可以 允许遍历映射和结构上未定义的键,并 应当 在文档中记录具体的行为。
重要
.
操作符 不得 用于遍历重复域或列表,与:
操作符一起使用时除外。
存在操作符
实现过滤时, 必须 提供 :
操作符,表示“存在”。可以用于集合(重复域或映射)或消息,不同情况下的行为略有不同。
重复字段查询,查看重复结构中是否包含匹配元素:
示例 | 含义 |
---|---|
r:42 | 如果 r 包含42,则为真。 |
r.foo:42 | 如果 r 包含一个元素 e ,使得 e.foo = 42 ,则为真。 |
重要 过滤器不能查询重复域中的特定元素的值。如
e.0.foo = 42
和e[0].foo = 42
是 无 效过滤器。
映射、结构、消息可以查询映射中是否存在域或特定值:
示例 | 含义 |
---|---|
m:foo | 如果 m 包含键"foo",则为真。 |
m.foo:* | 如果 m 包含键"foo",则为真。 |
m.foo:42 | 如果 m.foo 为42,则为真。 |
在解析消息时有两个细微的区别:
- 在遍历消息时,域只有在具有非默认值时才被视为存在。
- 在遍历消息时,域名字使用下划线命名,实现也 可以 选择支持自动转换成驼峰命名。
函数
过滤语言支持函数调用语法,支持API专属扩展。API 可以 使用 call(arg...)
语法定义函数,且 必须 在文档中记录所支持的任何特定函数。
限制
服务 可以 为过滤查询设定进一步的结构或限制。这些内容超出本文范围。例如,服务可能支持逻辑运算符,但只允许一定数量的运算符(避免“死亡查询”或其他性能问题)。
更多的结构或限制 必须 在文档中明确记录, 不得 违反本文要求。
验证
如果设定了不规范或模式无效的 filter
字符串,API 应当 返回 INVALID_ARGUMENT
错误。如果放宽对 filter
的验证,API 必须 在文档中记录差异。
模式验证包括但不限于以下内容:
filter
引用的域 必须 在过滤模式中村咋filter
提供的域值 必须 与域的类型一致- 例如,对于域
int32 age
,类似"age=hello"
的filter
是无效的
- 例如,对于域
filter
提供的有限数据类型(如enum
)的域值 必须 是集合中的有效值filter
提供的标准类型(如Timestamp
)的域值 必须 符合文档记录的标准(参考比较运算符,获取这些类型的列表)
修订记录
- 2024-12-11 将不规范过滤器的指南移至验证部分。