임시 리소스 이름
GoogleAdsService.Mutate
는 나중에 동일한 요청에서 참조할 수 있는 임시 리소스 이름을 지원합니다. 예를 들어 캠페인과 연결된 광고그룹, 광고, 키워드 등을 모두 단일 요청으로 만들 수 있습니다.
음수 ID를 사용하도록 새 리소스의 resource_name
를 지정하면 됩니다. 예를 들어 캠페인을 만들고 리소스 이름을 customers/<YOUR_CUSTOMER_ID>/campaigns/-1
로 지정하면 나중에 광고 그룹을 만들 때 해당 리소스 이름으로 참조할 수 있으며 지정한 -1
는 생성된 캠페인의 실제 ID로 자동 대체됩니다.
임시 리소스 이름을 사용할 때 유의해야 할 사항은 다음과 같습니다.
- 임시 리소스 이름은 리소스에 정의된 후에만 사용할 수 있습니다. 아래 예에서는 광고 그룹 작업이 작업 목록에서 캠페인 작업 뒤에 표시되어야 합니다.
- 임시 리소스 이름은 작업 또는 변형 요청 전반에서 기억되지 않습니다. 이전 작업 또는 변형 요청에서 만든 리소스를 참조하려면 실제 리소스 이름을 사용하세요.
- 단일 작업 또는 변형 요청의 경우 각 임시 리소스 이름은 리소스 유형이 다르더라도 고유한 음수를 사용해야 합니다. 임시 ID가 단일 작업 또는 변형 요청에서 재사용되면 오류가 반환됩니다.
예
위에서 언급한 상황에 관한 좀 더 구체적인 예를 들어 보겠습니다. 단일 API 요청에 캠페인, 광고 그룹, 광고를 추가하려고 한다고 가정해 보겠습니다. 다음과 유사한 요청 구조를 만듭니다.
mutate_operations: [
{
campaign_operation: {
create: {
resource_name: "customers/<YOUR_CUSTOMER_ID>/campaigns/-1",
...
}
}
},
{
ad_group_operation: {
create: {
resource_name: "customers/<YOUR_CUSTOMER_ID>/adGroups/-2",
campaign: "customers/<YOUR_CUSTOMER_ID>/campaigns/-1"
...
}
}
},
{
ad_group_ad_operation: {
create: {
ad_group: "customers/<YOUR_CUSTOMER_ID>/adGroups/-2"
...
}
}
},
]
캠페인에 사용한 -1
를 재사용할 수 없으므로 광고 그룹에 새 임시 ID가 사용되며 광고 그룹 광고를 만들 때도 이 광고 그룹을 참조합니다. 광고 그룹 자체는 요청의 이전 작업에서 캠페인에 대해 설정한 리소스 이름을 참조하지만, ad_group_ad_operation
의 resource_name
는 더 이상 작업에서 참조하지 않으므로 필요하지 않습니다.
동일한 유형의 작업 그룹화
GoogleAdsService.Mutate
를 사용할 때는 반복 작업 배열의 리소스에 따라 작업을 그룹화하는 것이 중요합니다. 이 변형 메서드는 기본적으로 각 개별 리소스의 자체 변형 메서드를 자동으로 순차적으로 호출하는 방법으로 작동합니다. 이를 위해 다른 유형의 리소스에 관한 작업을 찾을 때까지 작업을 읽은 다음 동일한 유형의 모든 작업을 하나의 요청으로 일괄 처리합니다.
예를 들어 Mutate
호출의 반복된 operations
필드에 캠페인 작업 5개와 광고 그룹 작업 10개가 있는 경우 시스템은 백엔드에서 총 두 번의 호출을 실행합니다. 하나는 5개의 작업에 대해 CampaignService
를 호출하고 다른 하나는 10개의 작업에 대해 AdGroupService
를 호출합니다.
하지만 다르게 그룹화하면 성능이 훨씬 저하될 수 있습니다. 캠페인 2개와 광고 그룹 2개만 만들었지만 작업이 [캠페인, 광고 그룹, 캠페인, 광고 그룹]으로 순서가 지정되도록 엮으면 백엔드에서 총 4번 호출됩니다. 이로 인해 API 성능이 느려지고 심한 경우 시간 초과가 발생할 수도 있습니다.
응답에서 변경 가능한 속성 가져오기
변환 요청의 response_content_type
를 MUTABLE_RESOURCE
로 설정하면 요청에 의해 생성되거나 업데이트된 모든 객체의 모든 변경 가능한 필드 값이 응답에 포함됩니다. 이 기능을 사용하면 각 변형 요청 후에 추가 search
또는 searchStream
요청이 실행되지 않습니다.
response_content_type
를 설정하지 않으면 Google Ads API는 기본적으로 RESOURCE_NAME_ONLY
로 설정되며 응답에는 생성되거나 업데이트된 각 리소스의 리소스 이름만 포함됩니다.
다음은 API 호출에서 변경 가능한 리소스를 가져오는 예입니다.
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( // The non-"control" arm, also called a "treatment" arm, will automatically // generate draft campaigns 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); } }
/// <summary> /// Creates the experiment arms. /// </summary> /// <param name="client">The Google Ads client.</param> /// <param name="customerId">The customer ID for which the call is made.</param> /// <param name="baseCampaignId">ID of the campaign for which the control arm is /// created.</param> /// <param name="experimentResourceName">Resource name of the experiment.</param> /// <returns>The control and treatment arms.</returns> private static (MutateExperimentArmResult, MutateExperimentArmResult) CreateExperimentArms(GoogleAdsClient client, long customerId, long baseCampaignId, string experimentResourceName) { // Get the ExperimentArmService. ExperimentArmServiceClient experimentService = client.GetService( Services.V19.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. The non-"control" arm, also called a "treatment" arm, // will automatically generate draft campaigns 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, customer_id, base_campaign_id, experiment): """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 = [] campaign_service = client.get_service("CampaignService") # The "control" arm references an already-existing campaign. operation_1 = client.get_type("ExperimentArmOperation") exa_1 = 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) # The non-"control" arm, also called a "treatment" arm, will automatically # generate draft campaigns that you can modify before starting the # experiment. operation_2 = client.get_type("ExperimentArmOperation") exa_2 = 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 = client.get_service("ExperimentArmService") request = 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 = 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 = response.results[0] treatment_arm_result = 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::V19::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V19::Resources::ExperimentArm->new({ # The "control" arm references an already-existing campaign. control => "true", campaigns => [ Google::Ads::GoogleAds::V19::Utils::ResourceNames::campaign( $customer_id, $base_campaign_id ) ], experiment => $experiment, name => "control arm", trafficSplit => 40 })}); push @$operations, Google::Ads::GoogleAds::V19::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V19::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]; }