Processamento em lote

Enquanto a maioria dos serviços oferece APIs síncronas, que exigem que você faça uma solicitação e aguarde por uma resposta, o BatchJobService oferece uma maneira de executar lotes de operações em vários serviços, sem esperar que elas sejam concluídas.

Ao contrário das operações "mutate" específicas de serviços, uma única tarefa em BatchJobService pode atuar em uma coleção diversificada de campanhas, grupos de anúncios, anúncios, critérios, etiquetas e itens de feed. As tarefas enviadas são executadas em paralelo, e o BatchJobService tenta realizar novamente as operações com falhas decorrentes de erros temporários, tais como RateExceededError.

Além disso, o BatchJobService permite a utilização de IDs temporários nas solicitações para que você possa enviar operações dependentes em uma única tarefa.

Operações compatíveis

O BatchJobService é compatível com as seguintes operações:

Operação Serviço síncrono correspondente
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

Esquema

Embora cada biblioteca cliente contenha utilitários que lidam com a seriação de XMLs de operações enviadas e a desserialização de XMLs de resultados do download, o esquema completo de solicitações de tarefas em lote e as respostas estão disponíveis em:

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

Fluxo de tarefas em lote

Estas são as etapas para utilizar tarefas em lote:

  1. Crie a BatchJob e capture o uploadUrl na resposta mutate().
  2. Faça o upload da lista de operações que você deseja executar em uploadUrl.
  3. Pesquise o status da tarefa em lote periodicamente até que ele esteja CANCELED ou DONE.
  4. Faça o download dos resultados da tarefa no downloadUrl e verifique se há processingErrors.

Além disso, é possível cancelar uma BatchJob no estado AWAITING_FILE ou ACTIVE definindo o status como CANCELING.

Criar uma tarefa em lote

Crie uma tarefa em lote enviando uma operação ADD que contém um novo objeto 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);

Nesse ponto do processo, o status da tarefa será AWAITING_FILE.

Criar operações para a tarefa em lote

Nesta etapa, crie as operações da sua tarefa em lote usando a mesma abordagem que você usaria para os serviços síncronos da API. Por exemplo, o snippet a seguir cria objetos CampaignOperation para adicionar novas campanhas.

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;

Se estiver criando objetos dependentes, como uma campanha completa que consiste em uma nova campanha e nos grupos de anúncios, anúncios e palavras-chave correspondentes, você poderá usar IDs temporários nas operações 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));

Fazer upload de operações no URL de upload

Depois de coletar o conjunto de operações da sua tarefa, a próxima etapa é enviá-los para o URL de upload.

Se você estiver usando o utilitário em uma das bibliotecas cliente, não se preocupe com todos os detalhes subjacentes. O utilitário lidará com a criação e o envio de solicitações para você e oferecerá métodos para estas duas opções:

  1. Como fazer upload de todas as operações de uma só vez.
  2. Como fazer o upload das operações usando várias chamadas do utilitário.

Opção 1: fazer o upload de todas as operações de uma só vez

Os exemplos abaixo usam o utilitário BatchJobHelper da biblioteca cliente Java para fazer o upload de todas as operações de uma só vez.

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

batchJobHelper.uploadBatchJobOperations(operations, uploadUrl);

Opção 2: fazer o upload das operações usando várias chamadas do utilitário

O exemplo abaixo usa o utilitário BatchJobHelper da biblioteca cliente Java para fazer upload das operações gradualmente por meio de várias chamadas do método uploadIncrementalBatchJobOperations() do utilitário.

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

Pesquisar o status da tarefa em lote

Depois de fazer o upload das suas operações, a tarefa em lote será enviada para a fila de tarefas. Portanto, verifique o status da tarefa periodicamente até ele estar como CANCELED ou DONE. Use uma política de recuo binário exponencial para evitar uma pesquisa muito ousada. O snippet abaixo aguardará 30 segundos na primeira tentativa, 60 segundos na segunda, 120 segundos na terceira e assim por diante.

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

Fazer o download dos resultados da tarefa em lote e verificar erros

Neste ponto, sua tarefa estará em um destes dois estados.

Status Descrição Ações a adotar
DONE BatchJobService analisou e tentou processar cada operação enviada.
  • Faça o download dos resultados de cada operação no downloadUrl da tarefa em lote.
CANCELED Ocorreu um erro enquanto o BatchJobService tentava analisar as operações enviadas.
  • Inspecione a lista de processingErrors na tarefa em lote.
  • Faça o download dos resultados de todas as operações analisadas com sucesso no downloadUrl da tarefa em lote, se houver.

O URL de download retornará um elemento mutateResult para cada operação enviada. Cada resultado terá os seguintes atributos, conforme definido e BatchJobOpsService.wsdl:

Atributo Tipo Descrição
result Operand Se a operação tiver sido bem-sucedida, terá exatamente um destes elementos secundários:
  • Ad
  • AdGroup
  • AdGroupAd
  • AdGroupAdLabel
  • AdGroupBidModifier
  • AdGroupCriterion
  • AdGroupCriterionLabel
  • AdGroupExtensionSetting
  • AdGroupLabel
  • Budget
  • Campaign
  • CampaignCriterion
  • CampaignExtensionSetting
  • CampaignLabel
  • CustomerExtensionSetting
  • FeedItem
O elemento e o objeto retornados corresponderão ao tipo de operação de index. Por exemplo, se a operação tiver sido bem-sucedida, CampaignOperation, um elemento Campaign será retornado aqui.
errorList ErrorList Se tiver ocorrido uma falha na operação, haverá um ou mais elementos de errors. Cada um deles será uma instância de ApiError ou uma das suas subclasses.
index long O número da operação com base em 0. Use-o para correlacionar esse resultado com a operação correspondente no seu upload.

O código abaixo mostra uma abordagem de processamento dos resultados recuperados em um URL de download.

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.");
}

O atributo processingErrors da tarefa em lote conterá todos os erros encontrados ao processar suas operações enviadas, por exemplo, corrompimento do arquivo de entrada. O código abaixo mostra uma abordagem para processar esses erros.

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.");
}

Como usar IDs temporários

Um recurso eficiente do BatchJobService é a compatibilidade com o uso de IDs temporários. Um ID temporário é um número negativo (long) que permite a referência do resultado de uma operação ADD de uma operação anterior na mesma tarefa em lote. Basta especificar um número negativo para o ID na operação ADD do objeto pai e reutilizá-lo nas operações mutate() subsequentes de outros objetos dependentes na mesma tarefa em lote.

Um caso de uso comum de IDs temporários é a criação de uma campanha completa em uma única tarefa em lote. Por exemplo, é possível criar uma única tarefa contendo operações ADD com as seguintes atribuições de ID em cada operand:

Essa sequência:

  • adiciona uma campanha com ID (temporário) -1;
    • adiciona um grupo de anúncios com ID temporário -2 para a campanha -1;
      • adiciona um anúncio para o grupo de anúncios -2;
      • adiciona vários critérios de grupos de anúncios (palavras-chave) ao grupo de anúncios -2;
  • aplica uma etiqueta à campanha -1;
  • adiciona um critério negativo (palavra-chave) na campanha -1.

Como cancelar uma tarefa em lote

Uma BatchJob pode ser cancelada caso o status dela seja AWAITING_FILE ou ACTIVE. Basta emitir uma solicitação BatchJobService.mutate() e passar uma BatchJobOperation com:

  • operator = SET
  • operand = uma BatchJob com:
    • id = o ID da tarefa em lote
    • status = CANCELING

Se o status da BatchJob não for AWAITING_FILE nem ACTIVE no momento da solicitação acima, ocorrerá uma falha na solicitação com um erro BatchJobError.INVALID_STATE_CHANGE.

O cancelamento de uma tarefa é uma operação assíncrona. Portanto, depois da solicitação mutate(), pesquise o status da tarefa em lote até que ele esteja como CANCELED ou DONE. Certifique-se de fazer o download dos resultados e verificar se há erros, pois pode ter ocorrido a tentativa de execução de algumas operações da tarefa antes do cancelamento dela.

Requisitos de upload

Uploads não incrementais

Todos os utilitários da biblioteca cliente oferecem um método de conveniência para operações de upload em uma única etapa. No entanto, se você não utiliza uma biblioteca cliente, os envios não incrementais não são compatíveis.

Uploads incrementais

Com os uploads incrementais, é possível enviar várias solicitações de upload ao uploadUrl da tarefa em lote. A tarefa só começará a ser executada quando você tiver feito upload do último conjunto de operações.

Substitua o uploadURL da BatchJob por um URL de upload recuperável

O processo de upload segue as Diretrizes do Armazenamento em nuvem do Google para uploads recuperáveis com a XML API.

O uploadUrl da BatchJob precisa ser substituído por um URL de upload recuperável. Para substituir o uploadUrl por um URL de upload recuperável, envie uma solicitação ao uploadUrl que atenda às seguintes especificações:

Atributos de solicitação
Método de solicitação POST
URL URL de upload retornado por BatchJobService.mutate
Cabeçalho HTTP Content-Type application/xml
Cabeçalho HTTP Content-Length 0
Cabeçalho HTTP x-goog-resumable start
Corpo da solicitação corpo da solicitação não necessário

Caso sua solicitação seja bem-sucedida, a resposta retornada terá status 201 Created e cabeçalho Location cujo valor é o URL de upload recuperável.

Operações de upload para o URL de upload recuperável

Quando você tiver o URL de upload recuperável, poderá começar a fazer upload das suas operações. Cada solicitação enviada para o URL de upload recuperável precisará cumprir com as seguintes especificações.

Atributos de solicitação
Método de solicitação PUT
URL URL de upload recuperável da etapa de inicialização acima.
Cabeçalho HTTP Content-Type application/xml
Cabeçalho HTTP Content-Length Número de bytes do conteúdo da solicitação atual.
Cabeçalho HTTP Content-Range
Intervalo de bytes da solicitação seguido pelo total de bytes. O total de bytes será * para a primeira solicitação e para as solicitações intermediárias, mas precisará ser definido para o total final de bytes ao enviar a última solicitação.
Exemplos:
0-262143/* bytes
262144-524287/* bytes
524288-786431/786432 bytes
Corpo da solicitação
Operações em XML, conforme especificado em BatchJobOpsService.wsdl.

Corpo da solicitação do URL de upload recuperável

O BatchJobService finalmente concatenará todo o XML enviado ao uploadUrl e o analisará como uma única solicitação. Portanto, inclua somente os elementos mutate de início e término na primeira e na última solicitação, respectivamente.

Solicitação Elemento mutate de início Elemento mutate de término
Primeira Marca de seleção Sinal de proibido
Intermediária Sinal de proibido Sinal de proibido
Última Sinal de proibido Marca de seleção

Além disso, como o BatchJobService analisará o XML enviado como um único documento, o corpo de uma única solicitação não precisará conter um documento XML completo. Por exemplo, se você estiver fazendo upload de 524.305 bytes (256 K + 256 K + 17), suas solicitações serão desta forma:

Solicitação 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

O tamanho do conteúdo de 262.144, no qual t, na última linha, é o 262.144º byte.

Solicitação 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

Tamanho do conteúdo de 262.144, no qual e, na última linha, é o 262.144º byte.

Solicitação 3

rations></mutate>
... (padded to 262144 bytes)

Tamanho do conteúdo sem espaçamento de 17 bytes, no qual > de fechamento em </mutate> é o 17º byte. O tamanho total do conteúdo com espaçamento é de 262.144 bytes.

Práticas recomendadas

Considere estas diretrizes ao usar o BatchJobService:

  • Para melhores resultados, recomenda-se dar preferência a poucas tarefas grandes, em vez de muitas tarefas pequenas.
  • Ao enviar várias tarefas simultâneas para o mesmo clientCustomerId, tente reduzir a probabilidade de as tarefas serem executadas nos mesmos objetos ao mesmo tempo, enquanto mantém tarefas grandes. Várias tarefas incompletas (com status ACTIVE ou CANCELING) que tentam modificar o mesmo conjunto de objetos podem levar a condições de impasse, resultando em uma severa diminuição de velocidade e até mesmo falhas nas tarefas.
  • Evite várias operações que mudam o mesmo objeto na mesma tarefa.
  • Para melhores resultados, organize as operações por tipo de operação. Por exemplo, se sua tarefa contém operações para adicionar campanhas, grupos de anúncios e critérios de grupo de anúncios, organize as operações no upload para que todas as CampaignOperations sejam executadas primeiro, seguidas de todas as AdGroupOperations e, por fim, todas as AdGroupCriterionOperations.
  • Não pesquise o status da tarefa com muita frequência, caso contrário, você correrá o risco de receber erros de limite de taxa.

Como trabalhar com Campanhas do Shopping

Durante a atualização de árvores de partição de produtos usando BatchJobService, as seguintes restrições se aplicam:

  1. Se uma lista de operações em uma árvore de partição de produtos resultar em uma árvore de partição de produtos estruturalmente inválida (por exemplo, um nó é subdividido sem criar outro nó), toda a lista de operações nessa árvore de partição de produtos falhará.

  2. Operações que não introduzem mudanças estruturais em uma árvore de partição de produtos (por exemplo, alterações de lance em um nó existente) são executadas independentemente.

  3. Ao remover um nó de partição de produtos, defina o campo criterion do objeto AdGroupCriterion como uma instância ProductPartition. A definição desse campo como uma instância Criterion causará uma falha na operação com um erro AdGroupCriterionError.CONCRETE_TYPE_REQUIRED.

Limitações

  • Uma conta do Google AdWords pode ter até 1 GB de operações enviadas em todas as suas tarefas em lote que ainda não foram concluídas, a qualquer momento. Quando sua conta atingir esse limite, você receberá um BatchJobError com o motivo DISK_QUOTA_EXCEEDED ao tentar adicionar novas tarefas em lote. Se você encontrar esse erro, aguarde até que o tamanho das operações enviadas pendentes esteja abaixo do limite para criar novas tarefas.

Exemplos de código

As bibliotecas cliente abaixo contêm um exemplo de código completo que ilustra todos os recursos acima.

Enviar comentários sobre…

Precisa de ajuda? Acesse nossa página de suporte.