共用方式為


適用於 NoSQL 的 Azure Cosmos DB 中的計算屬性 (預覽)

適用於:NoSQL

Azure Cosmos DB 中的計算屬性具有衍生自現有專案屬性的值,但屬性本身不會保存。 計算屬性的範圍會限定為單一專案,而且可以在查詢中參考,就像是保存的屬性一樣。 計算屬性可讓您更輕鬆地撰寫複雜的查詢邏輯一次,並多次參考它。 您可以在這些屬性上新增單一索引,或使用它們作為複合索引的一部分,以提高效能。

注意

您是否有任何關於計算屬性的意見反應? 我們想要知道您的看法! 歡迎您將意見反應直接告訴 Azure Cosmos DB 工程小組:cosmoscomputedprops@microsoft.com

什麼是計算屬性?

計算屬性必須位於專案的最上層,而且不能有巢狀路徑。 每個計算屬性定義都有兩個元件:名稱和查詢。 此名稱是計算的屬性名稱,而查詢會定義邏輯來計算每個項目的屬性值。 計算屬性的範圍設定為個別專案,因此無法使用來自多個專案的值,或依賴其他計算屬性。 每個容器最多可以有20個計算屬性。

計算屬性定義的範例:

{
  "computedProperties": [
    {
      "name": "cp_lowerName",
      "query": "SELECT VALUE LOWER(c.name) FROM c"
    }
  ]
}

名稱條件約束

強烈建議您命名計算屬性,以免與持續性屬性名稱發生衝突。 若要避免重疊的屬性名稱,您可以將前置詞或後綴新增至所有計算屬性名稱。 本文會在所有名稱定義中使用前置 cp_ 詞。

重要

使用與保存屬性相同的名稱定義計算屬性不會產生錯誤,但可能會導致非預期的行為。 不論計算屬性是否已編製索引,與計算屬性共用名稱的保存屬性值都不會包含在索引中。 查詢一律會使用計算屬性而非保存屬性,但如果 SELECT 子句中有萬用字元投影,且傳回的是保存屬性,而不是計算屬性,則此情形除外。 通配符投影不會自動包含計算屬性。

計算屬性名稱的條件約束如下:

  • 所有計算屬性都必須有唯一的名稱。
  • 屬性的值 name 代表可用來參考計算屬性的最上層屬性名稱。
  • 保留的系統屬性名稱,例如 id_rid_ts 無法當做計算屬性名稱使用。
  • 計算的屬性名稱無法比對已經編製索引的屬性路徑。 此條件約束適用於指定的所有索引路徑,包括:
    • 已排除的路徑
    • 已排除的路徑
    • 空間索引
    • 複合索引

查詢條件約束

計算屬性定義中的查詢在語法和語意上必須有效,否則建立或更新作業會失敗。 查詢應該評估為容器中所有項目的決定性值。 查詢可能會評估為某些專案的未定義或 Null,而具有未定義或 Null 值的計算屬性在查詢中使用時,其行為與具有未定義或 Null 值的保存屬性相同。

計算屬性查詢定義的限制如下:

  • 查詢必須指定代表根項目參考的FROM子句。 支援的 FROM 子句範例包括: FROM cFROM root cFROM MyContainer c
  • 查詢必須在投影中使用 VALUE 子句。
  • 查詢不能包含 JOIN。
  • 查詢無法使用不具決定性的純量表達式。 不具決定性純量表達式的範例包括:GetCurrentDateTime、GetCurrentTimeStamp、GetCurrentTicks 和 RAND。
  • 查詢無法使用下列任何子句:WHERE、GROUP BY、ORDER BY、TOP、DISTINCT、OFFSET LIMIT、EXISTS、ALL、LAST、FIRST 和 NONE。
  • 查詢不能包含純量子查詢。
  • 不支援聚合函數、空間函式、非決定性函式和使用者定義函數 (UDF)。

建立計算屬性

在預覽期間,必須使用 .NET v3 或 Java v4 SDK 建立計算屬性。 建立計算屬性之後,您可以使用任何方法來執行參考屬性的查詢,包括 Azure 入口網站 中的所有 SDK 和 Azure 數據總管。

支援的版本 備註
.NET SDK v3 >= 3.34.0-preview 計算屬性目前僅適用於預覽套件版本。
Java SDK v4 >= 4.46.0 計算屬性目前處於預覽版本。
Python SDK >= v4.5.2b5 計算屬性目前處於預覽版本。

使用 SDK 建立計算屬性

您可以建立已定義計算屬性的新容器,也可以將計算屬性新增至現有的容器。

以下是如何在新容器中建立計算屬性的範例:

ContainerProperties containerProperties = new ContainerProperties("myContainer", "/pk")
{
    ComputedProperties = new Collection<ComputedProperty>
    {
        new ComputedProperty
        {
            Name = "cp_lowerName",
            Query = "SELECT VALUE LOWER(c.name) FROM c"
        }
    }
};

Container container = await client.GetDatabase("myDatabase").CreateContainerAsync(containerProperties);

以下是如何在現有容器上更新計算屬性的範例:

var container = client.GetDatabase("myDatabase").GetContainer("myContainer");

// Read the current container properties
var containerProperties = await container.ReadContainerAsync();
// Make the necessary updates to the container properties
containerProperties.Resource.ComputedProperties = new Collection<ComputedProperty>
    {
        new ComputedProperty
        {
            Name = "cp_lowerName",
            Query = "SELECT VALUE LOWER(c.name) FROM c"
        },
        new ComputedProperty
        {
            Name = "cp_upperName",
            Query = "SELECT VALUE UPPER(c.name) FROM c"
        }
    };
// Update the container with changes
await container.ReplaceContainerAsync(containerProperties);

提示

每次更新容器屬性時,都會覆寫舊值。 如果您有現有的計算屬性,而且想要加入新的計算屬性,請務必將新的和現有的計算屬性新增至集合。

在查詢中使用計算屬性

計算屬性可以在查詢中參考,方式與參考保存屬性的方式相同。 未編製索引的計算屬性值會使用計算屬性定義在運行時間期間進行評估。 如果已編製計算屬性的索引,索引會與用於保存屬性的方式相同,而且會視需要評估計算屬性。 建議您 在計算屬性 上新增索引,以獲得最佳成本和效能。

下列範例使用 Azure 入口網站 數據總管中提供的快速入門產品數據集。 若要開始使用,請選取 [啟動快速入門 ],然後在新的容器中載入數據集。

顯示如何開始快速入門以在 Azure 入口網站 載入範例數據集的螢幕快照。

以下是專案的範例:

{
  "id": "08225A9E-F2B3-4FA3-AB08-8C70ADD6C3C2",
  "categoryId": "75BF1ACB-168D-469C-9AA3-1FD26BB4EA4C",
  "categoryName": "Bikes, Touring Bikes",
  "sku": "BK-T79U-50",
  "name": "Touring-1000 Blue, 50",
  "description": "The product called \"Touring-1000 Blue, 50\"",
  "price": 2384.07,
  "tags": [
    {
      "id": "27B7F8D5-1009-45B8-88F5-41008A0F0393",
      "name": "Tag-61"
    }
  ],
  "_rid": "n7AmAPTJ480GAAAAAAAAAA==",
  "_self": "dbs/n7AmAA==/colls/n7AmAPTJ480=/docs/n7AmAPTJ480GAAAAAAAAAA==/",
  "_etag": "\"01002683-0000-0800-0000-6451fb4b0000\"",
  "_attachments": "attachments/",
  "_ts": 1683094347
}

Projection

如果需要投影計算屬性,則必須明確參考這些屬性。 通配符投影,例如 SELECT * 傳回所有保存的屬性,但不包含計算屬性。

以下是將 屬性轉換成小寫的 name 計算屬性定義的範例:

{ 
  "name": "cp_lowerName", 
  "query": "SELECT VALUE LOWER(c.name) FROM c" 
} 

然後,這個屬性可以投影在查詢中:

SELECT 
    c.cp_lowerName 
FROM 
    c

WHERE 子句

計算屬性可以在篩選述詞中參考,就像任何保存的屬性一樣。 當您在篩選中使用計算屬性時,建議您新增任何相關的單一或複合索引。

以下是計算 20% 價格折扣的計算屬性定義範例:

{ 
  "name": "cp_20PercentDiscount", 
  "query": "SELECT VALUE (c.price * 0.2) FROM c" 
} 

然後,可以篩選此屬性,以確保只會傳回折扣小於 $50 的產品:

SELECT 
    c.price - c.cp_20PercentDiscount as discountedPrice, 
    c.name 
FROM 
    c 
WHERE 
    c.cp_20PercentDiscount < 50.00

GROUP BY 子句

如同保存的屬性,計算屬性可以在 GROUP BY 子句中參考,並盡可能使用索引。 為了獲得最佳效能,請新增任何相關的單一或複合索引。

以下是從屬性中尋找每個專案 categoryName 之主要類別的計算屬性定義範例:

{
  "name": "cp_primaryCategory",
  "query": "SELECT VALUE SUBSTRING(c.categoryName, 0, INDEX_OF(c.categoryName, ',')) FROM c"
}

然後,您可以依 cp_primaryCategory 分組,以取得每個主要類別中的項目計數:

SELECT 
    COUNT(1), 
    c.cp_primaryCategory 
FROM 
    c 
GROUP BY 
    c.cp_primaryCategory

提示

雖然您也可以在不使用計算屬性的情況下達成此查詢,但使用計算屬性可大幅簡化查詢的撰寫,並允許提升效能,因為 cp_primaryCategory 可以編製索引。 SUBSTRING()INDEX_OF() 都需要完整掃描容器中的所有專案,但如果您編製計算屬性的索引,則可以改為從索引提供整個查詢。 從索引提供查詢,而不是依賴完整掃描的能力會增加效能,並降低查詢要求單位 (RU) 成本。

ORDER BY 子句

如同保存的屬性,計算屬性可以在 ORDER BY 子句中參考,而且必須編製索引,查詢才能成功。 藉由使用計算屬性,您可以依複雜邏輯或系統函式的結果 ORDER BY,這會在使用 Azure Cosmos DB 時開啟許多新的查詢案例。

以下是計算屬性定義的範例,會從 _ts 值中取得月份:

{
  "name": "cp_monthUpdated",
  "query": "SELECT VALUE DateTimePart('m', TimestampToDateTime(c._ts*1000)) FROM c"
}

您必須先將它新增至索引編製原則,才能排序 BY cp_monthUpdated。 更新索引編製原則之後,您可以依計算屬性排序。

SELECT
    *
FROM
    c
ORDER BY
    c.cp_monthUpdated

索引計算屬性

根據預設,計算屬性不會編製索引,而且索引編製原則中的通配符路徑並未涵蓋。 您可以在索引編製原則中,在計算屬性上加入單一或複合索引,就像在保存的屬性上加入索引一樣。 我們建議您將相關的索引新增至所有計算屬性。 建議您使用這些索引,因為它們有助於提升效能,並在編製索引時減少 RU。 當計算屬性編製索引時,會在專案寫入作業期間評估實際值,以產生和保存索引詞彙。

編製計算屬性的索引有幾個考慮,包括:

  • 計算屬性可以在包含的路徑、排除的路徑和複合索引路徑中指定。
  • 計算屬性不能在它們上定義空間索引。
  • 計算屬性路徑下通配符路徑的運作方式,就像一般屬性一樣。
  • 如果您要移除已編製索引的計算屬性,該屬性上的所有索引也必須卸除。

注意

所有計算屬性都會定義在專案的最上層。 路徑一律 /<computed property name>為 。

提示

每次更新容器屬性時,都會覆寫舊值。 如果您有現有的計算屬性,而且想要加入新的計算屬性,請務必將新的和現有的計算屬性新增至集合。

注意

修改索引計算屬性的定義時,不會自動重新編製索引。 若要編制修改之計算屬性的索引,您必須先從索引卸除計算屬性。 然後在重新編製索引完成之後,將計算屬性新增回索引原則。

如果您想要刪除計算屬性,您必須先從索引原則中移除它。

為計算屬性新增單一索引

若要為名為 cp_myComputedProperty的計算屬性新增單一索引:

{
  "indexingMode": "consistent",
  "automatic": true,
  "includedPaths": [
    {
      "path": "/*"
    },
    {
      "path": "/cp_myComputedProperty/?"
    }
  ],
  "excludedPaths": [
    {
      "path": "/\"_etag\"/?"
    }
  ]
}

為計算屬性新增複合索引

若要在兩個屬性上加入複合索引,其中一個會計算為 cp_myComputedProperty,另一個會儲存為 myPersistedProperty

{
  "indexingMode": "consistent",
  "automatic": true,
  "includedPaths": [
    {
      "path": "/*"
    }
  ],
  "excludedPaths": [
    {
      "path": "/\"_etag\"/?"
    }
  ],
  "compositeIndexes": [
    [
      {
        "path": "/cp_myComputedProperty"
      },
      {
        "path": "/path/to/myPersistedProperty"
      }
    ]
  ]
}

瞭解要求單位耗用量

將計算屬性新增至容器並不會取用 RU。 在已定義計算屬性的容器上寫入作業可能會稍微增加 RU。 如果已編製計算屬性的索引,寫入作業上的 RU 會增加,以反映計算屬性的編製索引和評估成本。 在預覽期間,與計算屬性相關的 RU 費用可能會變更。