این روالهای مطلوب را برای بهینهسازی عملکرد، مدیریت وابستگیها در سراسر عملیات، و مدیریت پاسخها هنگام تغییر منابع در Google Ads API دنبال کنید.
نامهای منبع موقت
GoogleAdsService.Mutate و BatchJobService از نامهای موقت منابع که میتوانند در عملیاتهای بعدی ارجاع داده شوند پشتیبانی میکنند. این به شما امکان میدهد پویش و گروههای آگهی، آگهیها، و کلیدواژههای مرتبط با آن را در یک درخواست تغییر یا کار دستهای ایجاد کنید.
برای ارجاع به منبع جدیداً ایجادشده در همان درخواست تغییر یا کار دستهای، شناسه عدد صحیح منفی (مثل -1 یا -2، بهاستثنای 0) را در فیلد resource_name منبع جدید مشخص کنید. برای مثال، هنگام ایجاد پویش در
درخواست دستهای، نام منبع آن را روی customers/CUSTOMER_ID/campaigns/-1 تنظیم کنید.
هنگام ایجاد گروه آگهی در عملیات بعدی در همان درخواست،
customers/CUSTOMER_ID/campaigns/-1 را بهعنوان کمپین اصلی ارجاع دهید. API
بهطور خودکار -1 را با شناسه واقعی پویش که هنگام ایجاد تولید شده است جایگزین میکند.
محدودیتهای استفاده
هنگام استفاده از نامهای موقت منابع، قوانین زیر را بهخاطر داشته باشید:
- ترتیب مهم است: فقط پساز تعریف کردن نام منبع موقت میتوانید به آن ارجاع دهید. در فهرست عملیات، عملیات وابسته (مانند ایجاد گروه آگهی) باید پساز عملیاتی که منبع اصلی آن را ایجاد میکند (مانند ایجاد پویش) ظاهر شود.
- گستره درخواست تکی یا کار دستهای: نامهای موقت منابع در کارهای جداگانه یا درخواستهای تغییر باقی نمیمانند. برای ارجاع به منبعی که در درخواست تغییر یا کار قبلی ایجاد شده است، از نام منبع واقعی تولیدشده توسط سیستم استفاده کنید.
- یکتایی سراسری: در یک درخواست تغییر یا کار، هر نام منبع موقت باید از یک عدد صحیح منفی یکتا در همه انواع منبع استفاده کند.
برای مثال، نمیتوانید
-1را در یک درخواست به پویش و گروه آگهی اختصاص دهید. استفاده مجدد از شناسه موقت در همان درخواست یا کار دستهای خطایNewResourceCreationError.DUPLICATE_TEMP_IDSرا برمیگرداند.
پایهبار نمونه
فرض کنید میخواهید یک پویش، یک گروه آگهی، و یک آگهی را در یک درخواست API یا کار دستهای اضافه کنید. میتوانید آرایه mutateOperations را در بار داده درخواست
GoogleAdsService.Mutate یا BatchJobService.AddBatchJobOperations ساختاربندی کنید، همانطور که در نمونه REST JSON زیر نشان داده شده است (با حذف سایر فیلدهای منبع الزامی برای اختصار):
{
"mutateOperations": [
{
"campaignOperation": {
"create": {
"resourceName": "customers/CUSTOMER_ID/campaigns/-1"
}
}
},
{
"adGroupOperation": {
"create": {
"resourceName": "customers/CUSTOMER_ID/adGroups/-2",
"campaign": "customers/CUSTOMER_ID/campaigns/-1"
}
}
},
{
"adGroupAdOperation": {
"create": {
"adGroup": "customers/CUSTOMER_ID/adGroups/-2"
}
}
}
]
}
این مثال جزئیات کلیدی زیر را نشان میدهد:
- گروه آگهی از شناسه موقت جدیدی (
-2) استفاده میکند زیرا-1قبلاً به پویش اختصاص داده شده است. - گروه آگهی به
customers/CUSTOMER_ID/campaigns/-1ارجاع میدهد تا خودش را به پویش ایجادشده در عملیات قبلی پیوند دهد. adGroupAdOperationبهcustomers/CUSTOMER_ID/adGroups/-2ارجاع میدهد وresourceNameرا حذف میکند زیرا هیچ عملیات بعدی در درخواست به آگهی جدید ارجاع نمیدهد.
گروهبندی عملیاتهای همنوع
هنگام استفاده از GoogleAdsService.Mutate، عملیات را براساس نوع منبع در آرایه تکراری mutate_operations گروهبندی کنید و درعینحال وابستگیهای والد و فرزند را رعایت کنید. این روش بهطور متوالی عملیات را میخواند تا زمانی که با نوع منبع متفاوتی مواجه شود، و سپس همه عملیاتهای مجاور از یک نوع را در یک درخواست سرویس زیرینه دستهبندی میکند.
برای مثال، اگر ۵ عملیات پویش و سپس ۱۰ عملیات گروه آگهی را در فیلد تکراری mutate_operations اضافه کنید، سیستم دو فراخوانی پسنهایی انجام میدهد: یکی به CampaignService برای ۵ عملیات پویش، و دومی به AdGroupService برای ۱۰ عملیات گروه آگهی.
درمقابل، عملیات درهمبافی با ترتیب دادن آنها بهصورت [campaign, ad group,
campaign, ad group] منجر به چهار فراخوانی مجزای پسزمینه میشود. تماسهای درهمبافته
عملکرد میانای برنامهسازی کاربردی را کاهش میدهد و میتواند منجر به اتمام مهلت درخواست در دستههای بزرگ شود.
مدیریت کردن موارد ناقص ناموفق و محدودیتهای دستهای
بهطور پیشفرض، اگر هریک از عملیاتها ناموفق باشد، GoogleAdsService.Mutate کل درخواست را برمیگرداند. برای انجام عملیات معتبر حتی زمانی که
عملیات دیگر در همان درخواست ناموفق است، partial_failure را روی true در
درخواست تنظیم کنید و partial_failure_error را در پاسخ بررسی کنید. وقتی
partial_failure برابر با true باشد، اگر عملیات والدی که شناسه موقت را تعریف میکند
(مثل customers/CUSTOMER_ID/campaigns/-1) در اعتبارسنجی ناموفق باشد، هر عملیات
فرزند وابستهای که به آن شناسه موقت در همان درخواست ارجاع میدهد نیز
با NewResourceCreationError.TEMP_ID_RESOURCE_HAD_ERRORS ناموفق میشود. برای جزئیات بیشتر،
راهنمای خطای جزئی را ببینید.
همچنین اندازه درخواست، زیردستهبندی، و محدودیتهای نرخ را درنظر داشته باشید:
- حدود اندازه درخواست و تکه: یک درخواست
GoogleAdsService.Mutateحد ۱۰٬۰۰۰ عملیات تغییر را اعمال میکند (یا تا ۲۰٬۰۰۰ عملیات وقتی همه عملیات در درخواستAdGroupCriterionOperationباشند، و درصورت فراتر رفتن،RequestError.TOO_MANY_MUTATE_OPERATIONSرا برمیگرداند) و حداکثر ۱۰۰ عملیات کنش (RequestError.TOO_MANY_ACTION_OPERATIONS).BatchJobService.AddBatchJobOperationsحداکثر ۱۰٬۰۰۰ عملیات در هر تماس، ۱۰٬۴۸۴٬۵۰۴ بایت برای هرMutateOperation، و ۴۱٬۹۳۷٬۹۲۰ بایت برای هرAddBatchJobOperationsRequestرا اعمال میکند (و درصورت فراتر رفتن از هر حد،BatchJobError.REQUEST_TOO_LARGEرا برمیگرداند، با حداکثر ۱٬۰۰۰٬۰۰۰ عملیات در مجموع برای هر کار دستهای). جهشهای همزمان که همان پویش یا حساب را هدف قرار میدهند میتوانند خطاهایDatabaseError.CONCURRENT_MODIFICATIONرا راهاندازی کنند. - دستهبندی فرعی اتمی
BatchJobService: اگرچه کارهای دستهای تحت معناشناسی شکست جزئی اجرا میشوند (بهطور پیشفرض ۱۰۰۰ عملیات در هر دسته فرعی داخلی)،BatchJobServiceبهطور خودکار عملیاتهای وابسته مجاور خاصی را برای همان شناسه والد در دستههای فرعی اتمی گروهبندی میکند:- یک
AssetGroupOperation(create) و بهدنبال آن عملیاتهایAssetGroupAssetOperation(create) متوالی برای همانAssetGroupشناسه (درمجموع تا ۱۰۰۰ عملیات، که بهصورت اتمی باBatchJobError.ASSET_GROUP_AND_ASSET_GROUP_ASSET_TRANSACTION_FAILUREناموفق میشود؛ هرAssetGroupOperationupdateیاremoveدر یک زیردسته تکعملیاتی مستقل اجرا میشود). - یک
CampaignOperation«بیشینهسازی عملکرد» (create، وقتی «رهنمودهای نمانام» فعال باشد—که پیشفرض است مگراینکهbrand_guidelines_enabledرویfalseتنظیم شده باشد یاhotel_property_asset_setتنظیم شده باشد) و بهدنبال آن عملیاتCampaignAssetOperation(create) مجاور برای همان شناسهCampaign(درمجموع تا ۱٬۰۰۰ عملیات، که بهصورت اتمی باBatchJobError.CAMPAIGN_AND_CAMPAIGN_ASSET_TRANSACTION_FAILUREناموفق میشود). - عملیات متوالی
AssetGroupListingGroupFilterOperation(max 10,000، با شکست اتمی باBatchJobError.ASSET_GROUP_LISTING_GROUP_FILTER_TRANSACTION_FAILURE) یاAdGroupCriterionOperation(listing_group،max 20,000، با شکست اتمی باCriterionError.LISTING_GROUP_ERROR_IN_ANOTHER_OPERATION) برای همان والد (AssetGroupیاAdGroup).
- یک
بازیابی مشخصههای تغییرپذیر از پاسخ
اگر response_content_type درخواست تغییر خود را روی
MUTABLE_RESOURCE تنظیم کنید، پاسخ حاوی
resource_name و شیء منبع پرشده با فیلدهای تغییرپذیر آن (و همچنین
فیلدهای کلیدی پرشده توسط سیستم در منبع برگرداندهشده، مانند
ExperimentArm.in_design_campaigns) برای هر شیء پشتیبانیشده ایجادشده یا
بهروزرسانیشده (حذفنشده) توسط درخواست خواهد بود. برای عملیات remove—یا برای انواع منابعی که از برگرداندن MUTABLE_RESOURCE پشتیبانی نمیکنند—پاسخ همیشه فقط resource_name را برمیگرداند. از این ویژگی استفاده کنید تا از ارسال درخواست Search یا SearchStream اضافی پساز هر تماس تغییردهنده جلوگیری کنید.
اگر response_content_type را تنظیم نکنید، Google Ads API بهطور پیشفرض روی
RESOURCE_NAME_ONLY تنظیم میشود و فقط resource_name هر منبع تغییریافته را
برمیگرداند.
مثال زیر نشان میدهد که چگونه یک منبع قابل تغییر را از یک فراخوانی mutate بازیابی کنید:
جاوا
private String createExperimentArms( GoogleAdsClient googleAdsClient, long customerId, long campaignId, String experiment) { List<ExperimentArmOperation> operations = new ArrayList<>(); operations.add( ExperimentArmOperation.newBuilder() .setCreate( // The "control" arm references an already-existing campaign. ExperimentArm.newBuilder() .setControl(true) .addCampaigns(ResourceNames.campaign(customerId, campaignId)) .setExperiment(experiment) .setName("control arm") .setTrafficSplit(40) .build()) .build()); operations.add( ExperimentArmOperation.newBuilder() .setCreate( // In standard campaign experiments, creating the treatment arm automatically // generates a draft campaign that you can modify before starting the experiment. ExperimentArm.newBuilder() .setControl(false) .setExperiment(experiment) .setName("experiment arm") .setTrafficSplit(60) .build()) .build()); try (ExperimentArmServiceClient experimentArmServiceClient = googleAdsClient.getLatestVersion().createExperimentArmServiceClient()) { // Constructs the mutate request. MutateExperimentArmsRequest mutateRequest = MutateExperimentArmsRequest.newBuilder() .setCustomerId(Long.toString(customerId)) .addAllOperations(operations) // We want to fetch the draft campaign IDs from the treatment arm, so the easiest way // to do that is to have the response return the newly created entities. .setResponseContentType(ResponseContentType.MUTABLE_RESOURCE) .build(); // Sends the mutate request. MutateExperimentArmsResponse response = experimentArmServiceClient.mutateExperimentArms(mutateRequest); // Results always return in the order that you specify them in the request. Since we created // the treatment arm last, it will be the last result. If you don't remember which arm is the // treatment arm, you can always filter the query in the next section with // `experiment_arm.control = false`. MutateExperimentArmResult controlArmResult = response.getResults(0); MutateExperimentArmResult treatmentArmResult = response.getResults(response.getResultsCount() - 1); System.out.printf( "Created control arm with resource name '%s'%n", controlArmResult.getResourceName()); System.out.printf( "Created treatment arm with resource name '%s'%n", treatmentArmResult.getResourceName()); return treatmentArmResult.getExperimentArm().getInDesignCampaigns(0); } }
C#
private static (MutateExperimentArmResult, MutateExperimentArmResult) CreateExperimentArms(GoogleAdsClient client, long customerId, long baseCampaignId, string experimentResourceName) { // Get the ExperimentArmService. ExperimentArmServiceClient experimentService = client.GetService( Services.V26.ExperimentArmService); // Create the control arm. The control arm references an already-existing campaign. ExperimentArmOperation controlArmOperation = new ExperimentArmOperation() { Create = new ExperimentArm() { Control = true, Campaigns = { ResourceNames.Campaign(customerId, baseCampaignId) }, Experiment = experimentResourceName, Name = "Control Arm", TrafficSplit = 40 } }; // Create the non-control arm. // In standard campaign experiments, creating the treatment arm automatically // generates a draft campaign that you can modify before starting the experiment. ExperimentArmOperation treatmentArmOperation = new ExperimentArmOperation() { Create = new ExperimentArm() { Control = false, Experiment = experimentResourceName, Name = "Experiment Arm", TrafficSplit = 60 } }; // We want to fetch the draft campaign IDs from the treatment arm, so the // easiest way to do that is to have the response return the newly created // entities. MutateExperimentArmsRequest request = new MutateExperimentArmsRequest { CustomerId = customerId.ToString(), Operations = { controlArmOperation, treatmentArmOperation }, ResponseContentType = ResponseContentType.MutableResource }; MutateExperimentArmsResponse response = experimentService.MutateExperimentArms( request ); // Results always return in the order that you specify them in the request. // Since we created the treatment arm last, it will be the last result. MutateExperimentArmResult controlArm = response.Results.First(); MutateExperimentArmResult treatmentArm = response.Results.Last(); Console.WriteLine($"Created control arm with resource name " + $"'{controlArm.ResourceName}'."); Console.WriteLine($"Created treatment arm with resource name" + $" '{treatmentArm.ResourceName}'."); return (controlArm, treatmentArm); }
PHP
private static function createExperimentArms( GoogleAdsClient $googleAdsClient, int $customerId, int $campaignId, string $experimentResourceName ): string { $operations = []; $experimentArm1 = new ExperimentArm( [ // The "control" arm references an already-existing campaign. 'control' => true, 'campaigns' => [ResourceNames::forCampaign($customerId, $campaignId)], 'experiment' => $experimentResourceName, 'name' => 'control arm', 'traffic_split' => 40 ] ); $operations[] = new ExperimentArmOperation(['create' => $experimentArm1]); $experimentArm2 = new ExperimentArm( [ // The non-"control" arm, also called a "treatment" arm, will automatically // generate draft campaigns that you can modify before starting the // experiment. 'control' => false, 'experiment' => $experimentResourceName, 'name' => 'experiment arm', 'traffic_split' => 60 ] ); $operations[] = new ExperimentArmOperation(['create' => $experimentArm2]); // Issues a request to create the experiment arms. $experimentArmServiceClient = $googleAdsClient->getExperimentArmServiceClient(); $response = $experimentArmServiceClient->mutateExperimentArms( MutateExperimentArmsRequest::build($customerId, $operations) // We want to fetch the draft campaign IDs from the treatment arm, so the easiest // way to do that is to have the response return the newly created entities. ->setResponseContentType(ResponseContentType::MUTABLE_RESOURCE) ); // Results always return in the order that you specify them in the request. // Since we created the treatment arm last, it will be the last result. $controlArmResourceName = $response->getResults()[0]->getResourceName(); $treatmentArm = $response->getResults()[count($operations) - 1]; print "Created control arm with resource name '$controlArmResourceName'" . PHP_EOL; print "Created treatment arm with resource name '{$treatmentArm->getResourceName()}'" . PHP_EOL; return $treatmentArm->getExperimentArm()->getInDesignCampaigns()[0]; }
Python
def create_experiment_arms( client: GoogleAdsClient, customer_id: str, base_campaign_id: str, experiment: str, ) -> str: """Creates a control and treatment experiment arms. Args: client: an initialized GoogleAdsClient instance. customer_id: a client customer ID. base_campaign_id: the campaign ID to associate with the control arm of the experiment. experiment: the resource name for an experiment. Returns: the resource name for the new treatment experiment arm. """ operations: List[ExperimentArmOperation] = [] campaign_service: CampaignServiceClient = client.get_service( "CampaignService" ) # The "control" arm references an already-existing campaign. operation_1: ExperimentArmOperation = client.get_type( "ExperimentArmOperation" ) exa_1: ExperimentArm = operation_1.create exa_1.control = True exa_1.campaigns.append( campaign_service.campaign_path(customer_id, base_campaign_id) ) exa_1.experiment = experiment exa_1.name = "control arm" exa_1.traffic_split = 40 operations.append(operation_1) # In standard campaign experiments, creating the treatment arm automatically # generates a draft campaign that you can modify before starting the experiment. operation_2: ExperimentArmOperation = client.get_type( "ExperimentArmOperation" ) exa_2: ExperimentArm = operation_2.create exa_2.control = False exa_2.experiment = experiment exa_2.name = "experiment arm" exa_2.traffic_split = 60 operations.append(operation_2) experiment_arm_service: ExperimentArmServiceClient = client.get_service( "ExperimentArmService" ) request: MutateExperimentArmsRequest = client.get_type( "MutateExperimentArmsRequest" ) request.customer_id = customer_id request.operations = operations # We want to fetch the draft campaign IDs from the treatment arm, so the # easiest way to do that is to have the response return the newly created # entities. request.response_content_type = ( client.enums.ResponseContentTypeEnum.MUTABLE_RESOURCE ) response: MutateExperimentArmsResponse = ( experiment_arm_service.mutate_experiment_arms(request=request) ) # Results always return in the order that you specify them in the request. # Since we created the treatment arm second, it will be the second result. control_arm_result: Any = response.results[0] treatment_arm_result: Any = response.results[1] print( f"Created control arm with resource name {control_arm_result.resource_name}" ) print( f"Created treatment arm with resource name {treatment_arm_result.resource_name}" ) return treatment_arm_result.experiment_arm.in_design_campaigns[0]
Ruby
def create_experiment_arms(client, customer_id, base_campaign_id, experiment) operations = [] operations << client.operation.create_resource.experiment_arm do |ea| # The "control" arm references an already-existing campaign. ea.control = true ea.campaigns << client.path.campaign(customer_id, base_campaign_id) ea.experiment = experiment ea.name = 'control arm' ea.traffic_split = 40 end operations << client.operation.create_resource.experiment_arm do |ea| # In standard campaign experiments, creating the treatment arm automatically # generates a draft campaign that you can modify before starting the # experiment. ea.control = false ea.experiment = experiment ea.name = 'experiment arm' ea.traffic_split = 60 end response = client.service.experiment_arm.mutate_experiment_arms( customer_id: customer_id, operations: operations, # We want to fetch the draft campaign IDs from the treatment arm, so the # easiest way to do that is to have the response return the newly created # entities. response_content_type: :MUTABLE_RESOURCE, ) # Results always return in the order that you specify them in the request. # Since we created the treatment arm second, it will be the second result. control_arm_result = response.results.first treatment_arm_result = response.results.last puts "Created control arm with resource name #{control_arm_result.resource_name}." puts "Created treatment arm with resource name #{treatment_arm_result.resource_name}." treatment_arm_result.experiment_arm.in_design_campaigns.first end
پرل
sub create_experiment_arms { my ($api_client, $customer_id, $base_campaign_id, $experiment) = @_; my $operations = []; push @$operations, Google::Ads::GoogleAds::V26::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V26::Resources::ExperimentArm->new({ # The "control" arm references an already-existing campaign. control => "true", campaigns => [ Google::Ads::GoogleAds::V26::Utils::ResourceNames::campaign( $customer_id, $base_campaign_id ) ], experiment => $experiment, name => "control arm", trafficSplit => 40 })}); push @$operations, Google::Ads::GoogleAds::V26::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V26::Resources::ExperimentArm->new({ # The non-"control" arm, also called a "treatment" arm, will automatically # generate draft campaigns that you can modify before starting the # experiment. control => "false", experiment => $experiment, name => "experiment arm", trafficSplit => 60 })}); my $response = $api_client->ExperimentArmService()->mutate({ customerId => $customer_id, operations => $operations, # We want to fetch the draft campaign IDs from the treatment arm, so the # easiest way to do that is to have the response return the newly created # entities. responseContentType => MUTABLE_RESOURCE }); # Results always return in the order that you specify them in the request. # Since we created the treatment arm last, it will be the last result. my $control_arm_result = $response->{results}[0]; my $treatment_arm_result = $response->{results}[1]; printf "Created control arm with resource name '%s'.\n", $control_arm_result->{resourceName}; printf "Created treatment arm with resource name '%s'.\n", $treatment_arm_result->{resourceName}; return $treatment_arm_result->{experimentArm}{inDesignCampaigns}[0]; }