필드 마스크

Google Ads API에서는 필드 마스크를 사용하여 업데이트가 이루어집니다. 필드 마스크에는 업데이트와 함께 변경하려는 모든 필드가 나열되며, 필드 마스크에 없는 지정된 필드는 서버로 전송되더라도 무시됩니다.

FieldMaskUtil

필드 마스크를 생성하는 데 권장되는 방법은 필드 마스크를 처음부터 빌드하는 대신 수정된 객체에서 필드 마스크를 생성할 수 있는 Google의 기본 제공 필드 마스크 유틸리티를 사용하는 것입니다.

다음은 캠페인을 업데이트하는 예입니다.

// 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 will update 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() 메서드를 사용하여 설정된 모든 필드를 열거하는 필드 마스크를 자동으로 생성합니다. 그런 다음 반환된 마스크를 업데이트 호출에 직접 전달할 수 있습니다.

기존 객체로 작업하여 필드 몇 개를 업데이트해야 하는 경우 다음과 같이 코드를 수정할 수 있습니다.

Campaign existingCampaign;

// Obtains existingCampaign from elsewhere.
...

// Creates a new campaign based off 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 will update 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 객체를 만든 후 변경하려는 각 필드의 이름을 객체에 추가합니다.

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

메시지 필드 및 하위 필드 업데이트

MESSAGE 필드에는 하위 필드가 있거나 (예: target_cpa_micros, cpc_bid_ceiling_micros, cpc_bid_floor_micros 3개가 포함된 MaximizeConversions) 아예 없는 하위 필드 (예: ManualCpm)가 있을 수 있습니다.

정의된 하위 필드가 없는 메시지 필드

하위 필드가 정의되지 않은 MESSAGE 필드를 업데이트할 때는 위에서 설명한 대로 FieldMaskUtil을 사용하여 필드 마스크를 생성합니다.

정의된 하위 필드가 있는 메시지 필드

메시지의 하위 필드를 명시적으로 설정하지 않고 하위 필드로 정의된 MESSAGE 필드를 업데이트하는 경우 필드 마스크를 처음부터 만드는 위 예시와 유사하게 변경 가능한 MESSAGE 하위 필드를 각각 FieldMask에 수동으로 추가해야 합니다.

일반적인 예로 새 입찰 전략의 필드를 설정하지 않고 캠페인의 입찰 전략을 업데이트하는 경우가 있습니다. 아래 예는 입찰 전략의 하위 필드를 설정하지 않고 MaximizeConversions 입찰 전략을 사용하도록 캠페인을 업데이트하는 방법을 보여줍니다.

이 경우 FieldMaskUtil의 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 the FieldMasks' allSetFieldsOf utility to
// derive the update mask. The field mask will include 'maximize_conversions`,
// which will produce 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 will result in a
// FieldMaskError.FIELD_HAS_SUBFIELDS error because empty MESSAGE fields cannot
// be included 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 existing campaign and adds all of the mutable
// fields (only one in this case) on the MaximizeConversions bidding strategy to
// the field mask. Because this field is included in the field mask but
// excluded from the campaign object, the Google Ads API will set the campaign's
// bidding strategy to a MaximizeConversions object without any of its subfields
// set.
FieldMask fieldMask = FieldMasks.allSetFieldsOf(campaign)
    .toBuilder()
    // Only include 'maximize_conversions.target_cpa_micros' in the field mask
    // as it is the only mutable subfield on MaximizeConversions when used as a
    // standard bidding strategy.
    //
    // Learn more about standard and portfolio bidding strategies here:
    // https://developers.google.com/google-ads/api/docs/campaigns/bidding/assign-strategies
    .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가 필드 마스크에 추가되지 않으므로 target_cpa_micros 필드가 변경되지 않습니다.

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

// Constructs an operation, using the FieldMasks' allSetFieldsOf utility to
// derive the update mask. However, the field mask will NOT include
// 'maximize_conversions.target_cpa_micros'.
CampaignOperation operation =
    CampaignOperation.newBuilder()
        .setUpdate(campaign)
        .setUpdateMask(FieldMasks.allSetFieldsOf(campaign))
        .build();

// Sends the operation in a mutate request that will succeed but will NOT update
// the 'target_cpa_micros' field because
// 'maximize_conversions.target_cpa_micros' was not included in the field mask.
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 existing campaign and adds the
// 'maximize_conversions.target_cpa_micros' field to the field mask, which will
// clear 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();

위의 '잘못된' 예는 Google Ads API protocol buffers에서 optional로 정의된 필드에 정상적으로 적용됩니다. 하지만 target_cpa_microsoptional 필드가 아니므로 '잘못된' 예시는 target_cpa 필드를 지우도록 입찰 전략을 업데이트하지 않습니다.