冲突的否定关键字和共享集

否定关键字防止不相关的搜索结果触发广告展示。然而,如果您的否定关键字列表中存在不正确的匹配类型,则可能会在不经意间阻止正常的关键字匹配,削弱广告系列的成效。

本指南介绍如何使用 AdWords API 自动消除冲突的否定关键字以及使用共享集管理否定关键字和排除的展示位置。

场景

假设您拥有一家男装店,并希望针对男士配饰投放一个特殊的冬季假日广告系列,以增加网站的流量。您最近运行了搜索字词报告,且注意到,当用户搜索女士真丝围巾时,也会看到您广告系列中的男士配饰广告。

您的关键字列表中有“真丝领带”、“羊毛围巾”和“男士礼品”等广泛匹配关键字。您希望将“真丝围巾”添加为否定关键字,但应该选择哪种否定关键字匹配类型

下表列出了一些搜索字词,并说明对于这三个否定匹配类型中的每一个,广告是否会被阻止投放。

搜索字词 否定关键字
-真丝围巾
(否定广泛匹配)
-"真丝围巾"
(否定词组匹配)
-[真丝围巾]
(否定完全匹配)
男士围巾
男士领带
围巾真丝 圆圈斜杠符号
真丝领带
真丝礼品围巾 圆圈斜杠符号
真丝围巾 圆圈斜杠符号 圆圈斜杠符号 圆圈斜杠符号
真丝围巾礼品 圆圈斜杠符号 圆圈斜杠符号
真丝领带羊毛围巾 圆圈斜杠符号
女士真丝围巾 圆圈斜杠符号 圆圈斜杠符号
羊毛围巾

请注意,广泛匹配否定关键字-真丝围巾会阻止某些有效的搜索字词,如“真丝领带羊毛围巾”。

确定大规模冲突的否定关键字

如果只有几个关键字,那么很容易就能判断哪些否定关键字与肯定关键字冲突。而如果您的帐户中有数以千计的关键字和数以百计的否定关键字,这一过程就要困难得多。让我们来看看如何使用 AdWords API 实现这个过程的自动化。

为了方便演示,我们将这一场景限制为肯定关键字是在广告组级别,否定关键字是在广告系列级别。

获取否定关键字

如下所示,通过运行广告系列否定关键字效果报告,获取广告系列级否定关键字列表:

def retrieve_negative_keywords(report_utils)
  report_definition = {
    :selector => {
      :fields => ['CampaignId', 'Id', 'KeywordMatchType', 'KeywordText']
    },
    :report_name => 'Negative campaign keywords',
    :report_type => 'CAMPAIGN_NEGATIVE_KEYWORDS_PERFORMANCE_REPORT',
    :download_format => 'CSV',
    :date_range_type => 'TODAY',
    :include_zero_impressions => true
  }

  campaigns = {}

  report = report_utils.download_report(report_definition)
  # Slice off the first row (report name).
  report.slice!(0..report.index("\n"))

  CSV.parse(report, { :headers => true }) do |row|
    campaign_id = row['Campaign ID']

    # Ignore totals row.
    if row[0] != 'Total'
      campaigns[campaign_id] ||= Campaign.new(campaign_id)
      negative = Negative.from_csv_row(row)
      campaigns[campaign_id].negatives << negative
    end
  end

  return campaigns
end

获取肯定关键字

运行关键字效果报告,获取肯定关键字列表。此 allowed_values 参数允许您按状态来滤除广告系列、广告组和关键字,并可以接受值 PAUSEDREMOVED

def retrieve_positive_keyword_report(report_utils, allowed_values)
  report_definition = {
    :selector => {
      :fields => ['CampaignId', 'CampaignName', 'AdGroupId', 'Id',
                  'KeywordMatchType', 'KeywordText'],
      :predicates => [
        {
          :field => 'CampaignStatus',
          :operator => 'IN',
          :values => allowed_values
        },
        {
          :field => 'AdGroupStatus',
          :operator => 'IN',
          :values => allowed_values
        },
        {
          :field => 'Status',
          :operator => 'IN',
          :values => allowed_values
        },
        {
          :field => 'IsNegative',
          :operator => 'IN',
          :values => ['false']
        }
      ]
    },
    :report_name => 'Ad group keywords',
    :report_type => 'KEYWORDS_PERFORMANCE_REPORT',
    :download_format => 'CSV',
    :date_range_type => 'TODAY',
    :include_zero_impressions => true
  }

  report = report_utils.download_report(report_definition)
  # Slice off the first row (report name).
  report.slice!(0..report.index("\n"))

  return report
end

确定冲突的否定关键字

否定关键字按照以下逻辑工作:

  • 如果搜索字词包含广泛匹配否定关键字的所有字词,则会被该否定关键字阻止。例如,-真丝围巾将阻止“真丝礼品围巾”,而不会阻止“羊毛围巾”。
  • 如果搜索字词以一个单一短语的形式包含了词组匹配否定关键字中的所有字词,则会被该否定关键字阻止。例如,-"真丝围巾"将阻止“礼品真丝围巾”,而不会阻止“真丝礼品围巾”。
  • 而只有搜索字词与完全匹配否定关键字完全一致时,才会被阻止。例如,-[真丝围巾]将阻止“真丝围巾”,而不会阻止“红色真丝围巾”。
  • 关键字不区分大小写。
  • 紧密变体匹配不适用于否定关键字。例如,-silk scarves 不会阻止“silk scarf”,尽管该关键字是“silk scarves”的紧密变体匹配,也是如此。

以下方法是对这个逻辑的实现:

def compare_keywords(negatives, positive)
  negatives.each do |negative|
    match_type = negative.match_type.downcase
    negative_text = negative.text.downcase
    positive_text = positive.text.downcase

    match = false

    # Exact matching with negative keywords triggers only when the full text of
    # the keywords is exactly the same.
    # E.g. a negative "silk scarves" will only match "silk scarves", not
    # "red silk scarves".
    if match_type == 'exact'
      match = (negative_text == positive_text)
    end

    # Phrase matching with negative keywords triggers when the negative phrase
    # is present in the target, completely unmodified.
    # E.g. a negative "silk scarves" will match "gift silk scarves", but not
    # "silk gift scarves".
    if match_type == 'phrase'
      negative_tokens = negative_text.split(' ')
      positive_tokens = positive_text.split(' ')

      positive_tokens.each_with_index do |positive_token, positive_index|
        # Iterate until the current token matches the first token in the
        # negative keyword.
        if positive_token == negative_tokens.first
          candidate_match = true
          # Do all of the subsequent tokens also match?
          negative_tokens[1..-1].each_with_index do |token, index|
            if token != positive_tokens[positive_index + index + 1]
              candidate_match = false
              break
            end
          end

          match = candidate_match
        end
      end
    end

    # Broad matching with negative keywords triggers when all of the words are
    # present and exactly the same.
    # E.g. a negative "silk scarves" will match "silk gift scarves", but not
    # "wool scarves".
    if match_type == 'broad'
      negative_tokens = negative_text.split(' ')
      positive_tokens = positive_text.split(' ')

      candidate_match = true

      negative_tokens.each do |token|
        if !positive_tokens.include?(token)
          candidate_match = false
          break
        end
      end

      match = candidate_match
    end

    negative.add_blocked(positive) if match
  end
end

删除冲突的否定关键字

如果确定了冲突的否定关键字,您可以:

您应该定期重复此过程,以确保对关键字列表或否定关键字列表的任何更改都没有引入新的冲突。

完整示例代码

上面使用的完整示例代码AdWords API Ruby 客户端库的一部分。

共享集

如果您发现,有一组跨多个广告系列的关键字或展示位置为您带来了多余的展示或点击,您可以在 AdWords 中创建这些否定关键字或排除的展示位置集中列表,并将该列表添加到所有的广告系列。该功能被称为共享集

有了共享集,您就不需要在帐户内部复制条目,可以更有效地管理您的否定关键字和展示位置排除。

本节将介绍如何使用 AdWords API 来创建和使用共享集。

该代码示例使用 AdWords API Java 库。我们还为其他支持的客户端库提供了代码示例。

创建共享集

要使用否定关键字的共享集,必须先创建一个共享集,然后填充以要排除的关键字列表。以下代码段使用 SharedSetService 创建否定关键字的共享集。


// Create the operation.
SharedSetOperation operation = new SharedSetOperation();
operation.setOperator(Operator.ADD);

// Create the shared set.
SharedSet sharedSet = new SharedSet();
sharedSet.setName("API Negative keyword list for demo");

// Set the type of the shared set. This may be negative keywords or placements.
sharedSet.setType(SharedSetType.NEGATIVE_KEYWORDS);
operation.setOperand(sharedSet);

SharedSetReturnValue retval = sharedSetService.mutate(
    new SharedSetOperation[] {operation});
for (SharedSet set : retval.getValue()) {
  System.out.println("Shared set with id = " + set.getSharedSetId() + ", name = " +
      set.getName() + ", type = " + set.getType() + ", status = " + set.getStatus() +
      "was created.");
}

创建共享集之后,您可以使用 SharedCriterionService 将关键字添加到新创建的共享集。以下代码段将两个新的关键字添加到共享集。

String[] keywordTexts = new String[] {"mars cruise", "mars hotels"};

List operations = new ArrayList();
for (String keywordText: keywordTexts) {
  // Create the shared criterion.
  Keyword keyword = new Keyword();
  keyword.setText(keywordText);
  keyword.setMatchType(KeywordMatchType.BROAD);

  SharedCriterion sharedCriterion = new SharedCriterion();
  sharedCriterion.setCriterion(keyword);
  sharedCriterion.setNegative(true);
  sharedCriterion.setSharedSetId(sharedSetId);

  SharedCriterionOperation operation = new SharedCriterionOperation();
  operation.setOperator(Operator.ADD);
  operation.setOperand(sharedCriterion);
  operations.add(operation);
}

SharedCriterionReturnValue retval = sharedCriterionService.mutate(operations.toArray(
    new SharedCriterionOperation[operations.size()]));
for (SharedCriterion sharedCriterion : retval.getValue()) {
  Keyword keyword = (Keyword) sharedCriterion.getCriterion();
  System.out.println("Added keyword with id = " + keyword.getId() + ", text = " +
      keyword.getText() + ", matchtype = " + keyword.getMatchType() + " to shared " +
      "set with id = " + sharedSetId + ".");
}

您可以使用 memberCount 字段来确定共享集中的关键字或展示位置的数量。另一个有用的字段是 referenceCount,该字段说明共享集与多少广告系列相关联。

将共享集应用于广告系列

创建共享集之后,可以使用 CampaignSharedSetService 将其附加到多个广告系列。以下代码演示了如何将现有的共享集附加到广告系列:

// Create the campaign shared set
CampaignSharedSet campaignSharedSet = new CampaignSharedSet();
campaignSharedSet.setCampaignId(campaignId);
campaignSharedSet.setSharedSetId(sharedSetId);

CampaignSharedSetOperation operation = new CampaignSharedSetOperation();
operation.setOperator(Operator.ADD);
operation.setOperand(campaignSharedSet);

CampaignSharedSetReturnValue retval = campaignSharedSetService.mutate(
    new CampaignSharedSetOperation[] {operation});
for (CampaignSharedSet attachedCampaignSharedSet : retval.value) {
  System.out.println("Attached shared set with id = " +
      attachedCampaignSharedSet.getSharedSetId() + " to campaign id " +
      attachedCampaignSharedSet.getCampaignId() + ".");
}

如下所示,您可以使用 CampaignSharedSetService.get() 方法获取已应用于现有广告系列的共享集。

// Create the selector.
Selector selector = new Selector();
selector.setFields(new String[] {"SharedSetId", "CampaignId", "SharedSetName",
   "SharedSetType", "Status"});

// Filter your results by specific campaign id.
Predicate predicate = new Predicate();
predicate.setField("CampaignId");
predicate.setOperator(PredicateOperator.EQUALS);
predicate.setValues(new String[] {campaignId.toString()});

// Filter your results by the type of shared set.
Predicate predicate1 = new Predicate();
predicate1.setField("SharedSetType");
predicate1.setOperator(PredicateOperator.IN);
predicate1.setValues(new String[] {"NEGATIVE_KEYWORDS", "NEGATIVE_PLACEMENTS"});

selector.setPredicates(new Predicate[] {predicate});

CampaignSharedSetPage page = campaignSharedSetService.get(selector);
if (page.getEntries() != null) {
  for (CampaignSharedSet campaignSharedSet : page.getEntries()) {
    System.out.println("Shared set with id = " + campaignSharedSet.getSharedSetId() +
        ", name = " + campaignSharedSet.getSharedSetName() + ", type = " +
        campaignSharedSet.getSharedSetType() + " and status = " +
        campaignSharedSet.getStatus() + " was found.");
    }
  }
}

报告

使用共享集报告获取共享集的报告数据。使用广告系列共享集报告获取广告系列共享集的报告数据。共享集条件报告提供共享集条件的可下载快照。

发送以下问题的反馈:

此网页
AdWords API
AdWords API
需要帮助?请访问我们的支持页面