如果有口音

英语用变音符号(例如 ´, ^, 和 ¨) 来强调单词—​例如 rôle, déjà, 和 däis —​但是是否使用他们通常是可选的. 其他语言则通过变音符号来区分单词。当然,只是因为在你的索引中拼写正确的单词并不意味着用户将搜索正确的拼写。 去掉变音符号通常是有用的,让 rôle 对应 role, 或者反过来。 对于西方语言,可以用 asciifolding 字符过滤器来实现这个功能。 实际上,它不仅仅能去掉变音符号。它会把Unicode字符转化为ASCII来表示:

  • ßss
  • æae
  • łl
  • ɰm
  • ??
  • 2
  • 6

lowercase 过滤器一样, asciifolding 不需要任何配置,可以被 custom 分析器直接使用:

PUT /my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "folding": {
          "tokenizer": "standard",
          "filter":  [ "lowercase", "asciifolding" ]
        }
      }
    }
  }
}

GET /my_index?analyzer=folding
My œsophagus caused a débâcle 

得到的词元 my, oesophagus, caused, a, debacle

保留原意

理所当然的,去掉变音符号会丢失原意。 例如, 参考 这三个 西班牙单词:

esta
形容词 this 的阴性形式, 例如 esta silla (this chair) 和 esta (this one).
ésta
esta 的古代用法.
está
动词 estar (to be) 的第三人称形式, 例如 está feliz (he is happy).

通常我们会合并前两个形式的单词,而去区分和他们不相同的第三个形式的单词。类似的:

动词 saber (to know) 的第一人称形式 例如 Yo sé (I know).
se
与许多动词使用的第三人称反身代词, 例如 se sabe (it is known).

不幸的是,没有简单的方法,去区分哪些词应该保留变音符号和哪些词应该去掉变音符号。而且很有可能,你的用户也不知道.

相反, 我们对文本做两次索引: 一次用原文形式,一次用去掉变音符号的形式 :

PUT /my_index/_mapping/my_type
{
  "properties": {
    "title": { 
      "type":           "string",
      "analyzer":       "standard",
      "fields": {
        "folded": { 
          "type":       "string",
          "analyzer":   "folding"
        }
      }
    }
  }
}

title 字段用 standard 分析器,会保留原文的变音符号.

title.folded 字段用 folding 分析器,会去掉变音符号

你可以使用 analyze API 分析 Esta está loca (This woman is crazy)这个句子,来验证字段映射:

GET /my_index/_analyze?field=title 
Esta está loca

GET /my_index/_analyze?field=title.folded 
Esta está loca

得到的词元 esta, está, loca

得到的词元 esta, esta, loca

可以用更多的文档来测试:

PUT /my_index/my_type/1
{ "title": "Esta loca!" }

PUT /my_index/my_type/2
{ "title": "Está loca!" }

现在,我们可以通过联合所有的字段来搜索。在multi_match`查询中通过 <<most-fields,`most_fields mode>> 模式来联合所有字段的结果:

GET /my_index/_search
{
  "query": {
    "multi_match": {
      "type":     "most_fields",
      "query":    "esta loca",
      "fields": [ "title", "title.folded" ]
    }
  }
}

通过 validate-query API 来执行这个查询可以帮助你理解查询是如何执行的:

GET /my_index/_validate/query?explain
{
  "query": {
    "multi_match": {
      "type":     "most_fields",
      "query":    "está loca",
      "fields": [ "title", "title.folded" ]
    }
  }
}

multi-match 查询会搜索在 title 字段中原文形式的单词 (está),和在 title.folded 字段中去掉变音符号形式的单词 esta:

(title:está        title:loca       )
(title.folded:esta title.folded:loca)

无论用户搜索的是 esta 还是 está; 两个文档都会被匹配,因为去掉变音符号形式的单词在 title.folded 字段中。然而,只有原文形式的单词在 title 字段中。此额外匹配会把包含原文形式单词的文档排在结果列表前面。

我们用 title.folded 字段来 扩大我们的网 (widen the net)来匹配更多的文档,然后用原文形式的 title 字段来把关联度最高的文档排在最前面。在可以为了匹配数量牺牲文本原意的情况下,这个技术可以被用在任何分析器里。

Tip

asciifolding 过滤器有一个叫做 preserve_original 的选项可以让你这样来做索引 ,把词的原文词元(original token)和处理--折叠后的词元(folded token)放在同一个字段的同一个位置。开启了这个选项,结果会像这样:

Position 1     Position 2
--------------------------
(ésta,esta)    loca
--------------------------

虽然这个是节约空间的好办法,但是也意味着没有办法再说“给我精确匹配的原文词元”(Give me an exact match on the original word)。包含去掉和不去掉变音符号的词元,会导致不可靠的相关性评分。

所以,正如我们这一章做的,把每个字段的不同形式分开到不同的字段会让索引更清晰。