적용 대상: NoSQL
Azure Cosmos DB for NoSQL의 지리 공간적 데이터를 사용하면 위치 정보를 저장하고, 다음을 포함하지만 이에 국한되지 않는 일반적인 쿼리를 수행할 수 있습니다.
- 위치가 정의된 영역 내에 있는지 확인
- 두 위치 사이의 거리 측정
- 경로가 위치 또는 영역과 교차하는지 확인
이 가이드에서는 지리 공간적 데이터를 만들고, 데이터를 인덱싱하고, 컨테이너의 데이터를 쿼리하는 프로세스를 안내합니다.
필수 조건
- 기존 Azure Cosmos DB 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>"
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
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
를 사용하여 파티션 키 경로가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
마지막으로
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를 사용하여 지리적 개체를 컨테이너에 추가하는 프로세스를 간소화합니다.
빈 디렉터리에서 터미널을 엽니다.
dotnet new
템플릿에서 명령을 사용하여 새 .NET 애플리케이션을 만듭니다.dotnet new console
Microsoft.Azure.Cosmos
명령을 사용하여 NuGet 패키지를 가져옵니다dotnet add package
.dotnet add package Microsoft.Azure.Cosmos --version 3.*
경고
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;
Azure.Identity
네임스페이스에 대한 또 다른 using 지시문을 추가합니다.using Azure.Identity;
credential
형식의DefaultAzureCredential
라는 새 변수를 만듭니다.DefaultAzureCredential credential = new();
NoSQL용 Azure Cosmos DB 계정 엔드포인트로 명명된
endpoint
문자열 변수를 만듭니다.string endpoint = "<nosql-account-endpoint>";
connectionString
을 전달하고 이를 using 문으로 래핑하는CosmosClient
클래스의 새 인스턴스를 만듭니다.using CosmosClient client = new (connectionString);
cosmicworks/locations
,CosmosClient.GetDatabase
를 차례로 사용하여 Azure Cosmos DB for NoSQL 계정에서 이전에 만든 컨테이너(Database.GetContainer
)에 대한 참조를 검색합니다.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
만듭니다.유형 설명 기본값 id string
고유 식별자 이름 string
사무실 이름 ___location Point
GeoJSON 지리적 점 카테고리 string
파티션 키 값 business-office
using Microsoft.Azure.Cosmos.Spatial; public record Office( string id, string name, Point ___location, string category = "business-office" );
Region.cs라는 또 다른 새 파일을 만듭니다. 다음 속성을 사용하여
Region
이라는 다른 레코드 형식을 추가합니다.유형 설명 기본값 id string
고유 식별자 이름 string
사무실 이름 ___location Polygon
GeoJSON 지리적 도형 카테고리 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
라는 레코드 형식을 추가합니다.유형 설명 이름 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
를 사용하여 지역을 컨테이너에 추가합니다. 지역 정보를 콘솔에 씁니다.await container.UpsertItemAsync<Region>(mainCampusRegion); Console.WriteLine($"[UPSERT ITEM]\t{mainCampusRegion}");
팁
이 가이드에서는 insert 대신 upsert를 사용하므로 고유 식별자 간의 충돌이 발생하지 않고 스크립트를 여러 번 실행할 수 있습니다. upsert 작업에 대한 자세한 내용은 항목 만들기를 참조하세요.
Point
라는 새headquartersPoint
변수를 만듭니다.Office
변수를 사용하여headquartersOffice
라는 새 변수를 만드는데, 이 때 점, 고유 식별자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);
두
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 파일을 엽니다.
이 섹션에서 점 사이의 거리를 측정하는 데 사용되는 쿼리를 사용하여
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 ";
QueryDefinition
변수를 매개 변수로 사용하여query
라는 새nosqlString
변수를 만듭니다. 그런 다음,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 파일을 엽니다.
고유 식별자가
Region
인 컨테이너에서1000
항목을 검색하고 이를region
이라는 변수에 저장합니다.Region region = await container.ReadItemAsync<Region>("1000", new PartitionKey("business-region"));
Container.GetItemLinqQueryable<>
메서드를 사용하여 쿼리 가능한 LINQ를 가져오고, 다음 세 가지 작업을 수행하여 LINQ 쿼리를 원활하게 빌드합니다.Queryable.Where<>
확장 메서드를 사용하여category
에 해당하는"business-office"
가 있는 항목만 필터링합니다.Queryable.Where<>
를 다시 사용하여region
을 사용하는___location
변수의Geometry.Within()
속성 내의 위치로만 필터링합니다.CosmosLinqExtensions.ToFeedIterator<>
를 사용하여 LINQ 식을 피드 반복기로 변환합니다.
var regionIterator = container.GetItemLinqQueryable<Office>() .Where(o => o.category == "business-office") .Where(o => o.___location.Within(region.___location)) .ToFeedIterator<Office>();
중요한
이 예제에서 사무실의 위치 속성에는 점이 있고, 지역의 위치 속성에는 다각형이 있습니다.
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"