周 登朋 (zhoudengpeng@yahoo.com.cn), 軟件工程師, 上海交通大學(xué)
2006 年 9 月 06 日
Lucene 是基于 Java 的全文信息檢索包,它目前是 Apache Jakarta 家族下面的一個(gè)開源項(xiàng)目。在這篇文章中,我們首先來(lái)看如何利用 Lucene 實(shí)現(xiàn)高級(jí)搜索功能,然后學(xué)習(xí)如何利用 Lucene 來(lái)創(chuàng)建一個(gè)健壯的 Web 搜索應(yīng)用程序。
在本篇文章中,你會(huì)學(xué)習(xí)到如何利用 Lucene 實(shí)現(xiàn)高級(jí)搜索功能以及如何利用 Lucene 來(lái)創(chuàng)建 Web 搜索應(yīng)用程序。通過這些學(xué)習(xí),你就可以利用 Lucene 來(lái)創(chuàng)建自己的搜索應(yīng)用程序。
架構(gòu)概覽
通常一個(gè) Web 搜索引擎的架構(gòu)分為前端和后端兩部分,就像圖一中所示。在前端流程中,用戶在搜索引擎提供的界面中輸入要搜索的關(guān)鍵詞,這里提到的用戶界面一般是一個(gè)帶有輸入框的 Web 頁(yè)面,然后應(yīng)用程序?qū)⑺阉鞯年P(guān)鍵詞解析成搜索引擎可以理解的形式,并在索引文件上進(jìn)行搜索操作。在排序后,搜索引擎返回搜索結(jié)果給用戶。在后端流程中,網(wǎng)絡(luò)爬蟲或者機(jī)器人從因特網(wǎng)上獲取 Web 頁(yè)面,然后索引子系統(tǒng)解析這些 Web 頁(yè)面并存入索引文件中。如果你想利用 Lucene 來(lái)創(chuàng)建一個(gè) Web 搜索應(yīng)用程序,那么它的架構(gòu)也和上面所描述的類似,就如圖一中所示。
Figure 1. Web 搜索引擎架構(gòu)
利用 Lucene 實(shí)現(xiàn)高級(jí)搜索
Lucene 支持多種形式的高級(jí)搜索,我們?cè)谶@一部分中會(huì)進(jìn)行探討,然后我會(huì)使用 Lucene 的 API 來(lái)演示如何實(shí)現(xiàn)這些高級(jí)搜索功能。
布爾操作符
大多數(shù)的搜索引擎都會(huì)提供布爾操作符讓用戶可以組合查詢,典型的布爾操作符有 AND, OR, NOT。Lucene 支持 5 種布爾操作符,分別是 AND, OR, NOT, 加(+), 減(-)。接下來(lái)我會(huì)講述每個(gè)操作符的用法。
- OR: 如果你要搜索含有字符 A 或者 B 的文檔,那么就需要使用 OR 操作符。需要記住的是,如果你只是簡(jiǎn)單的用空格將兩個(gè)關(guān)鍵詞分割開,其實(shí)在搜索的時(shí)候搜索引擎會(huì)自動(dòng)在兩個(gè)關(guān)鍵詞之間加上 OR 操作符。例如,“Java OR Lucene” 和 “Java Lucene” 都是搜索含有 Java 或者含有 Lucene 的文檔。
- AND: 如果你需要搜索包含一個(gè)以上關(guān)鍵詞的文檔,那么就需要使用 AND 操作符。例如,“Java AND Lucene” 返回所有既包含 Java 又包含 Lucene 的文檔。
- NOT: Not 操作符使得包含緊跟在 NOT 后面的關(guān)鍵詞的文檔不會(huì)被返回。例如,如果你想搜索所有含有 Java 但不含有 Lucene 的文檔,你可以使用查詢語(yǔ)句 “Java NOT Lucene”。但是你不能只對(duì)一個(gè)搜索詞使用這個(gè)操作符,比如,查詢語(yǔ)句 “NOT Java” 不會(huì)返回任何結(jié)果。
- 加號(hào)(+): 這個(gè)操作符的作用和 AND 差不多,但它只對(duì)緊跟著它的一個(gè)搜索詞起作用。例如,如果你想搜索一定包含 Java,但不一定包含 Lucene 的文檔,就可以使用查詢語(yǔ)句“+Java Lucene”。
- 減號(hào)(-): 這個(gè)操作符的功能和 NOT 一樣,查詢語(yǔ)句 “Java -Lucene” 返回所有包含 Java 但不包含 Lucene 的文檔。
接下來(lái)我們看一下如何利用 Lucene 提供的 API 來(lái)實(shí)現(xiàn)布爾查詢。清單1 顯示了如果利用布爾操作符進(jìn)行查詢的過程。
清單1:使用布爾操作符
//Test boolean operator
public void testOperator(String indexDirectory) throws Exception{
Directory dir = FSDirectory.getDirectory(indexDirectory,false);
IndexSearcher indexSearcher = new IndexSearcher(dir);
String[] searchWords = {"Java AND Lucene", "Java NOT Lucene", "Java OR Lucene",
"+Java +Lucene", "+Java -Lucene"};
Analyzer language = new StandardAnalyzer();
Query query;
for(int i = 0; i < searchWords.length; i++){
query = QueryParser.parse(searchWords[i], "title", language);
Hits results = indexSearcher.search(query);
System.out.println(results.length() + "search results for query " + searchWords[i]);
}
}
|
域搜索(Field Search)
Lucene 支持域搜索,你可以指定一次查詢是在哪些域(Field)上進(jìn)行。例如,如果索引的文檔包含兩個(gè)域,Title 和 Content ,你就可以使用查詢 “Title: Lucene AND Content: Java” 來(lái)返回所有在 Title 域上包含 Lucene 并且在 Content 域上包含 Java 的文檔。清單 2 顯示了如何利用 Lucene 的 API 來(lái)實(shí)現(xiàn)域搜索。
清單2:實(shí)現(xiàn)域搜索
//Test field search
public void testFieldSearch(String indexDirectory) throws Exception{
Directory dir = FSDirectory.getDirectory(indexDirectory,false);
IndexSearcher indexSearcher = new IndexSearcher(dir);
String searchWords = "title:Lucene AND content:Java";
Analyzer language = new StandardAnalyzer();
Query query = QueryParser.parse(searchWords, "title", language);
Hits results = indexSearcher.search(query);
System.out.println(results.length() + "search results for query " + searchWords);
}
|
通配符搜索(Wildcard Search)
Lucene 支持兩種通配符:?jiǎn)柼?hào)(?)和星號(hào)(*)。你可以使用問號(hào)(?)來(lái)進(jìn)行單字符的通配符查詢,或者利用星號(hào)(*)進(jìn)行多字符的通配符查詢。例如,如果你想搜索 tiny 或者 tony,你就可以使用查詢語(yǔ)句 “t?ny”;如果你想查詢 Teach, Teacher 和 Teaching,你就可以使用查詢語(yǔ)句 “Teach*”。清單3 顯示了通配符查詢的過程。
清單3:進(jìn)行通配符查詢
//Test wildcard search
public void testWildcardSearch(String indexDirectory)throws Exception{
Directory dir = FSDirectory.getDirectory(indexDirectory,false);
IndexSearcher indexSearcher = new IndexSearcher(dir);
String[] searchWords = {"tex*", "tex?", "?ex*"};
Query query;
for(int i = 0; i < searchWords.length; i++){
query = new WildcardQuery(new Term("title",searchWords[i]));
Hits results = indexSearcher.search(query);
System.out.println(results.length() + "search results for query " + searchWords[i]);
}
}
|
模糊查詢
Lucene 提供的模糊查詢基于編輯距離算法(Edit distance algorithm)。你可以在搜索詞的尾部加上字符 ~ 來(lái)進(jìn)行模糊查詢。例如,查詢語(yǔ)句 “think~” 返回所有包含和 think 類似的關(guān)鍵詞的文檔。清單 4 顯示了如果利用 Lucene 的 API 進(jìn)行模糊查詢的代碼。
清單4:實(shí)現(xiàn)模糊查詢
//Test fuzzy search
public void testFuzzySearch(String indexDirectory)throws Exception{
Directory dir = FSDirectory.getDirectory(indexDirectory,false);
IndexSearcher indexSearcher = new IndexSearcher(dir);
String[] searchWords = {"text", "funny"};
Query query;
for(int i = 0; i < searchWords.length; i++){
query = new FuzzyQuery(new Term("title",searchWords[i]));
Hits results = indexSearcher.search(query);
System.out.println(results.length() + "search results for query " + searchWords[i]);
}
}
|
范圍搜索(Range Search)
范圍搜索匹配某個(gè)域上的值在一定范圍的文檔。例如,查詢 “age:[18 TO 35]” 返回所有 age 域上的值在 18 到 35 之間的文檔。清單5顯示了利用 Lucene 的 API 進(jìn)行返回搜索的過程。
清單5:測(cè)試范圍搜索
//Test range search
public void testRangeSearch(String indexDirectory)throws Exception{
Directory dir = FSDirectory.getDirectory(indexDirectory,false);
IndexSearcher indexSearcher = new IndexSearcher(dir);
Term begin = new Term("birthDay","20000101");
Term end = new Term("birthDay","20060606");
Query query = new RangeQuery(begin,end,true);
Hits results = indexSearcher.search(query);
System.out.println(results.length() + "search results is returned");
}
|
在 Web 應(yīng)用程序中集成 Lucene
接下來(lái)我們開發(fā)一個(gè) Web 應(yīng)用程序利用 Lucene 來(lái)檢索存放在文件服務(wù)器上的 HTML 文檔。在開始之前,需要準(zhǔn)備如下環(huán)境:
- Eclipse 集成開發(fā)環(huán)境
- Tomcat 5.0
- Lucene Library
- JDK 1.5
這個(gè)例子使用 Eclipse 進(jìn)行 Web 應(yīng)用程序的開發(fā),最終這個(gè) Web 應(yīng)用程序跑在 Tomcat 5.0 上面。在準(zhǔn)備好開發(fā)所必需的環(huán)境之后,我們接下來(lái)進(jìn)行 Web 應(yīng)用程序的開發(fā)。
1、創(chuàng)建一個(gè)動(dòng)態(tài) Web 項(xiàng)目
- 在 Eclipse 里面,選擇 File > New > Project,然后再?gòu)棾龅拇翱谥羞x擇動(dòng)態(tài) Web 項(xiàng)目,如圖二所示。
圖二:創(chuàng)建動(dòng)態(tài)Web項(xiàng)目
- 在創(chuàng)建好動(dòng)態(tài) Web 項(xiàng)目之后,你會(huì)看到創(chuàng)建好的項(xiàng)目的結(jié)構(gòu),如圖三所示,項(xiàng)目的名稱為 sample.dw.paper.lucene。
圖三:動(dòng)態(tài) Web 項(xiàng)目的結(jié)構(gòu)
2. 設(shè)計(jì) Web 項(xiàng)目的架構(gòu)
在我們的設(shè)計(jì)中,把該系統(tǒng)分成如下四個(gè)子系統(tǒng):
- 用戶接口: 這個(gè)子系統(tǒng)提供用戶界面使用戶可以向 Web 應(yīng)用程序服務(wù)器提交搜索請(qǐng)求,然后搜索結(jié)果通過用戶接口來(lái)顯示出來(lái)。我們用一個(gè)名為 search.jsp 的頁(yè)面來(lái)實(shí)現(xiàn)該子系統(tǒng)。
- 請(qǐng)求管理器: 這個(gè)子系統(tǒng)管理從客戶端發(fā)送過來(lái)的搜索請(qǐng)求并把搜索請(qǐng)求分發(fā)到搜索子系統(tǒng)中。最后搜索結(jié)果從搜索子系統(tǒng)返回并最終發(fā)送到用戶接口子系統(tǒng)。我們使用一個(gè) Servlet 來(lái)實(shí)現(xiàn)這個(gè)子系統(tǒng)。
- 搜索子系統(tǒng): 這個(gè)子系統(tǒng)負(fù)責(zé)在索引文件上進(jìn)行搜索并把搜索結(jié)構(gòu)傳遞給請(qǐng)求管理器。我們使用 Lucene 提供的 API 來(lái)實(shí)現(xiàn)該子系統(tǒng)。
- 索引子系統(tǒng): 這個(gè)子系統(tǒng)用來(lái)為 HTML 頁(yè)面來(lái)創(chuàng)建索引。我們使用 Lucene 的 API 以及 Lucene 提供的一個(gè) HTML 解析器來(lái)創(chuàng)建該子系統(tǒng)。
圖4 顯示了我們?cè)O(shè)計(jì)的詳細(xì)信息,我們將用戶接口子系統(tǒng)放到 webContent 目錄下面。你會(huì)看到一個(gè)名為 search.jsp 的頁(yè)面在這個(gè)文件夾里面。請(qǐng)求管理子系統(tǒng)在包 sample.dw.paper.lucene.servlet 下面,類 SearchController 負(fù)責(zé)功能的實(shí)現(xiàn)。搜索子系統(tǒng)放在包 sample.dw.paper.lucene.search 當(dāng)中,它包含了兩個(gè)類,SearchManager 和 SearchResultBean ,第一個(gè)類用來(lái)實(shí)現(xiàn)搜索功能,第二個(gè)類用來(lái)描述搜索結(jié)果的結(jié)構(gòu)。索引子系統(tǒng)放在包 sample.dw.paper.lucene.index 當(dāng)中。類 IndexManager 負(fù)責(zé)為 HTML 文件創(chuàng)建索引。該子系統(tǒng)利用包 sample.dw.paper.lucene.util 里面的類 HTMLDocParser 提供的方法 getTitle 和 getContent 來(lái)對(duì) HTML 頁(yè)面進(jìn)行解析。
圖四:項(xiàng)目的架構(gòu)設(shè)計(jì)
3. 子系統(tǒng)的實(shí)現(xiàn)
在分析了系統(tǒng)的架構(gòu)設(shè)計(jì)之后,我們接下來(lái)看系統(tǒng)實(shí)現(xiàn)的詳細(xì)信息。
- 用戶接口: 這個(gè)子系統(tǒng)有一個(gè)名為 search.jsp 的 JSP 文件來(lái)實(shí)現(xiàn),這個(gè) JSP 頁(yè)面包含兩個(gè)部分。第一部分提供了一個(gè)用戶接口去向 Web 應(yīng)用程序服務(wù)器提交搜索請(qǐng)求,如圖5所示。注意到這里的搜索請(qǐng)求發(fā)送到了一個(gè)名為 SearchController 的 Servlet 上面。Servlet 的名字和具體實(shí)現(xiàn)的類的對(duì)應(yīng)關(guān)系在 web.xml 里面指定。
圖5:向Web服務(wù)器提交搜索請(qǐng)求
這個(gè)JSP的第二部分負(fù)責(zé)顯示搜索結(jié)果給用戶,如圖6所示:
圖6:顯示搜索結(jié)果
- 請(qǐng)求管理器: 一個(gè)名為
SearchController 的 servlet 用來(lái)實(shí)現(xiàn)該子系統(tǒng)。清單6給出了這個(gè)類的源代碼。
清單6:請(qǐng)求管理器的實(shí)現(xiàn)
package sample.dw.paper.lucene.servlet;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sample.dw.paper.lucene.search.SearchManager;
/**
* This servlet is used to deal with the search request
* and return the search results to the client
*/
public class SearchController extends HttpServlet{
private static final long serialVersionUID = 1L;
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException{
String searchWord = request.getParameter("searchWord");
SearchManager searchManager = new SearchManager(searchWord);
List searchResult = null;
searchResult = searchManager.search();
RequestDispatcher dispatcher = request.getRequestDispatcher("search.jsp");
request.setAttribute("searchResult",searchResult);
dispatcher.forward(request, response);
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException{
doPost(request, response);
}
}
|
在清單6中,doPost 方法從客戶端獲取搜索詞并創(chuàng)建類 SearchManager 的一個(gè)實(shí)例,其中類 SearchManager 在搜索子系統(tǒng)中進(jìn)行了定義。然后,SearchManager 的方法 search 會(huì)被調(diào)用。最后搜索結(jié)果被返回到客戶端。
- 搜索子系統(tǒng): 在這個(gè)子系統(tǒng)中,我們定義了兩個(gè)類:
SearchManager 和 SearchResultBean 。第一個(gè)類用來(lái)實(shí)現(xiàn)搜索功能,第二個(gè)類是個(gè)JavaBean,用來(lái)描述搜索結(jié)果的結(jié)構(gòu)。清單7給出了類 SearchManager 的源代碼。
清單7:搜索功能的實(shí)現(xiàn)
package sample.dw.paper.lucene.search;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import sample.dw.paper.lucene.index.IndexManager;
/**
* This class is used to search the
* Lucene index and return search results
*/
public class SearchManager {
private String searchWord;
private IndexManager indexManager;
private Analyzer analyzer;
public SearchManager(String searchWord){
this.searchWord = searchWord;
this.indexManager = new IndexManager();
this.analyzer = new StandardAnalyzer();
}
/**
* do search
*/
public List search(){
List searchResult = new ArrayList();
if(false == indexManager.ifIndexExist()){
try {
if(false == indexManager.createIndex()){
return searchResult;
}
} catch (IOException e) {
e.printStackTrace();
return searchResult;
}
}
IndexSearcher indexSearcher = null;
try{
indexSearcher = new IndexSearcher(indexManager.getIndexDir());
}catch(IOException ioe){
ioe.printStackTrace();
}
QueryParser queryParser = new QueryParser("content",analyzer);
Query query = null;
try {
query = queryParser.parse(searchWord);
} catch (ParseException e) {
e.printStackTrace();
}
if(null != query >> null != indexSearcher){
try {
Hits hits = indexSearcher.search(query);
for(int i = 0; i < hits.length(); i ++){
SearchResultBean resultBean = new SearchResultBean();
resultBean.setHtmlPath(hits.doc(i).get("path"));
resultBean.setHtmlTitle(hits.doc(i).get("title"));
searchResult.add(resultBean);
}
} catch (IOException e) {
e.printStackTrace();
}
}
return searchResult;
}
}
|
在清單7中,注意到在這個(gè)類里面有三個(gè)私有屬性。第一個(gè)是 searchWord ,代表了來(lái)自客戶端的搜索詞。第二個(gè)是 indexManager ,代表了在索引子系統(tǒng)中定義的類 IndexManager 的一個(gè)實(shí)例。第三個(gè)是 analyzer ,代表了用來(lái)解析搜索詞的解析器?,F(xiàn)在我們把注意力放在方法 search 上面。這個(gè)方法首先檢查索引文件是否已經(jīng)存在,如果已經(jīng)存在,那么就在已經(jīng)存在的索引上進(jìn)行檢索,如果不存在,那么首先調(diào)用類 IndexManager 提供的方法來(lái)創(chuàng)建索引,然后在新創(chuàng)建的索引上進(jìn)行檢索。搜索結(jié)果返回后,這個(gè)方法從搜索結(jié)果中提取出需要的屬性并為每個(gè)搜索結(jié)果生成類 SearchResultBean 的一個(gè)實(shí)例。最后這些 SearchResultBean 的實(shí)例被放到一個(gè)列表里面并返回給請(qǐng)求管理器。
在類 SearchResultBean 中,含有兩個(gè)屬性,分別是 htmlPath 和 htmlTitle ,以及這個(gè)兩個(gè)屬性的 get 和 set 方法。這也意味著我們的搜索結(jié)果包含兩個(gè)屬性:htmlPath 和 htmlTitle ,其中 htmlPath 代表了 HTML 文件的路徑,htmlTitle 代表了 HTML 文件的標(biāo)題。
- 索引子系統(tǒng): 類
IndexManager 用來(lái)實(shí)現(xiàn)這個(gè)子系統(tǒng)。清單8 給出了這個(gè)類的源代碼。
清單8:索引子系統(tǒng)的實(shí)現(xiàn)
package sample.dw.paper.lucene.index;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import sample.dw.paper.lucene.util.HTMLDocParser;
/**
* This class is used to create an index for HTML files
*
*/
public class IndexManager {
//the directory that stores HTML files
private final String dataDir = "c:\\dataDir";
//the directory that is used to store a Lucene index
private final String indexDir = "c:\\indexDir";
/**
* create index
*/
public boolean createIndex() throws IOException{
if(true == ifIndexExist()){
return true;
}
File dir = new File(dataDir);
if(!dir.exists()){
return false;
}
File[] htmls = dir.listFiles();
Directory fsDirectory = FSDirectory.getDirectory(indexDir, true);
Analyzer analyzer = new StandardAnalyzer();
IndexWriter indexWriter = new IndexWriter(fsDirectory, analyzer, true);
for(int i = 0; i < htmls.length; i++){
String htmlPath = htmls[i].getAbsolutePath();
if(htmlPath.endsWith(".html") || htmlPath.endsWith(".htm")){
addDocument(htmlPath, indexWriter);
}
}
indexWriter.optimize();
indexWriter.close();
return true;
}
/**
* Add one document to the Lucene index
*/
public void addDocument(String htmlPath, IndexWriter indexWriter){
HTMLDocParser htmlParser = new HTMLDocParser(htmlPath);
String path = htmlParser.getPath();
String title = htmlParser.getTitle();
Reader content = htmlParser.getContent();
Document document = new Document();
document.add(new Field("path",path,Field.Store.YES,Field.Index.NO));
document.add(new Field("title",title,Field.Store.YES,Field.Index.TOKENIZED));
document.add(new Field("content",content));
try {
indexWriter.addDocument(document);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* judge if the index exists already
*/
public boolean ifIndexExist(){
File directory = new File(indexDir);
if(0 < directory.listFiles().length){
return true;
}else{
return false;
}
}
public String getDataDir(){
return this.dataDir;
}
public String getIndexDir(){
return this.indexDir;
}
}
|
這個(gè)類包含兩個(gè)私有屬性,分別是 dataDir 和 indexDir 。dataDir 代表存放等待進(jìn)行索引的 HTML 頁(yè)面的路徑,indexDir 代表了存放 Lucene 索引文件的路徑。類 IndexManager 提供了三個(gè)方法,分別是 createIndex , addDocument 和 ifIndexExist 。如果索引不存在的話,你可以使用方法 createIndex 去創(chuàng)建一個(gè)新的索引,用方法 addDocument 去向一個(gè)索引上添加文檔。在我們的場(chǎng)景中,一個(gè)文檔就是一個(gè) HTML 頁(yè)面。方法 addDocument 會(huì)調(diào)用由類 HTMLDocParser 提供的方法對(duì) HTML 文檔進(jìn)行解析。你可以使用最后一個(gè)方法 ifIndexExist 來(lái)判斷 Lucene 的索引是否已經(jīng)存在。
現(xiàn)在我們來(lái)看一下放在包 sample.dw.paper.lucene.util 里面的類 HTMLDocParser 。這個(gè)類用來(lái)從 HTML 文件中提取出文本信息。這個(gè)類包含三個(gè)方法,分別是 getContent ,getTitle 和 getPath 。第一個(gè)方法返回去除了 HTML 標(biāo)記的文本內(nèi)容,第二個(gè)方法返回 HTML 文件的標(biāo)題,最后一個(gè)方法返回 HTML 文件的路徑。清單9 給出了這個(gè)類的源代碼。
清單9:HTML 解析器
package sample.dw.paper.lucene.util;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import org.apache.lucene.demo.html.HTMLParser;
public class HTMLDocParser {
private String htmlPath;
private HTMLParser htmlParser;
public HTMLDocParser(String htmlPath){
this.htmlPath = htmlPath;
initHtmlParser();
}
private void initHtmlParser(){
InputStream inputStream = null;
try {
inputStream = new FileInputStream(htmlPath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
if(null != inputStream){
try {
htmlParser = new HTMLParser(new InputStreamReader(inputStream, "utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
public String getTitle(){
if(null != htmlParser){
try {
return htmlParser.getTitle();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "";
}
public Reader getContent(){
if(null != htmlParser){
try {
return htmlParser.getReader();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
public String getPath(){
return this.htmlPath;
}
}
|
5.在 Tomcat 5.0 上運(yùn)行應(yīng)用程序
現(xiàn)在我們可以在 Tomcat 5.0 上運(yùn)行開發(fā)好的應(yīng)用程序。
- 右鍵單擊 search.jsp,然后選擇 Run as > Run on Server,如圖7所示。
圖7:配置 Tomcat 5.0
- 在彈出的窗口中,選擇 Tomcat v5.0 Server 作為目標(biāo) Web 應(yīng)用程序服務(wù)器,然后點(diǎn)擊 Next,如圖8 所示:
圖8:選擇 Tomcat 5.0
- 現(xiàn)在需要指定用來(lái)運(yùn)行 Web 應(yīng)用程序的 Apache Tomcat 5.0 以及 JRE 的路徑。這里你所選擇的 JRE 的版本必須和你用來(lái)編譯 Java 文件的 JRE 的版本一致。配置好之后,點(diǎn)擊 Finish。如 圖9 所示。
圖9:完成Tomcat 5.0的配置
- 配置好之后,Tomcat 會(huì)自動(dòng)運(yùn)行,并且會(huì)對(duì) search.jsp 進(jìn)行編譯并顯示給用戶。如 圖10 所示。
圖10:用戶界面
- 在輸入框中輸入關(guān)鍵詞 “information” 然后單擊 Search 按鈕。然后這個(gè)頁(yè)面上會(huì)顯示出搜索結(jié)果來(lái),如 圖11 所示。
圖11:搜索結(jié)果
- 單擊搜索結(jié)果的第一個(gè)鏈接,頁(yè)面上就會(huì)顯示出所鏈接到的頁(yè)面的內(nèi)容。如 圖12 所示.
圖12:詳細(xì)信息
現(xiàn)在我們已經(jīng)成功的完成了示例項(xiàng)目的開發(fā),并成功的用Lucene實(shí)現(xiàn)了搜索和索引功能。你可以下載這個(gè)項(xiàng)目的源代碼(下載)。
總結(jié)
Lucene 提供了靈活的接口使我們更加方便的設(shè)計(jì)我們的 Web 搜索應(yīng)用程序。如果你想在你的應(yīng)用程序中加入搜索功能,那么 Lucene 是一個(gè)很好的選擇。在設(shè)計(jì)你的下一個(gè)帶有搜索功能的應(yīng)用程序的時(shí)候可以考慮使用 Lucene 來(lái)提供搜索功能。
下載
描述 |
名字 |
大小 |
下載方法 |
Lucene Web 應(yīng)用程序示例 |
wa-lucene2_source_code.zip |
504KB |
HTTP |
參考資料
學(xué)習(xí)
獲得產(chǎn)品和技術(shù)
討論
關(guān)于作者
|
|
|
周登朋,上海交通大學(xué)研究生,目前在IBM上海國(guó)際化實(shí)驗(yàn)室(SGL)實(shí)習(xí),對(duì) Java 技術(shù)以及信息檢索技術(shù)非常感興趣,你可以通過 zhoudengpeng@yahoo.com.cn 來(lái)聯(lián)系他。
|
|