Indexování a dotazování dat o poloze GeoJSON ve službě Azure Cosmos DB for NoSQL

PLATÍ PRO: NoSQL

Geoprostorová data ve službě Azure Cosmos DB for NoSQL umožňují ukládat informace o poloze a provádět běžné dotazy, mezi které mimo jiné patří:

  • Zjištění, jestli se umístění nachází v definované oblasti
  • Měření vzdálenosti mezi dvěma umístěními
  • Určení, jestli se cesta protíná s umístěním nebo oblastí

Tento průvodce vás provede procesem vytváření geoprostorových dat, indexování dat a následného dotazování dat v kontejneru.

Požadavky

Vytvoření zásad kontejneru a indexování

Všechny kontejnery obsahují výchozí zásady indexování, které úspěšně indexují geoprostorová data. Pokud chcete vytvořit vlastní zásady indexování, vytvořte účet a zadejte soubor JSON s konfigurací zásad. V této části se pro nově vytvořený kontejner použije vlastní prostorový index.

  1. Otevřete terminál.

  2. Vytvořte proměnnou prostředí pro název účtu a skupiny prostředků 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>"
    
  3. Vytvořte novou databázi s názvem cosmicworks pomocí az cosmosdb sql database create.

    az cosmosdb sql database create \
        --resource-group $resourceGroupName \
        --account-name $accountName \
        --name "cosmicworks" \
        --throughput 400
    
  4. Vytvořte nový soubor JSON s názvem index-policy.json a přidejte do souboru následující objekt JSON.

    {
      "indexingMode": "consistent",
      "automatic": true,
      "includedPaths": [
        {
          "path": "/*"
        }
      ],
      "excludedPaths": [
        {
          "path": "/\"_etag\"/?"
        }
      ],
      "spatialIndexes": [
        {
          "path": "/location/*",
          "types": [
            "Point",
            "Polygon"
          ]
        }
      ]
    }
    
  5. Slouží az cosmosdb sql container create k vytvoření nového kontejneru s klíčem locations oddílu /regions cestou .

    az cosmosdb sql container create \
        --resource-group $resourceGroupName \
        --account-name $accountName \
        --database-name "cosmicworks" \
        --name "locations" \
        --partition-key-path "/category" \
        --idx @index-policy.json
    
  6. Načtěte primární připojovací řetězec pro účet pomocí az cosmosdb keys list.

    az cosmosdb keys list \
        --resource-group $resourceGroupName \
        --name $accountName \
        --type "connection-strings" \
        --query "connectionStrings[?keyKind == \`Primary\`].connectionString" \
        --output tsv
    

    Tip

    Pokud chcete zobrazit všechny možné připojovací řetězce pro účet, použijte az cosmosdb keys list --resource-group $resourceGroupName --name $accountName --type "connection-strings".

  7. Zaznamenejte připojovací řetězec. Tyto přihlašovací údaje použijete dále v této příručce.

Vytvoření konzolové aplikace sady .NET SDK

Sada .NET SDK pro Azure Cosmos DB for NoSQL poskytuje třídy pro běžné objekty GeoJSON. Pomocí této sady SDK můžete zjednodušit proces přidávání geografických objektů do kontejneru.

  1. Otevřete terminál v prázdném adresáři.

  2. Vytvořte novou aplikaci .NET pomocí dotnet new příkazu se šablonou konzoly .

    dotnet new console
    
  3. Importujte balíček NuGet Microsoft.Azure.Cosmos pomocí dotnet add package příkazu .

    dotnet add package Microsoft.Azure.Cosmos --version 3.*
    

    Upozornění

    Entity Framework v současné době ve službě Azure Cosmos DB for NoSQL neobsahuje prostorová data. Použijte některou ze sad Azure Cosmos DB for NoSQL SDK pro podporu GeoJSON se silnými typy.

  4. Sestavte projekt pomocí dotnet build příkazu .

    dotnet build
    
  5. Otevřete integrované vývojové prostředí (IDE) podle svého výběru ve stejném adresáři jako konzolová aplikace .NET.

  6. Otevřete nově vytvořený soubor Program.cs a odstraňte veškerý existující kód. Přidejte direktivyMicrosoft.Azure.Cosmosusing pro obory názvů , Microsoft.Azure.Cosmos.LinqaMicrosoft.Azure.Cosmos.Spatial .

    using Microsoft.Azure.Cosmos;
    using Microsoft.Azure.Cosmos.Linq;
    using Microsoft.Azure.Cosmos.Spatial;
    
  7. Přidejte řetězcovou proměnnou s názvem *connectionString s připojovacím řetězcem, který jste si poznamenali dříve v této příručce.

    string connectionString = "<your-account-connection-string>"
    
  8. Vytvořte novou instanci CosmosClient třídy předávající connectionString a zabalte ji do příkazu using.

    using CosmosClient client = new (connectionString);
    
  9. Pomocí a pak Database.GetContainernačtěte odkaz na dříve vytvořený kontejner (cosmicworks/locations) v účtu Azure Cosmos DB for NoSQL.CosmosClient.GetDatabase Uložte výsledek do proměnné s názvem container.

    var container = client.GetDatabase("cosmicworks").GetContainer("locations");
    
  10. Uložte soubor Program.cs.

Přidání geoprostorových dat

Sada .NET SDK obsahuje více typů v Microsoft.Azure.Cosmos.Spatial oboru názvů, které představují běžné objekty GeoJSON. Tyto typy zjednodušují proces přidávání informací o novém umístění k položkám v kontejneru.

  1. Vytvořte nový soubor s názvem Office.cs. Do souboru přidejte direktivu Microsoft.Azure.Cosmos.Spatial using a pak vytvořte typ záznamuOffice s těmito vlastnostmi:

    Typ Description Výchozí hodnota
    id string Jedinečný identifikátor
    Jméno string Název kanceláře
    Umístění Point Geografický bod GeoJSON
    Kategorie string Hodnota klíče oddílu business-office
    using Microsoft.Azure.Cosmos.Spatial;
    
    public record Office(
        string id,
        string name,
        Point location,
        string category = "business-office"
    );
    

    Poznámka

    Tento záznam obsahuje Point vlastnost představující konkrétní pozici v GeoJSON. Další informace najdete v tématu GeoJSON Point.

  2. Vytvořte další nový soubor s názvem Region.cs. Přidejte další typ záznamu s názvem Region s těmito vlastnostmi:

    Typ Description Výchozí hodnota
    id string Jedinečný identifikátor
    Jméno string Název kanceláře
    Umístění Polygon Geografický obrazec GeoJSON
    Kategorie string Hodnota klíče oddílu business-region
    using Microsoft.Azure.Cosmos.Spatial;
    
    public record Region(
        string id,
        string name,
        Polygon location,
        string category = "business-region"
    );
    

    Poznámka

    Tento záznam obsahuje Polygon vlastnost představující obrazec složený z čar nakreslených mezi několika umístěními v GeoJSON. Další informace najdete v tématu GeoJSON Polygon.

  3. Vytvořte další nový soubor s názvem Result.cs. Přidejte typ záznamu s názvem Result s těmito dvěma vlastnostmi:

    Typ Description
    Jméno string Název odpovídajícího výsledku
    vzdálenostKilometry decimal Vzdálenost v km
    public record Result(
        string name,
        decimal distanceKilometers
    );
    
  4. Uložte soubory Office.cs, Region.cs a Result.cs .

  5. Znovu otevřete soubor Program.cs .

  6. Vytvořte nový Polygon v proměnné s názvem mainCampusPolygon.

    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),
            })
        }
    );
    
  7. Vytvořte novou Region proměnnou s názvem mainCampusRegion pomocí mnohoúhelníku, jedinečného identifikátoru 1000a názvu Main Campus.

    Region mainCampusRegion = new ("1000", "Main Campus", mainCampusPolygon);
    
  8. Použijte Container.UpsertItemAsync k přidání oblasti do kontejneru. Zapište informace o oblasti do konzoly.

    await container.UpsertItemAsync<Region>(mainCampusRegion);
    Console.WriteLine($"[UPSERT ITEM]\t{mainCampusRegion}");
    

    Tip

    Tato příručka používá upsert místo vložení , takže skript můžete spustit vícekrát, aniž by došlo ke konfliktu mezi jedinečnými identifikátory. Další informace o operacích upsert najdete v tématu Vytváření položek.

  9. Vytvořte novou Point proměnnou s názvem headquartersPoint. Tuto proměnnou použijte k vytvoření nové Office proměnné s názvem headquartersOffice point, jedinečný identifikátor 0001a název Headquarters.

    Point headquartersPoint = new (-122.12827, 47.63980);
    Office headquartersOffice = new ("0001", "Headquarters", headquartersPoint);
    
  10. Vytvořte další Point proměnnou s názvem researchPoint. Tuto proměnnou použijte k vytvoření další Office proměnné s názvem s použitím researchOffice odpovídajícího bodu, jedinečného identifikátoru 0002a názvu Research and Development.

    Point researchPoint = new (-96.84369, 46.81298);
    Office researchOffice = new ("0002", "Research and Development", researchPoint);
    
  11. Vytvořte k TransactionalBatch upsertu obou Office proměnných jako jednu transakci. Pak na konzolu zapište informace o obou pobočkách.

    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}");
    

    Poznámka

    Další informace o transakcích najdete v tématu Transakční dávkové operace.

  12. Uložte soubor Program.cs.

  13. Spusťte aplikaci v terminálu pomocí příkazu dotnet run. Všimněte si, že výstup spuštění aplikace obsahuje informace o třech nově vytvořených položkách.

    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 }
    

Dotazování geoprostorových dat pomocí dotazu NoSQL

Typy v Microsoft.Azure.Cosmos.Spatial oboru názvů je možné použít jako vstupy parametrizovaného dotazu NoSQL pro použití integrovaných funkcí, jako je ST_DISTANCE.

  1. Otevřete soubor Program.cs .

  2. Vytvoření nové string proměnné s názvem nosql s dotazem se použije v této části k měření vzdálenosti mezi body.

    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
    ";
    

    Tip

    Tento dotaz umístí geoprostorovou funkci do poddotazu , aby se zjednodušil proces opakovaného opakovaného použití již vypočítané hodnoty v SELECT klauzulích a WHERE .

  3. Vytvořte novou QueryDefinition proměnnou s názvem query s nosqlString použitím proměnné jako parametru. Pak několikrát použijte metodu QueryDefinition.WithParameter fluent a přidejte do dotazu tyto parametry:

    Hodnota
    @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));
    
  4. Vytvořte nový iterátor pomocí Container.GetItemQueryIterator<>, Result obecného typu a query proměnné . Pak použijte kombinaci smyčky while a foreach k iteraci všech výsledků na každé stránce výsledků. Vypíše každý výsledek do konzoly.

    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}");
        }
    }
    

    Poznámka

    Další informace o výčtu výsledků dotazu najdete v tématu položky dotazu.

  5. Uložte soubor Program.cs.

  6. Spusťte aplikaci znovu v terminálu pomocí příkazu dotnet run. Všimněte si, že výstup teď obsahuje výsledky dotazu.

    dotnet run
    
    [DISTANCE KM]   Result { name = Headquarters, distanceKilometers = 3.34 }
    [DISTANCE KM]   Result { name = Research and Development, distanceKilometers = 1907.43 }
    

Dotazování geoprostorových dat pomocí LINQ

Funkce LINQ to NoSQL v sadě .NET SDK podporují zahrnutí geoprostorových typů do výrazů dotazu. Sada SDK navíc zahrnuje rozšiřující metody, které se mapuje na ekvivalentní integrované funkce:

Rozšiřující metoda Integrovaná funkce
Distance() ST_DISTANCE
Intersects() ST_INTERSECTS
IsValid() ST_ISVALID
IsValidDetailed() ST_ISVALIDDETAILED
Within() ST_WITHIN
  1. Otevřete soubor Program.cs .

  2. Region Načtěte položku z kontejneru s jedinečným identifikátorem 1000 a uložte ji do proměnné s názvem region.

    Region region = await container.ReadItemAsync<Region>("1000", new PartitionKey("business-region"));
    
  3. Použijte metodu Container.GetItemLinqQueryable<> k získání dotazovatelného LINQ a k plynulému sestavení dotazu LINQ provedením těchto tří akcí:

    1. Pomocí rozšiřující metody vyfiltrujte Queryable.Where<> pouze položky, které mají category ekvivalent ."business-office"

    2. Pomocí Queryable.Where<> příkazu znovu vyfiltrujte pouze umístění v rámci region vlastnosti proměnnélocation.Geometry.Within()

    3. Pomocí příkazu přeložte výraz LINQ na iterátor informačního kanálu CosmosLinqExtensions.ToFeedIterator<>.

    var regionIterator = container.GetItemLinqQueryable<Office>()
        .Where(o => o.category == "business-office")
        .Where(o => o.location.Within(region.location))
        .ToFeedIterator<Office>();
    

    Důležité

    V tomto příkladu má vlastnost umístění kanceláře bod a vlastnost umístění oblasti mnohoúhelník. ST_WITHIN určuje, zda se místo kanceláře nachází v polygonu oblasti.

  4. Pomocí kombinace smyčky while a foreach můžete iterovat všechny výsledky na každé stránce výsledků. Vypíše každý výsledek do konzoly.

    while (regionIterator.HasMoreResults)
    {
        var response = await regionIterator.ReadNextAsync();
        foreach (var office in response)
        {
            Console.WriteLine($"[IN REGION]\t{office}");
        }
    }
    
  5. Uložte soubor Program.cs.

  6. Spusťte aplikaci naposledy v terminálu pomocí příkazu dotnet run. Všimněte si, že výstup teď obsahuje výsledky druhého dotazu založeného na LINQ.

    dotnet run
    
    [IN REGION]     Office { id = 0001, name = Headquarters, location = Microsoft.Azure.Cosmos.Spatial.Point, category = business-office }
    

Vyčištění prostředků

Po dokončení této příručky odeberte databázi.

  1. Otevřete terminál a vytvořte proměnnou prostředí pro název vašeho účtu a skupiny prostředků.

    # Variable for resource group name
    resourceGroupName="<name-of-your-resource-group>"
    
    # Variable for account name
    accountName="<name-of-your-account>"
    
  2. Slouží az cosmosdb sql database delete k odebrání databáze.

    az cosmosdb sql database delete \
        --resource-group $resourceGroupName \
        --account-name $accountName \
        --name "cosmicworks"
    

Další kroky