DocumentDBライブラリの「1クエリ」は「1HTTPリクエスト」ではない
豆知識的なメモ ブログです。
私自身、DocumentDBを学ぶ上で「あー、そうなんだぁ。ライブラリがいい意味でも、そうでない意味でも、面倒見てくれてるんだなぁ」と思った点について書いておきます。
※本記事では「FeedOptions.MaxItemCount」と「DocumentDBのREST API呼び出しにおけるHTTPヘッダー「x-ms-max-item-count」」について記述しています。
前提条件
以下のモデルクラスデータが 1,000件 、DocumentDBに保存されているものとします。
public class ProductItem { [JsonProperty(PropertyName = "id")] public string Id { get; set; } public string Name { get; set; } public int Price { get; set; } public int StockNumber { get; set; } }
また、ドキュメントは以下のデータベース・コレクションに保存されているものとします。
データベース名: ExampleDB1
コレクション名: ExampleCollection1
ライブラリを使って全件クエリー!
プロジェクトに対してNugetから「Microsoft.Azure.Document」を追加すると以下のようなコードで 1,000件のProductItemオブジェクト を取得することができます。
// リスト1 string EndpointUrl = "https://rddocdb.documents.azure.com:443/"; string PrimaryKey = "[プライマリキー]"; string DatabaseID = "ExampleDB1"; string CollectionID = "ExampleCollection1"; // DocumentClientオブジェクト初期化 DocumentClient client = new DocumentClient(new Uri(EndpointUrl), PrimaryKey); // 全件取得 Uri documentCollectionUri = UriFactory.CreateDocumentCollectionUri(DatabaseID, CollectionID); var query = client.CreateDocumentQuery<ProductItem>(documentCollectionUri); // result変数に1,000件のデータが取得される var result = query.ToList();
実際に発行されたHTTP
上記コードでは、最後の「result = query.ToList();」を実行したタイミングで DocumentDB へのクエリー要求が行われます。
処理完了後に result 変数には1,000件の ProductItemオブジェクト が取得されます。
FiddlerでHTTP通信を監視すると、以下のようなHTTP通信が行われていることを確認することができます。
10回の /docs へのリクエストが行われています。
また、各リクエスト時の リクエストチャージ(x-ms-request-charge)は 38.1 でした。全部で38.1×10のRUを消費。
つまり、ライブラリを利用するコードとしては「query.ToList()」の1文が、10回のHTTPリクエストに分割された、ということです。
x-ms-max-item-countの影響
全1,000件のデータが10回のHTTPリクエストに分割された理由、それはDocumentClient.CreateDocumentQuery()メソッド呼び出し時のFeedOptions引数に影響します。
リスト1ではCreateDocumentQuery()の第2引数を指定しませんでしたが、CreateDocumentQuery()には第2引数にFeedOptionsオブジェクトを指定することができます。
FeedOptions.MaxItemCountの値が1リクエストで取得する項目の最大件数になります(DocumentDBのREST API呼び出しにおけるHTTPヘッダー「x-ms-max-item-count」値)。
また、FeedOptions.MaxItemCountのデフォルト値は「100」となっています。
つまり、これを省略したリスト1では「1リクエストで取得する最大件数=100」で動作を行いました。
10回のリクエストの途中のHTTPヘッダーを見ると以下のようになっています。
上記キャプチャでは、HTTPレスポンスに「x-ms-continuation: {“token”:“qd4DAJ67FQDIAAAAAAAAAA==”,“range”:{“min”:“”,“max”:“FF”}}」が記述されています。
つまり、HTTPリクエスト・レスポンス間での特定クエリーに対するページング処理が挟み込まれています(10件ずつのページング)。
FeedOptions.MaxItemCountを指定する
では、以下のリスト2のように FeedOptions.MaxItemCount= 1000 を指定してみます。
// リスト2 string EndpointUrl = "https://rddocdb.documents.azure.com:443/"; string PrimaryKey = "[プライマリキー]"; string DatabaseID = "ExampleDB1"; string CollectionID = "ExampleCollection1"; // 1度の最大取得項目数は1,000 var feedOption = new FeedOptions() { MaxItemCount = 1000 }; // DocumentClientオブジェクト初期化 DocumentClient client = new DocumentClient(new Uri(EndpointUrl), PrimaryKey); // 全件取得 Uri documentCollectionUri = UriFactory.CreateDocumentCollectionUri(DatabaseID, CollectionID); var query = client.CreateDocumentQuery<ProductItem>(documentCollectionUri, feedOption); var result = query.ToList();
リスト2を実行すると、以下のように1度のHTTPリクエストで1,000件のProductItemオブジェクトを取得することができます。
ちなみにこの時の消費RUは 380.96 となりました。