TokenizerandTokenFilter区别

这几天在学习Lucene,感觉有些东西学习资料上没讲明白,不理解就容易忘,所以在网上搜了很多,功夫不负有心人,终于让我搜到一篇精华帖,粘出来与有心人分享。
原文出自http://biancheng.dnbcw.info/java/61305.html

从上图可以看出,四个Analyzer都是继承自Analyzer的。而Analyzer是一个抽象类,它只提供了一个叫tokenStream的虚函数,下面是Analyzer类的代码:
      public abstract class Analyzer {
         public abstract TokenStream tokenStream(String fieldName, Reader reader);
             …
      }
      接下来看看四个继承类的代码就会发现,它们的代码非常简单,Lucene把他们的实现细节隐藏在其他的一些类中了。

      public final class WhitespaceAnalyzer extends Analyzer {
           public TokenStream tokenStream(String fieldName, Reader reader) {
                return new WhitespaceTokenizer(reader);
           }
  }
public final class SimpleAnalyzer extends Analyzer {
 public TokenStream tokenStream(String fieldName, Reader reader) {
   return new LowerCaseTokenizer(reader);
 }
}
WhitespaceAnalyzer和SimpleAnalyzer非常的简单,它们只是把功能实现分别托管给了WhitespaceTokenizer和LowerCaseTokenizer。
public final class StopAnalyzer extends Analyzer {
 private Set stopWords;
 public static final String[] ENGLISH_STOP_WORDS = {
   "a", "an", "and", "are", "as", "at", "be", "but", "by",
   "for", "if", "in", "into", "is", "it",
   "no", "not", "of", "on", "or", "s", "such",
   "t", "that", "the", "their", "then", "there", "these",
   "they", "this", "to", "was", "will", "with"
 };
 …
 public TokenStream tokenStream(String fieldName, Reader reader) {
   return new StopFilter(new LowerCaseTokenizer(reader), stopWords);
 }
}
public class StandardAnalyzer extends Analyzer {
    private Set stopSet;
public static final String[] STOP_WORDS = StopAnalyzer.ENGLISH_STOP_WORDS;
public TokenStream tokenStream(String fieldName, Reader reader) {
            TokenStream result = new StandardTokenizer(reader);
            result = new StandardFilter(result);
           result = new LowerCaseFilter(result);
             result = new StopFilter(result, stopSet);
             return result;
      }
}
StopAnalyzer虽然复杂了一些,但其实也是把功能托管给了StopFilter。而StandardAnalyzer最复杂,它用到了三个Filter,分别是StandardFilter、LowerCaseFilter和StopFilter。
从上面的代码不难看出,四个Analyzer其实只和两个类型在打交道,就是各种Tokenizer和各种Filter。让我们看一下这里的继承体系:[见图二]

      原来各种Filter都继承自TokenFilter,各种Tokenizer都继承自Tokenizer。而这两个抽象类又全都继承自TokenStream,TokenFilter除了继承自TokenStream以外还拥有一个TokenStream的实例。
      那TokenStream是个什么类呢?正如它的名字,TokenStream其实就是一个token流,或者说token的序列。下面是TokenStream的代码:
      public abstract class TokenStream {
          public abstract Token next() throws IOException;
public void close() throws IOException {}
      }
      TokenStream只提供了一个虚函数next,每次调用next函数就可以获得TokenStream中的一个token,重复调用就可以遍历一个TokenStream中的所有token。
      那么到底什么是Tokenizer,什么又是TokenFilter呢?
      Lucene的注释中这样说:
A Tokenizer is a TokenStream whose input is a Reader.
A TokenFilter is a TokenStream whose input is another token stream.
从这两句话可以看出,Tokenizer是一个以Reader为输入的TokenStream;而TokenFilter是一个以另一个TokenStream为输入的TokenStream。表面上看两者只是输入不同,但正因为这一点,Tokenizer被用来做初级的文本处理,它把从Reader读入的原始文本通过一些简单的办法处理成一个个初级的token;TokenFilter则以Tokenizer为输入(因为Tokenizer继承自TokenStream),用一些规则过滤掉不符合要求的token(像StopFilter中的停用词),产生最终的token stream。还记得前文说的WhitespaceAnalyzer和SimpleAnalyzer引用的都是Tokenizer,StopAnalyzer和StandardAnalyzer引用的都是TokenFilter吗?这就是因为前二者处理规则比较简单,用Tokenizer把Reader的输入经过一步处理就够了;后二者处理要复杂一些,需要用到TokenFilter,而TokenFilter在Tokenizer处理的基础上进行一些过滤,这样才能满足后二者的需要。(待续)
附:测试四个Analyzer的代码
/**
* Adapted from code which first appeared in a java.net article
* written by Erik
*/
public class AnalyzerDemo {
private static final String[] examples = {
"The quick brown fox jumped over the lazy dogs",
"XY&Z Corporation - xyz@example.com"
};
private static final Analyzer[] analyzers = new Analyzer[] {
new WhitespaceAnalyzer(),
new SimpleAnalyzer(),
new StopAnalyzer(),
new StandardAnalyzer()
};
Listpublic static void main(String[] args) throws IOException {
// Use the embedded example strings, unless
// command line arguments are specified, then use those.
String[] strings = examples;
if (args.length > 0) {
strings = args;
}
for (int i = 0; i < strings.length; i++) {
analyze(strings[i]);
}
}
private static void analyze(String text) throws IOException {
System.out.println("Analyzing \"" + text + "\"");
for (int i = 0; i < analyzers.length; i++) {
Analyzer analyzer = analyzers[i];
String name = analyzer.getClass().getName();
name = name.substring(name.lastIndexOf(".") + 1);
System.out.println(" " + name + ":");
System.out.print(" ");
AnalyzerUtils.displayTokens(analyzer, text);
System.out.println("\n");
}
}
}
public class AnalyzerUtils {
public static Token[] tokensFromAnalysis
(Analyzer analyzer, String text) throws IOException {
TokenStream stream =
analyzer.tokenStream("contents", new StringReader(text));
ArrayList tokenList = new ArrayList();
while (true) {
Token token = stream.next();
if (token == null) break;
tokenList.add(token);
}
return (Token[]) tokenList.toArray(new Token[0]);
}
 
public static void displayTokens
(Analyzer analyzer, String text) throws IOException {
Token[] tokens = tokensFromAnalysis(analyzer, text);
for (int i = 0; i < tokens.length; i++) {
Token token = tokens[i];
System.out.print("[" + token.termText() + "] ");
}
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值