编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

Lucene集成IK Analyzer中文分词器

wxchong 2024-07-16 10:52:12 开源技术 9 ℃ 0 评论

IK Analyzer

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

IK Analyzer 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版本,词典支持中文,英文,数字混合词语。

地址:https://code.google.com/archive/p/ik-analyzer/

与Lucene集成

IK分词器最先作为lucence上使用而开发,主要用于对中文的分词,后来发展成独立的分词组件,目前只提供到lucence 4.0版本的支持,我们在使用4.0以后的版本的时候需要简单的集成一下。

IK需要集成一因为lucence4.0后,Analyer的createComponents方法的参数改变了。

1.添加依赖:

<dependency>
    <groupId>com.janeluo</groupId>
    <artifactId>ikanalyzer</artifactId>
    <version>2012_u6</version>
    
    <exclusions>
       <exclusion>
          <groupId>org.apache.lucene</groupId>
          <artifactId>lucene-core</artifactId>
       </exclusion>
       <exclusion>
          <groupId>org.apache.lucene</groupId>
          <artifactId>lucene-queryparser</artifactId>
       </exclusion>
       <exclusion>
          <groupId>org.apache.lucene</groupId>
          <artifactId>lucene-analyzers-common</artifactId>
       </exclusion>
    </exclusions>
</dependency>

<!--lucene-queryparser 查询分析器模块 -->
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-queryparser</artifactId>
    <version>7.3.0</version>
</dependency>
</dependencies>

2.因为lucence4.0后,Analyer的createComponents方法的参数改变了。

protected abstract Analyzer.TokenStreamComponents createComponents(String var1);

需要将org.apache.lucene.analysis的类IKAnalyzer,IKTokenizer拷贝修改:

import org.apache.lucene.analysis.Analyzer;

public class IKAnalyzer4Lucene7 extends Analyzer {

	private boolean useSmart = false;

	public IKAnalyzer4Lucene7() {
		this(false);
	}

	public IKAnalyzer4Lucene7(boolean useSmart) {
		super();
		this.useSmart = useSmart;
	}

	public boolean isUseSmart() {
		return useSmart;
	}

	public void setUseSmart(boolean useSmart) {
		this.useSmart = useSmart;
	}

	@Override
	protected TokenStreamComponents createComponents(String fieldName) {
		IKTokenizer4Lucene7 tk = new IKTokenizer4Lucene7(this.useSmart);
		return new TokenStreamComponents(tk);
	}

}
import java.io.IOException;

import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;

public class IKTokenizer4Lucene7 extends Tokenizer {

	// IK分词器实现
	private IKSegmenter _IKImplement;

	// 词元文本属性
	private final CharTermAttribute termAtt;
	// 词元位移属性
	private final OffsetAttribute offsetAtt;
	// 词元分类属性(该属性分类参考org.wltea.analyzer.core.Lexeme中的分类常量)
	private final TypeAttribute typeAtt;
	// 记录最后一个词元的结束位置
	private int endPosition;

	/**
	 * @param in
	 * @param useSmart
	 */
	public IKTokenizer4Lucene7(boolean useSmart) {
		super();
		offsetAtt = addAttribute(OffsetAttribute.class);
		termAtt = addAttribute(CharTermAttribute.class);
		typeAtt = addAttribute(TypeAttribute.class);
		_IKImplement = new IKSegmenter(input, useSmart);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.lucene.analysis.TokenStream#incrementToken()
	 */
	@Override
	public boolean incrementToken() throws IOException {
		// 清除所有的词元属性
		clearAttributes();
		Lexeme nextLexeme = _IKImplement.next();
		if (nextLexeme != null) {
			// 将Lexeme转成Attributes
			// 设置词元文本
			termAtt.append(nextLexeme.getLexemeText());
			// 设置词元长度
			termAtt.setLength(nextLexeme.getLength());
			// 设置词元位移
			offsetAtt.setOffset(nextLexeme.getBeginPosition(),
					nextLexeme.getEndPosition());
			// 记录分词的最后位置
			endPosition = nextLexeme.getEndPosition();
			// 记录词元分类
			typeAtt.setType(nextLexeme.getLexemeTypeString());
			// 返会true告知还有下个词元
			return true;
		}
		// 返会false告知词元输出完毕
		return false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.lucene.analysis.Tokenizer#reset(java.io.Reader)
	 */
	@Override
	public void reset() throws IOException {
		super.reset();
		_IKImplement.reset(input);
	}

	@Override
	public final void end() {
		// set final offset
		int finalOffset = correctOffset(this.endPosition);
		offsetAtt.setOffset(finalOffset, finalOffset);
	}
}

Ik中默认的停用词很少,我们往往需要扩展它。可从网址: https://github.com/cseryp/stopwords 下载一份比较全的停用词。

Ik中停用词的扩展步骤:

1、在类目录下创建IK的配置文件:IKAnalyzer.cfg.xml

2、在配置文件中增加配置扩展停用词文件的节点:

<entry key=“ext_stopwords”>my_ext_stopword.dic</entry>

如有多个,以“;”间隔

3、在类目录下创建我们的扩展停用词文件 my_ext_stopword.dic

4、编辑该文件加入停用词,一行一个

扩展 IKAnalyzer的词典:

每年都有很多的新词产生,往分词器的词典中添加新词的步骤:

1、在类目录下IK的配置文件:IKAnalyzer.cfg.xml 中增加配置扩展词文件的节点:

<entry key="ext_dict">ext.dic</entry>

如有多个,以“;”间隔

2、在类目录下创建扩展词文件 ext.dic

4、编辑该文件加入新词,一行一个

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">  
<properties>  
	<comment>IK Analyzer 扩展配置</comment>
	<!--用户可以在这里配置自己的扩展字典 -->
	<entry key="ext_dict">ext.dic</entry> 
	
	<!--用户可以在这里配置自己的扩展停止词字典-->
	<entry key="ext_stopwords">my_ext_stopword.dic</entry>
</properties>

ext_dict:字典,新词:比如奥利给

ext_stopwords:停用词:的,地,这

测试代码:

public class IkAnalyzerTestDemo {

   private static void doToken(TokenStream ts) throws IOException {
      ts.reset();
      CharTermAttribute cta = ts.getAttribute(CharTermAttribute.class);
      while (ts.incrementToken()) {
         System.out.print(cta.toString() + "|");
      }
      System.out.println();
      ts.end();
      ts.close();
   }

   public static void main(String[] args) throws IOException {
      String etext = "Don't be afraid of any difficulty we encounter. Smile at it. " +
            "The best way to eliminate fear is to face fear. Persistence is the victory. Come on, Ollie!";
      String chineseText = "我们遇到什么困难,也不要怕,微笑着面对它,消除恐惧的最好方法就是面对恐惧,坚持才是胜利,加油,奥利给! ";
      // IKAnalyzer 细粒度切分      try (Analyzer ik = new IKAnalyzer4Lucene7();) {
         TokenStream ts = ik.tokenStream("content", etext);
         System.out.println("IKAnalyzer中文分词器 细粒度切分,英文分词效果:");
         doToken(ts);
         ts = ik.tokenStream("content", chineseText);
         System.out.println("IKAnalyzer中文分词器 细粒度切分,中文分词效果:");
         doToken(ts);
      }

      // IKAnalyzer 智能切分      try (Analyzer ik = new IKAnalyzer4Lucene7(true);) {
         TokenStream ts = ik.tokenStream("content", etext);
         System.out.println("IKAnalyzer中文分词器 智能切分,英文分词效果:");
         doToken(ts);
         ts = ik.tokenStream("content", chineseText);
         System.out.println("IKAnalyzer中文分词器 智能切分,中文分词效果:");
         doToken(ts);
      }
   }
}

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表