J’ai eu récemment l’opportunité de travailler avec les services Azure Search et Cosmos DB afin de répondre à la problématique d’un client. Voici la problématique : pouvoir rechercher des entités au sein d’une base de données tout en ayant la possibilité de filtrer les types de relations établies entre ces entités.

Avec quelques contraintes techniques tout de même (ça serait trop facile sinon 😉) :

Dans un contexte technique full cloud Azure il fallait utiliser les ressources mises à disposition par Microsoft :

  • Que la recherche soit performante
  • Avec une gestion dynamique des types de relations
  • Pouvoir gérer les relations entre entités avec plusieurs niveaux -nous verrons en détail ce principe un peu plus loin dans l’article.

 

Présentation de Azure Cosmos DB

Azure Cosmos DB

Cosmos DB est le service incontournable sur Azure concernant les bases de données de type NoSQL. Azure cosmos DB est globalement distribué, totalement managé, scalable et surtout multi-model. C’est sur ce dernier point que nous allons faire un focus.

Voici les modèles pris en charge par Cosmos DB :

  • Clé/valeur
  • Colonnes
  • Documents JSON
  • Graphes

 

API Gremlin

 

 

L’API Azure Cosmos DB Gremlin permet de stocker, d’utiliser, de modéliser et de parcourir des données de graphes.

La structure d’un graphe est composée des éléments suivants :

  • Un vertex : qui correspond à une entité (personne, objet, évènement, endroit, etc.).
  • Un Edge : qui symbolise une relation entre vertex.
  • Des propriétés customisables relatives aux vertex et aux edges.

Cette fonctionnalité de Cosmos DB est tout particulièrement recommandée pour les scénarios de réseaux sociaux, moteurs de recommandations (ça tombe bien), IoT ainsi que pour la recherche géolocalisée.

La force de Cosmos DB API Gremlin réside dans son langage de requêtage de graphe transversal « Gremlin ».

Voici un exemple de requête permettant d’insérer une entité (vertex) avec des propriétés :

Exemple de requête d’ajout de relation entre les vertex « Bob » et « Bill » :

Ce qui devient intéressant, c’est la manière dont on va pouvoir requêter la relation entre les vertex.

L’expression « Je souhaite récupérer les personnes avec lesquelles travail Bill » devient :

Ce genre de modèle de requête ouvre les champs des possibles en allant un peu plus loin en matière de besoin. Par exemple, en récupérant tous les collègues des collègues de « Bill » :

Il est possible de requêter/visualiser les données à travers :

  • Le « Data Explorer » de la base Cosmos DB depuis le portail Azure.
  • Via l’outil Azure Storage Explorer.
  • Via Visual Studio Code (en ajoutant l’extension pour Azure Cosmos DB).

Cosmos DB permet également d’utiliser différents formats de données au sein de la même base de données. Par exemple, vous pouvez utiliser une collection de documents JSON côte à côte avec une collection de documents de relations graph et utiliser des requêtes SQL pour le JSON et des requêtes Gremlin pour récupérer l’ensemble des données.

Il reste néanmoins des étapes supplémentaires afin de consolider les données pour apporter de la valeur ajoutée à notre combinaison.

 

Azure Search

Afin d’effectuer des recherches sur un grand nombre de données nous avons opté pour le service Azure Search. Azure Search est un moteur d’indexation et de recherche « as a service » supportant plusieurs types de sources de données. La présentation détaillée du service est disponible ici

La fonctionnalité de requête des index est exposée à travers une API REST ainsi qu’un SDK .Net.

C’est en utilisant le SDK .NET que nous allons combiner la puissance de Cosmos API Gremlin et d’Azure Search.

Le tutoriel complet d’utilisation d’Azure Search via le .NET SDK est disponible dans cet article : Azure Search, installation et configuration.

 

Nous passons directement à l’étape de requête des index du service Azure Search.

Voici un exemple de requête Azure Search au format OData :

Analyse de la requête :

  • search=* : recherche de l’ensemble des documents présents dans l’index.
  • facet=tags&facet=baseRate,values:80|150|220 : indique au moteur de recherche de retourner le résultat de la requête groupé par les éléments spécifiés (tags,baseRate).
  • filter=Relation eq ‘Customer’ : correspond à la clause « where » de la requête. C’est sur cet attribut que va se baser notre recherche par relation.

Il existe néanmoins quelques limitations techniques en termes de longueur. La longueur maximale d’une URL de requête search est de 8Ko. De plus dans le cas d’une requête avec tri, la clause $orderby ne peut contenir qu’un maximum de 32 champs.

Un moyen de contournement possible est de créer une API proxy utilisant le .NET SDK (ci-après) en passant l’ensemble des paramètres dans une requête POST.

Il est également possible d’exécuter cette requête en utilisant le .NET SDK via le package nuget Microsoft.Azure.Search:

Etape 1 : Instanciation d’un objet SearchServiceClient

Etape 2 : exécution de la recherche

Combinaison des services

La combinaison des services Azure Search et Cosmos DB Graph nous permet d’agréger différents types de données : des objets métier (des utilisateurs) et les relations entre ces objets.
Cette agrégation de service nous donne un outil de visualisation de données intégrant une notion de réseau social (professionnel dans notre cas) à la fonctionnalité de recherche proposée par Azure Search. La réponse technique au besoin est inspirée de l’outil Delve de Microsoft pour analyser et donc projeter les relations entre objets/individus.

Si nous retournons à la problématique initiale qui était de pouvoir effectuer une recherche en filtrant sur des relations de type graph, dorénavant, c’est ici que nous allons combiner les fonctionnalités des deux services cités précédemment.

Dans notre architecture technique, Azure Search utilise une source de données Cosmos DB pour indexer les utilisateurs avec différentes propriétés caractérisant le domaine métier de ceux-ci.

La base Cosmos DB Graph va permettre de stocker les relations entre ces utilisateurs.

Un prérequis à la combinaison des services est la mise en place d’une liaison entre les entités (vertex) stockées dans Cosmos DB Graph et les documents présents dans l’index.

Pour ce faire, nous allons utiliser un id technique unique généré par Cosmos comme élément permettant d’identifier de manière unique un utilisateur.

En effet la recherche filtrée par type de relation est composée des étapes suivantes :

  1. En partant d’un utilisateur source, recherche de ces relations graph dans la base de données.
  2. Récupération des identifiants techniques des utilisateurs cible des relations stockées dans la base Cosmos DB Graph.
  3. Modification de la requête initiale pour y modifier le filtre en y ajoutant les ID technique des utilisateurs cible des relations.
    1. Remplacement du paramètre « filter=Relation eq ‘Customer’» par « search.in(id,’1’,’2’,’3’) »
  4. Exécution de la requête et récupération du résultat de la recherche.

 

Conclusion

Vous l’aurez compris il est techniquement impossible de créer des relations entre entités dans Azure Search. Pour ce faire nous avons tiré profit des fonctionnalités de Cosmos DB API Gremlin pour gérer la notion de relation combinée avec celle d’Azure Search pour l’indexation et la recherche.

Nous avons également abordé les basiques de l’API Gremlin et pu entrevoir la puissance du modèle de requêtage des graphes de manière transversale à travers les données.

 

livre blanc From Zero to Hero 2 réseau azure