El procesamiento por lotes te permite ejecutar varias operaciones en una solicitud, en lugar de tener que enviar cada operación de forma individual.
Nota: Para realizar operaciones por lotes, debes usar una versión reciente de la biblioteca cliente de la API de datos de Google. La biblioteca cliente de JavaScript no admite operaciones por lotes.
Público
Este documento está dirigido a los programadores que desean enviar varias operaciones en una sola solicitud por medio del procesamiento por lotes.
En este documento, se supone que estás familiarizado con el uso de la biblioteca cliente de Java para GData. En los ejemplos de este documento, se muestra cómo usar la biblioteca cliente de Java para ejecutar operaciones por lotes.
Los ejemplos de este documento son específicos de la API de datos base de Google. Sin embargo, otros servicios también pueden proporcionar capacidades por lotes.
Nota: El protocolo y los procedimientos generales serán los mismos para otras bibliotecas cliente, pero los métodos específicos para realizar solicitudes por lotes pueden variar. Consulta la documentación específica de la biblioteca cliente.
Introducción
Con un feed por lotes GData, puedes recopilar varias operaciones de inserción, actualización, eliminación y consulta, y luego enviarlas y ejecutarlas todas a la vez.
Por ejemplo, el siguiente feed incluye cuatro operaciones:
<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>
El servicio realizará la mayor cantidad posible de cambios solicitados y mostrará información sobre el estado que puedes usar para evaluar el éxito o el fracaso de cada operación.
El servicio intenta ejecutar cada una de las operaciones dentro de un lote, incluso si algunas de las operaciones incluidas en el lote no se ejecutan de forma correcta.
Envía una solicitud por lotes
Una solicitud por lotes se debe enviar como una solicitud HTTP POST a una URL por lotes. Los diferentes feeds admiten distintas operaciones por lotes. Los feeds de solo lectura solo admiten consultas.
Puedes consultar si el feed admite operaciones por lotes. Si el feed contiene una relación de vínculo “por lotes” a nivel del feed, esto indica que el feed admite operaciones por lotes.
Una relación de vínculo "por lotes" es un elemento <link>
con rel="http://schemas.google.com/g/2005#batch"
. El atributo href
de la relación de vínculo define la URL en la que se pueden publicar los documentos de feed de las operaciones por lotes.
Por ejemplo, si ejecutas: GET http://www.google.com/base/feeds/items
(el feed regular de “elementos” de Google Base), es posible que obtengas la siguiente respuesta:
<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>
En este ejemplo, la URL del lote es http://www.google.com/base/feeds/items/batch
.
Escribe un feed de operaciones por lotes
Un feed de operaciones contiene una lista de entradas para insertar, actualizar, borrar o consultar.
Cada operación se define con un elemento <batch:operation type="insert|update|delete|query"/>
.
Este elemento puede ser un elemento secundario directo de un elemento <feed>
, un elemento secundario directo de cualquiera de las entradas del feed o ambos. Cuando se incluye en una entrada, especifica la operación que se ejecutará en esa entrada específica. Cuando se incluye en este feed, este elemento especifica la operación predeterminada para ejecutar en cualquier entrada que no tenga un elemento <batch:operation/>
.
Cuando ni la entrada ni el feed especifican una operación, la operación predeterminada es insert
.
Las aplicaciones no deben aplicar varias operaciones a una misma entrada en un mismo feed por lotes. Los resultados son indeterminados si especificas varias operaciones para la misma entrada.
Para mejorar el rendimiento, es posible que las operaciones no se procesen en el orden en que se solicitaron. Sin embargo, el resultado final siempre es el mismo que si las entradas se procesaran en orden.
La cantidad de bytes en XML que envíes al servidor no puede superar 1 MB (1,048,576 bytes). En general, no hay límites en la cantidad de operaciones que puedes solicitar, siempre que el tamaño total en bytes no supere el MB. Sin embargo, algunos servicios pueden imponer restricciones adicionales.
Para usar las operaciones por lotes, debes agregar la declaración del espacio de nombres por lotes como un atributo al elemento <f
eed>
:
<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">
Operaciones de inserción
Una operación de inserción se indica de la siguiente manera:
<batch:operation type="insert">
Una operación de inserción es equivalente a POST la entrada. Cuando la operación se realiza correctamente, se muestra todo el contenido de la entrada, con un elemento <id>
de documento actualizado y un elemento <batch:status code="201"/>
.
A continuación, se muestra un ejemplo de una solicitud de inserción exitosa:
<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>
A continuación, se muestra un ejemplo de una respuesta a una solicitud de inserción exitosa:
<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>
Operaciones de actualización
<batch:operation type="update">
Una operación de actualización equivale a ejecutar una PUT
en la URL a la que hace referencia el elemento <id>
de la entrada. Cuando la operación se realiza correctamente, todo el contenido de la entrada se muestra con un elemento <batch:status
code="200"/>
.
Nota: Con determinados feeds, también debes especificar el vínculo rel="edit"
de la entrada con solicitudes de actualización por lotes. Esto incluye los feeds que admiten el estilo de protocolo de datos de Google v1 de simultaneidad optimista, y los feeds que no tienen ID que son las URL.
A continuación, se muestra un ejemplo de una solicitud de actualización:
<entry> <id>http://www.google.com/base/feeds/items/17437536661927313949</id> <batch:operation type="update"/> ... </entry>
A continuación, se muestra un ejemplo de una respuesta exitosa:
<entry> <batch:status code="200"/> <id>http://www.google.com/base/feeds/items/17437536661927313949</id> <batch:operation type="update"/> ... </entry>
Nota: Algunos feeds usan ETags fuertes a fin de evitar la modificación accidental de los cambios de otra persona. Cuando realizas una solicitud de actualización por lotes para una entrada de uno de estos feeds, debes proporcionar el valor ETag en el atributo gd:etag
de la entrada. Por ejemplo, <entry gd:etag="'F08NQAxFdip7IWA6WhVR'">...<batch:operation type="update"/>...
.
Operaciones de actualización parciales
Para los feeds que admiten actualizaciones parciales, también puedes usarlos en solicitudes por lotes. Una operación de actualización parcial es equivalente a ejecutar una PATCH
en la URL a la que hace referencia el elemento <id>
de la entrada. Cuando la operación se realiza correctamente, todo el contenido de la entrada se muestra con un elemento <batch:status
code="200"/>
.
Nota: Con determinados feeds, también debes especificar el vínculo rel="edit"
de la entrada con solicitudes de actualización por lotes. Esto incluye los feeds que admiten el estilo de protocolo de datos de Google v1 de simultaneidad optimista, y los feeds que no tienen ID que son las URL.
<batch:operation type="patch"/>
A continuación, se muestra un ejemplo de una solicitud de actualización 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>
A continuación, se muestra un ejemplo de una respuesta exitosa:
<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>
Borrar operaciones
<batch:operation type="delete">
Una operación de eliminación es equivalente a ejecutar una DELETE
en la URL a la que hace referencia el elemento <id>
de la entrada. En el caso de una operación de eliminación, solo necesitas enviar el elemento <id>
para borrar la entrada. Se ignorará cualquier otra información que proporciones en elementos que no se encuentren en el espacio de nombres batch:
. Cuando la operación se complete correctamente, se mostrará una entrada con el mismo ID y un elemento <batch:status
code="200"/>
.
Nota: Con determinados feeds, también debes especificar el vínculo rel="edit"
de la entrada con solicitudes de eliminación por lotes. Esto incluye los feeds que admiten el estilo de protocolo de datos de Google v1 de simultaneidad optimista, y los feeds que no tienen ID que son las URL.
A continuación, se muestra un ejemplo de una solicitud de eliminación:
<entry> <batch:operation type="delete"/> <id>http://www.google.com/base/feeds/items/17437536661927313949</id> </entry>
A continuación, se muestra un ejemplo de una respuesta exitosa:
<entry> <batch:operation type="delete"/> <id>http://www.google.com/base/feeds/items/17437536661927313949</id> <batch:status code="200" reason="Success"/> </entry>
Nota: Algunos feeds usan ETags fuertes a fin de evitar la modificación accidental de los cambios de otra persona. Cuando realizas una solicitud de eliminación por lotes para una entrada de uno de estos feeds, debes proporcionar el valor ETag en el atributo gd:etag
de la entrada. Por ejemplo, <entry gd:etag="'F08NQAxFdip7IWA6WhVR'">...<batch:operation type="delete"/>...
.
Operaciones de consulta
<batch:operation type="query">
Una operación de consulta es equivalente a ejecutar un GET
en la URL a la que hace referencia el elemento <id>
de la entrada. Cuando la operación se realiza correctamente, se muestra todo el contenido de la entrada.
Nota: Con determinados feeds, también debes especificar el vínculo rel="self"
de la entrada con solicitudes de consulta por lotes. Esto incluye los feeds que no tienen ID que sean URL.
Este es un ejemplo de una solicitud de consulta:
<entry> <id>http://www.google.com/base/feeds/items/1743753666192313949</id> <batch:operation type="query"/> </entry>
A continuación, se muestra un ejemplo de una respuesta exitosa:
<entry> <id>http://www.google.com/base/feeds/items/1743753666192313949</id> <batch:operation type="query"/> <batch:status code="200" reason="Success"/> ... </entry>
Operaciones de seguimiento
Los resultados de la entrada GData no necesariamente se muestran en el mismo orden que la solicitud. Puedes hacer el seguimiento de una operación durante su ciclo de vida mediante un identificador.
Para las operaciones de actualización, eliminación y consulta, puedes usar el ID de la entrada para realizar un seguimiento de la operación.
Para las operaciones de inserción, debido a que aún no existe un ID, puedes pasar un identificador de operación. Este identificador se puede usar para vincular las entradas del resultado con las entradas de la solicitud. El identificador de operación se pasa en el elemento <batch:id>
.
Para cada operación, GData muestra una respuesta que indica si la operación se realizó correctamente o no. Cada respuesta identifica la entrada relacionada. Para una operación de actualización, eliminación o consulta, o una operación de inserción exitosa, siempre se muestra el ID de entrada. Si especificaste un ID de lote, este también se muestra. Debido a que las operaciones de inserción incorrectas no tienen un ID de entrada asociado, solo se muestra el ID del lote.
Con el identificador de cada operación, puedes reintentar solo las operaciones que fallaron, en lugar de tener que volver a enviar todo el lote de operaciones.
El contenido de <batch:id>
es un valor de string definido por el cliente y se repite en la entrada de respuesta correspondiente.Puedes
especificar cualquier valor que ayude al cliente a correlacionar la respuesta
con la entrada en la solicitud original. Se repetirá este elemento tal como está en la entrada correspondiente, incluso si la operación falló. GData nunca almacena ni interpreta el contenido de este ID de lote.
En el siguiente ejemplo, se muestra un feed de operaciones por lotes. Ten en cuenta que el elemento <batch:id>
etiqueta esta operación 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>
En el siguiente ejemplo, se muestra la entrada del estado del lote que se muestra en respuesta a esta operación.
<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>
Manejo de códigos de estado
Los códigos de estado se expresan mediante el siguiente elemento:
<batch:status code="200|201|404|500|..." reason="reason" [content-type="type"]/>
Cada entrada del feed de respuesta contiene un elemento <batch:status>
. Este elemento describe lo que sucedió mientras se ejecutaba la operación. Imita la respuesta HTTP que se habría enviado si la operación se hubiera enviado de forma individual, en lugar de hacerlo como parte de un feed por lotes.
Debes verificar el elemento <batch:status>
de cada entrada en la respuesta para averiguar si la operación asociada se procesó correctamente. El atributo code="n"
contiene un código de estado GData.
Descripciones de estados
El atributo reason="reason"
del elemento <batch:status>
contiene una explicación más detallada del estado de la operación.
Tipo de contenido
El atributo content-type="type"
del elemento <batch:status>
contiene el tipo de MIME de los datos contenidos en el elemento <batch:status>
. Esto corresponde al encabezado Content-Type
de una respuesta de estado HTTP. Este atributo es opcional.
Cuando se establece el tipo de contenido, el cuerpo del elemento <batch:status>
describe lo que salió mal mientras se procesaba la entrada.
Identifica operaciones interrumpidas
El siguiente elemento se incluye en la respuesta de una operación interrumpida:
<batch:interrupted reason="reason" success="N" failures="N" parsed="N">
Este elemento significa que se interrumpió el procesamiento por lotes y no se pudieron recuperar todos los intentos de la causa de la interrupción. Es posible que algunas entradas ya se hayan procesado correctamente. Se abandonaron todas las entradas que no se informaron como correctas antes de este punto.
Este elemento es muy inusual y, por lo general, indica que el feed enviado en el cuerpo de la solicitud no estaba en un formato XML correcto.
Al igual que con el elemento <batch:status>
, se puede encontrar un código de estado corto en el atributo reason
. También se puede encontrar una respuesta más larga dentro del elemento.
Ejemplo de operaciones por lotes y feeds de estado
Este es un feed de operaciones por lotes que se podría enviar al servidor. Este feed solicita que el servidor borre dos entradas y agregue dos nuevas. Ten en cuenta que el elemento <feed>
debe incluir una explicación de espacio de nombres para el lote, como se destaca en el siguiente ejemplo.
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>
Supongamos que las dos inserciones funcionaron, pero una de las dos eliminaciones falló. En este caso, el feed de estado por lotes podría verse de la siguiente manera. Ten en cuenta que las entradas se reordenaron en comparación con el feed de operaciones por lotes.
<?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>
Usar la funcionalidad por lotes de la biblioteca cliente de GData para Java
En esta sección, se explica cómo usar la funcionalidad por lotes de la biblioteca cliente de Java para GData a fin de enviar un grupo de solicitudes de inserción, actualización o eliminación.
En los ejemplos proporcionados en esta sección, se usan las API de Google Base.
Primero, importa las clases que necesitarás, además de las clases estándar de GData y Google Base:
import com.google.gdata.data.batch.*; import com.google.api.gbase.client.*;
Para enviar una solicitud por lotes, debes obtener la URL de lote de un feed. En el siguiente fragmento de código, se ilustra cómo hacerlo si suponemos que feed
es un objeto GoogleBaseFeed
que contiene información sobre un 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 }
El siguiente fragmento de código prepara un feed que insertará dos entradas en una operación:
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);
El código de este ejemplo nunca indica de forma explícita que la operación que se realizará para estas entradas sea insert
. No es necesario que especifiques eso explícitamente, ya que la inserción es la operación predeterminada.
Para enviar el feed del lote y recibir los resultados, llama al método Service.batch
.
Al igual que Service.insert
, Service.batch
muestra las entradas insertadas con los valores <atom:id>
nuevos establecidos. Las entradas que se muestran se encuentran en un objeto GoogleBaseFeed
.
Si deseas borrar una tercera entrada (que ya recuperaste y almacenaste en entry3
) al mismo tiempo que insertas las otras dos entradas, puedes usar el siguiente código:
GoogleBaseEntry toDelete = new GoogleBaseEntry(); toDelete.setId(entry3.getId()); BatchUtils.setBatchOperationType(toDelete, BatchOperationType.DELETE); feed.addEntry(toDelete); GoogleBaseFeed result = service.batch(batchUrl, feed);
Aquí, service
es una instancia de com.google.gdata.client.Service
.
Si deseas actualizar una entrada, especifica OperationType.UPDATE
y, luego, inicializa la entrada con los cambios deseados en lugar de dejarla en blanco.
En estos ejemplos, se usa la API de datos de Google Base. Si estás usando service.batch
con otro tipo de servicio de GData, reemplaza las clases GoogleBaseFeed
, GoogleBaseEntry
y GoogleBaseService
con el feed, la entrada y las clases de servicio correspondientes.
Los resultados de una operación por lotes no siempre se muestran en el orden en que se solicitaron. En el ejemplo anterior, el feed de resultados podría contener entry2
seguido de entry1
. Nunca debes suponer que las entradas se muestran en un orden en particular.
Tu feed de operaciones por lotes debe asignar un ID de lote único a cada operación de inserción, como se explica en Operaciones de seguimiento. En los ejemplos anteriores, los ID de lote son A
y B
. Por lo tanto, para encontrar el estado de las operaciones solicitadas, debes iterar por las entradas del feed de lote mostrado y comparar su ID del lote o ID de la entrada, de la siguiente manera:
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 encontrarás en el feed que se muestre tendrá un objeto BatchStatus
asociado.
El objeto BatchStatus
contiene un código de retorno HTTP y una respuesta que describe qué salió mal mientras se procesaba la entrada. Debes verificar el código de retorno HTTP de cada entrada para saber si la operación se realizó correctamente.
La verificación se realiza en el ejemplo anterior mediante el método de conveniencia BatchUtils.isSuccess
.
En este caso, equivale a: BatchUtils.getBatchStatus(entry) < 300
.
Los códigos de estado y las respuestas se explican con más detalle en Cómo manejar códigos de estado.