این روالهای مطلوب را دنبال کنید تا عملکرد را بهینهسازی کنید، وابستگیها را در سراسر عملیات مدیریت کنید، و پاسخها را هنگام تغییر منابع در Google Ads API مدیریت کنید.
نامهای موقت منبع
GoogleAdsService.Mutate و BatchJobService از نامهای موقت منابع که میتوان در عملیاتهای بعدی به آنها ارجاع داد پشتیبانی میکنند. این به شما امکان میدهد پویش و گروههای آگهی، آگهیها، و کلیدواژههای مرتبط با آن را در یک درخواست تغییر یا کار دستهای ایجاد کنید.
برای ارجاع به منبع جدیداً ایجادشده در همان درخواست تغییر یا کار دستهای، شناسه عدد صحیح منفی (مثل -1 یا -2، بهاستثنای 0) را در فیلد resource_name منبع جدید مشخص کنید. برای مثال، هنگام ایجاد پویش در درخواست دستهای، نام منبع آن را روی customers/CUSTOMER_ID/campaigns/-1 تنظیم کنید.
هنگام ایجاد گروه آگهی در عملیات بعدی در همان درخواست،
به customers/CUSTOMER_ID/campaigns/-1 بهعنوان پویش اصلی ارجاع دهید. «میانای برنامهسازی کاربردی»
بهطور خودکار -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واحد محدودیت ۱۰٬۰۰۰ عمل جهش (یا حداکثر ۲۰٬۰۰۰ وقتی همه عملیات در درخواستAdGroupCriterionOperations هستند، درصورت تجاوز از حد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.V25.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| # The non-"control" arm, also called a "treatment" arm, will automatically # generate draft campaigns 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 last, it will be the last 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::V25::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V25::Resources::ExperimentArm->new({ # The "control" arm references an already-existing campaign. control => "true", campaigns => [ Google::Ads::GoogleAds::V25::Utils::ResourceNames::campaign( $customer_id, $base_campaign_id ) ], experiment => $experiment, name => "control arm", trafficSplit => 40 })}); push @$operations, Google::Ads::GoogleAds::V25::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V25::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]; }