首页 > 其他分享 >Elasticsearch常用的IK分析器原理

Elasticsearch常用的IK分析器原理

时间:2024-08-26 12:26:24浏览次数:15  
标签:lexeme hit tmpHits 分析器 Lexeme IK Elasticsearch context 分词

IK Analyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始, IKAnalyzer已经推出了4个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。从3.0版本开始,IK发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。在2012版本中,IK实现了简单的分词歧义排除算法,标志着IK分词器从单纯的词典分词向模拟语义分词衍化。

而在其2012 的特性:

  1. 采用了特有的“正向迭代最细粒度切分算法“,支持细粒度和智能分词两种切分模式;

  2. 在系统环境:Core2 i7 3.4G双核,4G内存,window 7 64位, Sun JDK 1.6_29 64位 普通pc环境测试,IK2012具有160万字/秒(3000KB/S)的高速处理能力。

  3. 2012版本的智能分词模式支持简单的分词排歧义处理和数量词合并输出。

  4. 采用了多子处理器分析模式,支持:英文字母、数字、中文词汇等分词处理,兼容韩文、日文字符

  5. 优化的词典存储,更小的内存占用。支持用户词典扩展定义。特别的,在2012版本,词典支持中文,英文,数字混合词语。

我尝试找了一下这个算法,没有找到任何相关的硬核论文,而网上资料也都比较水,只好瞧瞧Github的源码https://github.com/infinilabs/analysis-ik。我本来是没有信心的,但是想想12年前的技术能高到哪里去。

原理

IK本质上就是一个编译器,通过字典和规则来实现分词效果。主要运用了Lexeme方法。

Token, Patterns, and Lexemes

编译器是将高级语言编写的源程序翻译成低级语言的系统软件。源代码的编译过程分为几个阶段,以简化开发和设计过程。各阶段依次进行,上一阶段的输出结果将用于下一阶段。各个阶段如下:

Lexical Analysis Phase(词法分析阶段):

在这一阶段,输入是要从左到右阅读的源程序,输出则是下一个语法分析阶段要分析的标记序列。在扫描源代码的过程中,空白字符、注释、回车符、预处理器指令、宏、换行符、空格、制表符等都会被删除。词法分析器或扫描仪还有助于错误检测。例如,如果源代码中包含无效常量、关键字拼写错误等,词法分析阶段就会进行处理。正则表达式是指定编程语言标记的标准符号。

Token

它基本上是一串字符,由于无法进一步细分,因此被视为一个单元。

Lexeme

它是源代码中的字符序列,通过给定的预定义语言规则进行匹配,每个词素都将被指定为有效标记。

Patterns

它指定了扫描仪创建Token时所遵循的一系列规则。

代码

core/IKSegmenter.java

/**
	 * 分词,获取下一个词元
	 * @return Lexeme 词元对象
	 * @throws java.io.IOException
	 */
	public synchronized Lexeme next()throws IOException{
		Lexeme l = null;
		while((l = context.getNextLexeme()) == null ){
			/*
			 * 从reader中读取数据,填充buffer
			 * 如果reader是分次读入buffer的,那么buffer要  进行移位处理
			 * 移位处理上次读入的但未处理的数据
			 */
			int available = context.fillBuffer(this.input);
			if(available <= 0){
				//reader已经读完
				context.reset();
				return null;
				
			}else{
				//初始化指针
				context.initCursor();
				do{
        			//遍历子分词器
        			for(ISegmenter segmenter : segmenters){
        				segmenter.analyze(context);
        			}
        			//字符缓冲区接近读完,需要读入新的字符
        			if(context.needRefillBuffer()){
        				break;
        			}
   				//向前移动指针
				}while(context.moveCursor());
				//重置子分词器,为下轮循环进行初始化
				for(ISegmenter segmenter : segmenters){
					segmenter.reset();
				}
			}
			//对分词进行歧义处理
			this.arbitrator.process(context, configuration.isUseSmart());
			//将分词结果输出到结果集,并处理未切分的单个CJK字符
			context.outputToResult();
			//记录本次分词的缓冲区位移
			context.markBufferOffset();			
		}
		return l;
	}

core/QuickSortSet.java

class Cell implements Comparable<Cell>{
		private Cell prev;
		private Cell next;
		private Lexeme lexeme;
		
		Cell(Lexeme lexeme){
			if(lexeme == null){
				throw new IllegalArgumentException("lexeme must not be null");
			}
			this.lexeme = lexeme;
		}

		public int compareTo(Cell o) {
			return this.lexeme.compareTo(o.lexeme);
		}

		public Cell getPrev(){
			return this.prev;
		}
		
		public Cell getNext(){
			return this.next;
		}
		
		public Lexeme getLexeme(){
			return this.lexeme;
		}
	}

用于存储Lexeme

core/CJKSegmenter.java

/**
 *  中文-日韩文子分词器
 */
class CJKSegmenter implements ISegmenter {
	
	//子分词器标签
	static final String SEGMENTER_NAME = "CJK_SEGMENTER";
	//待处理的分词hit队列
	private List<Hit> tmpHits;
	
	
	CJKSegmenter(){
		this.tmpHits = new LinkedList<Hit>();
	}

	/* (non-Javadoc)
	 * @see org.wltea.analyzer.core.ISegmenter#analyze(org.wltea.analyzer.core.AnalyzeContext)
	 */
	public void analyze(AnalyzeContext context) {
		if(CharacterUtil.CHAR_USELESS != context.getCurrentCharType()){
			
			//优先处理tmpHits中的hit
			if(!this.tmpHits.isEmpty()){
				//处理词段队列
				Hit[] tmpArray = this.tmpHits.toArray(new Hit[this.tmpHits.size()]);
				for(Hit hit : tmpArray){
					hit = Dictionary.getSingleton().matchWithHit(context.getSegmentBuff(), context.getCursor() , hit);
					if(hit.isMatch()){
						//输出当前的词
						Lexeme newLexeme = new Lexeme(context.getBufferOffset() , hit.getBegin() , context.getCursor() - hit.getBegin() + 1 , Lexeme.TYPE_CNWORD);
						context.addLexeme(newLexeme);
						
						if(!hit.isPrefix()){//不是词前缀,hit不需要继续匹配,移除
							this.tmpHits.remove(hit);
						}
						
					}else if(hit.isUnmatch()){
						//hit不是词,移除
						this.tmpHits.remove(hit);
					}					
				}
			}			
			
			//*********************************
			//再对当前指针位置的字符进行单字匹配
			Hit singleCharHit = Dictionary.getSingleton().matchInMainDict(context.getSegmentBuff(), context.getCursor(), 1);
			if(singleCharHit.isMatch()){//首字成词
				//输出当前的词
				Lexeme newLexeme = new Lexeme(context.getBufferOffset() , context.getCursor() , 1 , Lexeme.TYPE_CNWORD);
				context.addLexeme(newLexeme);

				//同时也是词前缀
				if(singleCharHit.isPrefix()){
					//前缀匹配则放入hit列表
					this.tmpHits.add(singleCharHit);
				}
			}else if(singleCharHit.isPrefix()){//首字为词前缀
				//前缀匹配则放入hit列表
				this.tmpHits.add(singleCharHit);
			}
			

		}else{
			//遇到CHAR_USELESS字符
			//清空队列
			this.tmpHits.clear();
		}
		
		//判断缓冲区是否已经读完
		if(context.isBufferConsumed()){
			//清空队列
			this.tmpHits.clear();
		}
		
		//判断是否锁定缓冲区
		if(this.tmpHits.size() == 0){
			context.unlockBuffer(SEGMENTER_NAME);
			
		}else{
			context.lockBuffer(SEGMENTER_NAME);
		}
	}

	/* (non-Javadoc)
	 * @see org.wltea.analyzer.core.ISegmenter#reset()
	 */
	public void reset() {
		//清空队列
		this.tmpHits.clear();
	}

}

Dictionary 和 Lexeme 匹配,最后在 core/AnalyzeContext.java 实现完整的 Lexical Analysis Phase 过程。

标签:lexeme,hit,tmpHits,分析器,Lexeme,IK,Elasticsearch,context,分词
From: https://blog.csdn.net/weixin_41446370/article/details/141551060

相关文章

  • 【scikit-opt】七大启发式算法的使用
    @目录前言1.测试函数1.1针状函数1.1.1表达式1.1.2特征1.1.3图像1.2Brains’srcos函数1.2.1表达式1.2.2特征1.2.3图像1.3Griewank函数1.3.1表达式1.3.2特征1.3.3图像1.4Easom’s函数1.4.1表达式1.4.2特征1.4.3图像1.5Schwefel’s函数1.5.1表达式1.5.2特征1.5.3......
  • 2024玩儿转TikTok之环境介绍及独立使用住宅ip搭建,最便宜的网络,20元/月,刚刚更新最新教
    郑重申明:本文章只对合法合理做tiktok视频运营的用户做学习交流使用,有其他使用不当的违规违法行为后果自负!网络的环境测试,必须是独立住宅ip,网络环境优良,tiktok发布作品才能有流量1、选择服务器我选择的服务器:https://ipraft.com/?i71b7cf​​​然后下载FinalShell连接......
  • 多准则妥协解排序法(VIKOR)
    多准则妥协解排序法(VIKOR)多准则妥协解排序法(VIKOR)算法简介算法步骤算法优点多准则妥协解排序法(VIKOR)更多算法请见这里:2024数学建模国赛C题攻略(无废话版)算法简介VIKOR(VlseKriterijumskaOptimizacijaKompromisnoResenje)评价法又称多准则妥协解排序方法,是一种......
  • elasticsearch整合自定义词库实现自定义分词
            在进行分词时es有时没有办法对人名或者其他新词、偏词进行精准的分词,这时候就需要我们进行自定义分词。前置:        1).安装完成ik分词器,安装流程可以参考:ik安装流程        2).自定义的远程库我们使用nginx,所以需要提前安装nginx1.进入到......
  • 浅谈红队攻防之道-CobaltStrike钓鱼攻击集锦
    打个比方,一片大地上,躺着一群沉睡的人,远处就是火山,马上就要爆发了,你就像个闹钟,面对这些沉睡的人,你想把他们叫醒。你持续不断地响着,有的睡得浅的人,被你叫醒了,跟你一块去叫醒众人,但是人数太多了,你们的声音太微弱了,叫醒的人毕竟有限,而且保不齐有的人嫌烦,时不时还踢坏两个。那......
  • windows下安装es与elasticsearch报错
    发现网上很少关于windows安装elasticsearch的文章,所以本人结合一天的报错,解决问题的过程,写一下这篇文章,希望对大家有用,有帮助的话请点一个免费的赞,谢谢。安装es下载:点击https://www.elastic.co/cn/downloads/elasticsearch-->点击'Viewpastreleases'-->下拉栏中,找到7.10......
  • K8S之Ingress常用Nginx、Traefik示例
    NginxIngress创建Pod、Service,定义如下nginx-ingress-demo.yamlapiVersion:extensions/v1beta1kind:Deploymentmetadata:name:nginx-deploynamespace:defaultspec:replicas:3selector:matchLabels:app:nginx-demoreplease:canary......
  • python安装paramiko报错
    腾讯云上python3.6,使用pip3.6install paramiko报错[root@VM-0-14-centostest]#pip3.6installparamikoWARNING:Runningpipinstallwithrootprivilegesisgenerallynotagoodidea.Try`pip3.6install--user`instead.CollectingparamikoDownloadinghttp://......
  • 轻松上手:Docker部署Elasticsearch,高效构建搜索引擎环境
    我在前一段时间写了一个ES简介,博主建议大家先看完简介再来安装ES,那篇博文是:深入理解Elasticsearch:让搜索性能飞起来!-CSDN博客服务器开放9200和9300端口号:1.打开目录:cd/usr/local/docker/2.创建es目录:mkdires3.打开es目录:cdes/4.下载镜像:我在这里声明一下......
  • pikachu-Cross-Site Scripting通过攻略
    反射型xss(get)第一步:进入先将maxlength中的20修改大一些,以便我们可以输入更多的字符第二步:输入<script>alert(1)</script>成功爆破 反射型xss(post) 第一步:点击提示得到用户名和密码登录 第二步:输入<script>alert(1)</script>成功爆破 存储型xss在留言框里输入......