Nombres de recursos temporales
GoogleAdsService.Mutate
admite nombres de recursos temporales a los que se puede hacer referencia más adelante en la misma solicitud. Esto te permite, por ejemplo, crear una campaña y sus grupos de anuncios, anuncios, palabras clave, etc. asociados, todo en una sola solicitud.
Para ello, especifica el resource_name
del recurso nuevo para usar un ID negativo. Por ejemplo, si creas una campaña y especificas su nombre de recurso como customers/<YOUR_CUSTOMER_ID>/campaigns/-1
, cuando crees el grupo de anuncios en una operación posterior, podrás hacer referencia a él por ese nombre de recurso y el -1
que especificaste se reemplazará automáticamente por el ID real de la campaña creada.
A continuación, se incluyen algunos aspectos que debes tener en cuenta cuando utilizas nombres de recursos temporales:
- Un nombre de recurso temporal solo se puede usar después de definirlo en un recurso. En el siguiente ejemplo, la operación del grupo de anuncios debería aparecer después de la operación de la campaña en la lista de operaciones.
- Los nombres de recursos temporales no se recuerdan en las tareas ni en las solicitudes de mutación. Para hacer referencia a un recurso creado en una tarea o solicitud de mutación anterior, usa su nombre real.
- Para una sola tarea o solicitud de mutación, cada nombre de recurso temporal debe usar un número negativo único, incluso si son de diferentes tipos de recursos. Si se reutiliza un ID temporal en un solo trabajo o solicitud de mutación, se muestra un error.
Ejemplo
Para dar un ejemplo más concreto de la situación mencionada anteriormente, supongamos que quieres agregar una campaña, un grupo de anuncios y un anuncio en una sola solicitud a la API. Deberías crear una estructura para tu solicitud similar a la siguiente:
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"
...
}
}
},
]
Observa que se usa un nuevo ID temporal para el grupo de anuncios, ya que no podemos volver a usar el -1
que usamos para la campaña. También hacemos referencia a este grupo de anuncios cuando creamos un anuncio de grupo de anuncios. El grupo de anuncios hace referencia al nombre del recurso que establecimos para la campaña en una operación anterior de la solicitud, mientras que resource_name
en ad_group_ad_operation
no es necesario, ya que ninguna otra operación hace referencia a él.
Cómo agrupar operaciones del mismo tipo
Cuando se usa GoogleAdsService.Mutate
, es importante agrupar las operaciones según su recurso en el array de operaciones repetidas. En esencia, este método de mutación sirve como una forma de llamar de forma secuencial y automática al método de mutación de cada recurso individual. Para ello, lee operaciones hasta que encuentra una para un tipo de recursos diferente y, luego, agrupa todas las operaciones del mismo tipo en una solicitud.
Por ejemplo, si tienes 5 operaciones de campaña, seguidas de 10 operaciones de grupo de anuncios en el campo operations
repetido en tu llamada a Mutate
, el sistema realizará dos llamadas en total en el backend, una a CampaignService
para 5 operaciones y la siguiente a AdGroupService
para 10 operaciones.
Sin embargo, si los agruparas de manera diferente, el rendimiento podría ser mucho peor. Si solo creas 2 campañas y 2 grupos de anuncios, pero los unes para que las operaciones se ordenen como [campaña, grupo de anuncios, campaña, grupo de anuncios], se generarán cuatro llamadas en total en el backend. Esto provocará un rendimiento de la API más lento y, en casos extremos, incluso puede generar tiempos de espera.
Cómo recuperar atributos mutables de la respuesta
Si configuras el response_content_type
de tu solicitud de mutación en MUTABLE_RESOURCE
, la respuesta contendrá los valores de todos los campos mutables para cada objeto que la solicitud haya creado o actualizado. Usa esta función para evitar una solicitud adicional de search
o searchStream
después de cada solicitud de mutación.
Si no configuras response_content_type
, la API de Google Ads se establecerá de forma predeterminada en RESOURCE_NAME_ONLY
y la respuesta solo contendrá el nombre de cada recurso creado o actualizado.
Este es un ejemplo de cómo recuperar un recurso mutable de una llamada a la API:
Java
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); } }
C#
/// <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); }
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, 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]
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
Perl
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]; }