lucene analyzer 体系结构一览

分词这块内容往往是做搜索的入门级内容,例如我们刚接触搜索的时候,经常会碰到“想要检索的检索不到”的问题,这时得对分词有个大概的了解了。

这里是简要分析,因此我用的是lucene1.9来分析(目前看的源码主要也是1.9版本,虽然都快出4.0了)

 

一)体系结构

首先我们了解两组类结构,一是Analyzer,二是TokenStream。

图1:analyzer类结构

图2:TokenStream类结构

TokenStream有两个直接子类:TokenFilter和Tokenizer,其最主要的区别是:TokenFilter接收一个TokenStream进行再加工;Tokenizer接收一个Reader进行基础性分词。

然后Analyzer是一个包装器,一般选用一个Tokenizer,外加多个TokenFilter(当然也可以不加TokenFilter)构成一个分词器。

细细想想和java I/O的设计有点类似。

 

举例:StandardAnalyzer算是最复杂的分词器了(在1.9中),他的组装方式如下:

TokenStream result = new  StandardTokenizer(reader);
result = new  StandardFilter(result);
result = new  LowerCaseFilter(result);
result = new  StopFilter(result, stopSet);

不难看出,StandardAnalyzer首先选用StandardTokenizer进行分词,然后逐一通过StandardFilter、LowerCaseFilter、StopFilter进行再加工处理。

 

二)Tokenizer

Tokenizer就是按照指定规则将Reader划分成一个个词(Token),例如WhitespaceTokenizer就是按照空格进行划分,LetterTokenizer就是按照是不是字母进行划分,KeywordTokenizer就是将整个reader的内容作为一个token,等等。

对于CharTokenizer(LetterTokenizer、KeywordTokenizer)都是基于字符进行判断的,因此有一个方法比较重要,就是isTokenChar(char c)。

简单看看KeywordTokenizer的源码,如下:

public  Token next() throws  IOException {
   if  (!done) {
     done = true ;
     StringBuffer buffer = new  StringBuffer();
     int  length;
     while  ( true ) {
       length = input.read( this .buffer);
       if  (length == - 1 ) break ;
 
       buffer.append( this .buffer, 0 , length);
     }
     String text = buffer.toString();
     return  new  Token(text, 0 , text.length());
   }
   return  null ;
}

他将输入的内容作为一个整词输出。

 

三)TokenFilter

TokenFilter是对Tokenizer的再加工,包括字符小写(LowerCaseFilter)、去停用词(StopFilter)等。

LowerCaseFilter源码如下:

public  final  Token next() throws  IOException {
   Token t = input.next();
 
   if  (t == null )
     return  null ;
 
   t.termText = t.termText.toLowerCase();
 
   return  t;
}

这里不需过多解释,强调一下TokenFilter的输入时一个TokenStream,他们可以穿起来,形成一条加工线。

StopFilter源码如下:

/**
  * Returns the next input Token whose termText() is not a stop word.
  */
public  final  Token next() throws  IOException {
   // return the first non-stop word found
   for  (Token token = input.next(); token != null ; token = input.next())
   {
       String termText = ignoreCase ? token.termText.toLowerCase() : token.termText;
       if  (!stopWords.contains(termText))
         return  token;
   }
   // reached EOS -- return null
   return  null ;
}

这里有对字符大小写的控制。停用词存放在set中,对TokenStream中的Token进行逐一排查。

 

四)中文分词

中文分词目前主要是基于词库的方式,然后做最大匹配。例如IKAnalyzer。

也有基于统计的作法,例如CNSmart(Lucene提供)。

这里面又包括:人名、地名、机构名称的识别,未登录词的识别,歧义消除等内容。

posted @ 2018-01-23 15:00  車輪の唄  阅读(13)  评论(0编辑  收藏  举报  来源