적용 대상: 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 400index-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 consoleMicrosoft.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.IdentityNuGet 패키지를 가져옵니다.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 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>";CosmosClient을 전달하고 이를connectionString으로 래핑하는 클래스의 새 인스턴스를 만듭니다.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 PointGeoJSON 지리적 점 카테고리 string파티션 키 값 business-officeusing Microsoft.Azure.Cosmos.Spatial; public record Office( string id, string name, Point location, string category = "business-office" );Region.cs라는 또 다른 새 파일을 만듭니다. 다음 속성을 사용하여
Region이라는 다른 레코드 형식을 추가합니다.유형 설명 기본값 id string고유 식별자 이름 string사무실 이름 location PolygonGeoJSON 지리적 도형 카테고리 string파티션 키 값 business-regionusing 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);두
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}");참고
트랜잭션에 대한 자세한 내용은 트랜잭션 일괄 처리 작업을 참조하세요.
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"