初識 Lucene

          實戰(zhàn) Lucene,第 1 部分: 初識 Lucene

          developerWorks
          文檔選項
          將此頁作為電子郵件發(fā)送

          將此頁作為電子郵件發(fā)送

          未顯示需要 JavaScript 的文檔選項


          拓展 Tomcat 應(yīng)用

          下載 IBM 開源 J2EE 應(yīng)用服務(wù)器 WAS CE 新版本 V1.1


          級別: 初級

          朋 周登 (zhoudengpeng@yahoo.com.cn), 軟件工程師

          2006 年 4 月 20 日

          本文首先介紹了Lucene的一些基本概念,然后開發(fā)了一個應(yīng)用程序演示了利用Lucene建立索引并在該索引上進(jìn)行搜索的過程。

          Lucene 簡介

          Lucene 是一個基于 Java 的全文信息檢索工具包,它不是一個完整的搜索應(yīng)用程序,而是為你的應(yīng)用程序提供索引和搜索功能。Lucene 目前是 Apache Jakarta 家族中的一個開源項目。也是目前最為流行的基于 Java 開源全文檢索工具包。

          目前已經(jīng)有很多應(yīng)用程序的搜索功能是基于 Lucene 的,比如 Eclipse 的幫助系統(tǒng)的搜索功能。Lucene 能夠為文本類型的數(shù)據(jù)建立索引,所以你只要能把你要索引的數(shù)據(jù)格式轉(zhuǎn)化的文本的,Lucene 就能對你的文檔進(jìn)行索引和搜索。比如你要對一些 HTML 文檔,PDF 文檔進(jìn)行索引的話你就首先需要把 HTML 文檔和 PDF 文檔轉(zhuǎn)化成文本格式的,然后將轉(zhuǎn)化后的內(nèi)容交給 Lucene 進(jìn)行索引,然后把創(chuàng)建好的索引文件保存到磁盤或者內(nèi)存中,最后根據(jù)用戶輸入的查詢條件在索引文件上進(jìn)行查詢。不指定要索引的文檔的格式也使 Lucene 能夠幾乎適用于所有的搜索應(yīng)用程序。

          圖 1 表示了搜索應(yīng)用程序和 Lucene 之間的關(guān)系,也反映了利用 Lucene 構(gòu)建搜索應(yīng)用程序的流程:



          圖1. 搜索應(yīng)用程序和 Lucene 之間的關(guān)系
          圖1. 搜索應(yīng)用程序和 Lucene 之間的關(guān)系




          回頁首


          索引和搜索

          索引是現(xiàn)代搜索引擎的核心,建立索引的過程就是把源數(shù)據(jù)處理成非常方便查詢的索引文件的過程。為什么索引這么重要呢,試想你現(xiàn)在要在大量的文檔中搜索含有某個關(guān)鍵詞的文檔,那么如果不建立索引的話你就需要把這些文檔順序的讀入內(nèi)存,然后檢查這個文章中是不是含有要查找的關(guān)鍵詞,這樣的話就會耗費(fèi)非常多的時間,想想搜索引擎可是在毫秒級的時間內(nèi)查找出要搜索的結(jié)果的。這就是由于建立了索引的原因,你可以把索引想象成這樣一種數(shù)據(jù)結(jié)構(gòu),他能夠使你快速的隨機(jī)訪問存儲在索引中的關(guān)鍵詞,進(jìn)而找到該關(guān)鍵詞所關(guān)聯(lián)的文檔。Lucene 采用的是一種稱為反向索引(inverted index)的機(jī)制。反向索引就是說我們維護(hù)了一個詞/短語表,對于這個表中的每個詞/短語,都有一個鏈表描述了有哪些文檔包含了這個詞/短語。這樣在用戶輸入查詢條件的時候,就能非常快的得到搜索結(jié)果。我們將在本系列文章的第二部分詳細(xì)介紹 Lucene 的索引機(jī)制,由于 Lucene 提供了簡單易用的 API,所以即使讀者剛開始對全文本進(jìn)行索引的機(jī)制并不太了解,也可以非常容易的使用 Lucene 對你的文檔實現(xiàn)索引。

          對文檔建立好索引后,就可以在這些索引上面進(jìn)行搜索了。搜索引擎首先會對搜索的關(guān)鍵詞進(jìn)行解析,然后再在建立好的索引上面進(jìn)行查找,最終返回和用戶輸入的關(guān)鍵詞相關(guān)聯(lián)的文檔。





          回頁首


          Lucene 軟件包分析

          Lucene 軟件包的發(fā)布形式是一個 JAR 文件,下面我們分析一下這個 JAR 文件里面的主要的 JAVA 包,使讀者對之有個初步的了解。

          Package: org.apache.lucene.document

          這個包提供了一些為封裝要索引的文檔所需要的類,比如 Document, Field。這樣,每一個文檔最終被封裝成了一個 Document 對象。

          Package: org.apache.lucene.analysis

          這個包主要功能是對文檔進(jìn)行分詞,因為文檔在建立索引之前必須要進(jìn)行分詞,所以這個包的作用可以看成是為建立索引做準(zhǔn)備工作。

          Package: org.apache.lucene.index

          這個包提供了一些類來協(xié)助創(chuàng)建索引以及對創(chuàng)建好的索引進(jìn)行更新。這里面有兩個基礎(chǔ)的類:IndexWriter 和 IndexReader,其中 IndexWriter 是用來創(chuàng)建索引并添加文檔到索引中的,IndexReader 是用來刪除索引中的文檔的。

          Package: org.apache.lucene.search

          這個包提供了對在建立好的索引上進(jìn)行搜索所需要的類。比如 IndexSearcher 和 Hits, IndexSearcher 定義了在指定的索引上進(jìn)行搜索的方法,Hits 用來保存搜索得到的結(jié)果。





          回頁首


          一個簡單的搜索應(yīng)用程序

          假設(shè)我們的電腦的目錄中含有很多文本文檔,我們需要查找哪些文檔含有某個關(guān)鍵詞。為了實現(xiàn)這種功能,我們首先利用 Lucene 對這個目錄中的文檔建立索引,然后在建立好的索引中搜索我們所要查找的文檔。通過這個例子讀者會對如何利用 Lucene 構(gòu)建自己的搜索應(yīng)用程序有個比較清楚的認(rèn)識。





          回頁首


          建立索引

          為了對文檔進(jìn)行索引,Lucene 提供了五個基礎(chǔ)的類,他們分別是 Document, Field, IndexWriter, Analyzer, Directory。下面我們分別介紹一下這五個類的用途:

          Document

          Document 是用來描述文檔的,這里的文檔可以指一個 HTML 頁面,一封電子郵件,或者是一個文本文件。一個 Document 對象由多個 Field 對象組成的。可以把一個 Document 對象想象成數(shù)據(jù)庫中的一個記錄,而每個 Field 對象就是記錄的一個字段。

          Field

          Field 對象是用來描述一個文檔的某個屬性的,比如一封電子郵件的標(biāo)題和內(nèi)容可以用兩個 Field 對象分別描述。

          Analyzer

          在一個文檔被索引之前,首先需要對文檔內(nèi)容進(jìn)行分詞處理,這部分工作就是由 Analyzer 來做的。Analyzer 類是一個抽象類,它有多個實現(xiàn)。針對不同的語言和應(yīng)用需要選擇適合的 Analyzer。Analyzer 把分詞后的內(nèi)容交給 IndexWriter 來建立索引。

          IndexWriter

          IndexWriter 是 Lucene 用來創(chuàng)建索引的一個核心的類,他的作用是把一個個的 Document 對象加到索引中來。

          Directory

          這個類代表了 Lucene 的索引的存儲的位置,這是一個抽象類,它目前有兩個實現(xiàn),第一個是 FSDirectory,它表示一個存儲在文件系統(tǒng)中的索引的位置。第二個是 RAMDirectory,它表示一個存儲在內(nèi)存當(dāng)中的索引的位置。

          熟悉了建立索引所需要的這些類后,我們就開始對某個目錄下面的文本文件建立索引了,清單1給出了對某個目錄下的文本文件建立索引的源代碼。



          清單 1. 對文本文件建立索引
          package TestLucene;
                                  import java.io.File;
                                  import java.io.FileReader;
                                  import java.io.Reader;
                                  import java.util.Date;
                                  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;
                                  /**
                                  * This class demonstrate the process of creating index with Lucene
                                  * for text files
                                  */
                                  public class TxtFileIndexer {
                                  public static void main(String[] args) throws Exception{
                                  //indexDir is the directory that hosts Lucene's index files
                                  File   indexDir = new File("D:\\luceneIndex");
                                  //dataDir is the directory that hosts the text files that to be indexed
                                  File   dataDir  = new File("D:\\luceneData");
                                  Analyzer luceneAnalyzer = new StandardAnalyzer();
                                  File[] dataFiles  = dataDir.listFiles();
                                  IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
                                  long startTime = new Date().getTime();
                                  for(int i = 0; i < dataFiles.length; i++){
                                  if(dataFiles[i].isFile() && dataFiles[i].getName().endsWith(".txt")){
                                  System.out.println("Indexing file " + dataFiles[i].getCanonicalPath());
                                  Document document = new Document();
                                  Reader txtReader = new FileReader(dataFiles[i]);
                                  document.add(Field.Text("path",dataFiles[i].getCanonicalPath()));
                                  document.add(Field.Text("contents",txtReader));
                                  indexWriter.addDocument(document);
                                  }
                                  }
                                  indexWriter.optimize();
                                  indexWriter.close();
                                  long endTime = new Date().getTime();
                                  System.out.println("It takes " + (endTime - startTime)
                                  + " milliseconds to create index for the files in directory "
                                  + dataDir.getPath());
                                  }
                                  }
                                  

          在清單1中,我們注意到類 IndexWriter 的構(gòu)造函數(shù)需要三個參數(shù),第一個參數(shù)指定了所創(chuàng)建的索引要存放的位置,他可以是一個 File 對象,也可以是一個 FSDirectory 對象或者 RAMDirectory 對象。第二個參數(shù)指定了 Analyzer 類的一個實現(xiàn),也就是指定這個索引是用哪個分詞器對文擋內(nèi)容進(jìn)行分詞。第三個參數(shù)是一個布爾型的變量,如果為 true 的話就代表創(chuàng)建一個新的索引,為 false 的話就代表在原來索引的基礎(chǔ)上進(jìn)行操作。接著程序遍歷了目錄下面的所有文本文檔,并為每一個文本文檔創(chuàng)建了一個 Document 對象。然后把文本文檔的兩個屬性:路徑和內(nèi)容加入到了兩個 Field 對象中,接著在把這兩個 Field 對象加入到 Document 對象中,最后把這個文檔用 IndexWriter 類的 add 方法加入到索引中去。這樣我們便完成了索引的創(chuàng)建。接下來我們進(jìn)入在建立好的索引上進(jìn)行搜索的部分。





          回頁首


          搜索文檔

          利用Lucene進(jìn)行搜索就像建立索引一樣也是非常方便的。在上面一部分中,我們已經(jīng)為一個目錄下的文本文檔建立好了索引,現(xiàn)在我們就要在這個索引上進(jìn)行搜索以找到包含某個關(guān)鍵詞或短語的文檔。Lucene提供了幾個基礎(chǔ)的類來完成這個過程,它們分別是呢IndexSearcher, Term, Query, TermQuery, Hits. 下面我們分別介紹這幾個類的功能。

          Query

          這是一個抽象類,他有多個實現(xiàn),比如TermQuery, BooleanQuery, PrefixQuery. 這個類的目的是把用戶輸入的查詢字符串封裝成Lucene能夠識別的Query。

          Term

          Term是搜索的基本單位,一個Term對象有兩個String類型的域組成。生成一個Term對象可以有如下一條語句來完成:Term term = new Term(“fieldName”,”queryWord”); 其中第一個參數(shù)代表了要在文檔的哪一個Field上進(jìn)行查找,第二個參數(shù)代表了要查詢的關(guān)鍵詞。

          TermQuery

          TermQuery是抽象類Query的一個子類,它同時也是Lucene支持的最為基本的一個查詢類。生成一個TermQuery對象由如下語句完成: TermQuery termQuery = new TermQuery(new Term(“fieldName”,”queryWord”)); 它的構(gòu)造函數(shù)只接受一個參數(shù),那就是一個Term對象。

          IndexSearcher

          IndexSearcher是用來在建立好的索引上進(jìn)行搜索的。它只能以只讀的方式打開一個索引,所以可以有多個IndexSearcher的實例在一個索引上進(jìn)行操作。

          Hits

          Hits是用來保存搜索的結(jié)果的。

          介紹完這些搜索所必須的類之后,我們就開始在之前所建立的索引上進(jìn)行搜索了,清單2給出了完成搜索功能所需要的代碼。



          清單2 :在建立好的索引上進(jìn)行搜索
          package TestLucene;
                                  import java.io.File;
                                  import org.apache.lucene.document.Document;
                                  import org.apache.lucene.index.Term;
                                  import org.apache.lucene.search.Hits;
                                  import org.apache.lucene.search.IndexSearcher;
                                  import org.apache.lucene.search.TermQuery;
                                  import org.apache.lucene.store.FSDirectory;
                                  /**
                                  * This class is used to demonstrate the
                                  * process of searching on an existing
                                  * Lucene index
                                  *
                                  */
                                  public class TxtFileSearcher {
                                  public static void main(String[] args) throws Exception{
                                  String queryStr = "lucene";
                                  //This is the directory that hosts the Lucene index
                                  File indexDir = new File("D:\\luceneIndex");
                                  FSDirectory directory = FSDirectory.getDirectory(indexDir,false);
                                  IndexSearcher searcher = new IndexSearcher(directory);
                                  if(!indexDir.exists()){
                                  System.out.println("The Lucene index is not exist");
                                  return;
                                  }
                                  Term term = new Term("contents",queryStr.toLowerCase());
                                  TermQuery luceneQuery = new TermQuery(term);
                                  Hits hits = searcher.search(luceneQuery);
                                  for(int i = 0; i < hits.length(); i++){
                                  Document document = hits.doc(i);
                                  System.out.println("File: " + document.get("path"));
                                  }
                                  }
                                  }
                                  

          在清單2中,類IndexSearcher的構(gòu)造函數(shù)接受一個類型為Directory的對象,Directory是一個抽象類,它目前有兩個子類:FSDirctory和RAMDirectory. 我們的程序中傳入了一個FSDirctory對象作為其參數(shù),代表了一個存儲在磁盤上的索引的位置。構(gòu)造函數(shù)執(zhí)行完成后,代表了這個IndexSearcher以只讀的方式打開了一個索引。然后我們程序構(gòu)造了一個Term對象,通過這個Term對象,我們指定了要在文檔的內(nèi)容中搜索包含關(guān)鍵詞”lucene”的文檔。接著利用這個Term對象構(gòu)造出TermQuery對象并把這個TermQuery對象傳入到IndexSearcher的search方法中進(jìn)行查詢,返回的結(jié)果保存在Hits對象中。最后我們用了一個循環(huán)語句把搜索到的文檔的路徑都打印了出來。好了,我們的搜索應(yīng)用程序已經(jīng)開發(fā)完畢,怎么樣,利用Lucene開發(fā)搜索應(yīng)用程序是不是很簡單。





          回頁首


          總結(jié)

          本文首先介紹了 Lucene 的一些基本概念,然后開發(fā)了一個應(yīng)用程序演示了利用 Lucene 建立索引并在該索引上進(jìn)行搜索的過程。希望本文能夠為學(xué)習(xí) Lucene 的讀者提供幫助。



          關(guān)于作者

           

          周登朋,軟件工程師,上海交通大學(xué)研究生,對 Java 技術(shù)以及信息檢索技術(shù)很感興趣。您可以通過 zhoudengpeng@yahoo.com.cn 與他聯(lián)系。

          posted on 2007-04-13 22:06 mingyue 閱讀(261) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          <2007年4月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(2)

          隨筆檔案

          nice blog

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 观塘区| 三明市| 黄平县| 福泉市| 彰化县| 乌海市| 阳曲县| 呼图壁县| 华阴市| 若尔盖县| 沙洋县| 临西县| 双峰县| 金川县| 青浦区| 舞钢市| 波密县| 旅游| 昌黎县| 象山县| 牡丹江市| 古田县| 茂名市| 宁津县| 新干县| 乐山市| 柘城县| 七台河市| 辽中县| 调兵山市| 乐清市| 安新县| 肇庆市| 常熟市| 湾仔区| 武穴市| 安平县| 孝昌县| 盐源县| 固镇县| 博白县|