CosmosDBの計算済みプロパティ(Computed properties)を試してみた

Azure

2023年5月のMicrosoft BuildにてCosmosDBの計算済みプロパティがプレビューとして公開されました。そこで、どのような機能なのか、何ができるようになるのかを調べてまとめます。

2023年8月時点のプレビュー機能になります。最新の情報は公式ドキュメントを確認してください。

結論

  • 既存の項目に新しいプロパティ(計算済みプロパティ)を作成できる
  • 基本的には一部の集計関数を組み合わせて計算済みプロパティを作成する
  • 計算済みプロパティはAzure Portalからは確認できず、内部的に保存されている
  • 既存プロパティとほぼ同じだけど、フォーマット等少し変えた形式で新しいプロパティとして保持しておきたいという時に使えそう

計算済みプロパティの作成

説明だけ読んでもなかなかイメージしづらいと思うので、まずは実際に計算済みプロパティを作成してみましょう。

2023年8月時点で、計算済みプロパティは.NETもしくはJavaのSDK(プレビュー)からでしか作成できません。今回は.NET SDKを使用して作成します。

プレビューバージョンSDKの追加

最新のプレビューバージョンのSDKをプロジェクトに追加します。

dotnet add package Microsoft.Azure.Cosmos --version 3.35.2-preview

項目の形式

まず、前提としてCosmosDBには以下のようなデータが格納されているものとします。この項目のnameプロパティから姓を抜き出してすべて小文字にしたものを計算済みプロパティとして定義していきます。

{
    "id": "20230730-0444338430",
    "name": "Takina Inoue"
}

上記の項目であれば、計算済みプロパティの値は「inoue」となります。

計算済みプロパティを新規作成する

作成するC#のコードは以下になります。3行目で計算済みプロパティを設定しています。名前は既存の項目と被らないようにします。6行目で計算済みプロパティに設定される値を指定しています。既存のプロパティは「名前 苗字」の形式ですので、複数の関数を組み合わせて苗字を切り取り、最終的に小文字に変換しています。

10行目で計算済みプロパティを設定したコンテナ情報をもとにコンテナを新規作成します。

var conPro = new ContainerProperties("containe3", "/id")
{
    ComputedProperties = new Collection<ComputedProperty>{
        new ComputedProperty{
            Name = "cp_name",
            Query = "SELECT VALUE LOWER(RIGHT(c.name,(LENGTH(c.name) - INDEX_OF(c.name,' ') - 1))) FROM c"
        }
    }
};
Container con = await this._cosmosClient.GetDatabase(dnName).CreateContainerAsync(conPro);

項目を追加してみる

計算済みプロパティを設定したcontainer3というコンテナに、項目を1つ作成します。Azure Portalから作成した項目を確認すると、「cp_name」という計算済みプロパティは確認できません。

それでは、SELECT句で明示的に「cp_name」を指定して読み取ってみます。すると、小文字の姓だけが設定されたプロパティを読み取ることができました。

既存コンテナに計算済みプロパティを追加

先ほどはコンテナの新規作成と同時に計算済みプロパティを設定しました。今回は、既存のコンテナに対して計算済みプロパティを追加して、既存の項目にも自動的に計算済みプロパティが作成されるのかをみてみます。

既存コンテナには予め6つの項目を作成しています。項目の形式は先ほどと同様にidとnameプロパティを持っています。6つのnameは以下の通りです。

この時点でcp_nameをクエリしてみますが、まだ計算済みプロパティを設定していないので、結果は空となります。

それでは、実際に追加してみます。追加するコードは以下の通りです。

var container = this._cosmosClient.GetDatabase(dbName).GetContainer("container1");
var conPro = await container.ReadContainerAsync();
conPro.Resource.ComputedProperties = new Collection<ComputedProperty>{
    new ComputedProperty{
        Name = "cp_name",
        Query = "SELECT VALUE LOWER(RIGHT(c.name,(LENGTH(c.name) - INDEX_OF(c.name,' ') - 1))) FROM c"
    }
};
await container.ReplaceContainerAsync(conPro);

追加できましたので、再度cp_nameを検索すると計算済みプロパティが設定されていました。計算済みプロパティはすでに作成されている項目に対しても適用されるようです。

使い道

計算済みプロパティの設定は分かりました。では、これはどのような時に使えるのでしょうか。

そのままですが、既存のプロパティをもとにした新しいプロパティが必要な時に使うものになると思います。既存プロパティをもとに文字列変換や整形を施したプロパティを作成したい場合は、CosmosDBに新規プロパティを作成するか、プログラム側でプロパティを作成して保持する方法があると思います。

CosmosDBに新規プロパティを作成する場合は、既存の項目も作成し直しになり手間がかかります。項目数によっては現実的ではない可能性もあります。しかし、計算済みプロパティを使用することで、既存の項目を変更せずとも新しいプロパティを追加できます。

プログラム側でプロパティを用意して保持する方法が今まではよく行われていたかと思います。これでも問題はないと思います。それでも、計算済みプロパティを利用することで、複雑な変換処理でも1回設定するだけで済みます。また、計算済みプロパティにはインデックスを設定できるので、効率よく読み取りを行うことができますし、プログラム自体も必要な情報のみ取得し保存するだけで済むので、シンプルなコーディングを実現できます。

注意点

計算済みプロパティを作成するときに使用できる関数やクエリは制限があります。まずクエリではWHERE、GROUP BY、ORDER BY、TOP、DISTINCT、OFFSET LIMIT、EXISTS、ALL、NONEはすべて使用できません。また、関数も集計関数、空間関数、非決定論的関数、ユーザー定義関数はサポートされていません。

また、ドキュメントには計算済みプロパティを設定したコンテナへの書き込み操作でわずかにRUが増加する可能性があると記載されています。今回試した簡単な例ではRUの増加は見られませんでしたが、項目のサイズや計算済みプロパティ作成の複雑さなどによって変わる可能性があるので、実際に使用する際はRUの変化を調査する必要がありそうです。

最後に

今回は、新しくプレビューとなった機能である計算済みプロパティを試してみました。正直すぐに利用することはないと思いますが、新しい選択肢が増えたのはいいことだと思います。

また、個人的には同じタイミングで発表されたマテリアライズドビューとの違いが理解できました。マテリアライズドビューは新しいテーブルを作成しますが、計算済みプロパティは新しいプロパティを作成するものです。改めて言葉にするとシンプルですが、実際に手を動かすことで理解が大幅に進みました。

参考文献

コメント