一、概述
1.1 分詞的基本過(guò)程
首先是TokenStream
通過(guò)接收一個(gè)StringReader
流將需要進(jìn)行分詞的內(nèi)容讀入進(jìn)來(lái)相味,TokenStream
有兩個(gè)子抽象類Tokenizer
和TokenFilter
粹胯。讀入的過(guò)程為:StringReader
流經(jīng)過(guò)Tokenizer
接收輸入流并根據(jù)輸入流進(jìn)行詞切分,然后會(huì)經(jīng)過(guò)多個(gè)TokenFilter
對(duì)TokenStream
進(jìn)行過(guò)濾咨演,例如去掉一些索引詞闸昨、替代同義索引詞等操作,最后生成TokenStream
薄风。
1.2 Tokenizer
1
Tokenizer
主要負(fù)責(zé)接收Reader
字節(jié)流饵较,將Reader
進(jìn)行分詞操作,即將一組數(shù)據(jù)劃分不同的語(yǔ)匯單元遭赂。KeyWordTokenizer
是關(guān)鍵詞分詞循诉,StandardTokenizer
是標(biāo)準(zhǔn)分詞,CharTokenizer
是字符分詞撇他,WhitespaceTokenizer
是空白分詞茄猫,LetterTokenizer
是標(biāo)點(diǎn)分詞,LowerCaseTokenizer
是小寫(xiě)分詞(將各個(gè)語(yǔ)匯單元轉(zhuǎn)換成小寫(xiě))困肩。這里我們說(shuō)明一下
WhitespaceTokenizer
和LetterTokenizer
划纽,比如有這樣一句內(nèi)容:how are you I’m a teacher
。那么前者會(huì)分成這樣:how锌畸、 are勇劣、 you、 I’m、 a比默、 teacher
幻捏,而后者會(huì)分成:how、 are命咐、 you篡九、 I 、m醋奠、 a榛臼、 teacher
。
1.3 TokenFilter
2
TokenFilter
類繼承于TokenStream
钝域,其輸入是另一個(gè)TokenStream
讽坏,主要職責(zé)是對(duì)TokenStream
進(jìn)行過(guò)濾,例如去掉一些索引詞例证、替代同義索引詞等操作路呜。上面給出各類過(guò)濾器,這里只是作為了解织咧,后面再細(xì)說(shuō)胀葱。
二、入門(mén)示例(工程lucene_analyzer01
)
AnalyzerUtils.java
package cn.itcast.util;
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.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
public class AnalyzerUtils {
public static void displayToken(String str, Analyzer analyzer) {
try {
//首先我們使用分詞器analyzer將相關(guān)數(shù)據(jù)(這里比如是內(nèi)容gcontent)進(jìn)行分詞笙蒙,這樣得到一個(gè)詞匯流
//然后我們給這個(gè)流做一個(gè)標(biāo)記抵屿,可以用來(lái)遍歷此流
TokenStream stream = analyzer.tokenStream("content",new StringReader(str));//這就是一個(gè)詞匯流
CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);//相當(dāng)于一個(gè)標(biāo)記,隨著流增加
while (stream.incrementToken()) {
System.out.print("[" + cta + "]");
}
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
}
}
測(cè)試:TestAnalyzer.java
@Test
public void test01(){
Analyzer analyzer1 = new StandardAnalyzer(Version.LUCENE_35);//標(biāo)準(zhǔn)分詞器
Analyzer analyzer2 = new StopAnalyzer(Version.LUCENE_35);//停用分詞器
Analyzer analyzer3 = new SimpleAnalyzer(Version.LUCENE_35);//簡(jiǎn)單分詞器
Analyzer analyzer4 = new WhitespaceAnalyzer(Version.LUCENE_35);//空格分詞器
String text = "this is my house,I am come form Xian,My email is "
+ "xxx@qq.com,and my qq is 154625554";
AnalyzerUtils.displayToken(text, analyzer1);
AnalyzerUtils.displayToken(text, analyzer2);
AnalyzerUtils.displayToken(text, analyzer3);
AnalyzerUtils.displayToken(text, analyzer4);
}
說(shuō)明:可以看到我們構(gòu)造一個(gè)TokenStream
流捅位,此流接收兩個(gè)參數(shù)轧葛,第一個(gè)參數(shù)表示要進(jìn)行分詞的域(這里隨便),而第二個(gè)參數(shù)就是一個(gè)StringReader
流艇搀。而CharTermAttribute
相當(dāng)于流中的一個(gè)標(biāo)記尿扯,隨著流而增減,用戶我們遍歷流中各個(gè)語(yǔ)匯單元焰雕。而相關(guān)的分詞器我們通過(guò)參數(shù)傳入進(jìn)去衷笋。分詞結(jié)果為:
3
從結(jié)果我們可以看到各個(gè)分詞器的作用和區(qū)別。下面我們?cè)贉y(cè)試一下中文分詞:
@Test
public void test02(){
//對(duì)中文分詞不適用
Analyzer analyzer1 = new StandardAnalyzer(Version.LUCENE_35);//標(biāo)準(zhǔn)分詞器
Analyzer analyzer2 = new StopAnalyzer(Version.LUCENE_35);//停用分詞器
Analyzer analyzer3 = new SimpleAnalyzer(Version.LUCENE_35);//簡(jiǎn)單分詞器
Analyzer analyzer4 = new WhitespaceAnalyzer(Version.LUCENE_35);//空格分詞器
String text = "西安市雁塔區(qū)";
AnalyzerUtils.displayToken(text, analyzer1);
AnalyzerUtils.displayToken(text, analyzer2);
AnalyzerUtils.displayToken(text, analyzer3);
AnalyzerUtils.displayToken(text, analyzer4);
}
測(cè)試結(jié)果為:
4
可見(jiàn)一般的分詞器對(duì)中文分詞作用不大矩屁。
下面看語(yǔ)匯單元的一些屬性:
AnalyzerUtils.java
public static void displayAllTokenInfo(String str, Analyzer analyzer){
try {
TokenStream stream = analyzer.tokenStream("content", new StringReader(str));
PositionIncrementAttribute pia = stream.addAttribute(PositionIncrementAttribute.class);
OffsetAttribute oa = stream.addAttribute(OffsetAttribute.class);
CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);
TypeAttribute ta = stream.addAttribute(TypeAttribute.class);
while (stream.incrementToken()) {
System.out.print("位置增量: " + pia.getPositionIncrement());//詞與詞之間的空格
System.out.print("辟宗,單詞: " + cta + "[" + oa.startOffset() + "," + oa.endOffset() + "]");
System.out.print(",類型: " + ta.type()) ;
System.out.println();
}
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
}
測(cè)試
@Test
public void test03(){
//對(duì)中文分詞不適用
Analyzer analyzer1 = new StandardAnalyzer(Version.LUCENE_35);//標(biāo)準(zhǔn)分詞器
Analyzer analyzer2 = new StopAnalyzer(Version.LUCENE_35);//停用分詞器
Analyzer analyzer3 = new SimpleAnalyzer(Version.LUCENE_35);//簡(jiǎn)單分詞器
Analyzer analyzer4 = new WhitespaceAnalyzer(Version.LUCENE_35);//空格分詞器
String text = "how are you thank you";
System.out.println("************標(biāo)準(zhǔn)分詞器***************");
AnalyzerUtils.displayAllTokenInfo(text, analyzer1);
System.out.println("************停用分詞器***************");
AnalyzerUtils.displayAllTokenInfo(text, analyzer2);
System.out.println("************簡(jiǎn)單分詞器***************");
AnalyzerUtils.displayAllTokenInfo(text, analyzer3);
System.out.println("*************空格分詞器**************");
AnalyzerUtils.displayAllTokenInfo(text, analyzer4);
}
說(shuō)明:
- 語(yǔ)匯單元類型
TypeAttribute
:語(yǔ)匯單元的類型吝秕,一般有word
和ALPHANUM
兩種類型泊脐。 - 語(yǔ)匯單元偏移量
OffsetAttribute
:就是起始字符和終止字符之間的偏移量。這里我們舉例說(shuō)明烁峭,比如對(duì)how are you thank you
進(jìn)行分詞晨抡,那么各個(gè)語(yǔ)匯單元之間的偏移量為
5 - 語(yǔ)匯單元位置增量
PositionIncrementAttribute
:位置增量就是語(yǔ)匯單元之間的距離,比如上面的分詞如果不將某些語(yǔ)匯濾除,那么各個(gè)語(yǔ)匯單元之間的位置增量都是1耘柱,但是如果有些單元被濾掉,比如are
關(guān)鍵詞棍现,那么how
和you
之間的位置增量則為2调煎。我們看測(cè)試結(jié)果為:
6