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

Введение

Это руководство покажет вам, как запустить и загрузить отчет с помощью API. Он охватывает как использование существующего сохраненного запроса отчета, так и создание специального запроса отчета.

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

Праймер

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

Получение сохраненного запроса отчета

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

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

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

Джава


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

Питон


  statement = (ad_manager.StatementBuilder(version='v202402')
               .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();
    

С#


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
    

Чтобы выполнить запрос, см. Создание ReportJob .

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

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

Джава


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

Питон


  # Create statement object to filter for an order.
  statement = (ad_manager.StatementBuilder(version='v202402')
               .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()
      );
    

С#


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

Джава


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

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

Питон


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

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

С#


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

Джава


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

Питон


  # 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";
      }
    

С#


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 << open(download_url).read()
  end
    

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

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

Джава


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

Питон


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

С#


  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 для моего отчета?
Не все комбинации столбцов и параметров поддерживаются в Менеджере рекламы. Для сложных отчетов может быть проще создать действительный отчет в пользовательском интерфейсе, а затем получить его с помощью метода ReportService.getSavedQueriesByStatement .
Почему мой сохраненный отчет не возвращается в API?
Убедитесь, что владелец отчета предоставил доступ к отчету пользователю, под которым вы проходите аутентификацию.
Почему мой сохраненный отчет несовместим с API?
Некоторые функции отчетности недоступны в API. Сюда входят столбцы, атрибуты измерений, измерения и типы диапазонов дат. Для несовместимых типов диапазона дат вы можете сохранить отчет с поддерживаемым типом, чтобы сделать его доступным для извлечения, а затем изменить ReportQuery , чтобы он соответствовал желаемому фиксированному диапазону дат.
Почему количество кликов/показов за весь период не соответствует моему отчету в пользовательском интерфейсе?
Показы за весь срок действия производятся в течение всего срока действия позиции, независимо от диапазона дат отчета. Если позиция по-прежнему выполняется, значение, вероятно, будет меняться при запуске любых двух отчетов.
Мои отчеты занимают слишком много времени и иногда прерываются. Что я могу сделать?
Уменьшение диапазона дат или количества параметров поможет повысить производительность. Вместо этого попробуйте создать несколько отчетов для меньших диапазонов дат. Затем вы можете объединить данные отчета, чтобы охватить нужный диапазон дат.
В чем разница между столбцами INVENTORY_LEVEL и LINE_ITEM_LEVEL ? Что мне следует использовать?

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

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