在前面的http://xdwangiflytek.iteye.com/blog/1391510 文章裡我們使用Lucene3.5做了一個Demo,在Demo中我們實現了一個建立索引和搜尋的功能。那麼我們現在在回過頭來看看在上面的Demo中,我們是將索引的位置放在本地磁碟中的,在上面最開始我也說了索引的位置可以是本地磁碟也可以是記憶體中,那麼我們可以想想,如果索引放在記憶體中會怎麼樣?簡單點來想,肯定是速度快沒有IO操作,但是呢?程式一退出後就消失了,對吧,但是我們是不是可以考慮兩種存放方式配合起來用呢?達到更好點的效果呢?
首先我們來說說建立的這兩種位置的方式:
磁碟中:
Java代碼
- File indexFile = new File(indexPath);
- Directory directory = FSDirectory.open(indexFile);
File indexFile = new File(indexPath);Directory directory = FSDirectory.open(indexFile);
記憶體中:
Java代碼
- Directory directory = new RAMDirectory();
Directory directory = new RAMDirectory();
我們可以這樣考慮,在程式啟動並執行時候索引從記憶體進行讀取,在程式退出的時候,再將索引儲存到磁碟,但程式再啟動並執行時候,再將磁碟中的索引放到記憶體中。這樣的話是不是效率上好一點啊!
下面我們對昨天的Demo進行一個上面所說的簡單最佳化:
FirstLucene02.java:
Java代碼
- package com.iflytek.lucene;
-
- import java.io.File;
-
- import org.apache.lucene.analysis.Analyzer;
- import org.apache.lucene.analysis.standard.StandardAnalyzer;
- import org.apache.lucene.document.Document;
- 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.Filter;
- 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.RAMDirectory;
- import org.apache.lucene.util.Version;
-
- /**
- * @author xudongwang 2012-2-3
- *
- * Email:xdwangiflytek@gmail.com
- */
- public class FirstLucene02 {
-
- /**
- * 源檔案路徑
- */
- private String filePath01 = "F:\\Workspaces\\workspaceSE\\BlogDemo\\luceneDatasource\\HelloLucene01.txt";
-
- /**
- * 索引路徑
- */
- private String indexPath = "F:\\Workspaces\\workspaceSE\\BlogDemo\\luceneIndex";
-
- /**
- * 分詞器,這裡我們使用預設的分詞器,標準分析器(好幾個,但對中文的支援都不好)
- */
- private Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);
-
- private Directory ramDir = null;
- /**
- * 搜尋
- *
- * @param queryStr
- * 搜尋的關鍵詞
- * @throws Exception
- */
- public void search(String queryStr) throws Exception {
-
- // 1、把要搜尋的文本解析為Query對象
- // 指定在哪些欄位查詢
- String[] fields = { "name", "content" };
- // QueryParser: 是一個解析使用者輸入的工具,可以通過掃描使用者輸入的字串,產生Query對象。
- QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_35,
- fields, analyzer);
- // Query:查詢,lucene中支援模糊查詢,語意查詢,短語查詢,組合查詢等等,如有TermQuery,BooleanQuery,RangeQuery,WildcardQuery等一些類。
- Query query = queryParser.parse(queryStr);
- // 2、進行查詢
- IndexReader indexReader = IndexReader.open(ramDir);
- IndexSearcher indexSearcher = new IndexSearcher(indexReader);
- // Filter 過濾器,我們可以將查出來的結果進行過濾,可以屏蔽掉一些不想給使用者看到的內容
- Filter filter = null;
- // 10000表示一次性在資料庫中查詢多少個文檔
- // topDocs 類似集合
- TopDocs topDocs = indexSearcher.search(query, filter, 10000);
- System.out.println("總共有【" + topDocs.totalHits + "】條匹配的結果");// 注意這裡的匹配結果是指文檔的個數,而不是文檔中包含搜尋結果的個數
- // 3、列印結果
- for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
- int docSn = scoreDoc.doc;// 文檔內部編號
- Document document = indexSearcher.doc(docSn);// 根據文檔編號取出相應的文檔
- File2Document.printDocumentInfo(document);// 列印出文檔資訊
- }
- }
-
- /**
- * 最佳化建立索引,將索引存在在記憶體和磁碟配合使用
- *
- * @throws Exception
- */
- public void createIndexByYouHua() throws Exception {
- File indexFile = new File(indexPath);
- Directory fsDir = FSDirectory.open(indexFile);
-
- // 1、啟動時,將磁碟中的索引讀取到記憶體中
- ramDir = new RAMDirectory(fsDir);
- IndexWriterConfig ramConf = new IndexWriterConfig(Version.LUCENE_35,
- analyzer);
-
- // 運行程式時操作記憶體中的索引
- IndexWriter ramIndexWriter = new IndexWriter(ramDir, ramConf);
- Document document = File2Document.file2Document(filePath01);
- ramIndexWriter.addDocument(document);
- ramIndexWriter.close();
-
- // 2、退出時將記憶體中的索引儲存到磁碟中
- IndexWriterConfig fsConf = new IndexWriterConfig(Version.LUCENE_35,
- analyzer);
- IndexWriter fsIndexWriter = new IndexWriter(fsDir, fsConf);
- fsIndexWriter.addIndexes(ramDir);// 把另外幾個索引庫中的所有索引資料合併到當前的索引庫中
- fsIndexWriter.close();
- }
-
- public static void main(String[] args) throws Exception {
- FirstLucene02 lucene = new FirstLucene02();
- lucene.createIndexByYouHua();
- lucene.search("iteye");
- }
-
- }
package com.iflytek.lucene;import java.io.File;import org.apache.lucene.analysis.Analyzer;import org.apache.lucene.analysis.standard.StandardAnalyzer;import org.apache.lucene.document.Document;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.Filter;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.RAMDirectory;import org.apache.lucene.util.Version;/** * @author xudongwang 2012-2-3 * * Email:xdwangiflytek@gmail.com */public class FirstLucene02 {/** * 源檔案路徑 */private String filePath01 = "F:\\Workspaces\\workspaceSE\\BlogDemo\\luceneDatasource\\HelloLucene01.txt";/** * 索引路徑 */private String indexPath = "F:\\Workspaces\\workspaceSE\\BlogDemo\\luceneIndex";/** * 分詞器,這裡我們使用預設的分詞器,標準分析器(好幾個,但對中文的支援都不好) */private Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);private Directory ramDir = null;/** * 搜尋 * * @param queryStr * 搜尋的關鍵詞 * @throws Exception */public void search(String queryStr) throws Exception {// 1、把要搜尋的文本解析為Query對象// 指定在哪些欄位查詢String[] fields = { "name", "content" };// QueryParser: 是一個解析使用者輸入的工具,可以通過掃描使用者輸入的字串,產生Query對象。QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_35,fields, analyzer);// Query:查詢,lucene中支援模糊查詢,語意查詢,短語查詢,組合查詢等等,如有TermQuery,BooleanQuery,RangeQuery,WildcardQuery等一些類。Query query = queryParser.parse(queryStr);// 2、進行查詢IndexReader indexReader = IndexReader.open(ramDir);IndexSearcher indexSearcher = new IndexSearcher(indexReader);// Filter 過濾器,我們可以將查出來的結果進行過濾,可以屏蔽掉一些不想給使用者看到的內容Filter filter = null;// 10000表示一次性在資料庫中查詢多少個文檔// topDocs 類似集合TopDocs topDocs = indexSearcher.search(query, filter, 10000);System.out.println("總共有【" + topDocs.totalHits + "】條匹配的結果");// 注意這裡的匹配結果是指文檔的個數,而不是文檔中包含搜尋結果的個數// 3、列印結果for (ScoreDoc scoreDoc : topDocs.scoreDocs) {int docSn = scoreDoc.doc;// 文檔內部編號Document document = indexSearcher.doc(docSn);// 根據文檔編號取出相應的文檔File2Document.printDocumentInfo(document);// 列印出文檔資訊}}/** * 最佳化建立索引,將索引存在在記憶體和磁碟配合使用 * * @throws Exception */public void createIndexByYouHua() throws Exception {File indexFile = new File(indexPath);Directory fsDir = FSDirectory.open(indexFile);// 1、啟動時,將磁碟中的索引讀取到記憶體中ramDir = new RAMDirectory(fsDir);IndexWriterConfig ramConf = new IndexWriterConfig(Version.LUCENE_35,analyzer);// 運行程式時操作記憶體中的索引IndexWriter ramIndexWriter = new IndexWriter(ramDir, ramConf);Document document = File2Document.file2Document(filePath01);ramIndexWriter.addDocument(document);ramIndexWriter.close();// 2、退出時將記憶體中的索引儲存到磁碟中IndexWriterConfig fsConf = new IndexWriterConfig(Version.LUCENE_35,analyzer);IndexWriter fsIndexWriter = new IndexWriter(fsDir, fsConf);fsIndexWriter.addIndexes(ramDir);// 把另外幾個索引庫中的所有索引資料合併到當前的索引庫中fsIndexWriter.close();}public static void main(String[] args) throws Exception {FirstLucene02 lucene = new FirstLucene02();lucene.createIndexByYouHua();lucene.search("iteye");}}
運行結果:
總共有【1】條匹配的結果 name -->HelloLucene01.txt content -->Hello, my name is wang xudong, I in iteye blog address is xdwangiflytek.iteye.com. path -->F:\Workspaces\workspaceSE\BlogDemo\luceneDatasource\HelloLucene01.txt size -->84 |
注意上面,添加的時候,索引檔案可能會很多,所以這樣就會產生更多的IO操作,影響效率,所以需要對索引檔案進行最佳化,減少檔案數量,從而減少IO操作。
在上面的最佳化建立索引的方法裡的倒數第二行添加:
Java代碼
- fsIndexWriter.commit();
- fsIndexWriter.optimize();//對索引檔案進行最佳化,從而減少IO操作
fsIndexWriter.commit();fsIndexWriter.optimize();//對索引檔案進行最佳化,從而減少IO操作
但是在Lucene3.5中這個方法提示過時了
看源碼提示:
Java代碼
- /** This method has been deprecated, as it is horribly
- * inefficient and very rarely justified. Lucene's
- * multi-segment search performance has improved over
- * time, and the default TieredMergePolicy now targets
- * segments with deletions.
- *
- * @deprecated */
/** This method has been deprecated, as it is horribly * inefficient and very rarely justified. Lucene's * multi-segment search performance has improved over * time, and the default TieredMergePolicy now targets * segments with deletions. * * @deprecated */
這裡還不知道Lucene3.5中對索引檔案進行最佳化的方法,這裡暫時留個問題。(?????)
有哪位知道的可以指點一下。
謝謝“gao2008ss”ok了,這種方式fsIndexWriter.forceMerge(1);,把上面的fsIndexWriter.optimize();替換為fsIndexWriter.forceMerge(1);