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

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

对多个属性使用范围和不等式过滤条件

以下查询对优先级和天数使用范围过滤条件,返回优先级高于 4 且完成时间少于 3 天的所有任务。

Go

query := datastore.NewQuery("Task").
   FilterField("priority", ">", 4).
   FilterField("days", "<", 3).

GQL

SELECT * FROM /tasks WHERE priority > 4 AND days < 3;

Java

Query<Entity> query =
    Query.newEntityQueryBuilder()
      .setKind("Task")
      .setFilter(
        CompositeFilter.and(
            PropertyFilter.gt("priority", 4), PropertyFilter.lt("days", 3)))
    .build();

Node.js

const query = datastore
  .createQuery('Task')
  .filter(
    and([
      new PropertyFilter('priority', '>', 4),
      new PropertyFilter('days', '<', 3),
    ])
  );

Python

from google.cloud import datastore
client = datastore.Client()
query = client.query(kind="Task")
query.add_filter(filter=PropertyFilter("priority", ">", 4))
query.add_filter(filter=PropertyFilter("days", "<", 3))

PHP

$query = $datastore->query()
    ->kind('Task')
    ->filter('priority', '>', 4)
    ->filter('days', '<', 3)

C#

Query query = new Query("Task")
{
  Filter = Filter.And(Filter.GreaterThan("priority", 4),
    Filter.LessThan("days", 3))
};

Ruby

query = datastore.query("Task")
                 .where("priority", ">", 4)
                 .where("days", "<", 3)

索引编制注意事项

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

如果未指定 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 万美元的美国员工,并将结果按员工的工作经验年限进行排序。如果您预计只有少数员工的薪水会超过 10 万美元,那么可按如下所示编写高效的查询:

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 添加到排序依据子句,则 Datastore 模式 Firestore 会选择使用 (experience [...], salary [...]) 索引来计算查询结果。由于没有对 experience 使用其他限制条件,因此,Datastore 模式 Firestore 会先读取 employees 集合的所有索引条目,然后才会应用 salary 过滤条件来查找最终的结果集。这意味着,不满足 salary 过滤条件的索引条目仍会被读取,从而导致查询的延迟时间和费用增加。

价格

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

如需了解详细信息,请参阅价格页面。

限制

除了查询限制之外,在使用对多个媒体资源使用范围和不等式过滤条件的查询之前,还应注意以下限制:

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

后续步骤