一、概述
lucene是一個全文搜索引擎,在全文索引工具中,都是由這樣的但部分組成:
- 1、索引部分
- 2、分詞部分
- 3、搜索部分
二、入門程序
2.1 入門程序
這里我們需要導入lucene
的jar
包,注意:這里使用的是3.5.0版本,lucene
的各個版本差異較大。
下面看入門程序,看lucene如何創建索引和搜索索引(工程lucene01
):
HelloLucene.java
package cn.lucene.test;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
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.ParseException;
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.store.RAMDirectory;
import org.apache.lucene.util.Version;
public class HelloLucene {
//建立索引
public void index(){
IndexWriter writer = null;
try {
//1、創建Directory
//Directory directory = new RAMDirectory();//索引是建立在內存中的
Directory directory = FSDirectory.open(new File("E:/myeclipse/Lucene/index"));//創建在硬盤上
//2、創建IndexWriter
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35));
writer = new IndexWriter(directory, iwc);
//3、創建Document對象
Document doc = null;
//4、為Document添加Field,是Document的一個子元素
File file = new File("E:/myeclipse/Lucene/somefile");
for(File f : file.listFiles()){
doc = new Document();
doc.add(new Field("content", new FileReader(f)));
doc.add(new Field("filename", f.getName(), Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.add(new Field("path", f.getAbsolutePath(), Field.Store.YES, Field.Index.NOT_ANALYZED));
//5、通過IndexWriter添加文檔到索引中
writer.addDocument(doc);
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//搜索
public void search(){
Directory directory;
try {
//1、創建Directory
directory = FSDirectory.open(new File("E:/myeclipse/Lucene/index"));
//2、創建IndexReader
IndexReader reader = IndexReader.open(directory);
//3、根據IndexReader創建IndexSearcher
IndexSearcher searcher = new IndexSearcher(reader);
//4、創建搜索的Query
//創建QueryParser來確定要搜索文件的內容,第二個參數表示搜索的域
QueryParser parser = new QueryParser(Version.LUCENE_35, "content", new StandardAnalyzer(Version.LUCENE_35));
//創建Query,表示搜索域為content中包含java的文檔
Query query = parser.parse("java");
//5、根據searcher搜索并且返回TopDocs
TopDocs tdoc = searcher.search(query, 10);//只會顯示10條內容
//6、根據TopDocs獲取ScoreDoc對象
ScoreDoc sdocs[] = tdoc.scoreDocs;
for(ScoreDoc s : sdocs){
//7、根據searcher行業ScoreDoc獲取具體的Document對象
Document document = searcher.doc(s.doc);
//8、根據Document對象獲取所需要的值
System.out.println(document.get("filename") + "[" + document.get("path") + "]");
}
//9、關閉reader
reader.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
}
說明:這里我們存儲的文檔放在E:/myeclipse/Lucene/somefile
中,創建的搜索我們放在E:/myeclipse/Lucene/index
中,這里方法index()
是創建文檔索引的方法,而search()
是搜索文檔索引的方法。
2.2 測試
TestLucene.java
package cn.lucene.test;
import org.junit.Test;
public class TestLucene {
@Test
public void testIndex(){
HelloLucene hLucene = new HelloLucene();
hLucene.index();
}
@Test
public void testSearch(){
HelloLucene hLucene = new HelloLucene();
hLucene.search();
}
}
說明:這里我們在創建文檔之后再次創建生成的索引不會覆蓋,而是會增加,這是因為lucene
索引是一種增量索引,每次生成索引都不會將前面生成的索引刪除,而是添加,于是每次搜索出來的結果會有重復。這里我們搜索關鍵字為java
,會打印出相關的文件路徑,這里我們先不深究程序的具體實現。
三、相關概念
3.1 建立索引時最重要的幾個術語
Document
:一個要進行索引的單元,相當于數據庫的一行紀錄,任何想要被索引的數據,都必須轉化為Document
對象存放。Field
:Document
中的一個字段,相當于數據庫中的Column
,Field
是lucene
比較多概念一個術語。IndexWriter
:負責將Document
寫入索引文件。通常情況下,IndexWriter
的構造函數包括了以下3個參數:索引存放的路徑,分析器和是否重新創建索引。特別注意的一點,當IndexWriter
執行完addDocument
方法后,一定要記得調用自身的close
方法來關閉它。只有在調用了close
方法后,索引器才會將存放在內在中的所有內容寫入磁盤并關閉輸出流。Analyzer
:分析器,主要用于文本分詞(可以這樣理解,就是將一段話分成單個的詞語,然后為單個的詞語建立標識,便于搜索,就像一個超鏈接一樣)。常用的有StandardAnalyzer
分析器,StopAnalyzer
分析器,WhitespaceAnalyzer
分析器等。Directory
:索引存放的位置。lucene
提供了兩種索引存放的位置,一種是磁盤,一種是內存。一般情況將索引放在磁盤上;相應地lucene
提供了FSDirectory
和RAMDirectory
兩個類。-
段:
Segment
是Lucene
索引文件的最基本的一個單位。Lucene
說到底就是不斷加入新的Segment
,然后按一定的規則算法合并不同的Segment
以合成新的Segment
。我們在上面測試時從建立的索引文件中就可以看出有如
1
圖中使用0,1標號表示的就是段,而這里我們可以看到每次創建索引都是增加而不是覆蓋。 最后
lucene
建立索引的過程就是將待索引的對象轉化為Lucene
的Document
對象,使用IndexWriter
將其寫入lucene
自定義格式的索引文件中。待索引的對象可以來自文件、數據庫等任意途徑,用戶自行編碼遍歷目錄讀取文件或者查詢數據庫表取得ResultSet
,Lucene
的API
只負責和字符串打交道。
3.2 存儲域選項
存儲域選項有Field.Store.YES
或Field.Store.NO
,設置為YES
表示把這個域中的內容完全存儲到文件中,方便進行文本的還原,設置為NO
表示不把這個域中的內容完全存儲到文件中,但是可以被索引,此時內容無法完全還原。比如一篇文章,我們可以建立文章的索引(此索引就是用來搜索這篇文章的一個標簽),但是我們可以不將整片文章內容全部存儲下來,但是這樣我們雖然能搜索到這篇文章,但是卻不能將其還原。
3.3 索引域選項:
-
Field.Index.ANALYZED
:進行分詞和索引,適用于標題、內容等。 -
Field.Index. ANALYZED_NO_NORMS
:進行分詞但是不存儲norms
信息,這個norms
中包括創建索引的時間和權值等信息 -
Field.Index. NOT_ANALYZED
:進行索引,但是不進行分詞,如身份證號、姓名、ID等,試用于精確索引 -
Field.Index. NOT_ANALYZED_NO_NORMS
:即不進行分詞也不存儲norms
信息 -
Field.Index.NO
:不進行索引
3.4 最佳實踐
域選項 | 存儲與否 | 最佳實踐 |
---|---|---|
NOT_ANALYZED_NO_NORMS |
YES |
標識符(主鍵、文件名),電話號碼,身份證號,姓名,日期 |
ANALYZED |
YES |
文檔標題和摘要 |
ANALYZED |
NO |
文檔正文 |
NO |
YES |
文檔類型,數據庫主鍵(不進行索引) |
NOT_ANALYZED |
NO |
隱藏關鍵字 |