Requêtes par lot

En raison de l'abandon des points de terminaison HTTP par lot mondiaux, les requêtes HTTP par lot qui ne ciblent que les API BigQuery cesseront de fonctionner le 1er juin 2021. Si votre application envoie des requêtes HTTP par lot, remplacez-les par des requêtes HTTP individuelles avant le 1er juin 2021.

Pour plus d'informations sur cet abandon, consultez la section suivante concernant les questions fréquentes. Pour obtenir de la documentation sur l'exécution de requêtes HTTP par lot, consultez la section Effectuer des requêtes par lot.

Questions fréquentes sur l'abandon de l'API HTTP par lot BigQuery

Pourquoi les requêtes HTTP par lot BigQuery sont-elles obsolètes ?

La prise en charge des points de terminaison HTTP par lot mondiaux reposait sur une architecture utilisant un seul proxy partagé afin de recevoir des requêtes pour toutes les API. Google ayant adopté une architecture hautes performances plus distribuée où les requêtes parviennent directement au serveur d'API approprié, nous ne pouvons plus prendre en charge ces points de terminaison mondiaux.

La prochaine étape est l'abandon des requêtes HTTP par lot BigQuery. Le service BigQuery est également distribué. Les méthodes avec un nombre élevé de requêtes par seconde sont gérées par des backends dédiés. Toutes les régions sont isolées, mais les requêtes HTTP par lot peuvent entraîner une distribution ramifiée des requêtes entre les régions. Cela rend l'exécution par lot inefficace et peut générer une latence de traitement plus élevée, contrairement à l'objectif initial de la prise en charge des requêtes HTTP par lot.

Plus précisément, qu'est-ce qui est obsolète ?

Les méthodes de requête par lot suivantes pour l'interaction avec les API BigQuery ne fonctionneront plus :

Comment procéder à la migration ?

La plupart des utilisateurs BigQuery n'utilisent pas les requêtes HTTP par lot. Si vous utilisez encore des requêtes par lot, utilisez les exemples suivants pour remplacer les requêtes HTTP par lot par des requêtes HTTP individuelles.

REST

Envoyez des requêtes HTTP individuelles, comme indiqué dans la section de référence de l'API BigQuery. Ne combinez pas vos requêtes par lot à l'aide du chemin /batch/v2/bigquery.

JavaScript

Si vous utilisez JavaScript, vous commencez avec un bloc de code qui se présente comme suit :

// 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))

Remplacez le bloc de code précédent par un bloc de code semblable à ce qui suit :

// 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

Si vous utilisez Python, vous commencez avec un bloc de code qui se présente comme suit :

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)

Remplacez le bloc de code précédent par un bloc de code semblable à ce qui suit :

# 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

Autres langages

Comme dans les exemples précédents, remplacez les appels BatchRequest par des requêtes individuelles.

Obtenir de l'aide pour la migration

Pour obtenir de l'aide concernant la migration, vous pouvez poser des questions sur Stack Overflow. Les ingénieurs de Google surveillent les questions comportant le tag google-bigquery et y répondent. Utilisez ce tag lorsque vous posez vos questions. Notre objectif est de répondre à toutes les questions dans un délai raisonnable.

Effectuer des requêtes par lot

Ce document explique comment autoriser les appels d'API par lot pour réduire le nombre de connexions HTTP que votre client doit effectuer.

Vous allez plus spécifiquement apprendre à exécuter une requête par lot en envoyant une requête HTTP. Si vous souhaitez plutôt exécuter ce type de requête à l'aide d'une bibliothèque cliente Google, consultez la documentation associée à la bibliothèque en question.

Présentation

Chaque connexion HTTP effectuée par votre client entraîne certains coûts. L'API BigQuery accepte les requêtes par lot, ce qui permet à votre client d'intégrer plusieurs appels d'API dans une seule requête HTTP.

Voici quelques exemples de situations dans lesquelles l'utilisation de requêtes par lot peut s'avérer utile :

  • Vous commencez tout juste à utiliser l'API et avez beaucoup de données à importer.
  • Un utilisateur a modifié des données lorsque votre application était hors connexion (déconnectée d'Internet). Celle-ci doit donc envoyer un certain nombre d'opérations de mise à jour et de suppression pour synchroniser ses données locales avec le serveur.

Dans chacun de ces cas, vous pouvez regrouper plusieurs appels en une seule requête HTTP plutôt que de les envoyer séparément. Toutes les requêtes internes doivent être transmises à la même API Google.

Une même requête par lot peut contenir jusqu'à 1 000 appels. Si vous avez besoin d'effectuer plus d'appels, exécutez plusieurs requêtes par lot.

Remarque : Le système de requêtes par lot de l'API Google BigQuery utilise la même syntaxe que le système de traitement par lot OData, mais la sémantique diffère.

Informations sur les lots

Une requête par lot est constituée de plusieurs appels d'API combinés en une seule requête HTTP, qui peut être envoyée au chemin batchPath spécifié dans le document de découverte des API. Le chemin par défaut est /batch/api_name/api_version. Cette section décrit la syntaxe des requêtes par lot plus en détail. Vous en trouverez un exemple plus bas.

Remarque : Un ensemble de n requêtes regroupées est comptabilisé comme n requêtes dans votre limite d'utilisation, et non comme une seule. Avant d'être traitée, la requête par lot est décomposée en un ensemble de requêtes.

Format d'une requête par lot

Une requête par lot est une requête HTTP standard unique qui comprend plusieurs appels d'API BigQuery et utilise le type de contenu multipart/mixed. Chacune des parties de cette requête HTTP principale contient une requête HTTP imbriquée.

Chaque partie commence par son en-tête HTTP Content-Type: application/http, mais peut également comporter un en-tête Content-ID facultatif. Les en-têtes des différentes parties ne servent toutefois qu'à signaler le début des parties et sont séparés de la requête imbriquée. Une fois que le serveur a décomposé la requête par lot en requêtes distinctes, les en-têtes de parties sont ignorés.

Le corps de chaque partie est lui-même composé d'une requête HTTP complète dotée de son propre verbe, de son URL, de ses en-têtes et de son corps. Comme les requêtes par lot n'acceptent pas les URL complètes, la requête HTTP ne doit contenir que le chemin de l'URL.

Les en-têtes HTTP des requêtes par lot externes s'appliquent à toutes les requêtes au sein du lot, à l'exception des en-têtes Content- tels que Content-Type. Si vous spécifiez un en-tête HTTP spécifique à la fois dans la requête externe et dans un appel individuel, la valeur de l'en-tête de l'appel individuel remplace alors celle de la requête par lot externe. Les en-têtes d'un appel individuel ne s'appliquent qu'à cet appel.

Par exemple, si vous fournissez un en-tête "Authorization" à un appel spécifique, l'en-tête ne s'applique qu'à cet appel. Mais si vous fournissez un en-tête "Authorization" à la requête externe, il s'applique à tous les appels individuels, sauf s'ils le remplacent par leurs propres en-têtes "Authorization".

Lorsque le serveur reçoit la requête par lot, il applique les paramètres de requête et les en-têtes (selon le cas) de la requête externe à chaque partie, puis traite ces parties comme s'il s'agissait de requêtes HTTP distinctes.

Réponse à une requête par lot

La réponse du serveur est une réponse HTTP standard unique avec un type de contenu multipart/mixed. Chaque partie constitue la réponse à l'une des requêtes de la requête par lot et apparaît dans le même ordre que celles-ci.

À l'instar des parties de la requête, les parties de la réponse contiennent chacune une réponse HTTP complète, qui comprend un code d'état, des en-têtes et un corps. Elles sont aussi précédées d'un en-tête Content-Type signalant le début de la partie.

Si une partie donnée de la requête possède un en-tête Content-ID, la partie correspondante de la réponse dispose alors du même en-tête Content-ID, avec une valeur initiale précédée de la chaîne response-, comme le montre l'exemple suivant.

Remarque : Le serveur peut effectuer vos appels dans n'importe quel ordre. Ne vous attendez pas à ce qu'ils soient exécutés selon l'ordre dans lequel vous les avez spécifiés. Si vous souhaitez que deux appels se produisent dans un ordre donné, évitez de les envoyer dans la même requête. Vous devez plutôt envoyer le premier appel seul, attendre la réponse, puis envoyer le second.

Exemple

L'exemple suivant illustre l'utilisation du traitement par lot avec une API de démonstration générique (fictive) appelée API Farm. Notez toutefois que les mêmes concepts s'appliquent à l'API BigQuery.

Exemple de requête par lot

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--

Exemple de réponse par lot

Il s'agit de la réponse à l'exemple de requête abordé dans la section précédente.

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--