Elasticsearch之IK分词器 java api

一、Elasticsearch分词

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

http://localhost:9200/iktest/_analyze?pretty&analyzer=standard&text=中华人民共和国


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

    {
      "tokens" : [ {
        "token" : "中",
        "start_offset" : 0,
        "end_offset" : 1,
        "type" : "<IDEOGRAPHIC>",
        "position" : 0
      }, {
        "token" : "华",
        "start_offset" : 1,
        "end_offset" : 2,
        "type" : "<IDEOGRAPHIC>",
        "position" : 1
      }, {
        "token" : "人",
        "start_offset" : 2,
        "end_offset" : 3,
        "type" : "<IDEOGRAPHIC>",
        "position" : 2
      }, {
        "token" : "民",
        "start_offset" : 3,
        "end_offset" : 4,
        "type" : "<IDEOGRAPHIC>",
        "position" : 3
      }, {
        "token" : "共",
        "start_offset" : 4,
        "end_offset" : 5,
        "type" : "<IDEOGRAPHIC>",
        "position" : 4
      }, {
        "token" : "和",
        "start_offset" : 5,
        "end_offset" : 6,
        "type" : "<IDEOGRAPHIC>",
        "position" : 5
      }, {
        "token" : "国",
        "start_offset" : 6,
        "end_offset" : 7,
        "type" : "<IDEOGRAPHIC>",
        "position" : 6
      } ]
    }

从结果可以看出,对于自带的分词器是对每一个字进行切分分词的,但是如果按照这样来的话,搜索结果中可能好多就是按照单字进行搜索这种的,影响搜索结果,我们希望更智能的分词方法,对于es比较友好的一个分词器就是ik分词器,直接下载就可以进行使用

二、ik分词器的安装

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

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

要下载自己所使用es所对应的版本

    IK version    ES version
    master    2.1.1 -> master
    1.7.0    2.1.1
    1.6.1    2.1.0
    1.5.0    2.0.0
    1.4.1    1.7.2
    1.4.0    1.6.0
    1.3.0    1.5.0
    1.2.9    1.4.0
    1.2.8    1.3.2
    1.2.7    1.2.1
    1.2.6    1.0.0
    1.2.5    0.90.x
    1.1.3    0.20.x
    1.1.2    0.19.x
    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切分结果:

http://localhost:9200/iktest/_analyze?pretty&analyzer=ik_smart&text=中华人民共和国

    {
      "tokens" : [ {
        "token" : "中华人民共和国",
        "start_offset" : 0,
        "end_offset" : 7,
        "type" : "CN_WORD",
        "position" : 0
      } ]
    }

最大切分将一个中华人民共和国直接切分成一个完成的词语

ik_max_word切分:

http://localhost:9200/iktest/_analyze?pretty&analyzer=ik_max_word&text=中华人民共和国

    {
      "tokens" : [ {
        "token" : "中华人民共和国",
        "start_offset" : 0,
        "end_offset" : 7,
        "type" : "CN_WORD",
        "position" : 0
      }, {
        "token" : "中华人民",
        "start_offset" : 0,
        "end_offset" : 4,
        "type" : "CN_WORD",
        "position" : 1
      }, {
        "token" : "中华",
        "start_offset" : 0,
        "end_offset" : 2,
        "type" : "CN_WORD",
        "position" : 2
      }, {
        "token" : "华人",
        "start_offset" : 1,
        "end_offset" : 3,
        "type" : "CN_WORD",
        "position" : 3
      }, {
        "token" : "人民共和国",
        "start_offset" : 2,
        "end_offset" : 7,
        "type" : "CN_WORD",
        "position" : 4
      }, {
        "token" : "人民",
        "start_offset" : 2,
        "end_offset" : 4,
        "type" : "CN_WORD",
        "position" : 5
      }, {
        "token" : "共和国",
        "start_offset" : 4,
        "end_offset" : 7,
        "type" : "CN_WORD",
        "position" : 6
      }, {
        "token" : "共和",
        "start_offset" : 4,
        "end_offset" : 6,
        "type" : "CN_WORD",
        "position" : 7
      }, {
        "token" : "国",
        "start_offset" : 6,
        "end_offset" : 7,
        "type" : "CN_CHAR",
        "position" : 8
      } ]
    }

以上的结果表示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 代码如下所示:


    private  XContentBuilder createIKMapping(String indexType) {
            XContentBuilder mapping = null;
            try {
                mapping = XContentFactory.jsonBuilder().startObject()
                        // 索引库名(类似数据库中的表)
                        .startObject(indexType).startObject("properties")
                        .startObject("product_name").field("type", "string")
                        .field("analyzer","ik").field("search_analyzer","ik_smart").endObject()
                        .startObject("title_sub").field("type", "string")
                        .field("analyzer","ik").field("search_analyzer","ik_smart").endObject()
                        .startObject("title_primary").field("type", "string")
                        .field("analyzer","ik").field("search_analyzer","ik_smart").endObject()
                        .startObject("publisher").field("type", "string")
                        .field("analyzer","ik").field("search_analyzer","ik_smart").endObject()
                        .startObject("author_name").field("type", "string")
                        .field("analyzer","ik").field("search_analyzer","ik_smart").endObject()
                        //.field("boost",100).endObject()
                        // 姓名
                        //.startObject("name").field("type", "string").endObject()
                        // 位置
                        //.startObject("location").field("type", "geo_point").endObject()
                //.endObject().startObject("_all").field("analyzer","ik").field("search_analyzer","ik").endObject().endObject().endObject();
                        .endObject().endObject().endObject();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return mapping;
        }

即对几个字段做索引的时候使用ik分词器即ik_max_word,在搜索的时候使用ik_smart,以上经过测试成功

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

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

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

    curl -XPOST http://localhost:9200/index/fulltext/_mapping -d'
    {
        "fulltext": {
                 "_all": {
                "analyzer": "ik_max_word",
                "search_analyzer": "ik_max_word",
                "term_vector": "no",
                "store": "false"
            },
            "properties": {
                "content": {
                    "type": "string",
                    "store": "no",
                    "term_vector": "with_positions_offsets",
                    "analyzer": "ik_max_word",
                    "search_analyzer": "ik_max_word",
                    "include_in_all": "true",
                    "boost": 8
                }
            }
        }
    }'

即在_all字段进行设置,按照这个思路,我就写了如下的java 代码,经证实不可以,望万能的各位告诉我

     private  XContentBuilder createIKMapping(String indexType) {
            XContentBuilder mapping = null;
            try {
                mapping = XContentFactory.jsonBuilder().startObject()
                        // 索引库名(类似数据库中的表)
                        .startObject(indexType).startObject("properties") .endObject()
               .startObject("_all").field("analyzer","ik").field("search_analyzer","ik").endObject()
            .endObject().endObject();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return mapping;
        }

经过测试,查看mapping的时候再_all字段确实是分词器正确,但是搜索的时候明显可以感觉到不对,不清楚哪的问题,只是有这种方法,如果哪位这样搞出来了麻烦告知一声,多谢(这个我写的代码是不对的,只是在此抛砖引玉额,提出思路,也可能思路就是错的,望不喷)

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

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

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

猜你喜欢

转载自blog.csdn.net/aa1215018028/article/details/84027973