开源搜索框架Lucene学习之分词器(2)——TokenFilter类及其子类

      前面我们分析了一下Tokenizer类及它的子类,Tokenizer类继承于TokenStream类,它的作用主要是把一个字符串分隔成一个个的词,不同的子类实现不同的切分方式。有按空格的,有按非英文字符的。把切分出来的词Token组合成TokenStream。今天我们要讨论的是TokenFilter及其子类。TokenFilter类也是继承于TokenSteam类,它的作用是对分出来的词进行一些处理,比如去掉停词,转换大小写。我们来看TokenFilter类的代码:

abstract public class TokenFilter : TokenStream
{
    ///<summary>
    ///需要传过来的处理的TokenStream
    ///The source of tokens for this filter. 
    ///</summary>
    protected TokenStream input;
 
    ///<summary> Close the input TokenStream. </summary>
    public override void Close()
    {
        input.Close();
    }
 
}

     也是一个抽象类,它里面定义了一个受保护的成员TokenStream类型的input,我们知道在Tokenizer类里面定义了一个受保护的TextReader类型的input,Tokenizer类里面接收的是一个文本流,而TokenFilter类则需要接收一个TokenStream,也就是一个语汇单元流。具体的流程就是把一个字符串传递给Tokenizer,Tokenizer把这个字符串分拆成一个个的Token,然后把这些Token组合成一个TokenStream,也就是一个语汇单元流,然后把这个语汇单元流传给TokenFilter,TokenFilter会对TokenStream里面的每一个Token进行一下处理。根据处理方式的不同,由不同的子类来实现这些处理方式。先来看看第一个子类LowerCaseFilter,也就是把每个Token都转换成小写的。

public class LowerCaseFilter : TokenFilter
{
    /// <summary>
    /// Initializes a new instance of the LowerCaseFilter class.
    /// </summary>
    /// <param name="ts">Token stream to read from.</param>
    public LowerCaseFilter(TokenStream ts)
    {
        input = ts;
    }
 
    /// <summary>
    /// Returns the next token from the stream.
    /// </summary>
    /// <returns>The next token or null if EOS.</returns>
    public override Token Next()
    {
        Token t = input.Next();
 
        if (t == null)
            return null;
 
        t.TermText = t.TermText.ToLower();
 
        return t;
    }
}

     主要就是Next方法,里面就是把每一个Token转换成小写。方法比较简单,就不用解释了。再看第二个子类,去掉停词的类StopFilter,我们就只看Next方法,代码如下:

public override Token Next()
{
    // return the first non-stop word found
    for (Token token = input.Next(); token != null; token = input.Next())
        if (table[token.TermText] == null)
            return token;
    // reached EOS -- return null
    return null;
}

     这个方法里面有一个table变量,它是一个HashTable的对象,里面装的就是停词,也就是那些没有实际意义,需要剔除的词,这个停词集合,在这个类里面有一个初始化,也就是英文中常用的停词集合,你也可以自己传入一个停词的集合。Next方法主要就是遍历每一个Token,看其是否是停词,如果是的,就去掉。

     接下来要看的一个子类就比较有意思,它的作用就是把词元进行一些Stem处理,Stem就是把每一个词元还原成原型,比如cars转换成car。这里会用到一个著名的的stemming算法,全称是The Porter Stemming Algorithm,其主页为http://tartarus.org/~martin/PorterStemmer/,也可查看其论文http://tartarus.org/~martin/PorterStemmer/def.txt。通过以下网页可以进行简单的测试:Porter's Stemming Algorithm Online[http://facweb.cs.depaul.edu/mobasher/classes/csc575/porter.html]。比如cars –> car,driving –> drive,tokenization –> token。下面我们来看看这个类的Next方法:

public override Token Next()
{
    Token token = input.Next();
    if (token == null)
        return null;
    else
    {
        String s = stemmer.stem(token.TermText);
        if (s != token.TermText) // Yes, I mean object reference comparison here
            token.TermText = s;
        return token;
    }
}

    当然首先是定义了一个封装了stemming算法的类PorterStemmer的对象stemmer,然后调用这个里面的stem方法,把每一个Token都处理一下,返回即可。有时间的话把stemming算法单独拿出来解读一下。

    分词的一些基本类都已经介绍完成了,前面所介绍的都是一些简单的分词,Lucene里面内置了四个分词器,分别是WhitespaceAnalyzer,SimpleAnalyzer,StopAnalyzer还有一个StandardAnalyzer分词器,前三个分词器用前面介绍的一些类就可以完成其功能,StandardAnalyzer分词器比较复杂,下次将来解读,构成StandardAnalyzer分词器的StandardFilter类和StandardTokenizer类。

原文地址:https://www.cnblogs.com/xiaoxiangfeizi/p/2307357.html