IK分词器实现原理剖析 —— 一个小问题引发的思考
前言:
网上很多的文章都建议在使用IK分词器的时候,建立索引的时候使用ik_max_word模式;搜索的时候使用ik_smart模式。理由是max_word模式分词的结果会包含smart分词的结果,这样操作会使得搜索的结果很全面。
但在实际的应用中,我们会发现,有些时候,max_word模式的分词结果并不能够包含smart模式下的分词结果。
下面,我们就看一个简单的测试实例:
假设我们现在要分别在max_word模式和smart模式下搜索“2022年”,搜索结果如下表所示:
max_word模式 |
0 - 4 : 2022 | ARABIC 4 - 5 : 年 | COUNT |
smart模式 |
0 - 5 : 2022年 | TYPE_CQUAN |
我们会发现max_word模式下的分词结果并没有覆盖smart模式下的分词结果。这是什么原因导致的呢?
下面,我们通过分析IK分词器的处理流程来寻找答案。
IK分词器实现原理剖析
IKAnalyzer中包含3个子分词器
LetterSegmenter |
处理英文字母和阿拉伯数字的分词器 |
CN_QuantifierSegmenter |
处理中文数量词的分词器 |
CJKSegmenter |
处理中文和日韩字符的分词器 |
下面我们看下这三个子分词器分别是如何工作的。
英文字符及阿拉伯数字子分词器
假设我们现在对“111aaa222bbb”这个字符串在max_word模式下进行分词处理,其分词的处理结果如下所示:
0 - 12 : 111aaa222bbb | LETTER
0 - 3 : 111 | ARABIC
3 - 6 : aaa | ENGLISH
6 - 9 : 222 | ARABIC
9 - 12 : bbb | ENGLISH
上面的第一列代表的是词元的起始位移和偏移量,中间列是词元字符信息,第三列是词元属性。
现在我们将上面的字符串做一些改变,对字符串“111aaa@222bbb”进行分词处理,我们会发现其分词结果如下所示:
0 - 13 : 111aa@a222bbb | LETTER
0 - 3 : 111 | ARABIC
3 - 5 : aa | ENGLISH
6 - 7 : a | ENGLISH
7 - 10 : 222 | ARABIC
10 - 13 : bbb | ENGLISH
现在我们再将上面的字符串做一些修改,变成“111aaa 222bbb”,那么我们会得到如下的分词结果:
0 - 6 : 111aaa | LETTER
0 - 3 : 111 | ARABIC
3 - 6 : aaa | ENGLISH
7 - 13 : 222bbb | LETTER
7 - 10 : 222 | ARABIC
10 - 13 : bbb | ENGLISH
上面的三个字符串除了中间的字符外其他地方是一样的,但是得到的分词结果却是有很多相同。
从分词结果中,我们可以看到LetterSegmenter会拆分出三种词性的词元,分别是LETTER(数字英文混合),ARABIC(数字),ENGLISH(英文)。这三种不同的词元属性分别对应了三种不同的处理流程。
细心的同学可能还会有一个疑问,字符串"111aaa@222bbb"与字符串"111aaa 222bbb"解析出来的混合词元不一样。这是因为@字符是英文字符的链接符号,但空格并不是。
中文数量词子分词器
主要分为数词处理流程和量词处理流程两部分组成,处理流程比较简单,这里不再进行详细叙述。
中文-日韩文子分词器
主要是根据处理词典中的词库进行分词处理,那么如果我们要处理的词语在词库中并不存在的话,会出现什么情况呢?
因为IK分词是一个基于词典的分词器,只有包含在词典的词才能被正确切分,IK解决分词歧义只是根据几条最佳的分词实践规则,并没有用到任何概率模型,也不具有新词发现的功能。
因此,如果我们要处理的文本在词库中不存在的时候,就会被切分成单个字符的模式。
分词歧义裁决器
我们尝试一下在smart模式下对"111aaa 222bbb"进行分词处理,我们会得到如下的分词结果:
0 - 6 : 111aaa | LETTER
7 - 13 : 222bbb | LETTER
那么为什么smart模式下的分词结果会和max_word模式下的分词结果不同呢?通过阅读IK分词器的源代码,我们会发现IK分词器下的smart模式主要是通过IKArbitrator这个类来实现的。
这个类是分词结果的歧义处理类。在了解IKArbitrator这个类的处理流程之前,我们需要先了解两个数据结构,Lexeme,QuickSortSet和LexemePath。
Lexeme是分词器中解析出来的词元结果,其主要的字段包括:
// 词元的起始位移
private int offset;
// 词元的相对起始位置
private int begin;
// 词元的长度
private int length;
// 词元文本
private String lexemeText;
// 词元类型
private int lexemeType;
QuickSortSet是IK分词器中用来对词元进行排序的集合。其中的排序规则是词元相对起始位置小的优先;相对起始位置相同的情况下,词元长度大的优先。
LexemePath继承了QuickSortSet,其代表的是词元链。在IK分词器的smart模式下,会出现多个词元链的候选集。
那么,我们怎么选择最优的词元链呢?选择的关键就在LexemePath的compareTo方法中。
public int compareTo(LexemePath o) {
// 比较有效文本长度
if (this.payloadLength > o.payloadLength) {
return -1;
} else if (this.payloadLength < o.payloadLength) {
return 1;
} else {
// 比较词元个数,越少越好
if (this.size() < o.size()) {
return -1;
} else if (this.size() > o.size()) {
return 1;
} else {
// 路径跨度越大越好
if (this.getPathLength() > o.getPathLength()) {
return -1;
} else if (this.getPathLength() < o.getPathLength()) {
return 1;
} else {
// 根据统计学结论,逆向切分概率高于正向切分,因此位置越靠后的优先
if (this.pathEnd > o.pathEnd) {
return -1;
} else if (pathEnd < o.pathEnd) {
return 1;
} else {
// 词长越平均越好
if (this.getXWeight() > o.getXWeight()) {
return -1;
} else if (this.getXWeight() < o.getXWeight()) {
return 1;
} else {
// 词元位置权重比较
if (this.getPWeight() > o.getPWeight()) {
return -1;
} else if (this.getPWeight() < o.getPWeight()) {
return 1;
}
}
}
}
}
}
return 0;
}
接下来,我们看看IK分词器是如何选择出最优词元链的?其主要处理流程如下:
总结:
现在回到前言部分中我们提及的问题,经过我们对IK分词器处理流程地分析,我们很容易得到答案。
这是因为2022是数词,而年是量词。在max_word模式下,数词和量词不会进行合并处理。但是在smart模式下,数词和量词会进行合并处理。
通过阅读IK分词器的源码,我们会发现它并没有采用任何先进的算法模型,但是该分词器依然被广泛地被使用。
IK分词器被广泛使用,从某种意义上说明,很多真实的应用场景,并不需要使用那些先进而复杂的深度学习算法模型。低成本的浅层特征模型也仍然可以达到十分具有竞争力的准确率和召回率。
加入技术交流群,请扫描下方二维码。
IK分词器实现原理剖析 —— 一个小问题引发的思考的更多相关文章
- 一个小BUG引发的思考。(论开发与测试之间的那点事)
标题不是“一个馒头引发的血案”. 言归正传:今天上午测试的时候,发现了一个BUG,如图: 一个用肉眼就能发现的BUG.原因当然是因为开发同事没有自测试,流入到了测试人员这里了. 无非是开发同事不严谨造 ...
- Elasticsearch之文档的增删改查以及ik分词器
文档的增删改查 增加文档 使用elasticsearch-head查看 修改文档 使用elasticsearch-head查看 删除文档 使用elasticsearch-head查看 查看文档的三种方 ...
- 【ELK】【docker】【elasticsearch】2.使用elasticSearch+kibana+logstash+ik分词器+pinyin分词器+繁简体转化分词器 6.5.4 启动 ELK+logstash概念描述
官网地址:https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-cli-run-prod ...
- IK分词器原理与源码分析
原文:http://3dobe.com/archives/44/ 引言 做搜索技术的不可能不接触分词器.个人认为为什么搜索引擎无法被数据库所替代的原因主要有两点,一个是在数据量比较大的时候,搜索引擎的 ...
- IK分词器 原理分析 源码解析
IK分词器在是一款 基于词典和规则 的中文分词器.本文讲解的IK分词器是独立于elasticsearch.Lucene.solr,可以直接用在java代码中的部分.关于如何开发es分词插件,后续会有文 ...
- [Linux]Linux下安装和配置solr/tomcat/IK分词器 详细实例一.
在这里一下讲解着三个的安装和配置, 是因为solr需要使用tomcat和IK分词器, 这里会通过图文教程的形式来详解它们的安装和使用.注: 本文属于原创文章, 如若转载,请注明出处, 谢谢.关于设置I ...
- ElasticSearch6.5.0 【安装IK分词器】
不得不夸奖一下ES的周边资源,比如这个IK分词器,紧跟ES的版本,卢本伟牛逼!另外ES更新太快了吧,几乎不到半个月一个小版本就发布了!!目前已经发了6.5.2,估计我还没怎么玩就到7.0了. 下载 分 ...
- Elasticsearch入门之从零开始安装ik分词器
起因 需要在ES中使用聚合进行统计分析,但是聚合字段值为中文,ES的默认分词器对于中文支持非常不友好:会把完整的中文词语拆分为一系列独立的汉字进行聚合,显然这并不是我的初衷.我们来看个实例: POST ...
- Restful认识和 IK分词器的使用
什么是Restful风格 Restful是一种面向资源的架构风格,可以简单理解为:使用URL定位资源,用HTTP动词(GET,POST,DELETE,PUT)描述操作. 使用Restful的好处: 透 ...
随机推荐
- 图片管够!用Python做了个图片识别系统(附源码)
本项目将使用python3去识别图片是否为色情图片,会使用到PIL这个图像处理库,并且编写算法来划分图像的皮肤区域 介绍一下PIL: PIL(Python Image Library)是一种免费的图像 ...
- Autograd: 自动求导
Pytorch中神经网络包中最核心的是autograd包,我们先来简单地学习它,然后训练我们第一个神经网络. autograd包为所有在tensor上的运算提供了自动求导的支持,这是一个逐步运行的框架 ...
- SSH隧道代理
应用场景: A机器可以通过SSH连接到B机器,然后A想用B的身份访问B所在的资源(主要用于浏览器访问) 命令: A机器通过ssh与B建立连接,并暴露3128端口:ssh -N -D 127.0.0.1 ...
- Linux一些错误总结
1.cannot verify <mydomainname> certificate, issued by '/C=US/O=Let's Encrypt/CN=R3': 解决1:wget ...
- 第二十一天python3 python的正则表达式re模块学习
python的正则表达式 python使用re模块提供了正则表达式处理的能力: 常量 re.M re.MULTILINE 多行模式 re.S re.DOTALL 单行模式 re.I re.IGNORE ...
- 从零开始搭建Vue2.0项目(一)之快速开始
从零开始搭建Vue2.0项目(一)之项目快速开始 前言 该样板适用于大型,严肃的项目,并假定您对Webpack和有所了解vue-loader.确保还阅读vue-loader的文档,了解常见的工作流程配 ...
- placeholder 设置字体颜色
input::-webkit-input-placeholder { /* WebKit browsers */ color: #999; } input:-moz-placeholder { col ...
- React报错之Objects are not valid as a React child
正文从这开始~ 总览 当我们尝试在JSX代码中,直接渲染对象或者数组时,会产生"Objects are not valid as a React child"错误.为了解决该错误, ...
- Mysql8基础知识
系统表都变为InnoDb表 从MySQL 8.0开始,系统表全部换成事务型的InnoDB表,默认的MySQL实例将不包含任何MyISAM表,除非手动创建MyISAM表 基本操作 创建数据表的语句为CR ...
- 用JavaScript写随机出一个颜色
function changeColor(){ var r = parseInt(Math.random()*255) var g = parseInt(Math.random()*255) var ...