روال‌های مطلوب جهش

این روال‌های مطلوب را دنبال کنید تا عملکرد را بهینه‌سازی کنید، وابستگی‌ها را در سراسر عملیات مدیریت کنید، و پاسخ‌ها را هنگام تغییر منابع در Google Ads API مدیریت کنید.

نام‌های موقت منبع

GoogleAdsService.Mutate و BatchJobService از نام‌های موقت منابع که می‌توان در عملیات‌های بعدی به آن‌ها ارجاع داد پشتیبانی می‌کنند. این به شما امکان می‌دهد پویش و گروه‌های آگهی، آگهی‌ها، و کلیدواژه‌های مرتبط با آن را در یک درخواست تغییر یا کار دسته‌ای ایجاد کنید.

برای ارجاع به منبع جدیداً ایجادشده در همان درخواست تغییر یا کار دسته‌ای، شناسه عدد صحیح منفی (مثل -1 یا -2، به‌استثنای 0) را در فیلد resource_name منبع جدید مشخص کنید. برای مثال، هنگام ایجاد پویش در درخواست دسته‌ای، نام منبع آن را روی customers/CUSTOMER_ID/campaigns/-1 تنظیم کنید. هنگام ایجاد گروه آگهی در عملیات بعدی در همان درخواست، به customers/CUSTOMER_ID/campaigns/-1 به‌عنوان پویش اصلی ارجاع دهید. «میانای برنامه‌سازی کاربردی» به‌طور خودکار -1 را با شناسه پویش واقعی که هنگام ایجاد تولید می‌شود جایگزین می‌کند.

محدودیت‌های استفاده

هنگام استفاده از نام‌های موقت منابع، قوانین زیر را به‌خاطر داشته باشید:

  • ترتیب مهم است: فقط پس‌از تعریف کردن نام منبع موقت می‌توانید به آن ارجاع دهید. در فهرست عملیات، عملیات وابسته (مثل ایجاد گروه آگهی) باید بعداز عملیاتی که منبع اصلی آن را ایجاد می‌کند (مثل ایجاد پویش) نشان داده شود.
  • محدوده درخواست تکی یا کار دسته‌ای: نام‌های موقت منابع در کارهای جداگانه یا درخواست‌های تغییر باقی نمی‌مانند. برای ارجاع به منبعی که در کار قبلی یا درخواست تغییر ایجاد شده است، از نام منبع واقعی تولیدشده توسط سیستم استفاده کنید.
  • یکتایی سراسری: در یک درخواست تغییر یا کار، هر نام منبع موقت باید از یک عدد صحیح منفی یکتا در همه انواع منابع استفاده کند. برای مثال، نمی‌توانید -1 را در یک درخواست به پویش و گروه آگهی اختصاص دهید. استفاده مجدد از شناسه موقت در همان درخواست یا کار دسته‌ای خطای NewResourceCreationError.DUPLICATE_TEMP_IDS را برمی‌گرداند.

نمونه پایه‌بار

فرض کنید می‌خواهید یک پویش، یک گروه آگهی، و یک آگهی را در یک درخواست API یا کار دسته‌ای اضافه کنید. می‌توانید آرایه mutateOperations را در بار داده درخواست GoogleAdsService.Mutate یا BatchJobService.AddBatchJobOperations ساختاربندی کنید، همان‌طور که در نمونه REST JSON زیر نشان داده شده است (با حذف سایر فیلدهای منبع الزامی برای اختصار):

{
  "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"
        }
      }
    }
  ]
}

این مثال جزئیات کلیدی زیر را نشان می‌دهد:

  • گروه آگهی از شناسه موقت جدیدی (-2) استفاده می‌کند زیرا -1 قبلاً به پویش اختصاص داده شده است.
  • گروه آگهی به customers/CUSTOMER_ID/campaigns/-1 ارجاع می‌دهد تا خود را به پویشی که در عملیات قبلی ایجاد شده است پیوند دهد.
  • adGroupAdOperation به customers/CUSTOMER_ID/adGroups/-2 ارجاع می‌دهد و resourceName را حذف می‌کند زیرا هیچ عملیات بعدی در درخواست به آگهی جدید ارجاع نمی‌دهد.

گروه‌بندی عملیات‌های هم‌نوع

هنگام استفاده از GoogleAdsService.Mutate، عملیات گروهی را براساس نوع منبع در آرایه تکرارشونده mutate_operations با رعایت وابستگی‌های والد و فرزند با هم ترکیب کنید. این روش به‌طور متوالی عملیات را می‌خواند تا زمانی که با نوع منبع متفاوتی مواجه شود، و سپس همه عملیات‌های مجاور از همان نوع را در یک درخواست سرویس پس‌زمینه واحد دسته‌بندی می‌کند.

برای مثال، اگر ۵ عملیات پویش و به‌دنبال آن ۱۰ عملیات گروه آگهی را در فیلد تکراری mutate_operations اضافه کنید، سیستم دو فراخوانی پسین انجام می‌دهد: یکی به CampaignService برای ۵ عملیات پویش، و دومی به AdGroupService برای ۱۰ عملیات گروه آگهی.

درمقابل، درهم‌بافی عملیات با ترتیب دادن آن‌ها به‌صورت [campaign, ad group, campaign, ad group] منجر به چهار فراخوانی جداگانه در پس‌نما می‌شود. فراخوانی‌های درهم‌بافته عملکرد میانای برنامه‌سازی کاربردی را کاهش می‌دهد و می‌تواند منجر به اتمام مهلت درخواست در دسته‌های بزرگ شود.

رسیدگی به شکست جزئی و محدودیت‌های دسته‌ای

به‌طور پیش‌فرض، اگر هریک از عملیات‌ها ناموفق باشد، GoogleAdsService.Mutate کل درخواست را برمی‌گرداند. برای انجام عملیات‌های معتبر حتی زمانی که عملیات‌های دیگر در همان درخواست ناموفق است، partial_failure را در درخواست روی true تنظیم کنید و partial_failure_error را در پاسخ بازرسی کنید. وقتی partial_failure برابر با true باشد، اگر عملیات والدی که شناسه موقت را تعریف می‌کند (مثل customers/CUSTOMER_ID/campaigns/-1) در اعتبارسنجی ناموفق باشد، هر عملیات فرزند وابسته‌ای که به آن شناسه موقت در همان درخواست ارجاع می‌دهد نیز با NewResourceCreationError.TEMP_ID_RESOURCE_HAD_ERRORS ناموفق می‌شود. برای جزئیات بیشتر، راهنمای خطای جزئی را ببینید.

همچنین اندازه درخواست، دسته‌بندی فرعی، و محدودیت‌های نرخ را درنظر داشته باشید:

  • محدودیت‌های اندازه درخواست و تکه: یک درخواست GoogleAdsService.Mutate واحد محدودیت ۱۰٬۰۰۰ عمل جهش (یا حداکثر ۲۰٬۰۰۰ وقتی همه عملیات در درخواست AdGroupCriterionOperations هستند، درصورت تجاوز از حد RequestError.TOO_MANY_MUTATE_OPERATIONS برمی‌گرداند) و حداکثر ۱۰۰ عمل کنش (RequestError.TOO_MANY_ACTION_OPERATIONS) را اعمال می‌کند. BatchJobService.AddBatchJobOperations حداکثر ۱۰٬۰۰۰ عملیات در هر تماس، ۱۰٬۴۸۴٬۵۰۴ بایت در هر فرد MutateOperation، و ۴۱٬۹۳۷٬۹۲۰ بایت در هر AddBatchJobOperationsRequest (درصورت تجاوز از هر حد، BatchJobError.REQUEST_TOO_LARGE برمی‌گرداند، با حداکثر ۱٬۰۰۰٬۰۰۰ عملیات در مجموع در هر کار دسته‌ای) را اعمال می‌کند. جهش‌های هم‌زمان که همان پویش یا حساب را هدف قرار می‌دهند می‌توانند خطاهای DatabaseError.CONCURRENT_MODIFICATION را راه‌اندازی کنند.
  • دسته‌بندی فرعی اتمی BatchJobService: اگرچه کارهای دسته‌ای تحت معناشناسی شکست جزئی اجرا می‌شوند (به‌طور پیش‌فرض ۱۰۰۰ عملیات در هر دسته فرعی داخلی)، BatchJobService به‌طور خودکار عملیات وابسته مجاور خاصی را برای همان شناسه اصلی در دسته‌های فرعی اتمی گروه‌بندی می‌کند:
    • یک AssetGroupOperation (create) که با AssetGroupAssetOperation (create) عملیات پیوسته برای همان شناسه AssetGroup دنبال می‌شود (مجموعاً تا ۱٬۰۰۰ عملیات، که به‌صورت اتمی با BatchJobError.ASSET_GROUP_AND_ASSET_GROUP_ASSET_TRANSACTION_FAILURE; هر AssetGroupOperation update یا remove در یک زیردسته‌ای تک‌عملیاتی مستقل اجرا می‌شود).
    • یک CampaignOperation «بیشینه‌سازی عملکرد» (create، وقتی «رهنمودهای نمانام» فعال باشد—که پیش‌فرض است مگراینکه brand_guidelines_enabled روی false تنظیم شده باشد یا hotel_property_asset_set تنظیم شده باشد) و به‌دنبال آن عملیات CampaignAssetOperation (create) مجاور برای همان شناسه Campaign (درمجموع تا ۱٬۰۰۰ عملیات، که به‌صورت اتمی با BatchJobError.CAMPAIGN_AND_CAMPAIGN_ASSET_TRANSACTION_FAILURE ناموفق می‌شود).
    • ‫AssetGroupListingGroupFilterOperation متوالی (max 10,000، با BatchJobError.ASSET_GROUP_LISTING_GROUP_FILTER_TRANSACTION_FAILURE به‌صورت اتمی ناموفق است) یا AdGroupCriterionOperation (listing_group،‏ max 20,000، با CriterionError.LISTING_GROUP_ERROR_IN_ANOTHER_OPERATION به‌صورت اتمی ناموفق است) عملیات برای همان والد (AssetGroup یا AdGroup).

بازیابی مشخصه‌های تغییرپذیر از پاسخ

اگر response_content_type درخواست جهش خود را روی MUTABLE_RESOURCE تنظیم کنید، پاسخ حاوی resource_name و شیء منبعی است که با فیلدهای جهش‌پذیر آن (و همچنین فیلدهای کلیدی پرشده توسط سیستم در منبع برگشتی، مثل ExperimentArm.in_design_campaigns) برای هر شیء پشتیبانی‌شده‌ای که توسط درخواست ایجاد یا به‌روزرسانی شده است (برداشته نشده است) پر شده است. برای عملیات remove—یا برای انواع منابعی که از برگرداندن MUTABLE_RESOURCE پشتیبانی نمی‌کنند—پاسخ همیشه فقط resource_name را برمی‌گرداند. از این ویژگی استفاده کنید تا پس‌از هر تماس تغییر، درخواست Search یا SearchStream اضافی ارسال نکنید.

اگر response_content_type را تنظیم نکنید، Google Ads API به‌طور پیش‌فرض روی RESOURCE_NAME_ONLY تنظیم می‌شود و فقط resource_name هر منبع تغییریافته را برمی‌گرداند.

مثال زیر نشان می‌دهد که چگونه یک منبع قابل تغییر را از یک فراخوانی mutate بازیابی کنید:

جاوا

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
      

پرل

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];
}
      

curl