Indexera och fråga GeoJSON-platsdata i Azure Cosmos DB för NoSQL
GÄLLER FÖR: NoSQL
Med geospatiala data i Azure Cosmos DB for NoSQL kan du lagra platsinformation och utföra vanliga frågor, inklusive men inte begränsat till:
- Söka efter om en plats finns inom ett definierat område
- Mäta avståndet mellan två platser
- Avgöra om en sökväg korsar en plats eller ett område
Den här guiden går igenom processen med att skapa geospatiala data, indexera data och sedan köra frågor mot data i en container.
Förutsättningar
- Ett befintligt Azure Cosmos DB för NoSQL-konto.
- Om du inte har en Azure-prenumeration kan du prova Azure Cosmos DB utan kostnad för NoSQL.
- Om du har en befintlig Azure-prenumeration skapar du ett nytt Azure Cosmos DB för NoSQL-konto.
- Senaste versionen av .NET.
- Senaste versionen av Azure CLI.
- Om du använder en lokal installation loggar du in på Azure CLI med hjälp
az login
av kommandot .
- Om du använder en lokal installation loggar du in på Azure CLI med hjälp
Skapa en container och en indexeringsprincip
Alla containrar innehåller en standardindexeringsprincip som ska indexera geospatiala data. Skapa en anpassad indexeringsprincip genom att skapa ett konto och ange en JSON-fil med principens konfiguration. I det här avsnittet används ett anpassat rumsligt index för en nyligen skapad container.
Öppna en terminal.
Skapa en gränssnittsvariabel för namnet på ditt Azure Cosmos DB för NoSQL-konto och resursgrupp.
# Variable for resource group name resourceGroupName="<name-of-your-resource-group>" # Variable for account name accountName="<name-of-your-account>"
Skapa en ny databas med namnet
cosmicworks
med .az cosmosdb sql database create
az cosmosdb sql database create \ --resource-group "<resource-group-name>" \ --account-name "<nosql-account-name>" \ --name "cosmicworks" \ --throughput 400
Skapa en ny JSON-fil med namnet index-policy.json och lägg till följande JSON-objekt i filen.
{ "indexingMode": "consistent", "automatic": true, "includedPaths": [ { "path": "/*" } ], "excludedPaths": [ { "path": "/\"_etag\"/?" } ], "spatialIndexes": [ { "path": "/location/*", "types": [ "Point", "Polygon" ] } ] }
Använd
az cosmosdb sql container create
för att skapa en ny container med namnetlocations
med en partitionsnyckelsökväg/region
för .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
Hämta slutligen kontoslutpunkten för ditt konto med hjälp av
az cosmosdb show
och en JMESPath-fråga.az cosmosdb show \ --resource-group "<resource-group-name>" \ --name "<nosql-account-name>" \ --query "documentEndpoint"
Registrera kontoslutpunkten som du behöver i nästa avsnitt.
Skapa .NET SDK-konsolprogram
.NET SDK för Azure Cosmos DB for NoSQL tillhandahåller klasser för vanliga GeoJSON-objekt. Använd denna SDK för att effektivisera processen med att lägga till geografiska objekt i containern.
Öppna en terminal i en tom katalog.
Skapa ett nytt .NET-program med hjälp
dotnet new
av kommandot med konsolmallen.dotnet new console
Microsoft.Azure.Cosmos
Importera NuGet-paketet med kommandotdotnet add package
.dotnet add package Microsoft.Azure.Cosmos --version 3.*
Varning
Entity Framework lagrar för närvarande inte rumsliga data i Azure Cosmos DB för NoSQL. Använd en av Azure Cosmos DB for NoSQL SDK:erna för starkt skrivet GeoJSON-stöd.
Importera NuGet-paketet
Azure.Identity
.dotnet add package Azure.Identity --version 1.*
Skapa projektet med
dotnet build
kommandot .dotnet build
Öppna valfri integrerad utvecklarmiljö (IDE) i samma katalog som ditt .NET-konsolprogram.
Öppna den nyligen skapade Program.cs-filen och ta bort eventuell befintlig kod. Lägg till med hjälp av direktiv för
Microsoft.Azure.Cosmos
namnrymderna ,Microsoft.Azure.Cosmos.Linq
ochMicrosoft.Azure.Cosmos.Spatial
.using Microsoft.Azure.Cosmos; using Microsoft.Azure.Cosmos.Linq; using Microsoft.Azure.Cosmos.Spatial;
Lägg till ett annat användningsdirektiv för
Azure.Identity
namnområdet.using Azure.Identity;
Skapa en ny variabel med namnet
credential
av typenDefaultAzureCredential
.DefaultAzureCredential credential = new();
Skapa en strängvariabel med namnet
endpoint
med azure Cosmos DB för NoSQL-kontoslutpunkten.string endpoint = "<nosql-account-endpoint>";
Skapa en ny instans av klassen som
CosmosClient
skickar inconnectionString
och omsluter den i en using-instruktion.using CosmosClient client = new (connectionString);
Hämta en referens till den tidigare skapade containern (
cosmicworks/locations
) i Azure Cosmos DB för NoSQL-kontot med hjälpCosmosClient.GetDatabase
av och sedanDatabase.GetContainer
. Lagra resultatet i en variabel med namnetcontainer
.var container = client.GetDatabase("cosmicworks").GetContainer("locations");
Spara Program.cs-filen.
Lägga till geospatiala data
.NET SDK innehåller flera typer i Microsoft.Azure.Cosmos.Spatial
namnområdet för att representera vanliga GeoJSON-objekt. Dessa typer effektiviserar processen med att lägga till ny platsinformation till objekt i en container.
Skapa en ny fil med namnet Office.cs. I filen lägger du till ett användningsdirektiv i
Microsoft.Azure.Cosmos.Spatial
och skapar sedan enOffice
posttyp med följande egenskaper:Typ Beskrivning Standardvärde id string
Unik identifierare Namn string
Namnet på kontoret Plats Point
Geografisk punkt för GeoJSON kategori string
Partitionsnyckelvärde business-office
using Microsoft.Azure.Cosmos.Spatial; public record Office( string id, string name, Point location, string category = "business-office" );
Kommentar
Den här posten innehåller en
Point
egenskap som representerar en specifik position i GeoJSON. Mer information finns i GeoJSON Point.Skapa en annan ny fil med namnet Region.cs. Lägg till en annan posttyp med namnet
Region
med följande egenskaper:Typ Beskrivning Standardvärde id string
Unik identifierare Namn string
Namnet på kontoret Plats Polygon
Geografisk geoJSON-form kategori string
Partitionsnyckelvärde business-region
using Microsoft.Azure.Cosmos.Spatial; public record Region( string id, string name, Polygon location, string category = "business-region" );
Kommentar
Den här posten innehåller en
Polygon
egenskap som representerar en form som består av linjer som ritats mellan flera platser i GeoJSON. Mer information finns i GeoJSON Polygon.Skapa en annan ny fil med namnet Result.cs. Lägg till en posttyp med namnet
Result
med följande två egenskaper:Typ Beskrivning Namn string
Namnet på det matchade resultatet distanceKilometers decimal
Avstånd i kilometer public record Result( string name, decimal distanceKilometers );
Spara filerna Office.cs, Region.cs och Result.cs.
Öppna filen Program.cs igen.
Skapa en ny
Polygon
i en variabel med namnetmainCampusPolygon
.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), }) } );
Skapa en ny
Region
variabel med namnetmainCampusRegion
med hjälp av polygonen, den unika identifieraren1000
och namnetMain Campus
.Region mainCampusRegion = new ("1000", "Main Campus", mainCampusPolygon);
Använd
Container.UpsertItemAsync
för att lägga till regionen i containern. Skriv regionens information till konsolen.await container.UpsertItemAsync<Region>(mainCampusRegion); Console.WriteLine($"[UPSERT ITEM]\t{mainCampusRegion}");
Dricks
Den här guiden använder upsert i stället för infoga så att du kan köra skriptet flera gånger utan att orsaka en konflikt mellan unika identifierare. Mer information om upsert-åtgärder finns i skapa objekt.
Skapa en ny
Point
variabel med namnetheadquartersPoint
. Använd variabeln för att skapa en nyOffice
variabel med namnetheadquartersOffice
med hjälp av punkten, den unika identifieraren0001
och namnetHeadquarters
.Point headquartersPoint = new (-122.12827, 47.63980); Office headquartersOffice = new ("0001", "Headquarters", headquartersPoint);
Skapa en annan
Point
variabel med namnetresearchPoint
. Använd variabeln för att skapa en annanOffice
variabel med namnetresearchOffice
med hjälp av motsvarande punkt, den unika identifieraren0002
och namnetResearch and Development
.Point researchPoint = new (-96.84369, 46.81298); Office researchOffice = new ("0002", "Research and Development", researchPoint);
Skapa en
TransactionalBatch
till upsert bådaOffice
variablerna som en enda transaktion. Skriv sedan information om båda kontoren till konsolen.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}");
Kommentar
Mer information om transaktioner finns i Transaktionsbatchåtgärder.
Spara Program.cs-filen.
Kör programmet i en terminal med .
dotnet run
Observera att utdata från programkörningen innehåller information om de tre nyligen skapade objekten.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 }
Fråga geospatiala data med hjälp av NoSQL-fråga
Typerna Microsoft.Azure.Cosmos.Spatial
i namnområdet kan användas som indata till en NoSQL-parameteriserad fråga för att använda inbyggda funktioner som ST_DISTANCE
.
Öppna filen Program.cs .
Skapa en ny
string
variabel med namnetnosql
med frågan som används i det här avsnittet för att mäta avståndet mellan punkter.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 ";
Dricks
Den här frågan placerar den geospatiala funktionen i en underfråga för att förenkla processen att återanvända det redan beräknade värdet flera gånger i
SELECT
- och-satsernaWHERE
.Skapa en ny
QueryDefinition
variabel med namnetquery
med variabelnnosqlString
som parameter. AnvändQueryDefinition.WithParameter
sedan fluent-metoden flera gånger för att lägga till dessa parametrar i frågan:Värde @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));
Skapa en ny iterator med hjälp av
Container.GetItemQueryIterator<>
, denResult
generiska typen och variabelnquery
. Använd sedan en kombination av en while - och foreach-loop för att iterera över alla resultat på varje sida med resultat. Mata ut varje resultat till konsolen.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}"); } }
Kommentar
Mer information om hur du räknar upp frågeresultat finns i frågeobjekt.
Spara Program.cs-filen.
Kör programmet igen i en terminal med hjälp av
dotnet run
. Observera att utdata nu innehåller resultatet av frågan.dotnet run
[DISTANCE KM] Result { name = Headquarters, distanceKilometers = 3.34 } [DISTANCE KM] Result { name = Research and Development, distanceKilometers = 1907.43 }
Fråga geospatiala data med LINQ
FUNKTIONERNA LINQ till NoSQL i .NET SDK stöder inklusive geospatiala typer i frågeuttrycken. SDK innehåller även tilläggsmetoder som mappar till motsvarande inbyggda funktioner:
Tilläggsmetod | Inbyggd funktion |
---|---|
Distance() |
ST_DISTANCE |
Intersects() |
ST_INTERSECTS |
IsValid() |
ST_ISVALID |
IsValidDetailed() |
ST_ISVALIDDETAILED |
Within() |
ST_WITHIN |
Öppna filen Program.cs .
Region
Hämta objektet från containern med en unik identifierare för1000
och lagra det i en variabel med namnetregion
.Region region = await container.ReadItemAsync<Region>("1000", new PartitionKey("business-region"));
Container.GetItemLinqQueryable<>
Använd metoden för att få en LINQ-frågebar och skapa LINQ-frågan flytande genom att utföra följande tre åtgärder:Queryable.Where<>
Använd tilläggsmetoden för att filtrera till endast objekt med motsvarandecategory
"business-office"
.Använd
Queryable.Where<>
igen om du bara vill filtrera till platser iregion
variabelnslocation
egenskap med hjälp avGeometry.Within()
.Översätt LINQ-uttrycket till en feed-iterator med hjälp av
CosmosLinqExtensions.ToFeedIterator<>
.
var regionIterator = container.GetItemLinqQueryable<Office>() .Where(o => o.category == "business-office") .Where(o => o.location.Within(region.location)) .ToFeedIterator<Office>();
Viktigt!
I det här exemplet har kontorets platsegenskap en punkt och regionens platsegenskap har en polygon.
ST_WITHIN
avgör om platsen på kontoret ligger inom regionens polygon.Använd en kombination av en stund - och foreach-loop för att iterera över alla resultat på varje resultatsida. Mata ut varje resultat till konsolen.
while (regionIterator.HasMoreResults) { var response = await regionIterator.ReadNextAsync(); foreach (var office in response) { Console.WriteLine($"[IN REGION]\t{office}"); } }
Spara Program.cs-filen.
Kör programmet en sista gång i en terminal med .
dotnet run
Observera att utdata nu innehåller resultatet av den andra LINQ-baserade frågan.dotnet run
[IN REGION] Office { id = 0001, name = Headquarters, location = Microsoft.Azure.Cosmos.Spatial.Point, category = business-office }
Rensa resurser
Ta bort databasen när du har slutfört den här guiden.
Öppna en terminal och skapa en gränssnittsvariabel för namnet på ditt konto och din resursgrupp.
# Variable for resource group name resourceGroupName="<name-of-your-resource-group>" # Variable for account name accountName="<name-of-your-account>"
Använd
az cosmosdb sql database delete
för att ta bort databasen.az cosmosdb sql database delete \ --resource-group "<resource-group-name>" \ --account-name "<nosql-account-name>" \ --name "cosmicworks"