Indeksowanie i wykonywanie zapytań względem 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 $resourceGroupName \ --account-name $accountName \ --name "cosmicworks" \ --throughput 400
Utwórz nowy plik JSON o nazwie index-policy.json i dodaj do pliku następujący obiekt JSON.
{ "indexingMode": "consistent", "automatic": true, "includedPaths": [ { "path": "/*" } ], "excludedPaths": [ { "path": "/\"_etag\"/?" } ], "spatialIndexes": [ { "path": "/location/*", "types": [ "Point", "Polygon" ] } ] }
Użyj polecenia
az cosmosdb sql container create
, aby utworzyć nowy kontener o nazwielocations
ze ścieżką klucza partycji ./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
Pobierz podstawowe parametry połączenia dla konta przy użyciu polecenia
az cosmosdb keys list
.az cosmosdb keys list \ --resource-group $resourceGroupName \ --name $accountName \ --type "connection-strings" \ --query "connectionStrings[?keyKind == \`Primary\`].connectionString" \ --output tsv
Porada
Aby wyświetlić wszystkie możliwe parametry połączenia dla konta, użyj polecenia
az cosmosdb keys list --resource-group $resourceGroupName --name $accountName --type "connection-strings"
.Zapisz parametry połączenia. To poświadczenie będzie używane w dalszej części tego przewodnika.
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 pakiet NuGet Microsoft.Azure.Cosmos przy użyciu
dotnet add package
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 formatu GeoJSON.
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 zmienną ciągu o nazwie *
connectionString
z parametrami połączenia zarejestrowanymi wcześniej w tym przewodniku.string connectionString = "<your-account-connection-string>"
Utwórz nowe wystąpienie klasy przekazującej
CosmosClient
connectionString
i opakowujące ją 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:Typ Opis Wartość domyślna id string
Unikatowy identyfikator Nazwa string
Nazwa biura Lokalizacji Point
GeoJSON — punkt geograficzny Kategorii 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
Point
właściwość reprezentującą 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
Region
z następującymi właściwościami:Typ Opis Wartość domyślna id string
Unikatowy identyfikator Nazwa string
Nazwa biura Lokalizacji Polygon
Kształt geograficzny GeoJSON Kategorii 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(GeoJSON Polygon).Utwórz kolejny nowy plik o nazwie Result.cs. Dodaj typ rekordu o nazwie
Result
z tymi dwiema właściwościami:Typ Opis Nazwa 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 polecenia
Container.UpsertItemAsync
, aby dodać region do kontenera. Zapisz informacje o regionie w konsoli programu .await container.UpsertItemAsync<Region>(mainCampusRegion); Console.WriteLine($"[UPSERT ITEM]\t{mainCampusRegion}");
Porada
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 funkcję
TransactionalBatch
upsert obuOffice
zmiennych jako pojedynczej transakcji. Następnie zapisz informacje o obu biurach w konsoli.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ą być używane 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 służy 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. Dane wyjściowe każdego wyniku 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
Funkcja LINQ to NoSQL w zestawie SDK platformy .NET obsługuje m.in. typy geoprzestrzenne w wyrażeniach zapytania. 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 z równoważną wartościącategory
"business-office"
.Użyj
Queryable.Where<>
ponownie, aby filtrować tylko lokalizacje 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. Dane wyjściowe każdego wyniku 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
Usuń bazę danych po ukończeniu tego przewodnika.
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
az cosmosdb sql database delete
polecenia , aby usunąć bazę danych.az cosmosdb sql database delete \ --resource-group $resourceGroupName \ --account-name $accountName \ --name "cosmicworks"