说明
- es版本:5.1.1
- ik版本:5.1.2
- 开发:Java,TransportClient
http://blog.csdn.net/tianzhaixing2013/article/details/51506496
上面这个链接的这篇文章是es2.x版本+IK的近义词配置教程,es5.1的话一些地方还不一样。我从这篇文章中学到了不少,在此谢谢作者。
然后自己在此基础上改了改试了试,终于实现了近义词的功能。看网上关于es5.x配置近义词的资料很少,于是用Java api实现了之后,把过程记录下来供新学的小伙伴参考。
(文末也给出了rest接口方式实现的相关说明)
一. 建立Java工程
(略)
二. 新建近义词词库
首先在elasticsearch-5.1.1/config路径下新建近义词词库文件synonyms.txt。编码格式utf-8。
然后写入近义词内容,如下:
儿童, 婴儿, 幼儿, 婴幼儿, 初生儿
文胸 => 文胸, 内衣
这里注意逗号一定要是英文的,我最开始写成了中文的逗号,结果完成之后不起作用也不报错,让我还在怀疑这样的做法有问题。
另外解释下近义词的两种写法:
- 逗号隔开,如’儿童, 婴儿’。
可以配置多个词语,只要用逗号隔开就行。
这种格式代表所有词语之前都是互等的,当你索引内容中有’儿童’时,会将’儿童’分词为’儿童’和’婴儿’,并分别建立一个索引。 - 箭头隔开,如’文胸 => 文胸, 内衣’。
箭头左右都可以配置多个词语,也是用逗号隔开。但是这里逗号隔开的词语与上一种格式中’逗号隔开’所代表的意思无关。
这种格式代表箭头前面的词语可以分词为箭头后面的词语,但是箭头后面的词语不会分词为前面的词语。当你索引内容中有’文胸’时,会分词为’文胸’和’内衣’,并分别建立索引,但是当索引内容为’内衣’时,只会分词为’内衣’。
所以逗号隔开时,会对全部词语都建立索引;箭头隔开时,会对箭头右方的每个词语建立索引。
三. 定义自己的解释器
elasticsearch有一个synonym 的同义词filter,所以为了结合IK,我们需要借助IK定义自己的分词器。
在工程的resource文件夹下新建setting.json。内容如下:
{
"index": {
"analysis": {
"analyzer": {
"by_smart": {
"type": "custom",
"tokenizer": "ik_smart",
"filter": ["by_tfr", "by_sfr"],
"char_filter": ["by_cfr"] },
"by_max_word": {
"type": "custom",
"tokenizer": "ik_max_word",
"filter": ["by_tfr", "by_sfr"],
"char_filter": ["by_cfr"] }
},
"filter": {
"by_tfr": {
"type": "stop",
"stopwords": [" "] },
"by_sfr": {
"type": "synonym",
"synonyms_path": "synonyms.txt" }
},
"char_filter": {
"by_cfr": {
"type": "mapping",
"mappings": ["| => |"] }
}
}
}
}
这里by_smart和by_max_word就是自定义的分词器,分别使用ik_smart和ik_max_word做tokenizer,配合synonym类型的filter,完成近义词的功能。
char_filter里的by_cfr的作用就是可以把一个字符转换为另一个字符,如’& => and‘。了解更多见官方文档https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-mapping-charfilter.html
四. 定义索引中type的mapping
同样,在工程的resource文件夹下建立mapping.json。内容如下:
{
"properties": {
"title": {
"type": "text",
"index": "analyzed",
"analyzer": "by_max_word",
"search_analyzer": "by_smart"
}
}
}
在这里面title字段的分词器就指定成我们之前定义的分词器。
五. 调用api设置解释器和建立索引
......
String mapping = 读取setting.json的字符串;
String settings = 读取mapping.json的字符串;
CreateIndexResponse createIndexResponse = client.admin().indices().prepareCreate("indexname")
.setSettings(settings)
.addMapping("typename", mapping)
.get();
......
六. 测试
分词测试:
curl -XGET 'http://localhost:9200/indexname/_analyze?pretty&analyzer=by_smart' -d '{"text":"儿童"}'
返回结果:
{
"tokens" : [
{
"token" : "儿童",
"start_offset" : 0,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 0
},
{
"token" : "婴儿",
"start_offset" : 0,
"end_offset" : 2,
"type" : "SYNONYM",
"position" : 0
},
{
"token" : "幼儿",
"start_offset" : 0,
"end_offset" : 2,
"type" : "SYNONYM",
"position" : 0
},
{
"token" : "婴幼儿",
"start_offset" : 0,
"end_offset" : 2,
"type" : "SYNONYM",
"position" : 0
},
{
"token" : "初生儿",
"start_offset" : 0,
"end_offset" : 2,
"type" : "SYNONYM",
"position" : 0
}
]
}
七. REST接口方式(对应三、四、五步)
- 设置解释器
curl -XPUT 'http://localhost:9200/indexname' -d'
{
"index": {
"analysis": {
"analyzer": {
"by_smart": {
"type": "custom",
"tokenizer": "ik_smart",
"filter": [
"by_tfr",
"by_sfr"
],
"char_filter": [
"by_cfr"
]
},
"by_max_word": {
"type": "custom",
"tokenizer": "ik_max_word",
"filter": [
"by_tfr",
"by_sfr"
],
"char_filter": [
"by_cfr"
]
}
},
"filter": {
"by_tfr": {
"type": "stop",
"stopwords": [
" "
]
},
"by_sfr": {
"type": "synonym",
"synonyms_path": "synonyms.txt"
}
},
"char_filter": {
"by_cfr": {
"type": "mapping",
"mappings": [
"| => |"
]
}
}
}
}
}'
- 设置type的mapping
curl -XPUT 'http://localhost:9200/indexname/_mapping/typename' -d'
{
"properties": {
"title": {
"type": "text",
"index": "analyzed",
"analyzer": "by_max_word",
"search_analyzer": "by_smart"
}
}
}'
至此就是此篇文章的所有内容。有写得不对的地方,欢迎指正。有疑惑的地方,共同交流。