一、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,如图所示:
此种方法未经测试,只是可以确定可行性。