Présentation des requêtes avec des filtres de plage et d'inégalité sur plusieurs propriétés

Firestore en mode Datastore permet d'utiliser des filtres de plage et d'inégalité sur plusieurs propriétés dans une seule requête. Cette fonctionnalité vous offre des conditions de plage et d'inégalité sur plusieurs propriétés, et simplifie le développement de votre application en déléguant l'implémentation de la logique de post-filtrage à Firestore en mode Datastore.

Filtres de plage et d'inégalité sur plusieurs propriétés

La requête suivante utilise des filtres de plage sur la priorité et les jours pour renvoyer toutes les tâches dont la priorité est supérieure à quatre et qui doivent être terminées en moins de trois jours.

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)

Considérations concernant l'indexation

Avant de commencer à exécuter des requêtes, assurez-vous d'avoir lu la section sur les requêtes.

Si aucune clause ORDER BY n'est spécifiée, Firestore en mode Datastore utilise n'importe quel indice pouvant répondre à la condition de filtrage de la requête pour l'exécuter. Cette approche produit un ensemble de résultats ordonnés selon la définition de l'index.

Pour optimiser les performances et les coûts des requêtes Firestore en mode Datastore, optimisez l'ordre des propriétés dans l'index. Pour ce faire, assurez-vous que votre index est trié de gauche à droite afin que la requête se transforme en ensemble de données qui empêche l'analyse d'entrées d'index superflues.

Par exemple, supposons que vous souhaitiez rechercher dans une collection d'employés ceux dont le salaire est supérieur à 100 000 $et dont le nombre d'années d'expérience est supérieur à 0. D'après votre compréhension du jeu de données, vous savez que la contrainte de salaire est plus sélective que la contrainte d'expérience. L'index (salary [...], experience [...]) est un index qui réduit le nombre d'analyses d'index. Par conséquent, une requête rapide et économique classe salary avant experience, comme illustré dans l'exemple suivant:

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"]

Bonnes pratiques pour optimiser les index

Lorsque vous optimisez des index, tenez compte des bonnes pratiques suivantes.

Trier les requêtes par égalités, puis par plage ou champ d'inégalité le plus sélectif

Firestore en mode Datastore utilise les propriétés les plus à gauche d'un index composite pour satisfaire les contraintes d'égalité, ainsi que les contraintes de plage et d'inégalité, le cas échéant, sur le premier champ de la requête orderBy(). Ces contraintes peuvent réduire le nombre d'entrées d'index que Firestore en mode Datastore analyse. Firestore en mode Datastore utilise les propriétés restantes de l'index pour répondre aux autres contraintes de plage et d'inégalité de la requête. Ces contraintes ne réduisent pas le nombre d'entrées d'index analysées par Firestore en mode Datastore, mais elles filtrent les entités non mises en correspondance afin de réduire le nombre d'entités renvoyées aux clients.

Pour en savoir plus sur la création d'index efficaces, consultez les sections Structure et définition des index et Optimiser les index.

Classer les propriétés par ordre décroissant de sélectivité de la contrainte de requête

Pour vous assurer que Firestore en mode Datastore sélectionne l'index optimal pour votre requête, spécifiez une clause orderBy() qui trie les propriétés de plage et d'inégalité en fonction de la sélectivité de leurs contraintes dans votre requête, en commençant par les plus sélectives. Une sélectivité plus élevée correspond à moins d'entités, tandis qu'une sélectivité plus faible correspond à plus d'entités. Dans l'ordre d'indexation, placez les propriétés de plage et d'inégalité ayant une sélectivité plus élevée avant celles ayant une sélectivité plus faible.

Pour réduire le nombre d'entités que Firestore en mode Datastore analyse et renvoie sur le réseau, vous devez toujours trier les propriétés par ordre décroissant de sélectivité des contraintes de requête. Si l'ensemble de résultats n'est pas dans l'ordre requis et qu'il est censé être de petite taille, vous pouvez implémenter une logique côté client pour le réorganiser conformément à vos attentes.

Par exemple, si vous souhaitez rechercher dans une collection d'employés des employés basés aux États-Unis dont le salaire est supérieur à 100 000 $et classer les résultats par année d'expérience de l'employé. Si vous prévoyez que seul un petit nombre d'employés auront un salaire supérieur à 100 000 $, voici un moyen efficace d'écrire la requête:

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`

Bien que l'ajout d'un tri sur experience à la requête produise le même ensemble d'entités et évite de réorganiser les résultats sur les clients, la requête peut lire beaucoup plus d'entrées d'index superflues que la requête précédente. En effet, Firestore en mode Datastore préfère toujours un indice dont le préfixe de propriétés d'index correspond à la clause de tri de la requête. Si experience a été ajouté à la clause "order by", Firestore en mode Datastore sélectionnera l'index (experience [...], salary [...]) pour calculer les résultats de la requête. Comme il n'y a pas d'autres contraintes sur experience, Firestore en mode Datastore lit toutes les entrées d'index de la collection employees avant d'appliquer le filtre salary pour trouver l'ensemble de résultats final. Cela signifie que les entrées d'index qui ne satisfont pas le filtre salary sont toujours lues, ce qui augmente la latence et le coût de la requête.

Tarifs

Les requêtes avec des filtres de plage et d'inégalité sur plusieurs propriétés sont facturées en fonction des entités lues et des entrées d'index lues.

Pour en savoir plus, consultez la page Tarifs.

Limites

En plus des limites des requêtes, veuillez noter les limites suivantes avant d'utiliser des requêtes avec des filtres de plage et d'inégalité sur plusieurs propriétés:

  • Pour éviter que les requêtes ne deviennent trop coûteuses à exécuter, Firestore en mode Datastore limite le nombre d'opérateurs de plage ou d'inégalité à 10.

Étape suivante