天天看點

Lucene學習筆記(二)Lucene的使用

如果你想快速查詢你磁盤上檔案,或查詢郵件、Web頁面,甚至查詢存于資料庫的資料,你都可以借助于Lucene來完成。但是要完成查詢就必須先建立索引。首先從Lucene API說起:

1、 Lucene API(核心操作類)

IndexWriter 建立和維護索引(向原索引中添加新Document,設定合并政策、優化等)
FSDirectory 最主要用來存儲索引檔案的類,表示将索引檔案存儲到檔案系統
Document 索引和查詢的原子單元,一個Document包含一系列Field
IndexReader 一個抽象類,提供了通路索引的接口,當然通路索引也可以通過它的子類來完成
Analyzer 分詞類,它有一系列子類,都是用來将文本解析成TokenStream
Searcher 用于查詢索引的核心類

 2、建立索引

Directory dir = FSDirectory.open(new File("lucene.blog"));
IndexWriter writer = new IndexWriter(dir,new StandardAnalyzer(Version.LUCENE_29),true, IndexWriter.MaxFieldLength.UNLIMITED);
Document doc = new Document();
doc.add(new Field("id", "101", Field.Store.YES, Field.Index.NO));
doc.add(new Field("name", "kobe bryant", Field.Store.YES, Field.Index.NO));
writer.addDocument(doc);
writer.optimize();
writer.close();
           

 如上所示将索引檔案存儲于工作目錄下lucene.blog檔案夾 ,建立了Document,向Document裡添加了兩個Field id和name,然後使用IndexWriter的addDocument(Document)方法将其添加到索引目錄下的索引檔案中,然後使用IndexWriter的optimize()方法進行對索引檔案優化,最後關閉IndexWriter;

3、通過IndexWriter删除索引中Document

Directory dir = FSDirectory.open(new File("lucene.blog"));
IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(Version.LUCENE_29), true, IndexWriter.MaxFieldLength.UNLIMITED);
writer.deleteDocuments(new Term("id", "101"));
writer.commit();
writer.close();
           

 如上先打開索引位置(工作目錄下lucene.blog檔案夾 ),然後直接調運IndexWriter的deleteDocuments(Term)方法删除上面2中建立的Document,注意必須調運commit()方法,上面2中之是以沒有commit()是因為optimize()方法中存在預設Commit方法;

4、通過IndexWriter更新索引中Document

Directory dir = FSDirectory.open(new File("lucene.blog"));
IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(Version.LUCENE_29), true, IndexWriter.MaxFieldLength.UNLIMITED);
Document doc = new Document();
doc.add(new Field("id", "101", Field.Store.YES, Field.Index.NO));
doc.add(new Field("name", "kylin soong", Field.Store.YES, Field.Index.NO));
writer.updateDocument(new Term("id", "101"), doc);
writer.commit();
writer.close();
           

 通過IndexWriter的updateDocument(Term, Document)來完成更新,具體是将包含Term("id", "101")的Document删除,然後将傳入的Document添加到索引檔案;

5、Field選項意義

Field field = new Field(
		"101",
		"kobe bryant",
		Field.Store.YES,
		Field.Index.ANALYZED,
		Field.TermVector.YES);
           

  如上代碼顯示Field各屬性設定情況,下面簡單說明這些屬性選項的意義

Field.Store.*決定是否将Field的完全值進行存儲,注意:不能将整個文本内容存儲,這樣導緻索引檔案過大

Field.Store.YES 存儲,一旦存儲,你可以用完整的Field的完全值作為查詢條件查詢(id:101)
Field.Store.NO 不存儲

 Field.Index.*控制Field的值是否可查詢通過索引成的索引檔案

Field.Index.ANALYZED 用Analyzer将Field的值分詞成多個Token
Field.Index.NOT_ANALYZED 不對Field的值分詞,将Field的值作為一個Token處理
Field.Index.ANALYZED_NO_NORMS 類似ANALYZED,但不存正常資訊到索引檔案
Field.Index.NOT_ANALYZED_NO_NORMS 類似NOT_ANALYZED,但不存正常資訊到索引檔案
Field.Index.NO 不進行索引,Field的值不可被搜尋

 如果你想要檢索出唯一的terms在搜尋時,或對搜尋結果進行加亮處理等操作是Field.TermVector.*是必要的

Field.TermVector.YES 記錄唯一的terms,當重複發生時記下重複數,在不做額外處理
Field.TermVector.WITH_POSITIONS 在上面基礎上記錄下位置
Field.TermVector.WITH_OFFSETS 在TermVector.YES基礎上記錄偏移量
Field.TermVector.WITH_POSITIONS_OFFSETS 在TermVector.YES基礎上記錄偏移量和位置
Field.TermVector.NO 不做任何處理

 6、索引numbers

Document doc = new Document();
NumericField field1 = new NumericField("id");
field1.setIntValue(101);
doc.add(field1);
NumericField field2 = new NumericField("price");
field1.setDoubleValue(123.50);
doc.add(field2);
           

 如上所示為索引numbers方法;

7、索引Date和Time

Document doc = new Document();
doc.add(new NumericField("timestamp").setLongValue(new Date().getTime()));
doc.add(new NumericField("day").setIntValue((int) (new Date().getTime()/24/3600)));
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
doc.add(new NumericField("dayOfMonth").setIntValue(cal.get(Calendar.DAY_OF_MONTH)));
           

 實質上對Date和Time的處理是将Date和Time轉化為numbers來處理,注意:當然也可以把Date和Time以及上面的numbers當做字元串來處理,不過這樣影響查詢;

 8、IndexWriter的其他同法

Directory dir = FSDirectory.open(new File("lucene.blog"));
IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(Version.LUCENE_29), true, IndexWriter.MaxFieldLength.LIMITED);
writer.setMaxFieldLength(1);
MergePolicy policy = new LogByteSizeMergePolicy(writer);
writer.setMergePolicy(policy);
writer.optimize(5);
writer.close();
           

 如上IndexWriter.MaxFieldLength.LIMITED設定了Field截取功能,如果Field值相當長,而你隻想索引Field值的前固定個字元,可以用Field截取功能來實作;IndexWriter的setMergePolicy(policy),可以設定合并政策,另外optimize(int maxNumSegments)方法可以通過參數設定優化成的Segment個數;

9、根據确定的term查詢

IndexReader reader = IndexReader.open(FSDirectory.open(new File("lucene.blog")),true);
IndexSearcher searcher = new IndexSearcher(reader); 
Term term = new Term("id","101");
Query query = new TermQuery(term);
TopDocs topDocs = searcher.search(query, 10);
System.out.println(topDocs.totalHits);
ScoreDoc[] docs = topDocs.scoreDocs;
System.out.println(docs[0].doc + " " + docs[0].score);
Document doc = searcher.doc(docs[0].doc);
System.out.println(doc.get("id"));
           

 如上示例顯示了一個Lucene查詢的基本方法,IndexSearcher是核心的查詢類,IndexReader 可以讀取索引檔案,IndexSearcher有一系列重載的Search()方法,可以根據傳入不同參數進行不同查詢處理,ScoreDoc數組儲存查詢結果,和相關得分;

10、根據QueryParser查詢,并收集查詢結果

IndexReader reader = IndexReader.open(FSDirectory.open(new File("lucene.blog")),true);
IndexSearcher searcher = new IndexSearcher(reader);
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_29);
QueryParser parser = new QueryParser(Version.LUCENE_29,"name",analyzer);
String queryString = "kobe";
Query query = parser.parse(queryString);
TopScoreDocCollector collector = TopScoreDocCollector.create(10, false);
searcher.search(query, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;
for(int i = 0 ; i < hits.length ; i ++) {
Document  doc = searcher.doc(hits[i].doc);
String name = doc.get("name");
if (name != null) {
	System.out.println(name);
}
}
           

如上為一個使用QueryParser查詢關鍵字“kobe”的執行個體,另外還對查詢結果進行了收集

11、使用Lucene圖形化工具Luke來操作索引

Luke使用非常簡單:

下載下傳:http://code.google.com/p/luke/ 點選下載下傳最新版本,下載下傳完成直接點選下載下傳的jar包,就可以進入圖形化操作界面,選擇索引的目錄就可以對索引進行圖形化操作,如下圖:

Lucene學習筆記(二)Lucene的使用

繼續閱讀