Harness the power of predicates in your reports

Friday, December 10, 2010


The reporting services of the AdWords API are designed to allow you to download large amounts of data, but it can often be useful to filter out certain rows from the start to cut down on processing and transfer time. DefinedReportJobs created using the v13 ReportService supported a limited set of filtering options, primarily on IDs and statuses. Filtering on a more complex set of criteria would require post processing the report client-side. The ReportDefinitionService introduced in v201003 supports Predicates, a more flexible system of filters that can be used to create very targeted reports.

A predicate is composed of three parts: the field, the operator, and the values. Predicates can be created for almost every field available, indicated by canFilter set to "true" in the results returned from getReportFields().

<rval>
<fieldName>Clicks</fieldName>
<displayFieldName>Clicks</displayFieldName>
<xmlAttributeName>clicks</xmlAttributeName>
<fieldType>Long</fieldType>
<canSelect>true</canSelect>
<canFilter>true</canFilter>
</rval>


There are a fixed set of operators that can be used to compare the value of the field selected. EQUALS can be used to filter for an exact match, while IN can be used to match any of a set of values. GREATER_THAN and LESS_THAN are available for comparing numerical values, and CONTAINS is useful when working with strings. Only one operator can be used per predicate, but multiple predicates can be created for the same field to create more complex logic.

The values used in the predicate depend heavily on the field being operated on. Numerical values should be used for Long, Double, and Integer fields, and arbitrary strings can be used for String fields. The values for Money and Bid fields must always be specified in micros, even if the report is eventually downloaded with whole currency amounts. Although percentage fields like Ctr are returned as whole numbers, the values used in predicates should be the decimal equivalents. Predicates on Enum fields must only use the values of the enum, as outlined in the documentation and in the enumValues property returned by getReportFields().

<rval>
<fieldName>CampaignStatus</fieldName>
<displayFieldName>Campaign state</displayFieldName>
<xmlAttributeName>campaignState</xmlAttributeName>
<fieldType>CampaignStatus</fieldType>
<enumValues>ACTIVE</enumValues>
<enumValues>DELETED</enumValues>
<enumValues>PAUSED</enumValues>
<canSelect>true</canSelect>
<canFilter>true</canFilter>
</rval>


If multiple predicates are used within a Selector they will be combined using AND logic, so that the resulting report will only contain rows that satisfies all of the predicates. It’s not possible to combine predicates using OR logic at this time, but some common use cases can be handled using a single predicate and the IN operator. For example, to match keywords with either the PHRASE or EXACT match type you could use the following predicate:

<predicates>
<field>KeywordMatchType</field>
<operator>IN</operator>
<values>PHRASE</values>
<values>EXACT</values>
</predicates>


When combined together, predicates can be quite powerful. Consider the following example: I own an electronics shop that is starting to sell a wider array of tablet computers, and I want to drive more traffic to that section of my website. I’d like to start by finding all my current keywords that include the word "tablet" and have a high CTR, and then use them to generate new keyword ideas using the TargetingIdeaService. I’m only interested in keywords with greater than a 10% CTR, that have at least 100 impressions, and that are in enabled or paused ad groups.

Using predicates I can create a KEYWORDS_PERFORMANCE_REPORT that only returns me the exact data I am interested in:

<predicates>
<field>CampaignId</field>
<operator>EQUALS</operator>
<values>123456789</values>
</predicates>
<predicates>
<field>AdGroupStatus</field>
<operator>IN</operator>
<values>ENABLED</values>
<values>PAUSED</values>
</predicates>
<predicates>
<field>KeywordText</field>
<operator>CONTAINS</operator>
<values>tablet</values>
</predicates>
<predicates>
<field>Ctr</field>
<operator>GREATER_THAN</operator>
<values>0.10</values>
</predicates>
<predicates>
<field>Impressions</field>
<operator>GREATER_THAN_EQUALS</operator>
<values>100</values>
</predicates>


Predicates are one of many new improvements introduced in the ReportDefinitionService, and if you aren’t using the service yet, now is a great time to start looking into migrating. The service is fully supported in all our client libraries, and we’re available on the forum to answer any questions you may have.

- Eric Koleda, AdWords API Team

Discover v201008: Partial Failure for AdGroupCriterionService

Tuesday, December 07, 2010


With v201008 of the AdWords API we have introduced a new beta feature for AdGroupCriterionService: Partial Failure. Typically all requests to the AdWords API are atomic, so each of them either fails or succeeds in full. While this can be helpful to maintain consistency, we’ve heard from you that, in some cases, you would prefer that some operations fail while other changes are applied.

AdGroupCriterionService requests often contain many Criteria to add or update. Having an error in just one of them will force you to resend the whole set of objects again. We’ve introduced Partial Failure to enable you to get back a list of failed and successful operations and retry the failed ones only.

To utilize the new feature you’ll need to set this extra SOAP header:
partialFailure = true

Here’s an example from the Java client library:
// usual initialization code
AdWordsUser user = new AdWordsUser();
// Enable partial failure
user.setUsePartialFailure(true);
// Get the AdGroupCriterionService
AdGroupCriterionServiceInterface adGroupCriterionService =
  user.getService(AdWordsService.V201008.ADGROUP_CRITERION_SERVICE);
// Set up operations and operands here
List<AdGroupCriterionOperation> operations = new ArrayList<AdGroupCriterionOperation>();
// [...]

// Execute operations (add ad group criteria)
AdGroupCriterionReturnValue result =
  adGroupCriterionService.mutate(operations.toArray(
      new AdGroupCriterionOperation[] {}));

Now processing succeeded results:
// Display results
if ((result != null) && (result.getValue() != null)) {
  // A result is returned for every operation requested
  for (AdGroupCriterion adGroupCriterionResult : result.getValue()) {
    // Successful operation result will contain a non-null Criterion
    if (adGroupCriterionResult.getCriterion() != null) {
      System.out.printf("Ad group criterion with ad group id '%d', and " +
          "criterion id '%d', and keyword '%s' was added.\n",
          adGroupCriterionResult.getAdGroupId(),
          adGroupCriterionResult.getCriterion().getId(),
          ((Keyword) adGroupCriterionResult.getCriterion()).getText());
    }
  }
} else {
  System.out.println("No ad group criteria were added.");
}

Here is how to handle the failed operations:
// Is there any Partial Failure errors in the results?
if ((result != null) && (result.getPartialFailureErrors() != null)) {
  // Retrieving ApiError object for each of failures
  for (ApiError apiError : result.getPartialFailureErrors()) {
    // The order of the fields might be different to the order of operations in the
    // request, so we are getting the corresponding operation index from the fieldPath.
    Matcher matcher = operationIndexPattern.matcher(apiError.getFieldPath());
    if (matcher.matches()) {
      int operationIndex = Integer.parseInt(matcher.group(1));
      AdGroupCriterion adGroupCriterion =
          operations.get(operationIndex).getOperand();
      System.out.printf("Ad group criterion with ad group id '%d' and " +
          "keyword '%s' triggered a failure for the following reason: '%s'.\n",
          adGroupCriterion.getAdGroupId(),
          ((Keyword) adGroupCriterion.getCriterion()).getText(),
          apiError.getErrorString());
    } else {
      System.out.printf(
          "A failure for the following reason: '%s' has occurred.\n",
          apiError.getErrorString());
    }
  }
}


Partial Failure is fully supported in our client libraries. If you have any questions please post them on the AdWords API forum. This topic is also covered in a video presentation.

-- Danial Klimkin, AdWords API Team.

Discover v201008 - Track your account notifications with AlertService

Monday, November 22, 2010


When you’re managing a large number of accounts using the AdWords API you may want to retrieve account alerts. This was previously possible with AccountService in v13. The v201008 version introduces the AlertService, which brings similar functionality to the new AdWords API. This blog post discusses the differences between how alerts are retrieved using these two services.

Retrieving client account alerts

In v13, you could retrieve the alerts associated with list of client accounts linked to a My Client Center (MCC) using the getMccAlerts method of AccountService. In v201008, you can use the get method of AlertService to get the same results. The following code shows the service in action:


// Get the AlertService.
AlertService alertService = (AlertService) user.GetService(
    AdWordsService.v201008.AlertService);
 
// Create the alert query.
AlertQuery query = new AlertQuery();
query.filterSpec = FilterSpec.ALL;
query.clientSpec = ClientSpec.ALL;
query.triggerTimeSpec = TriggerTimeSpec.ALL_TIME;
query.severities = new AlertSeverity[] {AlertSeverity.GREEN,
    AlertSeverity.YELLOW, AlertSeverity.RED};

query.types = new AlertType[] {AlertType.CAMPAIGN_ENDING, 
    AlertType.CAMPAIGN_ENDED};
 
// Create the selector.
AlertSelector selector = new AlertSelector();
selector.query = query;
selector.paging = new Paging();
selector.paging.startIndex = 0;
selector.paging.numberResults = 10;

AlertPage page = alertService.get(selector);

Once you retrieve the alerts, you can display them by enumerating the page entries.

if (page != null && page.entries != null && page.entries.Length > 0) {
  Console.WriteLine("Retrieved {0} alerts out of {1}.",
      page.entries.Length, page.totalNumEntries);

  for (int i = 0; i < page.entries.Length; i++) {
    Alert alert = page.entries[i];
    Console.WriteLine("{0}) Customer Id is {1:###-###-####}, " +
        "Alert type is '{2}',Severity is {3}", i + 1, 
        alert.clientCustomerId, alert.alertType, alert.alertSeverity);
    for (int j = 0; j < alert.details.Length; j++) {
           Console.WriteLine("  - Triggered at {0}", alert.details[j].triggerTime);
    }
  }
} else {
  Console.WriteLine("No alerts were found.");
}

Differences between AccountService.getAllMccAlerts and AlertService.get

The main differences between the v13 AccountService.getAllMccAlerts and v201008 AlertService.get are in the table below.



AccountService.getAllMccAlerts AlertService.get
Returns alerts for all the client accounts immediately under the MCC. You can choose to retrieve alerts for all the child accounts, for immediate child accounts only, or for a specific list of customers by using the clientSpec and clientCustomerIds fields of AlertQuery.
Returns all available types of alerts for your client accounts. Returns only the types of alerts you request in your AlertQuery.
MccAlert provides multiple fields like clientLogin, clientName and clientCustomerId to associate an alert with a customer. Alert provides only clientCustomerId field to associate the alert with a customer.
Gives you one MccAlert object for each occurrence of the alert. Groups alerts of the same type for a given customer as a single Alert object. You can access the alert details from the details field of the alert object.
Alert priority can be low or high. Alert severity can be red, yellow or green.

The v201008 version of AlertService.get allows you to retrieve alerts only by predefined trigger time ranges. We plan to include support for filtering by custom date ranges in a future version of the AdWords API.

We have added support for AlertService in all of our client libraries, so please take advantage of this service and share your feedback with us on the forum.

-- Anash P. Oommen, AdWords API Team

Changes to managed placement bidding on the Display Network

Tuesday, November 16, 2010


Currently, ad groups using manual CPC bidding which contain managed placements are required to have a managed placements bid (siteMaxCpc). Today, we’re announcing that we’ll be sunsetting siteMaxCpc on March 15, 2011 to help simplify bid management on the Google Display Network (GDN).

We’re making this change in response to feedback that having multiple ad group bids for the GDN complicates bid management. Most of you using managed placements are already using placement-level bidding to control your costs on the GDN, and you’ll be able to continue to do this. In addition, the content bid (keywordContentMaxCpc) will continue to be available, offering control at the ad group level.

Here’s how this change will affect you: after March 15, we’ll stop accepting changes to ManualCpcAdGroupBids that modify siteMaxCpc to set it to anything other than 0. After that date, calls that attempt to set siteMaxCpc will return the error BiddingError.Reason.CANNOT_SET_SITE_MAX_CPC.

We’ll be announcing this change to all AdWords users early next year but wanted to let you know early so that you can prepare to modify your applications to stop accepting new siteMaxCpc bids. When we make the broader announcement, we’ll make it possible to “self-migrate” existing managed placements bids by setting them to zero and modifying their other bids as appropriate. In March, when we stop accepting changes to these bids entirely, we’ll migrate any remaining bids to the placement level, according to clear rules which we’ll share with you in a blog post in January.

If you have any questions about this change, we’ll be happy to answer them on our forum.

Posted by Prabhu Balasubramanian, Product Manager

AdWords Downtime: November 13, 10am-2pm PST

Tuesday, November 09, 2010


We'll be performing routine system maintenance on Saturday, November 13 from approximately 10:00am to 2:00pm PDT. You won't be able to access AdWords or the API during this time frame, but your ads will continue to run as normal.

Best,
- Eric Koleda, AdWords API Team 

Discover v201008: Remove incomplete BulkMutateJobs

Monday, November 08, 2010


The v201008 release of the AdWords API added a new feature to the BulkMutateJobService: the ability to remove incomplete jobs. This allows you to clean out your job queue after an application crash or other failure. In this post we’ll demonstrate how to use the feature and discuss some of its limitations.

When a BulkMutateJob is created the field numRequestParts is set, which determines how many BulkMutateRequest objects will be added to the job. Once the final request part has been added, the job enters into the account’s job queue, and when it reaches the front of the queue it begins processing. If the application crashes while the parts are being uploaded, the job will never start and remain stranded in the account.

Jobs that are incomplete and those that are complete but waiting in the queue behind a processing job will both have a PENDING status. An account can only have 10 pending jobs at a time, so stranded jobs can begin to fill up the account, until eventually no new jobs can be added. Prior to v201008 the only way to remove stranded jobs was to add the missing request parts so that the job would start. If the job had been stranded for a while though, the operations that were previously uploaded may make undesired changes to the account.

In v201008 the REMOVE operator can be used to delete incomplete jobs. The following code does this using the PHP client library.

$bulkMutateJobId = (float) 'INSERT_BULK_MUTATE_JOB_ID_HERE';

// Create BulkMutateJob.
$bulkMutateJob = new BulkMutateJob();
$bulkMutateJob->id = $bulkMutateJobId;

// Create operation.
$operation = new JobOperation();
$operation->operand = $bulkMutateJob;
$operation->operator = 'REMOVE';

// Delete bulk mutate job.
$bulkMutateJob = $bulkMutateJobService->mutate($operation);


After being removed, the job will be in the FAILED state and the failureReason field will contain JobError.USER_CANCELED_JOB.

A limitation of the REMOVE operator is that it only works on jobs that are in the PENDING state and that are incomplete (numRequestParts > numRequestPartsReceived). Jobs that are complete and have already entered the job queue, whether they be in the PENDING or PROCESSING state, cannot be deleted.

Code examples that show how to delete jobs are included in all of the client libraries. If you have any questions about this functionality or the BulkMutateJobService, ask us on the forum.

- Eric Koleda, AdWords API Team

A change to currency formatting in report downloads

Tuesday, November 02, 2010


If you're using the new AdWords API ReportDefinitionService, you may have noticed that monetary values in reports are returned as conventional currency instead of micros. At the request of the developer community, we'll be changing the format to micros on February 1, 2011 to make reporting more consistent with other AdWords API services.

A micro value is equal to one million times the conventional currency value, and is a standard we use throughout the AdWords API (including v13 reports) to represent money. For example, values currently returned as "1.50" (which would represent $1.50 for a USD account) will be returned as 1500000.

To help you with this change, we've introduced a new HTTP header flag (available immediately) that allows you to explicitly request the micros format. If you've written code that expects conventional currency values in reports, it's important that you update your code to expect micros and set the HTTP header "returnMoneyInMicros: true" when requesting a report download. Additionally, if you're just beginning to migrate from v13 reports, you should set this header on all your download requests.

To learn more about the new way to run reports via the API, see our blog post from this summer. As always, please post questions to the AdWords API Forum.

- Eric Koleda, AdWords API Team