レポートの検索と実行

ニーズに合ったレポートを特定または作成したら、次に出力を生成します。レポートの出力はレポート ファイルに保存され、プログラムから取得や操作を行うことができます。レポート ファイルはレポートを実行すると自動的に作成されます。

このガイドでは、プログラムから Reports サービスを使用してレポート ファイルを生成する方法について詳しく説明します。

レポートを検索する

レポートを実行するには、そのレポートの ID を知る必要があります。レポートを作成または更新した直後であれば、返されたレポート リソースの id フィールドでその値を確認できます。後で参照するために ID を保存しておくことをおすすめします。

実行するレポートの 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

返されたレポートのリストの並べ替え方を指定できるオプションのパラメータについては、リファレンス ドキュメントをご覧ください。リストを指定順に並べ替えるこの方法は、特に、最近変更されたレポートを探す場合に便利です。

レポートを実行する

適切なレポートが見つかったら、Reports サービスを使用してレポートを実行し、新しいレポート ファイルを生成することができます。レポートは、その複雑さと処理にかかる時間に応じて、同期または非同期(デフォルト)で実行できます。レポートの同期と非同期の違いについて詳しくは、同期レポートのガイドをご覧ください。

レポートを実行するには、下記の例のように、Reports サービスの run メソッドを呼び出します。

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)

このリクエストのレスポンスは Files リソースです。同期リクエストが正常に実行された場合、すべてのフィールドに値が入力されたリソースが返され、ファイルをダウンロードできる状態になります。一方、上記は非同期実行のリクエストなので、レポートは実行中となり、一部の主要なフィールドが欠落した状態でリソースが返され、ファイルの statusPROCESSING に設定されます。

レポートの実行終了を確認する

レポートを非同期に実行する場合、プレースホルダ ファイルがすぐに生成され、レポートは処理待ちのキューに入ります。プレースホルダには、レポートの実行が終了したかどうかを確認できる情報が 2 種類あります。

  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

statusREPORT_AVAILABLE に変わると、ファイルはダウンロードできる状態になります。上記の例に示すように、こうしたポーリングを行う際は、リクエストの割り当ての使用量を最適化するために指数バックオフ機能を実装することを強くおすすめします。