Implémenter la pagination et les totaux de recherche avec la recherche FHIR

L'implémentation de la recherche FHIR de l'API Cloud Healthcare est hautement évolutive et performante, tout en respectant les consignes et les limites de REST et de la spécification FHIR. Pour ce faire, la recherche FHIR présente les propriétés suivantes:

  • Le nombre total de résultats de recherche est une estimation jusqu'à ce que la dernière page soit renvoyée. Les résultats de recherche renvoyés par la méthode fhir.search incluent le total de la recherche (propriété Bundle.total), qui correspond au nombre total de correspondances dans la recherche. Le nombre total de recherches est une estimation jusqu'à ce que la dernière page des résultats de recherche soit renvoyée. Le total de la recherche renvoyé avec la dernière page de résultats est une somme exacte de toutes les correspondances de la recherche.

  • Les résultats de recherche proposent une pagination séquentielle et ascendante. Lorsqu'il y a d'autres résultats de recherche à renvoyer, la réponse inclut une URL de pagination (Bundle.link.url) pour obtenir la page de résultats suivante.

Cas d'utilisation de base

La recherche FHIR fournit des solutions aux cas d'utilisation suivants:

Consultez les sections suivantes pour découvrir les solutions possibles pour ces cas d'utilisation.

Parcourir de manière séquentielle

Vous pouvez créer une application à faible latence qui permet à un utilisateur de parcourir séquentiellement les pages de résultats jusqu'à ce qu'il trouve la correspondance souhaitée. Cette solution est envisageable si le nombre de correspondances est suffisamment faible pour que l'utilisateur puisse trouver la correspondance souhaitée en parcourant les pages sans sauter de résultats. Si votre cas d'utilisation nécessite que les utilisateurs naviguent vers l'avant de plusieurs pages à la fois ou vers l'arrière, consultez Accéder à une page à proximité.

Cette solution ne peut pas fournir un total de recherche précis tant que la dernière page de résultats n'est pas renvoyée. Toutefois, il peut fournir un total de recherche approximatif avec chaque page de résultats. Bien qu'un total de recherche précis puisse être requis pour un processus en arrière-plan, un total de recherche approximatif est généralement suffisant pour un utilisateur humain.

Workflow

Voici un exemple de workflow pour cette solution:

  1. Une application appelle la méthode fhir.search, qui renvoie la première page des résultats de recherche. La réponse inclut une URL de pagination (Bundle.link.url) si d'autres résultats doivent être renvoyés. La réponse inclut également le nombre total de résultats de recherche (Bundle.total). Si le nombre de résultats à renvoyer est supérieur à celui de la réponse initiale, le nombre total de résultats de recherche n'est qu'une estimation. Pour en savoir plus, consultez Pagination et tri.

  2. L'application affiche la page des résultats de recherche, un lien vers la page suivante des résultats (le cas échéant) et le nombre total de résultats.

  3. Si l'utilisateur souhaite afficher la page de résultats suivante, il clique sur le lien, ce qui génère un appel à l'URL de pagination. La réponse inclut une nouvelle URL de pagination si d'autres résultats doivent être renvoyés. La réponse inclut également le nombre total de recherches. Il s'agit d'une estimation mise à jour s'il y a d'autres résultats à renvoyer.

  4. L'application affiche la nouvelle page de résultats de recherche, un lien vers la page suivante (le cas échéant) et le nombre total de résultats.

  5. Les deux étapes précédentes sont répétées jusqu'à ce que l'utilisateur arrête de rechercher ou que la dernière page de résultats soit renvoyée.

Bonne pratique

Choisissez un format de page adapté à la lecture par un humain. Selon votre cas d'utilisation, il peut s'agir de 10 à 20 correspondances par page. Les pages plus petites se chargent plus rapidement, et un trop grand nombre de liens sur une page peut être difficile à gérer pour un utilisateur. Vous contrôlez la taille de la page avec le paramètre _count.

Traiter un ensemble de résultats de recherche

Vous pouvez obtenir un ensemble de résultats de recherche en effectuant des appels successifs à la méthode fhir.search à l'aide de l'URL de pagination. Si le nombre de résultats de recherche est suffisamment faible, vous pouvez obtenir un ensemble complet de résultats en continuant jusqu'à ce qu'il n'y ait plus de pages à renvoyer. Un total précis des recherches est inclus dans la dernière page de résultats. Une fois les résultats de recherche obtenus, votre application peut les lire et effectuer le traitement, l'analyse ou l'agrégation dont vous avez besoin.

Gardez à l'esprit que si vous obtenez un très grand nombre de résultats de recherche, il est possible que vous ne puissiez pas obtenir la dernière page des résultats de recherche (et le nombre exact de résultats) dans un délai raisonnable.

Workflow

Voici un exemple de workflow pour cette solution:

  1. L'application appelle la méthode fhir.search, qui renvoie la première page des résultats de recherche. La réponse inclut une URL de pagination (Bundle.link.url) si d'autres résultats doivent être renvoyés.

  2. Si d'autres résultats doivent être renvoyés, l'application appelle l'URL de pagination de l'étape précédente pour obtenir la page de résultats de recherche suivante.

  3. L'application répète l'étape précédente jusqu'à ce qu'il n'y ait plus de résultats à renvoyer ou qu'une autre limite prédéfinie soit atteinte. Si vous atteignez la dernière page des résultats de recherche, le nombre total de recherches est exact.

  4. L'application traite les résultats de recherche.

Selon votre cas d'utilisation, votre application peut effectuer l'une des opérations suivantes:

  • Attendez que tous les résultats de recherche soient reçus avant de traiter les données.
  • Traitez les données à mesure qu'elles sont reçues à chaque appel successif de fhir.search.
  • Définissez une limite, comme le nombre de correspondances renvoyées ou le temps écoulé. Lorsque la limite est atteinte, vous pouvez traiter les données, ne pas les traiter ou effectuer une autre action.

Options de conception

Voici quelques options de conception qui peuvent réduire la latence de recherche:

  • Définir une grande taille de page Utilisez le paramètre _count pour définir une grande taille de page, par exemple entre 500 et 1 000, en fonction de votre cas d'utilisation. L'utilisation d'une taille de page plus importante augmente la latence pour chaque récupération de page, mais elle peut accélérer le processus global, car moins de récupérations de pages sont nécessaires pour obtenir l'ensemble des résultats de recherche.

  • Limitez les résultats de recherche. Si tout ce dont vous avez besoin est un total de recherche précis (vous n'avez pas besoin de renvoyer le contenu de la ressource), définissez le paramètre _elements de la méthode fhir.search sur identifier. Cela peut réduire la latence de votre requête de recherche par rapport à la demande de retour de ressources FHIR complètes. Pour en savoir plus, consultez Limiter les champs affichés dans les résultats de recherche.

Cas d'utilisation nécessitant le préchargement et la mise en cache

Vous pouvez avoir besoin de fonctionnalités au-delà de ce qui est possible avec le mécanisme simple consistant à appeler successivement la méthode fhir.search à l'aide d'URL de pagination. Une possibilité consiste à créer une couche de mise en cache entre votre application et le magasin FHIR qui maintient l'état de la session tout en préchargeant et en mettant en cache les résultats de recherche. L'application peut regrouper les résultats de recherche en petites "pages d'applications" de 10 ou 20 correspondances. L'application peut ensuite diffuser rapidement ces petites pages d'application à l'utilisateur de manière directe et non séquentielle, en fonction de ses sélections. Pour obtenir un exemple de ce type de workflow, consultez Accéder à une page à proximité.

Vous pouvez créer une solution à faible latence qui permet à un utilisateur d'examiner un grand nombre de résultats de recherche jusqu'à ce qu'il trouve la correspondance qu'il recherche. Il peut s'adapter à un nombre pratiquement illimité de correspondances tout en maintenant la latence faible et en entraînant une augmentation relativement faible de la consommation de ressources. Un utilisateur peut accéder directement à une page de résultats de recherche, jusqu'à un nombre prédéterminé de pages en avant ou en arrière de la page actuelle. Vous pouvez fournir un total estimé des recherches avec chaque page de résultats. Pour information, cette conception est semblable à celle de la recherche Google.

Workflow

La figure 1 présente un exemple de workflow pour cette solution. Avec ce workflow, chaque fois que l'utilisateur sélectionne une page de résultats à afficher, l'application fournit des liens vers les pages à proximité. Dans ce cas, l'application fournit des liens vers les pages jusqu'à cinq pages en arrière de la page sélectionnée et jusqu'à quatre pages en avant de la page sélectionnée. Pour que les quatre pages suivantes soient disponibles à l'affichage, l'application précharge 40 correspondances supplémentaires lorsque l'utilisateur sélectionne une page de résultats.

préchargement et mise en cache

Figure 1 : L'application regroupe les résultats de recherche dans des "pages d'application" mises en cache et mises à la disposition de l'utilisateur.

La figure 1 illustre ces étapes:

  1. L'utilisateur saisit une requête de recherche dans l'interface de l'application, ce qui déclenche les actions suivantes:

    1. L'application appelle la méthode fhir.search pour précharger la première page des résultats de recherche.

      Le paramètre _count est défini sur 100 pour que la taille de la page de la réponse reste relativement petite, ce qui entraîne des temps de réponse relativement rapides. La réponse inclut une URL de pagination (Bundle.link.url) si d'autres résultats doivent être renvoyés. La réponse inclut également le nombre total de recherches (Bundle.total). Il s'agit d'une estimation si d'autres résultats doivent être renvoyés. Pour en savoir plus, consultez la section Pagination et tri.

    2. L'application envoie la réponse à la couche de mise en cache.

  2. Dans la couche de mise en cache, l'application regroupe les 100 correspondances de la réponse en 10 pages d'application de 10 correspondances chacune. Une page d'application est un petit groupe de correspondances que l'application peut afficher à l'utilisateur.

  3. L'application affiche la page 1 à l'utilisateur. La page 1 de l'application inclut des liens vers les pages 2 à 10 de l'application et le nombre total de recherches estimé.

  4. L'utilisateur clique sur un lien vers une autre page de l'application (page 10 de l'application dans cet exemple), ce qui déclenche les actions suivantes:

    1. L'application appelle la méthode fhir.search, à l'aide de l'URL de pagination renvoyée avec le préchargement précédent, pour précharger la page suivante des résultats de recherche.

      Le paramètre _count est défini sur 40 pour précharger les 40 correspondances suivantes à partir de la requête de recherche de l'utilisateur. Les 40 correspondances correspondent aux quatre pages suivantes de l'application que l'application met à la disposition de l'utilisateur.

    2. L'application envoie la réponse à la couche de mise en cache.

  5. Dans la couche de mise en cache, l'application regroupe les 40 correspondances de la réponse en quatre pages d'application de 10 correspondances chacune.

  6. L'application affiche la page 10 à l'utilisateur. La page 10 de l'application inclut des liens vers les pages 5 à 9 (les cinq pages de l'application avant la page 10) et vers les pages 11 à 14 (les quatre pages de l'application après la page 10). La page 10 de l'application inclut également le nombre total de recherches estimé.

Cela peut se poursuivre aussi longtemps que l'utilisateur souhaite continuer à cliquer sur les liens vers les pages de l'application. Notez que si l'utilisateur revient en arrière depuis la page de l'application actuelle et que toutes les pages de l'application à proximité sont déjà mises en cache, vous pouvez choisir de ne pas effectuer de préchargement, en fonction de votre cas d'utilisation.

Cette solution est rapide et efficace pour les raisons suivantes:

  • Les préchargements de petite envergure, et même les pages d'application de petite taille, sont traités rapidement.
  • Les résultats de recherche mis en cache réduisent le besoin d'effectuer plusieurs appels pour les mêmes résultats.
  • Le mécanisme reste rapide, quel que soit le nombre de résultats de recherche.

Options de conception

Voici quelques options de conception à envisager en fonction de votre cas d'utilisation:

  • Taille de la page de l'application. Les pages de votre application peuvent contenir plus de 10 correspondances si cela convient à votre cas d'utilisation. N'oubliez pas que les pages plus petites se chargent plus rapidement, et qu'un trop grand nombre de liens sur une page peut être difficile à gérer pour un utilisateur.

  • Nombre de liens vers les pages de l'application. Dans le workflow suggéré ici, chaque page de l'application renvoie neuf liens vers d'autres pages de l'application: cinq liens vers les pages de l'application directement en arrière de la page de l'application actuelle et quatre liens vers les pages directement en avant de la page de l'application actuelle. Vous pouvez ajuster ces chiffres en fonction de votre cas d'utilisation.

Bonnes pratiques

  • N'utilisez la couche de mise en cache que si nécessaire. Si vous configurez une couche de mise en cache, n'utilisez-la que lorsque votre cas d'utilisation l'exige. Les recherches qui ne nécessitent pas la couche de mise en cache doivent la contourner.

  • Réduisez la taille de votre cache. Pour économiser des ressources, vous pouvez réduire la taille de votre cache en purgeant vos anciens résultats de recherche, tout en conservant les URL des pages que vous avez utilisées pour obtenir les résultats. Vous pouvez ensuite reconstruire le cache si nécessaire en appelant les URL de la page. N'oubliez pas que les résultats de plusieurs appels à la même URL de pagination peuvent changer au fil du temps, car les ressources du magasin FHIR sont créées, mises à jour et supprimées en arrière-plan. La décision de purger le cache, la manière de le faire et la fréquence de purge sont des décisions de conception qui dépendent de votre cas d'utilisation.

  • Purgez le cache pour une recherche donnée. Pour économiser des ressources, vous pouvez supprimer complètement du cache les résultats des recherches inactives. Pensez à supprimer d'abord les recherches les plus inactives. N'oubliez pas que si une recherche supprimée redevient active, cela peut entraîner un état d'erreur qui force la couche de mise en cache à redémarrer la recherche.

Si vous souhaitez qu'un utilisateur puisse accéder à n'importe quelle page des résultats de recherche, et pas seulement aux pages à proximité de la page actuelle, vous pouvez utiliser une couche de mise en cache semblable à celle décrite dans Accéder à une page à proximité. Toutefois, pour permettre à un utilisateur d'accéder à n'importe quelle page de résultats de recherche de l'application, vous devez précharger et mettre en cache tous les résultats de recherche. Avec un nombre relativement faible de résultats de recherche, cela est possible. Avec un très grand nombre de résultats de recherche, il peut être difficile ou impossible de les précharger tous. Même avec un nombre modeste de résultats de recherche, le temps nécessaire pour les précharger peut être plus long que le temps d'attente raisonnable pour un utilisateur.

Workflow

Configurez un workflow semblable à Accéder à une page à proximité, avec cette différence essentielle: l'application continue de précharger les résultats de recherche en arrière-plan jusqu'à ce que toutes les correspondances soient renvoyées ou qu'une autre limite prédéfinie soit atteinte.

Voici un exemple de workflow pour cette solution:

  1. L'application appelle la méthode fhir.search pour précharger la première page des résultats de recherche à partir de la requête de recherche de l'utilisateur. La réponse inclut une URL de pagination (Bundle.link.url) si d'autres résultats doivent être renvoyés. La réponse inclut également le nombre total de résultats de recherche (Bundle.total). Il s'agit d'une estimation s'il y a d'autres résultats à renvoyer.

  2. L'application regroupe les correspondances de la réponse en pages d'application de 20 correspondances chacune et les stocke dans le cache. Une page d'application est un petit regroupement de correspondances que l'application peut afficher à l'utilisateur.

  3. L'application affiche la première page de l'application pour l'utilisateur. La page de l'application inclut des liens vers les pages de l'application mises en cache et le nombre total de recherches estimé.

  4. Si d'autres résultats doivent être renvoyés, l'application procède comme suit:

    • Appelle l'URL de pagination renvoyée par le préchargement précédent pour obtenir la page suivante des résultats de recherche.
    • Regroupe les correspondances de la réponse dans des pages d'application de 20 correspondances chacune et les stocke dans le cache.
    • Actualise la page de l'application que l'utilisateur consulte actuellement avec de nouveaux liens vers les pages de l'application nouvellement préchargées et mises en cache.
  5. L'application répète l'étape précédente jusqu'à ce qu'il n'y ait plus de résultats à renvoyer ou qu'une autre limite prédéfinie soit atteinte. Un total de recherche précis est renvoyé avec la dernière page des résultats de recherche.

Pendant que l'application précharge et met en cache les correspondances en arrière-plan, l'utilisateur peut continuer à cliquer sur les liens vers les pages mises en cache.

Options de conception

Voici quelques options de conception à envisager en fonction de votre cas d'utilisation:

  • Taille de la page de l'application. Les pages de votre application peuvent contenir plus ou moins de 20 correspondances si cela convient à votre cas d'utilisation. N'oubliez pas que les pages plus petites se chargent plus rapidement, et qu'un nombre trop important de liens sur une page peut être difficile à gérer pour un utilisateur.

  • Actualisez le nombre total de recherches. Pendant que votre application précharge et met en cache les résultats de recherche en arrière-plan, vous pouvez afficher progressivement des totaux de recherche plus précis à l'utilisateur. Pour ce faire, configurez votre application comme suit:

    • À un intervalle défini, obtenez le total des recherches (propriété Bundle.total) à partir du dernier préchargement dans la couche de mise en cache. Il s'agit de la meilleure estimation actuelle du nombre total de recherches. Affichez le nombre total de recherches à l'utilisateur, en indiquant qu'il s'agit d'une estimation. Déterminez la fréquence de cette actualisation en fonction de votre cas d'utilisation.

    • Détecter quand le nombre total de recherches de la couche de mise en cache est exact. Autrement dit, le total des recherches provient de la dernière page des résultats de recherche. Lorsque la dernière page des résultats de recherche est atteinte, l'application affiche le nombre total de résultats et indique à l'utilisateur qu'il est exact. L'application cesse alors d'obtenir les totaux de recherche à partir de la couche de mise en cache.

    Notez qu'en cas de grand nombre de correspondances, le préchargement en arrière-plan et la mise en cache peuvent ne pas atteindre la dernière page des résultats de recherche (et le total exact de la recherche) avant que l'utilisateur ne termine sa session de recherche.

Bonnes pratiques

  • Dédupliquez les ressources incluses. Si vous utilisez les paramètres _include et _revinclude lors du préchargement et de la mise en cache des résultats de recherche, nous vous recommandons de dédupliquer les ressources incluses dans le cache après chaque préchargement. Cela permet d'économiser de la mémoire en réduisant la taille de votre cache. Lorsque vous regroupez des correspondances dans des pages d'application, ajoutez les ressources incluses appropriées à chaque page d'application. Pour en savoir plus, consultez Inclure des ressources supplémentaires dans les résultats de recherche.

  • Définissez une limite pour le préchargement et la mise en cache. Avec un très grand nombre de résultats de recherche, il peut être difficile ou impossible de les précharger tous. Nous vous recommandons de limiter le nombre de résultats de recherche à précharger. Cela permet de maintenir votre cache à une taille gérable et d'économiser de la mémoire. Par exemple, vous pouvez limiter la taille de votre cache à 10 000 ou 20 000 correspondances. Vous pouvez également limiter le nombre de pages à précharger ou définir une limite de temps au-delà de laquelle le préchargement s'arrête. Le type de limite que vous imposez et la manière dont vous l'imposez sont des décisions de conception qui dépendent de votre cas d'utilisation. Si la limite est atteinte avant que tous les résultats de recherche ne soient renvoyés, envisagez de l'indiquer à l'utilisateur, en précisant que le nombre total de résultats de recherche reste une estimation.

Mise en cache du frontend

Le frontend de l'application, tel qu'un navigateur Web ou une application mobile, peut fournir un certain stockage en cache des résultats de recherche au lieu d'introduire une couche de mise en cache dans l'architecture. Cette approche permet de naviguer vers la page précédente ou vers n'importe quelle page de l'historique de navigation en exploitant les appels AJAX et en stockant les résultats de recherche et/ou les URL de pagination. Voici quelques avantages de cette approche:

  • Il peut être moins gourmand en ressources qu'une couche de mise en cache.
  • Il est plus évolutif, car il répartit le travail de mise en cache sur de nombreux clients.
  • Il est plus facile de déterminer quand les ressources mises en cache ne sont plus nécessaires (par exemple, lorsque l'utilisateur ferme un onglet ou quitte l'interface de recherche).

Bonnes pratiques générales

Voici quelques bonnes pratiques qui s'appliquent à toutes les solutions de ce document.

  • Planifiez les pages plus petites que la valeur _count. Dans certains cas, une recherche peut renvoyer des pages contenant moins de correspondances que la valeur _count que vous spécifiez. Par exemple, cela peut se produire si vous spécifiez une taille de page particulièrement importante. Si votre recherche renvoie une page inférieure à la valeur _count et que votre application utilise une couche de mise en cache, vous devrez peut-être choisir d'(1) afficher moins de résultats que prévu sur une page de l'application ou (2) extraire quelques résultats supplémentaires pour en obtenir suffisamment pour une page d'application complète. Pour en savoir plus, consultez la section Pagination et tri.

  • Renouvelez les erreurs de requête HTTP récupérables. Votre application doit s'attendre à des erreurs de requête HTTP réessayables, telles que 429 ou 500, et réessayer après les avoir reçues.

Évaluer vos cas d'utilisation

L'implémentation de fonctionnalités telles que la navigation vers n'importe quelle page, l'obtention de totaux de recherche précis et la mise à jour des totaux estimés augmente la complexité et les coûts de développement de votre application. Ces fonctionnalités peuvent également augmenter la latence et les coûts financiers liés à l'utilisation des ressources Google Cloud. Nous vous recommandons d'évaluer attentivement vos cas d'utilisation pour vous assurer que la valeur de ces fonctionnalités justifie les coûts. Voici quelques points à prendre en compte:

  • Accéder à n'importe quelle page Un utilisateur n'a généralement pas besoin d'accéder à une page spécifique, mais à plusieurs pages à partir de la page actuelle. Dans la plupart des cas, l'option Accéder à une page à proximité est suffisante.

  • des totaux de recherche précis ; Les totaux de recherche peuvent changer à mesure que les ressources du datastore FHIR sont créées, mises à jour et supprimées. Pour cette raison, un total de recherche précis est exact au moment où il est renvoyé (avec la dernière page des résultats de recherche), mais il peut ne pas le rester au fil du temps. Par conséquent, les totaux de recherche précis peuvent avoir une valeur limitée pour votre application, en fonction de votre cas d'utilisation.