Partager via


Tutoriel : Indexer à partir de plusieurs sources de données à l’aide du SDK .NET

Recherche Azure AI peut importer, analyser et indexer des données provenant de plusieurs sources de données dans un même index de recherche consolidé.

Ce tutoriel C# utilise la bibliothèque de client Azure.Search.Documents d’Azure SDK pour .NET afin d’indexer des exemples de données d’hôtels provenant d’une instance Azure Cosmos DB, et les fusionner avec les détails des chambres d’hôtel tirés de documents du Stockage Blob Azure. Le résultat est un index de recherche d’hôtel combiné contenant des documents d’hôtel, avec les chambres comme types de données complexes.

Dans ce tutoriel, vous allez effectuer les tâches suivantes :

  • Charger des exemples de données et créer des sources de données
  • Identifier la clé de document
  • Définir et créer l’index
  • Indexer les données d’hôtels issues d’Azure Cosmos DB
  • Fusionner les données des chambres d’hôtel provenant du stockage d’objets blob

Si vous n’avez pas d’abonnement Azure, créez un compte gratuit avant de commencer.

Vue d’ensemble

Ce tutoriel utilise Azure.Search.Documents pour créer et exécuter plusieurs indexeurs. Dans ce tutoriel, vous allez configurer deux sources de données Azure afin de pouvoir configurer un indexeur qui extrait des informations de ces deux sources pour remplir un index de recherche unique. Les deux jeux de données doivent avoir une valeur commune pour prendre en charge la fusion. Dans cet exemple, ce champ est un ID. Tant qu’il existe un champ en commun pour prendre en charge le mappage, un indexeur peut fusionner des données provenant de ressources disparates : des données structurées à partir d’Azure SQL, des données non structurées à partir du stockage Blob ou toute combinaison de sources de données prises en charge sur Azure.

Une version terminée du code de ce tutoriel se trouve dans le projet suivant :

Prérequis

Remarque

Vous pouvez utiliser un service de recherche gratuit pour ce tutoriel. Le niveau gratuit vous limite à trois index, trois indexeurs et trois sources de données. Ce didacticiel crée une occurrence de chaque élément. Avant de commencer, veillez à disposer de l’espace suffisant sur votre service pour accepter les nouvelles ressources.

1 - Créer les services

Ce tutoriel utilise Recherche Azure AI pour l’indexation et les requêtes, Azure Cosmos DB pour un jeu de données et Stockage Blob Azure pour le second jeu de données.

Si possible, créez tous les services dans la même région et le même groupe de ressources pour des raisons de proximité et de facilité de gestion. Dans la pratique, vos services peuvent se trouver dans n’importe quelle région.

Cet exemple utilise deux petits ensembles de données qui décrivent sept hôtels fictifs. Un ensemble décrit les hôtels eux-mêmes et est chargé dans une base de données Azure Cosmos DB. L’autre ensemble contient les détails des chambres d’hôtel et est fourni sous la forme de sept fichiers JSON distincts à charger dans Stockage Blob Azure.

Démarrer avec Azure Cosmos DB

  1. Connectez-vous au portail Azure, puis accédez à la page Vue d’ensemble de votre compte Azure Cosmos DB.

  2. Sélectionnez Explorateur de données, puis sélectionnez Nouvelle base de données.

    Créer une base de données

  3. Entrez le nom hotel-rooms-db. Acceptez les valeurs par défaut pour les autres paramètres.

    Configurer la base de données

  4. Créez un conteneur. Utilisez la base de données existante que vous venez de créer. Entrez hotels comme nom de conteneur et utilisez /HotelId comme clé de partition.

    Ajouter un conteneur

  5. Sélectionnez Éléments sous Hôtels, puis Charger un élément dans la barre de commandes. Accédez au fichier cosmosdb/HotelsDataSubset_CosmosDb.json dans le dossier du projet, puis sélectionnez-le.

    Charger dans la collection Azure Cosmos DB

  6. Utilisez le bouton Actualiser pour actualiser l’affichage des éléments dans la collection hotels. Sept nouveaux documents doivent être listés.

  7. Copier une chaîne de connexion de la page Clés dans le Bloc-notes. Vous aurez besoin de cette valeur pour appsettings.json dans une étape ultérieure. Si vous n’avez pas utilisé le nom de base de données suggéré « hotel-rooms-db », copiez également le nom de la base de données.

Stockage Blob Azure

  1. Connectez-vous au portail Azure, accédez à votre compte de stockage Azure, sélectionnez Blobs, puis + Conteneur.

  2. Créez un conteneur d’objets blob nommé hotel-rooms pour stocker les exemples de fichiers JSON des chambres d’hôtel. Vous pouvez définir le niveau d’accès public sur l’une de ses valeurs valides.

    Créer un conteneur d’objets blob

  3. Une fois le conteneur créé, ouvrez-le et sélectionnez Charger dans la barre de commandes. Accédez au dossier contenant les exemples de fichiers. Sélectionnez-les tous, puis choisissez Charger.

    Charger des fichiers

  4. Copiez le nom du compte de stockage et une chaîne de connexion de la page Clés d’accès dans le Bloc-notes. Vous aurez besoin de ces deux valeurs pour appsettings.json dans une étape ultérieure.

Le troisième composant est Recherche Azure AI, que vous pouvez créer dans le portail ou bien trouver en tant que service de recherche existant dans vos ressources Azure.

Pour vous authentifier auprès de votre service de recherche, vous aurez besoin de l’URL du service et d’une clé d’accès.

  1. Connectez-vous au portail Azure, puis dans la page Vue d’ensemble du service de recherche, récupérez l’URL. Voici un exemple de point de terminaison : https://mydemo.search.windows.net.

  2. Dans Paramètres>Clés, obtenez une clé d’administration pour avoir des droits d’accès complets sur le service. Il existe deux clés d’administration interchangeables, fournies pour assurer la continuité de l’activité au cas où vous deviez en remplacer une. Vous pouvez utiliser la clé primaire ou secondaire sur les demandes d’ajout, de modification et de suppression d’objets.

    Obtenir le nom du service, les clés d’administration et les clés de requête

L’utilisation d’une clé valide permet d’établir, en fonction de chaque demande, une relation de confiance entre l’application qui envoie la demande et le service qui en assure le traitement.

2 - Configurer votre environnement

  1. Démarrez Visual Studio. Ensuite, dans le menu Outils, sélectionnez Gestionnaire de package NuGet, puis Gérer les packages NuGet pour la solution... .

  2. Sous l’onglet Parcourir, recherchez et installez Azure.Search.Documents (version 11.0 ou ultérieure).

  3. Recherchez les packages NuGet Microsoft.Extensions.Configuration et Microsoft.Extensions.Configuration.Json, puis installez-les également.

  4. Ouvrez le fichier solution /v11/AzureSearchMultipleDataSources.sln.

  5. Dans l’Explorateur de solutions, modifiez le fichier appsettings.json en y ajoutant les informations de connexion.

    {
      "SearchServiceUri": "<YourSearchServiceURL>",
      "SearchServiceAdminApiKey": "<YourSearchServiceAdminApiKey>",
      "BlobStorageAccountName": "<YourBlobStorageAccountName>",
      "BlobStorageConnectionString": "<YourBlobStorageConnectionString>",
      "CosmosDBConnectionString": "<YourCosmosDBConnectionString>",
      "CosmosDBDatabaseName": "hotel-rooms-db"
    }
    

Les deux premières entrées sont l’URL et les clés d’administration d’un service de recherche. Utilisez le point de terminaison complet ; par exemple : https://mydemo.search.windows.net.

Les entrées suivantes spécifient les noms de compte et les informations de chaîne de connexion pour les sources de données Stockage Blob Azure et Azure Cosmos DB.

3 - Mapper les champs clés

La fusion de contenu nécessite que les deux flux de données ciblent les mêmes documents dans l’index de recherche.

Dans Recherche Azure AI, le champ de clé identifie chaque document de façon univoque. Chaque index de recherche doit comporter exactement un champ de clé de type Edm.String. Ce champ de clé doit être présent pour chaque document d’une source de données qui est ajouté à l’index. (il constitue en fait le seul champ obligatoire).

Quand vous indexez des données provenant de plusieurs sources de données, vérifiez que chaque ligne ou document entrant contient une clé de document commune pour les fusionner à partir de deux documents sources physiquement distincts dans un nouveau document de recherche dans l’index combiné.

Il est souvent nécessaire de passer par une planification préalable pour identifier une clé de document significative pour votre index et vous assurer qu’elle existe dans les deux sources de données. Dans cette démonstration, la clé HotelId de chaque hôtel dans Azure Cosmos DB est également présente dans les objets blob JSON des chambres dans Stockage Blob.

Les indexeurs Recherche Azure AI peuvent utiliser des mappages de champs pour renommer ou même remettre en forme des champs de données pendant le processus d’indexation, afin que les données sources puissent être redirigées vers le champ d’index correct. Par exemple, dans Azure Cosmos DB, l’identificateur d’hôtel est appelé HotelId. Mais dans les fichiers d’objets blob JSON pour les chambres d’hôtel, l’identificateur d’hôtel est nommé Id. Le programme gère cette discordance en mappant le champ Id des blobs au champ de clé HotelId dans l’indexeur.

Notes

Dans la plupart des cas, les clés de document générées automatiquement, comme celles créées par défaut par certains indexeurs, ne constituent pas des clés de document appropriées pour les index combinés. En général, il est préférable d’utiliser une valeur de clé unique explicite qui existe déjà dans vos sources de données ou qui peut y être facilement ajoutée.

4 - Explorer le code

Une fois que les données et les paramètres de configuration sont en place, l’exemple de programme figurant dans /v11/AzureSearchMultipleDataSources.sln doit être opérationnel.

Cette application console C#/.NET simple effectue les tâches suivantes :

  • Elle crée un index basé sur la structure de données de la classe Hotel C# (qui référence également les classes Address et Room).
  • Elle crée une source de données et un indexeur qui mappe les données Azure Cosmos DB aux champs d’index. Ce sont tous deux des objets dans Recherche Azure AI.
  • Elle exécute l’indexeur pour charger les données des hôtels à partir d’Azure Cosmos DB.
  • Elle crée une seconde source de données et un indexeur qui mappe les données blob JSON aux champs d’index.
  • Elle exécute le second indexeur pour charger des données des chambres à partir du stockage d’objets blob.

Avant d’exécuter le programme, prenez une minute pour étudier le code et les définitions d’index et d’indexeur de cet exemple. Le code qui convient se trouve dans deux fichiers :

  • Hotel.cs contient le schéma qui définit l’index
  • Program.cs contient des fonctions qui créent l’index, les sources de données et les indexeurs de Recherche Azure AI, et qui chargent les résultats combinés dans l’index.

Création d'un index

Cet exemple de programme utilise CreateIndexAsync pour définir et créer un index Recherche Azure AI. Il tire parti de la classe FieldBuilder pour générer une structure d’index à partir d’une classe de modèle de données C#.

Le modèle de données est défini par la classe Hotel, qui contient également des références aux classes Address et Room. La classe FieldBuilder explore plusieurs définitions de classe pour générer une structure de données complexes pour l’index. Des étiquettes de métadonnées sont utilisées pour définir les attributs de chaque champ, par exemple s’il peut faire l’objet d’une recherche ou d’un tri.

Le programme supprime tout index existant portant le même nom avant de créer le nouveau, au cas où vous souhaiteriez exécuter cet exemple plusieurs fois.

Les extraits de code suivants tirés du fichier Hotel.cs montrent des champs uniques, suivis d’une référence à une autre classe de modèle de données, Room[], qui est à son tour définie dans le fichier Room.cs (non affiché).

. . .
[SimpleField(IsFilterable = true, IsKey = true)]
public string HotelId { get; set; }

[SearchableField(IsFilterable = true, IsSortable = true)]
public string HotelName { get; set; }
. . .
public Room[] Rooms { get; set; }
. . .

Dans le fichier Program.cs, un objet SearchIndex est défini avec un nom et une collection de champs générés par la méthode FieldBuilder.Build, puis créé comme suit :

private static async Task CreateIndexAsync(string indexName, SearchIndexClient indexClient)
{
    // Create a new search index structure that matches the properties of the Hotel class.
    // The Address and Room classes are referenced from the Hotel class. The FieldBuilder
    // will enumerate these to create a complex data structure for the index.
    FieldBuilder builder = new FieldBuilder();
    var definition = new SearchIndex(indexName, builder.Build(typeof(Hotel)));

    await indexClient.CreateIndexAsync(definition);
}

Créer l’indexeur et la source de données Azure Cosmos DB

Ensuite, le programme principal inclut une logique destinée à créer la source de données Azure Cosmos DB pour les données d’hôtels.

Tout d’abord, il concatène le nom de la base de données Azure Cosmos DB à la chaîne de connexion. Il définit ensuite un objet SearchIndexerDataSourceConnection.

private static async Task CreateAndRunCosmosDbIndexerAsync(string indexName, SearchIndexerClient indexerClient)
{
    // Append the database name to the connection string
    string cosmosConnectString =
        configuration["CosmosDBConnectionString"]
        + ";Database="
        + configuration["CosmosDBDatabaseName"];

    SearchIndexerDataSourceConnection cosmosDbDataSource = new SearchIndexerDataSourceConnection(
        name: configuration["CosmosDBDatabaseName"],
        type: SearchIndexerDataSourceType.CosmosDb,
        connectionString: cosmosConnectString,
        container: new SearchIndexerDataContainer("hotels"));

    // The Azure Cosmos DB data source does not need to be deleted if it already exists,
    // but the connection string might need to be updated if it has changed.
    await indexerClient.CreateOrUpdateDataSourceConnectionAsync(cosmosDbDataSource);

Une fois la source de données créée, le programme configure un indexeur Azure Cosmos DB nommé hotel-rooms-cosmos-indexer.

Le programme met à jour tous les indexeurs existants portant le même nom, en remplaçant l’indexeur existant par le contenu du code ci-dessus. Il comprend également des actions de réinitialisation et d’exécution, au cas où vous souhaiteriez exécuter cet exemple plusieurs fois.

L’exemple suivant définit une planification pour l’indexeur, afin qu’il s’exécute une fois par jour. Si vous ne souhaitez pas que l’indexeur soit automatiquement réexécuté à l’avenir, vous pouvez supprimer la propriété de planification de cet appel.

SearchIndexer cosmosDbIndexer = new SearchIndexer(
    name: "hotel-rooms-cosmos-indexer",
    dataSourceName: cosmosDbDataSource.Name,
    targetIndexName: indexName)
{
    Schedule = new IndexingSchedule(TimeSpan.FromDays(1))
};

// Indexers keep metadata about how much they have already indexed.
// If we already ran the indexer, it "remembers" and does not run again.
// To avoid this, reset the indexer if it exists.
try
{
    await indexerClient.GetIndexerAsync(cosmosDbIndexer.Name);
    // Reset the indexer if it exists.
    await indexerClient.ResetIndexerAsync(cosmosDbIndexer.Name);
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
    // If the indexer does not exist, 404 will be thrown.
}

await indexerClient.CreateOrUpdateIndexerAsync(cosmosDbIndexer);

Console.WriteLine("Running Azure Cosmos DB indexer...\n");

try
{
    // Run the indexer.
    await indexerClient.RunIndexerAsync(cosmosDbIndexer.Name);
}
catch (RequestFailedException ex) when (ex.Status == 429)
{
    Console.WriteLine("Failed to run indexer: {0}", ex.Message);
}

Cet exemple inclut un bloc try-catch simple pour signaler les erreurs susceptibles de se produire pendant l’exécution.

Une fois l’indexeur Azure Cosmos DB exécuté, l’index de recherche contient un ensemble complet d’exemples de documents d’hôtel. Toutefois, le champ Rooms (Chambres) pour chaque hôtel est un tableau vide, car la source de données Azure Cosmos DB ne contenait omet les détails sur les chambres. Ensuite, le programme extrait les données des chambres du stockage d’objets blob et les fusionne.

Créer l’indexeur et la source de données du stockage blob

Pour obtenir les détails sur les chambres, le programme configure tout d’abord une source de données de stockage d’objets blob pour référencer un ensemble de fichiers d’objets blob JSON individuels.

private static async Task CreateAndRunBlobIndexerAsync(string indexName, SearchIndexerClient indexerClient)
{
    SearchIndexerDataSourceConnection blobDataSource = new SearchIndexerDataSourceConnection(
        name: configuration["BlobStorageAccountName"],
        type: SearchIndexerDataSourceType.AzureBlob,
        connectionString: configuration["BlobStorageConnectionString"],
        container: new SearchIndexerDataContainer("hotel-rooms"));

    // The blob data source does not need to be deleted if it already exists,
    // but the connection string might need to be updated if it has changed.
    await indexerClient.CreateOrUpdateDataSourceConnectionAsync(blobDataSource);

Une fois la source de données créée, le programme configure un indexeur d’objets blob nommé hotel-rooms-blob-indexer, comme indiqué ci-dessous.

Les objets blob JSON contiennent un champ de clé nommé Id au lieu de HotelId . Le code utilise la classe FieldMapping pour indiquer à l’indexeur de rediriger la valeur du champ Id vers la clé de document HotelId dans l’index.

Les indexeurs de stockage Blob peuvent utiliser IndexingParameters pour spécifier un mode d’analyse. Vous devez définir différents odes d’analyse selon que les objets blob représentent un document unique ou plusieurs documents au sein du même objet blob. Dans cet exemple, comme chaque objet blob représente un document JSON unique, le code utilise le mode d’analyse json. Pour plus d’informations sur les paramètres d’analyse d’indexeur pour les objets blob JSON, consultez Indexer des objets blob JSON.

Cet exemple définit une planification pour l’indexeur, afin qu’il s’exécute une fois par jour. Si vous ne souhaitez pas que l’indexeur soit automatiquement réexécuté à l’avenir, vous pouvez supprimer la propriété de planification de cet appel.

IndexingParameters parameters = new IndexingParameters();
parameters.Configuration.Add("parsingMode", "json");

SearchIndexer blobIndexer = new SearchIndexer(
    name: "hotel-rooms-blob-indexer",
    dataSourceName: blobDataSource.Name,
    targetIndexName: indexName)
{
    Parameters = parameters,
    Schedule = new IndexingSchedule(TimeSpan.FromDays(1))
};

// Map the Id field in the Room documents to the HotelId key field in the index
blobIndexer.FieldMappings.Add(new FieldMapping("Id") { TargetFieldName = "HotelId" });

// Reset the indexer if it already exists
try
{
    await indexerClient.GetIndexerAsync(blobIndexer.Name);
    await indexerClient.ResetIndexerAsync(blobIndexer.Name);
}
catch (RequestFailedException ex) when (ex.Status == 404) { }

await indexerClient.CreateOrUpdateIndexerAsync(blobIndexer);

try
{
    // Run the indexer.
    await searchService.Indexers.RunAsync(blobIndexer.Name);
}
catch (CloudException e) when (e.Response.StatusCode == (HttpStatusCode)429)
{
    Console.WriteLine("Failed to run indexer: {0}", e.Response.Content);
}

Étant donné que l’index a déjà été rempli avec les données d’hôtels à partir de la base de données Azure Cosmos DB, l’indexeur d’objets blob met à jour les documents existants dans l’index et ajoute les détails des chambres.

Notes

Si vous avez les mêmes champs non-clé dans vos deux sources de données et que les données au sein de ces champs ne correspondent pas, l’index contient les valeurs de l’indexeur qui a été exécuté le plus récemment. Dans notre exemple, les deux sources de données contiennent un champ HotelName. Si, pour une raison quelconque, les données de ce champ sont différentes pour des documents ayant la même valeur de clé, les données HotelName de la source de données qui a été indexée le plus récemment sont la valeur stockée dans l’index.

Une fois le programme exécuté, vous pouvez explorer l’index de recherche rempli en utilisant l’Explorateur de recherche dans le portail.

Dans le portail Azure, ouvrez la page Vue d’ensemble du service de recherche, puis recherchez l’index hotel-rooms-sample dans la liste Index.

Liste des index de recherche Azure AI

Sélectionnez l’index hotel-rooms-sample dans la liste. Vous verrez une interface de l’Explorateur de recherche pour l’index. Entrez une requête portant sur un terme, par exemple « Luxury » (Luxe). Vous devriez voir au moins un document dans les résultats, et ce document doit afficher une liste d’objets de chambre dans son tableau de chambres.

Réinitialiser et réexécuter

Dans les premières étapes expérimentales de développement, l’approche la plus pratique pour les itérations de conception consiste à supprimer les objets d’Azure AI Search et à autoriser votre code à les reconstruire. Les noms des ressources sont uniques. La suppression d’un objet vous permet de le recréer en utilisant le même nom.

L’exemple de code recherche les objets existants, et les supprime ou les met à jour pour vous permettre de réexécuter le programme.

Vous pouvez également utiliser le portail pour supprimer les index, les indexeurs et les sources de données.

Nettoyer les ressources

Lorsque vous travaillez dans votre propre abonnement, il est judicieux à la fin d’un projet de supprimer les ressources dont vous n’avez plus besoin. Les ressources laissées en cours d’exécution peuvent vous coûter de l’argent. Vous pouvez supprimer les ressources une par une, ou choisir de supprimer le groupe de ressources afin de supprimer l’ensemble des ressources.

Vous pouvez rechercher et gérer les ressources dans le portail à l’aide des liens Toutes les ressources ou Groupes de ressources situés dans le volet de navigation de gauche.

Étapes suivantes

Maintenant que vous êtes familiarisé avec le concept d’investigation de données provenant de plusieurs sources, examinons de plus près la configuration de l’indexeur, en commençant par Azure Cosmos DB.