今天看看 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 }