חיפוש והרצה של דוחות

לאחר זיהוי או יצירה של דוח שתואם את הצרכים שלך, הגיע הזמן ליצור פלט. פלט הדוחות נשמר בקובצי דוח. ניתן לאחזר אותם ולבצע בהם שינויים באופן פרוגרמטי. מופק קובץ דוח כתוצאה מהפעלת דוח.

במדריך הזה נסביר איך ליצור קובצי דוחות באופן פרוגרמטי דרך שירות הדוחות.

איתור דוח

כדי להפיק דוח, צריך לדעת את מזהה הדוח. אם יצרת או עדכנת דוח, הערך הזה מופיע בשדה 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));

PHP‏

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

PHP‏

// 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 מכיוון שהדוח עדיין לא הסתיים.

מתי פועל דוח כלשהו?

כשמריצים דוח באופן אסינכרוני, קובץ placeholder נוצר מיד והדוח מועבר לתור לעיבוד. ה-placeholder יכיל שני פרטים חשובים שיעזרו לכם לקבוע מתי הדוח מסתיים:

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

PHP‏

// 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, הקובץ יהיה מוכן להורדה. כפי שמתואר בדוגמה שלמעלה, מומלץ בחום ליישם אסטרטגיית השהיה מעריכית בעת עריכת סקר כזה, כדי לבצע אופטימיזציה של השימוש במכסת הבקשות.