【Azure】CosmosDBにおけるインデックスポリシー入門ガイド【初心者向け】

こんにちは、サイオステクノロジーの佐藤 陽です。
引き続きCosmosDBを勉強しているので、どんどんアウトプットしていきたいと思います。

今回のテーマはインデックスポリシーです。
インデックスの概念については前回の記事にてご紹介しているので、是非ご参照ください!

はじめに

今回はCosmosDBのインデックスの中でもインデックスポリシーについてご紹介します。
インデックスポリシーとは、インデックスを作成するための指示内容になります。

CosmosDBにおいてはデフォルトで、すべてのコンテナのすべての項目にインデックスが作成されます。
つまりデフォルトでは「全ての項目にインデックスを作成する」といったポリシーが存在しています。

ただし、本当に全ての項目にインデックスを作成するべきかどうかは要件に依ります。
インデックスの作成を必要な項目に絞ることで、無駄なRUの発生が抑えられ、コストの削減やスループットの向上が見込まれます。

つまり今回の記事の内容は、既にあるインデックスを削減する方向の話となります。

インデックスポリシー

繰り返しになりますが、インデックスポリシーとはインデックスを作成するための指示内容です。
インデックスポリシーの設定に基づき、CosmosDBはインデックスを作成します。

インデックスポリシーの設定としてはAzurePortalの以下の箇所から確認できます。
こちらの内容がデフォルトの内容になっています。

CosmosDB/データエクスプローラー/Database(Restaurant)/Container(Food)/Settings/IndexPolicy

 

includedPathsがインデックスを作成する対象となるパスを指定しています。

現在

"includedPaths": [
    {
        "path": "/*"
    }
],

となっていることから、全ての項目に対してインデックスが作成されることが分かります。
これは全ての項目に対する検索が高速化されることを意味しており、速度面だけ考えれば喜ばしい事です。

一方で、インデックス作成時にはRU(Request Unit)が発生するため、インデックス作成時にコストが発生したり、スループットが落ちたりします。

そう考えると「決して検索対象とならないようなデータ」にもインデックスを作成するのはもったいないですね。
そこで、インデックスポリシーを適切に設定し、最適化していく流れをご紹介したいと思います。

インデックスポリシーの設定値

まずインデックスポリシーの設定値について解説します。

先程示したjsonのプロパティとして以下のものが存在します。
これらを順を追って説明します。

  • indexMode
  • automatic
  • includedPaths
  • excludedPaths

indexMode

indexModeはその名通りインデックスを作成するモードになります。
このプロパティが取る値としてはconsistentnoneとなります。

consistent

ファイルが追加・更新・更新されたタイミングでインデックスの内容が更新されます。
つまり常に最新のデータの状態でインデックスを活用できる一方で、更新されるたびにRUが発生することも考慮する必要があります。

none

consistentとは異なり、ファイルなどが追加された場合でもインデックスの内容が更新されません。
noneの使いどころとしては以下2点です

  1. そもそもインデックスが必要ない
  2. データの大量投入(Bulk Insert)時

2.に関しては、consistentモードで短時間で大量にデータを投入するとインデックスの更新が頻発し、RUも大量に発生します。
そこで、大量のデータを投入する場合は一時的にnoneに設定し、データ投入後に再度consistentに戻すことによりRUを最小限に抑えることができます。

automatic

次にautomaticのプロパティですが、実はこれ使うことが非推奨とされているようです。

こちらのstackoverflowにてautomaticに関する質問されている方がいて、それに対してCosmosDBの開発チームの方が以下のように回答されていました。

「自動」プロパティは、ほとんどのコンテナで非推奨とされています。
自動プロパティをfalseに設定すると、インデックスを使用するかどうかに基づいてクエリの結果に不整合が生じることがありました(例えばスキャンとは対照的に)。

(翻訳&要約済み)

また、CosmosDBの公式ドキュメントの日本語のページにはautomaticに関する言及がありましたが、英語のページではその部分が削除されていました。

こういった事からも現状はこのプロパティは無視して良さそうです。

includedPaths

次にincludedPathsについてご紹介します。
こちらはその名の通り、インデックスを作成するアイテムを指定するためのパスになります。

このパスに関しては前回のブログ記事で示したような、ツリーを考えると分かりやすいです。

前回と同じ図表を改めて記載します。

パス id
/name 寿司 1
/name うどん 2
/name パスタ 3
/price 500 2
/price 1000 3
/price 2000 1
/ingredients/0/name 1
/ingredients/0/name 小麦 2
/ingredients/0/name デュラム小麦 3
/ingredients/1/name 1
/ingredients/1/name 2,3
/ingredients/2/name 2,3

先程も示しましたが、デフォルトとしては以下のようになっています。
この時、*(ワイルドカード)はそのパスの配下の全てのアイテムをインデックス作成の対象とすることを示しており、今回はrootの以下全てのアイテムが対象となります。

"includedPaths": [
    {
        "path": "/*"
    }
],

この時、例えば

料理名(name)のアイテムに対するインデックスのみを作成したい場合は以下のように設定します。

ここでPathの最後に?が付与されていますが、スカラー値(文字列または数値)へのパスは/?で終わるようにすることが仕様として決められています。

"includedPaths": [
    {
        "path": "name/?"
    }
],
この?の目的ですが、先程挙げた例だとうまく解説できないので、仮でnameの下に以下のようなデータを追加するものとします。
{
    "name": {
        "japanese":"寿司",
        "english":"sushi"
    }
}
この場合、nameのプロパティに対してはインデックスが作成されますが
その配下のjapanese, englishのプロパティに対してはインデックスが作成されないといった形でポリシーが設定されます。

次に原材料名(/ingredients/0/name)のアイテムに対するインデックスのみを作成したい場合は以下のように設定します。
配列を持つ場合は[]といった表記を用います。

"includedPaths": [
    {
        "path": "ingredients/[]/name?"
    }
],

excludedPaths

次はexcludedPathsになります。
こちらもその名の通り、インデックス作成の対象外とするパスを指定します。
パスの設定方法としてはincludedPathsと同様です。

パスの競合

includedPathsとexcludedPathsが競合している場合も想定されます。

例えば以下のようなケースです。
ingredientsのパスに関して、includedPathsにもexcludedPathsにも記載があります。

"includedPaths": [
    {
        "path": "/*"
    }
    {
        "path": "ingredients/[]/name?"
    }
],
"excludedPaths": [
    {
        "path": "ingredients/*"
    },
    {
        "path": "/\"_etag\"/?"
    },
],

結論から述べると、今回はincludedPathsの設定が優先されます。
理由としては、パスの指定がより具体的(深いパスまで指定されている)であるためです。

Include-Exclude戦略

ここでIncludeとExcludeに関して紹介してきましたが、この設定において含まれるパスまたは除外されるパスのいずれかとしてルート パス /* を指定する必要があるといった記載がドキュメントにはあります。

つまり以下の2択です。

  1. includedPathsとして全てのパス(/*)を選択し、除外するものをいくつかピックアップしてexcludedPathsに示す
  2. excludePathsとして全てのパス(/*)を選択し、対象するものをいくつかピックアップしてincludedPathsに示す

どちらが良いかは格納されるアイテムの性質に依るかと思います。
ただ、新規に追加されるプロパティのインデックス作成漏れを防ぐためにも1.の方が良いかなと思います。(MSとしても1.を推奨しています。)

まとめ

今回はCosmosDBのインデックスポリシーの基本的な部分についてご紹介しました。
デフォルトでは全てのプロパティに対してインデックスが作成されますが、インデックスポリシーを適切に設定することで無駄なRU発生を防ぎ、より高いパフォーマンス得ることができます。
今回紹介した設定方法などを活用し、是非CosmosDBを最適化していきましょう!
ではまた!

参考

https://learn.microsoft.com/ja-jp/azure/cosmos-db/index-policy

https://blog.shibayan.jp/entry/20201202/1606905917

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です