在lucene 8.4.0中使用complex、nlp,全部报错,使用most正常,排查发现lucene添加索引时会调用JcsegTokenizer的incrementToken方法,该方法会调用NLPSeg中的next方法,该方法中会对eWordPool对象进行判断,如果不为空,会返回第一个对象,在含有多个对象的情况下,对象不是根据position进行排序,lucene中添加索引时判断position会出现异常,修改NLPSeg中的if ( eWordPool.size() > 0 ) {
return eWordPool.removeFirst();
}代码,如果eWordPool中含有多个对象,先对eWordPool根据position从小到大排序,然后返回return eWordPool.removeFirst(),测试正常
lucene从8.0版本开始一直有这个bug,这并不是Jcseg的bug。
#I185R8:jcseg 2.6.0版本complex模式下分词异常
麻烦贴下你的出错的测试文本,我看下8.4.0版本的更改!
complex模式也出现同样错误,测试发现对 “干熄焦、TRT发电等发电技术的引入”进行分词时,complex模式将“trt”拆分成t、r、t,调用Segmenter类中next方法,判断为英文,在第200行调用getNextLatinWord方法,在601行调用enWordSeg方法,在该方法中使用如下循环获取词条
while ( index < chars.length ) {
chunk = getBestChunk(chars, index, config.EN_MAX_LEN);
word = chunk.getWords()[0];
word.setPosition(pos+index);
wList.add(word);
index += word.getValue().length();
}
通过getBestChunk方法获取词条,该方法中调用getNextMatch方法IWord对象,测试发现,对“trt”进行拆分时,t、r返回的对象正常,第二个t返回的第一个t的对象,使用word.setPosition设置position时会造成第一个词条的position错误
测试临时解决办法:
修改Segmenter类中的第931行wList.add(dic.get(ILexicon.CJK_WORD, temp)),第940行wList.add(dic.get(ILexicon.CJK_WORD, _key)),第950行wList.add(new Word(temp, ILexicon.UNMATCH_CJK_WORD))代码,对Word对象使用clone方法克隆
@杰 感谢反馈,发现了,这是2.6.0引入英文的mmseg分词后产生的bug,我稍后给个提交。
对于搜索场景,建议关掉默认开启的英文分词(设置jcseg.ensecondseg = false),对于没有专门英文词库维护的场景,建议先关掉,目前默认就托管了一些主流的英文词条。
对你来说,理想的结果应该是这样的。
jcseg~tokenizer:complex>> 干熄焦、TRT发电等发电技术的引入
分词结果:
干[0,1]/d 熄[1,1]/v 焦[2,1]/v 、[3,1]/w trt[4,3]/en 发电[7,2]/vn 等[9,1]/i 发电技术[10,4] 的[14,1]/u 引入[15,2]/v
Done, total:17, tokens:10, in 0.00033sec
同中文类似的英文拆分类似适合如下场景:
jcseg~tokenizer:complex>> openarkcompile编译器
分词结果:
open[0,4]/n ark[4,3]/n compile[7,7]/v 编译器[14,3]/n
Done, total:17, tokens:4, in 0.00033sec
刚才给了一个提交,已经修复,使用最新的master代码即可:
jcseg~tokenizer:complex>> 干熄焦、TRT发电等发电技术的引入
分词结果:
干[0,1]/d 熄[1,1]/v 焦[2,1]/v 、[3,1]/w t[4,1] r[5,1]/n t[6,1] 发电[7,2]/vn 等[9,1]/i 发电技术[10,4] 的[14,1]/u 引入[15,2]/v
Done, total:17, tokens:12, in 0.00052sec
Jcseg属于字符串密集型计算,不会在底层代码clone,Jcseg花了很多精力控制clone的调用数量,减少内存的申请和碎片的产生,导致现在逻辑也比较分散复杂。
ok
Sign in to comment