Beachten Sie die folgenden Best Practices, um die Leistung zu optimieren, Abhängigkeiten zwischen Vorgängen zu verwalten und Antworten zu 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 einzigen 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, ausgenommen 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 innerhalb derselben Anfrage eine Anzeigengruppe erstellen, geben Sie customers/CUSTOMER_ID/campaigns/-1 als übergeordnete Kampagne an. Die API ersetzt -1 automatisch durch die tatsächliche Kampagnen-ID, die beim Erstellen generiert wird.
Nutzungsbeschränkungen
Beachten Sie bei der Verwendung temporärer Ressourcennamen die folgenden Regeln:
- Reihenfolge beachten: Sie können auf einen temporären Ressourcennamen erst 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 erscheinen, mit dem die übergeordnete Ressource erstellt wird (z. B. das Erstellen einer Kampagne).
- Bereich für einzelne Anfragen oder Batchjobs: Temporäre Ressourcennamen bleiben nicht über separate Jobs oder Mutationsanfragen hinweg erhalten. Wenn Sie auf eine Ressource verweisen möchten, die in einem vorherigen Job oder einer Mutationsanfrage erstellt wurde, verwenden Sie den tatsächlichen, vom System generierten Ressourcennamen.
- Globale Eindeutigkeit: Innerhalb eines einzelnen Jobs oder einer Mutationsanfrage muss jeder temporäre Ressourcenname eine eindeutige negative Ganzzahl für alle Ressourcentypen verwenden.
Sie können beispielsweise
-1nicht in derselben Anfrage sowohl einer Kampagne als auch einer Anzeigengruppe zuweisen. 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 eine Kampagne, eine Anzeigengruppe und eine Anzeige in einer einzigen API-Anfrage oder einem einzigen Batchauftrag hinzufügen. Sie können das mutateOperations-Array in einer GoogleAdsService.Mutate- oder BatchJobService.AddBatchJobOperations-Anfragenutzlast strukturieren, wie im folgenden REST-JSON-Beispiel gezeigt (andere erforderliche Ressourcenfelder wurden der Einfachheit halber 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"
}
}
}
]
}
In diesem Beispiel werden die folgenden wichtigen Details veranschaulicht:
- 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 im vorherigen Vorgang erstellten Kampagne zu verknüpfen. adGroupAdOperationverweist aufcustomers/CUSTOMER_ID/adGroups/-2und lässtresourceNameaus, 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 über- und untergeordnete Abhängigkeiten. Bei dieser Methode werden Vorgänge nacheinander 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 im wiederkehrenden Feld mutate_operations fünf Kampagnenvorgänge gefolgt von zehn Anzeigengruppenvorgängen 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.
Im Gegensatz dazu führt die Verschachtelung von Vorgängen durch die Reihenfolge [campaign, ad group,
campaign, ad group] zu vier separaten Backend-Aufrufen. Verschachtelte Aufrufe beeinträchtigen die API-Leistung und können bei großen Batches zu Zeitüberschreitungen bei Anfragen führen.
Teilweise fehlgeschlagene Vorgänge 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 übernehmen 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 den Wert true hat und ein übergeordneter Vorgang, der eine temporäre ID (z. B. customers/CUSTOMER_ID/campaigns/-1) definiert, 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 im Leitfaden zu Teilausfällen.
Beachten Sie auch die Anfragegröße, die Unter-Batch-Verarbeitung und die Ratenbegrenzungen:
- Anfrage- und Blockgrößenlimits: Für eine einzelne
GoogleAdsService.Mutate-Anfrage gilt ein Limit von 10.000 Änderungsvorgängen (oder bis zu 20.000, wenn alle Vorgänge in der AnfrageAdGroupCriterionOperations sind, wobeiRequestError.TOO_MANY_MUTATE_OPERATIONSzurückgegeben wird, wenn das Limit überschritten wird) und maximal 100 Aktionsvorgänge (RequestError.TOO_MANY_ACTION_OPERATIONS). FürBatchJobService.AddBatchJobOperationsgilt ein Limit von maximal 10.000 Vorgängen pro Aufruf, 10.484.504 Byte pro einzelnemMutateOperationund 41.937.920 Byte proAddBatchJobOperationsRequest(wobeiBatchJobError.REQUEST_TOO_LARGEzurückgegeben wird, wenn ein Limit überschritten wird, mit bis zu 1.000.000 Vorgängen insgesamt pro Batchjob). Gleichzeitige Mutationen, die auf dieselbe Kampagne oder dasselbe Konto abzielen, könnenDatabaseError.CONCURRENT_MODIFICATION-Fehler auslösen. - Atomares Sub-Batching von
BatchJobService: Obwohl Batchjobs mit Semantik für Teilausfälle ausgeführt werden (standardmäßig 1.000 Vorgänge pro internem Sub-Batch), gruppiertBatchJobServiceautomatisch bestimmte zusammenhängende abhängige Vorgänge für dieselbe übergeordnete ID in atomare Sub-Batches:- Ein
AssetGroupOperation(create), gefolgt von aufeinanderfolgendenAssetGroupAssetOperation-Vorgängen (create) für dieselbeAssetGroup-ID (insgesamt bis zu 1.000 Vorgänge, die atomar mitBatchJobError.ASSET_GROUP_AND_ASSET_GROUP_ASSET_TRANSACTION_FAILUREfehlschlagen; jederAssetGroupOperation-updateoderremovewird in einem eigenständigen Unterbatch mit einem einzelnen Vorgang ausgeführt). - Ein Performance Max-
CampaignOperation(create, wenn Markenrichtlinien aktiviert sind – das ist die Standardeinstellung, sofernbrand_guidelines_enablednicht auffalseoderhotel_property_asset_setfestgelegt ist), 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-Vorgänge (max 10,000, atomarer Fehler mitBatchJobError.ASSET_GROUP_LISTING_GROUP_FILTER_TRANSACTION_FAILURE) oderAdGroupCriterionOperation-Vorgänge (listing_group,max 20,000, atomarer Fehler mitCriterionError.LISTING_GROUP_ERROR_IN_ANOTHER_OPERATION) für dasselbe übergeordnete Element (AssetGroupoderAdGroup).
- Ein
Änderbare Attribute aus der Antwort abrufen
Wenn Sie den response_content_type Ihrer Mutationsanfrage auf MUTABLE_RESOURCE festlegen, enthält die Antwort für jedes unterstützte Objekt, das durch die Anfrage erstellt oder aktualisiert (nicht entfernt) wurde, den resource_name und das Ressourcenobjekt, das mit seinen änderbaren Feldern (sowie wichtigen vom System ausgefüllten Feldern der zurückgegebenen Ressource, z. B. ExperimentArm.in_design_campaigns) gefüllt ist. Bei remove-Vorgängen oder bei Ressourcentypen, die die Rückgabe von MUTABLE_RESOURCE nicht unterstützen, wird in der Antwort immer nur die resource_name zurückgegeben. Mit dieser Funktion können Sie vermeiden, dass nach jedem Änderungsaufruf eine zusätzliche Search- oder SearchStream-Anfrage gesendet wird.
Wenn Sie response_content_type nicht festlegen, wird in der Google Ads API standardmäßig RESOURCE_NAME_ONLY verwendet und nur der resource_name jeder geänderten Ressource zurückgegeben.
Im folgenden Beispiel wird gezeigt, 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.V26.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| # In standard campaign experiments, creating the treatment arm automatically # generates a draft campaign 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 second, it will be the second 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::V26::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V26::Resources::ExperimentArm->new({ # The "control" arm references an already-existing campaign. control => "true", campaigns => [ Google::Ads::GoogleAds::V26::Utils::ResourceNames::campaign( $customer_id, $base_campaign_id ) ], experiment => $experiment, name => "control arm", trafficSplit => 40 })}); push @$operations, Google::Ads::GoogleAds::V26::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V26::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]; }