设为首页 收藏本站
查看: 1028|回复: 0

[经验分享] 关于Solr搜索标点与符号的中文分词你必须知道的(mmseg源码改造)

[复制链接]

尚未签到

发表于 2015-7-16 12:33:13 | 显示全部楼层 |阅读模式
关于Solr搜索标点与符号的中文分词你必须知道的(mmseg源码改造)

摘要:在中文搜索中的标点、符号往往也是有语义的,比如我们要搜索“C++”或是“C#”,我们不希望搜索出来的全是“C”吧?那样对程序员来说是个噩梦。然而在中文分词工具mmseg中,它的中文分词是将标点与符号均去除的,它认为对于中文来讲标点符号无意义,这明显不能满足我们的需求。那么怎样改造它让它符合我们的要求呢?本文就是针对这一问题的详细解决办法,我们改mmseg的源代码。
关键字:Solr, mmseg, 中文, 分词, 标点, 符号, 语义
前提:Solr(5.0.0版本),mmseg4j(1.10.0版本)
作者:王安琪(博客地址:http://www.iyunv.com/wgp13x/)

0、Solr的mmseg默认中文分词效果
做个实验,入Solr的语句为:t#\"\&\*CTY  C# "#"&*^#とう華뭄내ㅛ  #\"\&\*C8:8。3  C# \"#\"&*^#√とう ,使用的是mmseg中的“max-word”型分词。分词后会变成什么样呢?在对Solr进行简单的mmseg配置操作后,我们在Solr的Analysis中对以上语句进行分析,如下图所示。
DSC0000.jpg
图0-1 mmseg默认中文分词效果
      
从上图中可以看出,默认的mmseg“max-word”型分词将所有的标点、符号都抛弃掉了,余下的只是中文、数字、英文、韩文、日文等。经过mmseg的其他类型如:“complex”和“simple”分析操作后,其结果也是把所有的标点、符号均删除。然而使用Ansj进行中文分词的话,其默认是不删除标点符号的。使用IKAanalyzer来进行中文分词,它也删除掉所有的标点符号。具体情况见博客:中文分词器性能比较 http://www.iyunv.com/wgp13x/p/3748764.html。

mmseg在中文分词过程中删除标点符号,这直接导致搜索不出标点和符号,因为被删除的将不被建立索引,如:搜索“#”,返回的是所有。为了解释这个问题,我们分析一下Solr创建索引的过程。

1、Solr创建索引的过程
在创建索引的过程中,进入的每一句字符串,均依据fieldType中配置的:tokenizer及以下的filter,从上至下依次处理。正如下图所示的,当进入的字符串为 #Yummm :) Drinking a latte at ... 第一步经过StandardTokenizer后,变成了一个个单词:Yummm | Drinking | a | latte | at | ,可以看出这一步就已经将标点符号去除掉了,并使用标点符号和空格将句子划分成一个个单词。第二步经过的是StopFilter,它将stop words:a at in 等删掉,它认为他们是无语义的词汇,这要看具体情况了,这步结束后原文变成了:Yummm | Drinking | latte | 。第三步是经过LowercaseFilter,很明显从字面上解释就是把所有的单词小写化,最终的结果是:yummm | drinking | latte |。

DSC0001.jpg 图1-1 Solr创建索引的过程

在搜索的过程中,新入的搜索字符串,也需要经历这几个过程,再将经历这些过程后的单词以“与”或“或”的关系,进行搜索。这就解释了,上一个问题,为什么输入的搜索条件是“#”,返回的是所有,因为条件经历这些过程后,条件是空,即搜索所有了。


2、Solr的mmseg经过改进后的中文分词效果
经过我们的改进,在入Solr的语句为:!,工;1 - 低 ... 时, 中文分词效果如下图所示。

DSC0002.jpg
图2-1 mmseg经过改进后的中文分词效果

从上图可以看到,经过MMST后,所有的单词都已经大写小化了,所以可以去除LowerCaseFilter,对结果不影响,即在配置中将去掉。再次分析的效果如下图所示:

DSC0003.jpg
图2-2 mmseg经过改进后并去除LowerCaseFilter后的中文分词效果

可以看出,C++这样输入的输出变成了:c | + | +,这样的话,当搜索条件为入C++时,便可以匹配出来了!这正是我们想要的。最终效果可以从下图中看出,在图2-3中将一串带有标点符号的字符串添加入Solr的mmseg fild中。在图2-4中对mmseg fild搜索带有标点符号的字符串,可以看到,刚添加的字符串被正确搜索到了!

DSC0004.jpg           图2-3 添加带有标点符号的Document   

DSC0005.jpg
图2-4 搜索条件带有标点符号的搜索结果


3、Solr的mmseg的中文分词效果改进办法
首先,根据mmseg作者chenlb  https://github.com/chenlb/mmseg4j-solr 的提示与启发,可以在next()函数中进行修改源码,以达到不去除标点符号的目的。我们在mmseg源码中找到MMSeg类中存在next()函数,通过阅读源码,我们知道,这即是对已识别的各种类型的字符进行分门别类地处理,如数字、字母、韩语等。函数内对其他的字符均视为无效字符,其中标点与符号便落入了此类别,其对此类别的字符处理办法是:“不理睬”。下面就是我依照中文字符的处理过程,编写了标点与符号的处理过程,同时对空格及Tab、\n这些字符采取“不理睬”策略,因为他们真的是无语义的,具体的代码如下。




public Word next() throws IOException {
// 先从缓存中取
    Word word = bufWord.poll();
;
if (word == null) {
bufSentence.setLength(0);
int data = -1;
boolean read = true;
while (read && (data = readNext()) != -1) {
read = false; // 默认一次可以读出同一类字符,就可以分词内容
int type = Character.getType(data);
String wordType = Word.TYPE_WORD;
switch (type) {
。。。。。。。。
case Character.SPACE_SEPARATOR:
case Character.CONTROL:
read = true;
break;
default:
// 其它认为无效字符
// read = true;
                bufSentence.appendCodePoint(data);
readChars(bufSentence, new ReadCharByType(type));
// bufWord.add(createWord(bufSentence, Word.TYPE_LETTER));
                currentSentence = createSentence(bufSentence);
bufSentence.setLength(0);
}// switch  
// 中文分词
if (currentSentence != null) {
do {
Chunk chunk = seg.seg(currentSentence);
for (int i = 0; i < chunk.getCount(); i++) {
bufWord.add(chunk.getWords());
}
} while (!currentSentence.isFinish());
currentSentence = null;
}
word = bufWord.poll();
}
return word;
}
  


经过编译后,将MMSeg类相关的class替换到mmseg4j-core-1.10.0.jar目录下,如图3-1所示。然后重新部署Solr,一切运行正常!

DSC0006.jpg
图3-1 编译并替换MMSeg




4、Solr的配置补充
经过刚才的操作,已经解决了标点与符号删除的问题。下面讲一下autoGeneratePhraseQueries的配置。

DSC0007.jpg
图4-1 mmSeg配置

如上图的配置所示,autoGeneratePhraseQueries="false",autoGeneratePhraseQueries配置为false有下面的作用:将搜索关键词分词后,以或的条件进行搜索,比如入的是 DSC0008.jpg ,搜索关键词是 DSC0009.jpg ,关键词经过分词后有些分词结果不在Doc范围内,但是仍旧可以搜索出来;然而如果autoGeneratePhraseQueries="true" ,则搜索不出来,此时是且的关系。

这简直是太棒了!



来自王安琪  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-87305-1-1.html 上篇帖子: Spring Data Solr教程(翻译) 下篇帖子: solr定时增量索引
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表