本文主要介紹在Lucene中集成IKAnalyzer
1 環境介紹
系統:win10
lucene版本:7.3.0 https://lucene.apache.org/
jdk:1.8
2 IKAnalyzer 集成說明
IK分詞器最先作為lucence上使用而開發,主要用於對中文的分詞,后來發展成獨立的分詞組件,目前只提供到lucence 4.0版本的支持,我們在使用4.0以后的版本的時候需要簡單的集成一下。
IK需要集成一因為lucence4.0后,Analyer的createComponents方法的參數改變了。
我們在ikAnalyzer包中提供的Lucence支持類中可以看到
4.0后的版本中,該方法的參數只有一個fileldName,沒有第二個輸入流參數。故需要修改后使用
3 maven 依賴引用
<!-- lucene 核心模塊 -->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>7.3.0</version>
</dependency>
<!-- ikanalyzer 中文分詞器 -->
<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>
4 重寫IKAnalyer 類
我們重命名為IKAnalyzer4Lucene7,我們把ik包下的ikanalyer類里面的內容全部復制到IKAnalyzer4Lucene7中即可。然后修改createComponents方法。
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);
}
}
5 重寫IKTokenizer類
我們重命名為IKTokenizer4Lucene7,我們把ik包下的iktokenizer類里面的內容全部復制到IKTokenizer4Lucene7中即可。然后修改構造方法。
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);
}
}
6 詞典擴展
6.1 停用詞擴展
1 在類目錄下創建IK的配置問題:IKAnalyzer.cfg.xml
2 在配置文件中增加配置的停用詞文件的節點: <entry key="ext_stopwords">my_ext_stopword.dic</entry>
3 在類目前下創建擴展停用詞文件my_ext_stopword.dic
4, 在停用詞文件中添加,一行一個。
6.2 擴展字典
字典中的詞,IK會作為一個整體去分詞,如‘厲害了我的國’,不會進行拆分
1 在類目前下創建擴展詞文件ext.dic
2 在文件中添加,一行一個。
3 在配置文件中增加配置的停用詞文件的節點: <entry key="ext_dict">ext.dic</entry>
整體如下圖:
配置文件IKAnalyer.cfg.xml:
停用詞文件:
擴展詞文件:
7 IK分詞器使用效果
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 = "Analysis is one of the main causes of slow indexing. Simply put, ";
// String chineseText = "張三說的確實在理。";
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);
}
}
}
運行結果:
注意:一定要確認加載了擴展文件,否則不會生效。