高峰只对攀登它而不是仰望它的人来说才有真正意义。

关于同义词检索方案的一点实践经验

Elasticsearch | 作者 Jinyang Zhou | 发布于2018年06月15日 | | 阅读数:7994

最近一直在搞同义词搜索的问题,踩了一些坑,总结了一些经验,尤其是刚刚接触搜索和 ES,所以如果有不对的,或者不完备的地方也希望大家能提出改进意见。。。

下面是自己留下的文档记录:


需求

同义词检索也是搜索引擎必备的功能之一,例如,我们希望用户在搜索广东话的同时,也能找出和粤语有关的信息;用户在搜索苹果手机的同时,包含iPhone的内容也能被检索并呈现。

在现实生活中,相同语义的表述词汇往往有很多,而用户在检索的时候很难在一条 query 中将它们全部体现,所以识别和提供同义词检索显然可以获得更高的召回率。

需求剖析

在思考解决方案之前,我们不妨再来看看刚才提到的两个例子:

  1. 苹果手机iPhone
  2. 广东话粤语

我们先来看第一个,苹果手机iPhone

显然,这两个词是等价的,因为苹果公司发布的所有手机产品都叫 iPhone,而 iPhone 这个名字也没有被其他公司使用过。

于是,当用户搜索“苹果手机购买”的时候,我们也就有理由将它拆分成“苹果手机购买”和“iPhone购买”,分别进行检索,再将结果合并返回。


语言学中对这样的词组,称为是同义词中的相对同义词,或是等义词等义同义词。它们表达意思完全一致,在绝大多数语境中都可以相互替换,同时对上下文也不会产生影响。

这样的词组还有很多,例如:猫熊熊猫柚子文旦等等,这些等义词大抵来说有这样几种来源:

  1. 音节减缩形成:机枪机关枪坦克坦克车电扇电风扇
  2. 音译和音译形成:出租车的士维生素维他命
  3. 地域叫法不同,或新旧叫法:单车自行车脚踏车西红柿番茄马铃薯洋芋土豆黄瓜胡瓜
  4. 昵称代称:周杰伦周董
  5. 描述角度不同,学名方言差异:电脑计算机曲别针回形针

这些词组多以名词呈现,数量比较少,词组规模也较小,同时变化也很小。


接下来我们再来看第二组词:广东话粤语

广东话粤语这两个词代表的意思是相同的吗?它们也是可以相互替换的吗?

答案显然是否定的。

广东话从语义本身来说是一个比较粗糙的概念,它不仅指广东省内的粤语,还涵盖了潮汕话,客家话,雷州话等其他方言。而粤语却是一个非常严肃的概念,对语音语调都有非常详细的规定,不仅通用于广东省大部分地区,还包括广西、香港、澳门等地,甚至东南亚和北美。它们联系在于,大部分广东地区的人说的是粤语。

如此说来,给广东话粤语这样非常相似却又并不完全一致的词直接划上等号是有失偏颇的。当然,其实仔细考虑也不难发现,和广东话有相似之处却又不完全相同的词还有很多,例如:客家话广州话广府话等等。


语言学中把这样的词汇,称作是相对同义词,或是近义词。它们在意义上有一些相似之处,只能在特定的语境中进行替换。

它们的差别可能包括:

  1. 语义上:毁坏损坏(前者更严重),介绍说明(前者可以对人施加作用)
  2. 色彩上:团结勾结

对于这类相似却又不完全相同的近义词,在搜索的时候提供关联搜索是一个不错的方案。例如用户搜索“毁坏公物如何处罚”的时候,查询结果可以由90%的“损坏公物如何处罚”和10%的“毁坏公物如何处罚”查询结果合并后返回,从而获得更多的召回。

这些近义词以动词为主,不仅数量多,词组的规模也大,例如靠近的近义词可以是:靠拢逼近接近迫近等等。

解决思路

可替换的等义词问题中,我们可以直接使用 Elasticsearch 原生的 synonyms 功能来完成。虽说原生 synonyms 功能不支持热更新,而且需要将词典事先放进制定目录,不过好在这类等义词数量并不多,变化也并不大,尚且属于一劳永逸的任务。

对于不可直接替换的近义词问题,如果直接套用原生的 Synonyms 虽然可能会带来更多召回,但是查准率却骤降。

对于这类问题,我们期待的场景是,一旦发现用户 query 中的某个词有近义词,我们就将它拆分替换,成为多个 query 进行联合搜索。就像前面的例子:用户搜索“损坏公物如何处罚”的时候,查询结果可以由90%的“损坏公物如何处罚”和10%的“毁坏公物如何处罚”查询结果合并后返回。如此说来,使用 Elasticsearch 提供的 boosting_query 就成为了一个自然而然的想法。

不过稍加思考也不难发现,boosting_query 中 weight 的获得并不容易,也就是前面例子中的90%10%这组数字应该怎么设定,这也是近义词联合搜索中的重点。

先回到我们刚才的例子:当用户搜索“损坏公物如何处罚”的时候,我们本能地觉得用90%损坏10%毁坏合并在一起是“合理的”,这样的本能其实是来自于:我们主观地认为在检索“搞坏公物”这个事实的时候,90%的用户会使用毁坏来描述,10%的用户会使用损坏来描述。

简而言之,这组数字可以理解为用户群体描述同一个问题时,对词组选择的组成比例。再换个说法,也就是在当前这条 query 中,原词和近义词之间的可替换程度

再举一例,在“广东话入门”这条 query 中,从“表达学习语言”的语义上来看,广东话粤语差别并不大,这条 query 自然可以拆分成“广东话入门”和“粤语入门”,进行联合搜索,而且它们的 weight 甚至可以设置为 1:1 来获得更多合理的召回。

反过来,在“粤语歌曲推荐”这条 query 中,广东话的 weight 就需要慎重考虑,一方面是因为本身就没有“广东话歌曲”这种说法,另一方面也因为在广泛的语料中,歌曲广东话这两个词极少同时被提及。所以几遍是“粤语歌曲推荐”的拆分成分中有“广东话歌曲推荐”,weight 也需要被设置地非常低(倘若真的没有“粤语歌曲”相关的内容,推荐“广东话”的内容作为替补)。

说到这里,其实已经很明白了,语言模型是可以在这里被使用的,而语言模型的困惑度也与前面提到的 weight 一脉相承。

所以大致计算流程可以是:获得用户的query之后进行分词,在词组中寻找所有可能的同义词替换,将所有替换后的 query 分别放进语言模型中获得困惑度(或其他 metrics),依据它们来作为 boosting query 中的 weight。

graph TD;
广东话入门-->'广东话','入门';
'广东话','入门'-->_'广东话','入门'_;
'广东话','入门'-->_'粤语','入门'_;
_'广东话','入门'_-->语言模型;
_'粤语','入门'_-->语言模型;
语言模型-->PPL:0.65;
语言模型-->PPL:0.35;

对于这里语言模型的选择,可以使用传统的ngram,也可以使用双向的LSTM这样一些成熟的方案从语料中训练,也可以使用一些现成的方案:http://ai.baidu.com/tech/nlp/dnnlm_cn


[尊重社区原创,转载请保留或注明出处]
本文地址:http://elasticsearch.cn/article/671


0 个评论

要回复文章请先登录注册