複数のプロパティに対する範囲フィルタと不等式フィルタを使用したクエリの概要

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 のクエリのパフォーマンスと費用を最適化するには、インデックス内のプロパティの順序を最適化する必要があります。これを行うには、不要なインデックス エントリのスキャンを防ぐデータセットにクエリが抽出するようにインデックスを左から右に並べる必要があります。

従業員のコレクションを検索し、給与が 100,000 を超え、経験年数が 0 を超える従業員を見つけるとします。データセットに関する知識に基づき、給与の制約は経験の制約よりも選択的であることがわかります。インデックス スキャンの数を減らす理想的なインデックスは、(salary [...], experience [...]) インデックスです。したがって、高速で費用対効果の高いクエリは、experience の前に salary を順序付けすると、次のようになります。

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 がネットワーク経由でスキャンして返すエンティティの数を最小限に抑えるには、常にクエリ制約の選択性降順でプロパティを並べ替える必要があります。結果セットが必要な順序ではなく、結果セットのサイズが小さいと予想される場合、クライアントサイドのロジックを実装して、順序の想定に沿って順序を並べ替えることができます。

たとえば、従業員のコレクションを検索して、給与が 100,000 を超える従業員を見つけて、結果を従業員の経験年数で並べ替えるとします。少数の従業員のみ給与が 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 は、インデックス プロパティの接頭辞がクエリの order by 句と一致するインデックスを常に優先するためです。experience が order by 句に追加された場合、Datastore モードの Firestore はクエリ結果を計算するために (experience [...], salary [...]) インデックスを選択します。experience には他の制約がないため、Datastore モードの Firestore は、salary フィルタを適用する前に employees コレクションのすべてのインデックス エントリを読み取り、最終結果セットを見つけます。つまり、salary フィルタを満たさないインデックス エントリがまだ読み取られるため、クエリのレイテンシとコストが増加します。

料金

複数のプロパティに対して範囲フィルタと不等式フィルタを使用したクエリは、エンティティの読み取りとインデックス エントリの読み取りに基づいて課金されます。

詳細については、料金ページをご覧ください。

制限事項

クエリの制限とは別に、複数のプロパティに対する範囲フィルタと不等式フィルタでクエリを使用する前に、次の制限事項に注意してください。

  • Datastore モードの Firestore では、範囲演算子または不等式演算子の数が 10 に制限されています。これは、クエリの実行に要するコストが高くならないようにするためです。

次のステップ