Elasticsearch中使用ik分词器 JAVA api

一、Elasticsearch分词

在elasticsearch自带的分词器中,对中文分词是支持的,只是所有的分词都是按照单字进行分词的,例如所带的标准的分词器standard分词器,可以按照如下的方式查询是如何进行分词的

[java] view plain copy
  1. http://localhost:9200/iktest/_analyze?pretty&analyzer=standard&text=中华人民共和国  

上述例子使用的是standard进行分词,分词的结果如下:

[plain] view plain copy
  1. {  
  2.   "tokens" : [ {  
  3.     "token" : "中",  
  4.     "start_offset" : 0,  
  5.     "end_offset" : 1,  
  6.     "type" : "<IDEOGRAPHIC>",  
  7.     "position" : 0  
  8.   }, {  
  9.     "token" : "华",  
  10.     "start_offset" : 1,  
  11.     "end_offset" : 2,  
  12.     "type" : "<IDEOGRAPHIC>",  
  13.     "position" : 1  
  14.   }, {  
  15.     "token" : "人",  
  16.     "start_offset" : 2,  
  17.     "end_offset" : 3,  
  18.     "type" : "<IDEOGRAPHIC>",  
  19.     "position" : 2  
  20.   }, {  
  21.     "token" : "民",  
  22.     "start_offset" : 3,  
  23.     "end_offset" : 4,  
  24.     "type" : "<IDEOGRAPHIC>",  
  25.     "position" : 3  
  26.   }, {  
  27.     "token" : "共",  
  28.     "start_offset" : 4,  
  29.     "end_offset" : 5,  
  30.     "type" : "<IDEOGRAPHIC>",  
  31.     "position" : 4  
  32.   }, {  
  33.     "token" : "和",  
  34.     "start_offset" : 5,  
  35.     "end_offset" : 6,  
  36.     "type" : "<IDEOGRAPHIC>",  
  37.     "position" : 5  
  38.   }, {  
  39.     "token" : "国",  
  40.     "start_offset" : 6,  
  41.     "end_offset" : 7,  
  42.     "type" : "<IDEOGRAPHIC>",  
  43.     "position" : 6  
  44.   } ]  
  45. }  
从结果可以看出,对于自带的分词器是对每一个字进行切分分词的,但是如果按照这样来的话,搜索结果中可能好多就是按照单字进行搜索这种的,影响搜索结果,我们希望更智能的分词方法,对于es比较友好的一个分词器就是ik分词器,直接下载就可以进行使用

二、ik分词器的安装

ik分词器是一款在使用es的时候常用的分词器,只要在github上进行下载即可,下载地址如下

[java] view plain copy
  1. https://github.com/medcl/elasticsearch-analysis-ik/releases  
要下载自己所使用es所对应的版本

[java] view plain copy
  1. IK version  ES version  
  2. master  2.1.1 -> master  
  3. 1.7.0   2.1.1  
  4. 1.6.1   2.1.0  
  5. 1.5.0   2.0.0  
  6. 1.4.1   1.7.2  
  7. 1.4.0   1.6.0  
  8. 1.3.0   1.5.0  
  9. 1.2.9   1.4.0  
  10. 1.2.8   1.3.2  
  11. 1.2.7   1.2.1  
  12. 1.2.6   1.0.0  
  13. 1.2.5   0.90.x  
  14. 1.1.3   0.20.x  
  15. 1.1.2   0.19.x  
  16. 1.0.0   0.16.2 -> 0.19.0  
如上所示,个人认为版本高的会对版本低的进行兼容

下载完成之后,解压,然后使用mvn package进行打包,此处需要安装maven,如何安装请自行百度

打包完成之后,会出现 target/releases/elasticsearch-analysis-ik-{version}.zip

将zip文件拷贝到es所在目录下的/plugins/ik
对zip文件进行解压,解压完成之后需要修改plugin-descriptor.properties文件,将其中的java版本,以及es版本号均改为你所使用的版本号,即完成ik分词器的安装

三、对ik分词器的效果进行检测

安装完成时候,使用之前的命令进行检测,因为ik分词器分为两种分词方法,一种是最大切分,一种是全切分,对应的名字为ik_smart,ik_max_word,其中smart的切分更加符合日常的用于,max_word的切分会更加的细致,如github上面所讲述的,下面对于给定的句子我们进行一个检测,句子为:中华人民共和国

ik_samrt切分结果:

[java] view plain copy
  1. http://localhost:9200/iktest/_analyze?pretty&analyzer=ik_smart&text=中华人民共和国  
[java] view plain copy
  1. {  
  2.   "tokens" : [ {  
  3.     "token" : "中华人民共和国",  
  4.     "start_offset" : 0,  
  5.     "end_offset" : 7,  
  6.     "type" : "CN_WORD",  
  7.     "position" : 0  
  8.   } ]  
  9. }  
最大切分将一个中华人民共和国直接切分成一个完成的词语

ik_max_word切分:

[java] view plain copy
  1. http://localhost:9200/iktest/_analyze?pretty&analyzer=ik_max_word&text=中华人民共和国  
[java] view plain copy
  1. {  
  2.   "tokens" : [ {  
  3.     "token" : "中华人民共和国",  
  4.     "start_offset" : 0,  
  5.     "end_offset" : 7,  
  6.     "type" : "CN_WORD",  
  7.     "position" : 0  
  8.   }, {  
  9.     "token" : "中华人民",  
  10.     "start_offset" : 0,  
  11.     "end_offset" : 4,  
  12.     "type" : "CN_WORD",  
  13.     "position" : 1  
  14.   }, {  
  15.     "token" : "中华",  
  16.     "start_offset" : 0,  
  17.     "end_offset" : 2,  
  18.     "type" : "CN_WORD",  
  19.     "position" : 2  
  20.   }, {  
  21.     "token" : "华人",  
  22.     "start_offset" : 1,  
  23.     "end_offset" : 3,  
  24.     "type" : "CN_WORD",  
  25.     "position" : 3  
  26.   }, {  
  27.     "token" : "人民共和国",  
  28.     "start_offset" : 2,  
  29.     "end_offset" : 7,  
  30.     "type" : "CN_WORD",  
  31.     "position" : 4  
  32.   }, {  
  33.     "token" : "人民",  
  34.     "start_offset" : 2,  
  35.     "end_offset" : 4,  
  36.     "type" : "CN_WORD",  
  37.     "position" : 5  
  38.   }, {  
  39.     "token" : "共和国",  
  40.     "start_offset" : 4,  
  41.     "end_offset" : 7,  
  42.     "type" : "CN_WORD",  
  43.     "position" : 6  
  44.   }, {  
  45.     "token" : "共和",  
  46.     "start_offset" : 4,  
  47.     "end_offset" : 6,  
  48.     "type" : "CN_WORD",  
  49.     "position" : 7  
  50.   }, {  
  51.     "token" : "国",  
  52.     "start_offset" : 6,  
  53.     "end_offset" : 7,  
  54.     "type" : "CN_CHAR",  
  55.     "position" : 8  
  56.   } ]  
  57. }  
以上的结果表示ik_max_word的分词会更加的详细

四、关于两种不同分词的用处以及区别:

1、使用方面的不同

其中我们在做索引的时候,希望能将所有的句子切分的更详细,以便更好的搜索,所以ik_max_word更多的用在做索引的时候,但是在搜索的时候,对于用户所输入的query(查询)词,我们可能更希望得比较准确的结果,例如,我们搜索“无花果”的时候,更希望是作为一个词进行查询,而不是切分为"无",“花”,“果”三个词进行结果的召回,因此ik_smart更加常用语对于输入词的分析

2、效率方面的不同

ik_max_word分词相对来说效率更加迅速,而ik_smart的效率比不上ik_max_word(个人做索引的时候将两种分词器进行尝试得出的结果,有误的话,望指正)

五、java api实现指定分词器

实际应用的时候,我们可能都是在程序里面来实现指定分词器的,而上面所讲述的均为直接在网页进行查看的结果,那么如何指定分词器呢?如何用java代码实现呢

经过查找,最终发现三种方法来指定分词器

(1)在构造mapping的时候对于字段进行指定

在构造mapping的时候,我们可以对于指定的字段使用指定的分词器,所使用的java 代码如下所示:


[java] view plain copy
  1. private  XContentBuilder createIKMapping(String indexType) {  
  2.         XContentBuilder mapping = null;  
  3.         try {  
  4.             mapping = XContentFactory.jsonBuilder().startObject()  
  5.                     // 索引库名(类似数据库中的表)  
  6.                     .startObject(indexType).startObject("properties")  
  7.                     .startObject("product_name").field("type""string")  
  8.                     .field("analyzer","ik").field("search_analyzer","ik_smart").endObject()  
  9.                     .startObject("title_sub").field("type""string")  
  10.                     .field("analyzer","ik").field("search_analyzer","ik_smart").endObject()  
  11.                     .startObject("title_primary").field("type""string")  
  12.                     .field("analyzer","ik").field("search_analyzer","ik_smart").endObject()  
  13.                     .startObject("publisher").field("type""string")  
  14.                     .field("analyzer","ik").field("search_analyzer","ik_smart").endObject()  
  15.                     .startObject("author_name").field("type""string")  
  16.                     .field("analyzer","ik").field("search_analyzer","ik_smart").endObject()  
  17.                     //.field("boost",100).endObject()  
  18.                     // 姓名  
  19.                     //.startObject("name").field("type", "string").endObject()  
  20.                     // 位置  
  21.                     //.startObject("location").field("type", "geo_point").endObject()  
  22.             //.endObject().startObject("_all").field("analyzer","ik").field("search_analyzer","ik").endObject().endObject().endObject();  
  23.                     .endObject().endObject().endObject();  
  24.         } catch (IOException e) {  
  25.             e.printStackTrace();  
  26.         }  
  27.         return mapping;  
  28.     }  
即对几个字段做索引的时候使用ik分词器即ik_max_word,在搜索的时候使用ik_smart,以上经过测试成功

(2)对于所有的字段进行指定

此方法未经测试通过,只是知道有这种方法,通过的同学麻烦跟我说下哈,感激不尽

如果ik下面的介绍一样,所使用的dsl语句如下所示:

[java] view plain copy
  1. curl -XPOST http://localhost:9200/index/fulltext/_mapping -d'  
  2. {  
  3.     "fulltext": {  
  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. }'  
即在_all字段进行设置,按照这个思路,我就写了如下的java 代码,经证实不可以,望万能的各位告诉我

[java] view plain copy
  1. private  XContentBuilder createIKMapping(String indexType) {  
  2.        XContentBuilder mapping = null;  
  3.        try {  
  4.            mapping = XContentFactory.jsonBuilder().startObject()  
  5.                    // 索引库名(类似数据库中的表)  
  6.                    .startObject(indexType).startObject("properties") .endObject()  
  7.        .startObject("_all").field("analyzer","ik").field("search_analyzer","ik").endObject()  
  8.     .endObject().endObject();  
  9.        } catch (IOException e) {  
  10.            e.printStackTrace();  
  11.        }  
  12.        return mapping;  
  13.    }  
经过测试,查看mapping的时候再_all字段确实是分词器正确,但是搜索的时候明显可以感觉到不对,不清楚哪的问题,只是有这种方法,如果哪位这样搞出来了麻烦告知一声,多谢(这个我写的代码是不对的,只是在此抛砖引玉额,提出思路,也可能思路就是错的,望不喷)

(3)、在setting的时候进行设置

经过看书得知,在setting的时候可以直接设置analyzer,如图所示:

此种方法未经测试,只是可以确定可行性。


转自:http://blog.csdn.net/molong1208 https://blog.csdn.net/molong1208/article/details/50557253

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页