中文的搜索和英文的搜索最大不同之处在于分词,英文分词可以通过空格,而中文的分词则复杂很多,分词会直接影响用户的搜索使用体验,在一些大公司甚至会使用机器学习的方式进行分词。在这篇文章中笔者主要讲解ES中文分词相关的优化。
1. 网络新词
网络上经常会出现一些新词,比如“蓝瘦香菇”,蓝瘦香菇默认情况下会被分词,分词结果如下所示
蓝,瘦,香菇
这样的分词会导致搜索出很多不相关的结果,在这种情况下,我们使用扩展词库,以ik分词器为例,我们可以在/config/analysis-ik下创建一个my.dic。将”蓝瘦香菇”添加其中,修改IKAnalyzer.cfg.xml,修改IKAnalyzer.cfg.xml配置文件如下所示
重启ES,重试ik_smart分词器,分词如下所示
蓝瘦香菇
2. 分词器
分词器会直接影响分词效果。比如分别使用ik_max_word和ik_smart分别对”上海市”这个词进行分词,分词效果分别如下所示
ik_max_word
上海市,上海,海市
ik_smart
上海市
Ik_max_word分词器分词的粒度更加细,如果将它用于搜索阶段,以上文中的“上海市”这个关键词为例,分词结果“海市”关键词会搜索出很多不相关的结果,所以ik_max_word分词器建议仅仅用于索引阶段。Ik_smart分词粒度较粗,适用于搜索阶段,可以避免搜索出不相关的结果。
3. 停顿词
使用ik_max_word对短语” 美丽的世界”进行分词,分词结果如下
美丽,的,世界
上文中的”的”是一个停顿词,停顿词是一些没有意义的词语,除此之外,还有了,也,则,而等等。停顿词会干扰用户搜索结果,影响查询速度,如果用户的查询关键词中包含这些停顿词,搜索结果中会包括特别多的无实际意义的结果。所以我们需要屏蔽这些无意义的停顿词语,ES实现了该功能,ES将停顿词配置在如下两个配置文件中。
stopword.dic
extra_stopword.dic
其中stopword.dic包含了英文的停顿词比如the,and,if。而中文的停顿词放在了extra_stopword.dic当中,新增的停顿词都放在extra_stopword.dic中,extra_stopword.dic默认不生效,如果我们想让extra_stopword.dic生效,我们可以配置IKAnalyzer.cfg.xml中ext_stopwords项目,使得extra_stopword.dic生效
配置完成之后,再对短语”美丽的世界‘’进行优化,分词结果如下所示,这个时候就不会有停顿词了
美丽,世界
4. 同义词
如下有一篇文档
bilibili是国内知名的视频网站
笔者希望在搜索b站,bilibili,哔哩哔哩,弹幕网的时候都能搜索出上面的这篇文档。这种需求需要使用同义词搜索,当搜索b站的时候也会搜索bilibili,哔哩哔哩,弹幕网这几个关键词,而搜索bilibili的时候也会搜索出b站,哔哩哔哩,弹幕网, bilibili。ES提供的同义词分词过滤器可以解决这个问题,使用步骤如下
首先创建同义词词典synonyms.txt文件,内容如下所示
b站,哔哩哔哩,弹幕网, bilibili => b站,哔哩哔哩,弹幕网, bilibili
自定义分析器,这个分析器是具有同义词作用的ik分词器
PUT http://{{host}}:{{port}}/test2/_settings
{
"settings": {
"analysis": {
"filter": {
"my_synonym_filter": {
"type": "synonym",
"synonyms_path": "analysis/synonyms.txt"
}
},
"analyzer": {
"my_synonyms_analyzer": {
"tokenizer": "ik_smart",
"filter": [
"my_synonym_filter"
]
}
}
}
}
}
synonyms_path指的是同义词词典所在的路径
设置如下所示的mapping
POST http://{{host}}:{{port}}/test2/test/_mapping
{
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "my_synonyms_analyzer"
}
}
}
测试分析器
http://{{host}}:{{port}}/test2/_analyze?analyzer= my_synonyms_analyzer
{
"text": "b站"
}
笔者预期分析器会给出如下分词结果
b站,哔哩哔哩,弹幕网, bilibili
但是实际得到的分词结果如下
b,站
这是为什么呢?请看如下这张图,查询关键词首先会经过字符过滤器,随后是分词器,随后是分词过滤器,同义词处理其实也是分词过滤器的一种,用户输入查询关键词后,查询关键词经过分词器后,”b站”这个词就不是一个完整的词了,就变成了“b”和“站”,这两个词在同义词词典里找不到同义词,就不会有哔哩哔哩,弹幕网, bilibili这些同义词了
如何处理呢,就是将b站,哔哩哔哩,弹幕网关键字加入到扩展词典中,就能避免被分词了。添加之后再次进行测试,测试结果就为预期所示了
b站,哔哩哔哩,弹幕网, bilibili