热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ElasticSearchpinyin分词支持多音字

ElasticSearchpinyin分词支持多音字背景我们有一个搜索业务底层采用ElasticSearch作为搜索引擎,在索引的过程中,使用了ik中文分词、拼音分词、同义词等多种
ElasticSearch pinyin分词支持多音字

背景

我们有一个搜索业务底层采用ElasticSearch作为搜索引擎,在索引的过程中,使用了ik中文分词、拼音分词、同义词等多种分词器。ES和各种插件的组合已经能满足我们线上90%的需求,但是仍有部分需求无法覆盖,我们在拼音分词的时候过程中就遇到了无法解决的问题。

比如在 三一重工 中,一重 这个词在拼音词库 polyphone.txt 中有对应的词汇,读作 yichong,因此这整个词的读音为 sanyichonggong, 但是其真实读音应该为 sanyizhonggong。这是因为在拼音分词过程中会先去词库中检索是否有对应的词汇,没有的话再用单字拼音代替最后拼接在一起。

再比如在 蔚来汽车 中,蔚来 算是一个新词,在拼音词库 polyphone.txt 中没有对应的词汇,因此这个词对应的拼音是每个字的拼音拼接而成,结果为 yulai 。但是其真实读音应该为 weilai, 那么我们的用户就无法通过拼音 weilai 搜索到相关的内容。

经过查看拼音分词源代码发现,拼音分词其实是调用nlp-lang这个项目里的方法实现的分词器。而这个nlp-lang项目中,拼音解析如果遇到多音字仅仅返回第一个拼音,这样很多读音都无法获取到。

if(temp.length()==1){
//单个字取第一个拼音
lists.add(PinyinFormatter.formatPinyin(word.getParam()[0], format));
} else {
for (String t : word.getParam()) {
lists.add(PinyinFormatter.formatPinyin(t, format));
}
}

面对庞大的多音字列表,通过手工维护、修改词汇列表显然无法完全达到目的。

为此,我们决定调整这部分代码满足我们线上业务的需求。

调整

这部分仅仅介绍调整思路,不设计具体代码实现。

1. nlp-lang

拼音分词会调用 nlp-lang 中的一个方法,把中文字符串转换为拼音,获得一个字符串列表

List<String> pinyinList = Pinyin.pinyin(source);

我们在这个基础上新增了一个 multiplePinyin 方法,可以获取多音字所有读音,并且不再检索 polyphone.txt 中的词库对照表。

System.out.println(Pinyin.pinyin("蔚来"))
>>> ['yu', 'lai']
System.out.println(Pinyin.multiplePinyin("蔚来"))
>>> ['yu wei', 'lai']
System.out.println(Pinyin.pinyin("三一重工"))
>>> ['san', 'yi', 'chong', 'gong']
System.out.println(Pinyin.multiplePinyin("三一重工"))
>>> ['san', 'yi', 'zhong chong', 'gong']

多音字的多个读音用空格分割。

2. elasticsearch-analysis-pinyin

  1. 首先在原来的分词器基础上新增 multiple_pinyin 类型的分词器和过滤器,确保不会影响到之前的拼音分词的功能。

public Map<String, AnalysisModule.AnalysisProvider<org.elasticsearch.index.analysis.TokenFilterFactory>> getTokenFilters() {
Map<String, AnalysisModule.AnalysisProvider<org.elasticsearch.index.analysis.TokenFilterFactory>> extra = new HashMap<>();
extra.put("pinyin", PinyinTokenFilterFactory::new); // 新增加的分词类型
extra.put("multiple_pinyin", MultiplePinyinTokenFilterFactory::new);
return extra;
}

  1. multiple_pinyin的分词器中使用上面新增的 Pinyin.multiplePinyin 方法获取到每个字的多音字。然后根据空格拆分后将所有可能的结果组合在一起。

// pinyin "蔚来"
["yulai"]
// multiple_pinyin "蔚来"
["yulai", "weilai"]
// pinyin "三一重工"
["sanyichonggong"]
// multiple_pinyin "三一重工"
["sanyizhonggong", "sanyichonggong"]
// pinyin "厦门重工" (两个多音字:夏、重)
["xiamenzhonggong"]
// multiple_pinyin "厦门重工"
["shamenzhonggong", "shamenchonggong", "xiamenzhonggong", "xiamenchonggong"]

问题

因为支持多音字的拼音分词是所有读音可能结果的笛卡尔积,因此当输入的字符串长度过大时,分词的结果可能会特别大。假如输入的字符串中有10个字是多音字,每个字都有2种读音,那么分词结果就有2^10个。可想而之,耗时会非常长。

我们的使用场景中,仅仅针对物品名称进行分词,名称不会很长,暂时没有遇到性能瓶颈。

相关代码

nlp-lang
elasticsearch-analysis-pinyin


推荐阅读
author-avatar
捕鱼达人2502868831
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有