700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 如何在Elasticsearch中安装中文分词器(IK+pinyin)

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

时间:2021-02-12 11:44:20

相关推荐

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

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

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

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

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

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

分词器的作用

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

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

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

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

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

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

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

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

安装IK

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

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

├─config

├─src

└─target

├─archive-tmp

├─classes

├─generated-sources

├─maven-archiver

├─maven-status

├─releases

│ └─elasticsearch-analysis-ik-1.9.5.zip

└─surefire

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

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

[root@hadoop-master ik]# ll

total 1428

-rw-r–r-- 1 root root 263965 Sep 26 15:03 commons-codec-1.9.jar

-rw-r–r-- 1 root root 61829 Sep 26 15:03 commons-logging-1.2.jar

drwxr-xr-x 3 root root 4096 Sep 26 16:11 config

-rw-r–r-- 1 root root 56023 Sep 26 15:03 elasticsearch-analysis-ik-1.9.5.jar

-rw-r–r-- 1 root root 736658 Sep 26 15:03 httpclient-4.5.2.jar

-rw-r–r-- 1 root root 326724 Sep 26 15:03 httpcore-4.4.4.jar

-rw-r–r-- 1 root root 2666 Sep 26 15:03 plugin-descriptor.properties

[root@hadoop-master ik]# pwd

/usr/elk/elasticsearch-2.4.0/plugins/ik

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

最简单的测试

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

GET _analyze

{

“analyzer”:“ik_max_word”,

“text”:“中华人民共和国国歌”

}

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

{

“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

},

{

“token”: “国歌”,

“start_offset”: 7,

“end_offset”: 9,

“type”: “CN_WORD”,

“position”: 9

}

]

}

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

{

“tokens”: [

{

“token”: “中华人民共和国”,

“start_offset”: 0,

“end_offset”: 7,

“type”: “CN_WORD”,

“position”: 0

},

{

“token”: “国歌”,

“start_offset”: 7,

“end_offset”: 9,

“type”: “CN_WORD”,

“position”: 1

}

]

}

模拟测试

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

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

PUT test

{

}

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

第二步,设置映射类型

POST test/test/_mapping

{

“test”: {

“_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

}

}

}

}

上面的命令,是定义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,是跟计算分值相关的。

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

POST test/test/1

{

“test”:“美国留给伊拉克的是个烂摊子吗”

}

POST test/test/2

{

“content”:“公安部:各地校车将享最高路权吗”

}

POST test/test/3

{

“content”:“中韩渔警冲突调查:韩警平均每天扣1艘中国渔船”

}

POST test/test/4

{

“content”:“中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首”

}

最后,执行查询进行测试

GET test/_search

{

“query” : { “term” : { “content” : “中国” }},

“highlight” : {

“pre_tags” : ["", “”],

“post_tags” : ["", “”],

“fields” : {

“content” : {}

}

}

}

得到返回结果:

{

“took”: 4,

“timed_out”: false,

“_shards”: {

“total”: 5,

“successful”: 5,

“failed”: 0

},

“hits”: {

“total”: 2,

“max_score”: 1.5,

“hits”: [

{

“_index”: “test”,

“_type”: “test”,

“_id”: “4”,

“_score”: 1.5,

“_source”: {

“content”: “中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首”

},

“highlight”: {

“content”: [

“中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首”

]

}

},

{

“_index”: “test”,

“_type”: “test”,

“_id”: “3”,

“_score”: 0.53699243,

“_source”: {

“content”: “中韩渔警冲突调查:韩警平均每天扣1艘中国渔船”

},

“highlight”: {

“content”: [

“中韩渔警冲突调查:韩警平均每天扣1艘中国渔船”

]

}

}

]

}

}

安装elasticsearch-analysis-pinyin分词器

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

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

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

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

简单的测试

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

PUT medcl

{

“index” : {

“analysis” : {

“analyzer” : {

“pinyin_analyzer” : {

“tokenizer” : “my_pinyin”,

“filter” : “word_delimiter”

}

},

“tokenizer” : {

“my_pinyin” : {

“type” : “pinyin”,

“first_letter” : “none”,

“padding_char” : " "

}

}

}

}

}

然后使用analyze api,进行测试

GET medcl/_analyze

{

“text”:“刘德华”,

“analyzer”:“pinyin_analyzer”

}

可以得到结果:

{

“tokens”: [

{

“token”: “liu”,

“start_offset”: 0,

“end_offset”: 3,

“type”: “word”,

“position”: 0

},

{

“token”: “de”,

“start_offset”: 0,

“end_offset”: 3,

“type”: “word”,

“position”: 1

},

{

“token”: “hua”,

“start_offset”: 0,

“end_offset”: 3,

“type”: “word”,

“position”: 2

}

]

}

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

{

“tokens”: [

{

“token”: “ldh”,

“start_offset”: 0,

“end_offset”: 3,

“type”: “word”,

“position”: 0

}

]

}

模拟测试

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

POST medcl/_close

{

}

然后设置分词器配置

PUT medcl/_settings

{

“index” : {

“analysis” : {

“analyzer” : {

“pinyin_analyzer” : {

“tokenizer” : “my_pinyin”,

“filter” : [“word_delimiter”,“nGram”]

}

},

“tokenizer” : {

“my_pinyin” : {

“type” : “pinyin”,

“first_letter” : “prefix”,

“padding_char” : " "

}

}

}

}

}

打开索引

POST medcl/_open

{

}

定义映射类型

POST medcl/folks/_mapping

{

“folks”: {

“properties”: {

“name”: {

“type”: “multi_field”,

“fields”: {

“name”: {

“type”: “string”,

“store”: “no”,

“term_vector”: “with_positions_offsets”,

“analyzer”: “pinyin_analyzer”,

“boost”: 10

},

“primitive”: {

“type”: “string”,

“store”: “yes”,

“analyzer”: “keyword”

}

}

}

}

}

}

提交样例数据

POST medcl/folks/1

{

“name”:“刘德华”

}

执行查询

GET medcl/folks/_search

{

“query”: {“match”: {

“name”: “l d hua”

}}

}

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

得到结果

{

“took”: 7,

“timed_out”: false,

“_shards”: {

“total”: 5,

“successful”: 5,

“failed”: 0

},

“hits”: {

“total”: 1,

“max_score”: 7.408082,

“hits”: [

{

“_index”: “medcl”,

“_type”: “folks”,

“_id”: “1”,

“_score”: 7.408082,

“_source”: {

“name”: “刘德华”

}

}

]

}

}

最佳实战

ElasticSearch实战:IK中文分词插件

官方文档

/medcl/elasticsearch-analysis-ik

/archive/p/ik-analyzer/ 这里使用了腾讯云ElasticSearch服务,已默认集成了IK中文分词插件,因此安装过程略。

我们为什么要使用IK分词插件

2.1 示例

我们以下面这个例子来做说明

1)创建索引与映射

PUT tencent

POST /tencent/bh8ank/_mapping

{

“properties”: {

“content”: {

“type”: “text”

}

}

}

2)上传数据

POST /tencent/bh8ank/1

{

“content”: “《王者荣耀》是由腾讯游戏天美工作室群开发并运行的一款运营在Android、IOS、NS平台上的MOBA类手机游戏”

}

POST /tencent/bh8ank/2

{

“content”: “谁是行业的王者?国内细分行业龙头公司最全名单汇总”

}

POST /tencent/bh8ank/3

{

“content”: “一个衰落行业的王者!还有多少荣耀?”

}

POST /tencent/bh8ank/4

{

“content”: “王小二,1999年从中国人民大学新闻系毕业,以记者身份进入中央电视台”

}

3)检索数据

GET /tencent/bh8ank/_search

{

“query”: {

“match”: {

“content”:“王者荣耀”

}

}

}

此时,我们的目的,是搜索包含“王者荣耀”的结果,但实际上,搜索结果是:

我们会发现,搜索结果中,有部分结果,并不是我们想要的。当数据量庞大时,这种问题的影响会更深。

2.2 分析

ElasticSearch对中文文本的搜索,支持度很有限。使用标准分词器的情况下,会将一段文本,分成多个“词”(word),每个“词”实际上对应单独的一个汉字。如下图,标准分词器将“王者荣耀”分为了4个独立的汉字。所以,上一步中,检索结果返回了所有包含这4个独立汉字的内容。

那么问题来了,如果我们在检索“王者荣耀”时,只想要完整包含了“王者荣耀”这个词的结果,需要怎么办呢?

我们需要一款支持中文的分词器,根据我们的需求,对中文进行分词。比如说,我们在上面检索之前,将“王者荣耀”设定为一个整体的、不可拆分的“词”,在检索时,只有完整包含“王者荣耀”这个词的结果才会被匹配,其他没有完整包含关键词的结果不能被匹配。

IK中文分词器就实现了上述的功能。 IK Analyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。 从12月推出1.0版开始, IKAnalyzer已经推出了4个大版本。 最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。 从3.0版本开始,IK发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。 在版本中,IK实现了简单的分词歧义排除算法,标志着IK分词器从单纯的词典分词向模拟语义分词衍化。

3. IK中文分词插件怎么使用

下面,我们创建一个新的集群,仍以上面的检索为例。使用IK后,重新检索。

3.1 创建索引和映射

PUT tencent

POST /tencent/bh8ank/_mapping

{

“properties”: {

“content”: {

“type”: “text”,

“analyzer”: “ik_smart”, ##指定索引内容使用ik_smart分词

“search_analyzer”: “ik_smart” ##指定检索时,使用ik_smart分词

}

}

}

3.2 上传数据

POST /tencent/bh8ank/1

{

“content”: “《王者荣耀》是由腾讯游戏天美工作室群开发并运行的一款运营在Android、IOS、NS平台上的MOBA类手机游戏”

}

POST /tencent/bh8ank/2

{

“content”: “谁是行业的王者?国内细分行业龙头公司最全名单汇总”

}

POST /tencent/bh8ank/3

{

“content”: “一个衰落行业的王者!还有多少荣耀?”

}

POST /tencent/bh8ank/4

{

“content”: “王小二,1999年从中国人民大学新闻系毕业,以记者身份进入中央电视台”

}

3.3 检索数据

GET /tencent/bh8ank/_search

{

“query”: {

“match”: {

“content”:“王者荣耀”

}

}

}

查看结果,我们发现,并没有像我们期待的那样只返回完整包含了“王者荣耀”的结果,而是依旧返回了很多我们不需要的结果。如下图:

那么,问题出在哪里呢?

我们来看看,ik_smart是如何处理“王者荣耀”的,默认情况下,ik_smart对“王者荣耀”的拆分处理:

如上图,ik_smart将“王者荣耀”拆分为了两个词“王者”和“荣耀”,因此,在上一步检索时,返回了所有包含这两个词的结果。

那么,问题又来了,我们如何让IK插件准确地将“王者荣耀”识别为一个完整、独立的词呢?

3.4 上传启用词库

IK插件提供了启用词库的功能,这个功能,通过用户上传自定义的词库来实现。词库中定义的词,将不会被拆分,而是直接当做一个完整、独立的词来处理。

词库的制作需要注意两点:1,后缀以.dic格式命名;2,文件内容为utf-8编码,每行一个词

因此,我们需要制作一个词库,如下图:

然后上传至当前使用了ElasticSearch集群,如下图:

等待几分钟,词库生效。

3.5 再次检索数据

GET /tencent/bh8ank/_search

{

“query”: {

“match”: {

“content”:“王者荣耀”

}

}

}

查看检索结果,如下图上传启用词库后的检索结果:

4. 总结

IK中文分词插件的其他相关内容这里暂不赘述。启用词库的作用,主要是方便用户对某些自定义的词组进行统一处理,避免因拆分过度导致出现非期望的检索结果。

参考文章

更多相关知识和参考文章来源可以关注我的博客站点

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。