Indexer et interroger des données d’emplacement GeoJSON dans Azure Cosmos DB for NoSQL
S’APPLIQUE À : NoSQL
Les données géospatiales dans Azure Cosmos DB for NoSQL vous permettent de stocker des informations d’emplacement et d’effectuer des requêtes courantes, notamment :
- Rechercher si un emplacement se trouve dans une zone définie
- Mesure de la distance entre deux emplacements
- Déterminer si un chemin d’accès croise un emplacement ou une zone
Ce guide décrit le processus de création de données géospatiales, d’indexation des données, puis d’interrogation des données dans un conteneur.
Prérequis
- Un compte Azure Cosmos DB for NoSQL existant.
- Si vous n’avez pas d’abonnement Azure, essayez gratuitement Azure Cosmos DB for NoSQL.
- Si vous disposez d’un abonnement Azure, créez un compte Azure Cosmos DB for SQL.
- Dernière version de .NET.
- La dernière version d’Azure CLI.
- Si vous utilisez une installation locale, connectez-vous à Azure CLI à l’aide de la commande
az login
.
- Si vous utilisez une installation locale, connectez-vous à Azure CLI à l’aide de la commande
Créer un conteneur et une stratégie d’indexation
Tous les conteneurs incluent une stratégie d’indexation par défaut qui indexera correctement les données géospatiales. Pour créer une stratégie d’indexation personnalisée, créez un compte et spécifiez un fichier JSON avec la configuration de la stratégie. Dans cette section, un index spatial personnalisé est utilisé pour un conteneur nouvellement créé.
Ouvrez un terminal.
Créez une variable shell pour le nom de votre compte et groupe de ressources Azure Cosmos DB for NoSQL.
# Variable for resource group name resourceGroupName="<name-of-your-resource-group>" # Variable for account name accountName="<name-of-your-account>"
Créez une base de données sous le nom
cosmicworks
à l’aide deaz cosmosdb sql database create
.az cosmosdb sql database create \ --resource-group "<resource-group-name>" \ --account-name "<nosql-account-name>" \ --name "cosmicworks" \ --throughput 400
Créez un fichier JSON nommé index-policy.json et ajoutez l’objet JSON suivant au fichier.
{ "indexingMode": "consistent", "automatic": true, "includedPaths": [ { "path": "/*" } ], "excludedPaths": [ { "path": "/\"_etag\"/?" } ], "spatialIndexes": [ { "path": "/location/*", "types": [ "Point", "Polygon" ] } ] }
Utilisez
az cosmosdb sql container create
pour créer un conteneur nommélocations
avec un chemin de clé de partition de/region
.az cosmosdb sql container create \ --resource-group "<resource-group-name>" \ --account-name "<nosql-account-name>" \ --database-name "cosmicworks" \ --name "locations" \ --partition-key-path "/category" \ --idx @index-policy.json
Enfin, obtenez le point de terminaison de votre compte à l’aide de
az cosmosdb show
et d’une requête JMESPath.az cosmosdb show \ --resource-group "<resource-group-name>" \ --name "<nosql-account-name>" \ --query "documentEndpoint"
Enregistrez le point de terminaison du compte car vous en aurez besoin dans la section suivante.
Créer une application console SDK .NET
Le kit de développement logiciel (SDK) .NET pour Azure Cosmos DB for NoSQL fournit des classes pour les objets GeoJSON courants. Utilisez ce kit de développement logiciel (SDK) pour simplifier le processus d’ajout d’objets géographiques à votre conteneur.
Ouvrez un terminal dans un répertoire vide.
Créez une application .NET à l’aide de la commande
dotnet new
avec le modèle de console.dotnet new console
Importez le package NuGet
Microsoft.Azure.Cosmos
à l’aide de la commandedotnet add package
.dotnet add package Microsoft.Azure.Cosmos --version 3.*
Avertissement
Entity Framework ne contient actuellement pas de données spatiales dans Azure Cosmos DB for NoSQL. Utilisez l’un des SDK Azure Cosmos DB for NoSQL pour la prise en charge de GeoJSON fortement typé.
Importez le package NuGet
Azure.Identity
.dotnet add package Azure.Identity --version 1.*
Générez le projet avec la commande
dotnet build
.dotnet build
Ouvrez l’environnement de développement intégré (IDE) de votre choix dans le même répertoire que votre application console .NET.
Ouvrez le fichier Program.cs nouvellement créé et supprimez tout code existant. Ajoutez des directives d’utilisation pour les espaces de noms
Microsoft.Azure.Cosmos
,Microsoft.Azure.Cosmos.Linq
etMicrosoft.Azure.Cosmos.Spatial
.using Microsoft.Azure.Cosmos; using Microsoft.Azure.Cosmos.Linq; using Microsoft.Azure.Cosmos.Spatial;
Ajoutez une autre directive d’utilisation pour l’espace de noms
Azure.Identity
.using Azure.Identity;
Créez une variable nommée
credential
de typeDefaultAzureCredential
.DefaultAzureCredential credential = new();
Créez une variable de chaîne nommée
endpoint
avec le point de terminaison de votre compte Azure Cosmos DB pour NoSQL.string endpoint = "<nosql-account-endpoint>";
Créez une instance de la classe
CosmosClient
en la transmettant enconnectionString
et en l’enveloppant dans une instruction using.using CosmosClient client = new (connectionString);
Récupérez une référence au conteneur créé précédemment (
cosmicworks/locations
) dans le compte Azure Cosmos DB for NoSQL à l’aide deCosmosClient.GetDatabase
puis deDatabase.GetContainer
. Stockez le résultat dans une variable nomméecontainer
.var container = client.GetDatabase("cosmicworks").GetContainer("locations");
Enregistrez le fichier Program.cs.
Ajouter des données géospatiales
Le kit de développement logiciel (SDK) .NET inclut plusieurs types dans l’espace de noms Microsoft.Azure.Cosmos.Spatial
pour représenter les objets GeoJSON courants. Ces types simplifient le processus d’ajout de nouvelles informations sur l’emplacement aux éléments d’un conteneur.
Créez un fichier appelé Office.cs. Dans le fichier, ajoutez une instruction using à
Microsoft.Azure.Cosmos.Spatial
, puis créez un type d’enregistrementOffice
avec ces propriétés :Type Description Valeur par défaut id string
Identificateur unique name string
Nom du bureau location Point
Point géographique GeoJSON category string
Valeur de clé de la partition business-office
using Microsoft.Azure.Cosmos.Spatial; public record Office( string id, string name, Point location, string category = "business-office" );
Notes
Cet enregistrement inclut une propriété représentant
Point
une position spécifique dans GeoJSON. Pour plus d’informations, consultez Point GeoJSON.Créez un autre fichier nommé Region.cs. Ajoutez un autre type d’enregistrement nommé
Region
avec les propriétés suivantes :Type Description Valeur par défaut id string
Identificateur unique name string
Nom du bureau location Polygon
Forme géographique GeoJSON category string
Valeur de clé de la partition business-region
using Microsoft.Azure.Cosmos.Spatial; public record Region( string id, string name, Polygon location, string category = "business-region" );
Notes
Cet enregistrement inclut une propriété
Polygon
représentant une forme composée de lignes dessinées entre plusieurs emplacements dans GeoJSON. Pour plus d’informations, consultez Polygone GeoJSON.Créez un autre fichier nommé Result.cs. Ajoutez un type d’enregistrement nommé
Result
avec ces deux propriétés :Type Description name string
Nom du résultat mis en correspondance distanceKilometers decimal
Distance en kilomètres public record Result( string name, decimal distanceKilometers );
Enregistrez les fichiers Office.cs, Region.cs et Result.cs .
Rouvrez le fichier Program.cs.
Créez une
Polygon
dans une variable nomméemainCampusPolygon
.Polygon mainCampusPolygon = new ( new [] { new LinearRing(new [] { new Position(-122.13237, 47.64606), new Position(-122.13222, 47.63376), new Position(-122.11841, 47.64175), new Position(-122.12061, 47.64589), new Position(-122.13237, 47.64606), }) } );
Créez une variable
Region
nomméemainCampusRegion
à l’aide du polygone, de l’identificateur unique1000
et du nomMain Campus
.Region mainCampusRegion = new ("1000", "Main Campus", mainCampusPolygon);
Utilisez
Container.UpsertItemAsync
pour ajouter la région au conteneur. Écrivez les informations de la région dans la console.await container.UpsertItemAsync<Region>(mainCampusRegion); Console.WriteLine($"[UPSERT ITEM]\t{mainCampusRegion}");
Conseil
Ce guide utilise upsert au lieu de insert afin que vous puissiez exécuter le script plusieurs fois sans provoquer de conflit entre les identificateurs uniques. Pour plus d’informations sur les opérations upsert, consultez Création d’éléments.
Créer une variable
Point
nomméeheadquartersPoint
. Utilisez cette variable pour créer une variableOffice
nomméeheadquartersOffice
à l’aide du point, de l’identificateur0001
unique et du nomHeadquarters
.Point headquartersPoint = new (-122.12827, 47.63980); Office headquartersOffice = new ("0001", "Headquarters", headquartersPoint);
Créez une autre variable
Point
nomméeresearchPoint
. Utilisez cette variable pour créer une autre variableOffice
nomméeresearchOffice
à l’aide du point correspondant, de l’identificateur0002
unique et du nomResearch and Development
.Point researchPoint = new (-96.84369, 46.81298); Office researchOffice = new ("0002", "Research and Development", researchPoint);
Créez un
TransactionalBatch
pour faire un upsert des deux variablesOffice
en tant que transaction unique. Ensuite, écrivez les informations des deux bureaux dans la console.TransactionalBatch officeBatch = container.CreateTransactionalBatch(new PartitionKey("business-office")); officeBatch.UpsertItem<Office>(headquartersOffice); officeBatch.UpsertItem<Office>(researchOffice); await officeBatch.ExecuteAsync(); Console.WriteLine($"[UPSERT ITEM]\t{headquartersOffice}"); Console.WriteLine($"[UPSERT ITEM]\t{researchOffice}");
Notes
Pour plus d’informations sur les transactions, consultez Opérations de lot transactionnel.
Enregistrez le fichier Program.cs.
Exécutez l’application dans un terminal à l’aide de
dotnet run
. Notez que la sortie de l’exécution de l’application inclut des informations sur les trois éléments nouvellement créés.dotnet run
[UPSERT ITEM] Region { id = 1000, name = Main Campus, location = Microsoft.Azure.Cosmos.Spatial.Polygon, category = business-region } [UPSERT ITEM] Office { id = 0001, name = Headquarters, location = Microsoft.Azure.Cosmos.Spatial.Point, category = business-office } [UPSERT ITEM] Office { id = 0002, name = Research and Development, location = Microsoft.Azure.Cosmos.Spatial.Point, category = business-office }
Interroger des données géospatiales à l’aide d’une requête NoSQL
Les types de l’espace de noms Microsoft.Azure.Cosmos.Spatial
peuvent être utilisés comme entrées dans une requête paramétrable NoSQL pour utiliser des fonctions intégrées telles que ST_DISTANCE
.
Ouvrez le fichier Program.cs.
Créer une variable
string
nomméenosql
avec la requête est utilisée dans cette section pour mesurer la distance entre les points.string nosqlString = @" SELECT o.name, NumberBin(distanceMeters / 1000, 0.01) AS distanceKilometers FROM offices o JOIN (SELECT VALUE ROUND(ST_DISTANCE(o.location, @compareLocation))) AS distanceMeters WHERE o.category = @partitionKey AND distanceMeters > @maxDistance ";
Conseil
Cette requête place la fonction géospatiale dans une sous-requête pour simplifier le processus de réutilisation de la valeur déjà calculée plusieurs fois dans les clauses
SELECT
etWHERE
.Créez une variable
QueryDefinition
nomméequery
en utilisant la variablenosqlString
comme paramètre. Utilisez ensuite la méthode FluentQueryDefinition.WithParameter
plusieurs fois pour ajouter ces paramètres à la requête :Valeur @maxDistance 2000
@partitionKey "business-office"
@compareLocation new Point(-122.11758, 47.66901)
var query = new QueryDefinition(nosqlString) .WithParameter("@maxDistance", 2000) .WithParameter("@partitionKey", "business-office") .WithParameter("@compareLocation", new Point(-122.11758, 47.66901));
Créez un itérateur à l’aide de
Container.GetItemQueryIterator<>
, du type génériqueResult
et de la variablequery
. Ensuite, utilisez la combinaison d’une boucle while et foreach pour itérer sur tous les résultats dans chaque page de résultats. Sortie de chaque résultat dans la console.var distanceIterator = container.GetItemQueryIterator<Result>(query); while (distanceIterator.HasMoreResults) { var response = await distanceIterator.ReadNextAsync(); foreach (var result in response) { Console.WriteLine($"[DISTANCE KM]\t{result}"); } }
Notes
Pour plus d’informations sur l’énumération des résultats de requête, consultez les éléments de requête.
Enregistrez le fichier Program.cs.
Exécutez à nouveau l’application dans un terminal à l’aide de
dotnet run
. Notez que la sortie inclut désormais les résultats de la requête.dotnet run
[DISTANCE KM] Result { name = Headquarters, distanceKilometers = 3.34 } [DISTANCE KM] Result { name = Research and Development, distanceKilometers = 1907.43 }
Interroger des données géospatiales à l’aide de LINQ
La fonctionnalité LINQ to NoSQL dans le kit de développement logiciel (SDK) .NET prend en charge l’inclusion de types géospatiaux dans les expressions de requête. Plus encore, le kit de développement logiciel (SDK) inclut des méthodes d’extension qui correspondent à des fonctions intégrées équivalentes :
Méthode d’extension | Fonction intégrée |
---|---|
Distance() |
ST_DISTANCE |
Intersects() |
ST_INTERSECTS |
IsValid() |
ST_ISVALID |
IsValidDetailed() |
ST_ISVALIDDETAILED |
Within() |
ST_WITHIN |
Ouvrez le fichier Program.cs.
Récupérez l’élément
Region
du conteneur avec un identificateur unique de1000
et stockez-le dans une variable nomméeregion
.Region region = await container.ReadItemAsync<Region>("1000", new PartitionKey("business-region"));
Utilisez la méthode
Container.GetItemLinqQueryable<>
pour obtenir un LINQ requêtable, générez la requête LINQ couramment en effectuant ces trois actions :Utilisez la méthode d’extension
Queryable.Where<>
pour filtrer uniquement les éléments ayant uncategory
équivalent à"business-office"
.Utilisez
Queryable.Where<>
à nouveau pour afficher uniquement les emplacements de la propriétélocation
de la variableregion
à l’aide deGeometry.Within()
.Traduisez l’expression LINQ en itérateur de flux à l’aide de
CosmosLinqExtensions.ToFeedIterator<>
.
var regionIterator = container.GetItemLinqQueryable<Office>() .Where(o => o.category == "business-office") .Where(o => o.location.Within(region.location)) .ToFeedIterator<Office>();
Important
Dans cet exemple, la propriété d’emplacement du bureau a un point et la propriété d’emplacement de la région a un polygone.
ST_WITHIN
détermine si le point du bureau se trouve dans le polygone de la région.Utilisez la combinaison d’une boucle while et foreach pour itérer sur tous les résultats dans chaque page de résultats. Sortie de chaque résultat dans la console.
while (regionIterator.HasMoreResults) { var response = await regionIterator.ReadNextAsync(); foreach (var office in response) { Console.WriteLine($"[IN REGION]\t{office}"); } }
Enregistrez le fichier Program.cs.
Exécutez l’application une dernière fois dans un terminal à l’aide de
dotnet run
. Notez que la sortie inclut désormais les résultats de la deuxième requête basé sur LINQ.dotnet run
[IN REGION] Office { id = 0001, name = Headquarters, location = Microsoft.Azure.Cosmos.Spatial.Point, category = business-office }
Nettoyer les ressources
Supprimez votre base de données après avoir terminé ce guide.
Ouvrez un terminal et créez une variable shell pour le nom de votre compte et groupe de ressources.
# Variable for resource group name resourceGroupName="<name-of-your-resource-group>" # Variable for account name accountName="<name-of-your-account>"
Utilisez
az cosmosdb sql database delete
pour supprimer la base de données.az cosmosdb sql database delete \ --resource-group "<resource-group-name>" \ --account-name "<nosql-account-name>" \ --name "cosmicworks"