本章详细的讨论了 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 awhole, 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.