Podstawy raportowania

Wprowadzenie

Z tego przewodnika dowiesz się, jak wygenerować i pobrać raport za pomocą interfejsu API. Obejmuje zarówno używanie istniejącego zapisanego zapytania raportu, jak i tworzenie zapytania raportu ad hoc.

Wymagania wstępne

Primer

Jeśli nie znasz raportowania w usłudze Ad Manager, zapoznaj się z artykułem Tworzenie nowego raportu, aby dowiedzieć się, jak wygenerować raport w interfejsie Ad Managera. Interfejs zawiera podgląd danych wyjściowych oraz etykietki, które wyjaśniają, jakie kombinacje kolumn i wymiarów są obsługiwane. Podczas tworzenia złożonego zapytania do raportu łatwiej może być najpierw utworzyć je w interfejsie, a potem pobrać za pomocą interfejsu API.

Pobieranie zapisanego zapytania ReportQuery

Obiekt ReportQuery zawiera wszystkie szczegóły raportu. Zapytania do raportów możesz tworzyć w interfejsie Ad Managera i pobierać je za pomocą metody ReportService.getSavedQueriesByStatement. Identyfikator zapisanego zapytania jest uwzględniany w adresie URL podczas wyświetlania zapytania w interfejsie. Na przykład w adresie URL https://www.google.com/admanager/1234#reports/report/detail/report_id=456789 identyfikator zapytania to 456789.

Jeśli zapytanie jest niezgodne z Twoją wersją interfejsu API, pole SavedQuery.reportQuery będzie miało wartość null, a pole SavedQuery.isCompatibleWithApiVersion – wartość false.

Zgodne zapisane zapytania można uruchamiać z modyfikacjami lub bez nich.

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;
    

Ruby

  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
    

Aby uruchomić zapytanie, zobacz Tworzenie zadania raportu.

Tworzenie zapytania ReportQuery

Oprócz korzystania z zapisanych zapytań możesz też tworzyć doraźne zapytania ReportQuery. Aby to zrobić, musisz ustawić wymiary, atrybuty wymiarów, kolumny, filtr i zakres dat raportu. Ten przykład dotyczy podstawowego raportu dostawy dla pojedynczego zamówienia.

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

Ruby

  # 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()
  }
    

Tworzenie zadania raportu

Gdy masz już obiekt ReportQuery, możesz wygenerować raport. Obiekt ReportJob zawiera stan raportu i informuje, kiedy jest on gotowy do pobrania. Aby zacząć generować raport, użyj metody 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);
    

Ruby

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

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

Pobieranie raportu

Po uruchomieniu zadania raportu będzie ono miało identyfikator ustawiony przez serwer. Użyj tego identyfikatora z metodą ReportService.getReportJobStatus, aby sprawdzić stan raportu. Gdy stan zmieni się na ReportJobStatus.COMPLETED, raport będzie gotowy do pobrania.

Niektóre z naszych bibliotek klienta zawierają narzędzia pomocnicze, które odpytują interfejs API i czekają na ukończenie raportu. Gdy raport będzie gotowy, możesz uzyskać adres URL do pobrania za pomocą metody ReportService.getReportDownloadURL. Raport można pobrać w różnych formatach. Jeśli chcesz dalej przetwarzać raport maszynowo, użyj formatu 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);
    

Ruby

  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
    

Odczytywanie danych do raportu

Wiele naszych bibliotek klienta zawiera narzędzia do odczytywania danych do raportu. Jest to przydatne, gdy chcesz dodatkowo przetworzyć dane do raportu lub połączyć raporty z różnych zakresów dat. Pamiętaj, że przykładowy kod zakłada, że plik nie jest skompresowany.

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

Ruby

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

Więcej przykładów raportowania znajdziesz w naszych bibliotekach klienta na GitHubie.

Najczęstsze pytania

Dlaczego wszystkie wyniki raportów w mojej sieci testowej są puste?
Sieci testowe nie wyświetlają reklam, więc raporty wyświetlania nie będą zawierać danych.
Dlaczego wszystkie wyniki raportu w mojej sieci produkcyjnej są puste?
Użytkownik, jako którego się uwierzytelniasz, może nie mieć dostępu do danych, które próbujesz uwzględnić w raporcie. Sprawdź, czy uprawnienia roli i zespoły są prawidłowo skonfigurowane.
Dlaczego w raporcie pojawia się błąd ReportError.COLUMNS_NOT_SUPPORTED_FOR_REQUESTED_DIMENSIONS?
Nie wszystkie kombinacje kolumn i wymiarów są obsługiwane w usłudze Ad Manager. W przypadku złożonych raportów łatwiej może być utworzyć prawidłowy raport w interfejsie, a następnie pobrać go za pomocą metody ReportService.getSavedQueriesByStatement.
Dlaczego mój zapisany raport nie jest zwracany w interfejsie API?
Upewnij się, że właściciel raportu udostępnił go użytkownikowi, którego używasz do uwierzytelniania.
Dlaczego mój zapisany raport jest niezgodny z interfejsem API?
Niektóre funkcje raportowania są niedostępne w interfejsie API. Obejmuje to kolumny, atrybuty wymiarów, wymiary i typy zakresów dat. W przypadku niezgodnych typów zakresów dat możesz zapisać raport z obsługiwanym typem, aby można go było pobrać, a następnie zmienić ReportQuery, aby uzyskać odpowiedni stały zakres dat.
Dlaczego liczba kliknięć/wyświetleń od początku śledzenia nie zgadza się z raportem w interfejsie?
Wyświetlenia od początku dotyczą całego okresu realizacji elementu zamówienia, niezależnie od zakresu dat raportu. Jeśli element zamówienia nadal wyświetla reklamy, wartość prawdopodobnie zmieni się między kolejnymi raportami.
Generowanie raportów trwa zbyt długo i czasami przekracza limit czasu. Co mogę zrobić?
Zmniejszenie zakresu dat lub liczby wymiarów pomoże poprawić wydajność. Zamiast tego spróbuj wygenerować kilka raportów dla krótszych zakresów dat. Następnie możesz scalić dane do raportu, aby objąć odpowiedni zakres dat.
Jaka jest różnica między kolumnami INVENTORY_LEVEL i LINE_ITEM_LEVEL? Którego z nich mam użyć?

Kolumn z LINE_ITEM_LEVEL można używać tylko wtedy, gdy w sieci masz włączoną alokację dynamiczną na poziomie elementu zamówienia. Te kolumny zawierają dane z alokacji dynamicznej na poziomie elementu zamówienia do AdSense lub Ad Exchange. Podobnie kolumny INVENTORY_LEVEL zawierają dane z alokacji dynamicznej na poziomie zasobów reklamowych. Więcej informacji o alokacji dynamicznej znajdziesz w artykule Elementy zamówienia Ad Exchange.

Jeśli nadal nie masz pewności, których kolumn interfejsu API użyć, utwórz zapisane zapytanie w interfejsie Ad Managera i pobierz je za pomocą metody ReportService.getSavedQueriesByStatement.