Cosmos DB の計算済みプロパティ (Azure と Fabric) には、既存の項目プロパティから派生した値がありますが、そのプロパティは項目自体には保持されません。 計算されたプロパティのスコープは 1 つの項目であり、永続化されたプロパティであるかのようにクエリで参照できます。 計算されたプロパティを使用すると、複雑なクエリ ロジックを 1 回記述し、何度も参照しやすくなります。 これらのプロパティに 1 つのインデックスを追加するか、複合インデックスの一部として使用してパフォーマンスを向上させることができます。
計算プロパティとは
計算されるプロパティは、アイテムの最上位にある必要があり、入れ子になったパスを持つことはありません。 各計算プロパティ定義には、名前とクエリの 2 つのコンポーネントがあります。 名前は計算されたプロパティ名であり、クエリは各項目のプロパティ値を計算するロジックを定義します。 計算プロパティのスコープは個々のアイテムであるため、複数の項目の値を使用したり、他の計算プロパティに依存したりすることはできません。 すべてのコンテナーには、最大 20 個の計算プロパティを含めることができます。
計算されたプロパティ定義の例:
{
"computedProperties": [
{
"name": "cp_lowerName",
"query": "SELECT VALUE LOWER(c.name) FROM c"
}
]
}
名前の制約
永続化されたプロパティ名と競合しないように、計算されたプロパティに名前を付けすることを強くお勧めします。 重複するプロパティ名を回避するには、計算されたすべてのプロパティ名にプレフィックスまたはサフィックスを追加します。 この記事では、すべての名前定義でプレフィックス cp_ を使用します。
Important
永続化されたプロパティと同じ名前を使用して計算されたプロパティを定義してもエラーは発生しませんが、予期しない動作が発生する可能性があります。 計算されたプロパティがインデックス付けされているかどうかに関係なく、計算されたプロパティと名前を共有する永続化されたプロパティの値はインデックスに含まれません。 SELECT 句にワイルドカード プロジェクションがある場合、計算プロパティの代わりに返される永続化プロパティを除き、クエリでは常に、永続化されたプロパティの代わりに計算プロパティが使用されます。 ワイルドカード プロジェクションには、計算されたプロパティは自動的には含まれません。
計算されたプロパティ名の制約は次のとおりです。
- 計算されるすべてのプロパティには、一意の名前が必要です。
-
nameプロパティの値は、計算されたプロパティを参照するために使用できる最上位のプロパティ名を表します。 -
id、_rid、_tsなどの予約済みシステム プロパティ名は、計算プロパティ名として使用できません。 - 計算されたプロパティ名は、既にインデックスが作成されているプロパティ パスと一致できません。 この制約は、以下を含む、指定されたすべてのインデックス作成パスに適用されます。
- 含まれるパス
- 除外されたパス
- 空間インデックス
- 複合インデックス
クエリ制約
計算されたプロパティ定義内のクエリは、構文的および意味的に有効である必要があります。それ以外の場合、作成または更新操作は失敗します。 クエリは、コンテナー内のすべての項目の決定論的な値に評価される必要があります。 一部の項目ではクエリが未定義または null に評価される場合があり、未定義または null 値を持つ計算プロパティは、クエリで使用される場合、未定義または null 値を持つ永続化されたプロパティと同じように動作します。
計算されたプロパティ クエリ定義の制限事項は次のとおりです。
- クエリでは、ルート項目参照を表す FROM 句を指定する必要があります。 サポートされている FROM 句の例としては、
FROM c、FROM root c、FROM MyContainer cがあります。 - クエリでは、プロジェクションで VALUE 句を使用する必要があります。
- クエリに JOIN を含めることはできません。
- クエリでは、非決定的スカラー式を使用できません。 非決定的スカラー式の例としては、GetCurrentDateTime、GetCurrentTimeStamp、GetCurrentTicks、RAND があります。
- クエリでは、WHERE、GROUP BY、ORDER BY、TOP、DISTINCT、OFFSET LIMIT、EXISTS、ALL、LAST、FIRST、NONE のいずれかの句を使用できません。
- クエリにスカラー サブクエリを含めることはできません。
- 集計関数、空間関数、非決定的関数、ユーザー定義関数 (UDF) はサポートされていません。
計算プロパティを作成する
計算されたプロパティが作成されたら、Azure portal のすべてのソフトウェア開発キット (SDK) や Azure Data Explorer など、任意のメソッドを使用して、プロパティを参照するクエリを実行できます。
| サポートされているバージョン | 注記 | |
|---|---|---|
| .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);
ヒント
コンテナーのプロパティを更新するたびに、古い値が上書きされます。 既存の計算プロパティがあり、新しい計算プロパティを追加する場合は、新しい計算プロパティと既存の計算プロパティの両方をコレクションに追加してください。
データ エクスプローラーを使用して計算プロパティを作成する
データ エクスプローラーを使用して、コンテナーの計算プロパティを作成できます。
データ エクスプローラーで既存のコンテナーを開きます。
コンテナーの [設定] セクションに移動します。 次に、[*計算プロパティ ] サブセクションに移動します。
コンテナーの計算プロパティ定義 JSON を編集します。 この例では、この JSON を使用して、
-区切り記号を使用して小売製品のSKU文字列を分割する計算プロパティを定義します。[ { "name": "cp_splitSku", "query": "SELECT VALUE StringSplit(p.sku, \"-\") FROM products p" } ]計算されたプロパティを保存します。
クエリで計算プロパティを使用する
計算されたプロパティは、永続化されたプロパティが参照されるのと同じ方法でクエリで参照できます。 インデックスが作成されない計算プロパティの値は、計算されたプロパティ定義を使用して実行時に評価されます。 計算されたプロパティにインデックスが付いている場合、インデックスは永続化されたプロパティに使用されるのと同じ方法で使用され、計算されたプロパティは必要に応じて評価されます。 最適なコストとパフォーマンスを得るための インデックスを計算プロパティに追加 することをお勧めします。
項目の例を次に示します。
{
"id": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
"categoryId": "bbbbbbbb-1111-2222-3333-cccccccccccc",
"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": "cccccccc-2222-3333-4444-dddddddddddd",
"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 できます。これによって、Cosmos DB を使用する際に多くの新しいクエリ シナリオが開きます。
_ts値から月を取得する計算されたプロパティ定義の例を次に示します。
{
"name": "cp_monthUpdated",
"query": "SELECT VALUE DateTimePart('m', TimestampToDateTime(c._ts*1000)) FROM c"
}
ORDER BY cp_monthUpdatedする前に、インデックス作成ポリシーに追加する必要があります。 インデックス作成ポリシーが更新されたら、計算されたプロパティで並べ替えることができます。
SELECT
*
FROM
c
ORDER BY
c.cp_monthUpdated
インデックス計算プロパティ
計算されたプロパティは、既定ではインデックス付けされず、 インデックス作成ポリシーのワイルドカード パスではカバーされません。 永続化されたプロパティにインデックスを追加するのと同じ方法で、インデックス作成ポリシーの計算されたプロパティに単一インデックスまたは複合インデックスを追加できます。 すべての計算プロパティに関連するインデックスを追加することをお勧めします。 これらのインデックスは、パフォーマンスの向上と要求ユニット (RU) の削減に役立つため、推奨されます。 計算プロパティにインデックスを付けると、項目の書き込み操作中に実際の値が評価され、インデックス用語が生成されて保持されます。
計算プロパティのインデックス作成には、次のようないくつかの考慮事項があります。
- 計算プロパティは、インクルード パス、除外パス、複合インデックス パスで指定できます。
- 計算されたプロパティに空間インデックスを定義することはできません
- 計算されたプロパティ パスの下のワイルドカード パスは、通常のプロパティの場合と同様に機能します。
- 削除されたプロパティとインデックス付きプロパティの関連するインデックスも削除する必要があります
注
すべての計算プロパティは、アイテムの最上位レベルで定義されます。 パスは常に /<computed property name>。
ヒント
コンテナーのプロパティを更新するたびに、古い値が上書きされます。 既存の計算プロパティがあり、新しい計算プロパティを追加する場合は、新しい計算プロパティと既存の計算プロパティの両方をコレクションに追加してください。
注
インデックス付き計算プロパティの定義を変更しても、インデックスの再作成は自動的には行われません。 変更された計算プロパティのインデックスを作成するには、計算プロパティをインデックスから削除します。 その後、インデックスの再作成が完了したら、計算されたプロパティをインデックス ポリシーに追加し直します。
計算されたプロパティを削除する場合は、最初にインデックス ポリシーから削除します。
計算プロパティの 1 つのインデックスを追加する
cp_myComputedPropertyという名前の計算プロパティに 1 つのインデックスを追加するには:
{
"indexingMode": "consistent",
"automatic": true,
"includedPaths": [
{
"path": "/*"
},
{
"path": "/cp_myComputedProperty/?"
}
],
"excludedPaths": [
{
"path": "/\"_etag\"/?"
}
]
}
計算プロパティの複合インデックスを追加する
2 つのプロパティに複合インデックスを追加するには、1 つは cp_myComputedPropertyとして計算され、もう 1 つは myPersistedPropertyとして永続化されます。
{
"indexingMode": "consistent",
"automatic": true,
"includedPaths": [
{
"path": "/*"
}
],
"excludedPaths": [
{
"path": "/\"_etag\"/?"
}
],
"compositeIndexes": [
[
{
"path": "/cp_myComputedProperty"
},
{
"path": "/path/to/myPersistedProperty"
}
]
]
}
要求ユニットの使用量について
計算されたプロパティをコンテナーに追加しても、RU は使用されません。 計算プロパティが定義されているコンテナーに対する書き込み操作では、RU がわずかに増加する可能性があります。 計算されたプロパティにインデックスが付いている場合、書き込み操作の RU が増加し、計算されたプロパティのインデックス作成と評価のコストが反映されます。