バッチ リクエスト

グローバル バッチ HTTP エンドポイントの非推奨に伴い、BigQuery API のみを対象とするバッチ HTTP リクエストは 2021 年 6 月 1 日をもって動作しなくなります。アプリケーションがバッチ HTTP リクエストを送信する場合は、2021 年 6 月 1 日までにバッチ HTTP リクエストを個々の HTTP リクエストに置き換えてください

非推奨の詳細については、次のよくある質問をご覧ください。HTTP リクエストをバッチ処理する方法については、リクエストのバッチ処理をご覧ください。

BigQuery バッチ HTTP API の非推奨に関するよくある質問

BigQuery バッチ HTTP リクエストが非推奨になるのはなぜですか?

グローバル HTTP バッチ エンドポイントのサポートは、1 つの共有プロキシを使用してすべての API のリクエストを受信するアーキテクチャをベースにしていました。Google では、リクエストが適切な API サーバーに直接送信される分散型の高パフォーマンス アーキテクチャに移行したため、これらのグローバル エンドポイントがサポートされなくなりました

次のステップとして BigQuery バッチ HTTP リクエストが非推奨になります。BigQuery サービスも分散しています。高 QPS メソッドは専用のバックエンドで処理されます。すべてのリージョンが分離されていますが、バッチ HTTP リクエストにより、リージョン間のリクエストがファンアウトする可能性があります。これにより、バッチ処理が非効率的になり、処理レイテンシが増加する可能性があります。これは、バッチ HTTP リクエスト サポートの当初の目標とは逆の結果です。

具体的に何が非推奨になりますか?

BigQuery API を操作する次のバッチ リクエスト メソッドは機能しなくなります。

移行するにはどうすればよいですか?

ほとんどの BigQuery ユーザーはバッチ HTTP リクエストを使用していません。バッチ リクエストを使用している場合は、次の例を使用して、バッチ HTTP リクエストを個々の HTTP リクエストに置き換えてください。

REST

BigQuery API リファレンス セクションの説明に従って、個々の HTTP リクエストを送信します。/batch/v2/bigquery パスを使用してリクエストをバッチ処理しないでください。

JavaScript

JavaScript を使用している場合、コードブロックは次のようになります。

// Notice that the outer batch request contains inner API requests
// for two different APIs.

// Request to urlshortener API
request1 = gapi.client.urlshortener.url.get({"shortUrl":
"http://goo.gl/fbsS"});

// Request to zoo API
request2 = gapi.client.zoo.animals.list();

// Request to urlshortener API
request3 = gapi.client.urlshortener.url.get({"shortUrl":
"https://goo.gl/XYFuPH"});

// Request to zoo API
request4 = gapi.client.zoo.animal().get({"name": "giraffe"});

// Creating a batch request object
batchRequest = gapi.client.newBatch();
// adding the 4 batch requests
batchRequest.add(request1);
batchRequest.add(request2);
batchRequest.add(request3);
batchRequest.add(request4);
// print the batch request
batchRequest.then(x=>console.log(x))

上のコードブロックを、次のようなコードブロックに置き換えます。

// Request to urlshortener API
request1 = gapi.client.urlshortener.url.get({"shortUrl": "http://goo.gl/fbsS"});

// Request to zoo API
request2 = gapi.client.zoo.animals.list();

// Request to urlshortener API
request3 = gapi.client.urlshortener.url.get({"shortUrl": "http://goo.gl/fbsS"})

// Request to zoo API
request4 = gapi.client.zoo.animals.list();

// print the 4 individual requests
Promise.all([request1, request2, request3, request4])
    .then(x=>console.log(x));

Python

Python を使用する場合、コードブロックは次のようになります。

from apiclient.http import BatchHttpRequest

def insert_animal(request_id, response, exception):
  if exception is not None: # Do something with the exception
    pass
  else: # Do something with the response
    pass

service = build('farm', 'v2')
batch = service.new_batch_http_request(callback=insert_animal)
batch.add(service.animals().insert(name="sheep"))
batch.add(service.animals().insert(name="pig"))
batch.add(service.animals().insert(name="llama"))
batch.execute(http=http)

上のコードブロックを、次のようなコードブロックに置き換えます。

# import a new API to create a thread pool
from concurrent.futures import ThreadPoolExecutor as PoolExecutor

def run_it(request):
  print(request.execute())

service = build('farm', 'v2')
request1 = service.animals().insert(name="sheep")
request2 = service.animals().insert(name="pig")
request3 = service.animals().insert(name="llama")
with PoolExecutor(max_workers=4) as executor:
  for _ in executor.map(run_it,[request1, request2, request3]):
    pass

その他の言語

前の例と同様に、BatchRequest の呼び出しを個別のリクエストに置き換えます。

移行のサポート

移行について不明な点がある場合は、Stack Overflow で質問できます。google-bigquery のタグが付いている質問は、Google のエンジニアがチェックして回答しています。質問するときは、このタグを使用してください。Google では、すべての質問に対して、なるべく早く回答するように努力しています。

一括処理リクエスト

ここでは、複数のバッチ API 呼び出しを行って、クライアント側の HTTP 接続の回数を減らす方法について説明します。

具体的には、1 件の HTTP リクエストを送信してバッチ リクエストを行う方法を取り上げます。Google クライアント ライブラリを使用してバッチ リクエストを行う場合は、クライアント ライブラリのドキュメントをご覧ください。

概要

クライアントで HTTP 接続を行うたびに、ある程度のオーバーヘッドが発生します。BigQuery API ではバッチ処理がサポートされており、クライアントは複数の API 呼び出しを 1 つの HTTP リクエストにまとめることができます。

バッチ処理は次のような状況で使用します。

  • API の使用を開始したばかりで、アップロードするデータが大量にある。
  • アプリケーションがオフライン(インターネットに接続されていない状態)のときにユーザーがデータを変更したため、更新や削除の呼び出しを大量に送信してローカルデータとサーバー間で同期させる必要がある。

いずれの場合も、各呼び出しを個別に送信するのではなく、1 つの HTTP リクエストにまとめることができます。内部リクエストはすべて同じ Google API に送信する必要があります。

1 つのバッチ リクエストに含めることができる呼び出しの上限は 1,000 個です。これ以上の呼び出しを行う必要がある場合は、バッチ リクエストを複数使用します。

: BigQuery API のバッチシステムは OData バッチ処理システムと同じ構文を使用しますが、セマンティクスは異なります。

バッチ リクエストの詳細

バッチ リクエストは、複数の API 呼び出しを 1 つの HTTP リクエストにまとめたもので、API ディスカバリ ドキュメントで指定されている batchPath に送信できます。デフォルトのパスは /batch/api_name/api_version です。このセクションでは、バッチ リクエストの構文について詳しく説明し、最後にを紹介します。

: n 件のリクエストを 1 つにまとめたバッチ リクエストは、1 件のリクエストではなく n 件のリクエストとして使用量上限に加算されます。バッチ リクエストは、個々のリクエストに分割されてから処理されます。

バッチ リクエストの形式

バッチ リクエストは multipart/mixed コンテンツ タイプを使用した単一の標準 HTTP リクエストで、複数の BigQuery API 呼び出しから構成されます。そのメインの HTTP リクエスト内の各パーツには、ネストされた HTTP リクエストが含まれます。

各パーツはそれぞれ Content-Type: application/http という形式の HTTP ヘッダーで始まり、オプションの Content-ID ヘッダーを指定することもできます。ただし、パーツヘッダーはパーツの開始箇所を示すためだけに存在していて、ネストされたリクエストとは分かれています。サーバーがバッチ リクエストを別々のリクエストにアンラップした後、パーツヘッダーは無視されます。

各パーツのボディは、独自の動詞、URL、ヘッダー、ボディを含む完全な HTTP リクエストです。これらの HTTP リクエストには URL のパス部分のみを含める必要があり、完全な URL は、バッチ リクエストでは許可されていません。

外側のバッチ リクエストの HTTP ヘッダー(Content-Type などの Content- ヘッダー以外)はバッチ リクエスト内の各リクエストに適用されます。ある HTTP ヘッダーを外側のリクエストと個々の呼び出しの両方で指定した場合、個々の呼び出しのヘッダー値は外側のバッチ リクエストのヘッダー値を上書きします。個々の呼び出しのヘッダーはその呼び出しにのみ適用されます。

たとえば、ある呼び出しに Authorization ヘッダーを指定した場合、そのヘッダーはその呼び出しにのみ適用されます。Authorization ヘッダーを外側のリクエストに指定した場合、そのヘッダーはすべての呼び出しに適用されます。ただし、各呼び出しに独自の Authorization ヘッダーを指定している場合は各呼び出しの Authorization ヘッダーで上書きされます。

サーバーがバッチ リクエストを受信すると、外側のリクエストのクエリ パラメータとヘッダー(指定した場合)を各パーツに適用し、各パーツを個別の HTTP リクエストとして処理します。

バッチ リクエストへのレスポンス

サーバーのレスポンスは multipart/mixed コンテンツ タイプを使用した単一の標準 HTTP レスポンスです。各パーツはバッチ リクエスト内の個々のリクエストに対するレスポンスで、リクエストと同じ順序にネストされます。

レスポンスの各パーツは、リクエストのパーツと同様にステータス コード、ヘッダー、ボディを含む完全な HTTP レスポンスになっています。また、リクエストのパーツと同様に、レスポンスの各パーツはパーツの開始箇所を示す Content-Type ヘッダーから始まります。

リクエストのパーツに Content-ID ヘッダーがある場合、対応するレスポンスのパーツには、それに一致する Content-ID ヘッダーが指定されます。レスポンスのパーツのヘッダーは、以下の例に示すように、元の値の先頭に文字列 response- が付いた値となります。

: サーバーはバッチ リクエスト内の呼び出しを順番どおりに処理するとは限りません。指定した順序で実行されると想定しないでください。2 つの呼び出しを特定の順序で実行したい場合は、1 つのバッチ リクエストで送信することはできません。代わりに、最初の呼び出しを送信してレスポンスが返ってきてから、2 番目の呼び出しを送信します。

次の例では、Farm API という一般的な(架空の)デモ API にバッチ処理を使用しています。同じ考え方が BigQuery API にも当てはまります。

バッチ リクエストの例

POST /batch/farm/v1 HTTP/1.1
Authorization: Bearer your_auth_token
Host: www.googleapis.com
Content-Type: multipart/mixed; boundary=batch_foobarbaz
Content-Length: total_content_length

--batch_foobarbaz
Content-Type: application/http
Content-ID: <item1:12930812@barnyard.example.com>

GET /farm/v1/animals/pony

--batch_foobarbaz
Content-Type: application/http
Content-ID: <item2:12930812@barnyard.example.com>

PUT /farm/v1/animals/sheep
Content-Type: application/json
Content-Length: part_content_length
If-Match: "etag/sheep"

{
  "animalName": "sheep",
  "animalAge": "5"
  "peltColor": "green",
}

--batch_foobarbaz
Content-Type: application/http
Content-ID: <item3:12930812@barnyard.example.com>

GET /farm/v1/animals
If-None-Match: "etag/animals"

--batch_foobarbaz--

バッチ レスポンスの例

これは、前のセクションのリクエスト例に対するレスポンスです。

HTTP/1.1 200
Content-Length: response_total_content_length
Content-Type: multipart/mixed; boundary=batch_foobarbaz

--batch_foobarbaz
Content-Type: application/http
Content-ID: <response-item1:12930812@barnyard.example.com>

HTTP/1.1 200 OK
Content-Type application/json
Content-Length: response_part_1_content_length
ETag: "etag/pony"

{
  "kind": "farm#animal",
  "etag": "etag/pony",
  "selfLink": "/farm/v1/animals/pony",
  "animalName": "pony",
  "animalAge": 34,
  "peltColor": "white"
}

--batch_foobarbaz
Content-Type: application/http
Content-ID: <response-item2:12930812@barnyard.example.com>

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: response_part_2_content_length
ETag: "etag/sheep"

{
  "kind": "farm#animal",
  "etag": "etag/sheep",
  "selfLink": "/farm/v1/animals/sheep",
  "animalName": "sheep",
  "animalAge": 5,
  "peltColor": "green"
}

--batch_foobarbaz
Content-Type: application/http
Content-ID: <response-item3:12930812@barnyard.example.com>

HTTP/1.1 304 Not Modified
ETag: "etag/animals"

--batch_foobarbaz--