Пакетная обработка

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

В отличие от специальных операций mutate для служб, одно задание в BatchJobService обеспечивает работу со смешанным набором кампаний, групп объявлений, объявлений, критериев, ярлыков и элементов фида. Задания обрабатываются параллельно, и служба BatchJobService автоматически повторяет операции, при выполнении которых произошла временная ошибка, например RateExceededError.

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

Поддерживаемые операции

BatchJobService поддерживает следующие операции:

Операция Соответствующая синхронная служба
AdGroupAdOperation
AdGroupAdLabelOperation
AdGroupAdService
AdGroupBidModifierOperation AdGroupBidModifierService
AdGroupCriterionOperation
AdGroupCriterionLabelOperation
AdGroupCriterionService
AdGroupExtensionSettingOperation AdGroupExtensionSettingService
AdGroupOperation
AdGroupLabelOperation
AdGroupService
BudgetOperation BudgetService
CampaignCriterionOperation CampaignCriterionService
CampaignExtensionSettingOperation CampaignExtensionSettingService
CampaignOperation
CampaignLabelOperation
CampaignService
CustomerExtensionSettingOperation CustomerExtensionSettingService
FeedItemOperation FeedItemService

Схема

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

https://adwords.google.com/api/adwords/cm/v201702/BatchJobOpsService?wsdl

Процесс выполнения пакетных заданий

Чтобы выполнить пакетное задание:

  1. Создайте объект BatchJob и получите его uploadUrl из ответа метода mutate().
  2. Загрузите на uploadUrl список операций, которые необходимо выполнить.
  3. Периодически проверяйте статус (status) пакетного задания, пока он не примет значение CANCELED или DONE.
  4. Скачайте результаты задания с downloadUrl и проверьте их на наличие ошибок обработки (processingErrors).

Вы также можете отменить BatchJob на стадии выполнения AWAITING_FILE или ACTIVE, задав в поле status значение CANCELING.

Создание пакетного задания

Чтобы создать пакетное задание, отправьте операцию ADD с новым объектом BatchJob.

// Create a BatchJob.
BatchJobOperation addOp = new BatchJobOperation();
addOp.setOperator(Operator.ADD);
addOp.setOperand(new BatchJob());

BatchJob batchJob = batchJobService.mutate(new BatchJobOperation[] {addOp}).getValue(0);

// Get the upload URL from the new job.
String uploadUrl = batchJob.getUploadUrl().getUrl();

System.out.printf("Created BatchJob with ID %d, status '%s' and upload URL %s.%n",
    batchJob.getId(), batchJob.getStatus(), uploadUrl);

Статус задания (status) на этом этапе будет AWAITING_FILE.

Создание операций для пакетного задания

Операции для пакетного задания создаются так же, как и при использовании синхронных служб API. Например, следующий код создает объекты CampaignOperation для добавления новых кампаний:

List<CampaignOperation> operations = new ArrayList<>();
for (int i = 0; i < NUMBER_OF_CAMPAIGNS_TO_ADD; i++) {
  Campaign campaign = new Campaign();
  campaign.setName(String.format("Batch Campaign %s.%s", namePrefix, i));

  // Recommendation: Set the campaign to PAUSED when creating it to prevent
  // the ads from immediately serving. Set to ENABLED once you've added
  // targeting and the ads are ready to serve.
  campaign.setStatus(CampaignStatus.PAUSED);

  campaign.setId(tempIdGenerator.next());
  campaign.setAdvertisingChannelType(AdvertisingChannelType.SEARCH);
  Budget budget = new Budget();
  budget.setBudgetId(budgetId);
  campaign.setBudget(budget);
  BiddingStrategyConfiguration biddingStrategyConfiguration =
      new BiddingStrategyConfiguration();
  biddingStrategyConfiguration.setBiddingStrategyType(BiddingStrategyType.MANUAL_CPC);

  // You can optionally provide a bidding scheme in place of the type.
  ManualCpcBiddingScheme cpcBiddingScheme = new ManualCpcBiddingScheme();
  cpcBiddingScheme.setEnhancedCpcEnabled(false);
  biddingStrategyConfiguration.setBiddingScheme(cpcBiddingScheme);

  campaign.setBiddingStrategyConfiguration(biddingStrategyConfiguration);

  CampaignOperation operation = new CampaignOperation();
  operation.setOperand(campaign);
  operation.setOperator(Operator.ADD);
  operations.add(operation);
}
return operations;

Если вы создаете зависимые объекты (например, кампанию с группами объявлений, объявлениями и ключевыми словами), можно использовать временные идентификаторы в операциях ADD.

// Create a temporary ID generator that will produce a sequence of descending negative numbers.
Iterator<Long> tempIdGenerator =
    new AbstractSequentialIterator<Long>(-1L) {
      @Override
      protected Long computeNext(Long previous) {
        return Long.MIN_VALUE == previous.longValue() ? null : previous - 1;
      }
    };

// Use a random UUID name prefix to avoid name collisions.
String namePrefix = UUID.randomUUID().toString();

// Create the mutate request that will be sent to the upload URL.
List<Operation> operations = new ArrayList<>();

// Create and add an operation to create a new budget.
BudgetOperation budgetOperation = buildBudgetOperation(tempIdGenerator, namePrefix);
operations.add(budgetOperation);

// Create and add operations to create new campaigns.
List<CampaignOperation> campaignOperations =
    buildCampaignOperations(tempIdGenerator, namePrefix, budgetOperation);
operations.addAll(campaignOperations);

// Create and add operations to create new negative keyword criteria for each campaign.
operations.addAll(buildCampaignCriterionOperations(campaignOperations));

// Create and add operations to create new ad groups.
List<AdGroupOperation> adGroupOperations =
    new ArrayList<>(buildAdGroupOperations(tempIdGenerator, namePrefix, campaignOperations));
operations.addAll(adGroupOperations);

// Create and add operations to create new ad group criteria (keywords).
operations.addAll(buildAdGroupCriterionOperations(adGroupOperations));

// Create and add operations to create new ad group ads (text ads).
operations.addAll(buildAdGroupAdOperations(adGroupOperations));

Отправка операций на URL загрузки

Создав набор операций для пакетного задания, отправьте их на URL загрузки.

Если вы используете утилиту из клиентской библиотеки, вам не придется беспокоиться обо всех тонкостях процесса. Утилита будет создавать и отправлять запросы за вас. Вам нужно будет только предоставить методы для следующих двух вариантов действий:

  1. Загрузка сразу всех операций.
  2. Загрузка операций с использованием нескольких вызовов утилиты.

Вариант 1. Загрузка сразу всех операций

В приведенном ниже примере используется утилита BatchJobHelper из клиентской библиотеки Java для загрузки сразу всех операций.

// Use a BatchJobHelper to upload all operations.
BatchJobHelper batchJobHelper = adWordsServices.getUtility(session, BatchJobHelper.class);

batchJobHelper.uploadBatchJobOperations(operations, uploadUrl);

Вариант 2. Загрузка операций с использованием нескольких вызовов утилиты

В приведенном ниже примере используется утилита BatchJobHelper из клиентской библиотеки Java для загрузки операций путем нескольких вызовов метода uploadIncrementalBatchJobOperations().

// Use a BatchJobUploadHelper to upload all operations.
BatchJobHelper batchJobUploadHelper = new BatchJobHelper(session);
BatchJobUploadStatus startingUploadStatus =
    new BatchJobUploadStatus(0, URI.create(batchJob.getUploadUrl().getUrl()));
BatchJobUploadResponse uploadResponse;

// Create and upload the first operation to create a new budget.
BudgetOperation budgetOperation = buildBudgetOperation(tempIdGenerator, namePrefix);
uploadResponse = batchJobUploadHelper.uploadIncrementalBatchJobOperations(
    Lists.newArrayList(budgetOperation),
    false, /* pass isLastRequest = false */
    startingUploadStatus);
System.out.printf("First upload response: %s%n", uploadResponse);

// Create and upload intermediate operations to create new campaigns.
List<CampaignOperation> campaignOperations =
    buildCampaignOperations(budgetOperation, tempIdGenerator, namePrefix);
uploadResponse = batchJobUploadHelper.uploadIncrementalBatchJobOperations(
    campaignOperations,
    false, /* pass isLastRequest = false */
    uploadResponse.getBatchJobUploadStatus());
System.out.printf("Intermediate upload response: %s%n", uploadResponse);

// Upload more intermediate requests...

// Create and upload operations to create new ad group ads (text ads).
// This is the final upload request for the BatchJob.
uploadResponse = batchJobUploadHelper.uploadIncrementalBatchJobOperations(
    buildAdGroupAdOperations(adGroupOperations),
    true, /* pass isLastRequest = true */
    uploadResponse.getBatchJobUploadStatus());
System.out.printf("Last upload response: %s%n", uploadResponse);

Проверка статуса пакетного задания

После загрузки операций пакетное задание будет поставлено в очередь на обработку. Вам нужно будет периодически проверять его статус, пока он не примет значение CANCELED или DONE. Чтобы избежать слишком частой проверки, используйте алгоритм экспоненциальной отсрочки. В приведенном ниже примере после первой попытки система будет выжидать 30 секунд, после второй – 60, после третьей – 120 и т. д.

int pollAttempts = 0;
boolean isPending = true;
Selector selector =
    new SelectorBuilder()
        .fields(BatchJobField.Id, BatchJobField.Status, BatchJobField.DownloadUrl,
            BatchJobField.ProcessingErrors, BatchJobField.ProgressStats)
        .equalsId(batchJob.getId())
        .build();
do {
  long sleepSeconds = (long) Math.scalb(30, pollAttempts);
  System.out.printf("Sleeping %d seconds...%n", sleepSeconds);
  Thread.sleep(sleepSeconds * 1000);

  batchJob = batchJobService.get(selector).getEntries(0);
  System.out.printf(
      "Batch job ID %d has status '%s'.%n", batchJob.getId(), batchJob.getStatus());

  pollAttempts++;
  isPending = PENDING_STATUSES.contains(batchJob.getStatus());
} while (isPending && pollAttempts < MAX_POLL_ATTEMPTS);

Скачивание результатов выполнения пакетного задания и проверка на наличие ошибок

На этом этапе задание будет иметь один из следующих двух статусов:

Статус Описание Действия
DONE Служба BatchJobService успешно произвела синтаксический разбор и попыталась выполнить каждую из загруженных операций.
  • Скачайте результаты выполнения каждой операции с downloadUrl пакетного задания.
CANCELED При синтаксическом разборе загруженных операций произошла ошибка.
  • Изучите список ошибок обработки (processingErrors) пакетного задания.
  • Скачайте результаты успешно проанализированных операций (если таковые имеются) с downloadUrl пакетного задания.

URL скачивания (downloadURL) возвратит элемент mutateResult для всех выполненных операций. У каждого результата будут следующие атрибуты, как определено в файле BatchJobOpsService.wsdl:

Атрибут Тип Описание
result Operand Если операция была успешно выполнена, у этого атрибута будет только один из следующих дочерних элементов:
  • Ad
  • AdGroup
  • AdGroupAd
  • AdGroupAdLabel
  • AdGroupBidModifier
  • AdGroupCriterion
  • AdGroupCriterionLabel
  • AdGroupExtensionSetting
  • AdGroupLabel
  • Budget
  • Campaign
  • CampaignCriterion
  • CampaignExtensionSetting
  • CampaignLabel
  • CustomerExtensionSetting
  • FeedItem
Возвращенные элемент и объект будут соответствовать типу операции для атрибута index. Например, если операция CampaignOperation была выполнена успешно, будет возвращен элемент Campaign.
errorList ErrorList Если же она закончилась неудачей, вы увидите один или несколько элементов errors. Каждый из них будет представлять собой экземпляр ApiError или одного из его подклассов.
index long Номер операции (на основе 0). Используйте его, чтобы соотнести результат с соответствующей операцией из пакета.

В примере ниже показан один из способов обработки результатов, полученных с URL скачивания.

if (batchJob.getDownloadUrl() != null && batchJob.getDownloadUrl().getUrl() != null) {
  BatchJobMutateResponse mutateResponse =
      batchJobHelper.downloadBatchJobMutateResponse(batchJob.getDownloadUrl().getUrl());
  System.out.printf("Downloaded results from %s:%n", batchJob.getDownloadUrl().getUrl());
  for (MutateResult mutateResult : mutateResponse.getMutateResults()) {
    String outcome = mutateResult.getErrorList() == null ? "SUCCESS" : "FAILURE";
    System.out.printf("  Operation [%d] - %s%n", mutateResult.getIndex(), outcome);
  }
} else {
  System.out.println("No results available for download.");
}

Поле processingErrors будет содержать все ошибки, произошедшие во время предварительной обработки загруженных операций (например, вызванные повреждением входного файла). Вот пример обработки такого рода ошибок:

if (batchJob.getProcessingErrors() != null) {
  int i = 0;
  for (BatchJobProcessingError processingError : batchJob.getProcessingErrors()) {
    System.out.printf(
        "  Processing error [%d]: errorType=%s, trigger=%s, errorString=%s, fieldPath=%s"
        + ", reason=%s%n",
        i++, processingError.getApiErrorType(), processingError.getTrigger(),
        processingError.getErrorString(), processingError.getFieldPath(),
        processingError.getReason());
  }
} else {
  System.out.println("No processing errors found.");
}

Использование временных идентификаторов

Одним из важнейших достоинств службы BatchJobService является поддержка временных идентификаторов. Временный идентификатор – это отрицательное число (long), которое позволяет операциям из пакетного задания ссылаться на результат выполнения операции ADD из предыдущей операции в том же задании. Просто укажите отрицательное число в операции ADD для родительского объекта, а затем используйте этот идентификатор в последующих операциях mutate() для других зависимых объектов в том же пакетном задании.

Обычно временные идентификаторы используются для создания полной кампании в одном пакетном задании. Например, можно создать одно задание, содержащее операции ADD, со следующими идентификаторами для каждого operand:

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

  • Будет добавлена кампания с временным идентификатором -1.
    • Будет добавлена группа объявлений с временным идентификатором -2 для кампании -1.
      • Будет добавлено объявление для группы объявлений с временным идентификатором -2.
      • Будут добавлены критерии (например, ключевые слова) для группы объявлений с временным идентификатором -2.
  • Будет применен ярлык к кампании -1.
  • Будет добавлен минус-критерий (минус-слово) для кампании -1.

Отмена пакетного задания

Пакетное задание BatchJob можно отменить, если его статус (status) – AWAITING_FILE или ACTIVE. Просто отправьте запрос методу BatchJobService.mutate() и передайте объект BatchJobOperation со следующими настройками:

  • operator = SET
  • operand = BatchJob со следующими параметрами:
    • id = идентификатор пакетного задания
    • status = CANCELING

Если во время выполнения этого запроса поле status объекта BatchJob не будет иметь значение AWAITING_FILE или ACTIVE, вы получите ошибку BatchJobError.INVALID_STATE_CHANGE.

Отмена задания выполняется асинхронно, поэтому после отправки запроса mutate() проверяйте статус пакетного задания до тех пор, пока не получите значение CANCELED или DONE. Кроме того, обязательно скачайте результаты и проверьте их на наличие ошибок, поскольку некоторые операции могли быть начаты до отмены задания.

Требования к загрузке

Полная загрузка за один прием

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

Загрузка по частям

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

Замена uploadURL на URL возобновляемой загрузки

Загрузка выполняется в соответствии с рекомендациями Google Cloud Storage по возобновляемой загрузке с помощью XML API.

uploadUrl объекта BatchJob необходимо заменить на URL возобновляемой загрузки. Для этого отправьте на uploadUrl запрос, соответствующий следующим спецификациям:

Атрибуты запроса
Метод запроса POST
URL URL загрузки, возвращаемый методом BatchJobService.mutate
HTTP-заголовок Content-Type application/xml
HTTP-заголовок Content-Length 0
HTTP-заголовок x-goog-resumable start
Тело запроса Тело запроса не требуется

Если запрос окажется успешным, в ответе вы увидите статус 201 Created и заголовок Location, значением которого и будет URL возобновляемой загрузки.

Отправка операций на URL возобновляемой загрузки

Теперь можно приступать к отправке операций. Каждый запрос, передаваемый на URL возобновляемой загрузки, должен соответствовать следующим требованиям:

Атрибуты запроса
Метод запроса PUT
URL URL возобновляемой загрузки, полученный на шаге инициализации.
HTTP-заголовок Content-Type application/xml
HTTP-заголовок Content-Length Число байтов в содержимом текущего запроса.
HTTP-запрос Content-Range
Диапазон байтов в запросе, за которым следует общее количество байтов. Общее число байтов будет обозначено звездочкой (*) для первого и промежуточного запросов, однако при отправке последнего запроса оно должно быть указано.
Примеры:
bytes 0-262143/*
bytes 262144-524287/*
bytes 524288-786431/786432
Тело запроса
Операции в формате XML, как определено в файле BatchJobOpsService.wsdl.

Тело запроса для URL возобновляемой загрузки

Служба BatchJobService объединит все XML, загруженные на uploadUrl, в один запрос и произведет его синтаксический анализ. Поэтому вам нужно будет включить только начальные и конечные элементы mutate в первый и последний запрос соответственно.

Запрос Начальный элемент mutate Конечный элемент mutate
Первый Флажок Перечеркнутый круг
Промежуточный Перечеркнутый круг Перечеркнутый круг
Последний Перечеркнутый круг Флажок

Кроме того, поскольку служба BatchJobService производит синтаксический разбор всех загруженных XML как одного документа, в тело одного запроса не требуется включать полный XML-документ. Например, при загрузке 524305 байтов (256 K + 256 K + 17) запросы могут выглядеть следующим образом:

Запрос 1

<?xml version="1.0" encoding="UTF-8"?>
<ns1:mutate xmlns:ns1="https://adwords.google.com/api/adwords/cm/v201702">
<operations xsi:type="ns1:CampaignOperation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <operator xsi:type="ns1:Operator">ADD</operator>
  <operand xsi:type="ns1:Campaign">
  ...
</operations>
<operations>
  ...
</operat

Длина содержимого – 262144 байта, где t в последней строке – 262144-й байт.

Запрос 2

ions>
<operations xsi:type="ns1:AdGroupOperation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <operator xsi:type="ns1:Operator">ADD</operator>
  <operand xsi:type="ns1:AdGroup">
  ...
</operations>
<operations>
  ...
</ope

Длина содержимого – 262144 байта, где e в последней строке – 262144-й байт.

Запрос 3

rations></mutate>
... (с заполнением до 262144 байта)

Длина содержимого без заполнения – 17 байтов, где заключительный символ > в </mutate> – 17-й байт. Длина содержимого с заполнением – 262144 байта.

Рекомендации

При использовании службы BatchJobService следуйте этим советам.

  • Чем меньше число заданий и больше их размер, тем лучше.
  • При отправке большого числа параллельных заданий для одного идентификатора clientCustomerId необходимо свести к минимуму вероятность одновременного выполнения операций над одними и теми же объектами. Задания по возможности должны иметь большой размер. Наличие множества незавершенных заданий со статусом ACTIVE или CANCELING, пытающихся модифицировать один набор объектов, может привести к их взаимной блокировке и стать причиной заметного снижения производительности или даже сбоев.
  • Старайтесь не выполнять несколько операций одновременно над одним и тем же объектом из того же задания.
  • Для наилучших результатов упорядочивайте операции по типу. Например, если задание содержит операции по добавлению кампаний, групп объявлений и критериев, первыми должны идти все операции CampaignOperations, затем – все операции AdGroupOperations и наконец – все операции AdGroupCriterionOperations.
  • Не проверяйте статус задания слишком часто, чтобы не превысить ограничения на количество запросов.

Работа с торговыми кампаниями

При изменении дерева групп товаров с помощью BatchJobService действуют следующие ограничения:

  1. Если результатом списка операций над деревом групп товаров является дерево с недопустимой структурой (например, узел разделен без создания узла Все остальное), то весь список операций завершается с ошибкой.

  2. Операции, не изменяющие структуру дерева (например, содержащие только изменения ставок в существующих узлах), выполняются независимо.

  3. Если вы удаляете узел дерева, то в качестве значения поля criterion объекта AdGroupCriterion укажите экземпляр класса ProductPartition. Если указать экземпляр класса Criterion, то операция завершится с ошибкой AdGroupCriterionError.CONCRETE_TYPE_REQUIRED.

Ограничения

  • В любой момент времени в аккаунте AdWords может быть не более 1 ГБ загруженных операций во всех незавершенных пакетных заданиях. Если по достижении этого лимита вы попытаетесь добавить новые пакетные задания, то получите ошибку BatchJobError с причиной DISK_QUOTA_EXCEEDED. В этом случае подождите, пока размер невыполненных операций не станет ниже максимального порога, прежде чем создавать новые задания.

Примеры кода

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

Оставить отзыв о...

Текущей странице
Нужна помощь? Обратитесь в службу поддержки.