GoogleAdsService를 사용하여 보고서 스트리밍

Google Ads API 항목 및 보고 데이터를 검색하려면 다음 방법 중 하나를 사용하세요.

두 방법의 대략적인 차이점은 다음과 같습니다.

GoogleAdsService.SearchStream GoogleAdsService.Search
프로덕션 코드에 적합 예 예
서비스 GoogleAdsService GoogleAdsService
시나리오 객체 및 보고서 가져오기 객체 및 보고서 가져오기
응답 스트림 of GoogleAdsRow 객체 GoogleAdsRow 객체의 페이지
응답의 필드 쿼리에 지정된 필드만 쿼리에 지정된 필드만
일일 한도 액세스 수준에 따른 일일 한도 액세스 수준에 따른 일일 한도

Search는 전체 보고서를 다운로드하기 위해 여러 페이지로 나누어진 요청을 전송하는 반면 SearchStream는 보고서 크기와 관계없이 단일 요청을 전송하고 Google Ads API와의 영구 gRPC 연결을 시작합니다.

SearchStream의 경우 데이터 패킷이 SearchGoogleAdsStreamResponse 객체 배치로 즉시 다운로드되기 시작합니다. 코드는 전체 스트림이 완료될 때까지 기다리지 않고 도착하는 대로 수신 배치를 반복할 수 있습니다.

SearchStream은 Search 응답의 각 개별 페이지를 요청하는 데 필요한 왕복 네트워크 시간을 없애므로 특히 대규모 보고서의 경우 페이징보다 성능이 향상됩니다.

예

이 예에서는 100,000개의 행으로 구성된 보고서를 살펴봅니다. 다음 표는 두 방법 간의 요청 및 응답 차이점을 보여줍니다.

SearchStream Search
페이지 크기 해당 없음 페이지당 10,000개 행
API 요청 수 요청 1개 요청 10개
API 응답 수 연속 스트림 1개 응답 10개

실적 요인

대부분의 사용 사례에서는 다음과 같은 이유로 Search보다 SearchStream을 사용하는 것이 좋습니다.

  • 단일 페이지 보고서 (10,000개 미만의 행): 두 방법 간에 성능 차이가 크지 않습니다.
  • 다중 페이지 보고서: SearchStream은 일반적으로 여러 네트워크 왕복을 피하고 디스크 캐시에서 읽거나 쓰는 것이 덜 중요하므로 더 빠릅니다.
  • 메모리 효율성: SearchStream으로 대규모 보고서를 처리할 때는 메모리 부족 (OOM) 오류를 방지하기 위해 모든 행을 한 번에 메모리에 버퍼링하는 대신 스트림 청크를 반복하고 행이 도착하는 대로 처리합니다.
  • 연결 복원력: SearchStream은 영구 연결에 의존하므로 장기 실행 스트림이 네트워크 중단 또는 기한 시간 제한으로 인해 중단될 수 있습니다. 적절한 RPC 시간 제한을 구성하고 일시적인 스트림 오류에 대한 재시도 로직을 구현합니다.

비율 제한

두 방법의 일일 작업 한도는 Google Cloud 프로젝트의 표준 한도 및 액세스 수준을 준수합니다. 결과가 SearchStream으로 스트리밍되는지 또는 page_token이 있는 Search을 사용하여 여러 캐시된 페이지에서 검색되는지와 관계없이 단일 논리 보고서 쿼리는 일일 작업 할당량 에 대해 하나의 작업으로 계산됩니다. 하지만 각 페이지로 나누어진 Search 요청은 여전히 단기 비율 제한에 대해 개별 RPC 호출로 계산됩니다.

코드 예

다음 코드 예는 클라이언트 라이브러리를 사용하여 스트리밍 보고서 쿼리를 실행하는 방법을 보여줍니다.

자바

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.V25.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::V25::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