اصول گزارش‌دهی

مقدمه

این راهنما به شما نشان می‌دهد که چگونه بااستفاده از API گزارشی را اجرا و بارگیری کنید. این دوره هم شامل استفاده از پُرسمان گزارش ذخیره‌شده موجود و هم ایجاد پُرسمان گزارش موردی می‌شود.

پیش‌نیازها

Primer

اگر با گزارش‌دهی در Ad Manager آشنا نیستید، برای دریافت نمای کلی از نحوه اجرای گزارش در واسط کاربر Ad Manager، به ایجاد گزارش جدید مراجعه کنید. رابط کاربری پیش‌نمایشی از خروجی و همچنین نکته‌ابزارهایی دارد که توضیح می‌دهند کدام ترکیب‌های ستون و بُعد پشتیبانی می‌شوند. هنگام ایجاد یک پُرسمان گزارش پیچیده، ممکن است ایجاد آن در واسط کاربر در ابتدا آسان‌تر باشد و سپس پُرسمان را با API بازیابی کنید.

درحال بازیابی ReportQuery ذخیره‌شده

شیء ReportQuery حاوی همه جزئیات گزارش است. می‌توانید پُرسمان‌های گزارش را در میانای کاربری Ad Manager ایجاد کنید و آن‌ها را با روش ReportService.getSavedQueriesByStatement بازیابی کنید. شناسه پُرسمان ذخیره‌شده در نشانی وب گنجانده شده است، هنگام مشاهده پُرسمان در رابط کاربری. برای مثال، در نشانی وب https://www.google.com/admanager/1234#reports/report/detail/report_id=456789 شناسه پُرسمان 456789 است.

اگر پُرسمانی با نسخه میانای برنامه‌سازی کاربردی شما سازگار نباشد، SavedQuery.reportQuery null خواهد بود و SavedQuery.isCompatibleWithApiVersion false خواهد بود.

پُرسمان‌های ذخیره‌شده سازگار را می‌توان با یا بدون اصلاح اجرا کرد.

جاوا

    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
    

برای اجرای پُرسمان، ایجاد ReportJob را ببینید.

درحال ساختن ReportQuery

علاوه‌بر استفاده از پُرسمان‌های ذخیره‌شده، می‌توانید 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());
    

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

درحال ایجاد ReportJob

وقتی ReportQuery را داشتید، زمان اجرای گزارش است. شیء ReportJob وضعیت گزارش را نگه می‌دارد و به شما اطلاع می‌دهد که چه زمانی برای بارگیری آماده است. برای شروع اجرای گزارش، از روش ReportService.runReportJob استفاده کنید.

جاوا

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

درحال بارگیری گزارش

پس‌از شروع کار گزارش، شناسه‌ای خواهد داشت که توسط سرور تنظیم شده است. از این شناسه با روش ReportService.getReportJobStatus برای بررسی وضعیت گزارش خود استفاده کنید. وقتی وضعیت ReportJobStatus.COMPLETED باشد، گزارش برای بارگیری آماده است.

برخی‌از کتابخانه‌های مشتری ما ابزارهای کمکی دارند که میانای برنامه‌سازی کاربردی را نظرسنجی می‌کنند و منتظر می‌مانند تا گزارش تکمیل شود. وقتی گزارش تکمیل شد، می‌توانید نشانی وب بارگیری را با روش 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());
    }
    

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
    

خواندن داده‌های گزارش

بسیاری از کتابخانه‌های مشتری ما شامل ابزارهای کمکی برای خواندن داده‌های گزارش هستند. این کار برای انجام پردازش بیشتر روی داده‌های گزارش یا ترکیب گزارش‌های مربوط به محدوده‌های تاریخ مختلف مفید است. توجه داشته باشید که کد نمونه فرض می‌کند فایل فشرده نشده است.

جاوا

  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
    

برای نمونه‌های گزارش‌دهی بیشتر، کتابخانه‌های مشتری ما را در 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 بازیابی کنید.