elasticsearch添加拼音分词搜索
分词器是es当中的一个组件,通俗来讲,就是将搜索的条件按照语义进行拆分,分词为多个词语,es会讲text格式的字段按照分词器的结果进行分词,并编排成倒排索引,正因为如此,es的查询速度才会很快,es当中本身就内置了很多分词器
分词器 | 作用 |
---|---|
Standard | ES的默认分词器,按单词分类并进行大小写处理 |
Simple | 按照非字母区分,然后去除非字母并按小写进行处理 |
Stop | 按照停顿词进行过滤并进行小写处理,停用词包括the a is |
Whitespace | 按照空格进行拆分 |
Patter | 按照正则进行拆分,默认是\W+ ,代表非字母 |
Keyword | 不进行分词,作为一个整体输出 |
es的默认分词器为Standard,对中文分词时会全部拆分为单个字并过滤掉特殊字符
说到分词器,不得不提及中文分词器ik,这里只描述es中的ik分词器
ik分词器
ikAnalyzrer是一个开源的,基于java语言开发的轻量级的中文分词工具包,新版本的ik分词器发展为面向java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认实现
ik分词器默认有两种分词模式:
ik_max_word(常用模式)将文本做最细粒度拆分
ik_smart 将文本做粗粒度拆分
ik_smart分词
GET book/_analyze
{
"analyzer": "ik_smart",
"text": ["武当山上张三丰"]
}
{
"tokens" : [
{
"token" : "武当",
"start_offset" : 0,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 0
},
{
"token" : "山上",
"start_offset" : 2,
"end_offset" : 4,
"type" : "CN_WORD",
"position" : 1
},
{
"token" : "张三丰",
"start_offset" : 4,
"end_offset" : 7,
"type" : "CN_WORD",
"position" : 2
}
]
}
使用ik_max_word分词
GET book/_analyze
{
"analyzer": "ik_max_word",
"text": ["武当山上张三丰"]
}
{
"tokens" : [
{
"token" : "武当山",
"start_offset" : 0,
"end_offset" : 3,
"type" : "CN_WORD",
"position" : 0
},
{
"token" : "武当",
"start_offset" : 0,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 1
},
{
"token" : "山上",
"start_offset" : 2,
"end_offset" : 4,
"type" : "CN_WORD",
"position" : 2
},
{
"token" : "张三丰",
"start_offset" : 4,
"end_offset" : 7,
"type" : "CN_WORD",
"position" : 3
},
{
"token" : "张三",
"start_offset" : 4,
"end_offset" : 6,
"type" : "CN_WORD",
"position" : 4
},
{
"token" : "三",
"start_offset" : 5,
"end_offset" : 6,
"type" : "TYPE_CNUM",
"position" : 5
},
{
"token" : "丰",
"start_offset" : 6,
"end_offset" : 7,
"type" : "CN_CHAR",
"position" : 6
}
]
}
可以明显的看到ik_max_word拆分的更细一些,实际使用时一般写入数据时使用ik_max_word,查询数据时使用ik_smart(如果没有search_analyzer,默认使用analyzer)
一般安装了ik中文分词器可以满足大部分的场景,但是很多使用用户并不一定搜的是中文,输入法的原因可能输入的拼音,为了满足用户也为了搜索更加精准,扩展的分词器有拼音分词器、同义字分词器、繁体字转简体字等等,这里总结一下es使用拼音分词器
安装拼音分词器
项目地址:https://github.com/medcl/elasticsearch-analysis-pinyin
源码大致原理为调用nlp工具包https://github.com/NLPchina
1、下载完项目之后需要根据自己当前的es版本选择代码分支
这里我的版本是7.17.4所以使用7.x这个分支的代码
2、修改pom.xml中的elasticsearch.version为自己的版本
3、mvn install之后在target文件夹elasticsearch-analysis-pinyin-xxx.jar复制到es安装目录plugins目录底下,解压之后后看到elasticsearch-analysis-pinyin-7.17.4.jar、 plugin-descriptor.properties和nlp-lang-1.7.jar
4、重启es,线上环境要注意
安装完成我们可以重构索引,使用pinyin分词器
这里有一些tokenizer参数
参数 | 默认值 | 描述 | 分词结果 |
---|---|---|---|
keep_first_letter | true | 保留字符首个拼音 | 刘德华 -> ldh |
keep_separate_first_letter | false | 会将首字母单独拆分为一个token | 刘德华>[l,d,h] |
limit_first_letter_length | 16 | 设置首字母最大长度 | |
keep_full_pinyin | true | 每个字符的全拼 | 刘德华> [liu,de,hua] |
keep_joined_full_pinyin | false | 每个字符的全拼连接 | 刘德华> [liudehua] |
这里我们新建索引pinyin_test进一步测试
PUT pinyin_test
{
"settings": {
"analysis": {
"analyzer": {
"pinyin_analyzer": {
"tokenizer": "my_pinyin"
}
},
"tokenizer": {
"my_pinyin": {
"type": "pinyin",
"keep_first_letter": true,
"keep_separate_first_letter": false,
"keep_full_pinyin": true,
"keep_original": true,
"limit_first_letter_length": 16,
"lowercase": true,
"remove_duplicated_term": true,
"keep_separate_chinese": true
}
}
}
},
"mappings": {
"properties": {
"name": {
"type": "keyword",
"fields": {
"pinyin": {
"type": "text",
"analyzer": "pinyin_analyzer"
}
}
}
}
}
}
创建索引的时候指定name字段的分词器为pinyin_analyzer, 注意这里的 tokenizer里的名称不能是pinyin,如果写成pinyin所有的参数都是默认的,不利于我们定制不同的字段分词器。 这里我们先使用analyzer,不使用search_analyzer
插入数据
POST pinyin_test/_doc
{
"name": "少年歌行"
}
POST pinyin_test/_doc
{
"name": "骚年歌行"
}
POST pinyin_test/_doc
{
"name": "少年歌杭"
}
下面我们查看分词的结果
GET pinyin_test/_analyze
{
"analyzer": "pinyin_analyzer",
"text": "少年歌行"
}
{
"tokens" : [
{
"token" : "shao",
"start_offset" : 0,
"end_offset" : 0,
"type" : "word",
"position" : 0
},
{
"token" : "少年歌行",
"start_offset" : 0,
"end_offset" : 0,
"type" : "word",
"position" : 0
},
{
"token" : "sngx",
"start_offset" : 0,
"end_offset" : 0,
"type" : "word",
"position" : 0
},
{
"token" : "nian",
"start_offset" : 0,
"end_offset" : 0,
"type" : "word",
"position" : 1
},
{
"token" : "ge",
"start_offset" : 0,
"end_offset" : 0,
"type" : "word",
"position" : 2
},
{
"token" : "xing",
"start_offset" : 0,
"end_offset" : 0,
"type" : "word",
"position" : 3
}
]
}
可以看到的拆分后的token中含有我们需要的拼音,因为keep_first_letter设置为true所以可以看到sngx,
GET pinyin_test/_search
{
"query": {
"match_phrase": {
"name.pinyin": "shao年歌行"
}
}
}
搜索结果
但是当搜索 少年gexing 的时候,期望结果是只有少年歌行一条结果
但是可以看到骚年歌行也出来了,这是因为keep_separate_first_letter改为true之后骚年歌行也会包含s
针对这种情况,有位老哥提了issue并且作者合到了master分支,在tokenizer中添加参数keep_separate_chinese:true,可以保证在中文加拼音的时候,优先匹配到中文汉字,然后匹配拼音
https://github.com/medcl/elasticsearch-analysis-pinyin/issues/203
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析