برای بهینهسازی عملکرد، مدیریت وابستگیها در عملیات مختلف و مدیریت پاسخها هنگام تغییر منابع در API گوگل ادز، از این بهترین شیوهها پیروی کنید.
نامهای منابع موقت
هر دو GoogleAdsService.Mutate و BatchJobService از نامهای منبع موقت پشتیبانی میکنند که میتوانند در عملیات بعدی به آنها ارجاع داده شوند. این به شما امکان میدهد یک کمپین و گروههای تبلیغاتی، تبلیغات و کلمات کلیدی مرتبط با آن را در یک درخواست mutate یا کار دستهای ایجاد کنید.
برای ارجاع به یک منبع تازه ایجاد شده در همان درخواست تغییر یا کار دستهای، یک شناسه عدد صحیح منفی (مانند -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 گروهبندی کنید، ضمن اینکه وابستگیهای والد و فرزند را نیز در نظر بگیرید. این روش به صورت متوالی عملیات را میخواند تا زمانی که با نوع منبع متفاوتی مواجه شود، و سپس تمام عملیاتهای پیوسته از همان نوع را در یک درخواست سرویس backend واحد دستهبندی میکند.
برای مثال، اگر ۵ عملیات کمپین و به دنبال آن ۱۰ عملیات گروه تبلیغاتی را در فیلد mutate_operations تکرار شده قرار دهید، سیستم دو فراخوانی backend انجام میدهد: یکی برای ۵ عملیات کمپین به CampaignService و دومی برای ۱۰ عملیات گروه تبلیغاتی به AdGroupService .
در مقابل، عملیاتهای درهمتنیده با مرتبسازی آنها به صورت [campaign, ad group, campaign, ad group] منجر به چهار فراخوانی backend جداگانه میشود. فراخوانیهای درهمتنیده عملکرد API را کاهش میدهند و میتوانند منجر به وقفههای زمانی درخواست در دستههای بزرگ شوند.
مدیریت خرابیهای جزئی و محدودیتهای دستهای
به طور پیشفرض، 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شکست میخورند؛ هرupdateیاremoveAssetGroupOperationدر یک زیرگروه عملیاتی مستقل اجرا میشود). - یک Performance Max
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 درخواست mutate خود را روی MUTABLE_RESOURCE تنظیم کنید، پاسخ شامل resource_name و شیء منبعی است که با فیلدهای قابل تغییر آن پر شده است (و همچنین فیلدهای کلیدی سیستمی در منبع برگشتی، مانند ExperimentArm.in_design_campaigns ) برای هر شیء پشتیبانی شده که توسط درخواست ایجاد یا بهروزرسانی شده (حذف نشده) است. برای عملیات remove - یا برای انواع منابعی که از بازگرداندن MUTABLE_RESOURCE پشتیبانی نمیکنند - پاسخ همیشه فقط resource_name را برمیگرداند. از این ویژگی برای جلوگیری از ارسال درخواست Search یا SearchStream اضافی پس از هر فراخوانی mutate استفاده کنید.
اگر response_content_type تنظیم نکنید، 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); } }
سی شارپ
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); }
پی اچ پی
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]; }
پایتون
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]
روبی
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]; }