今天看看 ch3, Add search to your Application. 真正开始使用 Lucene search 来搜索你的目标了.

1. 实现一个简单的search feature

   在本章中只限于讨论简单Lucene 搜索API, 有下面几个相关的类:

 Lucene 基本搜索API:

功能

IndexSearcher搜索一个index的入口.所有的searches都是通过IndexSearcher 实例的几个重载的方法实现的.
Query (and subclasses)各个子类封装了特定搜索类型的逻辑(logic),Query实例传递给IndexSearcher的search方法.
QueryParser 处理一个可读的表达式,转换为一个具体的Query实例.
Hits 包含了搜索的结果.有IndexSearcher的search函数返回.

下面我们来看几个书中的例子:

LiaTestCase.java  一个继承自TestCase 并且扩展了TestCase的类, 下面的几个例子都继承自该类.

01 package lia.common;
02 
03 import junit.framework.TestCase;
04 import org.apache.lucene.store.FSDirectory;
05 import org.apache.lucene.store.Directory;
06 import org.apache.lucene.search.Hits;
07 import org.apache.lucene.document.Document;
08 
09 import java.io.IOException;
10 import java.util.Date;
11 import java.text.ParseException;
12 import java.text.SimpleDateFormat;
13 
14 /**
15  * LIA base class for test cases.
16  */
17 public abstract class LiaTestCase extends TestCase {
18   private String indexDir = System.getProperty("index.dir");  // 测试 index 已经建立好了
19   protected Directory directory;
20 
21   protected void setUp() throws Exception {
22     directory = FSDirectory.getDirectory(indexDir, false);
23   }
24 
25   protected void tearDown() throws Exception {
26     directory.close();
27   }
28 
29   /**
30    * For troubleshooting 为了 解决问题的方法
31    */
32   protected final void dumpHits(Hits hits) throws IOException {
33     if (hits.length() == 0) {
34       System.out.println("No hits");
35     }
36 
37     for (int i=0; i < hits.length(); i++) {
38       Document doc = hits.doc(i);
39       System.out.println(hits.score(i) + ":" + doc.get("title"));
40     }
41   }
42 
43   protected final void assertHitsIncludeTitle(
44                                           Hits hits, String title)
45     throws IOException {
46     for (int i=0; i < hits.length(); i++) {
47       Document doc = hits.doc(i);
48       if (title.equals(doc.get("title"))) {
49         assertTrue(true);
50         return;
51       }
52     }
53 
54     fail("title '" + title + "' not found");
55   }
56 
57   protected final Date parseDate(String s) throws ParseException {
58       return new SimpleDateFormat("yyyy-MM-dd").parse(s);
59   }
60 }

  I.搜索一个特定的Term 和利用QueryParser 解析用户输入的表达式

  要利用一个特定的term搜索,使用QueryTerm就可以了,单个term 尤其适合Keyword搜索. 解析用户输入的表达式可以更适合用户的使用方式,搜索表达式的解析有QueryParser来完成.如果表达式解析错误 会有异常抛出, 可以取得相信的错误信息 以便给用户适当的提示.在解析表达式时,还需要一个Analyzer 来分析用户的输入, 并根据不同的Analyzer来生产相应的Term然后构成Query实例.

下面看个例子吧:BasicSearchingTest.java

01 package lia.searching;
02 
03 import lia.common.LiaTestCase;
04 import org.apache.lucene.analysis.SimpleAnalyzer;
05 import org.apache.lucene.document.Document;
06 import org.apache.lucene.index.Term;
07 import org.apache.lucene.queryParser.QueryParser;
08 import org.apache.lucene.search.Hits;
09 import org.apache.lucene.search.IndexSearcher;
10 import org.apache.lucene.search.Query;
11 import org.apache.lucene.search.TermQuery;
12 
13 public class BasicSearchingTest extends LiaTestCase {
14 
15   public void testTerm() throws Exception {
16     IndexSearcher searcher = new IndexSearcher(directory);
17     Term t = new Term("subject""ant");                // 构造一个Term
18     Query query = new TermQuery(t);
19     Hits hits = searcher.search(query);                 // 搜索
20     assertEquals("JDwA"1, hits.length());             //测试结果
21 
22     t = new Term("subject""junit");
23     hits = searcher.search(new TermQuery(t));                  
24     assertEquals(2, hits.length());
25 
26     searcher.close();
27   }
28 
29   public void testKeyword() throws Exception {  // 测试关键字搜索
30     IndexSearcher searcher = new IndexSearcher(directory);
31     Term t = new Term("isbn""1930110995");                 // 关键字 term
32     Query query = new TermQuery(t);
33     Hits hits = searcher.search(query);
34     assertEquals("JUnit in Action"1, hits.length());
35   }
36 
37   public void testQueryParser() throws Exception {  // 测试 QueryParser.
38     IndexSearcher searcher = new IndexSearcher(directory);
39 
40     Query query = QueryParser.parse("+JUNIT +ANT -MOCK",
41                                     "contents",
42                                     new SimpleAnalyzer());  // 通过解析搜索表达式 返回一个Query实例
43     Hits hits = searcher.search(query);
44     assertEquals(1, hits.length());
45     Document d = hits.doc(0);
46     assertEquals("Java Development with Ant", d.get("title"));
47 
48     query = QueryParser.parse("mock OR junit",
49                               "contents",
50                               new SimpleAnalyzer());             
// 通过解析搜索表达式 返回一个Query实例
51     hits = searcher.search(query);
52     assertEquals("JDwA and JIA"2, hits.length());
53   }
54 }