基于開源搜索引擎的架構設計和J2EE實現(二)
第四章 基于lucene的索引與搜索
4.1什么是Lucene全文檢索
Lucene是Jakarta Apache的開源項目。它是一個用Java寫的全文索引引擎工具包,可以方便的嵌入到各種應用中實現針對應用的全文索引/檢索功能。
4.2 Lucene的原理分析
4.2.1全文檢索的實現機制
Lucene的API接口設計的比較通用,輸入輸出結構都很像數據庫的表==>記錄==>字段,所以很多傳統的應用的文件、數據庫等都可以比較方便的映射到Lucene的存儲結構和接口中。
總體上看:可以先把Lucene當成一個支持全文索引的數據庫系統。
索引數據源:doc(field1,field2...) doc(field1,field2...)
\ indexer /
_____________
| Lucene Index|
--------------
/ searcher 結果輸出:Hits(doc(field1,field2) doc(field1...))
Document:一個需要進行索引的“單元”,一個Document由多個字段組成
Field:字段
Hits:查詢結果集,由匹配的Document組成
4.2.2 Lucene的索引效率
通常書籍后面常常附關鍵詞索引表(比如:北京:12, 34頁,上海:3,77 頁……),它能夠幫助讀者比較快地找到相關內容的頁碼。而數據庫索引能夠大大提高查詢的速度原理也是一樣,想像一下通過書后面的索引查找的速度要比一頁一 頁地翻內容高多少倍……而索引之所以效率高,另外一個原因是它是排好序的。對于檢索系統來說核心是一個排序問題。
由于數據庫索引不是為全文索引設計的,因此,使用like "%keyword%"時,數據庫索引是不起作用的,在使用like查詢時,搜索過程又變成類似于一頁頁翻書的遍歷過程了,所以對于含有模糊查詢的數據庫 服務來說,LIKE對性能的危害是極大的。如果是需要對多個關鍵詞進行模糊匹配:like"%keyword1%" and like "%keyword2%" ...其效率也就可想而知了。所以建立一個高效檢索系統的關鍵是建立一個類似于科技索引一樣的反向索引機制,將數據源(比如多篇文章)排序順序存儲的同 時,有另外一個排好序的關鍵詞列表,用于存儲關鍵詞==>文章映射關系,利用這樣的映射關系索引:[關鍵詞==>出現關鍵詞的文章編號,出現 次數(甚至包括位置:起始偏移量,結束偏移量),出現頻率],檢索過程就是把模糊查詢變成多個可以利用索引的精確查詢的邏輯組合的過程。從而大大提高了多 關鍵詞查詢的效率,所以,全文檢索問題歸結到***是一個排序問題。
由此可以看出模糊查詢相對數據庫的精確查詢是一個非常不確定的問題,這也是大部分數據庫對全文檢索支持有限的原因。Lucene最核心的特征是通過特殊的索引結構實現了傳統數據庫不擅長的全文索引機制,并提供了擴展接口,以方便針對不同應用的定制。
可以通過一下表格對比一下數據庫的模糊查詢:
Lucene全文索引引擎 數據庫
索引 將數據源中的數據都通過全文索引一一建立反向索引 對于LIKE查詢來說,數據傳統的索引是根本用不上的。數據需要逐個便利記錄進行GREP式的模糊匹配,比有索引的搜索速度要有多個數量級的下降。
匹配效果 通過詞元(term)進行匹配,通過語言分析接口的實現,可以實現對中文等非英語的支持。 使用:like "%net%" 會把netherlands也匹配出來,
多個關鍵詞的模糊匹配:使用like "%com%net%":就不能匹配詞序顛倒的xxx.net..xxx.com
匹配度 有匹配度算法,將匹配程度(相似度)比較高的結果排在前面。 沒有匹配程度的控制:比如有記錄中net出現5詞和出現1次的,結果是一樣的。
結果輸出 通過特別的算法,將最匹配度***的頭100條結果輸出,結果集是緩沖式的小批量讀取的。 返回所有的結果集,在匹配條目非常多的時候(比如上萬條)需要大量的內存存放這些臨時結果集。
可定制性 通過不同的語言分析接口實現,可以方便的定制出符合應用需要的索引規則(包括對中文的支持) 沒有接口或接口復雜,無法定制
結論 高負載的模糊查詢應用,需要負責的模糊查詢的規則,索引的資料量比較大 使用率低,模糊匹配規則簡單或者需要模糊查詢的資料量少
4.2.3 中文切分詞機制
對于中文來說,全文索引首先還要解決一個語言分析的問題,對于英文來說,語句中單詞之間是天然通過空格分開的,但亞洲語言的中日韓文語句中的字是一個字挨一個,所有,首先要把語句中按“詞”進行索引的話,這個詞如何切分出來就是一個很大的問題。
首先,肯定不能用單個字符作(si-gram)為索引單元,否則查“上?!睍r,不能讓含有“海上”也匹配。但一句話:“北京天安門”,計算機如何按照中文的語言習慣進行切分呢?“北京 天安門” 還是“北 京 天安門”?讓計算機能夠按照語言習慣進行切分,往往需要機器有一個比較豐富的詞庫才能夠比較準確的識別出語句中的單詞。另外一個解決的辦法是采用自動切分算法:將單詞按照2元語法(bigram)方式切分出來,比如:"北京天安門" ==> "北京 京天 天安 安門"。這樣,在查詢的時候,無論是查詢"北京" 還是查詢"天安門",將查詢詞組按同樣的規則進行切分:"北京","天安安門",多個關鍵詞之間按與"and"的關系組合,同樣能夠正確地映射到相應的索引中。這種方式對于其他亞洲語言:韓文,日文都是通用的。
基于自動切分的***優點是沒有詞表維護成本,實現簡單,缺點是索引效率低,但對于中小型應用來說,基于2元語法的切分還是夠用的。基于2元切分后的索引一般大小和源文件差不多,而對于英文,索引文件一般只有原文件的30%-40%不同,
自動切分 詞表切分
實現 實現非常簡單 實現復雜
查詢 增加了查詢分析的復雜程度, 適于實現比較復雜的查詢語法規則
存儲效率 索引冗余大,索引幾乎和原文一樣大 索引效率高,為原文大小的30%左右
維護成本 無詞表維護成本 詞表維護成本非常高:中日韓等語言需要分別維護。
還需要包括詞頻統計等內容
適用領域 嵌入式系統:運行環境資源有限
分布式系統:無詞表同步問題
多語言環境:無詞表維護成本 對查詢和存儲效率要求高的專業搜索引擎
4.3 Lucene與Spider的結合
首先構造一個Index類用來實現對內容進行索引。
代碼分析如下:
- package news;
- /**
- * 新聞搜索引擎
- * 計算機99630 沈晨
- * 版本1.0
- */
- import java.io.IOException;
- import org.apache.lucene.analysis.cn.ChineseAnalyzer;
- import org.apache.lucene.document.Document;
- import org.apache.lucene.document.Field;
- import org.apache.lucene.index.IndexWriter;
- public class Index {
- IndexWriter _writer = null;
- Index() throws Exception {
- _writer = new IndexWriter("c:\\News\\index",
- new ChineseAnalyzer(), true);
- }
- /**
- * 把每條新聞加入索引中
- * @param url 新聞的url
- * @param title 新聞的標題
- * @throws java.lang.Exception
- */
- void AddNews(String url, String title) throws Exception {
- Document _doc = new Document();
- _doc.add(Field.Text("title", title));
- _doc.add(Field.UnIndexed("url", url));
- _writer.addDocument(_doc);
- }
- /**
- * 優化并且清理資源
- * @throws java.lang.Exception
- */
- void close() throws Exception {
- _writer.optimize();
- _writer.close();
- }
- }
然后構造一個HTML解析類,把通過bot程序收集的新聞內容進行索引。
代碼分析如下:
- package news;
- /**
- * 新聞搜索引擎
- * 計算機99630 沈晨
- * 版本1.0
- */
- import java.util.Iterator;
- import java.util.Vector;
- import com.heaton.bot.HTMLPage;
- import com.heaton.bot.HTTP;
- import com.heaton.bot.Link;
- public class HTMLParse {
- HTTP _http = null;
- public HTMLParse(HTTP http) {
- _http = http;
- }
- /**
- * 對Web頁面進行解析后建立索引
- */
- public void start() {
- try {
- HTMLPage _page = new HTMLPage(_http);
- _page.open(_http.getURL(), null);
- Vector _links = _page.getLinks();
- Index _index = new Index();
- Iterator _it = _links.iterator();
- int n = 0;
- while (_it.hasNext()) {
- Link _link = (Link) _it.next();
- String _herf = input(_link.getHREF().trim());
- String _title = input(_link.getPrompt().trim());
- _index.AddNews(_herf, _title);
- n++;
- }
- System.out.println("共掃描到" + n + "條新聞");
- _index.close();
- }
- catch (Exception ex) {
- System.out.println(ex);
- }
- }
- /**
- * 解決java中的中文問題
- * @param str 輸入的中文
- * @return 經過解碼的中文
- */
- public static String input(String str) {
- String temp = null;
- if (str != null) {
- try {
- temp = new String(str.getBytes("ISO8859_1"));
- }
- catch (Exception e) {
- }
- }
- return temp;
- }
- }
4.4小節
在進行海量數據搜索時,如果使用單純的數據庫技術,那將是非常痛苦的。速度將是極大的瓶頸。所以本章提出了使用全文搜索引擎Lucene進行索引、搜索。
***,還結合了具體代碼說明了如何把Lucene全文搜索引擎和Spider程序互相集合來實現新聞搜索的功能。
第五章 基于Tomcat的Web服務器
5.1什么是基于Tomcat的Web服務器
Web服務器是在網絡中為實現信息發布、資料查詢、數據處理等諸多應用搭建基本平臺的服務器。Web服務器如何工作:在Web頁面處理中大致可分為三個步 驟,***步,Web瀏覽器向一個特定的服務器發出Web頁面請求;第二步,Web服務器接收到Web頁面請求后,尋找所請求的Web頁面,并將所請求的 Web頁面傳送給Web瀏覽器;第三步,Web服務器接收到所請求的Web頁面,并將它顯示出來。
Tomcat是一個開放源代碼、運行servlet和JSP Web應用軟件的基于Java的Web應用軟件容器。Tomcat由Apache-Jakarta子項目支持并由來自開放性源代碼Java社區的志愿者進行維護。Tomcat Server是根據servlet和JSP規范進行執行的,因此我們就可以說Tomcat Server也實行了Apache-Jakarta規范且比絕大多數商業應用軟件服務器要好。
5.2用戶接口設計
5.3.1客戶端設計
一個良好的查詢界面非常重要,例如Googl就以她簡潔的查詢界面而聞名。我在設計的時候也充分考慮了實用性和簡潔性。
5.3.2服務端設計
主要利用JavaTM Servlet技術實現,用戶通過GET方法從客戶端向服務端提交查詢條件,服務端通過Tomcat的Servlet容器接受并分析提交參數,再調用lucene的開發包進行搜索操作。***把搜索的結果以HTTP消息包的形式發送至客戶端,從而完成一次搜索操作。
服務端Servlet程序的結構如下:
實現的關鍵代碼如下:
- public void Search(String qc, PrintWriter out) throws Exception {
- // 從索引目錄創建索引
- IndexSearcher _searcher = new IndexSearcher("c:\\news\\index");
- // 創建標準分析器
- Analyzer analyzer = new ChineseAnalyzer();
- // 查詢條件
- String line = qc;
- // Query是一個抽象類
- Query query = QueryParser.parse(line, "title", analyzer);
- out.println("< html>");
- out.println("< head>< title>搜索結果< /title>< /head>");
- out.println("< body bgcolor=#ffffff>");
- out.println("< center>" +
- "< form action='/NewsServer/results' method='get'>" +
- "< font face='華文中宋' color='#3399FF'>新聞搜索引擎< /font>:" +
- "< input type='text' name='QueryContent' size='20'>" +
- "< input type='submit' name='submit' value='開始搜索'>" +
- "< /form>< /center>"
- );
- out.println("< p>搜索關鍵字:< font color=red>" + query.toString("title") +
- "< /font>< /p>");
- Hits hits = _searcher.search(query);
- out.println(" 總共找到< font color=red>" + hits.length() +
- "< /font>條新聞< br>");
- final int HITS_PER_PAGE = 10;
- for (int start = 0; start < hits.length(); start += HITS_PER_PAGE) {
- int end = Math.min(hits.length(), start + HITS_PER_PAGE);
- for (int i = start; i < end; i++) {
- Document doc = hits.doc(i);
- String url = doc.get("url");
- if (url != null) {
- out.println( (i + 1) + " < a href='" + url + "'>" +
- replace(doc.get("title"), qc) +
- "< /a>< br>");}
- else {
- System.out.println("沒有找到!");}
- }}
- out.println("< /body>< /html>");
- _searcher.close();
- };
5.3在Tomcat上部署項目
Tomcat中的應用程序是一個WAR(Web Archive)文件。WAR是Sun提出的一種Web應用程序格式,與JAR類似,也是許多文件的一個壓縮包。這個包中的文件按一定目錄結構來組織:通 常其根目錄下包含有Html和Jsp文件或者包含這兩種文件的目錄,另外還會有一個WEB-INF目錄,這個目錄很重要。通常在WEB-INF目錄下有一 個web.xml文件和一個classes目錄,web.xml是這個應用的配置文件,而classes目錄下則包含編譯好的Servlet類和Jsp或 Servlet所依賴的其它類(如JavaBean)。通常這些所依賴的類也可以打包成JAR放到WEB-INF下的lib目錄下,當然也可以放到系統的 CLASSPATH中。
在Tomcat中,應用程序的部署很簡單,你只需將你的WAR放到Tomcat的webapp目錄下,Tomcat會自動檢測到這個文件,并將其解壓。你 在瀏覽器中訪問這個應用的Jsp時,通常***次會很慢,因為Tomcat要將Jsp轉化為Servlet文件,然后編譯。編譯以后,訪問將會很快。
5.4小節
本章中詳細介紹了如何構架基于Tomcat的Web服務器,使得用戶通過瀏覽器進行新聞的搜索,***還對Tomcat如何部署進行了說明。
第六章 搜索引擎策略
6.1簡介
隨著信息多元化的增長,千篇一律的給所有用戶同一個入口顯然已經不能滿足特定用戶更深入的查詢需求。同時,這樣的通用搜索引擎在目前的硬件條件下,要及時更新以得到互聯網上較全面的信息是不太可能的。針對這種情況,我們需要一個分類細致精確、數據全面深入、更新及時的面向主題的搜索引擎。
由于主題搜索運用了人工分類以及特征提取等智能化策略,因此它比上面提到的前三代的搜索引擎將更加有效和準確,我們將這類完善的主題搜索引擎稱為第四代搜索引擎。
6.2面向主題的搜索策略
6.2.1導向詞
導向詞就是一組關鍵詞,它們會引導搜索器按照一定順序搜索整個網絡,使得搜索引擎可以在最短的時間里面得到最全面的跟某一個主題相關的信息。通過設置導向 詞以及它們對應的不同權值,所有標題、作者、正文或超連接文本中含有某一導向詞的網頁都會被賦予較高的權值,在搜索的時候會優先考慮。搜索器在向主控程序 獲得URL的時候也是按照權值由高到低的順序。反之,搜索器在向主控程序提交新的URL和它的權值的時候,主控程序會按照權值預先排序,以便下一次有序的 發給搜索器。
6.2.2網頁評級
在考慮一個網頁被另一個網頁的引用時候,不是單純的將被引用網頁的Hit Number加一,而是將引用網頁的連接數作為權,同時將該引用網頁的重要性也考慮進來(看看上面提到的例子,Yahoo!引用的網頁顯然比個人網站引用的網頁重要,因為Yahoo!本身很重要),就可以得到擴展后的網頁評分。
最早提出網頁評分的計算方法是Google。它們提出了一個“隨機沖浪”模型來描述網絡用戶對網頁的訪問行為。模型假設如下:
1) 用戶隨機的選擇一個網頁作為上網的起始網頁;
2) 看完這個網頁后,從該網頁內所含的超鏈內隨機的選擇一個頁面繼續進行瀏覽;
3) 沿著超鏈前進了一定數目的網頁后,用戶對這個主題感到厭倦,重新隨機選擇一個網頁進行瀏覽,并重復2和3。
按照以上的用戶行為模型,每個網頁可能被訪問到的次數就是該網頁的鏈接權值。如何計算這個權值呢?PageRank采用以下公式進行計算:
其中Wj代表第j個網頁的權值;lij只取0、1值,代表從網頁i到網頁j是否存在鏈接;ni代表網頁i有多少個鏈向其它網頁的鏈接;d代表“隨機沖浪” 中沿著鏈接訪問網頁的平均次數。選擇合適的數值,遞歸的使用以上公式,即可得到理想的網頁鏈接權值。該方法能夠大幅度的提高簡單檢索返回結果的質量,同時 能夠有效的防止網頁編寫者對搜索引擎的欺騙。因此可以將其廣泛的應用在檢索器提供給用戶的網頁排序上,對于網頁評分越高的網頁,就排的越前。
6.2.3權威網頁和中心網頁
權威網頁
顧名思義,是給定主題底下的一系列重要的權威的網頁。其重要性和權威性主要體現在以下兩點:
1) 從單個網頁來看,它的網頁內容本身對于這個給定主題來說是重要的;
2) 從這個網頁在整個互聯網重的地位來看,這個網頁是被其他網頁承認為權威的,這主要體現在跟這個主題相關的很多網頁都有鏈接指向這個網頁。
由此可見,權威網頁對于主題搜索引擎的實現有很重大的意義。主題搜索引擎一個很關鍵的任務就是從互聯網上無數的網頁之中最快最準的找出這些可數的權威網頁,并為他們建立索引。這也是有效區別主題搜索引擎和前三代傳統通用搜索引擎的重要特征。
中心網頁
是包含很多指向權威網頁的超鏈接的網頁。最典型中心網頁的一個例子是Yahoo!,它的目錄結構指向了很多主題的權威網頁,使得它兼任了很多主題的中心網頁。由中心網頁出發,輕而易舉的就會到達大量的權威網頁。因此,它對于主題搜索引擎的實現也起了很大的意義。
權威網頁和中心網頁之間是一種互相促進的關系:一個好的中心網頁必然要有超鏈接指向多個權威網頁;一個好的權威網頁反過來也必然被多個中心網頁所鏈接。
6.3小節
本章介紹了面向主題的搜索策略,并作了詳細闡述。雖然在新聞搜索中并沒有應用到搜索策略,但是對于WWW搜索引擎來說,搜索策略是極其重要的。他直接關系到搜索的質量以及匹配度等性能。
【編輯推薦】