Did-you-mean

Did-you-mean建议器用于显示拼写错误的搜索词的纠正建议。

例如,如果用户输入“fliud”,UDB-SX 会建议一个纠正后的搜索词,如“fluid”。然后,您可以将纠正后的词条建议给用户,甚至自动更正搜索词。

您可以使用以下方法之一实现 Did-you-mean 建议器:

词条建议器

使用词条建议器为单个单词提供拼写纠正建议。 词条建议器使用编辑距离来计算建议。

编辑距离是指将一个词条匹配到另一个词条所需进行的单字符插入、删除或替换的次数。例如,要将单词“cat”改为“hats”,需要将“c”替换为“h”并插入“s”,因此此情况下的编辑距离为 2。

要使用词条建议器,您的索引不需要任何特殊的字段映射。默认情况下,字符串字段类型被映射为 texttext 字段会被分析,因此以下示例中的 title 会被分词为单个单词。索引以下文档会创建一个 books 索引,其中 title 是一个 text 字段:

PUT books/_doc/1
{
  "title": "Design Patterns (Object-Oriented Software)"
}

PUT books/_doc/2
{
  "title": "Software Architecture Patterns Explained"
}

要检查字符串如何被拆分为词元,可以使用 _analyze 端点。要应用字段使用的相同分析器,可以在 field 参数中指定字段名:

GET books/_analyze
{
  "text": "Design Patterns (Object-Oriented Software)",
  "field": "title"
}

默认分析器(standard)会在单词边界处分割字符串,移除标点符号,并将词元转换为小写:

{
  "tokens" : [
    {
      "token" : "design",
      "start_offset" : 0,
      "end_offset" : 6,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "patterns",
      "start_offset" : 7,
      "end_offset" : 15,
      "type" : "<ALPHANUM>",
      "position" : 1
    },
    {
      "token" : "object",
      "start_offset" : 17,
      "end_offset" : 23,
      "type" : "<ALPHANUM>",
      "position" : 2
    },
    {
      "token" : "oriented",
      "start_offset" : 24,
      "end_offset" : 32,
      "type" : "<ALPHANUM>",
      "position" : 3
    },
    {
      "token" : "software",
      "start_offset" : 33,
      "end_offset" : 41,
      "type" : "<ALPHANUM>",
      "position" : 4
    }
  ]
}

要获取拼写错误的搜索词的建议,请使用词条建议器。在 text 字段中指定需要建议的输入文本,并在 field 字段中指定从哪个字段获取建议:

GET books/_search
{
  "suggest": {
    "spell-check": {
      "text": "patern",
      "term": {
        "field": "title"
      }
    }
  }
}

词条建议器在 options 数组中返回输入文本的纠正建议列表:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "suggest" : {
    "spell-check" : [
      {
        "text" : "patern",
        "offset" : 0,
        "length" : 6,
        "options" : [
          {
            "text" : "patterns",
            "score" : 0.6666666,
            "freq" : 2
          }
        ]
      }
    ]
  }
}

score 值是根据编辑距离计算的。分数越高,建议越好。freq 是表示该词条在指定索引文档中出现次数的频率。

您可以在一个请求中包含多个建议。以下示例使用词条建议器提供两种不同的建议:

GET books/_search
{
  "suggest": {
    "spell-check1" : {
      "text" : "patern",
      "term" : {
        "field" : "title"
      }
    },
    "spell-check2" : {
      "text" : "desing",
      "term" : {
        "field" : "title"
      }
    }
  }
}

要针对同一输入文本从多个字段接收建议,可以全局定义文本以避免重复:

GET books/_search
{
  "suggest": {
    "text" : "patern",
    "spell-check1" : {
      "term" : {
        "field" : "title"
      }
    },
    "spell-check2" : {
      "term" : {
        "field" : "subject"
      }
    }
  }
}

如果 text 在全局和单个建议级别都有指定,建议级别的值会覆盖全局值。

词条建议器选项

您可以为词条建议器指定以下选项。

选项 描述
field 从中获取建议的字段。必需。可以为每个建议或全局设置。
analyzer 用于分析输入文本的分析器。默认为为 field 配置的分析器。
size 为输入文本中的每个词元返回的建议的最大数量。
sort 指定响应中建议的排序方式。有效值为:
- score:按相似度分数排序,然后按文档频率,最后按词条本身。
- frequency:按文档频率排序,然后按相似度分数,最后按词条本身。
suggest_mode 建议模式指定哪些词条的建议应包含在响应中。有效值为:
- missing:仅返回索引中不存在的输入文本词条的建议。
- popular:仅当建议在文档中出现的频率高于原始输入文本时才返回建议。
- always:始终为输入文本中的每个词条返回建议。
默认为 missing
max_edits 建议的最大编辑距离。有效值在 [1, 2] 范围内。默认值为 2。
prefix_length 一个整数,指定匹配前缀必须达到的最小长度才能开始返回建议。如果 prefix_length 的前缀不匹配,但搜索词仍在编辑距离内,则不返回建议。默认值为 1。较高的值可以提高拼写检查性能,因为拼写错误通常不会出现在单词的开头。
min_word_length 建议必须达到的最小长度才能包含在响应中。默认值为 4。
shard_size 从每个分片获取的候选建议的最大数量。考虑所有候选建议后,返回前 shard_size 条建议。默认值等于 size 值。分片级别的文档频率可能不精确,因为词条可能位于不同的分片中。如果 shard_size 大于 size,建议的文档频率会更准确,但会降低性能。
max_inspections shard_size 的乘法因子。UDB-SX 为查找建议而检查的候选建议的最大数量计算为 shard_size 乘以 max_inspection。可能会提高准确性,但会降低性能。默认值为 5。
min_doc_freq 建议应出现的最小文档数量或百分比才能被返回。通过仅返回具有高分片级文档频率的建议,可以提高准确性。有效值可以是代表文档频率的整数,也可以是代表文档百分比的 [0, 1] 范围内的浮点数。默认值为 0(功能禁用)。
max_term_freq 建议应出现的最大文档数量才能被返回。有效值可以是代表文档频率的整数,也可以是代表文档百分比的 [0, 1] 范围内的浮点数。默认值为 0.01。排除高频词可以提高拼写检查性能,因为高频词通常拼写正确。使用分片级文档频率。
string_distance 用于确定相似性的编辑距离算法。有效值为:
- internal:基于 Damerau-Levenshtein 算法的默认算法,但高度优化,用于比较索引中词条的编辑距离。
- damerau_levenshtein:基于 Damerau-Levenshtein 算法的编辑距离算法。
- levenshtein:基于 Levenshtein 编辑距离算法的编辑距离算法。
- jaro_winkler:基于 Jaro-Winkler 算法的编辑距离算法。
- ngram:基于字符 N 元语法的编辑距离算法。

短语建议器

要实现 Did-you-mean 功能,请使用短语建议器。 短语建议器类似于词条建议器,不同之处在于它使用 N 元语法语言模型来建议整个短语,而不是单个单词。

要设置短语建议器,请创建一个名为 trigram 的自定义分析器,它使用 shingle 过滤器并小写词元。此过滤器类似于 edge_ngram 过滤器,但它应用于单词而不是字母。然后,使用您创建的自定义分析器配置您将从中获取建议的字段:

PUT books2
{
  "settings": {
    "index": {
      "analysis": {
        "analyzer": {
          "trigram": {
            "type": "custom",
            "tokenizer": "standard",
            "filter": [
              "lowercase",
              "shingle"
            ]
          }
        },
        "filter": {
          "shingle": {
            "type": "shingle",
            "min_shingle_size": 2,
            "max_shingle_size": 3
          }
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "fields": {
          "trigram": {
            "type": "text",
            "analyzer": "trigram"
          }
        }
      }
    }
  }
}

将文档索引到新索引中:

PUT books2/_doc/1
{
  "title": "Design Patterns"
}

PUT books2/_doc/2
{
  "title": "Software Architecture Patterns Explained"
}

假设用户搜索一个不正确的短语:

GET books2/_search
{
  "suggest": {
    "phrase-check": {
      "text": "design paterns",
      "phrase": {
        "field": "title.trigram"
      }
    }
  }
}

短语建议器返回纠正后的短语:

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "suggest" : {
    "phrase-check" : [
      {
        "text" : "design paterns",
        "offset" : 0,
        "length" : 14,
        "options" : [
          {
            "text" : "design patterns",
            "score" : 0.31666178
          }
        ]
      }
    ]
  }
}

要高亮显示建议,请为短语建议器设置 highlight 字段:

GET books2/_search
{
  "suggest": {
    "phrase-check": {
      "text": "design paterns",
      "phrase": {
        "field": "title.trigram",
        "gram_size": 3,
        "highlight": {
          "pre_tag": "<em>",
          "post_tag": "</em>"
        }
      }
    }
  }
}

结果包含高亮显示的文本:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "suggest" : {
    "phrase-check" : [
      {
        "text" : "design paterns",
        "offset" : 0,
        "length" : 14,
        "options" : [
          {
            "text" : "design patterns",
            "highlighted" : "design <em>patterns</em>",
            "score" : 0.31666178
          }
        ]
      }
    ]
  }
}

短语建议器选项

您可以为短语建议器指定以下选项。

选项 描述
field 用于 N 元语法查找的字段。短语建议器使用此字段计算建议分数。必需。
gram_size 字段中 N 元语法(shingles)的最大大小 n。如果字段不包含 N 元语法(shingles),请省略此选项或将其设置为 1。如果字段使用 shingle 过滤器,且未设置 gram_size,则 gram_size 设置为 max_shingle_size
real_word_error_likelihood 即使一个词条存在于词典中,它被拼写错误的概率。默认值为 0.95(词典中 5% 的单词拼写错误)。
confidence 置信度是一个浮点数因子,乘以输入短语的分数,以计算其他建议的阈值分数。仅返回分数高于阈值的建议。置信度为 1.0 将仅返回分数高于输入短语的建议。如果将 confidence 设置为 0,则返回前 size 个候选建议。默认值为 1。
max_errors 可以返回建议的错误(拼写不正确)词条的最大数量或百分比。有效值可以是代表词条数量的整数,也可以是代表词条百分比的 (0, 1) 范围内的浮点数。默认值为 1(仅返回最多有一个拼写错误词条的建议)。将此值设置为较高的数字可能会降低性能。我们建议将 max_errors 设置为较低的数字,如 1 或 2,以减少建议调用相对于查询执行所花费的时间。
separator 二元语法字段中词条的分隔符。默认为空格字符。
size 为每个查询词元生成的候选建议数量。指定较高的值可能导致返回编辑距离较大的词条。默认值为 5。
analyzer 用于分析建议文本的分析器。默认为为 field 配置的分析器。
shard_size 从每个分片获取的候选建议的最大数量。考虑所有候选建议后,返回前 shard_size 条建议。默认值为 5。
collate 用于剪枝那些在索引中没有匹配文档的建议。
collate.query 指定一个查询,用于检查建议,以剪枝那些在索引中没有匹配文档的建议。
collate.prune 指定是否返回所有建议。如果 prune 设置为 false,则仅返回那些有匹配文档的建议。如果 prune 设置为 true,则返回所有建议;每个建议都有一个额外的 collate_match 字段,如果该建议有匹配文档,则为 true,否则为 false。默认为 false
highlight 配置建议高亮显示。pre_tagpost_tag 值都是必需的。
highlight.pre_tag 高亮显示的起始标签。
highlight.post_tag 高亮显示的结束标签。
smoothing 平滑模型,用于平衡索引中频繁出现的 shingles 的权重与索引中不频繁出现的 shingles 的权重。

Collate字段

要过滤掉那些不会返回任何结果的拼写检查建议,您可以使用 collate 字段。此字段包含一个脚本化查询,该查询针对每个返回的建议运行。有关构建模板化查询的信息,请参阅搜索模板。您可以使用 {% raw %}{{suggestion}}{% endraw %} 变量指定当前建议,也可以在 params 字段中传递您自己的模板参数(建议值将被添加到您指定的变量中)。

建议的 collate 查询仅在建议来源的分片上运行。查询是必需的。

此外,如果 prune 参数设置为 true,则每个建议都会添加一个 collate_match 字段。如果查询没有返回结果,collate_match 值为 false。然后,您可以根据 collate_match 字段过滤建议。prune 参数的默认值为 false

例如,以下查询配置 collate 字段以运行 match_phrase 查询,将 title 字段与当前建议进行匹配:

GET books2/_search
{
  "suggest": {
    "phrase-check": {
      "text": "design paterns",
      "phrase": {
        "field": "title.trigram",
        "collate" : {
          "query" : {
            "source": {
              "match_phrase" : {
                "title": "{{suggestion}}"
              }
            }
          },
          "prune": "true"
        }
      }
    }
  }
}

结果建议包含 collate_match 字段设置为 true,这意味着 match_phrase 查询将返回该建议的匹配文档:

{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "suggest" : {
    "phrase-check" : [
      {
        "text" : "design paterns",
        "offset" : 0,
        "length" : 14,
        "options" : [
          {
            "text" : "design patterns",
            "score" : 0.56759655,
            "collate_match" : true
          }
        ]
      }
    ]
  }
}

平滑模型

对于大多数用例,在计算建议分数时,您不仅要考虑 shingle 的频率,还要考虑 shingle 的大小。平滑模型用于计算不同大小的 shingles 的分数,以平衡频繁和不频繁 shingles 的权重。

支持以下平滑模型。

模型 描述
stupid_backoff 如果高阶 N 元语法计数为 0,则回退到低阶 N 元语法模型,并将低阶 N 元语法模型乘以一个常数因子(discount)。这是默认的平滑模型。
stupid.backoff.discount 低阶 N 元语法模型乘以的因子。可选。默认值为 0.4。
laplace 使用加性平滑,向所有计数添加一个常数 alpha 以平衡权重。
laplace.alpha 为平衡权重而添加到所有计数中的常数,通常为 1.0 或更小。可选。默认值为 0.5。

默认情况下,UDB-SX 使用 Stupid Backoff 模型—这是一种简单的算法,从最高阶的 shingles 开始,如果未找到更高阶的 shingles,则使用较低阶的 shingles。例如,如果您设置短语建议器具有 3-gram、2-gram 和 1-gram,Stupid Backoff 模型首先检查 3-gram。如果没有 3-gram,则检查 2-gram,但将分数乘以 discount 因子。如果没有 2-gram,则检查 1-gram,但再次将分数乘以 discount 因子。Stupid Backoff 模型在大多数情况下效果良好。如果您需要选择 Laplace 平滑模型,请在 smoothing 参数中指定:

GET books2/_search
{
  "suggest": {
    "phrase-check": {
      "text": "design paterns",
      "phrase": {
        "field": "title.trigram",
        "size" : 1,
        "smoothing" : {
          "laplace" : {
            "alpha" : 0.7
          }
        }
      }
    }
  }
}

候选生成器

候选生成器根据输入文本中的词条提供可能的建议词条。有一个候选生成器可用—direct_generator。直接生成器的功能类似于词条建议器:它也为输入文本中的每个词条调用。短语建议器支持多个候选生成器,其中每个生成器为输入文本中的每个词条调用。它还允许您指定一个预过滤器(在拼写检查阶段之前分析输入文本词条的分析器)和一个后过滤器(在返回之前分析生成建议的分析器)。

为短语建议器设置直接生成器:

GET books2/_search
{
  "suggest": {
    "text": "design paterns",
    "phrase-check": {
      "phrase": {
        "field": "title.trigram",
        "size": 1,
        "direct_generator": [
          {
            "field": "title.trigram",
            "suggest_mode": "always",
            "min_word_length": 3
          }
        ]
      }
    }
  }
}

您可以指定以下直接生成器选项。

选项 描述
field 从中获取建议的字段。必需。可以为每个建议或全局设置。
size 为输入文本中的每个词元返回的建议的最大数量。
suggest_mode 建议模式指定每个分片上生成的哪些建议应包含在内。建议模式应用于每个分片的建议,并且在合并来自不同分片的建议时不检查。因此,如果建议模式是 missing,则当词条在一个分片中缺失但在另一个分片中存在时,将返回建议。有效值为:
- missing:仅返回分片中不存在的输入文本词条的建议。
- popular:仅当建议在文档中出现的频率高于分片上的原始输入文本时才返回建议。
- always:始终返回建议。
默认为 missing
max_edits 建议的最大编辑距离。有效值在 [1, 2] 范围内。默认值为 2。
prefix_length 一个整数,指定匹配前缀必须达到的最小长度才能开始返回建议。如果 prefix_length 的前缀不匹配,但搜索词仍在编辑距离内,则不返回建议。默认值为 1。较高的值可以提高拼写检查性能,因为拼写错误通常不会出现在单词的开头。
min_word_length 建议必须达到的最小长度才能包含在内。默认值为 4。
max_inspections shard_size 的乘法因子。UDB-SX 为查找建议而检查的候选建议的最大数量计算为 shard_size 乘以 max_inspection。可能会提高准确性,但会降低性能。默认值为 5。
min_doc_freq 建议应出现的最小文档数量或百分比才能被返回。通过仅返回具有高分片级文档频率的建议,可以提高准确性。有效值可以是代表文档频率的整数,也可以是代表文档百分比的 [0, 1] 范围内的浮点数。默认值为 0(功能禁用)。
max_term_freq 建议应出现的最大文档数量才能被返回。有效值可以是代表文档频率的整数,也可以是代表文档百分比的 [0, 1] 范围内的浮点数。默认值为 0.01。排除高频词可以提高拼写检查性能,因为高频词通常拼写正确。使用分片级文档频率。
pre_filter 在生成建议之前应用于传递给生成器的每个输入文本词元的分析器。
post_filter 在传递给短语评分器之前应用于每个生成建议的分析器。