目录
1.字符类型分类
目前共有5种字符类型:
2.分词大致流程
主要分为三步:
1) 不断移动缓存区的指针,获取不同的字符的位置,值,类型
2) 调用不用的子分词器进行分词处理
3) 对最终的分词结果进行歧义处理
同时注意:IK分词器默认开启大写转小写的功能,即enable_lowercase=true
3.子分词器
IK分词器内置3种子分词器,分别是:
1)LetterSegmenter:处理英文字母和阿拉伯字母的子分词器
2)CN_QuantifierSegmenter:处理中文数量词的子分词器
3)CJKSegmenter:处理中文词的子分词器
每个具体的分词由以下结构体表示:
例如以下这段话:
缓存区分2次读完,分别为:
1)一次我们社导游带团到南京去,团里有位客人问:“南京市市长是不是叫江大桥”,我们导游的回答说:“不是啊”。
2)客人很奇怪的说那为什么我路过南京的时候,路边有个牌子上写着“南京市长江大桥欢迎您”?
其中标红的南京和牌子的Lexeme分别如下:
3.1LetterSegmenter
LetterSegmenter的分词流程:
LetterSegmenter主要处理3种情况:
1) 英文字母
2) 阿拉伯字母
3) 混合字母
以上处理流程都比较相似,拿英文字母处理流程说明:
其实就是比对起始字符,如果是英文字符,则标记起始位置,然后查找结束位置,查找结束位置主要分两种情况:1)遇到不是英文字符,则输出;2)缓冲区读完也输出
阿拉伯字母和混合字母的处理流程类似。
假如以下这段话:
经过LetterSegmenter分词之后为:
1) Abc(英文字母)
2) 123(阿拉巴字母)
3) abc123(混合字母)
3.2CN_QuantifierSegmenter
CN_QuantifierSegmenter主要是用来切分中文数词和中文量词,其中针对中文量词会建立一颗中文量词词典树,其加载的配置文件为:/usr/dahua/elasticsearch/plugins/analysis-ik/config/
quantifier.dic。IK中会根据不同的词类型建立不同的词典树,其形状如下图所示:
其中每个字由DictSegment,它存储了当前保存的字以及当前词链表是否组成一个关键词,其中private Character nodeChar保存了当前的字,private intnodeState = 0; 保存当前词链表的状态,如果为1,则从上至下可以组成一个词,否则只是前缀。
CN_QuantifierSegmenter的分词过程如下:
CN_QuantifierSegmenter主要处理2种情况:
1)中文数词,其中中文数词为以下这些词:"一二两三四五六七八九十零壹贰叁肆伍陆柒捌玖拾百千万亿拾佰仟萬億兆卅廿",这些词直接在代码中指定,如下:
2) 中文量词。它从/usr/dahua/elasticsearch/plugins/analysis-ik/config/quantifier.dic加载行程量词词典树
处理中文数词的过程如下:
处理中文数词主要是把关键字在Chn_Num中扫描,如果命中,则说明是中文数词,一旦没有命中,则把之前命中的组成一个词输出。
处理中文量词的过程如下:
假如以下这段话:
经过CN_QuantifierSegmenter分词之后为:
1) 两三四(中文数词)
2) 立方公尺(中文量词)
至于其它的例如:
两三,三四,三,四等是由CJKSegmenter分词而得的
3.3CJKSegmenter
CJKSegmenter主要是用来切分普通的中文词,其加载过程如下:
主要加载3个部分的词库,分别是:
1)/usr/dahua/elasticsearch/plugins/analysis-ik/config/main.dic
2)/usr/dahua/elasticsearch/plugins/analysis-ik/config/custom/mydict.dic;
/usr/dahua/elasticsearch/plugins/analysis-ik/config/custom/single_word_full.dic;
/usr/dahua/elasticsearch/plugins/analysis-ik/config/custom/sougou.dic
3)远程扩展字典,默认没有配置
加载完成之后都会生成一颗词典树
其分词过程和CN_QuantifierSegmenter处理中文量词的过程相似:
4.歧义词处理策略
当通过以上三个分词器将短语分词之后,会产生许多短的词语,即IK词元对象 Lexeme,此时需要根据不同的策略输出最终的分词结果,目前IK支持两种策略:1)
ik_max_word
:尽可能多的词语
2)ik_smart
:尽可能少的词语,且词语之间不会出现交叉,即
Lexeme的offset,begin和length不会出现相互之间重叠
其处理过程如下:
While循环会不断遍历初始词元集合,通过crossPath.addCrossLexeme(orgLexeme)不断来寻找每个潜在的交叉集合,比方说:
经过之前3个子分词器分词之后会变为以下几个关键字:
则找到的第一个交叉集合为:
第二个交叉集合为:
第三个交叉集合为:
4.1ik_max_word
当采用ik_max_word时,即useSmart为false,此时由于!useSmart为true,则不会做任何处理,会把所有的分词结果都作为最后的分词结果输出
4.2 ik_smart
当useSmart为true的时候会针对每个交叉集合进行歧义处理,输出最优结果:
其中judge的输入参数为:每个交叉集合的第一个词元(lexemeCell),交叉集合的长度(fullTextLength),最优集合的输出是由一颗有序的Set集合树决策,即TreeSet<LexemePath> pathOptions,其中根据LexemePath内部的compareTo方法进行排序,取第一个元素作为交叉集合的最优词元组。我们先来看下LexemePath的组成:
LexemePath继承QuickSortSet,其内部保存了不同的词元Lexeme,每一个LexemePath就代表了一个交叉集合中候选中的非交叉集合的输出词元Lexeme集合,它们统一插入到TreeSet<LexemePath> pathOptions中进行排序,最终输出pathOptions中的第一个LexemePath。
例如第一个交叉集合为:
则其内部非交叉集合的组合为:
在这些组合中会输出一个最优的结果:即中华人民共和国
那么输出的原则是什么呢?且看LexemePath的排序原则:
顺序按照以下几个原则排序:
1) 有效文本长度:优先输出有效文本长度长的,例如:
2) 词元个数:优先输出词元个数小的,例如:
3) 路径跨度:优先输出跨度大的,例如:
4)最后一个字符的位置:优先输出位置越靠后的,例如:
5)词长越平均越好,其计算公式如下:例如:
衡量的标准是词元的长度积
6)词元位置权重比较,其计算公式如下:例如: