5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Cosmos DBメモ】Cosmos DBで日付項目をパーティション キーに使用したい場合

Last updated at Posted at 2021-11-05

はじめに

Azure Cosmos DB の学習中にパーティション キーに日付項目を使用するケースがあり、これが一筋縄ではいかず、調査・検討した結果をメモとして記載しました。
見解に誤りやより良い方法があればコメント・アドバス願います。

Cosmos DBへの入出力操作の参考

事前知識

パーティション キーの役割

Azure Cosmos DB は、データベースの個別のコンテナーをパーティション分割を使用した水平スケーリングすることで、数ミリ秒 (1桁台) の応答時間と、自動および即時のスケーラビリティを実現しています。
そして、パーティション キーはコンテナーをパーティション分割する際のキーであり、パーティション キーに指定した項目の値が同じデータは同じパーティションに格納されます。
なお、パーティション キーはコンテナー作成時のみ指定可能で、後から変更することはできません。

パーティション キーのルール(「Microsof Docs」より)

  • パーティション キーを選択した後は、その場で変更することはできません。 パーティション キーを変更する必要がある場合は、新しい必要なパーティション キーを使用して、新しいコンテナーにデータを移動する必要があります。
  • すべての コンテナーで、パーティション キーが次のようになっている必要があります。
    • 値が変更されないプロパティであること。 プロパティがパーティション キーの場合、そのプロパティの値を更新することはできません。
    • 高いカーディナリティがあること。 言い換えると、プロパティには、有効な値が広範囲に及ぶことが必要です。
    • 要求ユニット (RU) の消費量とデータ ストレージをすべての論理パーティションに均等に分散すること。 これにより、物理パーティション全体でも RU の消費とストレージの分散が保証されます。

パーティション キーのパス (例: "/userId")のルール

  • パーティション キーのパスには、英数字とアンダースコア (_) 文字を使用できます。 また、標準パス表記 (/) を使用して、入れ子になったオブジェクトを使用することもできます。

パーティション キーの値 (例:"Andrew")のルール

  • パーティション キーの値には、文字列型または数値型を使用できます。
  • パーティション キー値の最大長は2048 バイトです。

参考

Azure Cosmos DB での日付の扱い

Azure Cosmos DB はJSON ドキュメントとしてモデル化されて保存しており、少数の基本的な型 (String、Number、Boolean、Array、Object、Null) のみサポートし、DateTime 型は直接サポートされません。
そのため、DateTime を文字列として格納する必要があります。

また、現在、Azure Cosmos DB では、日付のローカリゼーションはサポートされていないため、Microsof は日付は UTC の DateTime 値を ISO 8601 UTC 標準に準拠した yyyy-MM-ddTHH:mm:ss.fffffffZ 形式の文字列で保存することを推奨しています。

なお、フィルターとして DateTime 文字列を使用する範囲クエリは、DateTime 文字列がすべて UTC であり、同じ長さである場合にのみサポートされます。

参考

日付項目をパーティション キーに使用したい場合

方法1(王道パターンだと思いきやNG)

UTC の DateTime 値に変換した日付を ISO 8601 UTC 標準に準拠した yyyy-MM-ddTHH:mm:ss.fffffffZ 形式の文字列で保存する。

概要

DateTime 型の日付項目を以下の書式で文字列に変換

  • 書式: "yyyy-MM-dd'T'HH:mm:ss'Z'"

    • 実装イメージ
    [JsonProperty("datePartitionKey")]
    public string DatePartitionKey => {DateTime 型の項目}.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss'Z'");
    
  • 書式: "O"

    • 実装イメージ
    [JsonProperty("datePartitionKey")]
    public string DatePartitionKey => {DateTime 型の項目}.ToUniversalTime().ToString("O");
    

課題・問題点など

  • 「PartitionKey extracted from document doesn't match the one specified in the header.」のエラーで保存できず。

参考

方法2

UTC の DateTime 値に変換した日付を Unix タイムスタンプとして保存する。
※Azure Cosmos DB の内部 Timestamp(_ts)プロパティが採用

概要

UnixDateTimeConverter クラスを使用して、DateTime を数値としてシリアル化

  • 実装イメージ
  [JsonProperty("datePartitionKey")]
  [JsonConverter(typeof(Newtonsoft.Json.Converters.UnixDateTimeConverter))]
  public string DatePartitionKey => {DateTime 型の項目}.ToUniversalTime();

参考

課題・問題点など

  • 日付項目に対する検索条件も正常に機能し、特に問題点は見当たらない。

方法3

日付を yyyy-MM-dd 形式の文字列で保存する。
※国際化が不要な簡易なシステムであれば、UTC 変換も不要でJSONを参照した際も分かりやすい。

概要

DateTime 型の日付項目を日付のみの書式で文字列に変換

  • 実装イメージ
  [JsonProperty("datePartitionKey")]
  public string DatePartitionKey => {DateTime 型の項目}.ToString("yyyy-MM-dd");

参考

課題・問題点など

  • 日付項目に対する検索条件用に別途、DateTime 型の項目が必要。

まとめ

  • 日付項目をパーティション キーに使用する場合、日付項目をUTCに変換した値を Unix タイムスタンプ に変換した数値で保存する「方法2」が良さそうである。
  • ただし、国際化が不要な簡易なシステムであれば、日付項目を日付のみの書式で文字列で保存する「方法3」が、UTC 変換も不要でJSONを参照した際も分かりやすいため、検討の余地はあると考えます。
5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?