IKAnalyzer:IK分词器,采用特有的“正向迭代最细粒度切分算法”,支持细粒度和智能分词两种切分方式。
支持中文、数字、中文词汇等分词处理,兼容韩文、日语字符。
例子:主要展示细粒度和智能分词两种切分方式的不同。
Analyzer analyzer = new IKAnalyzer(); //默认构造函数是细粒度切分
还有一种构造函数:
Analyzer analyzer = new IKAnalyzer(true);//为true时支持智能切分,false为细粒度切分
细粒度:
package com.xuzengqiang.design.common.lucene.demo;
import java.io.IOException;
import java.io.StringReader;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.wltea.analyzer.lucene.IKAnalyzer;
/**
* 描述:IKAnalyzer
* @author xuzengqiang
*/
public class IKAnalyzerDemo {
public static void main(String[] args) {
String words = "IKAnalyzer是一个开源的, 基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始,IKAnalyzer已经推出了3个大版本。";
Analyzer analyzer = new IKAnalyzer();
StringReader reader = new StringReader(words);
TokenStream token = null;
try {
// 直接这样写会抛出java.lang.IllegalStateException: TokenStream contract
// violation: reset()/close() call missing,
// reset() called multiple times, or subclass does not call
// super.reset(). Please see Javadocs of
// TokenStream class for more information about the correct
// consuming workflow.可以查看TokenStream
// API在使用incrementToken()之前必须先reset()一次
token = analyzer.tokenStream("", reader);
CharTermAttribute term = token.getAttribute(CharTermAttribute.class);
token.reset();
// 遍历分词数据
while (token.incrementToken()) {
System.out.print(term.toString() + "|");
}
token.end();
} catch (IOException e) {
e.printStackTrace();
} finally {
destroyResource(token, reader);
}
System.out.println();
}
public static void destroyResource(TokenStream token, StringReader reader) {
try {
if (token != null) {
token.close();
}
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
打印结果:
ikanalyzer|是|一个|一|个|开源|的|基于|java|语言|开发|的|轻量级|量级|的|中文|分词|工具包|工具|包|从|2006|年|12|月|推出|1.0|版|开始|ikanalyzer|已经|推出|出了|3|个|大|版本|
当将构造函数换成new IKAnalyzer(true);之后打印:
ikanalyzer|是|一个|开源|的|基于|java|语言|开发|的|轻量级|的|中文|分词|工具包|从|2006年|12月|推出|1.0版|开始|ikanalyzer|已经|推|出了|3个|大|版本|
另外也可以使用这种方式分词:
package com.xuzengqiang.design.common.lucene.demo;
import java.io.IOException;
import java.io.StringReader;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;
import org.wltea.analyzer.lucene.IKAnalyzer;
/**
* 描述:IKAnalyzer
* @author xuzengqiang
*/
public class KAnalyzerDemoTwo {
public static void main(String[] args) {
String words = "IKAnalyzer是一个开源的, 基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始,IKAnalyzer已经推出了3个大版本。";
StringReader reader = new StringReader(words);
IKSegmenter segmenter = new IKSegmenter(reader, true);
Lexeme lexeme = null;
try {
while ((lexeme = segmenter.next()) != null) {
System.out.print(lexeme.getLexemeText() + "|");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println();
}
}
IKsegementer:IK分词器的核心类。
public IKSegmenter(Reader input , boolean useSmart)
参数1:字符输入读取,userSmart:是否采用智能切分策略,true:智能切分,false:最细粒度切分。
public IKSegmentation(Reader input , Configuration cfg)
参数2:分词器配置,用户可以定制自己的Configuration,来改变词典的配置。
public synchronized Lexeme next()throws IOException
读取分词器切分出来的下一个语义单元。为null分词结束。Luxeme语义单元对象,类似于Lucene Token.
public int getBeginPosition()
获取语义单元的起始字符在文本中的位置。
public int getEndPosition()
获取语义单元结束字符的下一个位置。
public int getLength()
获取语义单元包含字符串的长度。
public String getLexemeText()
获取语义单元包含字符串的内容。
IKAnalyzer扩展字典配置,需要配置IKAnalyzer.cfg.xml文件,放在源文件目录下:
分词器的词典文件格式是无BOM 的UTF-8 编码的中文文本文件,文件扩展名不限。词典中,每个中文词汇独立占一行,使用\r\n 的DOS 方式换行。可以参考jar包下面的main2012.dic文件。推荐与配置文件放在同一目录下。
IKAnalyzer.cfg.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IKAnalyzer扩展配置</comment>
<!-- 扩展字典: -->
<entry key="ext_dict">vnetoo_directory.dic</entry>
<!-- 扩展停止词字典:排除对该关键字的搜索 -->
<entry key="ext_stopwords">vnetoo_stopword.dic</entry>
</properties>
自定义扩展字典vnetoo_directory.dic:
互联天下
许增强
艾贞堆
何亚飞
自定义扩展停止词字典:vnetoo_stopword.dic
的
是
或
或者
那么这个时候就可以看到分词器中不会包含该关键词了,且能够分出自定义的词了:
package com.xuzengqiang.design.common.lucene.demo;
import java.io.IOException;
import java.io.StringReader;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;
/**
* 描述:IKAnalyzer
* @author xuzengqiang
*/
public class KAnalyzerDemoTwo {
public static void main(String[] args) {
String words = "许增强或者何亚飞的杯子";
StringReader reader = new StringReader(words);
IKSegmenter segmenter = new IKSegmenter(reader, true);
Lexeme lexeme = null;
try {
while ((lexeme = segmenter.next()) != null) {
System.out.print(lexeme.getLexemeText() + "|");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println();
}
}
打印结果:
加载扩展词典:vnetoo_directory.dic
加载扩展停止词典:vnetoo_stopword.dic
许增强|何亚飞|杯子|
如果配置了配置自定义的扩展词库,可能有时候操作不需要使用,这个时候我们可以实现Configuration类,如果不需要使用,那么返回对应的getExtDictionarys()和getExtStopWordDictionarys() 为空即可。
package com.vnetoo.redu.common.lucene;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.InvalidPropertiesFormatException;
import java.util.List;
import java.util.Properties;
import org.wltea.analyzer.cfg.Configuration;
/**
* 描述:IKAnalyzer配置文件.需要实现Configuration接口
* 主要提供各种词典的文件路径
* 单例模式
* @author xuzengqiang
* @since 2015-1-14 13:53:56
*/
public class IKConfiguration implements Configuration {
/**
* 描述:主词典目录
*/
private static final String PATH_DIC_MAIN = "org/wltea/analyzer/dic/main2012.dic";
/**
* 描述:量词词典目录
*/
private static final String PATH_DIC_QUANTIFIER = "org/wltea/analyzer/dic/quantifier.dic";
/**
* 描述:配置文件目录
*/
private static final String FILE_NAME = "IKAnalyzer.cfg.xml";
/**
* 描述:扩展词典key名称
*/
private static final String EXT_DICT = "ext_dict";
/**
* 描述:禁用词典的key名称
*/
private static final String EXT_STOP = "ext_stopwords";
/**
* 描述:配置文件属性对象
*/
private Properties props;
/**
* 描述:是否使用智能分词
*/
private boolean useSmart;
/**
* 描述:是否使用扩展停止词典(默认使用)
*/
private boolean useStopword = Boolean.TRUE;
/**
* 描述:是否使用扩展词典(默认使用)
* @return
*/
private boolean useDict = Boolean.TRUE;
/**
* 描述:提供外部接口
* @return
*/
public static IKConfiguration getInstance() {
return new IKConfiguration();
}
/**
* 描述:配置文件读取
*/
private IKConfiguration() {
this.props = new Properties();
InputStream input = super.getClass().getClassLoader().getResourceAsStream(FILE_NAME);
if (input == null)
return;
try {
this.props.loadFromXML(input);
} catch (InvalidPropertiesFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public boolean useSmart() {
return this.useSmart;
}
public void setUseSmart(boolean useSmart) {
this.useSmart = useSmart;
}
public boolean isUseDict() {
return useDict;
}
public void setUseDict(boolean useDict) {
this.useDict = useDict;
}
public boolean isUseStopword() {
return useStopword;
}
public void setUseStopword(boolean useStopword) {
this.useStopword = useStopword;
}
/**
* 描述:获取主词典目录
*/
public String getMainDictionary() {
return "org/wltea/analyzer/dic/main2012.dic";
}
/**
* 描述:获取量词词典目录
*/
public String getQuantifierDicionary() {
return "org/wltea/analyzer/dic/quantifier.dic";
}
/**
* 描述:获取扩展词典的路径,当不需要使用扩展词典,返回空
*/
public List<String> getExtDictionarys() {
if (!isUseDict()) {
return null;
}
List<String> extDictFiles = new ArrayList<String>(2);
String extDictCfg = this.props.getProperty("ext_dict");
if (extDictCfg != null) {
String[] filePaths = extDictCfg.split(";");
if (filePaths != null) {
for (String filePath : filePaths) {
if ((filePath != null) && (!("".equals(filePath.trim())))) {
extDictFiles.add(filePath.trim());
}
}
}
}
return extDictFiles;
}
/**
* 描述:获取禁止词典的路径.当不需要使用时返回空
*/
public List<String> getExtStopWordDictionarys() {
if (!isUseStopword()) {
return null;
}
List<String> extStopWordDictFiles = new ArrayList<String>(2);
String extStopWordDictCfg = this.props.getProperty("ext_stopwords");
if (extStopWordDictCfg != null) {
String[] filePaths = extStopWordDictCfg.split(";");
if (filePaths != null) {
for (String filePath : filePaths) {
if ((filePath != null) && (!("".equals(filePath.trim())))) {
extStopWordDictFiles.add(filePath.trim());
}
}
}
}
return extStopWordDictFiles;
}
}
使用方法:
package com.xuzengqiang.design.common.lucene.demo;
import java.io.IOException;
import java.io.StringReader;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;
/**
* 描述:IKAnalyzer
* @author xuzengqiang
*/
public class KAnalyzerDemoTwo {
public static void main(String[] args) {
String words = "许增强或者何亚飞的杯子";
StringReader reader = new StringReader(words);
IKConfiguration config = IKConfiguration.getInstance();
config.setUseDict(false);
config.setUseStopword(false);
IKSegmenter segmenter = new IKSegmenter(reader, config);
Lexeme lexeme = null;
try {
while ((lexeme = segmenter.next()) != null) {
System.out.print(lexeme.getLexemeText() + "|");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println();
}
}
或者可以使用下面这种方式,推荐:
package com.xuzengqiang.design.common.lucene.demo;
import java.io.IOException;
import java.io.StringReader;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;
import org.wltea.analyzer.dic.Dictionary;
/**
* 描述:IKAnalyzer
* @author xuzengqiang
*/
public class KAnalyzerDemoTwo {
public static void main(String[] args) {
IKConfiguration config = IKConfiguration.getInstance();
config.setUseDict(false);
config.setUseStopword(false);
config.setUseSmart(false);
Dictionary.initial(config);
String words = "许增强或者何亚飞的杯子";
StringReader reader = new StringReader(words);
IKSegmenter segmenter = new IKSegmenter(reader, true);
Lexeme lexeme = null;
try {
while ((lexeme = segmenter.next()) != null) {
System.out.print(lexeme.getLexemeText() + "|");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println();
}
}
这种方式对第一中分词方式仍然适用:
package com.xuzengqiang.design.common.lucene.demo;
import java.io.IOException;
import java.io.StringReader;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.wltea.analyzer.dic.Dictionary;
import org.wltea.analyzer.lucene.IKAnalyzer;
/**
* 描述:IKAnalyzer
* @author xuzengqiang
*/
public class IKAnalyzerDemo {
public static void main(String[] args) {
IKConfiguration config = IKConfiguration.getInstance();
config.setUseDict(false);
config.setUseStopword(false);
Dictionary.initial(config);
String words = "游戏小苹果青花瓷";
Analyzer analyzer = new IKAnalyzer();
StringReader reader = new StringReader(words);
TokenStream token = null;
try {
CharTermAttribute term = token.getAttribute(CharTermAttribute.class);
token.reset();
// 遍历分词数据
while (token.incrementToken()) {
System.out.print(term.toString() + "|");
}
token.end();
} catch (IOException e) {
e.printStackTrace();
} finally {
destroyResource(token, reader);
}
System.out.println();
}
public static void destroyResource(TokenStream token, StringReader reader) {
try {
if (token != null) {
token.close();
}
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}