使用 GoogleAdsService 流式传输报告

如需检索 Google Ads API 实体和报告数据,请使用以下方法之一:

以下是这两种方法的主要区别:

GoogleAdsService.SearchStream GoogleAdsService.Search
适用于生产代码 是 是
服务 GoogleAdsService GoogleAdsService
场景 正在提取对象和报告 正在提取对象和报告
响应 GoogleAdsRow 对象的流 GoogleAdsRow 对象的页面
响应的字段 仅限查询中指定的那些 仅限查询中指定的那些
每日上限 每日限额取决于访问权限级别 每日限额取决于访问权限级别

Search 会发送多个分页请求来下载整个报告,而 SearchStream 会发送单个请求,并与 Google Ads API 建立持久的 gRPC 连接,无论报告大小如何。

对于 SearchStream,数据包会立即开始以 SearchGoogleAdsStreamResponse 个对象为一批进行下载。您的代码可以在传入批次到达时对其进行迭代,而无需等待整个流完成。

通过消除请求 Search 响应的每个单独页面所需的往返网络时间,SearchStream 提供了比分页更好的性能,尤其是对于大型报告。

示例

此示例查看的是包含 100,000 行的报告。下表详细说明了这两种方法的请求和响应差异:

SearchStream 搜索
页面大小 不适用 每页 10,000 行
API 请求数 1 个请求 10 个请求
API 响应数量 1 个连续数据流 10 条回复

影响效果的因素

对于大多数应用场景,我们建议使用 SearchStream 而不是 Search,原因如下:

  • 单页报告(少于 10,000 行):这两种方法在性能上没有显著差异。
  • 多页报告:SearchStream 通常更快,因为避免了多次网络往返,并且从磁盘缓存读取或写入的影响较小。
  • 内存效率:使用 SearchStream 处理大型报告时,请遍历数据流块并在行到达时进行处理,而不是一次性将所有行缓冲到内存中,以避免内存不足 (OOM) 错误。
  • 连接弹性:由于 SearchStream 依赖于持久连接,因此长时间运行的流可能会因网络中断或截止期限超时而中断。配置适当的 RPC 超时,并针对暂时性流错误实现重试逻辑。

速率限制

这两种方法的每日操作限制均遵循 Google Cloud 项目的标准限制和访问权限级别。无论结果是通过 SearchStream 流式传输,还是使用 Search 和 page_token 跨多个缓存页面检索,单个逻辑报告查询都会计为一次操作,并计入您的每日操作配额。不过,每个分页 Search 请求仍会计为一次单独的 RPC 调用,并计入短期速率限制。

代码示例

以下代码示例演示了如何使用客户端库执行流式报告查询:

Java

private void runExample(GoogleAdsClient googleAdsClient, long customerId) {
  try (GoogleAdsServiceClient googleAdsServiceClient =
      googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
    String query = "SELECT campaign.id, campaign.name FROM campaign ORDER BY campaign.id";
    // Constructs the SearchGoogleAdsStreamRequest.
    SearchGoogleAdsStreamRequest request =
        SearchGoogleAdsStreamRequest.newBuilder()
            .setCustomerId(Long.toString(customerId))
            .setQuery(query)
            .build();

    // Creates and issues a search Google Ads stream request that will retrieve all campaigns.
    ServerStream<SearchGoogleAdsStreamResponse> stream =
        googleAdsServiceClient.searchStreamCallable().call(request);

    // Iterates through and prints all of the results in the stream response.
    for (SearchGoogleAdsStreamResponse response : stream) {
      for (GoogleAdsRow googleAdsRow : response.getResultsList()) {
        System.out.printf(
            "Campaign with ID %d and name '%s' was found.%n",
            googleAdsRow.getCampaign().getId(), googleAdsRow.getCampaign().getName());
      }
    }
  }
}
      

C#

public void Run(GoogleAdsClient client, long customerId)
{
    // Get the GoogleAdsService.
    GoogleAdsServiceClient googleAdsService = client.GetService(
        Services.V26.GoogleAdsService);

    // Create a query that will retrieve all campaigns.
    string query = @"SELECT
                    campaign.id,
                    campaign.name,
                    campaign.network_settings.target_content_network
                FROM campaign
                ORDER BY campaign.id";

    try
    {
        // Issue a search request.
        googleAdsService.SearchStream(customerId.ToString(), query,
            delegate (SearchGoogleAdsStreamResponse resp)
            {
                foreach (GoogleAdsRow googleAdsRow in resp.Results)
                {
                    Console.WriteLine("Campaign with ID {0} and name '{1}' was found.",
                        googleAdsRow.Campaign.Id, googleAdsRow.Campaign.Name);
                }
            }
        );
    }
    catch (GoogleAdsException e)
    {
        Console.WriteLine("Failure:");
        Console.WriteLine($"Message: {e.Message}");
        Console.WriteLine($"Failure: {e.Failure}");
        Console.WriteLine($"Request ID: {e.RequestId}");
        throw;
    }
}
      

PHP

public static function runExample(GoogleAdsClient $googleAdsClient, int $customerId)
{
    $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
    // Creates a query that retrieves all campaigns.
    $query = 'SELECT campaign.id, campaign.name FROM campaign ORDER BY campaign.id';
    // Issues a search stream request.
    /** @var GoogleAdsServerStreamDecorator $stream */
    $stream = $googleAdsServiceClient->searchStream(
        SearchGoogleAdsStreamRequest::build($customerId, $query)
    );

    // Iterates over all rows in all messages and prints the requested field values for
    // the campaign in each row.
    foreach ($stream->iterateAllElements() as $googleAdsRow) {
        /** @var GoogleAdsRow $googleAdsRow */
        printf(
            "Campaign with ID %d and name '%s' was found.%s",
            $googleAdsRow->getCampaign()->getId(),
            $googleAdsRow->getCampaign()->getName(),
            PHP_EOL
        );
    }
}
      

Python

def main(client: GoogleAdsClient, customer_id: str) -> None:
    ga_service: GoogleAdsServiceClient = client.get_service("GoogleAdsService")

    query: str = """
        SELECT
          campaign.id,
          campaign.name
        FROM campaign
        ORDER BY campaign.id"""

    # Issues a search request using streaming.
    stream: Iterator[SearchGoogleAdsStreamResponse] = ga_service.search_stream(
        customer_id=customer_id, query=query
    )

    for batch in stream:
        rows: List[GoogleAdsRow] = batch.results
        for row in rows:
            print(
                f"Campaign with ID {row.campaign.id} and name "
                f'"{row.campaign.name}" was found.'
            )
      

Ruby

def get_campaigns(customer_id)
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  responses = client.service.google_ads.search_stream(
    customer_id: customer_id,
    query: 'SELECT campaign.id, campaign.name FROM campaign ORDER BY campaign.id',
  )

  responses.each do |response|
    response.results.each do |row|
      puts "Campaign with ID #{row.campaign.id} and name '#{row.campaign.name}' was found."
    end
  end
end
      

Perl

sub get_campaigns {
  my ($api_client, $customer_id) = @_;

  # Create a search Google Ads stream request that will retrieve all campaigns.
  my $search_stream_request =
    Google::Ads::GoogleAds::V26::Services::GoogleAdsService::SearchGoogleAdsStreamRequest
    ->new({
      customerId => $customer_id,
      query      =>
        "SELECT campaign.id, campaign.name FROM campaign ORDER BY campaign.id"
    });

  # Get the GoogleAdsService.
  my $google_ads_service = $api_client->GoogleAdsService();

  my $search_stream_handler =
    Google::Ads::GoogleAds::Utils::SearchStreamHandler->new({
      service => $google_ads_service,
      request => $search_stream_request
    });

  # Issue a search request and process the stream response to print the requested
  # field values for the campaign in each row.
  $search_stream_handler->process_contents(
    sub {
      my $google_ads_row = shift;
      printf "Campaign with ID %d and name '%s' was found.\n",
        $google_ads_row->{campaign}{id}, $google_ads_row->{campaign}{name};
    });

  return 1;
}
      

curl