SpazioCodice

Un médiateur GraphQL pour implémenter une couche d’API de recherche hybride

Un médiateur GraphQL pour implémenter une couche d’API de recherche hybride

Cet article décrit la conception d’une couche de médiation qui implémente une API de recherche hybride via GraphQL. Bien qu’il s’agisse d’une description de haut niveau, elle est liée à une implémentation concrète que nous avons réalisée pour un projet (non mentionné car il est encore en cours).

Tout d’abord, commençons par examiner la signification des trois concepts dans la phrase ci-dessus.

Mediator

“Le modèle de conception Mediator définit un objet qui encapsule la manière dont un ensemble d’objets interagit. Le médiateur favorise un couplage lâche en empêchant les objets de se référer explicitement les uns aux autres.”

(“Design Patterns: Elements of Reusable Object-Oriented Software”, Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, 1994)

J’aime imaginer le Mediator en utilisant cette image

La zone grise représente la couche de médiation, tandis que les quatre composants sont les sous-systèmes médiés qui interagissent (indirectement) les uns avec les autres pour construire une instance de flux de travail. Notez que la médiation impose à la conception d’avoir les caractéristiques suivantes:

  • Elle relie les quatre sous-systèmes.
  • Elle établit des frontières claires entre chaque zone. En d’autres termes, un sous-système donné n’est pas conscient du contexte de déploiement sur lequel il s’exécute. 

La deuxième image représente la même idée, remplaçant les quatre composants anonymes par des exemples du monde réel.

Les sous-systèmes fournissent différents services qui, une fois orchestrés par la couche de médiation, renvoient une réponse unifiée aux clients. Par exemple (en se référant à l’exemple sur la gauche) :

  • La passerelle API peut contribuer avec des fonctionnalités non fonctionnelles telles que l’authentification/l’autorisation, le routage, l’équilibrage.
  • Apache Solr contribue avec des fonctionnalités de recherche rapides et puissantes (par exemple, recherche en texte intégral, facettage, suggestions de saisie semi-automatique, correction orthographique, mise en évidence).
  • PostgreSQL fournit des données en temps réel.
  • Fuseki offre une perspective RDF apportant des informations supplémentaires, par exemple, des liens vers des sources externes (par exemple, DBpedia).

Notez que les composants mentionnés ne sont que des exemples, ils pourraient être remplacés par d’autres alternatives capables d’offrir le même type de services.

Recherche hybride

Outre la passerelle API, les trois autres composants dans les exemples ci-dessus fournissent des services de stockage et de récupération de données. Pourquoi avons-nous besoin de trois sous-systèmes situés sur la même couche ? Y a-t-il une différence entre eux ?

La réponse évidente est oui. En simplifiant,

  • Solr ou Elasticsearch est excellent pour la recherche, mais les données ne sont disponibles qu’en quasi temps réel.
  • La base de données relationnelle peut fournir des données en temps réel, mais elle ne peut pas effectuer (à moins d’utiliser des extensions spécifiques au fournisseur) de recherche en texte intégral et d’autres fonctionnalités complémentaires comme le facettage.
  • Le RDFStore organise les données autour d’une approche centrée sur les liens, ce qui, en général, n’est pas aussi bon pour servir de source de données principale. De plus, les mêmes considérations concernant le facettage et la recherche en texte intégral s’appliquent.

Que diriez-vous d’utiliser une couche de médiation pour combiner les avantages de ces trois sources de données ?

 

Le rôle d’un médiateur serait :

  • Du point de vue du client, offrir une interface unifiée et simple. De ce point de vue, il agit comme une façade.
  • Du point de vue du serveur, orchestrer les trois sous-systèmes découplés et gérer le flux d’exécution des requêtes.

Les services de récupération dans un tel contexte consisteraient en :

  • Une interface d’entrée qui inclurait des paramètres pour déclencher un comportement spécifique (offert par l’un des sous-systèmes sous-jacents).
  • Une réponse composée avec des contributions provenant de différents systèmes de récupération.

 

Le rôle de la médiation serait, une fois de plus, de rendre tout cela simple, uniforme et transparent.

GraphQL

GraphQL est un langage de requête pour les API. Après avoir jeté un coup d’œil rapide aux spécifications GraphQL, vous pouvez avoir une idée de la vaste gamme de fonctionnalités capturées dans la syntaxe du langage.

Un moteur GraphQL (c’est-à-dire un moteur qui met en œuvre les spécifications ci-dessus et offre ces capacités) est parfaitement adapté au cas d’utilisation décrit dans cet article : il fournit un contrôleur frontal au-dessus de sources de données hétérogènes, que le fournisseur de données soit une API, une base de données ou une application arbitraire qui fournit ses services via un protocole interopérable.

Consultez cet article sur nos réflexions sur GraphQL et comment nous pensons qu’il peut être utilisé avec REST.

Modèles d'accès aux données

Concrètement, quels sont les scénarios qui nous intéressent ? Cette section répond à cette question en fournissant une liste de modèles d’accès aux données qui bénéficient d’une telle architecture hybride.

Recherche d'élément connu

La « recherche d’élément connu » est une spécialisation de l’exploration d’informations qui représente les activités réalisées par des chercheurs ayant un élément particulier en tête (source : Wikipedia).

La définition ci-dessus est un peu plus large que le scénario que nous voulons capturer : dans ce contexte, « élément connu » signifie quelque chose comme:

Je connais l’identifiant d’une entité ; je veux récupérer les informations sur cette entité.

Par exemple : donnez-moi les informations sur la personne identifiée par https://example.org/people/amadsen.

Quelle pourrait être la contribution attendue des sous-systèmes dans le diagramme d’exemple ci-dessus? La réponse pourrait changer en fonction des exigences; voici ce que nous avons implémenté:

  • L’identifiant de l’entité à récupérer est connu, il peut être utilisé pour obtenir des données fraîches (c’est-à-dire mises à jour en temps réel) de la base de données relationnelle.
  • Apache Solr n’est pas impliqué : il n’y a pas de recherche exploratoire dans ce scénario; une implication possible pourrait être liée à « Plus comme cela » (voir ci-dessous). Cependant, dans le système que nous avons construit, cela ne faisait pas partie des exigences du client.
  • Le même identifiant connu pourrait être utilisé pour récupérer depuis le RDF Store une représentation alternative de la ressource, dans le cas où un codage RDF spécifique est demandé (par exemple, N-Triples, RDF/XML).
Entités liées

Nous sommes dans une spécialisation du scénario ci-dessus, où le demandeur n’est pas directement intéressé par l’élément connu. Au lieu de cela, l’accent est mis sur le retour des entités liées à l’élément connu (par exemple, les voitures possédées par la personne identifiée par https://example.org/people/amadsen).

Dans ce scénario, en supposant une gestion appropriée de ces données de relations dans l’index inversé, Apache Solr peut commencer à contribuer avec ses fonctionnalités en quasi temps réel.

Voici la liste mise à jour des contributions :

  • La base de données relationnelle joue le même rôle que ci-dessus : l’identifiant de l’élément connu est utilisé pour récupérer des données en temps réel. L’entrée est toujours la même (l’identifiant) ; la différence réside dans les données récupérées, car cette fois, nous nous intéressons aux entités liées.
  • Apache Solr utilise l’identifiant pour des fonctionnalités complémentaires telles que le facettage et “plus comme ceci“.
  • L’implication du RDF Store suit le même chemin “parallèle” que ci-dessus, au cas où un format de sérialisation RDF serait demandé du côté du client.
FullText

Dans ce scénario, le point de départ est une recherche exploratoire : l’utilisateur entre un ou plusieurs termes de recherche pour obtenir une liste de correspondances “pertinentes” selon ses besoins en information.

Le jeu de contributions dans ce scénario introduit un schéma d’interaction intéressant où :

  • Le moteur d’index inversé (Apache Solr dans notre exemple) agit comme une source primaire déterminant les correspondances pertinentes. La réponse contient les documents correspondants ainsi que des fonctionnalités supplémentaires comme le facettage, la mise en évidence, la vérification orthographique.
  • Nous ne voulons pas récupérer les données stockées de Solr (qui, encore une fois, dispose d’un instantané en temps réel des données). Au lieu de cela, nous utilisons les identifiants renvoyés par Solr pour récupérer les données fraîches correspondantes à partir de la base de données relationnelle ou du RDF Store, en fonction du type de contenu demandé et négocié.

Voici le diagramme de flux de travail mis à jour :

 

Réponse Contribution

Nous avons examiné trois scénarios ; pour chacun d’entre eux, nous avons décrit le rôle joué par chaque sous-système dans l’exécution de la requête.

Nous avons également mentionné que la contribution a une autre perspective, spécifiquement dans la réponse.

Récupération des champs

Indépendamment du scénario, les attributs des entités sont toujours récupérés à partir de la base de données relationnelle (représentation JSON) ou du RDF Store (représentation RDF).

Nous pouvons envisager un protocole de récupération en deux phases :

  • dans la première phase, nous collectons les identifiants (ou l’identifiant)
  • dans la deuxième phase, chaque identifiant est utilisé pour récupérer les données de l’entité. Dans cette phase, la réponse pourrait également être enrichie par des contributions supplémentaires (par exemple, des facettes).

Dans les scénarios d’éléments connus et d’entités connexes, il n’y a qu’un seul identifiant ; il est connu à l’avance, donc la première phase est “virtuelle”, elle ne fait intervenir aucun sous-système. Dans le scénario de recherche en texte intégral, nous collectons d’abord les identifiants correspondants (classés par pertinence), puis nous créons les représentations des entités.

Facettes, Mise en évidence, Vérification orthographique, Plus comme ceci

Cette section vise à regrouper toutes les contributions de réponse du moteur d’index inversé (Apache Solr, dans notre exemple).

Le facettage fait référence à une fonctionnalité de recherche complémentaire où les résultats sont classés.

				
					{
  "Type":{
    "Person":4,
    "Book":5
  },
  "Genre":{
    "Traditional Literature":3,
    "Drama":2
  },
  "ContributionType":{
   "Author":2,
   "Illustrator":1,
   "Translator":1
  }
}
				
			

La mise en évidence fournit des extraits de documents correspondant à la requête de l’utilisateur, entourés de balises HTML.

				
					{
   "name":"Carroll, Lewis",
   "birthDate":1832,
   ...
},
{
   "title":"Alice in Wonderland",
   ...
},
				
			

La vérification orthographique (également appelée “Avez-vous voulu dire ?”) fournit des suggestions de requêtes et de termes en ligne basées sur d’autres termes similaires.

				
					"termsSuggestions":
 {
   "term": "winderlnd",
   "corrections": [
     "wonderland"
   ]
 },
...
"querySuggestions": [
 {
   "query": "wonderland carroll potter"
 },
 {
   "query": "wonderland carroll poṭer"
 },
 {
   "query": "wonderland carroll power"
 }
]
				
			

Plus Comme Cela fournit une liste de documents similaires selon un ensemble donné de critères.

L’idée est de conserver leur nature complémentaire et d’ajouter une section dans la réponse pour chacun d’eux. Cela, indépendamment de la provenance des données de la section principale (par exemple, RDBMS, Solr lui-même).

La matrice suivante combine les fonctionnalités et les scénarios décrits ci-dessus.

Avant de passer à l’exemple de réponse, voici un bref récapitulatif de ce qui se passe :

  • Le client recherche un ou plusieurs termes. La requête contient
  • Le Médiateur demande à Apache Solr d’exécuter la recherche. Solr renvoie les K meilleurs identifiants correspondants ainsi que les facettes, la vérification orthographique et des extraits mis en évidence.
  • Chaque identifiant est utilisé pour collecter les données (attributs) de la base de données relationnelle.
  • La réponse résultante est enrichie avec des facettes, une vérification orthographique.
  • Les extraits mis en évidence remplacent les attributs dans la liste des résultats.
				
					{
   "resources":[
      {
         "name":"Carroll, Lewis",
         "birthDate":1832,
         ...
      },
      {
         "title":"Alice in Wonderland",
         ...
      },
      ...
   ],
   "facets":{
      "type":{
         "Person":4,
         "Book":5
      },
      "genre":{
         "Traditional Literature":3,
         "Drama":2
      },
      "role":{
         "Author":2,
         "Illustrator":1,
         "Translator":1
      }
   },
   "didYouMean": {
     "termsSuggestions": {
        "term": "winderlnd",
        "corrections": [
            "wonderland"
        ]
    },
    "querySuggestions": [
      {
        "query": "wonderland carroll potter"
      },
      {
        "query": "wonderland carroll poṭer"
      },
      {
        "query": "wonderland carroll power"
      }
    ]
   },
   "page":{
      "totalMatches":9,
      "startOffset":0,
      "pageSize":5
   }
}
				
			

Conclusions

Dans cette étude de cas, nous avons fourni un aperçu de haut niveau de la manière dont nous avons construit une couche de médiation qui coordonne plusieurs sous-systèmes et produit une réponse à valeur ajoutée pour les consommateurs de services de haut niveau.

Je tiens à souligner que la manière dont nous avons mis en œuvre le flux de travail est étroitement liée aux exigences du client. Tout cela pour dire que ce n’est pas la seule façon de mélanger et orchestrer les contributions provenant des sous-systèmes médiés.

Comme toujours, tout retour d’information est le bienvenu !

Share this post

Laisser un commentaire

En savoir plus sur SpazioCodice

Abonnez-vous pour poursuivre la lecture et avoir accès à l’ensemble des archives.

Poursuivre la lecture