雖然使用Lucene已經有一段時間了,可是仍不敢妄加評論Lucene的好與壞,畢竟目前接觸的全文索引技術只有Lucene。並且Lucene並非真正意義上的引擎,只算的上是Java開發的全文索引工具包。與傳統的數據庫查詢對比,全文索引技術更具備優點。Lucene不只能夠對磁盤文件進行索引,也能夠對數據庫記錄進行索引,而且支持的索引文件格式多種多樣(結合其餘的文本處理工具)。言歸正傳,本文將爲讀者具體講解Lucene的基本使用,入門級。java
本文Lucene使用的版本爲4.0.0數據庫
1. 建立索引。工具
索引建立原理大體分爲如下幾步:spa
分詞,將原文檔傳給分詞組件進行分詞,獲得詞元。code
詞元處理,將詞元傳給語言處理組件進行一些語言處理,例如:變小寫,轉詞根。orm
索引,對處理後的詞元創建詞典。例如,詞‘中國’出如今ID爲2,5,7的文檔中,出現頻率分別爲1,5,3次。對象
具體實現以下:排序
建立索引時須要兩個目錄,一個是索引文件的存放目錄(indexPath),一個是待索引的文件目錄(docsPath)。在建立索引時,咱們首先要加載或建立索引目錄。經常使用的目錄建立方式有兩種:索引
RAMDirectory directory = new RAMDirectory();
Directory dir = FSDirectory.open(new File(indexPath));
而後經過IndexWriter對象來建立和維護索引。Analyzer爲索引分詞器,主要是對獲取的文本進行分詞操做。因爲Lucene是由外國人開發的,因此自己對中文的分詞效果不是很好。因爲中文不像英文那樣,詞與詞之間有明顯的分隔符(英文通常以空格區分),因此中文分詞在實現上就比英文分詞複雜困難的多,並且歧義識別和新詞識別一直是中文分詞中的難點。token
迴歸正題,IndexWriterConfig對象用來設置IndexWriter一些初始配置,一旦IndexWriter對象建立完成,改變IndexWriterConfig的配置對已建立的IndexWriter對象不會產生影響。
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_40); IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_40, analyzer); iwc.setOpenMode(OpenMode.CREATE_OR_APPEND);//設置索引維護的方式 iwc.setRAMBufferSizeMB(256.0);//設置用來緩衝文檔的RAM大小 IndexWriter writer = new IndexWriter(dir, iwc);
接下來須要建立Document文檔,並經過IndexWriter對象將文檔添加到索引庫中。Document文檔能夠是一個HTML頁面,一篇文本文檔,一封電子郵件。一個Document能夠包含多個Field,Field表明文檔的屬性。此處file爲文件對象。
Document doc = new Document(); doc.add(new StringField("path", file.getPath(), Field.Store.YES)); doc.add(new TextField("filename", file.getName(), Field.Store.YES));
注意:StringField被索引不被分詞,整個值被看做爲一個單獨的token而被索引。
TextField既被索引又被分詞,可是沒有詞向量。
Filed類型還包含LongField、DoubleField、IntFiled等,具體的含義請參考官方API。
最後須要將文檔添加到索引庫中。
writer.addDocument(doc); writer.close();
2. 檢索索引。
檢索索引的原理大體以下:
對查詢語句進行詞法分析、語法分析和語言處理。詞法分析主要是識別單詞和關鍵字。語法分析主要是根據查詢語句的語法規則來造成一顆語法樹。語言處理與索引創建過程當中語言處理幾乎相同。
搜索索引,獲得符合語法樹的文檔
根據獲得的文檔和查詢語句的相關性,對結果進行排序。
具體實現以下:
檢索索引首先要讀取索引文檔,並創建IndexSearch對象。
IndexReader reader = DirectoryReader.open(FSDirectory.open(new File(indexPath))); IndexSearcher searcher = new IndexSearcher(reader);
而後須要對查詢語句進行分析,Lucene經過Query接口實現類來對查詢條件進行分析。Lucene支持單Filed查詢、多Field查詢、邏輯組合查詢、模糊查詢、範圍查詢、通配符查詢等。各類查詢方式的具體實現本文暫時不討論。
單字段查詢。
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_40); QueryParser queryParser = new QueryParser(Version.LUCENE_40, " filename",analyzer) ; queryParser.setDefaultOperator(QueryParser.OR_OPERATOR);//設置默認邏輯‘或’查詢 Query query = queryParser.parse(condition);
多字段查詢
String[] fields = new String[]{"filename"," path "}; Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_40); //MultiFieldQueryParser multiFieldQueryParser = new MultiFieldQueryParser(Version.LUCENE_40, fields, analyzer); //Query query = multiFieldQueryParser.parse(condition); BooleanClause.Occur[] flags = {BooleanClause.Occur.SHOULD, BooleanClause.Occur.MUST}; Query query = MultiFieldQueryParser.parse(Version.LUCENE_40, condition, fields, flags, analyzer);
接下來,經過IndexSearcher對象進行查找。對查詢出來的結果能夠進行高亮顯示關鍵字,取摘要等處理。
TopDocs results = searcher.search(query,10); ScoreDoc[] hits = results.scoreDocs; for(ScoreDoc hit:hits){ Document doc = searcher.doc(hit.doc); SimpleHTMLFormatter formatter = new SimpleHTMLFormatter("<font color='red'>", "</font>"); Highlighter highlighter = new Highlighter(formatter, new QueryScorer(query)); Fragmenter fragmenter =new SimpleFragmenter(80); highlighter.setTextFragmenter(fragmenter); Information information = new Information(); information.setId(hit.doc); information.setPath(doc.get("path")); if(highlighter.getBestFragment(analyzer, "filename", doc.get("filename"))==null){ information.setFileName(doc.get("filename")); }else{ information.setFileName(highlighter.getBestFragment(analyzer, "filename", doc.get("filename"))); } informations.add(information); }
3. 更新索引。
Lucene索引的更新爲調用IndexWriter的updateDocument方法,該方法接受兩個參數,第一個Term詞向量,第二個爲新增的文檔,能夠是單個文檔,也能夠是批量文檔。Lucene會先根據Term刪除索引庫中原有的文檔,再向索引庫中添加新的document。Term的第一參數表示要在文檔的哪一個Field上查找,第二個表明查詢關鍵字。
writer.updateDocument(new Term("path", file.getPath()), doc);
4. 刪除索引。
Lucene索引的刪除的能夠根據Query對象來刪除,也能夠根據Term來刪除,也能夠一次刪除所有索引。
//根據Term刪除 writer.deleteDocuments(new Term("path", file.getPath())); //刪除所有索引 writer.deleteAll();