Индексирование и запрос данных расположения GeoJSON в Azure Cosmos DB для NoSQL
Статья
07.10.2024
ОБЛАСТЬ ПРИМЕНЕНИЯ: NoSQL
Геопространственные данные в Azure Cosmos DB для NoSQL позволяют хранить сведения о расположении и выполнять общие запросы, включая не только следующие:
Определение нахождения местоположения в границах заданной области
Измерение расстояния между двумя расположениями
Определение того, пересекается ли путь с местом или областью
В этом руководстве описывается процесс создания геопространственных данных, индексирования данных и последующего запроса данных в контейнере.
Требования
Существующая учетная запись Azure Cosmos DB для NoSQL.
Если вы используете локальную установку, войдите в Azure CLI с помощью az login команды.
Создание политики контейнера и индексирования
Все контейнеры включают политику индексирования по умолчанию, которая успешно индексирует геопространственные данные. Чтобы создать настраиваемую политику индексирования, создайте учетную запись и укажите JSON-файл с конфигурацией политики. В этом разделе для только что созданного контейнера используется настраиваемый пространственный индекс.
Откройте окно терминала.
Создайте переменную оболочки для имени учетной записи Azure Cosmos DB для NoSQL и группы ресурсов.
# Variable for resource group name
resourceGroupName="<name-of-your-resource-group>"
# Variable for account name
accountName="<name-of-your-account>"
Наконец, получите конечную точку для вашей учетной записи с помощью az cosmosdb show, используя запрос JMESPath.
az cosmosdb show \
--resource-group "<resource-group-name>" \
--name "<nosql-account-name>" \
--query "documentEndpoint"
Запишите конечную точку учетной записи, так как это потребуется в следующем разделе.
Создание консольного приложения пакета SDK для .NET
Пакет SDK для .NET для Azure Cosmos DB для NoSQL предоставляет классы для распространенных объектов GeoJSON. Используйте этот пакет SDK для упрощения процесса добавления географических объектов в контейнер.
Откройте терминал в пустом каталоге.
Создайте новое приложение .NET, используя команду dotnet new с шаблоном console.
Entity Framework в настоящее время не поддерживает пространственные данные в Azure Cosmos DB для NoSQL. Используйте один из SDK Azure Cosmos DB для NoSQL, чтобы обеспечить строго типизированную поддержку GeoJSON.
Откройте интегрированную среду разработки (IDE) в том же каталоге, что и консольное приложение .NET.
Откройте созданный файл 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;
Добавьте еще одну директиву using для пространства имен Azure.Identity.
Создайте строковую переменную с именем endpoint, которая будет использоваться для конечной точки учетной записи Azure Cosmos DB с поддержкой NoSQL.
string endpoint = "<nosql-account-endpoint>";
Создайте новый экземпляр класса CosmosClient, передав connectionString, и оберните его в оператор using.
using CosmosClient client = new (connectionString);
Получите ссылку на ранее созданный контейнер (cosmicworks/locations) в учетной записи Azure Cosmos DB для NoSQL с помощью CosmosClient.GetDatabase , а затем Database.GetContainer. Сохраните результат в переменной под названием container.
var container = client.GetDatabase("cosmicworks").GetContainer("locations");
Сохраните файл Program.cs.
Добавление геопространственных данных
Пакет SDK для .NET включает несколько типов в пространстве имен Microsoft.Azure.Cosmos.Spatial для представления общих объектов GeoJSON. Эти типы упрощают процесс добавления новых сведений о расположении в элементы в контейнере.
Создайте файл с именем 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.
Создайте другой файл с именем 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.
Создайте другой файл с именем Result.cs. Добавьте тип Result записи с этими двумя свойствами:
Тип
Описание
name
string
Имя соответствующего результата
distanceKilometers
decimal
Расстояние в километрах
public record Result(
string name,
decimal distanceKilometers
);
Сохраните файлы Office.cs, Region.cs и Result.cs .
Откройте опять файл Program.cs.
Создайте новую 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),
})
}
);
Создайте новую переменную Region с именем mainCampusRegion с использованием многоугольника, уникального идентификатора 1000, и имени Main Campus.
Region mainCampusRegion = new ("1000", "Main Campus", mainCampusPolygon);
Используйте Container.UpsertItemAsync для добавления региона в контейнер. Напишите сведения о регионе в консоль.
В этом руководстве используется upsert вместо вставки , чтобы можно было выполнять скрипт несколько раз, не вызывая конфликт между уникальными идентификаторами. Дополнительные сведения об операциях upsert см. в статье о создании элементов.
Создайте новую Point переменную с именем headquartersPoint. Используйте ту переменную для создания новой переменной Office, используя точку, уникальный идентификатор 0001 и имя Headquarters.
Point headquartersPoint = new (-122.12827, 47.63980);
Office headquartersOffice = new ("0001", "Headquarters", headquartersPoint);
Создайте другую Point переменную с именем researchPoint. Используйте ту переменную, чтобы создать другую Office переменную researchOffice с помощью соответствующей точки, уникального идентификатора 0002и имени Research and Development.
Point researchPoint = new (-96.84369, 46.81298);
Office researchOffice = new ("0002", "Research and Development", researchPoint);
Создайте TransactionalBatch, чтобы выполнить upsert обеих Office переменных в рамках одной транзакции. Затем напишите сведения о обоих офисах в консоль.
Запустите приложение в терминале с помощью 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.
Откройте файл Program.cs.
Создайте новую переменную 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 предложениях.
Создайте новую 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));
Создайте новый итератор, используя 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}");
}
}
Примечание
Дополнительные сведения о перечислении результатов запроса см. в разделе "Элементы запроса".
Сохраните файл Program.cs.
Снова запустите приложение в терминале с помощью 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 включает методы расширения, которые сопоставляют с эквивалентными встроенными функциями:
Region Извлеките элемент из контейнера с уникальным идентификатором 1000 и сохраните его в переменной с именемregion.
Region region = await container.ReadItemAsync<Region>("1000", new PartitionKey("business-region"));
Используйте метод Container.GetItemLinqQueryable<>, чтобы получить объект LINQ queryable, и стройте запрос LINQ последовательно, выполняя следующие три действия:
Queryable.Where<> Используйте метод расширения, чтобы отфильтровать только элементы с эквивалентом category"business-office".
Используйте Queryable.Where<> еще раз, чтобы отфильтровать только расположения в свойстве location переменной region с помощью Geometry.Within().
В этом примере местоположение офиса представлено точкой, а местоположение региона представлено многоугольником.
ST_WITHIN определяет, находится ли точка офиса в многоугольнике региона.
Используйте сочетание цикла while и цикла foreach, чтобы перебирать все результаты на каждой странице. Выводит каждый результат в консоль.
while (regionIterator.HasMoreResults)
{
var response = await regionIterator.ReadNextAsync();
foreach (var office in response)
{
Console.WriteLine($"[IN REGION]\t{office}");
}
}
Сохраните файл Program.cs.
Запустите приложение в последний раз в терминале с помощью dotnet run. Обратите внимание, что выходные данные теперь включают результаты второго запроса на основе LINQ.
dotnet run
[IN REGION] Office { id = 0001, name = Headquarters, location = Microsoft.Azure.Cosmos.Spatial.Point, category = business-office }
Очистка ресурсов
Удалите базу данных после завершения работы с этим руководством.
Откройте терминал и создайте переменную оболочки для имени учетной записи и группы ресурсов.
# Variable for resource group name
resourceGroupName="<name-of-your-resource-group>"
# Variable for account name
accountName="<name-of-your-account>"
Создавайте эффективные запросы, создавайте политики индексирования, управляйте и подготавливайте ресурсы в API SQL и пакете SDK с помощью Microsoft Azure Cosmos DB.