一. 概述
隨著系統(tǒng)信息的越來越多,怎么樣從這些信息海洋中撈起自己想要的那一根針就變得非常重要了,全文檢索是通常用于解決此類問題的方案,而Lucene則為實現(xiàn)全文檢索的工具,任何應用都可通過嵌入它來實現(xiàn)全文檢索。
二. 環(huán)境搭建
從lucene.apache.org上下載最新版本的lucene.jar,將此jar作為項目的build path,那么在項目中就可以直接使用lucene了。
三. 使用說明
3.1. 基本概念
這里介紹的主要為在使用中經(jīng)常碰到一些概念,以大家都比較熟悉的數(shù)據(jù)庫來進行類比的講解,使用Lucene進行全文檢索的過程有點類似數(shù)據(jù)庫的這個過程,table---à查詢相應的字段或查詢條件----à返回相應的記錄,首先是IndexWriter,通過它建立相應的索引表,相當于數(shù)據(jù)庫中的table,在構建此索引表時需指定的為該索引表采用何種方式進行構建,也就是說對于其中的記錄的字段以什么方式來進行格式的劃分,這個在Lucene中稱為Analyzer,Lucene提供了幾種環(huán)境下使用的Analyzer:SimpleAnalyzer、StandardAnalyzer、GermanAnalyzer等,其中StandardAnalyzer是經(jīng)常使用的,因為它提供了對于中文的支持,在表建好后我們就需要往里面插入用于索引的記錄,在Lucene中這個稱為Document,有點類似數(shù)據(jù)庫中table的一行記錄,記錄中的字段的添加方法,在Lucene中稱為Field,這個和數(shù)據(jù)庫中基本一樣,對于Field Lucene分為可被索引的,可切分的,不可被切分的,不可被索引的幾種組合類型,通過這幾個元素基本上就可以建立起索引了。在查詢時經(jīng)常碰到的為另外幾個概念,首先是Query,Lucene提供了幾種經(jīng)常可以用到的Query:TermQuery、MultiTermQuery、BooleanQuery、WildcardQuery、PhraseQuery、PrefixQuery、PhrasePrefixQuery、FuzzyQuery、RangeQuery、SpanQuery,Query其實也就是指對于需要查詢的字段采用什么樣的方式進行查詢,如模糊查詢、語義查詢、短語查詢、范圍查詢、組合查詢等,還有就是QueryParser,QueryParser可用于創(chuàng)建不同的Query,還有一個MultiFieldQueryParser支持對于多個字段進行同一關鍵字的查詢,IndexSearcher概念指的為需要對何目錄下的索引文件進行何種方式的分析的查詢,有點象對數(shù)據(jù)庫的哪種索引表進行查詢并按一定方式進行記錄中字段的分解查詢的概念,通過IndexSearcher以及Query即可查詢出需要的結果,Lucene返回的為Hits.通過遍歷Hits可獲取返回的結果的Document,通過Document則可獲取Field中的相關信息了。
比較一下Lucene和數(shù)據(jù)庫:
Lucene |
數(shù)據(jù)庫 |
索引數(shù)據(jù)源:doc(field1,field2...) doc(field1,field2...) \ indexer / _____________ | Lucene Index| -------------- / searcher \ 結果輸出:Hits(doc(field1,field2) doc(field1...))
|
索引數(shù)據(jù)源:record(field1,field2...) record(field1..) \ SQL: insert/ _____________ | DB Index | ------------- / SQL: select \ 結果輸出:results(record(field1,field2..) record(field1...))
|
Document:一個需要進行索引的“單元” 一個Document由多個字段組成 |
Record:記錄,包含多個字段 |
Field:字段 |
Field:字段 |
Hits:查詢結果集,由匹配的Document組成 |
RecordSet:查詢結果集,由多個Record組成 |
通過對于上面在建立索引和全文檢索的基本概念的介紹希望能讓你對Lucene建立一定的了解。
需要熟悉幾個接口:
分析器Analyzer
分析器主要工作是篩選,一段文檔進來以后,經(jīng)過它,出去的時候只剩下那些有用的部分,其他則剔除。而這個分析器也可以自己根據(jù)需要而編寫。
org.apache.lucene.analysis.Analyzer:這是一個虛構類,以下兩個借口均繼承它而來。
org.apache.lucene.analysis.SimpleAnalyzer:分析器,支持最簡單拉丁語言。
org.apache.lucene.analysis.standard.StandardAnalyzer:標準分析器,除了拉丁語言還支持亞洲語言,并在一些匹配功能上進行完善。在這個接口中還有一個很重要的構造函數(shù):StandardAnalyzer(String[] stopWords),可以對分析器定義一些使用詞語,這不僅可以免除檢索一些無用信息,而且還可以在檢索中定義禁止的政治性、非法性的檢索關鍵詞。
IndexWriter
IndexWriter的構造函數(shù)有三種接口,針對目錄Directory、文件File、文件路徑String三種情況。
例如IndexWriter(String path, Analyzer a, boolean create),path為文件路徑,a為分析器,create標志是否重建索引(true:建立或者覆蓋已存在的索引,false:擴展已存在的索引。)
一些重要的方法:
接口名 | 備注 |
addDocument(Document doc) | 索引添加一個文檔 |
addIndexes(Directory[] dirs) | 將目錄中已存在索引添加到這個索引 |
addIndexes(IndexReader[] readers) | 將提供的索引添加到這個索引 |
optimize() | 合并索引并優(yōu)化 |
close() | 關閉 |
IndexWriter為了減少大量的io維護操作,在每得到一定量的索引后建立新的小索引文件(筆者測試索引批量的最小單位為10),然后再定期將它們整合到一個索引文件中,因此在索引結束時必須進行wirter.optimize(),以便將所有索引合并優(yōu)化。
org.apache.lucene.document
以下介紹兩種主要的類:
a)org.apache.lucene.document.Document:
Document文檔類似數(shù)據(jù)庫中的一條記錄,可以由好幾個字段(Field)組成,并且字段可以套用不同的類型(詳細見b)。Document的幾種接口: 接口名 | 備注 |
add(Field field) | 添加一個字段(Field)到Document中 |
String get(String name) | 從文檔中獲得一個字段對應的文本 |
Field getField(String name) | 由字段名獲得字段值 |
Field[] getFields(String name) | 由字段名獲得字段值的集 |
b)org.apache.lucene.document.Field
即上文所說的“字段”,它是Document的片段section。
Field的構造函數(shù):
Field(String name, String string, boolean store, boolean index, boolean token)。
Indexed:如果字段是Indexed的,表示這個字段是可檢索的。
Stored:如果字段是Stored的,表示這個字段的值可以從檢索結果中得到。
Tokenized:如果一個字段是Tokenized的,表示它是有經(jīng)過Analyzer轉變后成為一個tokens序列,在這個轉變過程tokenization中,Analyzer提取出需要進行索引的文本,而剔除一些冗余的詞句(例如:a,the,they等,詳見org.apache.lucene.analysis.StopAnalyzer.ENGLISH_STOP_WORDS和org.apache.lucene.analysis.standard.StandardAnalyzer(String[] stopWords)的API)。Token是索引時候的基本單元,代表一個被索引的詞,例如一個英文單詞,或者一個漢字。因此,所有包含中文的文本都必須是Tokenized的。
Field的幾種接口:Name | Stored | Indexed | Tokenized | use |
Keyword(String name, String value) | Y | Y | N | date,url |
Text(String name, Reader value) | N | Y | Y | short text fields: title,subject |
Text(String name, String value) | Y | Y | Y | longer text fields, like “body” |
UnIndexed(String name, String value) | Y | N | N | |
UnStored(String name, String value) | N | Y | Y | |
Hits與Searcher
Hits的主要使用接口:接口名 | 備注 |
Doc(int n) | 返回第n個的文檔的所有字段 |
length() | 返回這個集中的可用個數(shù) |
3.2. 全文檢索需求的實現(xiàn)
索引建立部分的代碼:
private void createIndex(String indexFilePath) throws Exception{
IndexWriter iwriter=getWriter(indexFilePath);
Document doc=new Document();
doc.add(Field.Keyword("name","jerry"));
doc.add(Field.Text("sender","bluedavy@gmail.com"));
doc.add(Field.Text("receiver","google@gmail.com"));
doc.add(Field.Text("title","用于索引的標題"));
doc.add(Field.UnIndexed("content","不建立索引的內容"));
Document doc2=new Document();
doc2.add(Field.Keyword("name","jerry.lin"));
doc2.add(Field.Text("sender","bluedavy@hotmail.com"));
doc2.add(Field.Text("receiver","msn@hotmail.com"));
doc2.add(Field.Text("title","用于索引的第二個標題"));
doc2.add(Field.Text("content","建立索引的內容"));
iwriter.addDocument(doc);
iwriter.addDocument(doc2);
iwriter.optimize();
iwriter.close();
}
private IndexWriter getWriter(String indexFilePath) throws Exception{
boolean append=true;
File file=new File(indexFilePath+File.separator+"segments");
if(file.exists())
append=false;
return new IndexWriter(indexFilePath,analyzer,append);
}
3.2.1. 對于某字段的關鍵字的模糊查詢
Query query=new WildcardQuery(new Term("sender","*davy*"));
Searcher searcher=new IndexSearcher(indexFilePath);
Hits hits=searcher.search(query);
for (int i = 0; i < hits.length(); i++) {
System.out.println(hits.doc(i).get("name"));
}
3.2.2. 對于某字段的關鍵字的語義查詢
Query query=QueryParser.parse("索引","title",analyzer);
Searcher searcher=new IndexSearcher(indexFilePath);
Hits hits=searcher.search(query);
for (int i = 0; i < hits.length(); i++) {
System.out.println(hits.doc(i).get("name"));
}
3.2.3. 對于多字段的關鍵字的查詢
Query query=MultiFieldQueryParser.parse("索引",new String[]{"title","content"},analyzer);
Searcher searcher=new IndexSearcher(indexFilePath);
Hits hits=searcher.search(query);
for (int i = 0; i < hits.length(); i++) {
System.out.println(hits.doc(i).get("name"));
}
3.2.4. 復合查詢(多種查詢條件的綜合查詢)
Query query=MultiFieldQueryParser.parse("索引",new String[]{"title","content"},analyzer);
Query mquery=new WildcardQuery(new Term("sender","bluedavy*"));
TermQuery tquery=new TermQuery(new Term("name","jerry"));
BooleanQuery bquery=new BooleanQuery();
bquery.add(query,true,false);
bquery.add(mquery,true,false);
bquery.add(tquery,true,false);
Searcher searcher=new IndexSearcher(indexFilePath);
Hits hits=searcher.search(bquery);
for (int i = 0; i < hits.length(); i++) {
System.out.println(hits.doc(i).get("name"));
}
四. 總結
相信大家通過上面的說明能知道Lucene的一個基本的使用方法,在全文檢索時建議大家先采用語義時的搜索,先搜索出有意義的內容,之后再進行模糊之類的搜索,^_^,這個還是需要根據(jù)搜索的需求才能定了,Lucene還提供了很多其他更好用的方法,這個就等待大家在使用的過程中自己去進一步的摸索了,比如對于Lucene本身提供的Query的更熟練的掌握,對于Filter、Sorter的使用,自己擴展實現(xiàn)Analyzer,自己實現(xiàn)Query等等,甚至可以去了解一些關于搜索引擎的技術(切詞、索引排序 etc)等等
posted on 2007-01-28 10:38
周銳 閱讀(500)
評論(0) 編輯 收藏 所屬分類:
Lucene