1. 程式人生 > >用 Lucene 加速 Web 搜尋應用程式的開發

用 Lucene 加速 Web 搜尋應用程式的開發

2006 年 9 月 06 日 

在本篇文章中,你會學習到如何利用 Lucene 實現高階搜尋功能以及如何利用 Lucene 來建立 Web 搜尋應用程式。通過這些學習,你就可以利用 Lucene 來建立自己的搜尋應用程式。

架構概覽

通常一個 Web 搜尋引擎的架構分為前端和後端兩部分,就像圖一中所示。在前端流程中,使用者在搜尋引擎提供的介面中輸入要搜尋的關鍵詞,這裡提到的使用者介面一般是一個帶有輸入框的 Web 頁面,然後應用程式將搜尋的關鍵詞解析成搜尋引擎可以理解的形式,並在索引檔案上進行搜尋操作。在排序後,搜尋引擎返回搜尋結果給使用者。在後端流程中,網路爬蟲或者機器人從因特網上獲取 Web 頁面,然後索引子系統解析這些 Web 頁面並存入索引檔案中。如果你想利用 Lucene 來建立一個 Web 搜尋應用程式,那麼它的架構也和上面所描述的類似,就如

圖一中所示。

Lucene 支援多種形式的高階搜尋,我們在這一部分中會進行探討,然後我會使用 Lucene 的 API 來演示如何實現這些高階搜尋功能。

布林操作符

大多數的搜尋引擎都會提供布林操作符讓使用者可以組合查詢,典型的布林操作符有 AND, OR, NOT。Lucene 支援 5 種布林操作符,分別是 AND, OR, NOT, 加(+), 減(-)。接下來我會講述每個操作符的用法。

  • OR: 如果你要搜尋含有字元 A 或者 B 的文件,那麼就需要使用 OR 操作符。需要記住的是,如果你只是簡單的用空格將兩個關鍵詞分割開,其實在搜尋的時候搜尋引擎會自動在兩個關鍵詞之間加上 OR 操作符。例如,“Java OR Lucene” 和 “Java Lucene” 都是搜尋含有 Java 或者含有 Lucene 的文件。
  • AND: 如果你需要搜尋包含一個以上關鍵詞的文件,那麼就需要使用 AND 操作符。例如,“Java AND Lucene” 返回所有既包含 Java 又包含 Lucene 的文件。
  • NOT: Not 操作符使得包含緊跟在 NOT 後面的關鍵詞的文件不會被返回。例如,如果你想搜尋所有含有 Java 但不含有 Lucene 的文件,你可以使用查詢語句 “Java NOT Lucene”。但是你不能只對一個搜尋詞使用這個操作符,比如,查詢語句 “NOT Java” 不會返回任何結果。
  • 加號(+): 這個操作符的作用和 AND 差不多,但它只對緊跟著它的一個搜尋詞起作用。例如,如果你想搜尋一定包含 Java,但不一定包含 Lucene 的文件,就可以使用查詢語句“+Java Lucene”。
  • 減號(-): 這個操作符的功能和 NOT 一樣,查詢語句 “Java -Lucene” 返回所有包含 Java 但不包含 Lucene 的文件。

接下來我們看一下如何利用 Lucene 提供的 API 來實現布林查詢。清單1 顯示瞭如果利用布林操作符進行查詢的過程。

//Test boolean operator
publicvoid 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]);
   }

}

Lucene 支援域搜尋,你可以指定一次查詢是在哪些域(Field)上進行。例如,如果索引的文件包含兩個域,TitleContent,你就可以使用查詢 “Title: Lucene AND Content: Java” 來返回所有在 Title 域上包含 Lucene 並且在 Content 域上包含 Java 的文件。清單 2 顯示瞭如何利用 Lucene 的 API 來實現域搜尋。

//Test field search
publicvoid 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);
}

Lucene 支援兩種萬用字元:問號(?)和星號(*)。你可以使用問號(?)來進行單字元的萬用字元查詢,或者利用星號(*)進行多字元的萬用字元查詢。例如,如果你想搜尋 tiny 或者 tony,你就可以使用查詢語句 “t?ny”;如果你想查詢 Teach, Teacher 和 Teaching,你就可以使用查詢語句 “Teach*”。清單3 顯示了萬用字元查詢的過程。

//Test wildcard search
publicvoid 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)。你可以在搜尋詞的尾部加上字元 ~ 來進行模糊查詢。例如,查詢語句 “think~” 返回所有包含和 think 類似的關鍵詞的文件。清單 4 顯示瞭如果利用 Lucene 的 API 進行模糊查詢的程式碼。

//Test fuzzy search
publicvoid 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]);
   }

}

範圍搜尋匹配某個域上的值在一定範圍的文件。例如,查詢 “age:[18 TO 35]” 返回所有 age 域上的值在 18 到 35 之間的文件。清單5顯示了利用 Lucene 的 API 進行返回搜尋的過程。

//Test range search
publicvoid 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 應用程式利用 Lucene 來檢索存放在檔案伺服器上的 HTML 文件。在開始之前,需要準備如下環境:

  1. Eclipse 整合開發環境
  2. Tomcat 5.0
  3. Lucene Library
  4. JDK 1.5

這個例子使用 Eclipse 進行 Web 應用程式的開發,最終這個 Web 應用程式跑在 Tomcat 5.0 上面。在準備好開發所必需的環境之後,我們接下來進行 Web 應用程式的開發。

  1. 在 Eclipse 裡面,選擇 File > New > Project,然後再彈出的視窗中選擇動態 Web 專案,如圖二所示。
  1. 在建立好動態 Web 專案之後,你會看到建立好的專案的結構,如圖三所示,專案的名稱為 sample.dw.paper.lucene。

在我們的設計中,把該系統分成如下四個子系統:

  1. 使用者介面: 這個子系統提供使用者介面使使用者可以向 Web 應用程式伺服器提交搜尋請求,然後搜尋結果通過使用者介面來顯示出來。我們用一個名為 search.jsp 的頁面來實現該子系統。
  2. 請求管理器: 這個子系統管理從客戶端傳送過來的搜尋請求並把搜尋請求分發到搜尋子系統中。最後搜尋結果從搜尋子系統返回並最終傳送到使用者介面子系統。我們使用一個 Servlet 來實現這個子系統。
  3. 搜尋子系統: 這個子系統負責在索引檔案上進行搜尋並把搜尋結構傳遞給請求管理器。我們使用 Lucene 提供的 API 來實現該子系統。
  4. 索引子系統: 這個子系統用來為 HTML 頁面來建立索引。我們使用 Lucene 的 API 以及 Lucene 提供的一個 HTML 解析器來建立該子系統。

圖4 顯示了我們設計的詳細資訊,我們將使用者介面子系統放到 webContent 目錄下面。你會看到一個名為 search.jsp 的頁面在這個資料夾裡面。請求管理子系統在包 sample.dw.paper.lucene.servlet 下面,類 SearchController 負責功能的實現。搜尋子系統放在包 sample.dw.paper.lucene.search 當中,它包含了兩個類,SearchManagerSearchResultBean,第一個類用來實現搜尋功能,第二個類用來描述搜尋結果的結構。索引子系統放在包 sample.dw.paper.lucene.index 當中。類 IndexManager 負責為 HTML 檔案建立索引。該子系統利用包 sample.dw.paper.lucene.util 裡面的類 HTMLDocParser 提供的方法 getTitlegetContent 來對 HTML 頁面進行解析。

在分析了系統的架構設計之後,我們接下來看系統實現的詳細資訊。

  1. 使用者介面: 這個子系統有一個名為 search.jsp 的 JSP 檔案來實現,這個 JSP 頁面包含兩個部分。第一部分提供了一個使用者介面去向 Web 應用程式伺服器提交搜尋請求,如圖5所示。注意到這裡的搜尋請求傳送到了一個名為 SearchController 的 Servlet 上面。Servlet 的名字和具體實現的類的對應關係在 web.xml 裡面指定。

這個JSP的第二部分負責顯示搜尋結果給使用者,如圖6所示:

  1. 請求管理器: 一個名為 SearchController 的 servlet 用來實現該子系統。清單6給出了這個類的原始碼。
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
 
*/

publicclass SearchController extends HttpServlet{

    
privatestaticfinallong serialVersionUID =1L;

    
publicvoid 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);
    }


    
publicvoid doGet(HttpServletRequest request, HttpServletResponse response)
                     
throws IOException, ServletException{
        doPost(request, response);
    }

}

清單6中,doPost 方法從客戶端獲取搜尋詞並建立類 SearchManager 的一個例項,其中類 SearchManager 在搜尋子系統中進行了定義。然後,SearchManager 的方法 search 會被呼叫。最後搜尋結果被返回到客戶端。

  1. 搜尋子系統: 在這個子系統中,我們定義了兩個類:SearchManagerSearchResultBean。第一個類用來實現搜尋功能,第二個類是個JavaBean,用來描述搜尋結果的結構。清單7給出了類 SearchManager 的原始碼。
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;

相關推薦

Lucene 加速 Web 搜尋應用程式開發

2006 年 9 月 06 日  在本篇文章中,你會學習到如何利用 Lucene 實現高階搜尋功能以及如何利用 Lucene 來建立 Web 搜尋應用程式。通過這些學習,你就可以利用 Lucene 來建立自己的搜尋應用程式。 架構概覽 通常一個 Web 搜尋引擎的架

Lucene加速Web站點搜尋應用程式開發

在本篇文章中,你會學習到如何利用 Lucene 實現高階搜尋功能以及如何利用 Lucene 來建立 Web 搜尋應用程式。通過這些學習,你就可以利用 Lucene 來建立自己的搜尋應用程式。 架構概覽 通常一個 Web 搜尋引擎的架構分為前端和後端兩部分,就像圖一中所示。

Eclipse 開發Dynamic Web Project應用程式

轉載自:http://blog.csdn.net/blue_fire2008/article/details/7525557 簡介:本文僅簡單介紹基於Eclipse開發Dynamic Web Project應用下的JSP,Servlet及TOMCAT資料來源的配置和開發

加速ASP.NET Core WEB API應用程式——第2部分

目錄 應用程式生產力 非同步設計模式 資料規範化與SQL查詢效率 NCHAR與NVARCHAR 使用MSSQL伺服器的全文引擎 儲存過程 優化儲存過程 預編譯和重用儲存過程執行計劃 使用Entity Framework Core進行全文搜尋 Entity

加速ASP.NET Core WEB API應用程式——第1部分

目錄 介紹 建立測試RESTful WEB API服務 應用程式架構 資料庫 建立ASP.NET核心WEB API應用程式 使用實體框架核心進行資料庫訪問 非同步設計模式 儲存庫 儲存庫實現 服務 服務介面 服務的實現 產品和價格表之間的資料完

基於Leaflet 的Web地圖客戶端應用程式開發框架

MarsGIS for Leaflet地圖框架 是火星科技研發的一個Web地圖開發平臺系統,是火星科技團隊成員多年GIS開發和Leaflet使用的技術沉澱。基於Leaflet和現代Web技術棧全新構建, 集成了領先的開源地相簿、視覺化庫,提供了全新的大資料視覺化、實時流資料視

觸控式螢幕網站開發系列(一)-ios web App應用程式(ios meta)

轉自 觸控式螢幕網站的開發其實現在來講比前幾年移動端網站開發好多了,觸控式螢幕裝置IOS、Android、BBOS6等系統自帶瀏覽器均為WEBKIT核心,這就說明PC上面尚未立行的HTML5 CSS3能夠運用在這裡,極大的減少了工作量和資料的缺乏。 這篇文章講述關於IO

Java進行基於瀏覽器的桌面應用程式開發(Browser-based desktop application development with java)

http://blog.terac.com/andy/e_329.html關於嵌入式網站伺服器(Embedded web server):我這幾天試用了Jetty和Tomcat。總以為Jetty很小呢,最適合做BBDA呢

Spark應用程式開發引數調優深入剖析-Spark商業調優實戰

本套系列部落格從真實商業環境抽取案例進行總結和分享,並給出Spark商業應用實戰指導,請持續關注本套部落格。版權宣告:本套Spark商業應用實戰歸作者(秦凱新)所有,禁止轉載,歡迎學習。 Spark商業應用實戰-Spark資料傾斜案例測試及調優準則深入剖析 Spark商業應用實戰-Spark資源

P2P網路被谷歌來共享離線安裝應用程式

考慮到部分發展中國家網路覆蓋差和流量資費昂貴問題,谷歌正在通過P2P 共享技術幫助使用者離線安裝應用。 通過區域網的P2P 共享使用者可以快速獲得應用程式的安裝包,這樣可以降低使用者下載時間和耗費的流量費用。 當然基於安全考慮只有具有有效數字簽名的應用才可以P2P 共享,並且谷歌也會通過聯網

Windows應用程式開發

Windows窗體應用程式開發:WinForm、桌面應用程式,有可執行檔案(.exe)即安裝包。是一種C/S(客戶機/伺服器)架構應用程式 1.Windows窗體應用程式,用視覺化的窗體和控制元件生成豐富介面的,可互動操作的應用程式。從工具箱選擇相應控制元件,拖曳到窗體介面,通過設定其屬性,佈局外觀。雙擊控制

Linux應用程式開發筆記:測試程式碼執行時間

  #include <stdio.h> #include <sys/times.h> #include <unistd.h> void main(void) { double duration; clock_t start,

Linux應用程式開發筆記:make menuconfig環境搭建

1、目的 Linux應用程式開發採用與Linux核心一致的menuconfig圖形配置,方便功能元件裁剪。   2、準備工作 下載:Kconfiglib原始碼(https://github.com/ulfalizer/Kconfiglib)   3、環境搭

Android 應用程式開發環境搭建說明

之前開發一直用的Eclipse,今年接了個Android 車載POS機專案,系統使android 7.1 的,然後準備更新sdk發現已經停止更新了,儘管之前SDK的更新也很辛苦,國內google被牆了,只能利用國內的某些映象網站實現Android SDK線上更新。然後查閱論壇,才發現我已經落伍了,

IBM 釋出企業級社交協作平臺 Domino V10,開啟快速應用程式開發的新時代

北京時間 2018 年 10 月 10 日,IBM 正式全球釋出企業級社交協作平臺 Domino V10。全新版本 Domino V10 堅持安全可控,在保留傳統開發模式的同時擁抱現代化設計,創造更快速、現代、安全的開發環境,用更快更便捷的體驗帶企業進入下一個低

《資料庫系統應用程式開發》考試

考試的主要內容是JDBC Programing with Java,除了第一大題的簡單JDBC語句,還涉及實驗報告和Java程式設計的內容。 我屆考試題目與往年極其相似,後悔沒有好好看題。。呵呵 下面附上考試真題,造福全人類。(^_^) 看完可以考滿分了。     

Java應用程式開發學習之Iterator介面

Iterator是Java中的一個介面: 該介面提供瞭如下方法: 通過前面https://blog.csdn.net/morixinguan/article/details/85006962介面的學習我們已經瞭解到,介面需要一個子類去實現它的方法,而在相關的類中已經實現了對應

Java應用程式開發學習之多型

在Java中,使用關鍵字extends繼承或者關鍵字implements實現,是Java實現多型性的前提。 一、Java多型定義的格式 父類引用指向之類物件稱之為多型,多型的定義格式主要有兩種。 (1)父類名稱 物件名 = new 子類名稱(); (2)介面名稱 物件名 = new

Java應用程式開發學習之介面

一、介面的抽象方法定義: 在任何版本的java中,介面都能定義抽象方法 格式: public abstract 返回值型別 方法名稱(引數列表); 注意事項: 1.介面當中的抽象方法,修飾符必須是兩個固定的關鍵字:public abstract 2.這兩個關鍵字修飾符,可以選擇性省略

Java應用程式開發學習之繼承

面對物件程式語言有三類特性,分別是封裝性、繼承性以及多型性。 本節就來簡單介紹下Java的繼承。 一、繼承的簡單介紹、特點、規則 繼承是多型的前提,如果沒有繼承,就沒有多型。繼承主要解決的問題是:共性抽取(解決重複程式碼的問題)。 Java繼承知識點裡兩個重要的名詞:父類和子類