Paginer les résultats de recherche

Les applications Web paginent souvent les données lorsqu'elles sont présentées aux utilisateurs. L'utilisateur final reçoit une page de résultats. Lorsqu'il accède à la page suivante, le lot suivant de résultats est récupéré et présenté. Cette page explique comment ajouter la pagination aux résultats de recherche lorsque vous effectuez une recherche en texte intégral dans Spanner.

Options de pagination

Il existe deux façons d'implémenter des requêtes paginées dans Spanner : la pagination basée sur une clé (recommandée) et la pagination basée sur un décalage.

La pagination basée sur des clés est une méthode permettant de récupérer les résultats de recherche en blocs plus petits et plus faciles à gérer, tout en garantissant des résultats cohérents entre les requêtes. Un identifiant unique (la "clé") du dernier résultat d'une page est utilisé comme point de référence pour extraire l'ensemble de résultats suivant.

Spanner recommande généralement d'utiliser la pagination basée sur une clé. Bien que la pagination basée sur le décalage soit plus facile à implémenter, elle présente deux inconvénients importants:

  1. Coût des requêtes plus élevé:la pagination basée sur un décalage récupère et supprime à plusieurs reprises les mêmes résultats, ce qui entraîne une augmentation des coûts et une baisse des performances.
  2. Résultats incohérents:dans les requêtes paginées, chaque page est généralement récupérée à un code temporel de lecture différent. Par exemple, la première page peut provenir d'une requête à 13h et la suivante d'une requête à 13h10. Cela signifie que les résultats de recherche peuvent changer d'une requête à l'autre, ce qui entraîne des résultats incohérents entre les pages.

La pagination basée sur une clé, en revanche, utilise un identifiant unique (clé) du dernier résultat d'une page pour récupérer l'ensemble de résultats suivant. Cela garantit une récupération efficace et des résultats cohérents, même si les données sous-jacentes changent.

Pour assurer la stabilité des résultats de page, l'application peut émettre toutes les requêtes pour différentes pages au même code temporel. Toutefois, cela peut échouer si la requête dépasse la durée de conservation des versions (par défaut, une heure). Par exemple, cette erreur se produit si version_gc est égal à une heure, et que l'utilisateur final a extrait les premiers résultats à 13h et cliqué sur Suivant à 15h.

Utiliser la pagination basée sur une clé

La pagination basée sur une clé mémorise le dernier élément de la page précédente et l'utilise comme point de départ pour la requête de la page suivante. Pour ce faire, la requête doit renvoyer les colonnes spécifiées dans la clause ORDER BY et limiter le nombre de lignes à l'aide de LIMIT.

Pour que la pagination basée sur une clé fonctionne, la requête doit trier les résultats selon un ordre total strict. Le moyen le plus simple d'obtenir un classement est de choisir un ordre total, puis d'ajouter des colonnes de départage, si nécessaire. Dans la plupart des cas, l'ordre total correspond à l'ordre de tri de l'index de recherche, et la combinaison unique de colonnes correspond à la clé primaire de la table de base.

En utilisant notre exemple de schéma Albums, la requête pour la première page se présente comme suit:

SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 10;

AlbumId est le cas de figure où il n'y a pas de gagnant, car ReleaseTimestamp n'est pas une clé. Il peut y avoir deux albums différents avec la même valeur pour ReleaseTimestamp.

Pour reprendre, l'application exécute à nouveau la même requête, mais avec une clause WHERE qui limite les résultats de la page précédente. La condition supplémentaire doit tenir compte de l'orientation de la clé (ascendante ou descendante), des cas de partage de valeur et de l'ordre des valeurs NULL pour les colonnes nullables.

Dans notre exemple, AlbumId est la seule colonne de clé (par ordre croissant) et ne peut pas être NULL. La condition est donc la suivante:

SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE (ReleaseTimestamp < @last_page_release_timestamp
       OR (ReleaseTimestamp = @last_page_release_timestamp
           AND AlbumId > @last_page_album_id))
      AND SEARCH(AlbumTitle_Tokens, @p)
ORDER BY ReleaseTimestamp DESC, AlbumId ASC
LIMIT @page_size;

Spanner interprète ce type de condition comme recherchable. Cela signifie que Spanner ne lit pas l'index des documents que vous filtrez. C'est cette optimisation qui rend la pagination basée sur les clés beaucoup plus efficace que la pagination basée sur les décalages.

Utiliser la pagination basée sur le décalage

La pagination basée sur le décalage exploite les clauses LIMIT et OFFSET de la requête SQL pour simuler des pages. La valeur LIMIT indique le nombre de résultats par page. La valeur OFFSET est définie sur zéro pour la première page, sur la taille de la page pour la deuxième page et sur le double de la taille de la page pour la troisième page.

Par exemple, la requête suivante extrait la troisième page, avec une taille de page de 50:

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 50 OFFSET 100;

Remarques sur l'utilisation :

  • La clause ORDER BY est fortement recommandée pour garantir un ordre cohérent entre les pages.
  • Dans les requêtes de production, utilisez des paramètres de requête plutôt que des constantes pour spécifier LIMIT et OFFSET afin de rendre le cache de requêtes plus efficace. Pour en savoir plus, consultez la section Paramètres de requête.

Étape suivante