必知的技术知识:IK分词器实现原理剖析——一个小问题引发的思考

简介: 必知的技术知识: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模式下,会出现多个词//代码效果参考:http://hnjlyzjd.com/hw/wz_25344.html

元链的候选集。

那么,我们怎么选择最优的词元链呢?选择的关键就在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分词器被广泛使用,从某种意义上说明,很多真实的应用场景,并不需要使用那些先进而复杂的深度学习算法模型。低成本的浅层特征模型也仍然可以达到十分具有竞争力的准确率和召回率。


加入技术交流群,请扫描下方二维码。

相关文章
|
小程序 安全 物联网
【经验分享】支付宝小程序常用appId
【经验分享】支付宝小程序常用appId
4669 6
|
存储 JSON Java
SpringBoot集成AOP实现每个接口请求参数和返回参数并记录每个接口请求时间
SpringBoot集成AOP实现每个接口请求参数和返回参数并记录每个接口请求时间
1647 2
|
4月前
|
人工智能 API 开发工具
Skills比MCP更重要?更省钱的多!Python大佬这观点老金测了一周终于懂了
加我进AI学习群,公众号右下角“联系方式”。文末有老金开源知识库·全免费。本文详解Claude Skills为何比MCP更轻量高效:极简配置、按需加载、省90% token,适合多数场景。MCP仍适用于复杂集成,但日常任务首选Skills。推荐先用SKILL.md解决,再考虑协议。附实测对比与配置建议,助你提升效率,节省精力。关注老金,一起玩转AI工具。
|
存储 关系型数据库 MySQL
ES的全文索引和MySQL的全文索引有什么区别?如何选择?
【8月更文挑战第26天】ES的全文索引和MySQL的全文索引有什么区别?如何选择?
2332 5
|
存储 人工智能 监控
钉钉对话机器人实现赞踩收集
本文介绍如何通过AppFlow记录钉钉AI对话卡片的用户反馈情况。首先确保已接入钉钉AI机器人,然后分三步实现:1) 修改钉钉AI消息卡片,添加点赞按钮并配置回调参数;2) 配置钉钉卡片点赞消息接收连接流,更新卡片状态;3) 设置日志收集节点,存储用户反馈数据。完成配置后,用户可在群聊中与机器人互动,并使用点踩点赞功能,反馈数据将被有效记录和分析。
1140 6
钉钉对话机器人实现赞踩收集
|
12月前
|
SQL 关系型数据库 MySQL
Flink CDC 3.4 发布, 优化高频 DDL 处理,支持 Batch 模式,新增 Iceberg 支持
Apache Flink CDC 3.4.0 版本正式发布!经过4个月的开发,此版本强化了对高频表结构变更的支持,新增 batch 执行模式和 Apache Iceberg Sink 连接器,可将数据库数据全增量实时写入 Iceberg 数据湖。51位贡献者完成了259次代码提交,优化了 MySQL、MongoDB 等连接器,并修复多个缺陷。未来 3.5 版本将聚焦脏数据处理、数据限流等能力及 AI 生态对接。欢迎下载体验并提出反馈!
1816 1
Flink CDC 3.4 发布, 优化高频 DDL 处理,支持 Batch 模式,新增 Iceberg 支持
|
NoSQL Java Redis
Redlock分布式锁高并发下有什么问题
Redlock分布式锁在高并发场景下可能面临的问题主要包括:网络延迟、时钟偏移、单点故障、宕机重启问题、脑裂问题以及效率低等。接下来,我将使用Java代码示例来说明其中一些问题。
535 12
|
自然语言处理 达摩院 索引
Elasticsearch 中文分词器
在使用Elasticsearch 进行搜索中文时,Elasticsearch 内置的分词器会将所有的汉字切分为单个字,对用国内习惯的一些形容词、常见名字等则无法优雅的处理,此时就需要用到一些开源的分词器,以下分别介绍几种常见的中文分词器
11071 2
Elasticsearch 中文分词器
|
自然语言处理 应用服务中间件 nginx
一文教会你 分词器elasticsearch-analysis-ik 的安装使用【自定义分词库】
这篇文章是关于如何在Elasticsearch中安装和使用ik分词器的详细教程,包括版本匹配、安装步骤、分词测试、自定义词库配置以及创建使用ik分词器的索引的方法。
一文教会你 分词器elasticsearch-analysis-ik 的安装使用【自定义分词库】