背景
一年一度科技春晚(IPhone新品发布会)召开之后,公司上线了iPhone14全系商品,上线后接上级领导反馈,搜索iPhone14无结果。经过排查,搜索数据库中确实存在iPhone14全系商品,通过iPhone、iPhone 14等关键词都可以召回。相信眼神儿好的同学,已经看出差别了,iPhone后有没有空格。
原因分析
搜索召回结果异常,往往是分词导致的。先看商品原数据,商品标题由运营人员手动输入,不同英文单词之间带有空格,例如iPhone 14 pro,如下图所示:
而用户搜索的query呢,往往是不会带有空格的,例如iPhone14,iPhone14promax。当前采用IK分词器,IK遇到空格会默认拆分成一个词。实际验证也印证了我的猜想。
IK默认词库,未添加定制分词。
GET /_analyze
{
"analyzer": "ik_max_word",
"text": ["iphone14promax"]
}
分词结果:
iphone14promax
iphone
14
promax
GET /_analyze
{
"analyzer": "ik_max_word",
"text": ["iphone 14 pro max"]
}
分词结果:
iphone
14
pro
max
面对没有空格的query,IK的分词结果出现了明显的偏差,iphone14promax被当成了一个词,pro和max也当成了一个词。不同分词之间采用and策略召回,因此分词上的巨大差异,导致商品无法被召回。
分词调整
在IK词库中添加以下词:
pro
max
iphone
来看下人工干预后的分词效果
iphone14promax
iphone
14
promax
pro
max
干预后的分词效果略好一些,成功识别了pro和max这两个词,但令人诧异的是,iphone14promax仍被当成一个词,而且还新增了promax,pro和max在词库中明确为两个词,IK的算法还是认成了一个词。
受限于IK分词器本身分词算法的限制,人工调整也无法解决分词准确度的问题
解决方案
更换更智能的分词器才是解决类似故障的正确方式,然而临时替换分词器不太现实,影响面太大。这里给出两个临时的方案,可以用来应急。
使用同义词
通过分词分析发现,IK会将整个query拆成一个词,这是导致无法被召回的关键,如果为query配置带有空格的同义词,同义词在查询时是or的逻辑,则可以被正常召回。
这里利用elasticsearch中自带的同义词插件,配置方式如下:
PUT /test_index/
{
"settings": {
"index" : {
"analysis" : {
"analyzer" : {
"default" : {
"tokenizer" : "ik_max_word",
"filter" : ["ik_synonym", "lowercase"]
}
},
"filter" : {
"ik_synonym" : {
"type" : "synonym",
"synonyms_path" : "analysis-ik/synonym.txt"
}
}
}
}
}
}
synonym过滤器添加的词,同样也会被IK进行分词处理。例如,为iphone14promax配置同义词iphone 14 pro max,iphone 14 pro max经过分词后,同数据库中文档的拆分方式一致,因此可以被召回。
去掉空格
既然分词故障由空格引起,那就可以在创建索引时,格外写入一条去除空格的数据,在查询时一起参与索引,这样相当于分别依据带空格和非空格数据创建两次索引,该方案的好处是不需要配置同义词,缺点是存储空间会增长一倍。
总结
搜索效果很大程度上依赖于分词器的性能,而开源分词器普遍在电商场景上优化不足,即使是业界先进的中文分词器,例如百度的LAC,Hanlp,在默认词库下,都无法正确分词iphone14promax。因此使用开源分词器,人工对分词结果的干预能力就非常重要了,而经过这次的故障,显然IK在这方面的不足非常明显。