读书人

关于lucene的分词(1)

发布时间: 2012-10-09 10:21:45 作者: rapoo

关于lucene的分词(一)

算法和数据结构分析:

由于Analysis包比较简单,不详述了!

算法:基于机械分词 1-gram,2-gram,HMM(如果使用ICTCLAS接口的话)

数据结构:部分源码用到了Set ,HashTable,HashMap

认真理解Token

Lucene中的Analysis包专门用于完成对于索引文件的分词.Lucene中的Token是一个非常重要的概念.

看一下其源码实现:

public final class Token {

String termText;????????????????????? // the text of the term

int startOffset;???????????????????????? // start in source text

int endOffset;????????????????????????? // end in source text

String type = "word";????????????????????? // lexical type

private int positionIncrement = 1;

public Token(String text, int start, int end)

public Token(String text, int start, int end, String typ)

public void setPositionIncrement(int positionIncrement)

public int getPositionIncrement() { return positionIncrement; }

public final String termText() { return termText; }

public final int startOffset() { return startOffset; }

public void setStartOffset(int givenStartOffset)

public final int endOffset() { return endOffset; }

public void setEndOffset(int givenEndOffset)

public final String type() { return type; }

public String toString()

}

下面编一段代码来看一下

TestToken.java

package org.apache.lucene.analysis.test;

import org.apache.lucene.analysis.*;

import org.apache.lucene.analysis.standard.StandardAnalyzer;

import java.io.*;

public class TestToken

{

public static void main(String[] args)

{

??? String string = new String("我爱天大,但我更爱中国");

//Analyzer analyzer = new StandardAnalyzer();

Analyzer analyzer = new TjuChineseAnalyzer();

//Analyzer analyzer= new StopAnalyzer();

??? TokenStream ts = analyzer.tokenStream("dummy",new StringReader(string));

??? Token token;

??? try

??? {

????? int n=0;

????? while ( (token = ts.next()) != null)

????? {

??????? System.out.println((n++)+"->"+token.toString());

????? }

??? }

??? catch(IOException ioe)

??? {

????? ioe.printStackTrace();

??? }

?

}

}注意看其结果如下所示

0->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(我,0,1,<CJK>,1)

1->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(爱,1,2,<CJK>,1)

2->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(天,2,3,<CJK>,1)

3->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(大,3,4,<CJK>,1)

4->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(但,5,6,<CJK>,1)

5->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(我,6,7,<CJK>,1)

6->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(更,7,8,<CJK>,1)

7->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(爱,8,9,<CJK>,1)

8->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(中,9,10,<CJK>,1)

9->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(国,10,11,<CJK>,1)

注意:其中”,”被StandardAnalyzer给过滤掉了,所以大家注意第4个Token直接startOffset从5开始.

如果改用StopAnalyzer()

0->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(我爱天大,0,4,word,1)

1->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(但我更爱中国,5,11,word,1)

改用TjuChineseAnalyzer(我写的,下文会讲到如何去写)

0->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(爱,3,4,word,1)

1->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(天大,6,8,word,1)

2->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(更,19,20,word,1)

3->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(爱,22,23,word,1)

4->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(中国,25,27,word,1)

讲明白了Token,咱们来看以下其他的东西

一个TokenStream是用来走访Token的iterator(迭代器)

看一下其源代码:

public abstract class TokenStream {

public abstract Token next() throws IOException;

public void close() throws IOException {}

}

一个Tokenizer,is-a TokenStream(派生自TokenStream),其输入为Reader

看一下其源码如下:

public abstract class Tokenizer extends TokenStream {

protected Reader input;

protected Tokenizer() {}

protected Tokenizer(Reader input) {

??? this.input = input;

}

public void close() throws IOException {

??? input.close();

}

}

一个TokenFilter isa TokenStream(派生自TokenStream),其义如名就是用来完成对TokenStream的过滤操作,譬如

去StopWords,将Token变为小写等。

源码如下:

public abstract class TokenFilter extends TokenStream {

protected TokenStream input;

protected TokenFilter() {}

protected TokenFilter(TokenStream input) {

??? this.input = input;

}

public void close() throws IOException {

??? input.close();

}

}

一个Analyzer就是一个TokenStream工厂

看一下其源码就:

public abstract class Analyzer {

public TokenStream tokenStream(String fieldName, Reader reader)

{

?????? return tokenStream(reader);

}

public TokenStream tokenStream(Reader reader)

{

?????? return tokenStream(null, reader);

}

}

好,现在咱们来看一下Lucene的Analysis包下面的各个类文件都是用来干什么的。按照字典排序。

Analysis包中的源码详解

Analyzer.java 上文已经讲过。

CharTokenizer.java 此类为简单一个抽象类,用来对基于字符的进行简单分词(tokenizer)

LetterTokenizer.java两个非字符之间的字符串定义为token(举例来说英文单词由空白隔开,那个两个空白之间的字符串即被定义为一个token。备注:对于绝大多数欧洲语言来说,这个类工作效能很好。当时对于不用空白符分割的亚洲语言,效能极差(譬如中日韩)。)

LowerCaseFilter.java is-a TokenFilter用于将字母小写化

LowerCaseTokenizer is-a Tokenizer功能上等价于LetterTokenizer+LowerCaseFilter

PerFieldAnalyzerWrapper是一个Analyzer,因为继承自Analyzer当不同的域(Field)需要不同的语言分析器(Analyzer)时,这个Analyzer就派上了用场。使用成员函数addAnalyzer可以增加一个非缺省的基于某个Field的analyzer。很少使用。

PorterStemFilter.java使用词干抽取算法对每一个token流进行词干抽取。

PorterStemmer.java 有名的P-stemming算法

SimpleAnalyzer.java

StopAnalyzer.java?? 具有过滤停用词的功能

StopFilter.java???? StopFilter为一个Filter,主要用于从token流中去除StopWords

Token.java?????? 上面已讲.

TokenFilter.java?? 上面已经讲了

Tokenizer.java???? 上面已经讲了

TokenStream.java?? 上面已经讲了

WhitespaceAnalyzer.java

WhitespaceTokenizer.java 只是按照space区分Token.

读书人网 >软件架构设计

热点推荐