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 einzelnen Mutationsanfrage oder einem Batch-Job 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 (außer 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, verweisen Sie auf customers/CUSTOMER_ID/campaigns/-1 als übergeordnete Kampagne. Die API ersetzt -1 automatisch durch die tatsächliche Kampagnen-ID, die beim Erstellen generiert wird.
Nutzungseinschränkungen
Beachten Sie bei der Verwendung temporärer Ressourcennamen die folgenden Regeln:
- Reihenfolge wichtig:Sie können erst 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).
- Bereich für einzelne Anfragen oder Batchjobs:Temporäre Ressourcennamen bleiben nicht über separate Jobs oder Änderungsanfragen hinweg erhalten. 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:In einem einzelnen Job oder einer einzelnen Mutationsanfrage muss für jeden temporären Ressourcennamen eine eindeutige negative Ganzzahl für alle Ressourcentypen verwendet werden.
Sie können
-1beispielsweise nicht 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 einzelnen API-Anfrage oder einem Batch-Job hinzufügen. Sie können das mutateOperations-Array in einer GoogleAdsService.Mutate- oder BatchJobService.AddBatchJobOperations-Anfrage-Nutzlast 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. - Die
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, fassen Sie Vorgänge nach Ressourcentyp im wiederholten mutate_operations-Array zusammen und berücksichtigen Sie dabei die Abhängigkeiten zwischen übergeordneten 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 einzelnen Back-End-Dienstanfrage zusammengefasst.
Wenn Sie beispielsweise fünf Kampagnenvorgänge und dann zehn Anzeigengruppenvorgänge in das wiederholte Feld mutate_operations einfügen, 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 die 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.
Partielle Fehler und Batch-Limits verarbeiten
Standardmäßig wird mit 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 gleich true ist und die Validierung eines übergeordneten Vorgangs, der eine temporäre ID definiert (z. B. customers/CUSTOMER_ID/campaigns/-1), fehlschlägt, 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 Anfragengröße, die Aufteilung in Unter-Batches und die Ratenlimits:
- Anfrage- und Chunk-Größenbeschränkungen:Für eine einzelne
GoogleAdsService.Mutate-Anfrage gilt ein Limit von 10.000 Mutationsvorgä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ängen (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 insgesamt bis zu 1.000.000 Vorgängen pro Batchjob). Gleichzeitige Mutationen, die auf dieselbe Kampagne oder dasselbe Konto ausgerichtet sind, könnenDatabaseError.CONCURRENT_MODIFICATION-Fehler auslösen. BatchJobServiceAtomare Sub-Batch-Verarbeitung:Batch-Jobs werden zwar mit Semantik für Teilausfälle ausgeführt (standardmäßig 1.000 Vorgänge pro internem Sub-Batch), aberBatchJobServicegruppiert bestimmte zusammenhängende abhängige Vorgänge für dieselbe übergeordnete ID automatisch in atomaren Sub-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; jedeAssetGroupOperationupdateoderremovewird in einem eigenständigen Sub-Batch mit einem einzelnen Vorgang ausgeführt). - Eine Performance Max-Kampagne
CampaignOperation(create, wenn Markenrichtlinien aktiviert sind, was die Standardeinstellung ist, es sei denn,brand_guidelines_enabledist auffalsefestgelegt oderhotel_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-Vorgänge (max 10,000, die atomar mitBatchJobError.ASSET_GROUP_LISTING_GROUP_FILTER_TRANSACTION_FAILUREfehlschlagen) oderAdGroupCriterionOperation-Vorgänge (listing_group,max 20,000, die atomar mitCriterionError.LISTING_GROUP_ERROR_IN_ANOTHER_OPERATIONfehlschlagen) für dasselbe übergeordnete Element (AssetGroupoderAdGroup).
- Ein
Veränderbare Attribute aus der Antwort abrufen
Wenn Sie response_content_type Ihrer Mutationsanfrage auf MUTABLE_RESOURCE setzen, enthält die Antwort die resource_name und das Ressourcenobjekt, das mit den änderbaren Feldern (sowie den vom Schlüsselsystem ausgefüllten Feldern der zurückgegebenen Ressource, z. B. ExperimentArm.in_design_campaigns) für jedes unterstützte Objekt gefüllt ist, das durch die Anfrage erstellt oder aktualisiert (nicht entfernt) wurde. Bei remove-Vorgängen oder bei Ressourcentypen, die die Rückgabe von MUTABLE_RESOURCE nicht unterstützen, wird in der Antwort immer nur resource_name zurückgegeben. Mit dieser Funktion können Sie vermeiden, dass nach jedem Mutate-Aufruf 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 es wird nur die resource_name jeder geänderten Ressource zurückgegeben.
Das folgende Beispiel zeigt, wie eine veränderliche Ressource aus einem Mutate-Aufruf abgerufen wird:
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]; }