Indeksowanie i wykonywanie zapytań dotyczących danych lokalizacji GeoJSON w usłudze Azure Cosmos DB for NoSQL
DOTYCZY: NoSQL
Dane geoprzestrzenne w usłudze Azure Cosmos DB for NoSQL umożliwiają przechowywanie informacji o lokalizacji i wykonywanie typowych zapytań, w tym między innymi:
- Znajdowanie, czy lokalizacja znajduje się w zdefiniowanym obszarze
- Mierzenie odległości między dwiema lokalizacjami
- Określanie, czy ścieżka przecina się z lokalizacją lub obszarem
W tym przewodniku przedstawiono proces tworzenia danych geoprzestrzennych, indeksowania danych, a następnie wykonywania zapytań dotyczących danych w kontenerze.
Wymagania wstępne
- Istniejące konto usługi Azure Cosmos DB for NoSQL.
- Jeśli nie masz subskrypcji platformy Azure, wypróbuj bezpłatnie usługę Azure Cosmos DB dla noSQL.
- Jeśli masz istniejącą subskrypcję platformy Azure, utwórz nowe konto usługi Azure Cosmos DB for NoSQL.
- Najnowsza wersja platformy .NET.
- Najnowsza wersja interfejsu wiersza polecenia platformy Azure.
- Jeśli używasz instalacji lokalnej, zaloguj się do interfejsu
az login
wiersza polecenia platformy Azure przy użyciu polecenia .
- Jeśli używasz instalacji lokalnej, zaloguj się do interfejsu
Tworzenie zasad kontenera i indeksowania
Wszystkie kontenery zawierają domyślne zasady indeksowania, które pomyślnie indeksują dane geoprzestrzenne. Aby utworzyć dostosowane zasady indeksowania, utwórz konto i określ plik JSON z konfiguracją zasad. W tej sekcji niestandardowy indeks przestrzenny jest używany dla nowo utworzonego kontenera.
Otwórz terminal.
Utwórz zmienną powłoki dla nazwy konta i grupy zasobów usługi 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>"
Utwórz nową bazę danych o nazwie
cosmicworks
przy użyciu poleceniaaz cosmosdb sql database create
.az cosmosdb sql database create \ --resource-group "<resource-group-name>" \ --account-name "<nosql-account-name>" \ --name "cosmicworks" \ --throughput 400
Utwórz nowy plik JSON o nazwie index-policy.json i dodaj następujący obiekt JSON do pliku.
{ "indexingMode": "consistent", "automatic": true, "includedPaths": [ { "path": "/*" } ], "excludedPaths": [ { "path": "/\"_etag\"/?" } ], "spatialIndexes": [ { "path": "/location/*", "types": [ "Point", "Polygon" ] } ] }
Użyj
az cosmosdb sql container create
polecenia , aby utworzyć nowy kontener o nazwielocations
z ścieżką/region
klucza partycji .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
Na koniec pobierz punkt końcowy konta dla konta przy użyciu polecenia
az cosmosdb show
i zapytanie JMESPath.az cosmosdb show \ --resource-group "<resource-group-name>" \ --name "<nosql-account-name>" \ --query "documentEndpoint"
Zarejestruj punkt końcowy konta, ponieważ będzie to potrzebne w następnej sekcji.
Tworzenie aplikacji konsolowej zestawu SDK platformy .NET
Zestaw .NET SDK dla usługi Azure Cosmos DB for NoSQL udostępnia klasy dla typowych obiektów GeoJSON. Użyj tego zestawu SDK, aby usprawnić proces dodawania obiektów geograficznych do kontenera.
Otwórz terminal w pustym katalogu.
Utwórz nową aplikację .NET przy użyciu
dotnet new
polecenia z szablonem konsoli .dotnet new console
Zaimportuj
Microsoft.Azure.Cosmos
dotnet add package
pakiet NuGet przy użyciu polecenia .dotnet add package Microsoft.Azure.Cosmos --version 3.*
Ostrzeżenie
Program Entity Framework nie obsługuje obecnie danych przestrzennych w usłudze Azure Cosmos DB for NoSQL. Użyj jednego z zestawów SDK usługi Azure Cosmos DB for NoSQL w celu obsługi silnie typizowanego pliku GeoJSON.
Zaimportuj
Azure.Identity
pakiet NuGet.dotnet add package Azure.Identity --version 1.*
Skompiluj projekt za
dotnet build
pomocą polecenia .dotnet build
Otwórz wybrane zintegrowane środowisko deweloperskie (IDE) w tym samym katalogu co aplikacja konsolowa platformy .NET.
Otwórz nowo utworzony plik Program.cs i usuń dowolny istniejący kod. Dodaj dyrektywy using dla
Microsoft.Azure.Cosmos
przestrzeni nazw ,Microsoft.Azure.Cosmos.Linq
iMicrosoft.Azure.Cosmos.Spatial
.using Microsoft.Azure.Cosmos; using Microsoft.Azure.Cosmos.Linq; using Microsoft.Azure.Cosmos.Spatial;
Dodaj kolejną dyrektywę
Azure.Identity
using dla przestrzeni nazw.using Azure.Identity;
Utwórz nową zmienną o nazwie
credential
typuDefaultAzureCredential
.DefaultAzureCredential credential = new();
Utwórz zmienną ciągu o nazwie
endpoint
przy użyciu punktu końcowego konta usługi Azure Cosmos DB for NoSQL.string endpoint = "<nosql-account-endpoint>";
Utwórz nowe wystąpienie klasy przekazującej
CosmosClient
connectionString
i zawijając je w instrukcji using.using CosmosClient client = new (connectionString);
Pobierz odwołanie do wcześniej utworzonego kontenera (
cosmicworks/locations
) na koncie usługi Azure Cosmos DB for NoSQL przy użyciu poleceniaCosmosClient.GetDatabase
, a następnieDatabase.GetContainer
. Zapisz wynik w zmiennej o nazwiecontainer
.var container = client.GetDatabase("cosmicworks").GetContainer("locations");
Zapisz plik Program.cs.
Dodawanie danych geoprzestrzennych
Zestaw .NET SDK zawiera wiele typów w Microsoft.Azure.Cosmos.Spatial
przestrzeni nazw do reprezentowania typowych obiektów GeoJSON. Te typy usprawniają proces dodawania nowych informacji o lokalizacji do elementów w kontenerze.
Utwórz nowy plik o nazwie Office.cs. W pliku dodaj dyrektywę using, a
Microsoft.Azure.Cosmos.Spatial
następnie utwórz typ rekorduOffice
z następującymi właściwościami:Type Opis Domyślna wartość id string
Unikatowy identyfikator name string
Nazwa biura location Point
Punkt geograficzny GeoJSON kategoria string
Wartość klucza partycji business-office
using Microsoft.Azure.Cosmos.Spatial; public record Office( string id, string name, Point location, string category = "business-office" );
Uwaga
Ten rekord zawiera właściwość reprezentującą
Point
określoną pozycję w formacie GeoJSON. Aby uzyskać więcej informacji, zobacz GeoJSON Point (Punkt GeoJSON).Utwórz kolejny nowy plik o nazwie Region.cs. Dodaj inny typ rekordu o nazwie z
Region
następującymi właściwościami:Type Opis Domyślna wartość id string
Unikatowy identyfikator name string
Nazwa biura location Polygon
Kształt geograficzny w formacie GeoJSON kategoria string
Wartość klucza partycji business-region
using Microsoft.Azure.Cosmos.Spatial; public record Region( string id, string name, Polygon location, string category = "business-region" );
Uwaga
Ten rekord zawiera właściwość reprezentującą
Polygon
kształt składający się z linii rysowanych między wieloma lokalizacjami w formacie GeoJSON. Aby uzyskać więcej informacji, zobacz GeoJSON Polygon.Utwórz kolejny nowy plik o nazwie Result.cs. Dodaj typ rekordu o nazwie o
Result
następujących dwóch właściwościach:Type opis name string
Nazwa dopasowanego wyniku distanceKilometers decimal
Odległość w kilometrach public record Result( string name, decimal distanceKilometers );
Zapisz pliki Office.cs, Region.cs i Result.cs.
Otwórz ponownie plik Program.cs.
Utwórz nową
Polygon
w zmiennej o nazwiemainCampusPolygon
.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), }) } );
Utwórz nową
Region
zmienną o nazwiemainCampusRegion
przy użyciu wielokąta, unikatowego identyfikatora1000
i nazwyMain Campus
.Region mainCampusRegion = new ("1000", "Main Campus", mainCampusPolygon);
Użyj
Container.UpsertItemAsync
polecenia , aby dodać region do kontenera. Zapisz informacje o regionie w konsoli programu .await container.UpsertItemAsync<Region>(mainCampusRegion); Console.WriteLine($"[UPSERT ITEM]\t{mainCampusRegion}");
Napiwek
W tym przewodniku użyto operacji upsert zamiast wstawiania, aby można było uruchomić skrypt wielokrotnie bez powodowania konfliktu między unikatowymi identyfikatorami. Aby uzyskać więcej informacji na temat operacji upsert, zobacz tworzenie elementów.
Utwórz nową
Point
zmienną o nazwieheadquartersPoint
. Użyj tej zmiennej, aby utworzyć nowąOffice
zmienną o nazwieheadquartersOffice
przy użyciu punktu, unikatowego identyfikatora0001
i nazwyHeadquarters
.Point headquartersPoint = new (-122.12827, 47.63980); Office headquartersOffice = new ("0001", "Headquarters", headquartersPoint);
Utwórz inną zmienną
Point
o nazwieresearchPoint
. Użyj tej zmiennej, aby utworzyć innąOffice
zmienną o nazwieresearchOffice
przy użyciu odpowiedniego punktu, unikatowego identyfikatora0002
i nazwyResearch and Development
.Point researchPoint = new (-96.84369, 46.81298); Office researchOffice = new ("0002", "Research and Development", researchPoint);
Utwórz wartość ,
TransactionalBatch
aby upsert obieOffice
zmienne jako pojedyncza transakcja. Następnie zapisz informacje o obu biurach w konsoli programu .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}");
Uwaga
Aby uzyskać więcej informacji na temat transakcji, zobacz operacje transakcyjne wsadowe.
Zapisz plik Program.cs.
Uruchom aplikację w terminalu przy użyciu polecenia
dotnet run
. Zwróć uwagę, że dane wyjściowe przebiegu aplikacji zawierają informacje o trzech nowo utworzonych elementach.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 }
Wykonywanie zapytań dotyczących danych geoprzestrzennych przy użyciu zapytania NoSQL
Typy w Microsoft.Azure.Cosmos.Spatial
przestrzeni nazw mogą służyć jako dane wejściowe do zapytania sparametryzowanego NoSQL w celu używania wbudowanych funkcji, takich jak ST_DISTANCE
.
Otwórz plik Program.cs.
Utwórz nową
string
zmienną o nazwienosql
z zapytaniem, która jest używana w tej sekcji do mierzenia odległości między punktami.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 ";
Utwórz nową
QueryDefinition
zmienną o nazwiequery
przy użyciu zmiennejnosqlString
jako parametru. Następnie użyjQueryDefinition.WithParameter
metody fluent wiele razy, aby dodać te parametry do zapytania:Wartość @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));
Utwórz nowy iterator przy użyciu
Container.GetItemQueryIterator<>
typuResult
ogólnego i zmiennejquery
. Następnie użyj kombinacji pętli while i foreach, aby iterować wszystkie wyniki na każdej stronie wyników. Wyprowadź każdy wynik do konsoli.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}"); } }
Uwaga
Aby uzyskać więcej informacji na temat wyliczania wyników zapytania, zobacz elementy zapytania.
Zapisz plik Program.cs.
Uruchom ponownie aplikację w terminalu przy użyciu polecenia
dotnet run
. Zwróć uwagę, że dane wyjściowe zawierają teraz wyniki zapytania.dotnet run
[DISTANCE KM] Result { name = Headquarters, distanceKilometers = 3.34 } [DISTANCE KM] Result { name = Research and Development, distanceKilometers = 1907.43 }
Wykonywanie zapytań dotyczących danych geoprzestrzennych przy użyciu LINQ
Funkcje LINQ to NoSQL w zestawie SDK platformy .NET obsługują uwzględnienie typów geoprzestrzennych w wyrażeniach zapytań. Ponadto zestaw SDK zawiera metody rozszerzeń mapowane na równoważne wbudowane funkcje:
Metoda rozszerzenia | Wbudowana funkcja |
---|---|
Distance() |
ST_DISTANCE |
Intersects() |
ST_INTERSECTS |
IsValid() |
ST_ISVALID |
IsValidDetailed() |
ST_ISVALIDDETAILED |
Within() |
ST_WITHIN |
Otwórz plik Program.cs.
Region
Pobierz element z kontenera z unikatowym identyfikatorem1000
i zapisz go w zmiennej o nazwieregion
.Region region = await container.ReadItemAsync<Region>("1000", new PartitionKey("business-region"));
Container.GetItemLinqQueryable<>
Użyj metody , aby uzyskać zapytanie LINQ i skompiluj zapytanie LINQ płynnie, wykonując następujące trzy akcje:Queryable.Where<>
Użyj metody rozszerzenia, aby filtrować tylko elementy o odpowiednikucategory
"business-office"
.Użyj
Queryable.Where<>
ponownie, aby filtrować tylko do lokalizacji we właściwości zmiennejlocation
region
przy użyciu poleceniaGeometry.Within()
.Przetłumacz wyrażenie LINQ na iterator kanału informacyjnego przy użyciu polecenia
CosmosLinqExtensions.ToFeedIterator<>
.
var regionIterator = container.GetItemLinqQueryable<Office>() .Where(o => o.category == "business-office") .Where(o => o.location.Within(region.location)) .ToFeedIterator<Office>();
Ważne
W tym przykładzie właściwość lokalizacji biura ma punkt, a właściwość lokalizacji regionu ma wielokąt.
ST_WITHIN
Określa, czy punkt biura znajduje się w obrębie wielokąta regionu.Użyj kombinacji pętli while i foreach, aby iterować wszystkie wyniki na każdej stronie wyników. Wyprowadź każdy wynik do konsoli.
while (regionIterator.HasMoreResults) { var response = await regionIterator.ReadNextAsync(); foreach (var office in response) { Console.WriteLine($"[IN REGION]\t{office}"); } }
Zapisz plik Program.cs.
Uruchom aplikację po raz ostatni w terminalu przy użyciu polecenia
dotnet run
. Zwróć uwagę, że dane wyjściowe zawierają teraz wyniki drugiego zapytania opartego na linQ.dotnet run
[IN REGION] Office { id = 0001, name = Headquarters, location = Microsoft.Azure.Cosmos.Spatial.Point, category = business-office }
Czyszczenie zasobów
Po ukończeniu tego przewodnika usuń bazę danych.
Otwórz terminal i utwórz zmienną powłoki dla nazwy konta i grupy zasobów.
# Variable for resource group name resourceGroupName="<name-of-your-resource-group>" # Variable for account name accountName="<name-of-your-account>"
Użyj polecenia
az cosmosdb sql database delete
, aby usunąć bazę danych.az cosmosdb sql database delete \ --resource-group "<resource-group-name>" \ --account-name "<nosql-account-name>" \ --name "cosmicworks"