Основы отчетности

Введение

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

Предварительные требования

Грунтовка

Если вы не знакомы с созданием отчетов в Ad Manager, см. раздел «Создание нового отчета» для получения обзора того, как запустить отчет в пользовательском интерфейсе Ad Manager. В пользовательском интерфейсе есть предварительный просмотр результатов, а также всплывающие подсказки, объясняющие, какие комбинации столбцов и измерений поддерживаются. При создании сложного запроса для отчета может быть проще сначала создать его в пользовательском интерфейсе, а затем получить запрос с помощью API.

Получение сохраненного ReportQuery

Объект ReportQuery содержит все подробности отчета. Вы можете создавать запросы для отчетов в пользовательском интерфейсе Ad Manager и получать их с помощью метода ReportService.getSavedQueriesByStatement . Идентификатор сохраненного запроса включается в URL-адрес при просмотре запроса в пользовательском интерфейсе. Например, в URL-адресе https://www.google.com/admanager/1234#reports/report/detail/report_id=456789 идентификатор запроса равен 456789 .

Если запрос несовместим с вашей версией API, SavedQuery.reportQuery будет иметь null , а SavedQuery.isCompatibleWithApiVersion — значение false .

Совместимые сохраненные запросы можно запускать с изменениями или без них.

Java

    StatementBuilder statementBuilder =
        new StatementBuilder()
            .where("id = :id")
            .orderBy("id ASC")
            .limit(1)
            .withBindVariableValue("id", savedQueryId);

    SavedQueryPage page = reportService.getSavedQueriesByStatement(statementBuilder.toStatement());
    SavedQuery savedQuery = Iterables.getOnlyElement(Arrays.asList(page.getResults()));

    if (!savedQuery.getIsCompatibleWithApiVersion()) {
      throw new IllegalStateException("The saved query is not compatible with this API version.");
    }

    ReportQuery reportQuery = savedQuery.getReportQuery();
    

Python

  statement = (ad_manager.StatementBuilder(version='v202608')
               .Where('id = :id')
               .WithBindVariable('id', int(saved_query_id))
               .Limit(1))

  response = report_service.getSavedQueriesByStatement(
      statement.ToStatement())

  if 'results' in response and len(response['results']):
    saved_query = response['results'][0]

    if saved_query['isCompatibleWithApiVersion']:
      report_job = {}

      # Set report query and optionally modify it.
      report_job['reportQuery'] = saved_query['reportQuery']
    

PHP

      $statementBuilder = (new StatementBuilder())->where('id = :id')
          ->orderBy('id ASC')
          ->limit(1)
          ->withBindVariableValue('id', $savedQueryId);

      $savedQueryPage = $reportService->getSavedQueriesByStatement(
          $statementBuilder->toStatement()
      );
      $savedQuery = $savedQueryPage->getResults()[0];

      if ($savedQuery->getIsCompatibleWithApiVersion() === false) {
          throw new UnexpectedValueException(
              'The saved query is not compatible with this API version.'
          );
      }

      $reportQuery = $savedQuery->getReportQuery();
    

C#

StatementBuilder statementBuilder = new StatementBuilder()
    .Where("id = :id")
    .OrderBy("id ASC")
    .Limit(1)
    .AddValue("id", savedQueryId);

SavedQueryPage page =
    reportService.getSavedQueriesByStatement(statementBuilder.ToStatement());
SavedQuery savedQuery = page.results[0];

if (!savedQuery.isCompatibleWithApiVersion)
{
    throw new InvalidOperationException("Saved query is not compatible with this " +
        "API version");
}

// Optionally modify the query.
ReportQuery reportQuery = savedQuery.reportQuery;
    

Руби

  statement = ad_manager.new_statement_builder do |sb|
    sb.where = 'id = :saved_query_id'
    sb.with_bind_variable('saved_query_id', saved_query_id)
  end

  saved_query_page = report_service.get_saved_queries_by_statement(
      statement.to_statement()
  )

  unless saved_query_page[:results].nil?
    saved_query = saved_query_page[:results].first

    if saved_query[:is_compatible_with_api_version]
      # Create report job.
      report_job = {:report_query => saved_query[:report_query]}
    else
      raise StandardError, 'Report query is not compatible with the API'
    end
    

Для выполнения запроса см. раздел «Создание задания отчета» .

Создание запроса для отчета

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

Java

    // Create report query.
    ReportQuery reportQuery = new ReportQuery();
    reportQuery.setDimensions(new Dimension[] {Dimension.DATE, Dimension.ORDER_ID});
    reportQuery.setColumns(
        new Column[] {
          Column.AD_SERVER_IMPRESSIONS,
          Column.AD_SERVER_CLICKS,
          Column.AD_SERVER_CTR,
          Column.AD_SERVER_CPM_AND_CPC_REVENUE
        });
    reportQuery.setDimensionAttributes(
        new DimensionAttribute[] {
          DimensionAttribute.ORDER_TRAFFICKER,
          DimensionAttribute.ORDER_START_DATE_TIME,
          DimensionAttribute.ORDER_END_DATE_TIME
        });

    // Create statement to filter for an order.
    StatementBuilder statementBuilder =
        new StatementBuilder()
            .where("ORDER_ID = :orderId")
            .withBindVariableValue("orderId", orderId);

    // Set the filter statement.
    reportQuery.setStatement(statementBuilder.toStatement());

    // Set the start and end dates or choose a dynamic date range type.
    reportQuery.setDateRangeType(DateRangeType.CUSTOM_DATE);
    reportQuery.setStartDate(
        DateTimes.toDateTime("2013-05-01T00:00:00", "America/New_York").getDate());
    reportQuery.setEndDate(
        DateTimes.toDateTime("2013-05-31T00:00:00", "America/New_York").getDate());
    

Python

  # Create statement object to filter for an order.
  statement = (ad_manager.StatementBuilder(version='v202608')
               .Where('ORDER_ID = :id')
               .WithBindVariable('id', int(order_id))
               .Limit(None)  # No limit or offset for reports
               .Offset(None))

  # Set the start and end dates of the report to run (past 8 days).
  end_date = datetime.now().date()
  start_date = end_date - timedelta(days=8)

  # Create report job.
  report_job = {
      'reportQuery': {
          'dimensions': ['ORDER_ID', 'ORDER_NAME'],
          'dimensionAttributes': ['ORDER_TRAFFICKER', 'ORDER_START_DATE_TIME',
                                  'ORDER_END_DATE_TIME'],
          'statement': statement.ToStatement(),
          'columns': ['AD_SERVER_IMPRESSIONS', 'AD_SERVER_CLICKS',
                      'AD_SERVER_CTR', 'AD_SERVER_CPM_AND_CPC_REVENUE',
                      'AD_SERVER_WITHOUT_CPD_AVERAGE_ECPM'],
          'dateRangeType': 'CUSTOM_DATE',
          'startDate': start_date,
          'endDate': end_date
      }
  }
    

PHP

      // Create report query.
      $reportQuery = new ReportQuery();
      $reportQuery->setDimensions(
          [
              Dimension::ORDER_ID,
              Dimension::ORDER_NAME
          ]
      );
      $reportQuery->setDimensionAttributes(
          [
              DimensionAttribute::ORDER_TRAFFICKER,
              DimensionAttribute::ORDER_START_DATE_TIME,
              DimensionAttribute::ORDER_END_DATE_TIME
          ]
      );
      $reportQuery->setColumns(
          [
              Column::AD_SERVER_IMPRESSIONS,
              Column::AD_SERVER_CLICKS,
              Column::AD_SERVER_CTR,
              Column::AD_SERVER_CPM_AND_CPC_REVENUE,
              Column::AD_SERVER_WITHOUT_CPD_AVERAGE_ECPM
          ]
      );

      // Create statement to filter for an order.
      $statementBuilder = (new StatementBuilder())
          ->where('ORDER_ID = :orderId')
          ->withBindVariableValue(
              'orderId',
              $orderId
          );

      // Set the filter statement.
      $reportQuery->setStatement($statementBuilder->toStatement());

      // Set the start and end dates or choose a dynamic date range type.
      $reportQuery->setDateRangeType(DateRangeType::CUSTOM_DATE);
      $reportQuery->setStartDate(
          AdManagerDateTimes::fromDateTime(
              new DateTime(
                  '-10 days',
                  new DateTimeZone('America/New_York')
              )
          )
              ->getDate()
      );
      $reportQuery->setEndDate(
          AdManagerDateTimes::fromDateTime(
              new DateTime(
                  'now',
                  new DateTimeZone('America/New_York')
              )
          )
              ->getDate()
      );
    

C#

// Create report job.
ReportJob reportJob = new ReportJob();
reportJob.reportQuery = new ReportQuery();
reportJob.reportQuery.dimensions = new Dimension[]
{
    Dimension.ORDER_ID,
    Dimension.ORDER_NAME
};
reportJob.reportQuery.dimensionAttributes = new DimensionAttribute[]
{
    DimensionAttribute.ORDER_TRAFFICKER,
    DimensionAttribute.ORDER_START_DATE_TIME,
    DimensionAttribute.ORDER_END_DATE_TIME
};
reportJob.reportQuery.columns = new Column[]
{
    Column.AD_SERVER_IMPRESSIONS,
    Column.AD_SERVER_CLICKS,
    Column.AD_SERVER_CTR,
    Column.AD_SERVER_CPM_AND_CPC_REVENUE,
    Column.AD_SERVER_WITHOUT_CPD_AVERAGE_ECPM
};

// Set a custom date range for the last 8 days
reportJob.reportQuery.dateRangeType = DateRangeType.CUSTOM_DATE;
System.DateTime endDateTime = System.DateTime.Now;
reportJob.reportQuery.startDate = DateTimeUtilities
    .FromDateTime(endDateTime.AddDays(-8), "America/New_York").date;
reportJob.reportQuery.endDate = DateTimeUtilities
    .FromDateTime(endDateTime, "America/New_York").date;

// Create statement object to filter for an order.
StatementBuilder statementBuilder = new StatementBuilder().Where("ORDER_ID = :id")
    .AddValue("id", orderId);
reportJob.reportQuery.statement = statementBuilder.ToStatement();
    

Руби

  # Specify a report to run for the last 7 days.
  report_end_date = ad_manager.today()
  report_start_date = report_end_date - 7

  # Create statement object to filter for an order.
  statement = ad_manager.new_report_statement_builder do |sb|
    sb.where = 'ORDER_ID = :order_id'
    sb.with_bind_variable('order_id', order_id)
  end

  # Create report query.
  report_query = {
    :date_range_type => 'CUSTOM_DATE',
    :start_date => report_start_date.to_h,
    :end_date => report_end_date.to_h,
    :dimensions => ['ORDER_ID', 'ORDER_NAME'],
    :dimension_attributes => ['ORDER_TRAFFICKER', 'ORDER_START_DATE_TIME',
        'ORDER_END_DATE_TIME'],
    :columns => ['AD_SERVER_IMPRESSIONS', 'AD_SERVER_CLICKS', 'AD_SERVER_CTR',
        'AD_SERVER_CPM_AND_CPC_REVENUE', 'AD_SERVER_WITHOUT_CPD_AVERAGE_ECPM'],
    :statement => statement.to_statement()
  }
    

Создание задания отчета

После того, как у вас есть ReportQuery, пришло время запустить отчет. Объект ReportJob хранит статус отчета и сообщает вам, когда он готов к загрузке. Чтобы начать запуск отчета, используйте метод ReportService.runReportJob .

Java

    // Create report job.
    ReportJob reportJob = new ReportJob();
    reportJob.setReportQuery(reportQuery);

    // Run report job.
    reportJob = reportService.runReportJob(reportJob);
    

Python

  # Initialize a DataDownloader.
  report_downloader = client.GetDataDownloader(version='v202608')

  try:
    # Run the report and wait for it to finish.
    report_job_id = report_downloader.WaitForReport(report_job)
  except errors.AdManagerReportError as e:
    print('Failed to generate report. Error was: %s' % e)
    

PHP

      // Create report job and start it.
      $reportJob = new ReportJob();
      $reportJob->setReportQuery($reportQuery);
      $reportJob = $reportService->runReportJob($reportJob);
    

C#

// Run report job.
reportJob = reportService.runReportJob(reportJob);
    

Руби

  # Create report job.
  report_job = {:report_query => report_query}

  # Run report job.
  report_job = report_service.run_report_job(report_job);
    

Загрузка отчета

После запуска задания создания отчета сервер присвоит ему идентификатор. Используйте этот идентификатор в методе ReportService.getReportJobStatus , чтобы проверить статус отчета. Как только статус изменится на ReportJobStatus.COMPLETED, отчет будет готов к загрузке.

Некоторые из наших клиентских библиотек содержат вспомогательные утилиты, которые опрашивают API и ожидают завершения формирования отчета. После завершения формирования отчета вы можете получить URL-адрес для загрузки с помощью метода ReportService.getReportDownloadURL . Отчет можно загрузить в различных форматах. Если вы хотите выполнить дальнейшую машинную обработку отчета, следует использовать формат CSV_DUMP .

Java

    // Create report downloader.
    ReportDownloader reportDownloader = new ReportDownloader(reportService, reportJob.getId());

    // Wait for the report to be ready.
    if (reportDownloader.waitForReportReady()) {
      // Change to your file location.
      File file = File.createTempFile("delivery-report-", ".csv.gz");

      System.out.printf("Downloading report to %s ...", file.toString());

      // Download the report.
      ReportDownloadOptions options = new ReportDownloadOptions();
      options.setExportFormat(ExportFormat.CSV_DUMP);
      options.setUseGzipCompression(true);
      URL url = reportDownloader.getDownloadUrl(options);
      Resources.asByteSource(url).copyTo(Files.asByteSink(file));

      System.out.println("done.");
    } else {
      System.out.printf("Report job %d failed.%n", reportJob.getId());
    }
    

Python

  # Change to your preferred export format.
  export_format = 'CSV_DUMP'

  report_file = tempfile.NamedTemporaryFile(suffix='.csv.gz', delete=False)

  # Download report data.
  report_downloader.DownloadReportToFile(
      report_job_id, export_format, report_file)

  report_file.close()

  # Display results.
  print('Report job with id "%s" downloaded to:\n%s' % (
      report_job_id, report_file.name))
    

PHP

      // Create report downloader to poll report's status and download when
      // ready.
      $reportDownloader = new ReportDownloader(
          $reportService,
          $reportJob->getId()
      );
      if ($reportDownloader->waitForReportToFinish()) {
          // Write to system temp directory by default.
          $filePath = sprintf(
              '%s.csv.gz',
              tempnam(sys_get_temp_dir(), 'delivery-report-')
          );
          printf("Downloading report to %s ...%s", $filePath, PHP_EOL);
          // Download the report.
          $reportDownloader->downloadReport(
              ExportFormat::CSV_DUMP,
              $filePath
          );
          print "done.\n";
      } else {
          print "Report failed.\n";
      }
    

C#

ReportUtilities reportUtilities =
    new ReportUtilities(reportService, reportJob.id);

// Set download options.
ReportDownloadOptions options = new ReportDownloadOptions();
options.exportFormat = ExportFormat.CSV_DUMP;
options.useGzipCompression = true;
reportUtilities.reportDownloadOptions = options;

// Download the report.
using (ReportResponse reportResponse = reportUtilities.GetResponse())
{
    reportResponse.Save(filePath);
}

Console.WriteLine("Report saved to \"{0}\".", filePath);
    

Руби

  MAX_RETRIES.times do |retry_count|
    # Get the report job status.
    report_job_status = report_service.get_report_job_status(report_job[:id])

    break unless report_job_status == 'IN_PROGRESS'
    puts 'Report with ID %d is still running.' % report_job[:id]
    sleep(RETRY_INTERVAL)
  end

  puts 'Report job with ID %d finished with status "%s".' % [report_job[:id],
      report_service.get_report_job_status(report_job[:id])]

  # Get the report URL.
  download_url = report_service.get_report_download_url(
      report_job_id, export_format
  )

  puts 'Downloading "%s" to "%s"...' % [download_url, file_name]
  open(file_name, 'wb') do |local_file|
    local_file << URI.open(download_url).read()
  end
    

Чтение данных отчета

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

Java

  List<String[]> rows = CsvFiles.getCsvDataArray(filePath, true);
  for (String[] row : rows) {
    // Additional row processing
    processReportRow(row);
  }
    

Python

  with open(report_file.name, 'rb') as report:
    report_reader = csv.reader(report)
    for row in report_reader:
      # Additional row processing
      process_row(row)
    

PHP

  $report = fopen($filePath, 'r');
  while (!feof($report)) {
    // Additional row processing
    processRow(fgetcsv($report));
  }
  fclose($report);
    

C#

  CsvFile file = new CsvFile();
  file.Read(fileName, true);
  for (String[] row : file.Records) {
    // Additional row processing
    ProcessReportRow(row);
  }
    

Руби

    CSV.foreach(file_name, converters: :numeric, headers: true) do |row|
      # Additional row processing
      process_row(row)
    end
    

Больше примеров отчетов вы найдете в наших клиентских библиотеках на GitHub.

Часто задаваемые вопросы

Почему все результаты отчетов по моей тестовой сети пусты?
Тестовые сети не показывают рекламу, поэтому в отчетах о доставке данных не будет.
Почему все результаты отчетов в моей производственной сети пусты?
Пользователь, от имени которого вы выполняете аутентификацию, может не иметь доступа к данным, по которым вы пытаетесь создать отчет. Убедитесь, что его роли и команды настроены правильно.
Почему при составлении отчета я получаю ошибку ReportError.COLUMNS_NOT_SUPPORTED_FOR_REQUESTED_DIMENSIONS ?
В Ad Manager поддерживаются не все комбинации столбцов и измерений. Для сложных отчетов может быть проще создать корректный отчет в пользовательском интерфейсе, а затем получить его с помощью метода ReportService.getSavedQueriesByStatement .
Почему мой сохранённый отчёт не возвращается в API?
Убедитесь, что владелец отчета предоставил доступ к отчету пользователю, от имени которого вы выполняете аутентификацию.
Почему мой сохранённый отчёт несовместим с API?
Некоторые функции создания отчетов недоступны в API. К ним относятся столбцы, атрибуты измерений, сами измерения и типы диапазонов дат. Для несовместимых типов диапазонов дат вы можете сохранить отчет с поддерживаемым типом, чтобы сделать его доступным для восстановления, а затем изменить ReportQuery в соответствии с желаемым фиксированным диапазоном дат.
Почему общее количество кликов/показов за все время не соответствует данным в моем отчете в пользовательском интерфейсе?
Показы за весь период существования позиции относятся ко всему времени ее существования, независимо от диапазона дат, заложенных в отчете. Если позиция по-прежнему приносит доход, значение, вероятно, изменится между запуском любых двух отчетов.
Подготовка отчетов занимает слишком много времени, а иногда и вовсе прерывается по истечении времени ожидания. Что я могу сделать?
Уменьшение диапазона дат или количества измерений поможет повысить производительность. Попробуйте запустить несколько отчетов для меньших диапазонов дат. Затем вы можете объединить данные отчетов, чтобы охватить нужный диапазон дат.
В чём разница между столбцами INVENTORY_LEVEL и LINE_ITEM_LEVEL ? Какой из них следует использовать?

Столбцы с LINE_ITEM_LEVEL можно использовать только в том случае, если в вашей сети включено динамическое распределение на уровне позиций заказа. Эти столбцы содержат данные из динамического распределения на уровне позиций заказа в AdSense или Ad Exchange. Аналогично, столбцы INVENTORY_LEVEL содержат данные из динамического распределения на уровне инвентаря. Для получения дополнительной информации о динамическом распределении см. раздел «Позиции заказа в Ad Exchange» .

Если вы все еще не уверены, какие столбцы API использовать, создайте сохраненный запрос в пользовательском интерфейсе Ad Manager и получите его с помощью метода ReportService.getSavedQueriesByStatement .