Processamento em lote no protocolo de dados do Google

O processamento em lote permite que você execute várias operações em uma solicitação, em vez de precisar enviar cada operação individualmente.

Observação: para realizar operações em lote, você precisa usar uma versão recente da biblioteca de cliente da API Google Data. As operações em lote não são compatíveis com a biblioteca de cliente JavaScript.

Público-alvo

Este documento é destinado a programadores que queiram enviar várias operações em uma única solicitação usando o processamento em lote.

Ele pressupõe que você esteja familiarizado com a biblioteca de cliente Java para dados do Google. Os exemplos neste documento mostram como usar a biblioteca de cliente Java para executar operações em lote.

Os exemplos neste documento são específicos para a API Google Base Data. No entanto, outros serviços também podem oferecer recursos em lote.

Observação:o protocolo e os procedimentos gerais serão os mesmos para outras bibliotecas de cliente, mas os métodos específicos para executar solicitações em lote podem ser diferentes. Consulte a documentação específica da biblioteca de cliente.

Introdução

Com um feed em lote do GData, é possível coletar várias operações de inserção, atualização, exclusão e consulta e, em seguida, enviar e executar todas de uma vez.

Por exemplo, o feed a seguir inclui quatro operações:

<feed>
  <entry>
    <batch:operation type="insert"/>
    ... what to insert ...
  </entry> 
  <entry>
    <batch:operation type="update"/>
    ... what to update ...
  </entry>
  <entry>
    <batch:operation type="delete"/>
    ... what to delete ...
  </entry>
  <entry>
    <batch:operation type="query"/>
    ... what to query ...
  </entry>
</feed>

O serviço realizará o maior número possível de alterações solicitadas e retornará informações de status que podem ser usadas para avaliar o sucesso ou a falha de cada operação.

O serviço tenta executar cada uma das operações em um lote, mesmo que algumas das operações incluídas nele não tenham êxito.

Como enviar uma solicitação em lote

Uma solicitação em lote deve ser enviada como POST HTTP para um URL em lote. Feeds diferentes oferecem suporte a operações em lote distintas. Os feeds somente leitura são compatíveis apenas com consultas.

Para descobrir se um determinado feed oferece suporte a operações em lote, é possível consultar o feed. Se o feed contém uma relação de vinculação em "lote" no nível do feed, isso indica que ele é compatível com operações em lote.

Uma relação de link "em lote" é um elemento <link> com rel="http://schemas.google.com/g/2005#batch". O atributo href da relação do link define o URL em que os documentos do feed para operações em lote podem ser postados.

Por exemplo, se você executar: GET http://www.google.com/base/feeds/items (o feed normal de "itens" do Google Base), poderá receber a seguinte resposta:

<feed xmlns=...
  <id>http://www.google.com/base/feeds/items</id>
  <link rel="http://schemas.google.com/g/2005#feed"
    type="application/atom+xml"
    href="http://www.google.com/base/feeds/items"/>
  <link rel="http://schemas.google.com/g/2005#post"
    type="application/atom+xml"
    href="http://www.google.com/base/feeds/items"/>
  <link rel="http://schemas.google.com/g/2005#batch"
    type="application/atom+xml"
    href="http://www.google.com/base/feeds/items/batch"/>
  ...
</feed> 

Neste exemplo, o URL do lote é http://www.google.com/base/feeds/items/batch.

Como criar um feed de operações em lote

Um feed de operações contém uma lista de entradas para inserir, atualizar, excluir ou consultar. Cada operação é definida por um elemento <batch:operation type="insert|update|delete|query"/>.

Esse elemento pode ser filho direto de um elemento <feed>, de um filho direto de qualquer uma das entradas no feed ou de ambos. Quando incluída em uma entrada, ela especifica a operação a ser executada para essa entrada específica. Quando incluído no feed, esse elemento especifica a operação padrão a ser executada em todas as entradas que não têm um elemento <batch:operation/>.

Quando a entrada e o feed não especificam uma operação, a operação padrão é insert.

Os aplicativos não podem aplicar várias operações à mesma entrada em um único feed em lote. Os resultados serão indeterminados se você especificar várias operações para a mesma entrada.

Para melhorar o desempenho, não é possível processar as operações na ordem em que foram solicitadas. No entanto, o resultado final é sempre o mesmo se as entradas tivessem sido processadas em ordem.

O número de bytes no XML que você envia ao servidor não pode exceder 1 MB (1.048.576 bytes). Em geral, não há limites para o número de operações solicitadas, desde que o tamanho total do byte não exceda 1 MB. No entanto, alguns serviços podem ter outras restrições.

Para usar as operações em lote, é preciso adicionar a declaração de namespace em lote como um atributo ao elemento <feed>:

<feed 
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
  ...
  xmlns:batch="http://schemas.google.com/gdata/batch">

Inserir operações

Uma operação de inserção é indicada da seguinte forma:

<batch:operation type="insert">

Uma operação de inserção é equivalente a POSTAR a entrada. Quando a operação é bem-sucedida, todo o conteúdo da entrada é retornado, com um elemento <id> do documento atualizado e um <batch:status code="201"/>.

Veja um exemplo de uma solicitação de inserção bem-sucedida:

<entry>
  <title type="text">...</title>
  <content type="html">...</content>
  <batch:id>itemA</batch:id>
  <batch:operation type="insert"/>
  <g:item_type>recipes</g:item_type>
  ... 
</entry>

Veja um exemplo de resposta a uma solicitação de inserção:

<entry>
  <batch:status code="201"/>
  <batch:id>itemA</batch:id>
  <batch:operation type="insert"/>
  <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
  <link rel="self" type="application/atom+xml"
    href="http://www.google.com/base/feeds/items/17437536661927313949"/>
  <title type="text">...</title>
  <content type="html">...</content>
  <g:item_type>recipes</g:item_type>
  ... 
</entry>

Operações de atualização

<batch:operation type="update">

Uma operação de atualização é equivalente a executar um PUT no URL referenciado pelo elemento <id> da entrada. Quando a operação é bem-sucedida, todo o conteúdo da entrada é retornado com um elemento <batch:status code="200"/>.

Observação: com determinados feeds, também é necessário especificar o link rel="edit" da entrada com solicitações de atualização em lote. Isso inclui os feeds compatíveis com o estilo v1 do simultaneidade otimista do Protocolo de dados do Google e os feeds que não têm IDs que são URLs.

Veja um exemplo de uma solicitação de atualização:

<entry>
  <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
  <batch:operation type="update"/>
  ...
</entry>

Veja um exemplo de resposta:

<entry>
  <batch:status code="200"/>
  <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
  <batch:operation type="update"/>
  ... 
</entry>

Observação: alguns feeds usam ETags fortes para impedir que você modifique acidentalmente as alterações de outra pessoa. Ao fazer uma solicitação de atualização em lote para uma entrada em um desses feeds, é preciso fornecer o valor de ETag no atributo gd:etag da entrada. Por exemplo, <entry gd:etag="'F08NQAxFdip7IWA6WhVR'">...<batch:operation type="update"/>....

Operações de atualização parcial

Para feeds compatíveis com atualizações parciais, você também pode usá-los em solicitações em lote. Uma operação de atualização parcial é equivalente a executar um PATCH no URL referenciado pelo elemento <id> da entrada. Quando a operação é bem-sucedida, todo o conteúdo da entrada é retornado com um elemento <batch:status code="200"/>.

Observação: com determinados feeds, também é necessário especificar o link rel="edit" da entrada com solicitações de atualização em lote. Isso inclui os feeds compatíveis com o estilo v1 do simultaneidade otimista do Protocolo de dados do Google e os feeds que não têm IDs que são URLs.

<batch:operation type="patch"/>

Veja um exemplo de uma solicitação de atualização parcial:

<entry gd:fields="content" gd:etag="FE8LQQJJeSp7IWA6WhVa">
  <id>http://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID</id>
  <batch:operation type="patch"/>
  <title>New title</title>
</entry>

Veja a seguir uma explicação de uma resposta bem-sucedida:

<entry gd:etag="FE8LQQJJeSp7IWA6WhVa">
  <batch:status code="200"/>
  <id>http://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID</id>
  <batch:operation type="patch"/>
  <title>New title</title>
  <content></content>
  ...rest of the entry...
</entry>

Excluir operações

<batch:operation type="delete">

Uma operação de exclusão equivale a executar um DELETE no URL referenciado pelo elemento <id> da entrada. Para uma operação de exclusão, basta enviar um elemento <id> para excluir a entrada. Qualquer outra informação que você fornecer em elementos que não estejam no namespace batch: será ignorada. Quando a operação for bem-sucedida, uma entrada com o mesmo ID será retornada com um elemento <batch:status code="200"/>.

Observação: com determinados feeds, também é necessário especificar o link rel="edit" da entrada com uma solicitação de exclusão em lote. Isso inclui os feeds compatíveis com o estilo v1 do simultaneidade otimista do Protocolo de dados do Google e os feeds que não têm IDs que são URLs.

Veja um exemplo de uma solicitação de exclusão:

<entry>
  <batch:operation type="delete"/>
  <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
</entry>

Veja um exemplo de resposta:

<entry>
  <batch:operation type="delete"/>
  <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
  <batch:status code="200" reason="Success"/>
</entry>

Observação: alguns feeds usam ETags fortes para impedir que você modifique acidentalmente as alterações de outra pessoa. Ao fazer uma solicitação de exclusão em lote para uma entrada em um desses feeds, é preciso fornecer o valor de ETag no atributo gd:etag da entrada. Por exemplo, <entry gd:etag="'F08NQAxFdip7IWA6WhVR'">...<batch:operation type="delete"/>....

Operações de consulta

<batch:operation type="query">

Uma operação de consulta é equivalente a executar um GET no URL referenciado pelo elemento <id> da entrada. Quando a operação é bem-sucedida, todo o conteúdo da entrada é retornado.

Observação: com determinados feeds, também é necessário especificar o link rel="self" da entrada com solicitações de consulta em lote. Isso inclui os feeds que não têm IDs.

Veja um exemplo de uma solicitação de consulta:

<entry>
  <id>http://www.google.com/base/feeds/items/1743753666192313949</id>
  <batch:operation type="query"/>
</entry>

Veja um exemplo de resposta:

<entry>
  <id>http://www.google.com/base/feeds/items/1743753666192313949</id>
  <batch:operation type="query"/>
  <batch:status code="200" reason="Success"/>
   ...
</entry>

Operações de rastreamento

Os resultados de entrada de dados não são necessariamente retornados na mesma ordem da solicitação. É possível rastrear uma operação durante todo o ciclo de vida dela usando um identificador.

Para operações de atualização, exclusão e consulta, use o ID da própria entrada para rastrear a operação.

Para operações de inserção, como nenhum ID ainda existe, é possível transmitir um identificador de operação. Esse identificador pode ser usado para vincular as entradas de resultado às entradas de solicitação. O identificador da operação é transmitido no elemento <batch:id>.

Para cada operação, o GData retorna uma resposta que informa se a operação foi bem-sucedida ou não. Cada resposta identifica a entrada relacionada. Para uma operação de atualização, exclusão ou consulta, ou uma operação de inserção bem-sucedida, o ID da entrada é sempre retornado. Se você tiver especificado um ID de lote, ele também será retornado. Como operações de inserção malsucedidas não têm um ID de entrada associado, apenas o código do lote é retornado.

Usando o identificador de cada operação, é possível repetir apenas as operações com falha, em vez de precisar reenviar todo o lote de operações.

O conteúdo do <batch:id> é um valor de string definido pelo cliente e vai ser retornado na entrada de resposta correspondente.É possível especificar qualquer valor que ajude o cliente a correlacionar a resposta com a entrada na solicitação original. Esse elemento será ecoado como está na entrada correspondente, mesmo se a operação falhar. O GData nunca armazena nem interpreta o conteúdo desse ID em lote.

O exemplo a seguir mostra um feed de operações em lote. Observe que o elemento <batch:id> rotula essa operação como itemB.

<entry>
  <title type="text">...</title>
  <content type="html">...</content>
  <batch:id>itemB</batch:id>
  <batch:operation type="insert"/>
  <g:item_type>recipes</g:item_type>
</entry>

O exemplo a seguir mostra a entrada do status do lote retornada em resposta a essa operação.

<entry>
  <id>http://www.google.com/base/feeds/items/2173859253842813008</id>
  <published>2006-07-11T14:51:43.560Z</published>
  <updated>2006-07-11T14:51: 43.560Z</updated>
  <title type="text">...</title>
  <content type="html">...</content>
  <link rel="self" 
    type="application/atom+xml" 
    href="http://www.google.com/base/feeds/items/2173859253842813008"/>
  <link rel="edit" 
    type="application/atom+xml" 
    href="http://www.google.com/base/feeds/items/2173859253842813008"/>
  <g:item_type>recipes</g:item_type>
  <batch:operation type="insert"/>
  <batch:id>itemB</batch:id>
  <batch:status code="201" reason="Created"/>
</entry>

Como processar códigos de status

Os códigos de status são expressos pelo seguinte elemento:

<batch:status code="200|201|404|500|..." reason="reason" [content-type="type"]/>

Cada entrada no feed de resposta contém um elemento <batch:status>. Esse elemento descreve o que aconteceu durante a execução da operação. Ela imita a resposta de HTTP que seria enviada se a operação tivesse sido enviada individualmente, e não como parte de um feed em lote.

Você precisa verificar o elemento <batch:status> de cada entrada na resposta para descobrir se a operação associada foi processada com êxito. O atributo code="n" contém um código de status do GData.

Descrições de status

O atributo reason="reason" do elemento <batch:status> contém uma explicação mais detalhada do status da operação.

Tipo de conteúdo

O atributo content-type="type" do elemento <batch:status> contém o tipo MIME dos dados contidos no elemento <batch:status>. Corresponde ao cabeçalho Content-Type de uma resposta de status HTTP. Esse atributo é opcional.

Quando o tipo de conteúdo é definido, o corpo do elemento <batch:status> descreve o que deu errado ao processar a entrada.

Como identificar operações interrompidas

O elemento a seguir é incluído na resposta de uma operação interrompida:

<batch:interrupted reason="reason" success="N" failures="N" parsed="N">

Esse elemento significa que o processamento em lote foi interrompido e todas as tentativas de recuperação da causa da interrupção falharam. Algumas entradas podem já ter sido processadas. Todas as entradas que não foram relatadas como bem-sucedidas antes desse ponto foram abandonadas.

Esse elemento é muito incomum e geralmente sinaliza que o feed enviado no corpo da solicitação não estava em um formato XML correto.

Assim como no elemento <batch:status>, um código de status curto pode ser encontrado no atributo reason. Uma resposta mais longa também pode ser encontrada dentro do elemento.

Exemplos de operações em lote e feeds de status

Veja um feed de operações em lote que pode ser enviado ao servidor. Esse feed solicita que o servidor exclua duas entradas e adicione duas novas. O elemento <feed> precisa incluir uma delegação de namespace para o lote, conforme destacado no exemplo abaixo.

POST : http://www.google.com/base/feeds/items/batch
<?xml version="1.0" encoding="UTF-8"?>
<feed
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
  xmlns:g="http://base.google.com/ns/1.0"
  xmlns:batch="http://schemas.google.com/gdata/batch">
  <title type="text">My Batch Feed</title>
  <entry>
    <id>http://www.google.com/base/feeds/items/13308004346459454600</id>
    <batch:operation type="delete"/>
  </entry>
  <entry>
    <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
    <batch:operation type="delete"/>
  </entry>
  <entry>
    <title type="text">...</title>
    <content type="html">...</content>
    <batch:id>itemA</batch:id>
    <batch:operation type="insert"/>
    <g:item_type>recipes</g:item_type>
  </entry>
  <entry>
    <title type="text">...</title>
    <content type="html">...</content>
    <batch:id>itemB</batch:id>
    <batch:operation type="insert"/>
    <g:item_type>recipes</g:item_type>
  </entry>
</feed>

Vamos supor que as duas inserções funcionaram, mas uma das duas exclusões falhou. Nesse caso, o feed de status do lote pode ter a seguinte aparência. As entradas foram reordenadas em comparação com o feed de operações em lote.

<?xml version="1.0" encoding="UTF-8"?>
<feed
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
  xmlns:g="http://base.google.com/ns/1.0"
  xmlns:batch="http://schemas.google.com/gdata/batch">
  <id>http://www.google.com/base/feeds/items</id>
  <updated>2006-07-11T14:51:42.894Z</updated>
  <title type="text">My Batch</title>
  <link rel="http://schemas.google.com/g/2005#feed"
    type="application/atom+xml"
    href="http://www.google.com/base/feeds/items"/>
  <link rel="http://schemas.google.com/g/2005#post"
    type="application/atom+xml"
    href="http://www.google.com/base/feeds/items"/>
  <link rel=" http://schemas.google.com/g/2005#batch"
    type="application/atom+xml"
    href="http://www.google.com/base/feeds/items/batch"/>
  <entry>
    <id>http://www.google.com/base/feeds/items/2173859253842813008</id>
    <published>2006-07-11T14:51:43.560Z</published>
    <updated>2006-07-11T14:51: 43.560Z</updated>
    <title type="text">...</title>
    <content type="html">...</content>
    <link rel="self"
      type="application/atom+xml"
      href="http://www.google.com/base/feeds/items/2173859253842813008"/>
    <link rel="edit"
      type="application/atom+xml"
      href="http://www.google.com/base/feeds/items/2173859253842813008"/>
    <g:item_type>recipes</g:item_type>
    <batch:operation type="insert"/>
    <batch:id>itemB</batch:id>
    <batch:status code="201" reason="Created"/>
  </entry>
  <entry>
    <id>http://www.google.com/base/feeds/items/11974645606383737963</id>
    <published>2006-07-11T14:51:43.247Z</published>
    <updated>2006-07-11T14:51: 43.247Z</updated>
    <title type="text">...</title>
    <content type="html">...</content>
    <link rel="self"
      type="application/atom+xml"
      href="http://www.google.com/base/feeds/items/11974645606383737963"/>
    <link rel="edit"
      type="application/atom+xml"
      href="http://www.google.com/base/feeds/items/11974645606383737963"/>
    <g:item_type>recipes</g:item_type>
    <batch:operation type="insert"/>
    <batch:id>itemA</batch:id>
    <batch:status code="201" reason="Created"/>
  </entry>
  <entry>
    <id>http://www.google.com/base/feeds/items/13308004346459454600</id>
    <updated>2006-07-11T14:51:42.894Z</updated>
    <title type="text">Error</title>
    <content type="text">Bad request</content>
    <batch:status code="404"
      reason="Bad request"
      content-type="application/xml">
      <errors>
        <error type="request" reason="Cannot find item"/>
      </errors>
    </batch:status>
  </entry>
  <entry>
    <id>http://www.google.com/base/feeds/items/17437536661927313949</id>
    <updated>2006-07-11T14:51:43.246Z</updated>
    <content type="text">Deleted</content>
    <batch:operation type="delete"/>
    <batch:status code="200" reason="Success"/>
  </entry>
</feed>

Como usar a funcionalidade em lote da biblioteca de cliente GData Java

Nesta seção, explicamos como usar a funcionalidade em lote da biblioteca de cliente Java para dados do Google para enviar um grupo de solicitações de inserção, atualização e/ou exclusão.

Os exemplos fornecidos nesta seção usam as APIs do Google Base.

Primeiro, importe as classes necessárias, além das classes padrão GData e Google Base:

import com.google.gdata.data.batch.*;
import com.google.api.gbase.client.*;

Para enviar uma solicitação em lote, é necessário encontrar o URL do lote de um feed. O snippet de código a seguir ilustra como fazer isso, supondo que feed é um objeto GoogleBaseFeed que contém informações sobre um feed:

Link batchLink = feed.getLink(Link.Rel.FEED_BATCH, Link.Type.ATOM);
if (batchLink != null) {
  URL batchUrl = new URL(batchLink.getHref());
  ... // batch handling
} else {
  // batching is not supported for this feed
}

O snippet de código a seguir prepara um feed que insere duas entradas em uma operação:

GoogleBaseEntry entry1 = new GoogleBaseEntry();
...   // initialize entry 1 content
BatchUtils.setBatchId(entry1, "A"); // A is the local batch ID for this entry
feed.addEntry(entry1);
GoogleBaseEntry entry2 = new GoogleBaseEntry();
... // initialize entry 2 content
BatchUtils.setBatchId(entry2, "B"); // B is the local batch ID for this entry
feed.addEntry(entry2);

O código neste exemplo nunca declara explicitamente que a operação a ser executada para essas entradas é insert. Não é necessário especificar explicitamente, porque a inserção é a operação padrão.

Para enviar o feed em lote e receber os resultados, chame o método Service.batch.

Como Service.insert, Service.batch retorna as entradas inseridas com novos valores de <atom:id> definidos. As entradas retornadas estão contidas em um objeto GoogleBaseFeed.

Para excluir uma terceira entrada (que você já buscou e armazenou em entry3) ao mesmo tempo em que inseriu as outras duas entradas, use este código:

GoogleBaseEntry toDelete = new GoogleBaseEntry();


toDelete.setId(entry3.getId());
BatchUtils.setBatchOperationType(toDelete, BatchOperationType.DELETE);

feed.addEntry(toDelete);


GoogleBaseFeed result = service.batch(batchUrl, feed);

Aqui, service é uma instância de com.google.gdata.client.Service.

Se você quiser atualizar uma entrada, especifique OperationType.UPDATE e inicialize a entrada com as mudanças desejadas em vez de deixá-las em branco.

Esses exemplos usam a API de dados do Google Base. Se você estiver usando service.batch com outro tipo de serviço GData, substitua as classes GoogleBaseFeed, GoogleBaseEntry e GoogleBaseService pelas classes adequadas de entrada, serviço e feed.

Os resultados de uma operação em lote não são necessariamente retornados na ordem em que foram solicitados. No exemplo acima, o feed de resultados pode conter muito bem entry2 seguido por entry1. Nunca suponha que as entradas sejam retornadas em uma ordem específica.

Seu feed de operações em lote deve atribuir um ID de lote exclusivo a cada operação de inserção, conforme explicado em Operações de rastreamento. Nos exemplos acima, os IDs de lote são A e B. Portanto, para encontrar o status das operações solicitadas, itere sobre as entradas no feed de lote retornado e compare o ID de lote ou o ID de entrada, da seguinte maneira:

for (GoogleBaseEntry entry : result.getEntries()) {
  String batchId = BatchUtils.getBatchId(entry);      
  if (BatchUtils.isSuccess(entry)) {     
    if ("A".equals(batchId)) {       
      entry1 = entry;     } 
    else if ("B".equals(batchId)) {       
      entry2 = entry;     } 
    else if (BatchUtils.getBatchOperationType(entry) 
      == BatchOperationType.DELETE) {       
      System.out.println("Entry " + entry.getId() +
      " has been deleted successfully.");     
    }      
  } else {     
    BatchStatus status = BatchUtils.getBatchStatus(entry);     
    System.err.println(batchId + " failed (" +                
      status.getReason() + ") " +  status.getContent());      
    }    
  } 

Cada entrada que você encontrar no feed retornado terá um objeto BatchStatus associado. O objeto BatchStatus contém um código de retorno HTTP e uma resposta que descreve o que deu errado enquanto a entrada foi processada. Você precisa verificar o código de retorno HTTP de cada entrada para saber se a operação foi bem-sucedida.

A verificação é feita no exemplo acima pelo método de conveniência BatchUtils.isSuccess. Nesse caso, ele é equivalente a: BatchUtils.getBatchStatus(entry) < 300.

Os códigos de status e as respostas são explicados com mais detalhes em Como processar códigos de status.

Voltar ao início