لاسترداد كيانات Google Ads API وبيانات التقارير، استخدِم إحدى الطرق التالية:
في ما يلي الاختلافات الرئيسية بين الطريقتَين:
| GoogleAdsService.SearchStream | GoogleAdsService.Search | |
|---|---|---|
| مناسب لرمز الإنتاج | نعم | نعم |
| الخدمة | GoogleAdsService |
GoogleAdsService |
| السيناريو | جارٍ جلب العناصر والتقارير | جارٍ جلب العناصر والتقارير |
| الردّ | مجموعة من عناصر GoogleAdsRow |
صفحات من عناصر GoogleAdsRow |
| حقول الردّ | المستخدمون المحدّدون في طلب البحث فقط | المستخدمون المحدّدون في طلب البحث فقط |
| الحدود اليومية | الحدود اليومية استنادًا إلى مستويات الوصول | الحدود اليومية استنادًا إلى مستويات الوصول |
SearchStream ضد Search
بينما تُرسِل Search طلبات متعددة مقسّمة على صفحات لتنزيل تقرير كامل، تُرسِل SearchStream طلبًا واحدًا وتبدأ اتصال gRPC دائمًا مع Google Ads API بغض النظر عن حجم التقرير.
بالنسبة إلى SearchStream، يبدأ تنزيل حِزم البيانات على الفور في دفعات من عناصر SearchGoogleAdsStreamResponse. يمكن للرمز البرمجي تكرار الدفعات الواردة عند وصولها بدون انتظار انتهاء البث بالكامل.
من خلال إلغاء الوقت الذي تستغرقه الشبكة في إرسال البيانات واستقبالها لطلب كل صفحة فردية من استجابة Search، يقدّم SearchStream أداءً أفضل من التنقّل بين الصفحات، خاصةً للتقارير الكبيرة.
مثال
يتناول هذا المثال تقريرًا يتألف من 100,000 صف. يوضّح الجدول التالي الاختلافات بين الطلبات والردود في الطريقتَين:
| SearchStream | بحث | |
|---|---|---|
| حجم الصفحة | غير سارٍ | 10,000 صف في كل صفحة |
| عدد طلبات البيانات من واجهة برمجة التطبيقات | طلب واحد | 10 طلبات |
| عدد الردود من واجهة برمجة التطبيقات | بث مباشر واحد متواصل | 10 ردود |
عوامل الأداء
في معظم حالات الاستخدام، ننصح باستخدام SearchStream بدلاً من Search للأسباب التالية:
- التقارير المكوّنة من صفحة واحدة (أقل من 10,000 صف): لا توجد اختلافات كبيرة في الأداء بين الطريقتين.
- التقارير المتعدّدة الصفحات: يكون
SearchStreamعادةً أسرع لأنّه يتجنّب رحلات الذهاب والعودة المتعدّدة على الشبكة، كما أنّ القراءة أو الكتابة من ذاكرة التخزين المؤقت للقرص تكون أقل تأثيرًا. - كفاءة الذاكرة: عند معالجة تقارير كبيرة باستخدام
SearchStream، يجب تكرار العملية على أجزاء من مصدر البيانات ومعالجة الصفوف فور وصولها بدلاً من تخزين جميع الصفوف مؤقتًا في الذاكرة في الوقت نفسه لتجنُّب أخطاء نفاد الذاكرة (OOM). - مرونة الاتصال: نظرًا لأنّ
SearchStreamيعتمد على اتصال مستمر، يمكن أن تتم مقاطعة عمليات البث الطويلة بسبب انقطاع الشبكة أو انتهاء المهلة المحددة. اضبط مهلات RPC المناسبة ونفِّذ منطق إعادة المحاولة لأخطاء البث المؤقتة.
الحدود القصوى لمعدّل الاستخدام
تلتزم حدود العمليات اليومية لكلتا الطريقتَين بالحدود العادية ومستويات الوصول لمشروعك على Google Cloud. يتم احتساب طلب البحث المنطقي الواحد
للتقرير كعملية واحدة ضمن حصة العمليات اليومية
بغض النظر عما إذا كانت النتيجة يتم بثها باستخدام SearchStream أو استردادها
عبر صفحات مخزنة مؤقتًا متعددة باستخدام Search مع page_token. ومع ذلك، لا يزال كل طلب 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.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; }