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

这是因为使用了Elasticsearch中默认的标准分词器,这个分词器在处理中文的时候会把中文单词切分成一个一个的汉字,因此引入中文的分词器就能解决这个问题。

本篇文章按照下面的内容进行描述:

  • 分词器的作用
  • 安装IK
  • 简单的测试
  • 模拟测试
  • 安装elasticsearch-analysis-pinyin
  • 简单的测试
  • 模拟测试

分词器的作用

分词顾名思义,就是把一句话分成一个一个的词。这个概念在搜索中很重要,比如 This is a banana. 如果按照普通的空格来分词,分成this,is,a,banana,的出来的a其实对我们并没有什么用处。因此需要注意下面的问题:

  • 1 区分停顿词(a,or,and这种都属于停顿词)
  • 2 大小写转换(Bananabanana)
  • 3 时态的转换....

具体的算法可以参考http://tartarus.org/~martin/PorterStemmer/,对照的词语可以参考这里http://snowball.tartarus.org/algorithms/porter/diffs.txt

相比中文,就复杂的度了。因为中文不能单纯的依靠空格,标点这种进行分词。就比如中华人民共和国国民,不能简单的分成一个词,也不能粗暴的分成中华人民共和国国民人民中华这些也都算一个词!

因此常见的分词算法就是拿一个标准的词典,关键词都在这个词典里面。然后按照几种规则去查找有没有关键词,比如:

  • 正向最大匹配(从左到右)
  • 逆向最大匹配(从右到左)
  • 最少切分
  • 双向匹配(从左扫描一次,从右扫描一次)

IK,elasticsearch-analysis-ik提供了两种方式,ik_smart就是最少切分,ik_max_word则为细粒度的切分(可能是双向,没看过源码)

了解了分词器的背景后,就可以看一下如何在Elasticsearch重安装分词器了。

安装IK

github中下载相应的代码,比如我的最新版本2.4.0就没有对应的ik版本,不用担心,只需要修改pom.xml就可以了:

  1. <properties>
  2. <!-- 这里的版本号,修改成你对应的版本就行了。
  3. 不过最好不要跨度太大,相近的版本可能没有问题,但是跨度太大的版本,这样做就不保证好使了-->
  4. <elasticsearch.version>2.4.0</elasticsearch.version>
  5. <maven.compiler.target>1.7</maven.compiler.target>
  6. <elasticsearch.assembly.descriptor>${project.basedir}/src/main/assemblies/plugin.xml</elasticsearch.assembly.descriptor>
  7. <elasticsearch.plugin.name>analysis-ik</elasticsearch.plugin.name>
  8. <elasticsearch.plugin.classname>org.elasticsearch.plugin.analysis.ik.AnalysisIkPlugin</elasticsearch.plugin.classname>
  9. <elasticsearch.plugin.jvm>true</elasticsearch.plugin.jvm>
  10. <tests.rest.load_packaged>false</tests.rest.load_packaged>
  11. <skip.unit.tests>true</skip.unit.tests>
  12. <gpg.keyname>4E899B30</gpg.keyname>
  13. <gpg.useagent>true</gpg.useagent>
  14. </properties>

下载后,执行mvn package,进行打包:

  1. ├─config
  2. ├─src
  3. └─target
  4. ├─archive-tmp
  5. ├─classes
  6. ├─generated-sources
  7. ├─maven-archiver
  8. ├─maven-status
  9. ├─releases
  10. └─elasticsearch-analysis-ik-1.9.5.zip
  11. └─surefire

编译完成后,可以在target/releases目录下找到对应的zip包。

解压zip包,复制到elasticsearch-root-path/plugins/ik下即可。

  1. [root@hadoop-master ik]# ll
  2. total 1428
  3. -rw-r--r-- 1 root root 263965 Sep 26 15:03 commons-codec-1.9.jar
  4. -rw-r--r-- 1 root root 61829 Sep 26 15:03 commons-logging-1.2.jar
  5. drwxr-xr-x 3 root root 4096 Sep 26 16:11 config
  6. -rw-r--r-- 1 root root 56023 Sep 26 15:03 elasticsearch-analysis-ik-1.9.5.jar
  7. -rw-r--r-- 1 root root 736658 Sep 26 15:03 httpclient-4.5.2.jar
  8. -rw-r--r-- 1 root root 326724 Sep 26 15:03 httpcore-4.4.4.jar
  9. -rw-r--r-- 1 root root 2666 Sep 26 15:03 plugin-descriptor.properties
  10. [root@hadoop-master ik]# pwd
  11. /usr/elk/elasticsearch-2.4.0/plugins/ik

拷贝后,重启elasticsearch就可以使用分词器了。

最简单的测试

这里使用_analyze api对中文段落进行分词,测试一下:

  1. GET _analyze
  2. {
  3. "analyzer":"ik_max_word",
  4. "text":"中华人民共和国国歌"
  5. }

可以看到ik尽可能多的切分的单词:

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

如果使用ik_smart,则会尽可能少的返回词语:

  1. {
  2. "tokens": [
  3. {
  4. "token": "中华人民共和国",
  5. "start_offset": 0,
  6. "end_offset": 7,
  7. "type": "CN_WORD",
  8. "position": 0
  9. },
  10. {
  11. "token": "国歌",
  12. "start_offset": 7,
  13. "end_offset": 9,
  14. "type": "CN_WORD",
  15. "position": 1
  16. }
  17. ]
  18. }

模拟测试

我这里直接在elastic Sense中进行测试的(强烈推荐这个插件,非常好用,不过输入中文的时候,有点BUG)

第一步,创建一个空的索引

  1. PUT test
  2. {
  3. }

如果你用的是curl,可以执行curl -XPUT localhost:9200/test

第二步,设置映射类型

  1. POST test/test/_mapping
  2. {
  3. "test": {
  4. "_all": {
  5. "analyzer": "ik_max_word",
  6. "search_analyzer": "ik_max_word",
  7. "term_vector": "no",
  8. "store": "false"
  9. },
  10. "properties": {
  11. "content": {
  12. "type": "string",
  13. "store": "no",
  14. "term_vector": "with_positions_offsets",
  15. "analyzer": "ik_max_word",
  16. "search_analyzer": "ik_max_word",
  17. "include_in_all": "true",
  18. "boost": 8
  19. }
  20. }
  21. }
  22. }

上面的命令,是定义test索引下test类型的映射。其中定义了_all字段的分析方法,以及content属性的分析方法。

这里介绍下什么是_all字段,其实_all字段是为了在不知道搜索哪个字段时,使用的。es会把所有的字段(除非你手动设置成false),都放在_all中,然后通过分词器去解析。当你使用query_string的时候,默认就在这个_all字段上去做查询,而不需要挨个字段遍历,节省了时间。

properties中定义了特定字段的分析方式。在上面的例子中,仅仅设置了content的分析方法。

  • type,字段的类型为string,只有string类型才涉及到分词,像是数字之类的是不需要分词的。
  • store,定义字段的存储方式,no代表不单独存储,查询的时候会从_source中解析。当你频繁的针对某个字段查询时,可以考虑设置成true。
  • term_vector,定义了词的存储方式,with_position_offsets,意思是存储词语的偏移位置,在结果高亮的时候有用。
  • analyzer,定义了索引时的分词方法
  • search_analyzer,定义了搜索时的分词方法
  • include_in_all,定义了是否包含在_all字段中
  • boost,是跟计算分值相关的。

设置完成后,添加一个文档

  1. POST test/test/1
  2. {
  3. "test":"美国留给伊拉克的是个烂摊子吗"
  4. }
  5. POST test/test/2
  6. {
  7. "content":"公安部:各地校车将享最高路权吗"
  8. }
  9. POST test/test/3
  10. {
  11. "content":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"
  12. }
  13. POST test/test/4
  14. {
  15. "content":"中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"
  16. }

最后,执行查询进行测试

  1. GET test/_search
  2. {
  3. "query" : { "term" : { "content" : "中国" }},
  4. "highlight" : {
  5. "pre_tags" : ["<tag1>", "<tag2>"],
  6. "post_tags" : ["</tag1>", "</tag2>"],
  7. "fields" : {
  8. "content" : {}
  9. }
  10. }
  11. }

得到返回结果:

  1. {
  2. "took": 4,
  3. "timed_out": false,
  4. "_shards": {
  5. "total": 5,
  6. "successful": 5,
  7. "failed": 0
  8. },
  9. "hits": {
  10. "total": 2,
  11. "max_score": 1.5,
  12. "hits": [
  13. {
  14. "_index": "test",
  15. "_type": "test",
  16. "_id": "4",
  17. "_score": 1.5,
  18. "_source": {
  19. "content": "中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"
  20. },
  21. "highlight": {
  22. "content": [
  23. "<tag1>中国</tag1>驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"
  24. ]
  25. }
  26. },
  27. {
  28. "_index": "test",
  29. "_type": "test",
  30. "_id": "3",
  31. "_score": 0.53699243,
  32. "_source": {
  33. "content": "中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"
  34. },
  35. "highlight": {
  36. "content": [
  37. "中韩渔警冲突调查:韩警平均每天扣1艘<tag1>中国</tag1>渔船"
  38. ]
  39. }
  40. }
  41. ]
  42. }
  43. }

安装elasticsearch-analysis-pinyin分词器

pinyin分词器可以让用户输入拼音,就能查找到相关的关键词。比如在某个商城搜索中,输入shuihu,就能匹配到水壶。这样的体验还是非常好的。

pinyin分词器的安装与IK是一样的,这里就省略掉了。下载的地址参考github.

这个分词器在1.8版本中,提供了两种分词规则:

  • pinyin,就是普通的把汉字转换成拼音;
  • pinyin_first_letter,提取汉字的拼音首字母

简单的测试

首先创建索引,并创建分词器:

  1. PUT medcl
  2. {
  3. "index" : {
  4. "analysis" : {
  5. "analyzer" : {
  6. "pinyin_analyzer" : {
  7. "tokenizer" : "my_pinyin",
  8. "filter" : "word_delimiter"
  9. }
  10. },
  11. "tokenizer" : {
  12. "my_pinyin" : {
  13. "type" : "pinyin",
  14. "first_letter" : "none",
  15. "padding_char" : " "
  16. }
  17. }
  18. }
  19. }
  20. }

然后使用analyze api,进行测试

  1. GET medcl/_analyze
  2. {
  3. "text":"刘德华",
  4. "analyzer":"pinyin_analyzer"
  5. }

可以得到结果:

  1. {
  2. "tokens": [
  3. {
  4. "token": "liu",
  5. "start_offset": 0,
  6. "end_offset": 3,
  7. "type": "word",
  8. "position": 0
  9. },
  10. {
  11. "token": "de",
  12. "start_offset": 0,
  13. "end_offset": 3,
  14. "type": "word",
  15. "position": 1
  16. },
  17. {
  18. "token": "hua",
  19. "start_offset": 0,
  20. "end_offset": 3,
  21. "type": "word",
  22. "position": 2
  23. }
  24. ]
  25. }

如果分词器设置为pinyin_first_letter,则分析的结果为:

  1. {
  2. "tokens": [
  3. {
  4. "token": "ldh",
  5. "start_offset": 0,
  6. "end_offset": 3,
  7. "type": "word",
  8. "position": 0
  9. }
  10. ]
  11. }

模拟测试

如果索引已经存在,需要先关闭索引

  1. POST medcl/_close
  2. {
  3. }

然后设置分词器配置

  1. PUT medcl/_settings
  2. {
  3. "index" : {
  4. "analysis" : {
  5. "analyzer" : {
  6. "pinyin_analyzer" : {
  7. "tokenizer" : "my_pinyin",
  8. "filter" : ["word_delimiter","nGram"]
  9. }
  10. },
  11. "tokenizer" : {
  12. "my_pinyin" : {
  13. "type" : "pinyin",
  14. "first_letter" : "prefix",
  15. "padding_char" : " "
  16. }
  17. }
  18. }
  19. }
  20. }

打开索引

  1. POST medcl/_open
  2. {
  3. }

定义映射类型

  1. POST medcl/folks/_mapping
  2. {
  3. "folks": {
  4. "properties": {
  5. "name": {
  6. "type": "multi_field",
  7. "fields": {
  8. "name": {
  9. "type": "string",
  10. "store": "no",
  11. "term_vector": "with_positions_offsets",
  12. "analyzer": "pinyin_analyzer",
  13. "boost": 10
  14. },
  15. "primitive": {
  16. "type": "string",
  17. "store": "yes",
  18. "analyzer": "keyword"
  19. }
  20. }
  21. }
  22. }
  23. }
  24. }

提交样例数据

  1. POST medcl/folks/1
  2. {
  3. "name":"刘德华"
  4. }

执行查询

  1. GET medcl/folks/_search
  2. {
  3. "query": {"match": {
  4. "name": "l d hua"
  5. }}
  6. }

这里搜liu de hua,ldh,l de hua都能匹配到,还是很强大滴。

得到结果

  1. {
  2. "took": 7,
  3. "timed_out": false,
  4. "_shards": {
  5. "total": 5,
  6. "successful": 5,
  7. "failed": 0
  8. },
  9. "hits": {
  10. "total": 1,
  11. "max_score": 7.408082,
  12. "hits": [
  13. {
  14. "_index": "medcl",
  15. "_type": "folks",
  16. "_id": "1",
  17. "_score": 7.408082,
  18. "_source": {
  19. "name": "刘德华"
  20. }
  21. }
  22. ]
  23. }
  24. }

参考

如何在Elasticsearch中安装中文分词器(IK+pinyin)的更多相关文章

  1. 如何在Elasticsearch中安装中文分词器(IK)和拼音分词器?

    声明:我使用的Elasticsearch的版本是5.4.0,安装分词器前请先安装maven 一:安装maven https://github.com/apache/maven 说明: 安装maven需 ...

  2. 如何给Elasticsearch安装中文分词器IK

    安装Elasticsearch安装中文分词器IK的步骤: 1. 停止elasticsearch 2.2的服务 2. 在以下地址下载对应的elasticsearch-analysis-ik插件安装包(版 ...

  3. ElasticSearch安装中文分词器IK

    1.安装IK分词器,下载对应版本的插件,elasticsearch-analysis-ik中文分词器的开发者一直进行维护的,对应着elasticsearch的版本,所以选择好自己的版本即可.IKAna ...

  4. Elasticsearch如何安装中文分词插件ik

    elasticsearch-analysis-ik 是一款中文的分词插件,支持自定义词库. 安装步骤: 1.到github网站下载源代码,网站地址为:https://github.com/medcl/ ...

  5. Solr安装中文分词器IK

    安装环境 jdk1.7 solr-4.10.3.tgz KAnalyzer2012FF_u1.jar tomcat7 VM虚拟机redhat6.5-x64:192.168.1.201 Xshell4 ...

  6. ElasticSearch安装中文分词器IKAnalyzer

    # ElasticSearch安装中文分词器IKAnalyzer  本篇主要讲解如何在ElasticSearch中安装中文分词器IKAnalyzer,拆分的每个词都是我们熟知的词语,从而建立词汇与文档 ...

  7. ElasticSearch 安装中文分词器

    1.安装中文分词器IK 下载地址:https://github.com/medcl/elasticsearch-analysis-ik 在线下载安装: elasticsearch-plugin.bat ...

  8. 转:solr6.0配置中文分词器IK Analyzer

    solr6.0中进行中文分词器IK Analyzer的配置和solr低版本中最大不同点在于IK Analyzer中jar包的引用.一般的IK分词jar包都是不能用的,因为IK分词中传统的jar不支持s ...

  9. 我与solr(六)--solr6.0配置中文分词器IK Analyzer

    转自:http://blog.csdn.net/linzhiqiang0316/article/details/51554217,表示感谢. 由于前面没有设置分词器,以至于查询的结果出入比较大,并且无 ...

随机推荐

  1. 数学思想:为何我们把 x²读作x平方

    要弄清楚这个问题,我们得先认识一个人.古希腊大数学家 欧多克索斯,其在整个古代仅次于阿基米德,是一位天文学家.医生.几何学家.立法家和地理学家. 为何我们把 x²读作x平方呢? 古希腊时代,越来越多的 ...

  2. 前端css兼容性与易混淆的点

    一.常用的骨灰级清除浮动 .clearfix:after { content: "."; display: block; height:; clear: both; visibil ...

  3. Apache执行Python脚本

    由于经常需要到服务器上执行些命令,有些命令懒得敲,就准备写点脚本直接浏览器调用就好了,比如这样: 因为线上有现成的Apache,就直接放它里面了,当然访问安全要设置,我似乎别的随笔里写了安全问题,这里 ...

  4. 理解CSS边框border

    前面的话   边框是CSS盒模型属性中默默无闻的一个普通属性,CSS3的到来,但得边框属性重新焕发了光彩.本文将详细介绍CSS边框 基础样式   边框是一条以空格分隔的集合样式,包括边框粗细(边框宽度 ...

  5. Objective-C三种定时器CADisplayLink / NSTimer / GCD的使用

    OC中的三种定时器:CADisplayLink.NSTimer.GCD 我们先来看看CADiskplayLink, 点进头文件里面看看, 用注释来说明下 @interface CADisplayLin ...

  6. 编写高质量代码:改善Java程序的151个建议(第8章:多线程和并发___建议126~128)

    建议126:适时选择不同的线程池来实现 Java的线程池实现从根本上来说只有两个:ThreadPoolExecutor类和ScheduledThreadPoolExecutor类,这两个类还是父子关系 ...

  7. HTML5实现文件断点续传

    HTML5的FILE api,有一个slice方法,可以将BLOB对象进行分割.前端通过FileList对象获取到相应的文件,按照指定的分割方式将大文件分段,然后一段一段地传给后端,后端再按顺序一段段 ...

  8. ABP创建数据库操作步骤

    1 ABP创建数据库操作步骤 1.1 SimpleTaskSystem.Web项目中的Web.config文件修改数据库配置. <add name="Default" pro ...

  9. BPM合同管理解决方案分享

    一.方案概述合同是组织与组织间所订协议的法律 表现形式,体现着双方对于合作在法律和道德上的承诺.然而,大多数企业的合同管理都或多或少存在合同审批过程不规范.签订草率.审批权责不清.合同执行跟踪难.合同 ...

  10. join Linq

    List<Publisher> Publishers = new List<Publisher>(); Publisher publish1 = new Publisher() ...