ES中分词器Analyzer的组成
分词器是专门处理分词的组件,由三部分组成。
- Character filter:针对原始文本处理,例如去除html
- Tokenizer:按照规则切分为单词
- Token Filter:将切分的单词进行加工,小写,删除stopwords,增加同义词
以上三部分是串行处理的关系,除Tokenizer只能一个外,其他两个都可以多个。IK分词器仅实现了Tokenizer
IK分词器原理
IK分词器在是一款基于词典和规则的中文分词器。具有以下特性:
- 采用了特有的“正向迭代最细粒度切分算法“
- 支持细粒度和智能分词两种切分模式
- 智能分词模式支持简单的分词排歧义处理和数量词合并输出
- 采用了多子处理器分析模式,支持:英文字母、数字、中文词汇等分词处理,兼容韩文、日文字符
IK内部有3个子分词器(Segmenter),CJKSegmenter(中日韩文分词器),CN_QuantifierSegmenter(中文数量词分词器),LetterSegmenter(英文分词器)。
LetterSegmenter:从遇到第一个英文字符往后,直到碰到第一个非英文字符,这中间的所有字符则切分为一个英文单词。
CN_QuantifierSegmenter:从遇到每一个中文数量词,然后检查该数量词后一个字符是否为中文量词(根据是否包含在中文量词词典中为判断依据),如是,则分成一个词,如否,则不是一个词。
CJKSegmenter:处理逻辑较为复杂,整体思路是从字典树中寻找匹配的词
分词裁决器IKArbitrator:只有在Smart模式才会生效,仅根据几条可能是最佳的分词实践规则,并没有用到任何概率模型,也不具有新词发现的功能。
两种分词模式
智能模式
对应es的IK插件的ik_smart,会做最粗粒度的拆分。比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”,适合 Phrase 查询。
细粒度模式
对用es的插件ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,华,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合,适合 Term Query。
IK分词实践
IK分词的效果主要取决于词库,目前自带主词典拥有27万左右的汉语单词量。对于应用领域的不同,需要各类专业词库的支持。
分词规律
es检索的核心数据结构为倒排索引,分词是否合理正确,直接影响数据的检索结果,在自定义词典及分词器时,可以采取以下方式来验证分词的结果:
GET /_analyze
{
"analyzer": "ik_max_word",
"text": ["甲三"]
}
ik_max_word
- 当查询词在词典中不存在时,会按字拆分
例如:在北-->在,北
- 当查询词在词典中存在,且长度为两个字时,有时拆分有时不拆分
例如:甲乙-->甲乙
联通-->联通,联,通
- 当查询词在词典中存在,且查询词的一部分也在词典在中存在,则分别拆分
例如:甲乙丙丁-->甲乙丙丁,甲乙,丙丁
中国联通-->中国联通,中国,国联,联通,通(没弄明白为啥这里联通不拆成联、通)
- 当查询词任意部分都不在词典中存储,则按字拆分
ik_smart
- 当查询词在词典中不存在时,会按字拆分
例如:在北-->在,北
- 当查询词在词典中存在,不做拆分
例如:甲乙-->甲乙
甲乙丙丁-->甲乙丙丁
- 当查询词任意部分都不在词典中存储,则按字拆分
依据上述规律,我们可以在写入数据时使用ik_max_word,增加分词数量,提高被命中几率,在查询数据时使用ik_smart,减少分词数量,提升结果准确率,减少无关结果
去掉分词结果中的单个字
使用es内置的token filter:length
POST _analyze
{
"text": "一中华人民共和国国歌",
"filter": [
{
"type": "length",
"min": "2"
}
],
"tokenizer": "ik_smart"
}
分词结果中“一”被过滤掉,但对于某些查询词,例如“父与子”,该设置会导致无分词结果