Mit diesen Best Practices können Sie die Leistung optimieren, Abhängigkeiten zwischen Vorgängen verwalten und Antworten verarbeiten, wenn Sie Ressourcen in der Google Ads API ändern.
Temporäre Ressourcennamen
Sowohl GoogleAdsService.Mutate als auch
BatchJobService unterstützen temporäre Ressourcennamen, auf die
in nachfolgenden Vorgängen verwiesen werden kann. So können Sie eine Kampagne und die zugehörigen Anzeigengruppen, Anzeigen und Keywords in einer einzigen Mutationsanfrage oder einem Batchjob erstellen.
Wenn Sie in derselben Mutationsanfrage oder demselben Batchjob auf eine neu erstellte Ressource verweisen möchten, geben Sie im Feld resource_name der neuen Ressource eine negative Ganzzahl-ID an (z. B. -1 oder -2, aber nicht 0). Wenn Sie beispielsweise eine Kampagne in einer Batchanfrage erstellen, legen Sie den Ressourcennamen auf customers/CUSTOMER_ID/campaigns/-1 fest.
Wenn Sie in einem späteren Vorgang in derselben Anfrage eine Anzeigengruppe erstellen, verweisen Sie auf customers/CUSTOMER_ID/campaigns/-1 als übergeordnete Kampagne. Die API ersetzt -1 automatisch durch die tatsächliche Kampagnen-ID, die bei der Erstellung generiert wurde.
Nutzungsbeschränkungen
Beachten Sie bei der Verwendung temporärer Ressourcennamen die folgenden Regeln:
- Reihenfolge ist wichtig:Sie können nur auf einen temporären Ressourcennamen verweisen, nachdem Sie ihn definiert haben. In einer Liste von Vorgängen muss der abhängige Vorgang (z. B. das Erstellen einer Anzeigengruppe) nach dem Vorgang stehen, mit dem die übergeordnete Ressource erstellt wird (z. B. das Erstellen einer Kampagne).
- Umfang der Einzelanfrage oder des Batchjobs:Temporäre Ressourcennamen bleiben nicht über separate Jobs oder Änderungsanfragen hinweg bestehen. Wenn Sie auf eine Ressource verweisen möchten, die in einem vorherigen Job oder einer vorherigen Mutationsanfrage erstellt wurde, verwenden Sie den tatsächlichen vom System generierten Ressourcennamen.
- Globale Eindeutigkeit:Innerhalb eines einzelnen Jobs oder einer einzelnen Mutationsanfrage muss für jeden temporären Ressourcennamen eine eindeutige negative Ganzzahl für alle Ressourcentypen verwendet werden.
Sie können beispielsweise nicht in derselben Anfrage sowohl einer Kampagne als auch einer Anzeigengruppe
-1zuweisen. Wenn Sie eine temporäre ID innerhalb derselben Anfrage oder desselben Batchjobs wiederverwenden, wird der FehlerNewResourceCreationError.DUPLICATE_TEMP_IDSzurückgegeben.
Beispielnutzlast
Angenommen, Sie möchten in einer einzigen API-Anfrage oder einem einzigen Batchjob eine Kampagne, eine Anzeigengruppe und eine Anzeige hinzufügen. Sie können das Array mutateOperations in einer GoogleAdsService.Mutate- oder BatchJobService.AddBatchJobOperations-Anfrage so strukturieren, wie im folgenden REST-JSON-Beispiel gezeigt (andere erforderliche Ressourcenfelder wurden aus Gründen der Übersichtlichkeit weggelassen):
{
"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"
}
}
}
]
}
Dieses Beispiel veranschaulicht die folgenden wichtigen Details:
- Die Anzeigengruppe verwendet eine neue temporäre ID (
-2), da-1bereits der Kampagne zugewiesen ist. - Die Anzeigengruppe verweist auf
customers/CUSTOMER_ID/campaigns/-1, um sich mit der Kampagne zu verknüpfen, die im vorherigen Vorgang erstellt wurde. - Der
adGroupAdOperation-Vorgang verweist aufcustomers/CUSTOMER_ID/adGroups/-2und lässtresourceNameweg, da kein nachfolgender Vorgang in der Anfrage auf die neue Anzeige verweist.
Vorgänge desselben Typs gruppieren
Wenn Sie GoogleAdsService.Mutate verwenden, gruppieren Sie Vorgänge nach
Ressourcentyp im wiederholten mutate_operations Array und berücksichtigen Sie dabei die Abhängigkeiten zwischen über-
und untergeordneten Elementen. Bei dieser Methode werden Vorgänge sequenziell gelesen, bis ein anderer Ressourcentyp gefunden wird. Anschließend werden alle zusammenhängenden Vorgänge desselben Typs in einer einzigen Backend-Dienstanfrage zusammengefasst.
Wenn Sie beispielsweise fünf Kampagnenvorgänge und dann zehn Anzeigengruppenvorgänge im wiederholten mutate_operations Feld angeben, führt das System zwei Backend-Aufrufe aus: einen an CampaignService für die fünf Kampagnenvorgänge und einen zweiten an AdGroupService für die zehn Anzeigengruppenvorgänge.
Wenn Sie Vorgänge dagegen verschachteln, indem Sie sie als [campaign, ad group,
campaign, ad group] anordnen, werden vier separate Backend-Aufrufe ausgeführt. Verschachtelte Aufrufe beeinträchtigen die API-Leistung und können bei großen Batches zu Zeitüberschreitungen bei Anfragen führen.
Teilweise Fehler und Batchlimits verarbeiten
Standardmäßig wird bei GoogleAdsService.Mutate die gesamte
Anfrage zurückgesetzt, wenn ein einzelner Vorgang fehlschlägt. Wenn Sie gültige Vorgänge auch dann ausführen möchten, wenn
andere Vorgänge in derselben Anfrage fehlschlagen, setzen Sie partial_failure in der Anfrage auf true und prüfen Sie partial_failure_error in der Antwort. Wenn partial_failure auf true gesetzt ist und ein übergeordneter Vorgang, der eine temporäre ID definiert (z. B. customers/CUSTOMER_ID/campaigns/-1), die Validierung nicht besteht, schlagen auch alle abhängigen untergeordneten Vorgänge, die in derselben Anfrage auf diese temporäre ID verweisen, mit NewResourceCreationError.TEMP_ID_RESOURCE_HAD_ERRORS fehl. Weitere Informationen finden Sie unter
siehe den Leitfaden zu teilweisen Fehlern.
Beachten Sie auch die Größenbeschränkungen für Anfragen, die Aufteilung in Unter-Batches und die Ratenbegrenzungen:
- Größenbeschränkungen für Anfragen und Chunks:Bei einer einzelnen
GoogleAdsService.Mutate-Anfrage gilt ein Limit von 10.000 Änderungsvorgängen (oder bis zu 20.000, wenn alle Vorgänge in der AnfrageAdGroupCriterionOperations sind). Wenn dieses Limit überschritten wird, wirdRequestError.TOO_MANY_MUTATE_OPERATIONSzurückgegeben. Außerdem sind maximal 100 Aktionsvorgänge zulässig (RequestError.TOO_MANY_ACTION_OPERATIONS).BatchJobService.AddBatchJobOperationsenforces a maximum of 10.000 Vorgängen pro Aufruf, 10.484.504 Byte pro einzelnemMutateOperationund 41.937.920 Byte proAddBatchJobOperationsRequest(returningBatchJobError.REQUEST_TOO_LARGEif any limit is exceeded, with up to 1.000.000 Vorgängen insgesamt pro Batchjob). Gleichzeitige Änderungen an derselben Kampagne oder demselben Konto könnenDatabaseError.CONCURRENT_MODIFICATION-Fehler auslösen. BatchJobServiceatomare Unter-Batches: Obwohl Batchjobs mit der Semantik für teilweise Fehler ausgeführt werden (standardmäßig 1.000 Vorgänge pro internem Unter-Batch), gruppiertBatchJobServicebestimmte zusammenhängende abhängige Vorgänge für dieselbe übergeordnete ID automatisch in atomare Unter-Batches:- Ein
AssetGroupOperation(create), gefolgt von zusammenhängendenAssetGroupAssetOperation(create) Vorgängen für dieselbeAssetGroup-ID (insgesamt bis zu 1.000 Vorgänge, die atomar mitBatchJobError.ASSET_GROUP_AND_ASSET_GROUP_ASSET_TRANSACTION_FAILUREfehlschlagen; jederAssetGroupOperationupdateoderremovewird in einem eigenständigen Unter-Batch mit einem einzelnen Vorgang ausgeführt). - Ein
CampaignOperation-Vorgang vom Typcreatefür Performance Max-Kampagnen (wenn Markenrichtlinien aktiviert sind – das ist die Standardeinstellung, es sei denn,brand_guidelines_enabledist auffalseoderhotel_property_asset_setist festgelegt), gefolgt von zusammenhängendenCampaignAssetOperation-Vorgängen (create) für dieselbeCampaign-ID (insgesamt bis zu 1.000 Vorgänge, die atomar mitBatchJobError.CAMPAIGN_AND_CAMPAIGN_ASSET_TRANSACTION_FAILUREfehlschlagen). - Aufeinanderfolgende
AssetGroupListingGroupFilterOperation(max 10,000, die atomar mitBatchJobError.ASSET_GROUP_LISTING_GROUP_FILTER_TRANSACTION_FAILUREfehlschlagen) oderAdGroupCriterionOperation(listing_group,max 20,000, die atomar mitCriterionError.LISTING_GROUP_ERROR_IN_ANOTHER_OPERATIONfehlschlagen) Vorgänge für dasselbe übergeordnete Element (AssetGroupoderAdGroup).
- Ein
Änderbare Attribute aus der Antwort abrufen
Wenn Sie das response_content_type Ihrer Mutationsanfrage auf
MUTABLE_RESOURCE setzen, enthält die Antwort für jedes unterstützte Objekt, das durch die Mutationsanfrage erstellt oder
aktualisiert (nicht entfernt) wurde, das
resource_name und das Ressourcenobjekt mit seinen änderbaren Feldern (sowie wichtige vom System ausgefüllte Felder der zurückgegebenen Ressource, z. B.
ExperimentArm.in_design_campaigns). Bei remove-Vorgängen oder bei Ressourcentypen, die die Rückgabe von MUTABLE_RESOURCE nicht unterstützen, enthält die Antwort immer nur resource_name. Mit dieser Funktion können Sie vermeiden, nach jedem Änderungsaufruf eine
zusätzliche Search oder SearchStream Anfrage zu senden.
Wenn Sie response_content_type nicht festlegen, wird in der Google Ads API standardmäßig RESOURCE_NAME_ONLY verwendet und es wird nur der resource_name jeder geänderten Ressource zurückgegeben.
Das folgende Beispiel zeigt, wie Sie eine änderbare Ressource aus einem Änderungsaufruf abrufen:
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( // 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
Perl
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]; }