輪詢並查看已完成的報表

報表執行作業會以非同步方式執行,屬於長時間執行的作業,並以 Operation 物件表示。報表執行作業的輸出內容是根據 Report 物件產生的報表結果。

本指南說明如何使用 Curation Partners API 取得報表執行作業,輪詢作業狀態,以及擷取已完成報表執行作業的報表結果。

事前準備

繼續操作前,請先完成下列事項:

輪詢報表執行狀態

如要檢查報表執行作業的執行狀態,請使用 curators.reports.operations.get 方法。

以下範例會發出 GET 要求,輪詢作業:

REST

要求

curl \
  'https://curationpartners.googleapis.com/v1/curators/ACCOUNT_ID/reports/123456789/operations/10486370264' \
  --header 'Authorization: Bearer ACCESS_TOKEN' \
  --header 'Accept: application/json' \
  --compressed

更改下列內容:

  • ACCOUNT_ID:您的帳戶 ID。
  • ACCESS_TOKEN:存取權杖。

回應

成功完成後,回應會是 Operation,且 done 欄位會設為 true,而 response 酬載會填入 reportResult 資源名稱:

{
  "name": "curators/ACCOUNT_ID/reports/123456789/operations/10486370264",
  "done": true,
  "metadata": {
    "@type": "type.googleapis.com/google.ads.curationpartners.v1.RunReportMetadata",
    "percentComplete": 100
  },
  "response": {
    "@type": "type.googleapis.com/google.ads.curationpartners.v1.RunReportResponse",
    "reportResult": "curators/ACCOUNT_ID/reports/123456789/results/10486370264"
  }
}

Java

/*
 * Copyright (c) 2026 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.api.services.samples.curationpartners.v1.curators.reports.operations;

import com.google.api.services.curationpartners.v1.CurationPartners;
import com.google.api.services.curationpartners.v1.model.Operation;
import com.google.api.services.samples.curationpartners.v1.Utils;
import java.io.IOException;
import java.security.GeneralSecurityException;
import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.ArgumentParserException;
import net.sourceforge.argparse4j.inf.Namespace;

public class GetReportOperation {

  /**
   * Executes the get operation for a report operation.
   *
   * @param curationPartnersClient the initialized Curation Partners API client.
   * @param accountId the account ID of the curator.
   * @param reportId the resource ID of the report.
   * @param operationId the resource ID of the report operation.
   * @throws IOException if the API returns an error.
   */
  public static void execute(
      CurationPartners curationPartnersClient,
      Long accountId,
      String reportId,
      String operationId)
      throws IOException {
    String name =
        String.format(
            "curators/%s/reports/%s/operations/%s", accountId, reportId, operationId);

    System.out.printf("Getting report operation with name \"%s\".%n", name);

    // Get the status of the report operation.
    Operation operation =
        curationPartnersClient
            .curators()
            .reports()
            .operations()
            .get(name)
            .execute();

    System.out.println("Successfully retrieved report operation:");
    Utils.jsonPrettyPrint(operation);
  }

  /**
   * Creates and configures the ArgumentParser for this sample.
   *
   * @return the configured ArgumentParser.
   */
  private static ArgumentParser createArgumentParser() {
    ArgumentParser parser =
        ArgumentParsers.newFor("GetReportOperation")
            .build()
            .defaultHelp(true)
            .description("Gets the status of a long-running report operation. If the " +
                "operation is done, you can view the report contents with the " +
                "`curators.reports.results.fetchRows` method.");

    // Required arguments.
    parser
        .addArgument("-a", "--account_id")
        .help("The account ID of the curator.")
        .required(true)
        .type(Long.class);
    parser
        .addArgument("-r", "--report_id")
        .help("The resource ID of the report.")
        .required(true);
    parser
        .addArgument("-o", "--operation_id")
        .help("The resource ID of the report operation to retrieve.")
        .required(true);

    return parser;
  }

  public static void main(String[] args) {
    ArgumentParser parser = createArgumentParser();

    Namespace parsedArgs = null;
    try {
      parsedArgs = parser.parseArgs(args);
    } catch (ArgumentParserException ex) {
      parser.handleError(ex);
      System.exit(1);
    }

    CurationPartners client = null;
    try {
      client = Utils.getCurationPartnersClient();
    } catch (IOException ex) {
      System.out.printf("Unable to create Curation Partners API service:%n%s", ex);
      System.out.println("Did you specify a valid path to a service account key file?");
      System.exit(1);
    } catch (GeneralSecurityException ex) {
      System.out.printf("Unable to establish secure HttpTransport:%n%s", ex);
      System.exit(1);
    }

    try {
      execute(
          client,
          parsedArgs.getLong("account_id"),
          parsedArgs.getString("report_id"),
          parsedArgs.getString("operation_id"));
    } catch (IOException ex) {
      System.out.printf("Curation Partners API returned error response:%n%s", ex);
      System.exit(1);
    }
  }
}

以下說明如何使用 done 欄位輪詢作業狀態:

  • 如果回應中的 done 欄位是 false 值,表示報表執行作業仍在處理中。
  • 如果回應中的 done 欄位是 true 值,表示報表執行作業已完成。回應主體中的 Operation 物件也包含下列其中一個欄位:
    • response:表示報表執行作業成功。 這個欄位是物件,其中填入的 @type 欄位會設為 type.googleapis.com/google.ads.curationpartners.v1.RunReportResponse 類型。RunReportResponse 類型會填入 reportResult 欄位,其中包含對應報表的名稱 result。
    • error:表示報表執行作業未成功。error 欄位會填入 Status 物件,說明報表執行失敗的原因。

從已完成的報表擷取資料列

您可以使用 curators.reports.results.fetchRows 方法,擷取已完成的報表執行作業內容。您必須填寫報表結果的 name 路徑參數,也就是完整報表執行作業 reportResult 欄位的資源名稱。

以下範例會發出 GET 要求,擷取結果列:

REST

要求

curl \
  'https://curationpartners.googleapis.com/v1/curators/ACCOUNT_ID/reports/123456789/results/10486370264:fetchRows?pageSize=1' \
  --header 'Authorization: Bearer ACCESS_TOKEN' \
  --header 'Accept: application/json' \
  --compressed

回應

{
  "rows": [
    {
      "dimensionValues": [
        {
          "stringValue": "2026-08-01"
        },
        {
          "stringValue": "segment-1001"
        }
      ],
      "metricValueGroups": [
        {
          "primaryValues": [
            {
              "intValue": "150000"
            },
            {
              "intValue": "3200"
            },
            {
              "doubleValue": 450.75
            },
            {
              "doubleValue": 45.08
            }
          ]
        }
      ]
    }
  ],
  "runTime": "2026-08-05T12:00:00Z",
  "dateRanges": [
    {
      "startDate": {
        "year": 2026,
        "month": 7,
        "day": 6
      },
      "endDate": {
        "year": 2026,
        "month": 8,
        "day": 4
      }
    }
  ],
  "totalRowCount": 2,
  "nextPageToken": "QC7nzW91c2VTcGFubmVyQ29udGlubWF0aW6uVG9wZY45NP=="
}

Java

/*
 * Copyright (c) 2026 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.api.services.samples.curationpartners.v1.curators.reports.results;

import com.google.api.services.curationpartners.v1.CurationPartners;
import com.google.api.services.curationpartners.v1.model.FetchReportResultRowsResponse;
import com.google.api.services.samples.curationpartners.v1.Utils;
import java.io.IOException;
import java.security.GeneralSecurityException;
import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.ArgumentParserException;
import net.sourceforge.argparse4j.inf.Namespace;

public class FetchReportResultRows {

  /**
   * Executes the fetchRows operation for report result rows.
   *
   * @param curationPartnersClient the initialized Curation Partners API client.
   * @param accountId the account ID of the curator.
   * @param reportId the resource ID of the report.
   * @param resultId the resource ID of the report result.
   * @param pageSize the maximum number of rows to return per page.
   * @param pageToken the page token from a previous response, if any.
   * @throws IOException if the API returns an error.
   */
  public static void execute(
      CurationPartners curationPartnersClient,
      Long accountId,
      String reportId,
      String resultId,
      Integer pageSize,
      String pageToken)
      throws IOException {
    String name = String.format("curators/%s/reports/%s/results/%s", accountId, reportId, resultId);

    System.out.printf("Fetching report result rows for \"%s\".%n", name);

    CurationPartners.Curators.Reports.Results.FetchRows request =
        curationPartnersClient.curators().reports().results().fetchRows(name);

    if (pageSize != null) {
      request.setPageSize(pageSize);
    }
    if (pageToken != null) {
      request.setPageToken(pageToken);
    }

    FetchReportResultRowsResponse response = request.execute();

    System.out.println("Successfully fetched report result rows:");
    Utils.jsonPrettyPrint(response);
  }

  /**
   * Creates and configures the ArgumentParser for this sample.
   *
   * @return the configured ArgumentParser.
   */
  private static ArgumentParser createArgumentParser() {
    ArgumentParser parser =
        ArgumentParsers.newFor("FetchReportResultRows")
            .build()
            .defaultHelp(true)
            .description("Fetches rows for a completed report result.");

    // Required arguments.
    parser
        .addArgument("-a", "--account_id")
        .help("The account ID of the curator.")
        .required(true)
        .type(Long.class);
    parser
        .addArgument("-r", "--report_id")
        .help("The resource ID of the report.")
        .required(true);
    parser
        .addArgument("--result_id")
        .help("The resource ID of the report result. This is identical to the resource ID of " +
            "the corresponding report run operation.")
        .required(true);

    // Optional arguments.
    parser
        .addArgument("--page_size")
        .help("The maximum number of rows to return per page.")
        .type(Integer.class);
    parser
        .addArgument("--page_token")
        .help("A page token, received from a previous `FetchReportResultRows` call.");

    return parser;
  }

  public static void main(String[] args) {
    ArgumentParser parser = createArgumentParser();

    Namespace parsedArgs = null;
    try {
      parsedArgs = parser.parseArgs(args);
    } catch (ArgumentParserException ex) {
      parser.handleError(ex);
      System.exit(1);
    }

    CurationPartners client = null;
    try {
      client = Utils.getCurationPartnersClient();
    } catch (IOException ex) {
      System.out.printf("Unable to create Curation Partners API service:%n%s", ex);
      System.out.println("Did you specify a valid path to a service account key file?");
      System.exit(1);
    } catch (GeneralSecurityException ex) {
      System.out.printf("Unable to establish secure HttpTransport:%n%s", ex);
      System.exit(1);
    }

    try {
      execute(
          client,
          parsedArgs.getLong("account_id"),
          parsedArgs.getString("report_id"),
          parsedArgs.getString("result_id"),
          parsedArgs.getInt("page_size"),
          parsedArgs.getString("page_token"));
    } catch (IOException ex) {
      System.out.printf("Curation Partners API returned error response:%n%s", ex);
      System.exit(1);
    }
  }
}

您可以指定下列查詢參數:

  • pageSize:要傳回的資料列數量上限。預設值為 1,000 列,最多 10,000 列。
  • pageToken:先前 fetchRows 回應中傳回的頁面權杖,用於擷取下一批資料列。

回應包含下列欄位:

  • rows:Row 物件的陣列。每個資料列包含:
    • dimensionValues:每個所要求維度的值,排序方式與報表定義中的維度相同。
    • metricValueGroups:與日期範圍對應的指標值群組。每個群組都包含 primaryValues 清單,排序方式與報表定義中的指標相同。
  • dateRanges: 報表計算出的固定日期範圍。dateRanges 欄位只會包含在第一頁的回應主體中。
  • totalRowCount: 報表結果中的資料列總數。totalRowCount 欄位只會包含在第一頁的回應主體中。
  • nextPageToken: 在後續要求中傳遞的權杖,用於擷取下一頁的資料列。 如果沒有其他資料列,Curation Partners API 會從回應主體中省略這個欄位。

在 curators.reports.results.fetchRows REST 範例中,rows 中的每個項目都會直接對應至報表中設定的 ReportDefinition:

  • dimensionValues:包含與 reportDefinition.dimensions 欄位中每個維度對應的值,且順序與您指定的完全相同。在這個範例中,第一個值 2026-08-01 對應至 DATE 維度,第二個值 segment-1001 則對應至 CURATION_DATA_SEGMENT_ID 維度。
  • metricValueGroups:包含報表日期範圍內分組的指標值。在每個群組中,primaryValues 欄位會包含與 reportDefinition.metrics 欄位中每個指標對應的值,且順序與您指定的完全相同。在本例中,這四個值對應於下列 Metric 列舉值:

    • IMPRESSIONS:150000
    • CLICKS:3200
    • SPEND:450.75
    • CURATION_PARTNER_FEE:45.08
  • dateRanges:包含 Google 為報表定義中設定的相對範圍 THIS_MONTH_TO_DATE 計算的固定日期範圍。

後續步驟