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개의 응답

성능 요인

대부분의 사용 사례에서는 다음과 같은 이유로 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