一、Lucene版本的選擇 |
首先在我打算學習Lucene,在我開始寫這個系列的文章的時候Lucene已經出了6.2.0。但是我學習的版本是3.5.0,之所以選擇這個版本是因爲鄭浩老師有一個視頻講解,能帶我從具體的實踐中瞭解Lucene,爲了不陷入到版本的不兼容的泥潭中,我打算學習Lucene3.5.0,弄明白了具體的原理和操作,在學習新的版本。
解壓後的Lucene3.5.0的文件夾的內容如下圖:
對於初學者,知道只需要知道兩個jar包:
1. lucene-core-3.5.0.jar包,這個是Lucene的主要功能包。
2. lib文件夾下面的junit的jar包,做單元測試使用。儘量使用lucene壓縮包中的junit,不然會出現版本不兼容的問題。
還要了解docs文件夾下的index.html,這個是對應版本的Lucene的API說明文檔,很有用。
二、HelloLucene工程創建 |
看一下HelloLucene的工程目錄:
其中lib文件夾下存放的是需要用到的兩個jar包,Referenced Libraries
中是通過 add build path
生成的。
三、HelloLucene建立索引 |
索引的建立就是針對原始的數據生成一個用於檢索的索引,這個索引可以存儲在內存中,也可以存儲在硬盤上。
public void index() {
IndexWriter writer = null;
try {
//1、創建Directory
//Directory directory = new RAMDirectory(); //將索引建立在內存中
Directory directory = FSDirectory.open(new File("d:/lucene/index01"));
//2、創建IndexWriter
IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35));
writer = new IndexWriter(directory, conf);
//3、創建文檔Document對象
Document doc = null;
//4、爲文檔Document添加域Field
File f = new File("d:/lucene/example");
for(File file: f.listFiles()) {
doc = new Document();
doc.add(new Field("content", new FileReader(file)));
doc.add(new Field("filename", file.getName(), Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.add(new Field("path", file.getAbsolutePath(), Field.Store.YES, Field.Index.NOT_ANALYZED));
//5、通過IndexWriter添加文檔到索引中
writer.addDocument(doc);
} //for
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(writer != null)
try {
writer.close();
} catch (CorruptIndexException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} //index()
四、Lucene通過索引檢索 |
索引建立之後,接下來就是通過索引對數據進行檢索:
public void searcher() {
try {
//1、創建Directory
Directory directory = FSDirectory.open(new File("d:/lucene/index01"));
//2、創建IndexReader
IndexReader reader = IndexReader.open(directory);
//3、根據IndexReader創建IndexSeacher
IndexSearcher searcher = new IndexSearcher(reader);
//4、創建搜索的query
// 創建parser來確定要搜索的文件的內容,第二個參數表示文件的域
QueryParser parser = new QueryParser(Version.LUCENE_35, "content", new StandardAnalyzer(Version.LUCENE_35));
//創建query,表示搜索域content中包含java的文檔
Query query = parser.parse("language");
//5、根據searcher搜索並且返回TopDocs
TopDocs tds = searcher.search(query, 10);
//6、根據TopDocs獲取ScoreDoc對象
ScoreDoc[] sds = tds.scoreDocs;
for(ScoreDoc sd: sds) {
//7、根據searcher和ScoreDoc對象獲取具體的Document對象
Document d = searcher.doc(sd.doc);
//8、根據Document對象獲取需要的值
System.out.println(d.get("filename") + "[" + d.get("path") + "]");
}
//9、關閉reader
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
} // searcher()
注意:整個工作流程很簡單,建立索引的過程就是讀取磁盤上的某一個目錄,然後依次對該目錄中的文件建立索引,把索引存儲在硬盤的一個目錄中。檢索的過程就是讀取這個索引目錄的過程。
在建立索引的時候,content
這個域僅僅是讀取了文件,沒有指定是否存儲,通過看Field的源代碼可以發現默認是不存儲、要索引、要分詞的。所以檢索的時候可以在content
中檢索language
這個檢索關鍵詞,並等得到相應的文檔,但是得到的文檔不能通過d.get("content")
得到文檔的內容,因爲索引文件中沒有存儲這個域的原始數據。
Lucene的三個大的步驟就是:
- 建立索引
- 分詞
- 檢索
具體的一些概念,這裏先不講,本文只是針對Lucene做一個實戰的認知,有了實戰的認知之後,在講述原理的部分纔不會那麼枯燥。
說明幾個Eclipse的快捷鍵:
- shift+ctrl+o:快速導入包名(前提已經build path)
- ctrl + /:快速添加註釋
- alt + /:自動不全或者提示補全