这篇文章主要来介绍下什么是 Analysis ,什么是分词器,以及 ElasticSearch 自带的分词器是怎么工作的,最后会介绍下中文分词是怎么做的。

首先来说下什么是 Analysis:

什么是 Analysis?

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

举一个分词简单的例子:比如你输入 Mastering Elasticsearch,会自动帮你分成两个单词,一个是 mastering,另一个是 elasticsearch,可以看出单词也被转化成了小写的。

再简单了解了 Analysis 与 Analyzer 之后,让我们来看下分词器的组成:

分词器的组成

分词器是专门处理分词的组件,分词器由以下三部分组成:

  • Character Filters:针对原始文本处理,比如去除 html 标签
  • Tokenizer:按照规则切分为单词,比如按照空格切分
  • Token Filters:将切分的单词进行加工,比如大写转小写,删除 stopwords,增加同义语

同时 Analyzer 三个部分也是有顺序的,从图中可以看出,从上到下依次经过 Character FiltersTokenizer 以及 Token Filters,这个顺序比较好理解,一个文本进来肯定要先对文本数据进行处理,再去分词,最后对分词的结果进行过滤。

其中,ES 内置了许多分词器:

  • Standard Analyzer - 默认分词器,按词切分,小写处理
  • Simple Analyzer - 按照非字母切分(符号被过滤),小写处理
  • Stop Analyzer - 小写处理,停用词过滤(the ,a,is)
  • Whitespace Analyzer - 按照空格切分,不转小写
  • Keyword Analyzer - 不分词,直接将输入当做输出
  • Pattern Analyzer - 正则表达式,默认 \W+
  • Language - 提供了 30 多种常见语言的分词器
  • Customer Analyzer - 自定义分词器

接下来会对以上分词器进行讲解,在讲解之前先来看下很有用的 API:_analyzer API

Analyzer API

它可以通过以下三种方式来查看分词器是怎么样工作的:

  • 直接指定 Analyzer 进行测试
  1. GET _analyze
  2. {
  3. "analyzer": "standard",
  4. "text" : "Mastering Elasticsearch , elasticsearch in Action"
  5. }
  • 指定索引的字段进行测试
  1. POST books/_analyze
  2. {
  3. "field": "title",
  4. "text": "Mastering Elasticesearch"
  5. }
  • 自定义分词进行测试
  1. POST /_analyze
  2. {
  3. "tokenizer": "standard",
  4. "filter": ["lowercase"],
  5. "text": "Mastering Elasticesearch"
  6. }

再了解了 Analyzer API 后,让我们一起看下 ES 内置的分词器:

ES 分词器

首先来介绍下 Stamdard Analyzer 分词器:

Stamdard Analyzer

它是 ES 默认的分词器,它会对输入的文本按词的方式进行切分,切分好以后会进行转小写处理,默认的 stopwords 是关闭的

下面使用 Kibana 看一下它是怎么样进行工作的,在 Kibana 的开发工具(Dev Tools)中指定 Analyzer 为 standard,并输入文本 In 2020, Java is the best language in the world.,然后我们运行一下:

  1. GET _analyze
  2. {
  3. "analyzer": "standard",
  4. "text": "In 2020, Java is the best language in the world."
  5. }

运行结果如下:

  1. {
  2. "tokens" : [
  3. {
  4. "token" : "in",
  5. "start_offset" : 0,
  6. "end_offset" : 2,
  7. "type" : "<ALPHANUM>",
  8. "position" : 0
  9. },
  10. {
  11. "token" : "2020",
  12. "start_offset" : 3,
  13. "end_offset" : 7,
  14. "type" : "<NUM>",
  15. "position" : 1
  16. },
  17. {
  18. "token" : "java",
  19. "start_offset" : 9,
  20. "end_offset" : 13,
  21. "type" : "<ALPHANUM>",
  22. "position" : 2
  23. },
  24. {
  25. "token" : "is",
  26. "start_offset" : 14,
  27. "end_offset" : 16,
  28. "type" : "<ALPHANUM>",
  29. "position" : 3
  30. },
  31. {
  32. "token" : "the",
  33. "start_offset" : 17,
  34. "end_offset" : 20,
  35. "type" : "<ALPHANUM>",
  36. "position" : 4
  37. },
  38. {
  39. "token" : "best",
  40. "start_offset" : 21,
  41. "end_offset" : 25,
  42. "type" : "<ALPHANUM>",
  43. "position" : 5
  44. },
  45. {
  46. "token" : "language",
  47. "start_offset" : 26,
  48. "end_offset" : 34,
  49. "type" : "<ALPHANUM>",
  50. "position" : 6
  51. },
  52. {
  53. "token" : "in",
  54. "start_offset" : 35,
  55. "end_offset" : 37,
  56. "type" : "<ALPHANUM>",
  57. "position" : 7
  58. },
  59. {
  60. "token" : "the",
  61. "start_offset" : 38,
  62. "end_offset" : 41,
  63. "type" : "<ALPHANUM>",
  64. "position" : 8
  65. },
  66. {
  67. "token" : "world",
  68. "start_offset" : 42,
  69. "end_offset" : 47,
  70. "type" : "<ALPHANUM>",
  71. "position" : 9
  72. }
  73. ]
  74. }

可以看出是按照空格、非字母的方式对输入的文本进行了转换,比如对 Java 做了转小写,对一些停用词也没有去掉,比如 in

其中 token 为分词结果;start_offset 为起始偏移;end_offset 为结束偏移;position 为分词位置。

下面来看下 Simple Analyzer 分词器:

Simple Analyzer

它只包括了 Lower CaseTokenizer,它会按照非字母切分非字母的会被去除,最后对切分好的做转小写处理,然后接着用刚才的输入文本,分词器换成 simple 来进行分词,运行结果如下:

  1. {
  2. "tokens" : [
  3. {
  4. "token" : "in",
  5. "start_offset" : 0,
  6. "end_offset" : 2,
  7. "type" : "word",
  8. "position" : 0
  9. },
  10. {
  11. "token" : "java",
  12. "start_offset" : 9,
  13. "end_offset" : 13,
  14. "type" : "word",
  15. "position" : 1
  16. },
  17. {
  18. "token" : "is",
  19. "start_offset" : 14,
  20. "end_offset" : 16,
  21. "type" : "word",
  22. "position" : 2
  23. },
  24. {
  25. "token" : "the",
  26. "start_offset" : 17,
  27. "end_offset" : 20,
  28. "type" : "word",
  29. "position" : 3
  30. },
  31. {
  32. "token" : "best",
  33. "start_offset" : 21,
  34. "end_offset" : 25,
  35. "type" : "word",
  36. "position" : 4
  37. },
  38. {
  39. "token" : "language",
  40. "start_offset" : 26,
  41. "end_offset" : 34,
  42. "type" : "word",
  43. "position" : 5
  44. },
  45. {
  46. "token" : "in",
  47. "start_offset" : 35,
  48. "end_offset" : 37,
  49. "type" : "word",
  50. "position" : 6
  51. },
  52. {
  53. "token" : "the",
  54. "start_offset" : 38,
  55. "end_offset" : 41,
  56. "type" : "word",
  57. "position" : 7
  58. },
  59. {
  60. "token" : "world",
  61. "start_offset" : 42,
  62. "end_offset" : 47,
  63. "type" : "word",
  64. "position" : 8
  65. }
  66. ]
  67. }

从结果中可以看出,数字 2020 被去除掉了,说明非字母的的确会被去除,所有的词也都做了小写转换。

现在,我们来看下 Whitespace Analyzer 分词器:

Whitespace Analyzer

它非常简单,根据名称也可以看出是按照空格进行切分的,下面我们来看下它是怎么样工作的:

  1. {
  2. "tokens" : [
  3. {
  4. "token" : "In",
  5. "start_offset" : 0,
  6. "end_offset" : 2,
  7. "type" : "word",
  8. "position" : 0
  9. },
  10. {
  11. "token" : "2020,",
  12. "start_offset" : 3,
  13. "end_offset" : 8,
  14. "type" : "word",
  15. "position" : 1
  16. },
  17. {
  18. "token" : "Java",
  19. "start_offset" : 9,
  20. "end_offset" : 13,
  21. "type" : "word",
  22. "position" : 2
  23. },
  24. {
  25. "token" : "is",
  26. "start_offset" : 14,
  27. "end_offset" : 16,
  28. "type" : "word",
  29. "position" : 3
  30. },
  31. {
  32. "token" : "the",
  33. "start_offset" : 17,
  34. "end_offset" : 20,
  35. "type" : "word",
  36. "position" : 4
  37. },
  38. {
  39. "token" : "best",
  40. "start_offset" : 21,
  41. "end_offset" : 25,
  42. "type" : "word",
  43. "position" : 5
  44. },
  45. {
  46. "token" : "language",
  47. "start_offset" : 26,
  48. "end_offset" : 34,
  49. "type" : "word",
  50. "position" : 6
  51. },
  52. {
  53. "token" : "in",
  54. "start_offset" : 35,
  55. "end_offset" : 37,
  56. "type" : "word",
  57. "position" : 7
  58. },
  59. {
  60. "token" : "the",
  61. "start_offset" : 38,
  62. "end_offset" : 41,
  63. "type" : "word",
  64. "position" : 8
  65. },
  66. {
  67. "token" : "world.",
  68. "start_offset" : 42,
  69. "end_offset" : 48,
  70. "type" : "word",
  71. "position" : 9
  72. }
  73. ]
  74. }

可以看出,只是按照空格进行切分,2020 数字还是在的,Java 的首字母还是大写的,, 还是保留的。

接下来看 Stop Analyzer 分词器:

Stop Analyzer

它由 Lowe CaseTokenizerStopToken Filters 组成的,相较于刚才提到的 Simple Analyzer,多了 stop 过滤,stop 就是会把 theais 等修饰词去除,同样让我们看下运行结果:

  1. {
  2. "tokens" : [
  3. {
  4. "token" : "java",
  5. "start_offset" : 9,
  6. "end_offset" : 13,
  7. "type" : "word",
  8. "position" : 1
  9. },
  10. {
  11. "token" : "best",
  12. "start_offset" : 21,
  13. "end_offset" : 25,
  14. "type" : "word",
  15. "position" : 4
  16. },
  17. {
  18. "token" : "language",
  19. "start_offset" : 26,
  20. "end_offset" : 34,
  21. "type" : "word",
  22. "position" : 5
  23. },
  24. {
  25. "token" : "world",
  26. "start_offset" : 42,
  27. "end_offset" : 47,
  28. "type" : "word",
  29. "position" : 8
  30. }
  31. ]
  32. }

可以看到 in is the 等词都被 stop filter过滤掉了。

接下来看下 Keyword Analyzer

Keyword Analyzer

它其实不做分词处理,只是将输入作为 Term 输出,我们来看下运行结果:

  1. {
  2. "tokens" : [
  3. {
  4. "token" : "In 2020, Java is the best language in the world.",
  5. "start_offset" : 0,
  6. "end_offset" : 48,
  7. "type" : "word",
  8. "position" : 0
  9. }
  10. ]
  11. }

我们可以看到,没有对输入文本进行分词,而是直接作为 Term 输出了。

接下来看下 Pattern Analyzer

Pattern Analyzer

它可以通过正则表达式的方式进行分词,默认是用 \W+ 进行分割的,也就是非字母的符合进行切分的,由于运行结果和 Stamdard Analyzer 一样,就不展示了。

Language Analyzer

ES 为不同国家语言的输入提供了 Language Analyzer 分词器,在里面可以指定不同的语言,我们用 english 进行分词看下:

  1. {
  2. "tokens" : [
  3. {
  4. "token" : "2020",
  5. "start_offset" : 3,
  6. "end_offset" : 7,
  7. "type" : "<NUM>",
  8. "position" : 1
  9. },
  10. {
  11. "token" : "java",
  12. "start_offset" : 9,
  13. "end_offset" : 13,
  14. "type" : "<ALPHANUM>",
  15. "position" : 2
  16. },
  17. {
  18. "token" : "best",
  19. "start_offset" : 21,
  20. "end_offset" : 25,
  21. "type" : "<ALPHANUM>",
  22. "position" : 5
  23. },
  24. {
  25. "token" : "languag",
  26. "start_offset" : 26,
  27. "end_offset" : 34,
  28. "type" : "<ALPHANUM>",
  29. "position" : 6
  30. },
  31. {
  32. "token" : "world",
  33. "start_offset" : 42,
  34. "end_offset" : 47,
  35. "type" : "<ALPHANUM>",
  36. "position" : 9
  37. }
  38. ]
  39. }

可以看出 language 被改成了 languag,同时它也是有 stop 过滤器的,比如 in,is 等词也被去除了。

最后,让我们看下中文分词:

中文分词

中文分词有特定的难点,不像英文,单词有自然的空格作为分隔,在中文句子中,不能简单地切分成一个个的字,而是需要分成有含义的词,但是在不同的上下文,是有不同的理解的。

比如以下例子:

  1. 在这些,企业中,国有,企业,有十个/在这些,企业,中国,有企业,有十个
  2. 各国,有,企业,相继,倒闭/各,国有,企业,相继,倒闭
  3. 羽毛球,拍卖,完了/羽毛球拍,卖,完了

那么,让我们来看下 ICU Analyzer 分词器,它提供了 Unicode 的支持,更好的支持亚洲语言!

我们先用 standard 来分词,以便于和 ICU 进行对比。

  1. GET _analyze
  2. {
  3. "analyzer": "standard",
  4. "text": "各国有企业相继倒闭"
  5. }

运行结果就不展示了,分词是一个字一个字切分的,明显效果不是很好,接下来用 ICU 进行分词,分词结果如下:

  1. {
  2. "tokens" : [
  3. {
  4. "token" : "各国",
  5. "start_offset" : 0,
  6. "end_offset" : 2,
  7. "type" : "<IDEOGRAPHIC>",
  8. "position" : 0
  9. },
  10. {
  11. "token" : "有",
  12. "start_offset" : 2,
  13. "end_offset" : 3,
  14. "type" : "<IDEOGRAPHIC>",
  15. "position" : 1
  16. },
  17. {
  18. "token" : "企业",
  19. "start_offset" : 3,
  20. "end_offset" : 5,
  21. "type" : "<IDEOGRAPHIC>",
  22. "position" : 2
  23. },
  24. {
  25. "token" : "相继",
  26. "start_offset" : 5,
  27. "end_offset" : 7,
  28. "type" : "<IDEOGRAPHIC>",
  29. "position" : 3
  30. },
  31. {
  32. "token" : "倒闭",
  33. "start_offset" : 7,
  34. "end_offset" : 9,
  35. "type" : "<IDEOGRAPHIC>",
  36. "position" : 4
  37. }
  38. ]
  39. }

可以看到分成了各国企业相继倒闭,显然比刚才的效果好了很多。

还有许多中文分词器,在这里列举几个:

IK

jieba

THULAC

大家可以自己安装下,看下它中文分词效果。

总结

本文主要介绍了 ElasticSearch 自带的分词器,学习了使用 _analyzer API 去查看它的分词情况,最后还介绍下中文分词是怎么做的。

参考文献

Elasticsearch顶尖高手系列

Elasticsearch核心技术与实战

https://www.elastic.co/guide/en/elasticsearch/reference/7.1/indices-analyze.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/analyzer-anatomy.html

ElasticSearch 分词器,了解一下的更多相关文章

  1. Elasticsearch——分词器对String的作用

    更多内容参考:Elasticsearch学习总结 关于String类型--分词与不分词 在Elasticsearch中String是最基本的数据类型,如果不是数字或者标准格式的日期等这种很明显的类型, ...

  2. elasticsearch分词器Jcseg安装手册

    Jcseg是什么? Jcseg是基于mmseg算法的一个轻量级中文分词器,同时集成了关键字提取,关键短语提取,关键句子提取和文章自动摘要等功能,并且提供了一个基于Jetty的web服务器,方便各大语言 ...

  3. Elasticsearch 分词器

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

  4. ElasticSearch分词器

    什么是分词器? 分词器,是将用户输入的一段文本,分析成符合逻辑的一种工具.到目前为止呢,分词器没有办法做到完全的符合人们的要求.和我们有关的分词器有英文的和中文的.英文的分词器过程:输入文本-关键词切 ...

  5. elasticsearch分词器ik

    1. 下载和es配套的版本 git clone https://github.com/medcl/elasticsearch-analysis-ik 2. 编译 cd elasticsearch-an ...

  6. Elasticsearch(10) --- 内置分词器、中文分词器

    Elasticsearch(10) --- 内置分词器.中文分词器 这篇博客主要讲:分词器概念.ES内置分词器.ES中文分词器. 一.分词器概念 1.Analysis 和 Analyzer Analy ...

  7. elasticsearch教程--中文分词器作用和使用

    概述   本文都是基于elasticsearch安装教程 中的elasticsearch安装目录(/opt/environment/elasticsearch-6.4.0)为范例 环境准备 ·全新最小 ...

  8. 使用Docker 安装Elasticsearch、Elasticsearch-head、IK分词器 和使用

    原文:使用Docker 安装Elasticsearch.Elasticsearch-head.IK分词器 和使用 Elasticsearch的安装 一.elasticsearch的安装 1.镜像拉取 ...

  9. 如何在Elasticsearch中安装中文分词器(IK+pinyin)

    如果直接使用Elasticsearch的朋友在处理中文内容的搜索时,肯定会遇到很尴尬的问题--中文词语被分成了一个一个的汉字,当用Kibana作图的时候,按照term来分组,结果一个汉字被分成了一组. ...

随机推荐

  1. user.ini Operation not permitted

    rm: cannot remove '/public/.user.ini': Operation not permitted chattr -i .user.ini rm -f .user.ini

  2. win10系统出现“VMware Workstation与Device/Credential Guard不兼容”的解决办法

    办公室win10 64位系统安装的VMware Workstation,有一天启动时出现提示"VMware Workstation 与 Device/Credential Guard 不兼容 ...

  3. VMware Workstation Pro 虚拟机安装CentOS-7

    一.下载CentOS-7镜像 我是通过阿里开源镜像站下载的, 下载url:https://mirrors.aliyun.com/centos/7/isos/x86_64/ 下载CentOS-7-x86 ...

  4. D. Concatenated Multiples 解析(思維)

    Codeforce 1029 D. Concatenated Multiples 解析(思維) 今天我們來看看CF1029D 題目連結 題目 給你一個序列\(a\)和一個數字\(k\),求有幾種ind ...

  5. CPU上下文

    CPU上下文 包括CPU寄存器和程序计数器(Program Counter,PC). CPU寄存器,是CPU内置的容量小.但速度极快的内存. 程序计数器,是用来存储CPU正在执行的指令位置.或者即将执 ...

  6. 如何处理 Kubeadm 搭建的集群证书过期问题

    Kubeadm 证书过期处理 以下内容参考了如下链接:https://www.cnblogs.com/skymyyang/p/11093686.html 一.处理证书已过期的集群 使用 kubeadm ...

  7. Dapr Golang HTTP 调用

    Dapr Golang HTTP 调用 版本介绍 Go 版本:1.15 Dapr Go SKD 版本:0.11.1 工程结构 从上图可知,新建 3 个 Go 启动项目,cmd 为启动项目目录,其中 c ...

  8. Git的全局及单个仓库配置

    我们先来了解一下在git中的配置文件路径: /etc/gitconfig 文件: 包含系统上每一个用户及他们仓库的通用配置. 如果在执行 git config 时带上 --system 选项,那么它就 ...

  9. C++ stringstream 实现字符与数字之间的转换

    c++中利用srtingstream可以将数字转为字符串,或者将字符串转为数字: 首先将double型数字串转成了string: stringnum2string(double *a,int n) { ...

  10. leetcode24:word-ladder-ii

    题目描述 给定两个单词(初始单词和目标单词)和一个单词字典,请找出所有的从初始单词到目标单词的最短转换序列: 每一次转换只能改变一个单词 每一个中间词都必须存在单词字典当中 例如: 给定的初始单词st ...