Azure Cosmos DB for NoSQL에서 GeoJSON 위치 데이터 인덱싱 및 쿼리
적용 대상: NoSQL
Azure Cosmos DB for NoSQL의 지리 공간적 데이터를 사용하면 위치 정보를 저장하고, 다음을 포함하지만 이에 국한되지 않는 일반적인 쿼리를 수행할 수 있습니다.
- 위치가 정의된 영역 내에 있는지 확인
- 두 위치 사이의 거리 측정
- 경로가 위치 또는 영역과 교차하는지 확인
이 가이드에서는 지리 공간적 데이터를 만들고, 데이터를 인덱싱하고, 컨테이너의 데이터를 쿼리하는 프로세스를 안내합니다.
필수 조건
- 기존 Azure Cosmos DB API for NoSQL 계정.
- Azure 구독이 없는 경우 Azure Cosmos DB for NoSQL을 무료로 사용해 보세요.
- 기존 Azure 구독이 있는 경우 새 Azure Cosmos DB for NoSQL 계정을 만듭니다.
- 최신 버전의 .NET
- 최신 버전의 Azure CLI
- 로컬 설치를 사용하는 경우
az login
명령을 사용하여 Azure CLI에 로그인합니다.
- 로컬 설치를 사용하는 경우
컨테이너 및 인덱싱 정책 만들기
모든 컨테이너에는 지리 공간적 데이터를 성공적으로 인덱싱하는 기본 인덱싱 정책이 포함되어 있습니다. 사용자 지정된 인덱싱 정책을 만들려면 계정을 만들고 정책 구성이 포함된 JSON 파일을 지정합니다. 이 섹션에서는 사용자 지정 공간 인덱스가 새로 만든 컨테이너에 사용됩니다.
터미널을 엽니다.
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>"
az cosmosdb sql database create
를 사용하여cosmicworks
라는 새 데이터베이스를 만듭니다.az cosmosdb sql database create \ --resource-group "<resource-group-name>" \ --account-name "<nosql-account-name>" \ --name "cosmicworks" \ --throughput 400
index-policy.json이라는 새 JSON 파일을 만들고, 다음 JSON 개체를 파일에 추가합니다.
{ "indexingMode": "consistent", "automatic": true, "includedPaths": [ { "path": "/*" } ], "excludedPaths": [ { "path": "/\"_etag\"/?" } ], "spatialIndexes": [ { "path": "/location/*", "types": [ "Point", "Polygon" ] } ] }
az cosmosdb sql container create
를 사용하여 파티션 키 경로가/region
인locations
라는 새 컨테이너를 만듭니다.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
마지막으로 사용하는 계정의 계정 엔드포인트
az cosmosdb show
와 JMESPath 쿼리를 가져옵니다.az cosmosdb show \ --resource-group "<resource-group-name>" \ --name "<nosql-account-name>" \ --query "documentEndpoint"
다음 섹션에서 필요하므로 계정 엔드포인트를 기록합니다.
.NET SDK 콘솔 애플리케이션 만들기
Azure Cosmos DB for NoSQL용 .NET SDK는 일반적인 GeoJSON 개체에 대한 클래스를 제공합니다. 이 SDK를 사용하여 지리적 개체를 컨테이너에 추가하는 프로세스를 간소화합니다.
빈 디렉터리에서 터미널을 엽니다.
console 템플릿에서
dotnet new
명령을 사용하여 새 .NET 애플리케이션을 만듭니다.dotnet new console
Microsoft.Azure.Cosmos
명령을 사용하여 NuGet 패키지를 가져옵니다dotnet add package
.dotnet add package Microsoft.Azure.Cosmos --version 3.*
Warning
Entity Framework는 현재 Azure Cosmos DB for NoSQL의 공간 데이터를 지원하지 않습니다. 강력한 형식의 GeoJSON 지원을 위해 Azure Cosmos DB for NoSQL SDK 중 하나를 사용합니다.
Azure.Identity
NuGet 패키지를 가져옵니다.dotnet add package Azure.Identity --version 1.*
dotnet build
명령을 사용하여 프로젝트를 빌드합니다.dotnet build
.NET 콘솔 애플리케이션과 동일한 디렉터리에서 원하는 IDE(통합 개발자 환경)를 엽니다.
새로 만든 Program.cs 파일을 열고 기존 코드를 삭제합니다.
Microsoft.Azure.Cosmos
,Microsoft.Azure.Cosmos.Linq
및Microsoft.Azure.Cosmos.Spatial
네임스페이스에 대한 using 지시문을 추가합니다.using Microsoft.Azure.Cosmos; using Microsoft.Azure.Cosmos.Linq; using Microsoft.Azure.Cosmos.Spatial;
네임스페이스에 대한 다른 using 지시문을
Azure.Identity
추가합니다.using Azure.Identity;
DefaultAzureCredential
형식의credential
라는 새 변수를 만듭니다.DefaultAzureCredential credential = new();
NoSQL용 Azure Cosmos DB 계정 엔드포인트로 명명된
endpoint
문자열 변수를 만듭니다.string endpoint = "<nosql-account-endpoint>";
connectionString
을 전달하고 이를 using 문으로 래핑하는CosmosClient
클래스의 새 인스턴스를 만듭니다.using CosmosClient client = new (connectionString);
CosmosClient.GetDatabase
,Database.GetContainer
를 차례로 사용하여 Azure Cosmos DB for NoSQL 계정에서 이전에 만든 컨테이너(cosmicworks/locations
)에 대한 참조를 검색합니다.container
라는 변수에 결과를 저장합니다.var container = client.GetDatabase("cosmicworks").GetContainer("locations");
Program.cs 파일을 저장합니다.
지리 공간적 데이터 추가
.NET SDK에는 공통 GeoJSON 개체를 나타내는 여러 형식이 Microsoft.Azure.Cosmos.Spatial
네임스페이스에 포함되어 있습니다. 이러한 형식은 새 위치 정보를 컨테이너의 항목에 추가하는 프로세스를 간소화합니다.
Office.cs라는 새 파일을 만듭니다. 파일에서 using 지시문을
Microsoft.Azure.Cosmos.Spatial
추가한 다음, 다음 속성을 사용하여 레코드 형식을Office
만듭니다.Type 설명 기본값 id string
고유 식별자 이름 string
사무실 이름 location Point
GeoJSON 지리적 점 category string
파티션 키 값 business-office
using Microsoft.Azure.Cosmos.Spatial; public record Office( string id, string name, Point location, string category = "business-office" );
Region.cs라는 또 다른 새 파일을 만듭니다. 다음 속성을 사용하여
Region
이라는 다른 레코드 형식을 추가합니다.Type 설명 기본값 id string
고유 식별자 이름 string
사무실 이름 location Polygon
GeoJSON 지리적 도형 category string
파티션 키 값 business-region
using Microsoft.Azure.Cosmos.Spatial; public record Region( string id, string name, Polygon location, string category = "business-region" );
참고 항목
이 레코드에는 GeoJSON의 여러 위치 사이에 그려진 선으로 구성된 도형을 나타내는
Polygon
속성이 포함됩니다. 자세한 내용은 GeoJSON 다각형을 참조하세요.Result.cs라는 또 다른 새 파일을 만듭니다. 다음 두 속성을 사용하여
Result
라는 레코드 형식을 추가합니다.Type Description 이름 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), }) } );
다각형,
1000
고유 식별자 및Main Campus
이름을 사용하여mainCampusRegion
이라는 새Region
변수를 만듭니다.Region mainCampusRegion = new ("1000", "Main Campus", mainCampusPolygon);
Container.UpsertItemAsync
를 사용하여 지역을 컨테이너에 추가합니다. 지역 정보를 콘솔에 씁니다.await container.UpsertItemAsync<Region>(mainCampusRegion); Console.WriteLine($"[UPSERT ITEM]\t{mainCampusRegion}");
팁
이 가이드에서는 insert 대신 upsert를 사용하므로 고유 식별자 간의 충돌이 발생하지 않고 스크립트를 여러 번 실행할 수 있습니다. upsert 작업에 대한 자세한 내용은 항목 만들기를 참조하세요.
headquartersPoint
라는 새Point
변수를 만듭니다. 이 변수에서 점,0001
고유 식별자 및Headquarters
이름을 사용하여headquartersOffice
라는 새Office
변수를 만듭니다.Point headquartersPoint = new (-122.12827, 47.63980); Office headquartersOffice = new ("0001", "Headquarters", headquartersPoint);
researchPoint
라는 또 다른Point
변수를 만듭니다. 해당 변수를 사용하여 대응 점,0002
고유 식별자 및Research and Development
이름을 사용하여researchOffice
라는 또 다른Office
변수를 만듭니다.Point researchPoint = new (-96.84369, 46.81298); Office researchOffice = new ("0002", "Research and Development", researchPoint);
두
Office
변수를 모두 단일 트랜잭션으로 upsert하는TransactionalBatch
를 만듭니다. 그런 다음, 두 사무실의 정보를 콘솔에 씁니다.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}");
참고 항목
트랜잭션에 대한 자세한 내용은 트랜잭션 일괄 처리 작업을 참조하세요.
Program.cs 파일을 저장합니다.
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 파일을 엽니다.
이 섹션에서 점 사이의 거리를 측정하는 데 사용되는 쿼리를 사용하여
nosql
이라는 새string
변수를 만듭니다.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 ";
nosqlString
변수를 매개 변수로 사용하여query
라는 새QueryDefinition
변수를 만듭니다. 그런 다음,QueryDefinition.WithParameter
흐름 메서드를 여러 번 사용하여 다음 매개 변수를 쿼리에 추가합니다.값 @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를 사용하여 지리 공간적 데이터 쿼리
.NET SDK의 LINQ to NoSQL 기능은 지리 공간적 형식을 쿼리 식에 포함할 수 있도록 지원합니다. 또한 SDK에는 동등한 기본 제공 함수에 매핑되는 다음 확장 메서드가 포함되어 있습니다.
확장 메서드 | 기본 제공 함수 |
---|---|
Distance() |
ST_DISTANCE |
Intersects() |
ST_INTERSECTS |
IsValid() |
ST_ISVALID |
IsValidDetailed() |
ST_ISVALIDDETAILED |
Within() |
ST_WITHIN |
Program.cs 파일을 엽니다.
고유 식별자가
1000
인 컨테이너에서Region
항목을 검색하고 이를region
이라는 변수에 저장합니다.Region region = await container.ReadItemAsync<Region>("1000", new PartitionKey("business-region"));
Container.GetItemLinqQueryable<>
메서드를 사용하여 쿼리 가능한 LINQ를 가져오고, 다음 세 가지 작업을 수행하여 LINQ 쿼리를 원활하게 빌드합니다.Queryable.Where<>
확장 메서드를 사용하여"business-office"
에 해당하는category
가 있는 항목만 필터링합니다.Queryable.Where<>
를 다시 사용하여Geometry.Within()
을 사용하는region
변수의location
속성 내의 위치로만 필터링합니다.CosmosLinqExtensions.ToFeedIterator<>
를 사용하여 LINQ 식을 피드 반복기로 변환합니다.
var regionIterator = container.GetItemLinqQueryable<Office>() .Where(o => o.category == "business-office") .Where(o => o.location.Within(region.location)) .ToFeedIterator<Office>();
Important
이 예제에서 사무실의 위치 속성에는 점이 있고, 지역의 위치 속성에는 다각형이 있습니다.
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>"
az cosmosdb sql database delete
를 사용하여 데이터베이스를 제거합니다.az cosmosdb sql database delete \ --resource-group "<resource-group-name>" \ --account-name "<nosql-account-name>" \ --name "cosmicworks"