Thông tin cơ bản về báo cáo

Giới thiệu

Hướng dẫn này sẽ chỉ cho bạn cách chạy và tải báo cáo xuống bằng API. Hướng dẫn này đề cập đến cả việc sử dụng truy vấn báo cáo đã lưu hiện có và tạo truy vấn báo cáo đặc biệt.

Điều kiện tiên quyết

Primer

Nếu bạn chưa hiểu rõ về báo cáo trong Ad Manager, hãy xem bài viết Tạo báo cáo mới để biết thông tin tổng quan về cách chạy báo cáo trong giao diện người dùng Ad Manager. Giao diện người dùng có bản xem trước kết quả, cũng như chú giải công cụ giải thích các tổ hợp cột và phương diện được hỗ trợ. Khi tạo một truy vấn báo cáo phức tạp, trước tiên, bạn nên tạo một truy vấn báo cáo trong giao diện người dùng, sau đó truy xuất truy vấn đó bằng API.

Truy xuất ReportQuery đã lưu

Đối tượng ReportQuery chứa tất cả thông tin chi tiết của báo cáo. Bạn có thể tạo các truy vấn báo cáo trong giao diện người dùng Ad Manager và truy xuất các truy vấn đó bằng phương thức ReportService.getSavedQueriesByStatement. Mã truy vấn đã lưu được đưa vào URL khi bạn xem một truy vấn trong giao diện người dùng. Ví dụ: trong URL https://www.google.com/admanager/1234#reports/report/detail/report_id=456789, mã truy vấn là 456789.

Nếu một truy vấn không tương thích với phiên bản API của bạn, SavedQuery.reportQuery sẽ là nullSavedQuery.isCompatibleWithApiVersionfalse.

Bạn có thể chạy các truy vấn đã lưu tương thích mà có hoặc không cần sửa đổi.

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='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']
    

1.199


      $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
    

Để chạy truy vấn, hãy xem phần Tạo ReportJob.

Tạo ReportQuery

Ngoài việc sử dụng truy vấn đã lưu, bạn cũng có thể tạo một ReportQuery đặc biệt. Để thực hiện việc này, bạn phải đặt phương diện, thuộc tính phương diện, cột, bộ lọc và phạm vi ngày của báo cáo. Ví dụ này là dành cho báo cáo phân phối cơ bản cho một đơn đặt hàng.

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='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
      }
  }
    

1.199


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

Tạo ReportJob

Sau khi bạn có ReportQuery, đã đến lúc chạy báo cáo. Đối tượng ReportJob lưu giữ trạng thái của báo cáo và cho bạn biết thời điểm báo cáo đó có thể tải xuống. Để bắt đầu chạy báo cáo, hãy sử dụng phương thức 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='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)
    

1.199


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

Tải Báo cáo xuống

Sau khi bạn bắt đầu công việc báo cáo, nó sẽ có một mã do máy chủ đặt. Hãy sử dụng mã nhận dạng này với phương thức ReportService.getReportJobStatus để kiểm tra trạng thái của báo cáo. Sau khi trạng thái là ReportJobStatus.COMPLETED, bạn sẽ có thể tải báo cáo xuống.

Một số thư viện ứng dụng của chúng tôi có các tiện ích trợ giúp sẽ thăm dò API và chờ báo cáo hoàn tất. Khi báo cáo hoàn tất, bạn có thể lấy URL tải xuống bằng phương thức ReportService.getReportDownloadURL. Bạn có thể tải báo cáo xuống ở nhiều định dạng. Nếu muốn xử lý thêm báo cáo bằng máy, bạn nên sử dụng định dạng 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))
    

1.199


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

Đọc dữ liệu báo cáo

Nhiều thư viện ứng dụng của chúng tôi có các tiện ích để đọc dữ liệu báo cáo. Việc này rất hữu ích khi cần xử lý thêm dữ liệu báo cáo hoặc kết hợp các báo cáo trong nhiều phạm vi ngày. Xin lưu ý rằng mã ví dụ giả định tệp không được nén.

Java


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

1.199


  $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
    

Để biết thêm ví dụ về báo cáo, hãy xem thư viện ứng dụng của chúng tôi trên GitHub.

Câu hỏi thường gặp

Tại sao tất cả kết quả báo cáo trên mạng thử nghiệm của tôi đều trống?
Mạng thử nghiệm không phân phát quảng cáo, vì vậy, báo cáo phân phối sẽ không có dữ liệu.
Tại sao tất cả kết quả báo cáo trên mạng thực tế của tôi đều trống?
Người dùng mà bạn đang xác thực có thể không có quyền truy cập vào dữ liệu mà bạn đang cố gắng báo cáo. Xác minh rằng bạn đã thiết lập chính xác quyền vai trònhóm của họ.
Tại sao tôi gặp lỗi ReportError.COLUMNS_NOT_SUPPORTED_FOR_REQUESTED_DIMENSIONS trong báo cáo của mình?
Không phải cách kết hợp cột và phương diện nào cũng được hỗ trợ trong Ad Manager. Đối với các báo cáo phức tạp, bạn có thể dễ dàng tạo một báo cáo hợp lệ trong giao diện người dùng, sau đó truy xuất báo cáo đó bằng phương thức ReportService.getSavedQueriesByStatement.
Tại sao báo cáo đã lưu của tôi không được trả về trong API?
Hãy đảm bảo rằng chủ sở hữu báo cáo đã chia sẻ báo cáo với người dùng mà bạn đang xác thực.
Tại sao báo cáo đã lưu của tôi không tương thích với API?
Một số tính năng báo cáo không được cung cấp trong API. Dữ liệu này bao gồm cột, thuộc tính của phương diện, phương diện và loại phạm vi ngày. Đối với các loại phạm vi ngày không tương thích, bạn có thể lưu báo cáo với một loại được hỗ trợ để có thể truy xuất báo cáo, sau đó thay đổi ReportQuery để đáp ứng phạm vi ngày cố định mà bạn muốn.
Tại sao số lượt nhấp/lượt hiển thị toàn thời gian không khớp với báo cáo của tôi trong giao diện người dùng?
Số lượt hiển thị toàn thời gian là trong toàn bộ thời gian của mục hàng, bất kể phạm vi ngày của báo cáo. Nếu một mục hàng vẫn đang phân phối, thì giá trị có thể sẽ thay đổi giữa thời điểm chạy hai báo cáo bất kỳ.
Báo cáo của tôi mất quá nhiều thời gian và đôi khi hết thời gian chờ. Tôi có thể làm gì?
Việc giảm phạm vi ngày hoặc số lượng phương diện sẽ giúp cải thiện hiệu suất. Hãy thử chạy nhiều báo cáo cho các phạm vi ngày nhỏ hơn. Sau đó, bạn có thể hợp nhất dữ liệu báo cáo để xem xét phạm vi ngày mong muốn.
Sự khác biệt giữa cột INVENTORY_LEVELLINE_ITEM_LEVEL là gì? Tôi nên sử dụng công cụ nào?

Bạn chỉ có thể sử dụng các cột có LINE_ITEM_LEVEL nếu đã bật tính năng phân bổ động cấp mục hàng trên mạng của mình. Các cột này bao gồm dữ liệu từ tính năng phân bổ động cấp mục hàng đến AdSense hoặc Ad Exchange. Tương tự, các cột INVENTORY_LEVEL bao gồm dữ liệu từ tính năng phân bổ động cấp khoảng không quảng cáo. Để biết thêm thông tin về phân bổ động, hãy xem Mục hàng Ad Exchange.

Nếu bạn vẫn không chắc nên sử dụng cột API nào, hãy tạo một truy vấn đã lưu trong giao diện người dùng Ad Manager và truy xuất truy vấn đó bằng phương thức ReportService.getSavedQueriesByStatement.