Share 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 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

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.

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

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

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

  4. Skapa projektet med dotnet build kommandot .

    dotnet build
    
  5. Öppna den integrerade utvecklarmiljö (IDE) som du väljer i samma katalog som ditt .NET-konsolprogram.

  6. Ö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.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 anslutningssträngen 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 Officeposttyp 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.

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

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

    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.

  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 för att öka 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}");
    

    Anteckning

    Mer information om transaktioner finns i transaktionella batchå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
    ";
    

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

    Anteckning

    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 .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
  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 dessa 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 kontorsplatsegenskapen en punkt och regionens platsegenskap har en polygon. ST_WITHIN avgör om platsen för kontoret ligger inom regionens polygon.

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