背景:

IK分词器分为两种,粗粒度分词和细粒度分词,粗粒度会分为长词,细粒度分出的词比较多,会分出与词库中所有可匹配的词,现在我们想要这样的分词效果如:

关键词:“北京青年路”

粗粒度会分出:




ik分词器maven依赖 ik分词器 分词原理_粗粒度


细粒度会分出:


ik分词器maven依赖 ik分词器 分词原理_ik分词器maven依赖_02


那么我们需要只分出整词、去掉包含词、相同词不去重 如下:


ik分词器maven依赖 ik分词器 分词原理_ik分词器 分词原理_03


1、歧义词处理

这个功能实际上是用到了IK的歧义词处理,为什么粗粒度不展示包含词和重复词了?是因为做了歧义词过滤,过程如下:

在IKAegmennter.java的next方法中进行歧义词处理


ik分词器maven依赖 ik分词器 分词原理_粗粒度_04


歧义词处理分了两块,功能是一样的,只是处理循环中和循环结束最后一个词组的处理。


ik分词器maven依赖 ik分词器 分词原理_粗粒度_05


上面的代码是我修改后的了,增加了judge2的方法,用于处理不处理重复歧义词,第99行判读是否执行歧义处理过程,如果不执行歧义词处理则所有的词都添加到context的词队列中,接下来看看judge歧义词处理过程:


ik分词器maven依赖 ik分词器 分词原理_细粒度_06


首先输入的参数lexemeCell是成词的一个链表,这个链表存储了当前词、同位置词、包含词,代码156行过滤歧义词保存到lexemeStack中,以提供后续处理,159行pathOptions存储了处理歧义后的结果,163行循环歧义列表开始处理歧义词,166行move掉了包含歧义词,168行生成拷贝C创建一个optionn,169行添加到结果列表中,这个添加的重复词是添加不进去的,因为LexemePath重写了compareTo方法,173行只取结果列表的第一个,实际上这第一个词是按权重的分词器排在上面的分词器分出的词。


ik分词器maven依赖 ik分词器 分词原理_ik分词器maven依赖_07


2、保留重复词

增加一个处理歧义词的方法judeg2,用来保留歧义重复词,200行遍历词源队列,并判断是否小于队列中的第一个词,如果小于说明是包含词则进行过滤,大于等于队列第一个词则保留,并调用optionn.addCrossLexeme方法加入到结果集队列中,返回为分词队列,而原方法返回的是一个词源。


ik分词器maven依赖 ik分词器 分词原理_分词器_08


addCrossLexeme方法向LexemePath追加相交的Lexeme。


ik分词器maven依赖 ik分词器 分词原理_分词器_09


3、分词字符

题外话,IK会对不认识的特征字符做分割处理,如果词典中有特殊字符想被分出时,可以修改 CharacterUtil类中的identifyCharType方法实现。


ik分词器maven依赖 ik分词器 分词原理_ik分词器 分词原理_10