什么是lucence
Lucene是apache軟件基金會發布的一個開放源代碼的全文檢索引擎工具包,由資深全文檢索專家Doug Cutting所撰寫,它是一個全文檢索引擎的架構,提供了完整的創建索引和查詢索引,以及部分文本分析的引擎,Lucene的目的是為軟件開發人員提供一個簡單易用的工具包,以方便在目標系統中實現全文檢索的功能,或者是以此為基礎建立起完整的全文檢索引擎,Lucene在全文檢索領域是一個經典的祖先,現在很多檢索引擎都是在其基礎上創建的,思想是相通的。Lucene是根據關健字來搜索的文本搜索工具,只能在某個網站內部搜索文本內容,不能跨網站搜索。
索引和搜素
索引是現代搜索引擎的核心,建立索引的過程就是把源數據處理成非常方便查詢的索引文件的過程。為什么索引這么重要呢,試想你現在要在大量的文檔中搜索含有某個關鍵詞的文檔,那么如果不建立索引的話你就需要把這些文檔順序的讀入內存,然后檢查這個文章中是不是含有要查找的關鍵詞,這樣的話就會耗費非常多的時間,想想搜索引擎可是在毫秒級的時間內查找出要搜索的結果的。這就是由於建立了索引的原因,你可以把索引想象成這樣一種數據結構,他能夠使你快速的隨機訪問存儲在索引中的關鍵詞,進而找到該關鍵詞所關聯的文檔。Lucene 采用的是一種稱為反向索引(inverted index)的機制。反向索引就是說我們維護了一個詞 / 短語表,對於這個表中的每個詞 / 短語,都有一個鏈表描述了有哪些文檔包含了這個詞 / 短語。這樣在用戶輸入查詢條件的時候,就能非常快的得到搜索結果。
全文檢索
將非結構化數據中的一部分信息提取出來,重新組織,使其變得有一定結構,然后對此有一定結構的數據進行搜索,從而達到搜索相對較快的目的。這部分從非結構化數據中提取出的然后重新組織的信息,我們稱之索引。例如:字典。字典的拼音表和部首檢字表就相當於字典的索引,對每一個字的解釋是非結構化的,如果字典沒有音節表和部首檢字表,在茫茫辭海中找一個字只能順序掃描。然而字的某些信息可以提取出來進行結構化處理,比如讀音,就比較結構化,分聲母和韻母,分別只有幾種可以一一列舉,於是將讀音拿出來按一定的順序排列,每一項讀音都指向此字的詳細解釋的頁數。我們搜索時按結構化的拼音搜到讀音,然后按其指向的頁數,便可找到我們的非結構化數據——也即對字的解釋。這種先建立索引,再對索引進行搜索的過程就叫全文檢索(Full-text Search)。
Luncene使用流程
創建索引庫
1、創建JavaBean對象
2、創建Docment對象
3、將JavaBean對象所有的屬性值,均放到Document對象
4、創建IndexWriter對象
4、將Document對象通過IndexWriter對象寫入索引庫
5、關閉IndexWriter對象
查詢索引庫中的內容
1、創建IndexSearcher對象
2、創建QueryParser對象
3、創建Query對象來封裝關鍵字
4、 用IndexSearcher對象去索引庫中查詢符合條件的前100條記錄,不足100條記錄的以實際為准
5、獲取符合條件的編號
6、用indexSearcher對象去索引庫中查詢編號對應的Document對象,將Document對象中的所有屬性取出,再封裝回JavaBean對象中去,並加入到集合中保存
Lucene 軟件包分析
Package: org.apache.lucene.document
這個包提供了一些為封裝要索引的文檔所需要的類,比如 Document, Field。這樣,每一個文檔最終被封裝成了一個 Document 對象。
Package: org.apache.lucene.analysis
這個包主要功能是對文檔進行分詞,因為文檔在建立索引之前必須要進行分詞,所以這個包的作用可以看成是為建立索引做准備工作。
Package: org.apache.lucene.index
這個包提供了一些類來協助創建索引以及對創建好的索引進行更新。這里面有兩個基礎的類:IndexWriter 和 IndexReader,其中 IndexWriter 是用來創建索引並添加文檔到索引中的,IndexReader 是用來刪除索引中的文檔的。
Package: org.apache.lucene.search
這個包提供了對在建立好的索引上進行搜索所需要的類。比如 IndexSearcher 和 Hits, IndexSearcher 定義了在指定的索引上進行搜索的方法,Hits 用來保存搜索得到的結果
快速入門
創建項目,導入相關jar包
public class Article { //編號 private Integer id; //標題 private String title; //內容 private String content; public Article(){} public Article(Integer id, String title, String content) { this.id = id; this.title = title; this.content = 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; } @Override public String toString() { return "編號:" + id+"\n標題:" + title + "\n內容:" + content; } }
public class FirstApp { /** * 創建索引庫 * 將Aritcle對象放入索引庫中的原始記錄表中,從而形成詞匯表 */ @Test public void createIndexDB() throws Exception{ // 創建Article對象 Article article = new Article(1,"培訓","傳智是一家IT培訓機構"); // 創建Document對象 Document document = new Document(); // 將Article對象中的三個屬性值分別綁定到Document對象 /* *參數一:document對象中的屬性名 *參數二:document對象中的屬性值 *參數三:是否將屬性值存入由原始記錄表中轉存入詞匯表 * Store.YES表示該屬性值會存入詞匯表 * Store.NO表示該屬性值不會存入詞匯表 *參數四:是否將屬性值進行分詞算法 * Index.ANALYZED表示該屬性值會進行詞匯拆分 * Index.NOT_ANALYZED表示該屬性值不會進行詞匯拆分 */ document.add(new Field("xid",article.getId().toString(), Field.Store.YES, Field.Index.ANALYZED)); document.add(new Field("xtitle",article.getTitle(), Field.Store.YES, Field.Index.ANALYZED)); document.add(new Field("xcontent",article.getContent(), Field.Store.YES, Field.Index.ANALYZED)); // 創建IndexWriter字符流對象 /* * 參數一:lucene索引庫最終應對於硬盤中的目錄,例如:E:/IndexDBDBDB * 參數二:采用什么策略將文本拆分,一個策略就是一個具體的實現類 * 參數三:最多將文本拆分出多少詞匯,LIMITED表示1W個,即只取前1W個詞匯,如果不足1W個詞匯個,以實際為准 */ Directory directory = FSDirectory.open(new File("E:/IndexDBDBDB")); Version version = Version.LUCENE_30; Analyzer analyzer = new StandardAnalyzer(version); IndexWriter.MaxFieldLength maxFieldLength = IndexWriter.MaxFieldLength.LIMITED; IndexWriter indexWriter = new IndexWriter(directory,analyzer,maxFieldLength); // 將document對象寫入lucene索引庫 indexWriter.addDocument(document); // 關閉IndexWriter字符流對象 indexWriter.close(); } /** * 根據關鍵字從索引庫中搜索符合條件的內容 */ @Test public void findIndexDB() throws Exception{ String keywords = "培"; List<Article> articleList = new ArrayList<>(); Directory directory = FSDirectory.open(new File("E:/IndexDBDBDB")); Version version = Version.LUCENE_30; Analyzer analyzer = new StandardAnalyzer(version); // 創建IndexSearcher字符流對象 IndexSearcher indexSearcher = new IndexSearcher(directory); // 創建查詢解析器對象 /* * 參數一:使用分詞器的版本,提倡使用該jar包中的最高版本 * 參數二:對document對象中的哪個屬性進行搜索 */ QueryParser queryParser = new QueryParser(version,"xcontent",analyzer); // 創建對象,封裝查詢關鍵字 Query query = queryParser.parse(keywords); // 根據關鍵字,去索引庫中的詞匯表搜索 /* * 參數一:表示封裝關鍵字查詢對象,QueryParser表示查詢解析器 * 參數二:MAX_RECORD表示如果根據關鍵字搜索出來的內容較多,只取前MAX_RECORD個內容 * 不足MAX_RECORD個數的話,以實際為准 */ int MAX_RECORD = 100; TopDocs topDocs = indexSearcher.search(query,MAX_RECORD); // 迭代詞匯表中符合條件的編號 for(int i=0;i<topDocs.scoreDocs.length;i++){ // 取出封裝編號和分數的ScoreDoc對象 ScoreDoc scoreDoc = topDocs.scoreDocs[i]; // 取出每一個編號,例如:0,1,2 int no = scoreDoc.doc; // 根據編號去索引庫中的原始記錄表中查詢對應的document對象 Document document = indexSearcher.doc(no); // 獲取document對象中的三個屬性值 String xid = document.get("xid"); String xtitle = document.get("xtitle"); String xcontent = document.get("xcontent"); // 封裝到artilce對象中 Article article = new Article(Integer.parseInt(xid),xtitle,xcontent); // 將article對象加入到list集合中 articleList.add(article); } // 迭代結果集 for(Article a:articleList){ System.out.println(a); } } }