Unicode的世界

edit

当Elasticsearch在比较词元(token)的时候,它是进行字节(byte)级别的比较。 换句话说,如果两个词元(token)被判定为相同的话,他们必须是相同的字节(byte)组成的。然而,Unicode允许你用不同的字节来写相同的字符。

例如, é 的不同是什么?这取决于你问谁。对于Elasticsearch,第一个是由 0xC3 0xA9 这两个字节组成的,第二个是由 0x65 0xCC 0x81 这三个字节组成的。

对于Unicode,他们的差异和他们的怎么组成没有关系,所以他们是相同的。第一个是单个单词 é ,第二个是一个简单 e 和重音符 ´

如果你的数据有多个来源,就会有可能发生这种状况:因为相同的单词使用了不同的编码,导致一个形式的 déjà 不能和它的其他形式进行匹配。

幸运的是,这里就有解决办法。这里有4种Unicode 归一化形式 (normalization forms) : nfc, nfd, nfkc, nfkd,它们都把Unicode字符转换成对应标准格式,把所有的字符 进行字节(byte)级别的比较。

无论你选择哪一个归一化(normalization)模式,只要你的文本只用一种模式,那你的同一个词元(token)就会由相同的字节(byte)组成。例如,兼容 (compatibility) 模式 可以用连词 的简化形式 `ffi`来进行对比。

你可以使用 icu_normalizer 语汇单元过滤器(token filters) 来保证你的所有词元(token)是相同模式:

PUT /my_index
{
  "settings": {
    "analysis": {
      "filter": {
        "nfkc_normalizer": { 
          "type": "icu_normalizer",
          "name": "nfkc"
        }
      },
      "analyzer": {
        "my_normalizer": {
          "tokenizer": "icu_tokenizer",
          "filter":  [ "nfkc_normalizer" ]
        }
      }
    }
  }
}

nfkc 归一化(normalization)模式来归一化(Normalize)所有词元(token).

包括刚才提到过的 icu_normalizer 语汇单元过滤器(token filters)在内,这里还有 icu_normalizer 字符 过滤器(character filters)。虽然它和语汇单元过滤器做相同的工作,但是会在文本到达过滤器之前做。到底是用`standard` 过滤器,还是 icu_tokenizer 过滤器,其实并不重要。因为过滤器知道怎么来正确处理所有的模式。

但是,如果你使用不同的分词器,例如: ngram, edge_ngram, 或者 pattern 分词器,那么在语汇单元过滤器(token filters)之前使用 icu_normalizer 字符过滤器就变得有意义了。

通常来说,你不仅仅想要归一化(normalize)词元(token)的字节(byte)规则,还需要把他们转成小写字母。这个可以通过 icu_normalizer 和定制的归一化(normalization)的模式 nfkc_cf 来实现。下一节我们会具体讲这个。