パフォーマンスの向上

このドキュメントでは、アプリケーションのパフォーマンスの向上に利用できるテクニックについていくつか説明します。わかりやすく説明するために他の API や汎用 API を例として使用する場合もありますが、DCM/DFA Reporting and Trafficking API にも同じ概念が適用されます。

gzip を使用した圧縮

リクエストごとに必要な帯域幅を減らすには、gzip 圧縮を有効にするのが簡単で便利な方法です。圧縮を行うと展開が必要になる分 CPU 時間が長くなりますが、多くの場合、そのデメリットを大きく上回るネットワーク コストの節約効果が得られます。

gzip でエンコードされたレスポンスを受け取るには、2 つの準備作業が必要です。1 つは、Accept-Encoding ヘッダーを設定すること、もう 1 つは、ユーザー エージェントに gzip という文字列を追加することです。gzip 圧縮を有効にする正しい HTTP ヘッダーの例を次に示します。

Accept-Encoding: gzip
User-Agent: my program (gzip)

部分リソースを使用した作業

API 呼び出しのパフォーマンスを向上させるもう 1 つの方法は、対象となるデータの一部分だけを送受信する方法です。こうすることで、アプリケーションの側で不必要なフィールドの転送、解析、格納をせずに済むので、ネットワーク、CPU、メモリなどのリソースをより効率良く利用できるようになります。

部分リクエストには次の 2 種類があります。

  • 部分レスポンス: レスポンスに含めるフィールドを指定するリクエスト(fields リクエスト パラメータを使用)。
  • パッチ: 変更するフィールドのみを送信する更新リクエスト(PATCH HTTP 動詞を使用)。

以下では部分リクエストの実行方法について詳しく説明します。

部分レスポンス

デフォルトでは、サーバーはリクエストの処理後に、完全に表示された形のリソースを送り返します。パフォーマンスを向上させるため、本当に必要なフィールドだけを送信するようサーバーに指示し、代わりに「部分レスポンス」を取得することができます。

部分レスポンスをリクエストするには、fields リクエスト パラメータを使用して取得するフィールドを指定します。このパラメータは、レスポンス データを返す任意のリクエストで使用できます。

fields パラメータはレスポンス データにのみ影響を与えます。送信する必要があるデータには影響を与えません。リソースを変更する際に送信するデータの量を減らすには、パッチ リクエストを使用します。

JSON

以下の例では、fields パラメータの使い方を汎用的な(架空の)Demo API を用いて示します。

シンプルなリクエスト: 次の HTTP GET リクエストでは fields パラメータを省略し、リソース全体を取得します。

https://www.googleapis.com/demo/v1

完全なリソース レスポンス: 完全なリソースデータには、次のようなフィールドが含まれます。ここでは、わかりやすくするために多数のフィールドを省略しています。

{
  "kind": "demo",
  ...
  "items": [
  {
    "title": "First title",
    "comment": "First comment.",
    "characteristics": {
      "length": "short",
      "accuracy": "high",
      "followers": ["Jo", "Will"],
    },
    "status": "active",
    ...
  },
  {
    "title": "Second title",
    "comment": "Second comment.",
    "characteristics": {
      "length": "long",
      "accuracy": "medium"
      "followers": [ ],
    },
    "status": "pending",
    ...
  },
  ...
  ]
}

部分的レスポンスのリクエスト: 同じリソースに対する次のリクエストでは、fields パラメータを使用しているため、返されるデータが大幅に少なくなります。

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

部分的レスポンス: サーバーは、上記のリクエストに対するレスポンスで、種類情報(kind)と、各アイテムの HTML タイトル(title)および長さの特性情報(characteristics)のみを格納した items 配列を返します。

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

JSON オブジェクトであるこのレスポンスには、指定したフィールドとその親オブジェクトしか含まれていないことに注目してください。

次のセクションで、fields パラメータの形式の指定方法について説明し、さらにその後に、レスポンスとして返される具体的な内容について詳細に説明します。

fields パラメータの構文について

fields リクエスト パラメータの形式は、XPath の構文に基づいています。サポートされる構文の概要を以下に示し、次のセクションでその他の例を示します。

  • 複数のフィールドを選択する場合は、カンマ区切りのリストを使用する。
  • フィールド a 内にネストされているフィールド b を選択するには a/b と指定します。b 内にネストされているフィールド c を選択するには a/b/c と指定します。

    例外: データラッパーを使用する API レスポンスは、data: { ... } のように data オブジェクト内にネストされているので、fields の指定に data を含めません。data/a/b のように、fields の指定に data オブジェクトを含めるとエラーになります。この場合は、fieldsa/b のように指定してください。

  • 配列またはオブジェクトの特定のサブフィールド セットをリクエストする場合は、サブセレクタを使用し、かっこ「( )」の中に式を記述する。

    たとえば、fields=items(id,author/email) と指定すると、items 配列内の各要素について、アイテム ID と作者のメールアドレスのみが返されます。サブフィールドは 1 つだけでもかまいません。たとえば、fields=items(id) と指定するのと fields=items/id と指定するのは同じことです。

  • フィールドの選択では、必要に応じてワイルドカードを使用する。

    たとえば fields=items/pagemap/* とすると、pagemap のすべてのオブジェクトが選択されます。

fields パラメータのその他の使用例

以下にいくつか例を挙げて、fields パラメータ値がレスポンスに与える影響を説明します。

注: 他のすべてのクエリ パラメータの値と同じように、fields パラメータ値には URL エンコードを使用する必要があります。読みやすくするために、このドキュメントの例ではエンコードを省略します。

取得するフィールドを特定する(フィールド選択を行う)
fields リクエスト パラメータ値はフィールドのカンマ区切りのリストであり、各フィールドは、レスポンスのルートからの相対位置で指定します。そのため、list 操作を実行した場合、レスポンスはコレクションとなり、通常はリソースの配列が含まれます。1 つのリソースを取得する操作を実行する場合は、そのリソースを基準位置としてフィールドを指定します。選択したフィールドが配列または配列の一部である場合、サーバーはその配列の選択された部分のすべての要素を返します。

以下はコレクション レベルの例です。
効果
items items 配列内のすべての要素を、各要素内のすべてのフィールドも含めて返します。他のフィールドは返しません。
etag,items etag フィールドと items 配列内のすべての要素を返します。
items/title items 配列内のすべての要素の title フィールドのみを返します。

ネストされたフィールドが返される場合は常に、フィールドを囲む親オブジェクトがレスポンスに含まれます。他の子フィールドは、同様にして明示的に選択しない限り、親フィールドには含まれません。
context/facets/label context オブジェクトにネストされている facets 配列内のすべてのメンバーの label フィールドのみを返します。
items/pagemap/*/title items 配列内の各要素について、pagemap のすべての子オブジェクトの title フィールド(存在する場合)のみを返します。

以下はリソースレベルの例です。
効果
title リクエストされたリソースの title フィールドを返します。
author/uri リクエストされたリソースの author オブジェクトの uri サブフィールドを返します。
links/*/href
links のすべての子オブジェクトの href フィールドを返します。
「サブ選択」を使用して特定のフィールドの一部分だけをリクエストする方法。
デフォルトでは、リクエストで特定のフィールドを指定した場合、サーバーはオブジェクトまたは配列要素全体を返します。特定のサブフィールドだけを含むレスポンスを指定することもできます。それには、下の例のように「( )」というサブ選択の構文を使用します。
効果
items(title,author/uri) items 配列内の各要素について、title の値と author の uri の値のみを返します。

部分的レスポンスの処理

fields クエリ パラメータを含む有効なリクエストを処理した後、サーバーは HTTP 200 OK ステータス コードとともにリクエストされたデータを返します。fields クエリ パラメータにエラーがある場合、またはパラメータが無効な場合、サーバーは、HTTP 400 Bad Request ステータス コードとフィールド選択の問題箇所を示すメッセージ(例: "Invalid field selection a/b")を返します。

上記の導入部で紹介した部分的レスポンスの例は次のとおりです。このリクエストでは、どのフィールドを返すかを fields パラメータで指定しています。

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

この場合の部分的レスポンスは次のようになります。

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

注: maxResultsnextPageToken など、データのページ設定のためのクエリ パラメータをサポートする API では、こうしたパラメータを使用して各クエリの結果を適切なサイズに制限してください。そうしないと、部分レスポンスで可能になるパフォーマンスの向上が得られないことがあります。

Atom

Atom データ形式は DCM/DFA Reporting and Trafficking API ではサポートされていません。

パッチ(部分更新)

リソースを変更する際に不要なデータの送信を避けることもできます。変更しようとする特定のフィールドについてのみ更新されたデータを送信するには、HTTP の PATCH 動詞を使用します。このドキュメントで説明するパッチの意味は、従来の GData による部分更新の実装の場合とは異なり、よりシンプルになっています。

パッチを使用することで、少量の更新をする場合に必要な送信データが最小限に抑えられます。ここではその簡単な例を紹介します。

JSON

この例は、「Demo」という汎用的な(架空)の API リソースのタイトルだけを更新する簡単なパッチ リクエストです。リソースには、コメント、特徴のセット、ステータスなど、多数のフィールドがありますが、このリクエストで変更するのは title フィールドのみですので、このフィールドだけを送信します。

PATCH https://www.googleapis.com/demo/v1/324
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "title": "New title"
}

レスポンス

200 OK
{
  "title": "New title",
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "accuracy": "high",
    "followers": ["Jo", "Will"],
  },
  "status": "active",
  ...
}

サーバーからは、200 OK のステータス コードと更新されたリソースが完全な表現で返されます。パッチ リクエストに含まれていたのは title フィールドだけなので、更新前と異なるのはこのフィールドだけです。

注: 部分レスポンスfields パラメータをパッチと組み合わせて使用すれば、更新リクエストの効率をさらに高めることができます。パッチ リクエストはリクエストのサイズのみを小さくし、部分的レスポンスはレスポンスのサイズのみを小さくします。このことから、双方向のデータ送信量を削減するには、パッチ リクエストに fields パラメータを指定します。

パッチ リクエストの意味

パッチ リクエストの本文には、変更するリソース フィールドだけを含めます。フィールドを指定する際は、部分レスポンスでフィールドを囲む親が返されるのとまったく同様に、フィールドを囲む親オブジェクトをすべて含める必要があります。変更されたデータを送信すると、親オブジェクトのデータが存在する場合は、そのデータにマージされます。

  • 追加: まだ存在しないフィールドを追加するには、新しいフィールドとその値を指定します。
  • 変更: 既存のフィールドの値を変更するには、フィールドを指定し、そのフィールドに新しい値を設定します。
  • 削除: フィールドを削除するには、そのフィールドを指定し null に設定します。たとえば、"comment": null などとします。オブジェクト全体を削除するには(オブジェクトが変更可能な場合)、オブジェクトに null を設定します。Java API クライアント ライブラリを使用する場合は、代わりに Data.NULL_STRING を使用します。詳細については、JSON null をご覧ください。

配列についての注意: 配列が含まれるパッチ リクエストでは、既存の配列が指定した配列に置き換えられます。配列内の項目を個別に変更、追加、または削除することはできません。

読み取り / 変更 / 書き込みサイクルでのパッチの使用

パッチ リクエストを使用する場合は、まず部分的レスポンスで変更が必要なデータを取得することをおすすめします。これは、ETag を使用するリソースでは特に重要になります。このようなリソースは、If-Match HTTP ヘッダーに最新の ETag 値を指定しないと、正常に更新できないからです。データを取得したら、値の変更を設定し、変更部分のみを記述した部分的な表現をパッチ リクエストで送り返します。次の例は、demo リソースで ETag が使用されていることを前提としています。

GET https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token

部分レスポンスは次のようになります。

200 OK
{
  "etag": "ETagString"
  "title": "New title"
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "level": "5",
    "followers": ["Jo", "Will"],
  }
}

次のパッチ リクエストはレスポンスに基づくものです。以下に示すとおり、このリクエストでは fields パラメータを使用して、パッチ レスポンスで返されるデータを制限しています。

PATCH https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json
If-Match: "ETagString"
{
  "etag": "ETagString"
  "title": "",                  /* Clear the value of the title by setting it to the empty string. */
  "comment": null,              /* Delete the comment by replacing its value with null. */
  "characteristics": {
    "length": "short",
    "level": "10",              /* Modify the level value. */
    "followers": ["Jo", "Liz"], /* Replace the followers array to delete Will and add Liz. */
    "accuracy": "high"          /* Add a new characteristic. */
  },
}

サーバーは 200 OK の HTTP ステータス コードで応答します。更新されたリソースの部分表現は次のようになります。

200 OK
{
  "etag": "newETagString"
  "title": "",                 /* Title is cleared; deleted comment field is missing. */
  "characteristics": {
    "length": "short",
    "level": "10",             /* Value is updated.*/
    "followers": ["Jo" "Liz"], /* New follower Liz is present; deleted Will is missing. */
    "accuracy": "high"         /* New characteristic is present. */
  }
}

パッチ リクエストを直接作成する方法

パッチ リクエストによっては、以前に取得したデータをもとに作成しなければならないことがあります。たとえば、配列に項目を追加するものの既存の配列要素をすべて残す場合は、先に既存のデータを取得しておく必要があります。同様に、API で ETag を使用する場合は、リソースを正しく更新するために、リクエストを使用して以前の ETag 値を送信する必要があります。

注: HTTP の "If-Match: *" ヘッダーを使用して、ETag の使用中にパッチの実行を強制できます。そうすれば、書き込みの前に読み取りを実行する必要がなくなります。

上記以外の場合は、既存のデータを先に取得せずにパッチ リクエストを直接作成することができます。たとえば、フィールドを新しい値に更新するパッチ リクエストや、新しいフィールドを追加するパッチ リクエストを簡単に作成できます。次に例を示します。

PATCH https://www.googleapis.com/demo/v1/324?fields=comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "comment": "A new comment",
  "characteristics": {
    "volume": "loud",
    "accuracy": null
  }
}

このリクエストは、comment フィールドに値が設定されている場合は新しい値で上書きし、設定されていない場合は新しい値を設定します。同様に、volume の特徴が存在する場合はその値が上書きされ、存在しない場合は作成されます。accuracy フィールドは、すでに設定されている場合は削除されます。

Atom

Atom データ形式は DCM/DFA Reporting and Trafficking API ではサポートされていません。

パッチへのレスポンスの処理

有効なパッチ リクエストを処理すると、API は、200 OK HTTP レスポンス コードと、変更済みリソース全体を返します。API で ETag が使用されている場合、サーバーは、パッチ リクエストが正常に処理されれば、PUT の場合とまったく同様に ETag の値を更新します。

パッチ リクエストでは、リクエストから返されるデータの量を減らすために fields パラメータを使用しない限り、リソース全体が返されます。

パッチ リクエストの結果として新しいリソースの状態が構文上あるいは意味上無効になった場合、サーバーは 400 Bad Request または 422 Unprocessable Entity の HTTP ステータス コードを返し、リソースの状態は変化しません。たとえば、必須フィールドの値を削除しようとした場合、サーバーはエラーを返します。

HTTP の PATCH 動詞がサポートされていない場合の代わりの表記法

ファイアウォールで HTTP の PATCH リクエストが許可されていない場合は、HTTP の POST リクエストを実行し、上書きヘッダーを PATCH に設定します。次に例を示します。

POST https://www.googleapis.com/...
X-HTTP-Method-Override: PATCH
...

パッチと更新の違い

HTTP の PUT 動詞を使用する更新リクエストのデータを送信する場合は、必須かオプションのどちらかのフィールドを送信するだけで済みます。サーバーによって設定されるフィールドの値を送信してもそれらは無視されます。そのため、この操作でも部分的更新を行えるように思えるかもしれませんが、この方法にはいくつかの制限事項があります。HTTP の PUT 動詞を使用する更新の場合、必須パラメータを指定しなければリクエストは失敗し、オプション パラメータを指定しなければ以前に設定されたデータがクリアされます。

このため、処理の安全性はパッチを使用した方がはるかに高くなります。変更するフィールドのデータを指定するだけで済み、省略したフィールドはクリアされません。ただし、唯一の例外として反復要素や反復配列があります。反復要素や反復配列をすべて省略した場合、それらはそのままの状態に保たれます。いずれかひとつでも指定した場合は、セット全体が指定したセットに置き換えられます。