本案例使用的是Lucene-3.6.2版本,Lucene官方網站:http://lucene.apache.org/。
案例說明:
本例類比了貼吧中檢索文章的功能,通過建立Article類來類比文章對象。使用者輸入檢索資訊,Lucene就可以根據檢索資訊來擷取與之相關的Article對象,並返回給使用者。
一、建立工程
首先在我們的MyEclipse中建立一個Java工程即可,在裡面建立一個lib檔案夾用於存放我們開發時用的jar包。
二、匯入jar包
本案例需要Lucene的4個基本jar包。如下:
lucene-core-3.6.2.jar
contrib\analyzers\common\lucene-analyzers-3.6.2.jar(分詞器)
contrib\highlighter\lucene-highlighter-3.6.2.jar(高亮)
contrib\memory\lucene-memory-3.6.2.jar(高亮)
然後將lib中的四個jar包Build Path。
三、建立HelloWorld類
在src下自建立一個包,並在包中建立HelloWorld.java檔案。
這個檔案中不需要main函數,我們將通過jUnit來測試程式。
所以在我們的方法中需要添加@Test註解。
public class HelloWorld {//建立索引庫@Testpublic void createIndex() {}//搜尋索引庫@Testpublic void seacherIndex() {}}
四、建立檢索類PO
建立我們需要檢索的類Article(類比文章對象),裡面有三個欄位:id,title,content,
分別表示:編號、標題、內容。
public class Article {private Integer id;//idprivate String title;//標題private String content;//內容public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}@Overridepublic String toString() {return "Article [id=" + id + ", title=" + title + ", content="+ content + "]";}}
五、編寫HelloWorld,實現建立和查詢索引庫
這裡需要記住建立和查詢的兩個核心API:
向索引庫中增刪改的時候,使用IndexWriter對象。
其主要方法為:addDocument()、updateDocument()、deleteDocument()。
從索引庫中搜尋的時候,使用IndexSearcher對象。
其主要方法為:search()。
裡面的一些API的體繫結構圖會在最後的附件中列出,可對照查看。
程式中的步驟是按照編號走的,由於需要準備各種參數,所以顯得有些淩亂,只要按照步驟參考即可。
import java.io.File;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.document.Document;import org.apache.lucene.document.Field;import org.apache.lucene.document.Field.Index;import org.apache.lucene.document.Fieldable;import org.apache.lucene.document.Field.Store;import org.apache.lucene.index.CorruptIndexException;import org.apache.lucene.index.IndexReader;import org.apache.lucene.index.IndexWriter;import org.apache.lucene.index.IndexWriterConfig;import org.apache.lucene.queryParser.MultiFieldQueryParser;import org.apache.lucene.queryParser.QueryParser;import org.apache.lucene.search.IndexSearcher;import org.apache.lucene.search.Query;import org.apache.lucene.search.ScoreDoc;import org.apache.lucene.search.TopDocs;import org.apache.lucene.store.Directory;import org.apache.lucene.store.FSDirectory;import org.apache.lucene.store.LockObtainFailedException;import org.apache.lucene.util.Version;import org.junit.Test;import lucene.a_domain.Article;public class HelloWorld {//建立索引庫/** * 執行這個方法會將這個方法中建立的Article對象中的屬性:id,title,content轉換成Document欄位, * 索引庫中只能存放Document類型對象,不能存放我們建立的對象,將Article轉成Document後, * 通過IndexWriter的addDocument方法將轉換後的Document對象添加到索引庫中, * 執行這個方法後,將會在指定的索引庫目錄中建立索引檔案,這是一堆二進位檔案。 * 因為用到了IO,所以最後需要將IndexWriter關閉。 * @throws Exception */@Testpublic void createIndex() throws Exception {/* * 2.建立索引庫目錄,這是IndexWriter構造器的第一個參數。 * 這個Directory是個抽象類別,按住ctrl+t可以查看這個類的繼承體系, * 會發現他有一個子抽象類別,叫做FSDirectory, * 我們需要使用這個類的執行個體當作我們的Directory, * 但他是抽象的,無法new, * FSDirectory裡面有一個open方法, open方法接收一個File, * 這個open方法就可以擷取FSDirectory執行個體, * 而File是我們指定的存放目錄的路徑,在當前工程建立一個indexDir檔案夾作為路徑即可, * 至此,索引庫目錄配置完成,將這個引用添加到IndexWriter的第一個參數的位置。 */Directory directory = FSDirectory.open(new File("./indexDir/"));/* * 4.建立IndexWriterConfig構造器的第二個參數,analyzer分詞器。 * 這個Analyzer也是一個抽象類別,ctrl+t查看其繼承體系可以發現它有很多子類。 * 這裡先使用它的標準分詞器,StandardAnalyzer。 * new這個類需要一個版本號碼參數,同樣通過Version的靜態常量給出。 * 分詞器建立完成。添加到IndexWriterConfig的第二個參數上。 */Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_36);/* * 3.建立IndexWriter構造器的第二個參數,配置。 * 直接new,發現報錯,它的構造器需要兩個參數, * 一個是Version,一個是Analyzer, * Version通過Version.LUCENE_36即可建立,這時Version類中的一個靜態常量。 * Analyzer是分詞器,這是Lucene內建的分詞器,這個分詞器不支援中文 */IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36,analyzer);//1.這裡需要兩個參數,第一個是索引庫目錄,第二個是配置,在上面提供這兩個參數即可IndexWriter indexWriter = new IndexWriter(directory,indexWriterConfig);/* * 6.建立要存入索引庫的對象Article, * 建立完成後,我們需要將Article中的屬性轉換成Document的欄位 */Article article = new Article();article.setId(1);article.setTitle("Lucene是什麼");article.setContent("Lucene,速度捷徑離開減肥啦實際得分卡設計大方");/* * 7.將Article轉換成Document對象, * 需要將Article中的屬性轉換成Document的欄位 * 直接new一個Document,再通過Document的add方法添加欄位, * add方法需要一個Fieldable類型的參數,Fieldable是一個介面, */Document doc = new Document();/* * 8.建立Fieldable的子類,ctrl+t查看繼承體系,發現有個Field子類 * 建立Field需要四個參數,String name,String value,Store store,Index index * 第一個參數表示索引庫的欄位名稱; * 第二個參數表示存放到該欄位上的值; * 第三個參數表示是否儲存 * 第四個參數表示分詞 * 在add方法裡直接new,Article有三個屬性,需要添加三個欄位到Document中,所以add三次 *///Fieldable field = new Field("id",article.getId().toString(),Store.YES,Index.ANALYZED);doc.add(new Field("id",article.getId().toString(),Store.YES,Index.ANALYZED));doc.add(new Field("title", article.getTitle(), Store.YES, Index.ANALYZED));doc.add(new Field("content", article.getContent(), Store.YES, Index.ANALYZED));/* * 5.建立索引庫,使用IndexWriter的addDocument方法。 * 這個方法需要一個Document參數。這個Document就是放入索引庫的資料, * 但是我們需要放入的是Article對象,這就需要將我們的Article類型轉換成Document類型。 */indexWriter.addDocument(doc);/* * 9.關閉流 */indexWriter.close();}//搜尋索引庫/** * 搜尋索引庫時,開始先建立了一個List集合來儲存最終查詢的結果。 * 這個程式中,將查詢條件寫死了,真正開發的時候是不可能寫死的,所以開發時這個查詢條件是需要擷取的。 * 根據查詢條件就可以從索引庫的到最終的結果集,但是索引庫中存放的是Document對象,所以擷取的結果集也是Document對象集合。 * 還需要將Document對象轉換成我們需要的Article對象,根據document對象的get方法擷取即可,get(name)參數為欄位名稱。 * 最後我們調用了showResults(List list)方法將擷取的結果集遍曆取出,顯示在控制台上。 * @throws Exception */@Testpublic void seacherIndex() throws Exception {//建立一個集合,存放查詢出來的資料。List<Article> list = new ArrayList<Article>();/* * 2.建立索引庫目錄,指定索引庫目錄路徑,提供給IndexSearcher */Directory directory = FSDirectory.open(new File("./indexDir/"));/* * 1.建立IndexSearcher對象,這個對象的構造器需要接收一個IndexReader對象 * 這個IndexReader是一個抽象類別,它裡面有一個抽象方法:open。 * open方法的參數是Directory,即索引庫目錄,需要指定它從那個索引庫目錄中讀取資料。 * 在上面建立這個目錄,跳到第2步。 */IndexSearcher indexSearcher = new IndexSearcher(IndexReader.open(directory));/* * 4.建立查詢條件 * QueryParser只能指定在一個欄位上進行檢索,例如如果指定了id欄位就只能查詢id欄位。是單欄位檢索。 * QueryParser有三個參數, * 參數1:版本 * 參數2:表示對哪個欄位進行檢索,這裡傳入一個欄位名稱 * 參數3:分詞器 * 這裡查詢條件是"Lucene"表示在某個欄位中查詢"Lucene"。 */String queryString = "Lucene";//6.準備分詞器:Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_36);//5.建立解析器QueryParser queryParser = new QueryParser(Version.LUCENE_36,"title",analyzer);//7.將查詢條件放入解析器中。這裡返回的是query對象,這個對象作為IndexSearcher的search方法的第一個參數Query query = queryParser.parse(queryString);/* * 3.通過IndexSearcher的search方法建立查詢 * 參數1:表示查詢條件 * 參數2:表示返回的前多少條記錄 * search傳回值為TopDocs類型,這是查詢完的結果集。 */TopDocs topDocs = indexSearcher.search(query, 100);System.out.println("總記錄數:" + topDocs.totalHits);//這個欄位擷取查詢到的總記錄數。//8.擷取結果集數組ScoreDoc[] scoreDocs = topDocs.scoreDocs;//遍曆scoreDocs,if(scoreDocs!=null && scoreDocs.length>0) {for (int i = 0; i < scoreDocs.length; i++) {ScoreDoc scoreDoc = scoreDocs[i];System.out.println("擷取這個記錄的得分:" + scoreDoc.score);//擷取檢索出的記錄在索引庫中的唯一編號,根據這個編號就可以擷取需要的資料int doc = scoreDoc.doc;//IndexSearcher的doc方法可以通過剛擷取的唯一編號從索引庫中擷取我們需要的資料Document document = indexSearcher.doc(doc);//擷取了Document對象,還需要將Document對象轉成Article對象。Article article = new Article();/* * 通過document對象的get方法,根據欄位名稱擷取值, * 這裡的名稱是通過上面的 * doc.add(new Field("id",article.getId().toString(),Store.YES,Index.ANALYZED)); * 這個方法設定的欄位名稱 */article.setId(Integer.parseInt(document.get("id")));article.setTitle(document.get("title"));article.setContent(document.get("content"));//添加到存放結果的集合中。list.add(article);}}//9.關閉流indexSearcher.close();//10.遍曆輸出最終擷取的結果集合if(list != null && list.size() > 0) {showResults(list);}}private void showResults(List<Article> list) {for(Article article : list) {System.out.println("文章編號:" + article.getId());System.out.println("文章標題:" + article.getTitle());System.out.println("文章內容:" + article.getContent());System.out.println("------------------------------------------------");}}}
先執行createIndex方法,這樣我們先建立的索引庫就有資料了,然後再執行seacherIndex方法,就可以將索引庫擷取的資料顯示在控制台上。
六、查看索引庫中產生的檔案
我們將索引庫定義在了工程的根目錄下:
進入這個目錄,可以看到產生的檔案,這都是一些二進位檔案。
七、附件
這裡提供了一些類的繼承體系資訊。
Directory類:
Analyzer類: