在 Azure Cosmos DB for NoSQL 中為 GeoJSON 位置資料編製索引和加以查詢
適用於: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>"
使用
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
建立名為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
使用
dotnet add package
命令匯入Microsoft.Azure.Cosmos
NuGet 套件。dotnet add package Microsoft.Azure.Cosmos --version 3.*
警告
Entity Framework 目前不支援 Azure Cosmos DB for NoSQL 中的空間資料。 將其中一個 Azure Cosmos DB for NoSQL 用於強型別 GeoJSON 支援。
匯入
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;
建立名為
credential
的DefaultAzureCredential
型別新變數。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 在 Microsoft.Azure.Cosmos.Spatial
命名空間中包含了多個類型,以代表常見的 GeoJSON 物件。 這些類型可簡化將新的位置資訊新增至容器所含項目的程序。
建立名為 Office.cs 的新檔案。 在 檔案中,將 using 指示詞新增至
Microsoft.Azure.Cosmos.Spatial
,然後使用下列屬性建立Office
記錄類型:類型 描述 預設值 id string
唯一識別碼 name string
辦公室的名稱 位置 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
的另一個記錄類型:類型 描述 預設值 id string
唯一識別碼 name string
辦公室的名稱 位置 Polygon
GeoJSON 地理圖形 category string
分割區索引鍵值 business-region
using Microsoft.Azure.Cosmos.Spatial; public record Region( string id, string name, Polygon location, string category = "business-region" );
注意
此記錄包含
Polygon
屬性,代表在 GeoJSON 中的多個位置之間繪製的線條所組成的圖形。 如需詳細資訊,請參閱 GeoJSON 多邊形。建立名為 Result.cs 的另一個新檔案。 使用以下兩個屬性新增名為
Result
的記錄類型:類型 Description name string
相符結果的名稱 distanceKilometers decimal
以公里為單位的距離 public record Result( string name, decimal distanceKilometers );
儲存 Office.cs、Region.cs 和 Result.cs 檔案。
再次開啟 Program.cs 檔案。
在名為
mainCampusPolygon
的變數中建立新的Polygon
。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}");
提示
本指南使用 upsert 而不是 insert,因此您可以執行指令碼多次,而不會造成唯一識別碼之間的衝突。 如需 upsert 作業的詳細資訊,請參閱建立項目。
新建名為
headquartersPoint
的Point
變數。 使用該變數新建名為headquartersOffice
的Office
變數 (使用點、唯一識別碼0001
和名稱Headquarters
)。Point headquartersPoint = new (-122.12827, 47.63980); Office headquartersOffice = new ("0001", "Headquarters", headquartersPoint);
建立另一個名為
researchPoint
的Point
變數。 使用該變數建立名為researchOffice
的另一個Office
變數 (使用對應點、唯一識別碼0002
和名稱Research and Development
)。Point researchPoint = new (-96.84369, 46.81298); Office researchOffice = new ("0002", "Research and Development", researchPoint);
建立
TransactionalBatch
以將兩個Office
變數 upsert 為單一交易。 然後,將這兩個辦公室的資訊都寫入主控台。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
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 查詢地理空間資料
.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<>
擴充方法,僅篩選出category
等同於"business-office"
的項目。再次使用
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>();
重要
在此範例中,辦公室的位置屬性有一個點,而區域的位置屬性則有多邊形。
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"