ElasticSearch核心之——分词

前言

我们知道ElasticSearch(简称ES)底层的搜索使用的是倒排索引依赖于分词器的实现,那么分词器的规则可以如何制定、ES中都提供了哪些常用的分词器给我们去使用呢?本文将围绕分词器的使用和细节进行讲解,希望能够对想要了解ES分词器的小伙伴们一个参考。

一、说在前面的概念

(一)分词

分词是将文本转换成一系列单词的过程,也可以叫做文本分析,在ES中被称为Analysis。其实在日常生活中,分词这个概念我们应该并不陌生,比如我们使用百度/谷歌搜索引擎进行检索的时候,我们常常可以发现,我们输入的一段句子会被分割成不同的关键词关联查询。
以“windows打开控制面板命令”为例子,我们在百度中进行搜索,会发现它被分割为windows控制面板命令等关键字来查询。

(二)分词器

对语句进行分词的前提是定义了分词的规则。ES中为我们提供了许多功能强大、场景丰富的分词器组件,英文是Analyzer,它的组成如下:

  • Character Filter
    -针对原始的文本进行处理,比如去除html标记
  • Tokenizer
    -将原始的文本按照一定的规则切分为单词
  • Token Filter
    -针对tokenizer处理的单词进行再加工,比如转小写、删除或新增等处理

我们可以看到分词器可以由三种组件组成,原始的数据流从Character Filter -> Tokenizer -> Token Filter一路下来,可以一步步地去除多余的数据再进去分割存储(输出)。

二、分词器的API

(一)简单的使用分词器

ES给我们提供了一个测试分词的API接口,方便验证分词效果,在这个API中我们可以指定使用的分词器和索引来源,还可以使用自定义的分词器进行查看。

POST _analyze
{
  "analyzer": "standard",
  "text": [
      "hello es"
    ]
}

执行后结果如下:



上面的例子中,我们使用的是默认的分词器,我们也可以自定义分词器来进行使用

POST _analyze
{
  "tokenizer": "standard",
  "filter": ["lowercase"],
  "text": ["Hello World ElasticSearch"]
}
(二)ES中自带的分词器
1. Standard 标准分词器

Standard是ES的默认分词器,具备按词切分、支持多语言;小写处理等特点。其具体组成如下图:

POST _analyze
{
  "analyzer": "standard",
  "text": ["The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."]
}
2. Simple Analyzer 简单分词器

简单分词器有着按照非字母切分、小写处理的特点,其具体组成如下图:


POST _analyze
{
  "analyzer": "simple",
  "text": ["The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."]
}
3. Whitespace Analyzer 空格分词器

这个分词器很好理解,就是将文本根据空格进行分词。其组成如下图


POST _analyze
{
  "analyzer": "whitespace",
  "text": ["The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."]
}

4. Stop Analyzer 语气助词分词器

Stop Word指的是语气助词等修饰性的词语,比如thean等等,其组成如下图:

POST _analyze
{
  "analyzer": "stop",
  "text": ["The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."]
}
5. Keyword Analyzer 关键字分词器

Keyword分词器是一个比较特殊的存在,它不会对输入的句子进行分词,而是直接将输入作为一个单词输出,也就是说会将输入看成是一个整体。其组成如下:


POST _analyze
{
  "analyzer": "keyword",
  "text": ["The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."]
}
6. Pattern Analyzer 正则分词器

正则分词器很好理解,就是根据我们提供的正则表达式来进行分词,默认会按照 \W+ ,即非字词的符号作为分隔符。其组成如下:

POST _analyze
{
  "analyzer": "pattern",
  "text": ["The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."]
}
7. Langueage Analyzer 多语言分词器

多语言分词器提供了30+种常见语言的分词器
诸如:arabic, armenian, basque, bengali, brazilian, bulgarian, catalan, cjk, czech, danish, dutch, english, estonian, finnish, french, galician, german, greek, hindi, hungarian, indonesian, irish, italian, latvian, lithuanian, norwegian, persian, portuguese, romanian, russian, sorani, spanish, swedish, turkish, thai.
(详细用法可点击具体的语言,通过超链接进入es官网查看)

(三)中文分词器

上述的分词都是基于英文来进行分词的,对于中文而言,并不能完全适用。中文分词是指将一个汉字序列切分成一个个单独的词,在英文中,单词之间是通过空格作为自然分隔符,汉字中没有一个形式上的分词符。
同时,汉字中存在着一词多义,一词多性(可做动词也可做名词),比如:"乒乓 / 球拍 / 卖完了" 和“乒乓球 / 拍卖 / 完了”。同样的一句话可以有多种分词方式,所以中文分词的难度较大,往往需要自己根据实际情况进行定义。常用的中文分词器有 ik分词器jieba分词器。

三、自定义分词器

当ES提供的分词器不能满足我们的分词需要的时候,我们可以通过自定义分词器来满足我们的工作需要,下面我们就从ES分词器的各个组件来进行自定义分词的测试吧。

(一)Character Filter 字符过滤器

我们知道最先到达分词器的组件是Character Filter,他会在 Tokenizer 之前对文本进行处理,比如增加、删除、或替换字符等。
ES中自带的Character Filter有HTML Strip(去除html标签和转换html实体)、Mapping(进行字符替换等操作)、Pattern Replace(进行正则字符替换)。

POST _analyze
{
  "tokenizer": "keyword",
  "char_filter": ["html_strip"],
  "text": ["<p>I&apos;m so <b>happy</b>!</p>"]
}
(二)Tokenizer 字符切分者

Tokenizer会将原始文本(此处是指已经经过char_filter处理过的文本)按照一定的规则切分为单词,自带的Tokenizer如下:

Tokenizer 功能
standard 按照单词进行分割
letter 按照非字符类进行分割
whitespace 按照空格进行分割
UAX URL Email 按照standard分割,但不会分割邮箱和url
NGram和Edge NGram 连词分割
Path Hierarchy 按照文件路径进行切割
POST _analyze
{
  "tokenizer": "uax_url_email",
  "text": ["his email is 123123@123.com"]
}
(三)Token Filter

Token Filter会对 tokenizer输出的单词(term)进行增加、删除和修改等操作
自带的Token Filter如下:

token filter 功能
lowercase 将所有的term转换为小写
stop 删除stop words
NGram和Edge NGram 连词分割
Synonym 添加近义词的term
POST _analyze
{
  "tokenizer": "standard",
  "text": ["a Hello,Word!"],
  "filter": [
      "stop",
      "lowercase",
      {
        "type": "ngram",
        "min_gram": 3,
        "max_gram": 4
      }
    ]
}
(四)自定义分词的API

通过上面的介绍,我们可以知道分词器的三个组件的使用方法,下面我们就来学习一下如何定义一个自己的分词器吧。
分词器的使用需要在索引的配置中设定,如下所示:

PUT index_test
{
  "settings": {
    "analysis": {
      "char_filter": {},
      "tokenizer": {},
      "filter": {},
      "analyzer": {}
    }
  }
}

比如我们要自定义这样结构的一个分词器:



具体的定义语句如下:

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

我们再来举一个例子:



想要定义这样一个分词器,我们的建分词器语句为:

PUT /index_test
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_coustom_analyzer": {
          "type": "custom",
          "char_filter": [
            "emoticons"
          ],
          "tokenizer": "punctuation",
          "filter": [
            "lowercase",
            "english_stop"
          ]
        }
      },
      "tokenizer": {
        "punctuation": {
          "type": "pattern",
          "pattern": "[ .!,?]"
        }
      },
      "char_filter": {
        "emoticons": {
          "type": "mapping",
          "mappings": [
            ":) => _happy_",
            ":( => _sad_"
          ]
        }
      },
      "filter": {
        "english_stop": {
          "type": "stop",
          "stopwords": "_english_"
        }
      }
    }
  }
}

四、分词的使用说明

对于ES分词的使用,一共有两个时机,一个是创建文档和更新文档(Index time)时,会对相应的文档进行分词处理;第二是查询时,会对查询语句进行分词。

  • 索引时分词
    索引时分词是通过配置Index Mapping 中每个字段的analyzer属性实现的
PUT /index_test
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "standard" # 为字段指定analyzer
      }
    }
  }
}
  • 查询时分词
    查询时分词可以有两种形式,分别是查询的时候通过analyzer指定分词器以及通过index mapping设置search_analyzer实现

    我们可以发现,在创建index的时候也可以定义查询时分词,一般来说,如果在创建索引的时候定义了查询时使用的分词器,那么我们在执行查询的过程中,也是要使用相同的分词器,否则会出现无法匹配的情况!!!

五、使用分词的建议

1、明确字段是否需要分词,不需要分词的字段就将type设置为keyword,可以节省空间和提高写性能
2、对于不太清楚的分词效果,可以自己动手调试或者查看一下官方文档,个人觉得官方文档还是写的比较全面的。
官方文档链接如下:
https://www.elastic.co/guide/en/elasticsearch/reference/7.x/analysis-index-search-time.html
(自己根据实际版本看对应的文档)

posted @ 2021-01-30 22:43  moutory  阅读(585)  评论(0编辑  收藏  举报  来源