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 ligger 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 för NoSQL kostnadsfritt.
- 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 container- och 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 $resourceGroupName \ --account-name $accountName \ --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 för/region
.az cosmosdb sql container create \ --resource-group $resourceGroupName \ --account-name $accountName \ --database-name "cosmicworks" \ --name "locations" \ --partition-key-path "/category" \ --idx @index-policy.json
Hämta den primära anslutningssträngen för kontot med .
az cosmosdb keys list
az cosmosdb keys list \ --resource-group $resourceGroupName \ --name $accountName \ --type "connection-strings" \ --query "connectionStrings[?keyKind == \`Primary\`].connectionString" \ --output tsv
Tips
Om du vill se alla möjliga anslutningssträngar för ett konto använder du
az cosmosdb keys list --resource-group $resourceGroupName --name $accountName --type "connection-strings"
.Registrera anslutningssträngen. Du använder den här autentiseringsuppgiften senare i den här guiden.
Skapa .NET SDK-konsolprogram
.NET SDK för Azure Cosmos DB for NoSQL innehå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
Importera NuGet-paketet Microsoft.Azure.Cosmos med kommandot
dotnet add package
.dotnet add package Microsoft.Azure.Cosmos --version 3.*
Varning
Entity Framework har för närvarande inte rumsliga data i Azure Cosmos DB för NoSQL. Använd en av SDK:erna för Azure Cosmos DB for NoSQL för starkt skrivet GeoJSON-stöd.
Skapa projektet med
dotnet build
kommandot .dotnet build
Öppna den integrerade utvecklarmiljö (IDE) som du väljer i samma katalog som ditt .NET-konsolprogram.
Öppna den nyligen skapade Program.cs-filen och ta bort befintlig kod. Lägg till med hjälp av direktiv för namnrymderna
Microsoft.Azure.Cosmos
,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 en strängvariabel med namnet *
connectionString
med anslutningssträngen som du registrerade tidigare i den här guiden.string connectionString = "<your-account-connection-string>"
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 Description Standardvärde id string
Unik identifierare Namn string
Namnet på kontoret Plats Point
Geografisk geoJSON-punkt Kategori string
Partitionsnyckelvärde business-office
using Microsoft.Azure.Cosmos.Spatial; public record Office( string id, string name, Point location, string category = "business-office" );
Anteckning
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 Description 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" );
Anteckning
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 Description 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}");
Tips
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
för att öka 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}");
Anteckning
Mer information om transaktioner finns i transaktionella batchå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 ";
Tips
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
allmänna 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}"); } }
Anteckning
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 .
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
FUNKTIONEN LINQ till NoSQL i .NET SDK stöder inklusive geospatiala typer i frågeuttrycken. SDK innehåller dessutom 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 dessa 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 kontorsplatsegenskapen en punkt och regionens platsegenskap har en polygon.
ST_WITHIN
avgör om platsen för kontoret ligger inom regionens polygon.Använd en kombination av en while - 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 $resourceGroupName \ --account-name $accountName \ --name "cosmicworks"