注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Koala++'s blog

计算广告学 RTB

 
 
 

日志

 
 

Lucene源代码分析[2]  

2009-07-02 16:15:28|  分类: Lucene |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

         上次提到了Analyzer类,说它是用于对输入进行过滤,分词等,现在我们详细看一个这个类,Lucene中一个Analyzer通常由TokenizerTokenFilter组成,我们先看一下Tokenizer

public abstract class Tokenizer extends TokenStream {

    /** The text source for this Tokenizer. */

    protected Reader input;

 

    /** Construct a tokenizer with null input. */

    protected Tokenizer() {

    }

 

    /** Construct a token stream processing the given input. */

    protected Tokenizer(Reader input) {

       this.input = input;

    }

 

    /** By default, closes the input Reader. */

    public void close() throws IOException {

       input.close();

    }

}

    只是一个抽象类,而且也没什么值得我们关注的函数,我们看一下他的父类TokenStream:

public abstract class TokenStream {

    /** Returns the next token in the stream, or null at EOS. */

    public abstract Token next() throws IOException;

 

    /** Releases resources associated with this stream. */

    public void close() throws IOException {

    }

}

    原来值得我们关注的函数在它的父类中,next函数,它会返回流中的下一个token。其实刚才提到的另一个类TokenFilter也继承自TokenStream

public abstract class TokenFilter extends TokenStream {

    /** The source of tokens for this filter. */

    protected TokenStream input;

 

    /** Call TokenFilter(TokenStream) instead.

     * @deprecated */

    protected TokenFilter() {

    }

 

    /** Construct a token stream filtering the given input. */

    protected TokenFilter(TokenStream input) {

       this.input = input;

    }

 

    /** Close the input TokenStream. */

    public void close() throws IOException {

       input.close();

    }

}

    先写一个依然没有意义的测试类:

package forfun;

 

import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import org.apache.lucene.analysis.LetterTokenizer;

 

public class TokenTest

{

    public static void main( String[] args ) throws Exception

    {

       File f = new File( "E:\\source.txt" );

       BufferedReader reader = new BufferedReader(new FileReader(f));

      

       LetterTokenizer lt = new LetterTokenizer( reader );

       System.out.println( lt.next() );

    }

}

    Source.txt中我写的hello world!。当然你也可以写别的,我用LetterTokenizer进行分词,最后打印分词后的第一个token。我们先看一下他是如何分词的,也就是next到底在做什么。

public class LetterTokenizer extends CharTokenizer {

    /** Construct a new LetterTokenizer. */

    public LetterTokenizer(Reader in) {

       super(in);

    }

 

    /** Collects only characters which satisfy

     * {@link Character#isLetter(char)}.*/

    protected boolean isTokenChar(char c) {

       return Character.isLetter(c);

    }

}

    函数isTokenChar来判断c是不是一个字母,它并没有实现next函数,我们到它的父类看一下,找到了next函数:

/** Returns the next token in the stream, or null at EOS. */

public final Token next() throws IOException {

    int length = 0;

    int start = offset;

    while (true) {

       final char c;

 

       offset++;

       if (bufferIndex >= dataLen) {

           dataLen = input.read(ioBuffer);

           bufferIndex = 0;

       }

       ;

       if (dataLen == -1) {

           if (length > 0)

              break;

           else

              return null;

       } else

           c = ioBuffer[bufferIndex++];

 

       if (isTokenChar(c)) { // if it's a token char

 

           if (length == 0) // start of token

              start = offset - 1;

 

           buffer[length++] = normalize(c); // buffer it, normalized

 

           if (length == MAX_WORD_LEN) // buffer overflow!

              break;

 

       } else if (length > 0) // at non-Letter w/ chars

           break; // return 'em

 

    }

 

    return new Token(new String(buffer, 0, length), start,

start + length);

}

    看起来很长,其实很简单,至少读起来很简单,其中isTokenChar就是我们刚才在LetterTokenizer中看到的,代码中用start记录一个token的起始位置,用length记录它的长度,如果不是字符的话,就break;,我们看到一个新的类Token,这里它的构造参数有字符串,起始位置,结束位置。

    看一下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;

 

/** Constructs a Token with the given term text, and start & end offsets.

 The type defaults to "word." */

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

    termText = text;

    startOffset = start;

    endOffset = end;

}

 

/** Constructs a Token with the given text, start and end offsets, & type. */

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

    termText = text;

    startOffset = start;

    endOffset = end;

    type = typ;

}

    和我们刚才用到的构造函数对应一下,就知道三个成员变量的意思了,typepositionIncrement我还是引用一下别的人话,Type主要用来表示文本编码和语言类型,single表示单个ASCII字符,double表示non-ASCII字符,Word是默认的不区分的字符类型。而positionIncrement表示位置增量,用于处理拼音之类的情况(拼音就在那个词的上方)

 

 

 

 

 

 

  评论这张
 
阅读(1316)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017