Пакетная обработка в протоколе данных Google

Пакетная обработка дает вам возможность выполнять несколько операций в одном запросе, а не отправлять каждую операцию по отдельности.

Примечание . Для выполнения пакетных операций необходимо использовать последнюю версию клиентской библиотеки Google Data API. Пакетные операции не поддерживаются клиентской библиотекой JavaScript.

Аудитория

Этот документ предназначен для программистов, которые хотят отправить несколько операций в одном запросе, используя пакетную обработку.

В этом документе предполагается, что вы знакомы с использованием клиентской библиотеки GData Java . Примеры в этом документе показывают, как использовать клиентскую библиотеку Java для выполнения пакетных операций.

Примеры в этом документе относятся к Google Base Data API . Однако другие службы также могут предоставлять пакетные возможности.

Примечание. Протокол и общие процедуры будут одинаковыми для других клиентских библиотек, но конкретные методы выполнения пакетных запросов могут отличаться. Пожалуйста, обратитесь к документации по клиентской библиотеке.

Введение

Используя пакетный канал GData, вы можете собирать несколько операций вставки, обновления, удаления и запроса, а затем отправлять и выполнять их все одновременно.

Например, следующий фид включает четыре операции:

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

Служба выполнит как можно больше запрошенных изменений и вернет информацию о состоянии, которую можно использовать для оценки успеха или неудачи каждой операции.

Служба пытается выполнить каждую из операций в пакете, даже если некоторые из операций, включенных в пакет, не завершаются успешно.

Отправка пакетного запроса

Пакетный запрос должен быть отправлен как HTTP POST на пакетный URL-адрес. Разные каналы поддерживают разные пакетные операции. Каналы только для чтения поддерживают только запросы.

Чтобы узнать, поддерживает ли данный фид пакетные операции, вы можете запросить фид. Если фид содержит отношение ссылки «пакет» на уровне фида, это означает, что фид поддерживает пакетные операции.

Отношение "пакетная" ссылка — это элемент <link> с rel="http://schemas.google.com/g/2005#batch" . Атрибут href отношения ссылки определяет URL-адрес, по которому могут публиковаться документы канала для пакетных операций.

Например, если вы выполните: GET http://www.google.com/base/feeds/items (обычный фид «элементов» Google Base), вы можете получить следующий ответ:

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

В этом примере URL пакета — http://www.google.com/base/feeds/items/batch .

Написание фида пакетных операций

Лента операций содержит список записей, которые нужно вставить, обновить, удалить или запросить. Каждая операция определяется элементом <batch:operation type="insert|update|delete|query"/> .

Этот элемент может быть прямым дочерним элементом элемента <feed> , прямым дочерним элементом любой из записей в ленте или и тем, и другим. Когда он включен в запись, он указывает операцию, выполняемую для этой конкретной записи. При включении в ленту этот элемент указывает операцию по умолчанию для выполнения над любыми записями, которые не имеют элемента <batch:operation/> .

Если ни в записи, ни в веб-канале не указана операция, по умолчанию используется операция insert .

Приложения не должны применять несколько операций к одной и той же записи в одном пакетном фиде. Результаты будут неопределенными, если вы укажете несколько операций для одной и той же записи.

Для повышения производительности операции могут обрабатываться не в том порядке, в котором они были запрошены. Однако окончательный результат всегда будет таким же, как если бы записи обрабатывались по порядку.

Количество байтов в XML, отправляемом на сервер, не может превышать 1 МБ (1 048 576 байт). Как правило, количество операций, которые вы можете запросить, не ограничено, если общий размер байта не превышает 1 МБ. Однако некоторые сервисы могут накладывать дополнительные ограничения.

Чтобы использовать пакетные операции, вы должны добавить объявление пространства имен пакета в качестве атрибута к eed> <f

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

Вставить операции

Операция вставки обозначается следующим образом:

<batch:operation type="insert">

Операция вставки эквивалентна отправке записи. Когда операция завершается успешно, возвращается все содержимое записи с обновленным элементом документа <id> и элементом <batch:status code="201"/> .

Вот пример успешного запроса на вставку:

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

Операции обновления

<batch:operation type="update">

Операция обновления эквивалентна выполнению PUT для URL-адреса, на который ссылается элемент <id> записи. Когда операция завершается успешно, все содержимое записи возвращается с элементом <batch:status code="200"/> .

Примечание. Для некоторых фидов вам также необходимо указать ссылку rel="edit" записи с запросами на пакетное обновление. Сюда входят те фиды, которые поддерживают оптимистичный параллелизм в стиле Google Data Protocol v1, а также те фиды, у которых нет идентификаторов, являющихся URL-адресами.

Вот пример запроса на обновление:

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

Вот пример успешного ответа:

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

Примечание. В некоторых фидах используются надежные ETag , чтобы предотвратить непреднамеренное изменение изменений, внесенных другим пользователем. При отправке запроса на пакетное обновление записи в одном из этих каналов необходимо указать значение ETag в атрибуте записи gd:etag . Например, <entry gd:etag="'F08NQAxFdip7IWA6WhVR'">...<batch:operation type="update"/>...

Частичные операции обновления

Фиды, поддерживающие частичные обновления , также можно использовать в пакетных запросах. Операция частичного обновления эквивалентна выполнению PATCH для URL-адреса, на который ссылается элемент <id> записи. Когда операция завершается успешно, все содержимое записи возвращается с элементом <batch:status code="200"/> .

Примечание. Для некоторых фидов вам также необходимо указать ссылку rel="edit" записи с запросами на пакетное обновление. Сюда входят те фиды, которые поддерживают оптимистичный параллелизм в стиле Google Data Protocol v1, а также те фиды, у которых нет идентификаторов, являющихся URL-адресами.

<batch:operation type="patch"/>

Вот пример частичного запроса на обновление:

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

Вот пример успешного ответа:

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

Удалить операции

<batch:operation type="delete">

Операция удаления эквивалентна выполнению DELETE для URL-адреса, на который ссылается элемент <id> записи. Для операции удаления вам нужно только отправить элемент <id> , чтобы удалить запись. Любая другая информация, которую вы предоставляете в элементах, не входящих в batch: пространство имен, будет игнорироваться. При успешном выполнении операции будет возвращена запись с тем же идентификатором с элементом <batch:status code="200"/> .

Примечание. Для некоторых фидов вам также необходимо указать ссылку rel="edit" записи с пакетными запросами на удаление. Сюда входят те фиды, которые поддерживают оптимистичный параллелизм в стиле Google Data Protocol v1, а также те фиды, у которых нет идентификаторов, являющихся URL-адресами.

Вот пример запроса на удаление:

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

Вот пример успешного ответа:

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

Примечание. В некоторых фидах используются надежные ETag , чтобы предотвратить непреднамеренное изменение изменений, внесенных другим пользователем. При отправке запроса на пакетное удаление записи в одном из этих каналов необходимо указать значение ETag в атрибуте записи gd:etag . Например, <entry gd:etag="'F08NQAxFdip7IWA6WhVR'">...<batch:operation type="delete"/>...

Операции запроса

<batch:operation type="query">

Операция запроса эквивалентна выполнению GET для URL-адреса, на который ссылается элемент <id> записи. Когда операция завершается успешно, возвращается все содержимое записи.

Примечание. Для некоторых фидов вам также необходимо указать ссылку rel="self" записи с пакетными запросами запросов. Сюда входят те каналы, у которых нет идентификаторов, являющихся URL-адресами.

Вот пример запроса-запроса:

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

Вот пример успешного ответа:

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

Отслеживание операций

Результаты ввода GData не обязательно возвращаются в том же порядке, что и запрос. Вы можете отслеживать операцию на протяжении всего ее жизненного цикла с помощью идентификатора.

Для операций обновления, удаления и запроса вы можете использовать идентификатор самой записи для отслеживания операции.

Для операций вставки, поскольку идентификатор еще не существует, вы можете передать идентификатор операции. Этот идентификатор можно использовать для связи записей результатов с записями запроса. Идентификатор операции передается в элементе <batch:id> .

Для каждой операции GData возвращает ответ, в котором указывается, была ли операция успешной или неудачной. Каждый ответ идентифицирует связанную запись. Для операции обновления, удаления или запроса или успешной операции вставки всегда возвращается идентификатор записи. Если вы указали идентификатор пакета, он также возвращается. Поскольку неудачные операции вставки не имеют связанного идентификатора записи, возвращается только идентификатор пакета.

Используя идентификатор каждой операции, вы можете повторить только те операции, которые завершились неудачно, вместо того, чтобы повторно отправлять весь пакет операций.

Содержимое <batch:id> — это строковое значение, определяемое клиентом, которое будет отражено в соответствующей записи ответа. Вы можете указать любое значение, которое поможет клиенту сопоставить ответ с записью в исходном запросе. Этот элемент будет отображаться как есть в соответствующей записи, даже если операция не удалась. GData никогда не сохраняет и не интерпретирует содержимое этого идентификатора пакета.

В следующем примере показан канал пакетных операций. Обратите внимание, что элемент <batch:id> помечает эту операцию как 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>

В следующем примере показана запись состояния пакета, возвращенная в ответ на эту операцию.

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

Обработка кодов состояния

Коды состояния выражаются следующим элементом:

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

Каждая запись в ленте ответов содержит один элемент <batch:status> . Этот элемент описывает, что произошло во время выполнения операции. Он имитирует HTTP-ответ, который был бы отправлен, если бы операция была отправлена ​​отдельно, а не как часть пакетного потока.

Вам необходимо проверить элемент <batch:status> каждой записи в ответе, чтобы узнать, была ли успешно обработана соответствующая операция. Атрибут code="n" содержит код состояния GData .

Описание статуса

Атрибут reason="reason" элемента <batch:status> содержит более подробное объяснение статуса операции.

Тип содержимого

Атрибут content-type="type" элемента <batch:status> содержит MIME-тип данных, содержащихся в элементе <batch:status> . Это соответствует заголовку Content-Type ответа состояния HTTP. Этот атрибут является необязательным.

Когда тип содержимого установлен, тело элемента <batch:status> описывает, что пошло не так при обработке записи.

Идентификация прерванных операций

В ответ на прерванную операцию включается следующий элемент:

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

Этот элемент означает, что пакетная обработка была прервана и все попытки восстановить причину прерывания не увенчались успехом. Некоторые записи могли быть уже успешно обработаны. Все записи, о которых не было сообщено как об успешном выполнении до этого момента, были оставлены.

Этот элемент очень необычен и обычно сигнализирует о том, что фид, отправленный в теле запроса, имеет неверный формат XML.

Как и в случае с элементом <batch:status> , краткий код состояния можно найти в атрибуте reason . Более длинный ответ также может быть найден внутри элемента.

Примеры пакетных операций и каналов статуса

Вот канал пакетных операций, который можно отправить на сервер. Этот фид запрашивает, чтобы сервер удалил две записи и добавил две новые записи. Обратите внимание, что элемент <feed> должен включать описание пространства имен для пакета, как показано в примере ниже.

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>

Предположим, что две вставки сработали, но одно из двух удалений не удалось. В этом случае канал статуса пакета может выглядеть следующим образом. Обратите внимание, что записи были переупорядочены по сравнению с лентой пакетных операций.

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

Использование пакетных функций клиентской библиотеки GData Java

В этом разделе объясняется, как использовать пакетную функцию клиентской библиотеки GData Java для отправки группы запросов на вставку, обновление и/или удаление.

В примерах, приведенных в этом разделе, используются базовые API Google.

Сначала импортируйте необходимые классы в дополнение к стандартным классам GData и Google Base:

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

Чтобы отправить пакетный запрос, вам необходимо получить пакетный URL-адрес из фида. Следующий фрагмент кода иллюстрирует, как это сделать, предполагая, что feed является объектом GoogleBaseFeed , содержащим информацию о фиде:

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
}

Следующий фрагмент кода подготавливает фид, который будет вставлять две записи за одну операцию:

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

Код в этом примере никогда явно не указывает, что для этих записей должна быть выполнена операция insert . Вам не нужно указывать это явно, потому что вставка является операцией по умолчанию.

Чтобы отправить пакетный поток и получить результаты, вызовите метод Service.batch .

Подобно Service.insert , Service.batch возвращает вставленные записи с новыми установленными значениями <atom:id> . Возвращенные записи содержатся в объекте GoogleBaseFeed .

Если вы хотите удалить третью запись (которую вы уже извлекли и сохранили в entry3 ) одновременно с вставкой двух других записей, вы можете использовать следующий код:

GoogleBaseEntry toDelete = new GoogleBaseEntry();


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

feed.addEntry(toDelete);


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

Здесь service является экземпляром com.google.gdata.client.Service .

Если вы хотите обновить запись, укажите OperationType.UPDATE и инициализируйте запись с нужными изменениями вместо того, чтобы оставлять ее практически пустой.

В этих примерах используется API данных Google Base. Если вы используете service.batch с другим типом службы GData, замените классы GoogleBaseFeed , GoogleBaseEntry и GoogleBaseService соответствующими классами канала, записи и службы.

Результаты пакетной операции не обязательно возвращаются в том порядке, в котором они были запрошены. В приведенном выше примере фид результатов вполне может содержать entry2 за которой следует entry1 . Вы никогда не должны предполагать, что записи возвращаются в каком-то определенном порядке.

Фид пакетных операций должен присваивать уникальный идентификатор пакета каждой операции вставки, как описано в разделе Отслеживание операций . В приведенных выше примерах идентификаторами пакетов являются A и B . Таким образом, чтобы найти статус запрошенных операций, вы должны пройтись по записям в возвращаемом пакетном фиде и сравнить их идентификаторы пакетов или записей следующим образом:

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());      
    }    
  } 

Каждая запись, которую вы найдете в возвращенном веб-канале, будет иметь связанный объект BatchStatus . Объект BatchStatus содержит код возврата HTTP и ответ, описывающий, что пошло не так во время обработки записи. Вам необходимо проверить код возврата HTTP каждой записи, чтобы определить, успешно ли выполнена операция.

В приведенном выше примере проверка выполняется вспомогательным методом BatchUtils.isSuccess . В этом случае это эквивалентно: BatchUtils.getBatchStatus(entry) < 300 .

Коды состояния и ответы более подробно описаны в разделе Обработка кодов состояния .

Вернуться к вершине