العثور على التقارير وتشغيلها

بعد تحديد تقرير يلبي احتياجاتك أو إنشاؤه، يحين وقت إنشاء إعلان. يتم تخزين إخراج التقرير في ملفات التقارير، ويمكن استرداده ومعالجته آليًا. يتم إنشاء ملف التقرير كنتيجة لتشغيل تقرير.

يشرح هذا الدليل كيفية إنشاء ملفات التقارير آليًا من خلال خدمة التقارير.

العثور على تقرير

لتشغيل تقرير، تحتاج إلى معرفة رقم تعريف التقرير. إذا أنشأت أو عدّلت تقريرًا، يمكنك العثور على هذه القيمة في الحقل id بمورد التقرير الذي تم عرضه. ننصح المستخدمين بتخزين أرقام التعريف المعروضة هذه للبحث لاحقًا.

إذا كنت لا تعرف رقم تعريف التقرير الذي تريد تشغيله، يمكنك البحث في قائمة جميع التقارير المتاحة للعثور على التقرير الذي تريده. يوضّح المثال التالي كيفية البحث عن تقرير حسب بعض المعايير التي يحدِّدها المستخدم:

C#‎

Report target = null;
ReportList reports;
String nextPageToken = null;

do {
  // Create and execute the reports list request.
  ReportsResource.ListRequest request = service.Reports.List(profileId);
  request.PageToken = nextPageToken;
  reports = request.Execute();

  foreach (Report report in reports.Items) {
    if (IsTargetReport(report)) {
      target = report;
      break;
    }
  }

  // Update the next page token.
  nextPageToken = reports.NextPageToken;
} while (target == null
    && reports.Items.Any()
    && !String.IsNullOrEmpty(nextPageToken));

لغة Java

Report target = null;
ReportList reports;
String nextPageToken = null;

do {
  // Create and execute the reports list request.
  reports = reporting.reports().list(profileId).setPageToken(nextPageToken).execute();

  for (Report report : reports.getItems()) {
    if (isTargetReport(report)) {
      target = report;
      break;
    }
  }

  // Update the next page token.
  nextPageToken = reports.getNextPageToken();
} while (target == null
    && !reports.getItems().isEmpty()
    && !Strings.isNullOrEmpty(nextPageToken));

‫2,999

$target = null;
$response = null;
$pageToken = null;

do {
    // Create and execute the report list request.
    $response = $this->service->reports->listReports(
        $userProfileId,
        ['pageToken' => $pageToken]
    );

    foreach ($response->getItems() as $report) {
        if ($this->isTargetReport($report)) {
            $target = $report;
            break;
        }
    }

    $pageToken = $response->getNextPageToken();
} while (empty($target) && !empty($response->getItems()) && !empty($pageToken));

لغة Python

target = None

# Construct the request.
request = service.reports().list(profileId=profile_id)

while True:
  response = request.execute()

  for report in response['items']:
    if is_target_report(report):
      target = report
      break

  if not target and response['items'] and response['nextPageToken']:
    request = service.reports().list_next(request, response)
  else:
    break

Ruby

page_token = nil
target = nil

loop do
  result = service.list_reports(profile_id, page_token: page_token)

  result.items.each do |report|
    if target_report?(report)
      target = report
      break
    end
  end

  page_token = (result.next_page_token if target.nil? && result.items.any?)
  break if page_token.to_s.empty?
end

ارجع إلى المستندات المرجعية للتعرّف على المعلّمات الاختيارية التي يمكنك تحديدها للتحكّم في كيفية ترتيب قائمة التقارير المعروضة وترتيبها. يمكن أن يكون التحكم في ترتيب هذه القائمة وترتيبها مفيدًا بشكل خاص للعثور على التقارير التي تم تعديلها مؤخرًا.

تنفيذ تقرير

بعد العثور على تقرير مناسب، يمكنك استخدام خدمة الإبلاغ لتشغيله وإنشاء ملف تقرير جديد. ويمكن تشغيل التقارير إما بشكل متزامن أو غير متزامن (تلقائي)، وذلك استنادًا إلى تعقيد التقرير والوقت الذي ستستغرقه عملية المعالجة. اطّلِع على دليل التقارير المتزامنة للحصول على تفاصيل عن إعداد التقارير المتزامنة مقابل التقارير غير المتزامنة.

لتشغيل تقرير، تُجري اتصالاً بطريقة التشغيل لخدمة الإبلاغ، كما في المثال أدناه:

C#‎

// Run the report.
File file = service.Reports.Run(profileId, reportId).Execute();

لغة Java

// Run the report.
File file = reporting.reports().run(profileId, reportId).execute();

‫2,999

// Run the report.
$file = $this->service->reports->run($userProfileId, $reportId);

لغة Python

# Run the report.
report_file = service.reports().run(
    profileId=profile_id, reportId=report_id).execute()

Ruby

# Run the report.
report_file = service.run_report(profile_id, report_id)

إنّ الرد على هذا الطلب هو مورد للملفات. وإذا كان هذا طلب تشغيل متزامنًا ناجحًا، سيتم ملء جميع حقول المورد المعروض وسيكون الملف جاهزًا للتنزيل. ولأنّ هذا طلب تشغيل غير متزامن، لن تتوفّر حقول رئيسية معيّنة وسيتم ضبط status للملف على PROCESSING، لأنّ التقرير لم ينتهِ بعد.

متى ينتهي تشغيل التقرير؟

عند تشغيل تقرير بشكلٍ غير متزامن، يتم إنشاء ملف عنصر نائب على الفور ويتم وضع التقرير في قائمة انتظار لمعالجته. يحتوي العنصر النائب على عنصرَين أساسيَين لمساعدتك في تحديد وقت انتهاء تشغيل التقرير:

  1. حقل id، والذي يمكن استخدامه للإشارة إلى هذا الملف في الطلبات اللاحقة:
  2. حقل status، الذي يمثل الحالة الحالية للتقرير.

لتحديد وقت انتهاء أحد التقارير، يجب التحقق بشكل دوري من status في الملف، كما في المثال أدناه:

C#‎

// Wait for the report file to finish processing.
// An exponential backoff policy is used to limit retries and conserve quota.
int sleep = 0;
int startTime = GetCurrentTimeInSeconds();
do {
  File file = service.Files.Get(reportId, fileId).Execute();

  if ("REPORT_AVAILABLE".Equals(file.Status)) {
    Console.WriteLine("File status is {0}, ready to download.", file.Status);
    return;
  } else if (!"PROCESSING".Equals(file.Status)) {
    Console.WriteLine("File status is {0}, processing failed.", file.Status);
    return;
  } else if (GetCurrentTimeInSeconds() - startTime > MAX_RETRY_ELAPSED_TIME) {
    Console.WriteLine("File processing deadline exceeded.");
    return;
  }

  sleep = GetNextSleepInterval(sleep);
  Console.WriteLine("File status is {0}, sleeping for {1} seconds.", file.Status, sleep);
  Thread.Sleep(sleep * 1000);
} while (true);

لغة Java

BackOff backOff =
    new ExponentialBackOff.Builder()
        .setInitialIntervalMillis(10 * 1000) // 10 second initial retry
        .setMaxIntervalMillis(10 * 60 * 1000) // 10 minute maximum retry
        .setMaxElapsedTimeMillis(60 * 60 * 1000) // 1 hour total retry
        .build();

do {
  File file = reporting.files().get(reportId, fileId).execute();

  if ("REPORT_AVAILABLE".equals(file.getStatus())) {
    // File has finished processing.
    System.out.printf("File status is %s, ready to download.%n", file.getStatus());
    return file;
  } else if (!"PROCESSING".equals(file.getStatus())) {
    // File failed to process.
    System.out.printf("File status is %s, processing failed.", file.getStatus());
    return null;
  }

  // The file hasn't finished processing yet, wait before checking again.
  long retryInterval = backOff.nextBackOffMillis();
  if (retryInterval == BackOff.STOP) {
    System.out.println("File processing deadline exceeded.%n");
    return null;
  }

  System.out.printf("File status is %s, sleeping for %dms.%n", file.getStatus(), retryInterval);
  Thread.sleep(retryInterval);
} while (true);

‫2,999

// Wait for the report file to finish processing.
// An exponential backoff policy is used to limit retries and conserve
// quota.
$sleep = 0;
$startTime = time();

do {
    $file = $this->service->files->get($reportId, $fileId);

    if ($file->getStatus() === 'REPORT_AVAILABLE') {
        printf('File status is %s, ready to download<br>', $file->getStatus());
        return $file;
    } elseif ($file->getStatus() !== 'PROCESSING') {
        printf('File status is %s, processing failed<br>', $file->getStatus());
        return null;
    } elseif (time() - $startTime > self::MAX_RETRY_ELAPSED_TIME) {
        printf('File processing deadline exceeded<br>');
        return null;
    }

    $sleep = $this->getNextSleepInterval($sleep);
    printf(
        'File status is %s, sleeping for %d seconds<br>',
        $file->getStatus(),
        $sleep
    );
    $this->sleep($sleep);
} while (true);

لغة Python

# Wait for the report file to finish processing.
# An exponential backoff strategy is used to conserve request quota.
sleep = 0
start_time = time.time()
while True:
  report_file = service.files().get(
      reportId=report_id, fileId=file_id).execute()

  status = report_file['status']
  if status == 'REPORT_AVAILABLE':
    print 'File status is %s, ready to download.' % status
    return
  elif status != 'PROCESSING':
    print 'File status is %s, processing failed.' % status
    return
  elif time.time() - start_time > MAX_RETRY_ELAPSED_TIME:
    print 'File processing deadline exceeded.'
    return

  sleep = next_sleep_interval(sleep)
  print 'File status is %s, sleeping for %d seconds.' % (status, sleep)
  time.sleep(sleep)

Ruby

# Wait for the report file to finish processing.
# An exponential backoff strategy is used to conserve request quota.
interval = 0
start_time = Time.now
loop do
  report_file = service.get_file(report_id, file_id)

  status = report_file.status
  if status == 'REPORT_AVAILABLE'
    puts format('File status is %s, ready to download.', status)
    break
  elsif status != 'PROCESSING'
    puts format('File status is %s, processing failed.', status)
    break
  elsif Time.now - start_time > MAX_RETRY_ELAPSED_TIME
    puts 'File processing deadline exceeded.'
    break
  end

  interval = next_sleep_interval(interval)
  puts format('File status is %s, sleeping for %d seconds.', status,
    interval)
  sleep(interval)
end

عند تغيير status إلى REPORT_AVAILABLE، يصبح الملف جاهزًا للتنزيل. كما هو موضّح في المثال أعلاه، ننصحك بشدة بتنفيذ استراتيجية تراجع أسي عند إجراء استطلاع مثل هذه، وذلك لتحسين استخدام حصة الطلبات.