字段掩码

在 Google Ads API 中,更新是通过字段遮盖完成的。字段掩码 (google.protobuf.FieldMask) 包含 snake_case 中您打算通过更新更改的字段路径列表。即使发送到服务器,系统也会忽略字段掩码中未包含的所有指定字段。

FieldMasks 实用程序

在 Java 客户端库中生成字段掩码的推荐方法是使用内置的 FieldMasks 实用程序类,该类可让您从修改后的对象生成字段掩码,而不是从头开始构建。

以下是更新广告系列的示例:

// Creates a Campaign object with the proper resource name and any other
// changes.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .setStatus(CampaignStatus.PAUSED)
        .build();

// Constructs an operation that updates the campaign, using the
// FieldMasks.allSetFieldsOf utility to derive the update mask. This mask tells
// the Google Ads API which attributes of the campaign you want to change.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(FieldMasks.allSetFieldsOf(campaign))
        .build();

// Sends the operation in a mutate request.
MutateCampaignsResponse response =
    campaignServiceClient.mutateCampaigns(
        customerId.toString(), Collections.singletonList(operation));

此示例首先创建一个空的 Campaign 构建器,并设置其资源名称,以便 API 知道要更新哪个广告系列。

然后,该示例对广告系列调用 FieldMasks.allSetFieldsOf(),以自动生成一个枚举所有已设置字段的字段掩码。您可以将返回的掩码直接传递给更新调用。

如果您需要处理现有对象并更新几个字段,请按如下方式使用 FieldMasks.compare():

// Assumes existingCampaign was retrieved from a previous API call.

// Creates a new campaign based on the existing campaign and updates the
// campaign by setting its status to paused.
Campaign campaignToUpdate =
    existingCampaign.toBuilder()
        .setStatus(CampaignStatus.PAUSED)
        .build();

// Constructs an operation that updates the campaign, using the
// FieldMasks.compare utility to derive the update mask. This mask tells the
// Google Ads API which attributes of the campaign you want to change.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaignToUpdate)
        .setUpdateMask(FieldMasks.compare(existingCampaign, campaignToUpdate))
        .build();

// Sends the operation in a mutate request.
MutateCampaignsResponse response =
    campaignServiceClient.mutateCampaigns(
        customerId.toString(), Collections.singletonList(operation));

如需从头开始创建字段掩码,请创建一个 FieldMask 构建器,并添加您打算更改的每个字段的 snake_case 名称:

FieldMask fieldMask =
    FieldMask.newBuilder()
        .addPaths("status")
        .addPaths("name")
        .build();

更新消息字段及其子字段

MESSAGE 字段可以包含子字段(例如 MaximizeConversions,其中包含 target_cpa_micros、cpc_bid_ceiling_micros 和 cpc_bid_floor_micros),也可以不包含子字段(例如 ManualCpm)。

没有定义子字段的消息字段

更新未定义任何子字段的 MESSAGE 字段时,请使用 FieldMasks 实用程序生成字段掩码,如上一部分中所述。

具有已定义的子字段的消息字段

在更新具有已定义子字段的 MESSAGE 字段时,如果未在该消息中明确设置任何子字段,您必须手动将每个可变的 MESSAGE 子字段添加到 FieldMask,这与从头开始创建字段掩码类似。

一个常见示例是更新广告系列的出价策略(oneof 字段 campaign_bidding_strategy),而不设置新出价策略上的任何字段。以下示例演示了如何更新广告系列以使用 MaximizeConversions 出价策略,而不设置出价策略的任何子字段。

在这种情况下,仅使用 FieldMasks 的 allSetFieldsOf() 和 compare() 方法无法实现预期目标。

以下示例会生成一个包含 maximize_conversions 的字段掩码。不过,Google Ads API 不允许更新掩码中包含具有子字段的顶级消息路径(以防止意外清除子字段),并且会返回 FieldMaskError.FIELD_HAS_SUBFIELDS 错误。

// Creates a campaign with the proper resource name and an empty
// MaximizeConversions field.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .setMaximizeConversions(MaximizeConversions.newBuilder().build())
        .build();

// Constructs an operation using FieldMasks.allSetFieldsOf to derive the update
// mask. The field mask includes 'maximize_conversions', which produces a
// FieldMaskError.FIELD_HAS_SUBFIELDS error.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(FieldMasks.allSetFieldsOf(campaign))
        .build();

// Sends the operation in a mutate request that results in a
// FieldMaskError.FIELD_HAS_SUBFIELDS error because empty MESSAGE fields with
// subfields cannot be included directly in a field mask.
MutateCampaignsResponse response =
    campaignServiceClient.mutateCampaigns(
        customerId.toString(), Collections.singletonList(operation));

以下示例演示了如何正确更新广告系列以使用 MaximizeConversions 出价策略,而不设置其任何子字段。详细了解如何分配标准出价策略和组合出价策略。

// Creates a Campaign object with the proper resource name.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .build();

// Creates a field mask from the campaign and adds the mutable subfield
// ('maximize_conversions.target_cpa_micros') on the MaximizeConversions
// bidding strategy to the field mask. Because this subfield is included in the
// field mask while excluded from the campaign object, the Google Ads API
// switches the campaign's bidding strategy oneof to MaximizeConversions with
// target_cpa_micros unset.
FieldMask fieldMask =
    FieldMasks.allSetFieldsOf(campaign).toBuilder()
        .addPaths("maximize_conversions.target_cpa_micros")
        .build();

// Creates an operation to update the campaign with the specified fields.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(fieldMask)
        .build();

清除字段

某些字段可以明确清除。与上一个示例类似,您必须明确将这些字段添加到字段掩码,同时在消息对象中将这些字段保留为未设置状态。例如,假设您有一个使用 MaximizeConversions 出价策略的广告系列,并且 target_cpa_micros 字段设置的值大于 0。

以下代码会运行,但 maximize_conversions.target_cpa_micros 不会按预期清除:

// Creates a campaign with the proper resource name and a MaximizeConversions
// object with target_cpa_micros set to 0L.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .setMaximizeConversions(
            MaximizeConversions.newBuilder().setTargetCpaMicros(0L).build())
        .setStatus(CampaignStatus.PAUSED)
        .build();

// Constructs an operation using FieldMasks.allSetFieldsOf to derive the
// update mask.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(FieldMasks.allSetFieldsOf(campaign))
        .build();

// Sends the operation in a mutate request that does not clear the field
// cleanly.
MutateCampaignsResponse response =
    campaignServiceClient.mutateCampaigns(
        customerId.toString(), Collections.singletonList(operation));

以下示例演示了如何正确清除 MaximizeConversions 出价策略中的 target_cpa_micros 字段。

// Creates a Campaign object with the proper resource name.
Campaign campaign =
    Campaign.newBuilder()
        .setResourceName(ResourceNames.campaign(customerId, campaignId))
        .build();

// Constructs a field mask from the campaign and adds the
// 'maximize_conversions.target_cpa_micros' field to the field mask, which
// clears this field from the bidding strategy without impacting any other
// fields on the bidding strategy.
FieldMask fieldMask =
    FieldMasks.allSetFieldsOf(campaign).toBuilder()
        .addPaths("maximize_conversions.target_cpa_micros")
        .build();

// Creates an operation to update the campaign with the specified field.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(fieldMask)
        .build();