对多个属性概览使用范围和不等式过滤条件的查询

Datastore 模式 Firestore 支持在单个查询中对多个属性使用范围和不等式过滤条件。您现在可以对多个属性设置范围和不等式条件,并通过将过滤后逻辑的实现委托给 Datastore 模式 Firestore 来简化应用开发。

针对多个属性的范围和不等式过滤条件

以下查询返回年龄大于 35,身高介于 60 到 70 之间,且使用针对年龄和身高的范围过滤条件的所有用户。

GQL

 SELECT * FROM /users WHERE age > 35 AND height > 60 AND height < 70;

Java


  Query<Entity> query =
    Query.newEntityQueryBuilder()
      .setKind("users")
      .setFilter(
        CompositeFilter.and(
            PropertyFilter.gt("age", 35), PropertyFilter.gt("height", 60), PropertyFilter.lt("height", 70)))
    .build();

索引注意事项

在开始运行查询之前,请确保您已阅读有关查询的内容。

如果未指定 ORDER BY 子句,则 Datastore 模式 Firestore 使用任何能满足查询过滤条件的索引来处理查询,从而生成根据索引定义进行排序的结果集。

如需优化 Datastore 模式 Firestore 查询的性能和费用,您应优化索引中属性的顺序。为此,您应该确保索引按从左到右的顺序排列,以便查询能够提取到可防止扫描无关索引条目的数据集。

假设您想要搜索一组员工,并查找薪资超过 10 万且工作年数大于 0 的员工。根据您对数据集的了解,您知道工资限制条件比经验限制条件更具选择性。可以减少索引扫描次数的理想索引是 (salary [...], experience [...]) 索引。因此,快速且经济高效的查询会将 salary 放在 experience 之前,如下所示:

GQL

SELECT *
FROM /employees
WHERE salary > 100000 AND experience > 0
ORDER BY salary, experience

Java

Query<Entity> query =
  Query.newEntityQueryBuilder()
    .setKind("employees")
    .setFilter(
        CompositeFilter.and(
            PropertyFilter.gt("salary", 100000), PropertyFilter.gt("experience", 0)))
    .setOrderBy(OrderBy("salary"), OrderBy("experience"))
    .build();

Node.js

const query = datastore
  .createQuery("employees")
  .filter(
    and([
      new PropertyFilter("salary", ">", 100000),
      new PropertyFilter("experience", ">", 0),
       ])
    )
  .order("salary")
  .order("experience");

Python

query = client.query(kind="employees")
query.add_filter("salary", ">", 100000)
query.add_filter("experience", ">", 0)
query.order = ["-salary", "-experience"]

优化索引的最佳实践

优化索引时,请注意以下最佳实践。

按等式顺序对查询进行排序,后跟选择性最高的范围或不等式字段

Datastore 模式 Firestore 使用复合索引的最左边属性来满足 orderBy() 查询的第一个字段的等式约束以及范围和不等式约束条件(如果有)。这些限制条件可以减少 Datastore 模式 Firestore 扫描的索引条目数量。Datastore 模式 Firestore 使用索引的其余属性来满足查询的其他范围和不等式约束。这些限制不会减少 Datastore 模式 Firestore 扫描的索引条目数量,而是会过滤掉不匹配的实体,从而减少返回给客户端的实体数量。

如需详细了解如何创建高效索引,请参阅索引结构和定义以及优化索引

按查询限制条件选择性降序对属性进行排序

要确保 Datastore 模式 Firestore 为您的查询选择最佳索引,请指定 orderBy() 子句,以按查询限制选择性降序对范围和不等式属性进行排序。选择性较高的实体会匹配较小的实体子集,而较低的选择性则会匹配较大实体子集。请确保在索引排序时尽早选择选择性较高的范围和不等式属性,而不是选择性较低的属性。

为了最大限度地减少 Datastore 模式 Firestore 通过网络扫描和返回的实体数量,您应始终按查询限制条件选择性降序对属性进行排序。如果结果集不符合要求的顺序,并且结果集预计很小,您可以实现客户端逻辑,以按照所需的排序方式对其进行重新排序。

例如,假设您想要搜索一组员工以查找薪资超过 10 万的员工,并按员工的工作年数对结果进行排序。如果您预计只有少数员工的薪资会超过 100, 000,那么编写查询的最有效方式如下所示:

Java

Query<Entity> query =
  Query.newEntityQueryBuilder()
    .setKind("employees")
    .setFilter(PropertyFilter.gt("salary", 100000))
    .setOrderBy(OrderBy("salary"))
    .build();
QueryResults<Entity> results = datastore.run(query);
// Order results by `experience`

Node.js

const query = datastore
  .createQuery("employees")
  .filter(new PropertyFilter("salary", ">", 100000))
  .order("salary");
const [entities] = await datastore.runQuery(query);
// Order results by `experience`

Python

query = client.query(kind="employees")
query.add_filter("salary", ">", 100000)
query.order = ["salary"]
results = query.fetch()
// Order results by `experience`

虽然为查询添加 experience 排序会生成相同的实体集,并避免对客户端上的结果进行重新排序,但查询可能会比先前的查询读取更多无关的索引条目。这是因为 Datastore 模式 Firestore 始终优先选择其索引属性前缀与查询的“排序依据”子句匹配的索引。如果将 experience 添加到 order by 子句,则 Datastore 模式 Firestore 将选择 (experience [...], salary [...]) 索引来计算查询结果。由于 experience 没有其他限制,因此 Datastore 模式 Firestore 会先读取 employees 集合的所有索引条目,然后再应用 salary 过滤条件来查找最终结果集。这意味着系统会读取不符合 salary 过滤条件的索引条目,从而提高查询的延迟时间和费用。

价格

针对多个属性使用范围和不等式过滤条件的查询根据实体读取和索引条目读取来计费。

如需了解详情,请参阅价格页面。

限制

在对多个属性使用包含范围和不等式过滤条件的查询之前,请注意以下限制:除了查询限制

  • Datastore 模式 Firestore 将范围或不等式运算符的数量限制为 10。这是为了防止查询的运行费用过高。

后续步骤