Прочитать на английском

Поделиться через


Индексирование и запрос данных расположения GeoJSON в Azure Cosmos DB для NoSQL

ОБЛАСТЬ ПРИМЕНЕНИЯ: NoSQL

Геопространственные данные в Azure Cosmos DB для NoSQL позволяют хранить сведения о расположении и выполнять общие запросы, включая не только следующие:

  • Определение нахождения местоположения в границах заданной области
  • Измерение расстояния между двумя расположениями
  • Определение того, пересекается ли путь с местом или областью

В этом руководстве описывается процесс создания геопространственных данных, индексирования данных и последующего запроса данных в контейнере.

Требования

Создание политики контейнера и индексирования

Все контейнеры включают политику индексирования по умолчанию, которая успешно индексирует геопространственные данные. Чтобы создать настраиваемую политику индексирования, создайте учетную запись и укажите JSON-файл с конфигурацией политики. В этом разделе для только что созданного контейнера используется настраиваемый пространственный индекс.

  1. Откройте окно терминала.

  2. Создайте переменную оболочки для имени учетной записи Azure Cosmos DB для NoSQL и группы ресурсов.

    # Variable for resource group name
    resourceGroupName="<name-of-your-resource-group>"
    
    # Variable for account name
    accountName="<name-of-your-account>"
    
  3. Создайте новую базу данных с именем cosmicworks с помощью az cosmosdb sql database create.

    az cosmosdb sql database create \
        --resource-group "<resource-group-name>" \
        --account-name "<nosql-account-name>" \
        --name "cosmicworks" \
        --throughput 400
    
  4. Создайте файл JSON с именем index-policy.json и добавьте следующий объект JSON в файл.

    {
      "indexingMode": "consistent",
      "automatic": true,
      "includedPaths": [
        {
          "path": "/*"
        }
      ],
      "excludedPaths": [
        {
          "path": "/\"_etag\"/?"
        }
      ],
      "spatialIndexes": [
        {
          "path": "/location/*",
          "types": [
            "Point",
            "Polygon"
          ]
        }
      ]
    }
    
  5. Используйте az cosmosdb sql container create для создания нового контейнера с именем locations с путем ключа раздела /region.

    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
    
  6. Наконец, получите конечную точку для вашей учетной записи с помощью az cosmosdb show, используя запрос JMESPath.

    az cosmosdb show \
        --resource-group "<resource-group-name>" \
        --name "<nosql-account-name>" \
        --query "documentEndpoint"
    
  7. Запишите конечную точку учетной записи, так как это потребуется в следующем разделе.

Создание консольного приложения пакета SDK для .NET

Пакет SDK для .NET для Azure Cosmos DB для NoSQL предоставляет классы для распространенных объектов GeoJSON. Используйте этот пакет SDK для упрощения процесса добавления географических объектов в контейнер.

  1. Откройте терминал в пустом каталоге.

  2. Создайте новое приложение .NET, используя команду dotnet new с шаблоном console.

    dotnet new console
    
  3. Microsoft.Azure.Cosmos Импортируйте пакет NuGet с помощью dotnet add package команды.

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

    Предупреждение

    Entity Framework в настоящее время не поддерживает пространственные данные в Azure Cosmos DB для NoSQL. Используйте один из SDK Azure Cosmos DB для NoSQL, чтобы обеспечить строго типизированную поддержку GeoJSON.

  4. Azure.Identity Импортируйте пакет NuGet.

    dotnet add package Azure.Identity --version 1.*
    
  5. Создайте проект с помощью команды dotnet build.

    dotnet build
    
  6. Откройте интегрированную среду разработки (IDE) в том же каталоге, что и консольное приложение .NET.

  7. Откройте созданный файл Program.cs и удалите существующий код. Добавьте директивы using для пространств имен Microsoft.Azure.Cosmos, Microsoft.Azure.Cosmos.Linq, и Microsoft.Azure.Cosmos.Spatial.

    using Microsoft.Azure.Cosmos;
    using Microsoft.Azure.Cosmos.Linq;
    using Microsoft.Azure.Cosmos.Spatial;
    
  8. Добавьте еще одну директиву using для пространства имен Azure.Identity.

    using Azure.Identity;
    
  9. Создайте новую переменную с именем credential типа DefaultAzureCredential.

    DefaultAzureCredential credential = new();
    
  10. Создайте строковую переменную с именем endpoint, которая будет использоваться для конечной точки учетной записи Azure Cosmos DB с поддержкой NoSQL.

    string endpoint = "<nosql-account-endpoint>";
    
  11. Создайте новый экземпляр класса CosmosClient, передав connectionString, и оберните его в оператор using.

    using CosmosClient client = new (connectionString);
    
  12. Получите ссылку на ранее созданный контейнер (cosmicworks/locations) в учетной записи Azure Cosmos DB для NoSQL с помощью CosmosClient.GetDatabase , а затем Database.GetContainer. Сохраните результат в переменной под названием container.

    var container = client.GetDatabase("cosmicworks").GetContainer("locations");
    
  13. Сохраните файл Program.cs.

Добавление геопространственных данных

Пакет SDK для .NET включает несколько типов в пространстве имен Microsoft.Azure.Cosmos.Spatial для представления общих объектов GeoJSON. Эти типы упрощают процесс добавления новых сведений о расположении в элементы в контейнере.

  1. Создайте файл с именем Office.cs. В файле добавьте директиву using для Microsoft.Azure.Cosmos.Spatial, а затем создайте Officeтип записи со следующими свойствами:

    Тип Описание Значение по умолчанию
    id string Уникальный идентификатор
    name string Имя офиса
    расположение Point Географическая точка GeoJSON
    категория string Значение ключа раздела business-office
    using Microsoft.Azure.Cosmos.Spatial;
    
    public record Office(
        string id,
        string name,
        Point location,
        string category = "business-office"
    );
    

    Примечание

    Эта запись включает Point свойство, представляющее определенную позицию в GeoJSON. Дополнительные сведения см. в разделе GeoJSON Point.

  2. Создайте другой файл с именем Region.cs. Добавьте еще один тип записи с именем Region и следующими свойствами:

    Тип Описание Значение по умолчанию
    id string Уникальный идентификатор
    name string Имя офиса
    расположение Polygon Географическая фигура GeoJSON
    категория string Значение ключа раздела business-region
    using Microsoft.Azure.Cosmos.Spatial;
    
    public record Region(
        string id,
        string name,
        Polygon location,
        string category = "business-region"
    );
    

    Примечание

    Эта запись включает Polygon свойство, представляющее фигуру, состоящую из линий, нарисованных между несколькими точками в GeoJSON. Дополнительные сведения см. в разделе GeoJSON Polygon.

  3. Создайте другой файл с именем Result.cs. Добавьте тип Result записи с этими двумя свойствами:

    Тип Описание
    name string Имя соответствующего результата
    distanceKilometers decimal Расстояние в километрах
    public record Result(
        string name,
        decimal distanceKilometers
    );
    
  4. Сохраните файлы Office.cs, Region.cs и Result.cs .

  5. Откройте опять файл Program.cs.

  6. Создайте новую Polygon переменную с именем 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. Создайте новую переменную Region с именем mainCampusRegion с использованием многоугольника, уникального идентификатора 1000, и имени Main Campus.

    Region mainCampusRegion = new ("1000", "Main Campus", mainCampusPolygon);
    
  8. Используйте Container.UpsertItemAsync для добавления региона в контейнер. Напишите сведения о регионе в консоль.

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

    Совет

    В этом руководстве используется upsert вместо вставки , чтобы можно было выполнять скрипт несколько раз, не вызывая конфликт между уникальными идентификаторами. Дополнительные сведения об операциях upsert см. в статье о создании элементов.

  9. Создайте новую Point переменную с именем headquartersPoint. Используйте ту переменную для создания новой переменной Office, используя точку, уникальный идентификатор 0001 и имя Headquarters.

    Point headquartersPoint = new (-122.12827, 47.63980);
    Office headquartersOffice = new ("0001", "Headquarters", headquartersPoint);
    
  10. Создайте другую Point переменную с именем researchPoint. Используйте ту переменную, чтобы создать другую Office переменную researchOffice с помощью соответствующей точки, уникального идентификатора 0002и имени Research and Development.

    Point researchPoint = new (-96.84369, 46.81298);
    Office researchOffice = new ("0002", "Research and Development", researchPoint);
    
  11. Создайте TransactionalBatch, чтобы выполнить upsert обеих Office переменных в рамках одной транзакции. Затем напишите сведения о обоих офисах в консоль.

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

    Примечание

    Дополнительные сведения о транзакциях см. в разделе транзакционные пакетные операции.

  12. Сохраните файл Program.cs.

  13. Запустите приложение в терминале с помощью dotnet run. Обратите внимание, что выходные данные запуска приложения содержат сведения о трех только что созданных элементах.

    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 }
    

Запрос геопространственных данных с помощью запроса NoSQL

Типы в Microsoft.Azure.Cosmos.Spatial пространстве имен можно использовать в качестве входных данных для параметризованного запроса NoSQL для использования встроенных функций, таких как ST_DISTANCE.

  1. Откройте файл Program.cs.

  2. Создайте новую переменную string, названную nosql, которая будет использоваться в этом разделе для измерения расстояния между точками.

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

    Совет

    Этот запрос помещает геопространственную функцию в вложенный запрос, чтобы упростить процесс повторного использования уже вычисленного значения несколько раз в SELECT и WHERE предложениях.

  3. Создайте новую QueryDefinition переменную с именем query с помощью переменной nosqlString в качестве параметра. Затем несколько раз используйте QueryDefinition.WithParameter метод fluent, чтобы добавить эти параметры в запрос:

    Значение
    @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. Создайте новый итератор, используя Container.GetItemQueryIterator<>, универсальный тип Result и переменную query. Затем используйте сочетание цикла while и цикла foreach, для перебора всех результатов на каждой странице результатов. Выводит каждый результат в консоль.

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

    Примечание

    Дополнительные сведения о перечислении результатов запроса см. в разделе "Элементы запроса".

  5. Сохраните файл Program.cs.

  6. Снова запустите приложение в терминале с помощью dotnet run. Обратите внимание, что выходные данные теперь включают результаты запроса.

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

Запрос геопространственных данных с помощью LINQ

Функции LINQ to NoSQL в пакете SDK для .NET поддерживают включение геопространственных типов в выражения запроса. Кроме того, пакет SDK включает методы расширения, которые сопоставляют с эквивалентными встроенными функциями:

Метод расширения Встроенная функция
Distance() ST_DISTANCE
Intersects() ST_INTERSECTS
IsValid() ST_ISVALID
IsValidDetailed() ST_ISVALIDDETAILED
Within() ST_WITHIN
  1. Откройте файл Program.cs.

  2. Region Извлеките элемент из контейнера с уникальным идентификатором 1000 и сохраните его в переменной с именемregion.

    Region region = await container.ReadItemAsync<Region>("1000", new PartitionKey("business-region"));
    
  3. Используйте метод Container.GetItemLinqQueryable<>, чтобы получить объект LINQ queryable, и стройте запрос LINQ последовательно, выполняя следующие три действия:

    1. Queryable.Where<> Используйте метод расширения, чтобы отфильтровать только элементы с эквивалентом category"business-office".

    2. Используйте Queryable.Where<> еще раз, чтобы отфильтровать только расположения в свойстве location переменной region с помощью Geometry.Within().

    3. Переведите выражение LINQ в итератор потока с помощью CosmosLinqExtensions.ToFeedIterator<>.

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

    Важно!

    В этом примере местоположение офиса представлено точкой, а местоположение региона представлено многоугольником. ST_WITHIN определяет, находится ли точка офиса в многоугольнике региона.

  4. Используйте сочетание цикла while и цикла foreach, чтобы перебирать все результаты на каждой странице. Выводит каждый результат в консоль.

    while (regionIterator.HasMoreResults)
    {
        var response = await regionIterator.ReadNextAsync();
        foreach (var office in response)
        {
            Console.WriteLine($"[IN REGION]\t{office}");
        }
    }
    
  5. Сохраните файл Program.cs.

  6. Запустите приложение в последний раз в терминале с помощью dotnet run. Обратите внимание, что выходные данные теперь включают результаты второго запроса на основе LINQ.

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

Очистка ресурсов

Удалите базу данных после завершения работы с этим руководством.

  1. Откройте терминал и создайте переменную оболочки для имени учетной записи и группы ресурсов.

    # Variable for resource group name
    resourceGroupName="<name-of-your-resource-group>"
    
    # Variable for account name
    accountName="<name-of-your-account>"
    
  2. Используется az cosmosdb sql database delete для удаления базы данных.

    az cosmosdb sql database delete \
        --resource-group "<resource-group-name>" \
        --account-name "<nosql-account-name>" \
        --name "cosmicworks"
    

Следующие шаги


Дополнительные ресурсы

Обучение

Модуль

Внедрение Azure Cosmos DB для операций работы с точками входа в NoSQL - Training

Написание кода для создания, чтения, обновления и удаления элементов в Azure Cosmos DB для NoSQL.

Сертификация

Сертификация Майкрософт: специальность "Разработчик Azure Cosmos DB" - Certifications

Создавайте эффективные запросы, создавайте политики индексирования, управляйте и подготавливайте ресурсы в API SQL и пакете SDK с помощью Microsoft Azure Cosmos DB.