ElasticSearch 分词器解析

365 阅读6分钟

什么是分词器?

顾名思义,文本分析就是把全文本转换成一系列单词(term/token)的过程,也叫分词。在 ES 中,Analysis 是通过分词器(Analyzer) 来实现的,可使用 ES 内置的分析器或者按需定制化分析器。

他有什么功能?可以做什么?

分词器的主要作用将用户输入的一段文本,按照一定逻辑,分析成多个词语的一种工具。 举一个分词简单的例子:比如你输入 Mastering Elasticsearch,会自动帮你分成两个单词,一个是 mastering,另一个是 elasticsearch,可以看出单词也被转化成了小写的。

1700637435708.png

Analyzer

Elasticsearch 可以实现秒级的搜索速度,其中很重要的一个原因就当一个文档被存储的时候,同时它也对文档的数据进行了索引(indexing)。这样在以后的搜索中,就可以变得很快。简单地说,当一个文档进入到 Elasticsearch 时,它会经历如下的步骤:

1700654354634.png

中间的那部分就叫做 Analyzer。我们可以看出来,它分为三个部分:Char Filters, Tokenizer 及 Token Filters。

下图显示了一个解释分析过程的示例。

1700654621418.png 它们的作用分别如下:

Char Filters(字符过滤器): 字符过滤器的工作是执行清除任务,将原始文本作为字符流接收,并可以通过添加、删除或更改字符来转换流。例如剥离 HTML 标记,词项处理将印度-阿拉伯数字 (٠ ١٢٣٤٥٦٧٨ ٩ ) 转换为阿拉伯-拉丁语等价物 (0123456789)等。分词器可能有零个或多个字符过滤器,它们按顺序应用

Tokenizer(分词器): 接收字符流,将其分解为单独的 tokens(通常是单个单词),并输出 tokens 流。 例如,whitespace 分词器在看到任何空格时将文本分解为tokens。 它会将文本“Quick brown fox!”转换为terms[Quick, brown, fox!]。tokenizer分词器还负责记录每个词条的顺序或位置,以及该词条所代表的原始单词的开始和结束字符偏移量。分词器必须具有正好一个 tokenizer。

Token filters(词项过滤器): 一旦创建了 token,它们就会被传递给 token filters,这些过滤器会对 token 进行规范化。 Token filters 可以更改 token,删除术语或向 token 添加术语。

请注意,字符和标记过滤器都是可选的,但我们必须有一个分词器。

一个 analyzer 有且只有一个 tokenizer,有0个或一个以上的 char filter 及 token filter。

在默认的情况下,standard analyzer 是 Elasticsearch 的缺省分析器:

  • 没有 Char Filter
  • 使用 standard tokonizer
  • 把字符串变为小写,同时有选择地删除一些 stop words 等。默认的情况下 stop words 为 none,也即不过滤任何 stop words。

Elasticsearch 已经提供了比较丰富的 analyzer。我们可以自己创建自己的 token analyzer,甚至可以利用已经有的 char filters,tokenizer 及 token filters 来重新组合成一个新的 analyzer,并可以对文档中的每一个字段分别定义自己的 analyzer。

自带分词器

分析器描述分词对象
standard标准分析器是默认的分析器,如果没有指定,则使用该分析器。它提供了基于文法的标记化(基于 Unicode 文本分割算法,如 Unicode 标准附件 # 29所规定) ,并且对大多数语言都有效。The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone.
simple简单分析器将文本分解为任何非字母字符的标记,如数字、空格、连字符和撇号、放弃非字母字符,并将大写字母更改为小写字母。The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone.
whitespace空格分析器在遇到空白字符时将文本分解为术语The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone.
stop停止分析器与简单分析器相同,但增加了删除停止字的支持。默认使用的是 english 停止词。The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone.
keyword不分词,把整个字段当做一个整体返回The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone.
pattern模式分析器使用正则表达式将文本拆分为术语。正则表达式应该匹配令牌分隔符,而不是令牌本身。正则表达式默认为 w+ (或所有非单词字符)。The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone.
ik_smartk分词器中的简单分词器,支持自定义字典,远程字典学如逆水行舟,不进则退
ik_max_wordik_分词器的全量分词器,支持自定义字典,远程字典学如逆水行舟,不进则退

索引和搜索分词

analyzer 执行将输入字符流分解为token的过程,它一般发生在两个场合:

  • 在 indexing 的时候,也即在建立索引的时候,默认会索引时分词
  • 在 searching 的时候,也即在搜索时,分析需要搜索的词语,需要指定search_analyzer字段

样例:

索引数据时分词:
PUT my_index
{
    "mappings": {
        "properties": {
            "title": {
                "type": "text",
                "analyzer": "whitespace"
            }
        }
    }
}

搜索时分词
PUT my_index2
{
    "mappings": {
        "properties": {
            "title": {
                "type": "text",
                "analyzer": "whitespace",
                "search_analyzer": "simple"
            }
        }
    }
}

测试分词

如何自定义分词器

参数描述
tokenizer内置或定制的tokenizer.(必须)
char_filter内置或定制的char_filter(非必须)
filter内置或定制的token filter(非必须)
position_increment_gap当值为文本数组时,设置改值会在文本的中间插入假空隙。设置该属性,对与后面的查询会有影响。默认该值为100.

样例:

PUT my_index
{
    "settings": {
        "analysis": {
            "analyzer": {
                "my_custom_analyzer": {
                    "type": "custom",
                    "tokenizer": "standard",
                    "char_filter": [
                        "html_strip"
                    ],
                    "filter": [
                        "lowercase"
                    ]
                }
            }
        }
    }
}

该分词器的type为custom,tokenizer为standard,char_filter为hmtl_strip,filter定义了两个分别为:lowercase和asciifolding。这个分词器的主要作用就是过滤html标签,转成文本存起来 1700656780292.png

定义复杂分词器

PUT /ablogs
{
    "settings": {
        "index": {
            "number_of_shards": "1",           # 索引的主分片数,默认值是 51024"number_of_replicas": "1",         # 索引主分片的副本数,默认值是 1"provided_name": "article_news_2019-01",  
      # 执行新索引数据的刷新操作频率
      "refresh_interval": "60s",
            "analysis": {
          #定制化分析器
        "analyzer": {
            #自定义分析器名称
          "my_custom_analyzer": {
                        "type": "custom",
                        "char_filter": [
                            "xgame_filter"
                        ],
                        "tokenizer": "standard",
                        "filter": [
                            "lowercase",
                            "my_stop"
                        ]
                    }
                },
        #自定义char_filter实现
        "char_filter": {
                    "xgame_filter": {
                        "type": "mapping",
                        "mappings": [
                            "X-Game => XGame"
                        ]
                    }
                },
        #自定义filter实现
        "filter": {
                    "my_stop": {
                        "type": "stop",
                        "stopwords": [
                            "so",
                            "to",
                            "the"
                        ]
                    }
                }
            }
        }
    },
  #定义mapping
"mappings": {
      #索引的type
    "_doc": {
            "properties": {
                "content": {
                    "type": "text",
          #指定分析器
          "analyzer": "my_custom_analyzer"
          #指定查询分析器
           "search_analyzer": "standard"
                }
            }
        }
    }
}