本章详细的讨论了 Lucene的分析处理过程和几个Analyzer.

在indexing过程中 要把需要indexing的text分析处理一下, 经过处理和切词 然后建立index. 而不通的Analyzer有不同的分析规则, 因此在程序中使用Lucene时 选择正确的Analyzer是很重要的.

1.Using Analyzers

在使用Analyzer以前 先来看看text经过Analyzer分析后的效果吧:

Listing 4.1 Visualizing analyzer effects
Analyzing "The quick brown fox jumped over the lazy dogs"
  WhitespaceAnalyzer:
    [The] [quick] [brown] [fox] [jumped] [over] [the] [lazy] [dogs]
  SimpleAnalyzer:
    [the] [quick] [brown] [fox] [jumped] [over] [the] [lazy] [dogs]
  StopAnalyzer:
    [quick] [brown] [fox] [jumped] [over] [lazy] [dogs]
  StandardAnalyzer:
    [quick] [brown] [fox] [jumped] [over] [lazy] [dogs]
 

Analyzing "XY&Z Corporation - xyz@example.com"
  WhitespaceAnalyzer:
    [XY&Z] [Corporation] [-] [xyz@example.com]
  SimpleAnalyzer:
    [xy] [z] [corporation] [xyz] [example] [com]
  StopAnalyzer:
    [xy] [z] [corporation] [xyz] [example] [com]
  StandardAnalyzer:
    [xy&z] [corporation] [xyz@example.com]

上面是在下面我们要提到的一个例子的运行结果. 可以看出不同的Analyzer 是如何来分析text的.在分析The quick brown fox jumped over the lazy dogs 时, WhitespaceAnalyzer和 SimpleAnalyzer只是简单的把词分开,建立Term就可以了;而另外两个Analyzer则去掉了stop word. 而在分析XY&Z Corporation - xyz@example.com 的时候 不同的Analyzer 对待 & 和 - 的方式也是不一样的 . 现在对Analysis有个感性的了解,下面来看看不同处理阶段的分析过程.

I. Indexing Analysis

还记得在ch2 indexing 中 讲到 ,在建立index时,使用IndexWriter 在构造IndexWriter时,要使用到Analyser.如下所示:

Analyzer analyzer = new StandardAnalyzer();

IndexWriter writer = new IndexWriter(directory,

analyzer, true);

 

然后就可以使用writer对 document 来indexing了.如下

 

Document doc = new Document();

doc.add(

Field.Text("title", "This is the title"));

doc.add(

Field.UnStored("contents", "...document contents..."));

writer.addDocument(doc);

 

使用的是在构造IndexWriter时 指定的Analyzer. 如果要给一个文档单独指定一个Analyzer 可以用下面的一个方法:

 writer.addDocument(doc,analyzer);

II.QueryParser Analysis

  Analysis 是term搜索的关键.要确保经过Analyzer分析后的term和被索引的一样 这样才可以得到搜索结果.在使用QueryParser parse 用户输入的搜索表达式时可以 指定一个Analyzer 如下所示:

Query query = QueryParser.parse(expression, "contents",

analyzer);

 

通过QueryParser的静态方法实现. 如果使用QueryParser实例, 则可以在构造QueryParser时候 提供一个Analyzer 如下:

QueryParser parser = new QueryParser("contents",

analyzer);

query = parser.parse(expression);

 

QueryParser

analyzes individual pieces of the expression, not the expression as a

whole, which may include operators, parenthesis, and other special expression

syntax to denote range, wildcard, and fuzzy searches.

QueryParser 平等的分析所有的text,她并不知道他们是如何每indxed, 这时如果当搜索一个被索引为Keyword的filed时 就可能会遇到问题.

还有一个问题就是在分析一些包含其他元素的text时该如何处理 ,如 Html xml 文档, 他们都带有元素标签 而这些标签一般是不索引的.以及如何处理分域(field)索引, 如 Html 有Header 和 Body域 如何分开搜索 这个问题Analyzer现在也不能解决的, 因为在每次Analyzer都处理单个域. 在后面我们在进一步讨论该问题.

 

2. Analyzing the Analyzer

要详细了解Lucene分析文本的过程就要知道Analyzer是如何工作的,下面就来看看Analyzer是怎么工作的吧. Analyzer是各个XXXAnalyzer的基类 ,该类出奇的简单(比我想象的要简单多了) 只要一个方法 tokenStream(String fieldName, Reader reader); fieldName 参数对有些Analyzer实现是没有作用的,如SimpleAnalyzer, 该类的代码如下:

public final class SimpleAnalyzer extends Analyzer {

  public TokenStream tokenStream(String fieldName, Reader reader) {

    return new LowerCaseTokenizer(reader);

  }

}

可以看到该类也是出奇的简单, 只用到了LowerCaseTokenizer; 但LowerCaseTokenizer是干什么的呢? 看看名字就可以猜个差不多啦 ,

该类把Text 中非字母(nonletters)的字符去掉,并把所有Text转换为小写.

而返回的

TokenStream 是一个 enumerator-like class ,通过她可以得到连续的 Tokens,当到达末尾时候返回null.