Dela via


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

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.

  1. Öppna en terminal.

  2. 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>"
    
  3. 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
    
  4. 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"
          ]
        }
      ]
    }
    
  5. Använd az cosmosdb sql container create för att skapa en ny container med namnet locations med en partitionsnyckelsökväg /regionför .

    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. Hämta den primära niska veze för kontot med hjälp av az cosmosdb keys list.

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

    Dricks

    Om du vill se alla möjliga niska veze för ett konto använder du az cosmosdb keys list --resource-group $resourceGroupName --name $accountName --type "connection-strings".

  7. Registrera niska veze. 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 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.

  1. Öppna en terminal i en tom katalog.

  2. Skapa ett nytt .NET-program med hjälp dotnet new av kommandot med konsolmallen.

    dotnet new console
    
  3. Importera NuGet-paketet Microsoft.Azure.Cosmos med kommandot dotnet 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.

  4. Skapa projektet med dotnet build kommandot .

    dotnet build
    
  5. Öppna valfri integrerad utvecklarmiljö (IDE) i samma katalog som ditt .NET-konsolprogram.

  6. Ö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.Cosmosnamnrymderna , Microsoft.Azure.Cosmos.LinqochMicrosoft.Azure.Cosmos.Spatial .

    using Microsoft.Azure.Cosmos;
    using Microsoft.Azure.Cosmos.Linq;
    using Microsoft.Azure.Cosmos.Spatial;
    
  7. Lägg till en strängvariabel med namnet *connectionString med den niska veze som du registrerade tidigare i den här guiden.

    string connectionString = "<your-account-connection-string>"
    
  8. Skapa en ny instans av klassen som CosmosClient skickar in connectionString och omsluter den i en using-instruktion.

    using CosmosClient client = new (connectionString);
    
  9. Hämta en referens till den tidigare skapade containern (cosmicworks/locations) i Azure Cosmos DB för NoSQL-kontot med hjälp CosmosClient.GetDatabase av och sedan Database.GetContainer. Lagra resultatet i en variabel med namnet container.

    var container = client.GetDatabase("cosmicworks").GetContainer("locations");
    
  10. 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.

  1. 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 en Office 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.

  2. 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.

  3. 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
    );
    
  4. Spara filerna Office.cs, Region.cs och Result.cs.

  5. Öppna filen Program.cs igen.

  6. Skapa en ny Polygon i en variabel med namnet 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. Skapa en ny Region variabel med namnet mainCampusRegion med hjälp av polygonen, den unika identifieraren 1000och namnet Main Campus.

    Region mainCampusRegion = new ("1000", "Main Campus", mainCampusPolygon);
    
  8. 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.

  9. Skapa en ny Point variabel med namnet headquartersPoint. Använd variabeln för att skapa en ny Office variabel med namnet headquartersOffice med hjälp av punkten, den unika identifieraren 0001och namnet Headquarters.

    Point headquartersPoint = new (-122.12827, 47.63980);
    Office headquartersOffice = new ("0001", "Headquarters", headquartersPoint);
    
  10. Skapa en annan Point variabel med namnet researchPoint. Använd variabeln för att skapa en annan Office variabel med namnet researchOffice med hjälp av motsvarande punkt, den unika identifieraren 0002och namnet Research and Development.

    Point researchPoint = new (-96.84369, 46.81298);
    Office researchOffice = new ("0002", "Research and Development", researchPoint);
    
  11. Skapa en TransactionalBatch till upsert båda Office 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.

  12. Spara Program.cs-filen.

  13. 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.

  1. Öppna filen Program.cs .

  2. Skapa en ny string variabel med namnet nosql 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-satserna WHERE .

  3. Skapa en ny QueryDefinition variabel med namnet query med variabeln nosqlString som parameter. Använd QueryDefinition.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));
    
  4. Skapa en ny iterator med hjälp av Container.GetItemQueryIterator<>, den Result generiska typen och variabeln query . 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.

  5. Spara Program.cs-filen.

  6. 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
  1. Öppna filen Program.cs .

  2. Region Hämta objektet från containern med en unik identifierare för 1000 och lagra det i en variabel med namnet region.

    Region region = await container.ReadItemAsync<Region>("1000", new PartitionKey("business-region"));
    
  3. 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:

    1. Queryable.Where<> Använd tilläggsmetoden för att filtrera till endast objekt med motsvarande category "business-office".

    2. Använd Queryable.Where<> igen om du bara vill filtrera till platser i region variabelns location egenskap med hjälp av Geometry.Within().

    3. Ö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.

  4. 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}");
        }
    }
    
  5. Spara Program.cs-filen.

  6. 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.

  1. Ö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>"
    
  2. 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"
    

Nästa steg