Elasticsearch 分词器

在全文搜索(Fulltext Search)中,词(Term)是一个搜索单元,表示文本中的一个词,标记(Token)表示在文本字段中出现的词,由词的文本、在原始文本中的开始和结束偏移量、以及数据类型等组成。ElasticSearch 把文档数据写到倒排索引(Inverted Index)的结构中,倒排索引建立词(Term)和文档之间的映射,索引中的数据是面向词,而不是面向文档的。分析器(Analyzer)的作用就是分析(Analyse),用于把传入Lucene的文档数据转化为倒排索引,把文本处理成可被搜索的词。

  在ElasticSearch引擎中,分析器的任务是分析(Analyze)文本数据,分析是分词,规范化文本的意思,其工作流程是:


   1. 首先,字符过滤器对分析(analyzed)文本进行过滤和处理,例如从原始文本中移除HTML标记,根据字符映射替换文本等,

   2. 过滤之后的文本被分词器接收,分词器把文本分割成标记流,也就是一个接一个的标记,

   3. 然后,标记过滤器对标记流进行过滤处理,例如,移除停用词,把词转换成其词干形式,把词转换成其同义词等,

   4. 最终,过滤之后的标记流被存储在倒排索引中;

   5. ElasticSearch引擎在收到用户的查询请求时,会使用分析器对查询条件进行分析,根据分析的结构,重新构造查询,以搜索倒排索引,完成全文搜索请求。


无论是内置的分析器(analyzer),还是自定义的分析器(analyzer),都由三种构件块组成的:character filters tokenizers token filters


  • character filters 

    字符过滤器以字符流的形式接收原始文本,并可以通过添加、删除或更改字符来转换该流。

    举例来说,一个字符过滤器可以用来把阿拉伯数字(٠‎١٢٣٤٥٦٧٨‎٩)‎转成成Arabic-Latin的等价物(0123456789)。

    一个分析器可能有0个或多个字符过滤器,它们按顺序应用。

  • Tokenizer (分词器)

    一个分词器接收一个字符流,并将其拆分成单个token (通常是单个单词),并输出一个token流。例如,一个whitespace分词器当它看到空白的时候就会将文本拆分成token。它会将文本“Quick brown fox!”转换为[Quick, brown, fox!]

    (PS:Tokenizer 负责将文本拆分成单个token ,这里token就指的就是一个一个的单词。就是一段文本被分割成好几部分 )

    分词器还负责记录每个term的顺序或位置,以及该term所表示的原单词的开始和结束字符偏移量。(PS:文本被分词后的输出是一个term数组)

    一个分析器必须只能有一个分词器

  • Token filters (token过滤器)

    token过滤器接收token流,并且可能会添加、删除或更改tokens。

    例如,一个lowercase token filter可以将所有的token转成小写。stop token filter可以删除常用的单词,比如 the 。synonym token filter可以将同义词引入token流。

    不允许token过滤器更改每个token的位置或字符偏移量。

    一个分析器可能有0个或多个token过滤器,它们按顺序应用。


ES内置分词器(Tokenizer)

分词器在字符过滤器之后工作,用于把文本分割成多个标记(Token),一个标记基本上是词加上一些额外信息,分词器的处理结果是标记流,它是一个接一个的标记,准备被过滤器处理。

  • 标准分析器(Standard)

    分析器类型是standard,由标准分词器(Standard Tokenizer),标准标记过滤器(Standard Token Filter),小写标记过滤器(Lower Case     Token Filter)和停用词标记过滤器(Stopwords Token Filter)组成。参数stopwords用于初始化停用词列表,默认是空的。

  • 简单分析器(Simple)

    分析器类型是simple,实际上是小写标记分词器(Lower Case Tokenizer),在非字母位置上分割文本,并把分词转换为小写形式,功能上是Letter Tokenizer和 Lower Case Token Filter的结合(Combination),但是性能更高,一次性完成两个任务。

  •  空格分析器(Whitespace)

    分析器类型是whitespace,实际上是空格分词器(Whitespace Tokenizer)。

  • 停用词分析器(Stopwords)

    分析器类型是stop,由小写分词器(Lower Case Tokenizer)和停用词标记过滤器(Stop Token Filter)构成,配置参数stopwords或    stopwords_path指定停用词列表。

  • 雪球分析器(Snowball)

    分析器类型是snowball,由标准分词器(Standard Tokenizer),标准过滤器(Standard Filter),小写过滤器(Lowercase Filter),停用词过滤器(Stop Filter)和雪球过滤器(Snowball Filter)构成。参数language用于指定语言。

  • 自定义分析器

    分析器类型是custom,允许用户定制分析器。参数tokenizer 用于指定分词器,filter用于指定过滤器,char_filter用于指定字符过滤器。



内置分析器实例

这里我们使用的工具是Kibana,我们在这里来操作一下Elasticsearch。如下的事例是ES默认的标准分析器,我们使用_analyze来调试实验一下。

POST _analyze
{
  "analyzer": "standard",
  "text": "I am Chinese."
}


输出如下结果:

{
  "tokens" : [
    {
      "token" : "i",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "am",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "<ALPHANUM>",
      "position" : 1
    },
    {
      "token" : "chinese",
      "start_offset" : 5,
      "end_offset" : 12,
      "type" : "<ALPHANUM>",
      "position" : 2
    }
  ]
}


而使用空格分析器的话,就会对每个空格进行分割,如下

POST _analyze
{
  "analyzer": "whitespace",
  "text": "I'm Chinese."
}


输出结果:

{
  "tokens" : [
    {
      "token" : "I'm",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "Chinese.",
      "start_offset" : 4,
      "end_offset" : 12,
      "type" : "word",
      "position" : 1
    }
  ]
}


接下来我们创建一个自定义分析器:

# 创建一个自定义分词器
PUT test_index_1
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_custom_anaylzer" : {
          "type" : "custom",
          "tokenizer" : "standard",
          "char_filter" : ["html_strip"],
          "filter" : ["lowercase"]
        }
      }
    }
  }
}

以上代码是创建一个自定义分析器,其中使用分析器是标准分析器,字符串过滤使用的是html_strip(去除里面的html标签内容),token过滤器用的是lowercase,也就是把取出来的字符都转成小写。运行如下事例。

POST test_index_1/_analyze
{
 "analyzer" : "my_custom_anaylzer",
 "text" : "Is this <b> a box <b>?"
}

输出结果为:

{
 "tokens" : [
   {
     "token" : "is",
     "start_offset" : 0,
     "end_offset" : 2,
     "type" : "<ALPHANUM>",
     "position" : 0
   },
   {
     "token" : "this",
     "start_offset" : 3,
     "end_offset" : 7,
     "type" : "<ALPHANUM>",
     "position" : 1
   },
   {
     "token" : "a",
     "start_offset" : 12,
     "end_offset" : 13,
     "type" : "<ALPHANUM>",
     "position" : 2
   },
   {
     "token" : "box",
     "start_offset" : 14,
     "end_offset" : 17,
     "type" : "<ALPHANUM>",
     "position" : 3
   }
 ]
}


参考

https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-tokenfilters.html

https://github.com/medcl/elasticsearch-analysis-ik

头像
QQ登录: