lucene入門整理

作者:梁章坪 1 / 21 4/16/2009 4:18:00 PM
1. 概述
Lucene 是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎。Lucene 以其方便
使用、快速實施以及靈活性受到廣泛的關注。它可以方便地嵌入到各種應用中實現針對應用
的全文索引、檢索功能,本總結使用lucene--2.3.2。
2. lucene 的包結構
1、org.apache.lucene.analysis 對需要建立索引的文本進行分詞、過濾等操作, 語言分析器,
主要用於的切詞Analyzer 是一個抽象類,管理對文本內容的切分詞規則。
2、org.apache.lucene.analysis.standard 是標準分析器
3、org.apache.lucene.document 提供對Document 和Field 的各種操作的支持。索引存儲時的
文檔結構管理,類似於關係型數據庫的表結構。Document 相對於關係型數據庫的記錄對象,
Field 主要負責字段的管理。
4、org.apache.lucene.index 是最重要的包,用於向Lucene 提供建立索引時各種操作的支持。
索引管理,包括索引建立、刪除等。索引包是整個系統核心,全文檢索的根本就是爲每個切
出來的詞建索引,查詢時就只需要遍歷索引,而不需要去正文中遍歷,從而極大的提高檢索
效率。
5、org.apache.lucene.queryParser 提供檢索時的分析支持。查詢分析器,實現查詢關鍵詞間的
運算,如與、或、非等。
6、org.apache.lucene.search 負責檢索。檢索管理,根據查詢條件,檢索得到結果。
7、org.apache.lucene.store 提供對索引存儲的支持。數據存儲管理,主要包括一些底層的I/0
操作。
8、org.apache.lucene.util 提供一些常用工具類和常量類的支持
3. 索引文件格式
a) .fnm 格式 包含了Document 中所有field 名稱
b) .fdt 與.fdx 格式 .fdt 文件用於存儲具有Store.YES 屬性的Field 的數據;.fdx 是一個索
引,用於存儲Document 在.fdt 中的位置。
c) .tis 與.tii 格式 .tis 文件用於存儲分詞後的詞條(Term),而.tii 就是它的索引文件,它
表明了每個.tis 文件中的詞條的位置。
d) deletable 格式 文檔被刪除後,會首先在deletable 文件中留下一個記錄,要真正刪除時,
纔將索引除去。
e) 複合索引格式 .cfs
使用IndexWriter 的useCompoundFile() 默認爲True
作者:梁章坪 2 / 21 4/16/2009 4:18:00 PM
4. lucene 中主要的類
4.1. Document 文檔類
4.1.1. 常用方法
方法 描述
void add(Field field) 往Document 對象中添加字段
void removeField(String name) 刪除字段。若多個字段以同一個字段名存在,則刪除首
先添加的字段;若不存在,則Document 保持不變
void removeFields(String name) 刪除所有字段。若字段不存在,則Document 保持不變
Field getField(String name) 若多個字段以同一個字段名存在,則返回首先添加的字
段;若字段不存在,則Document 保持不變
Enumeration fields() 返回Document 對象的所有字段,以枚舉類型返回
Field [] getFields(String name) 根據名稱得到一個Field 的數組
String [] getValues(String name) 根據名稱得到一個Field 的值的數組
4.1.2. 示例
Document doc1 = new Document();
doc1.add(new Field("name", "word1 word2 word3",
Field.Store.NO,Field.Index.TOKENIZED));
Document doc2 = new Document();
doc2.add(new Field("name", "word1 word2 word3",
Field.Store.NO,Field.Index.TOKENIZED));
4.2. Field 字段類
4.2.1. 構造方法
1) public Field(String name,String value,Store store,Index index);//直接的字符串方式
2) public Field(String name,String value,Store store,Index index,TermVector termVector);
3) public Field(String name,String value,Reader reader);//使用Reader 從外部傳入
4) public Field(String name,String value,Reader reader,TermVector termVector);
5) public Field(String name,byte[] value,Store store)//使用直接的二進制byte 傳入
當Field 值爲二進制時,可以使用Lucene 的壓縮功能將其值進行壓縮。
作者:梁章坪 3 / 21 4/16/2009 4:18:00 PM
4.2.2. Store 類
靜態屬性 描述
Store.NO 表示該Field 不需要存儲
Store.YES 表示該Field 需要存儲
Store.COMPRESS 表示用壓縮方式來保存這個Field 的值
4.2.3. Index 類
靜態屬性 描述
Index.NO 不需要索引
Index.TOKENIZED 先被分詞再被索引
Index.UN_TOKENIZED 不對該Field 進行分詞,但會對它進行索引
Index.NO_NORMS 對該Field 進行索引,但是不使用Analyzer,同時禁止
它參加評分,主要是爲了減少內存的消耗。
4.2.4. 示例
new Field("name", "word1 word2 word3",Field.Store.YES,Field.Index.TOKENIZED)
4.3. IndexWriter 類
4.3.1. 構造方法
1) public IndexWriter(String path,Analyzer a,Boolean create)
2) public IndexWriter(File path,Analyzer a,Boolean create)
3) public IndexWriter(Directory d,Analyzer a,Boolean create)
第一個參數:索引存放在什麼地方
第二個參數:分析器,繼承自org.apache.lucene.analysis.Analyzer 類
第三個參數:爲true 時,IndexWriter 不管目錄內是否已經有索引了,一律清空,重新建立;
當爲false 時,則IndexWriter 會在原有基礎上增量添加索引。所以在更新的過程中,需要設
置該值爲false。
4.3.2. 添加文檔
public void addDocument(Document doc)
public void addDocument(Document doc,Analyzer analyzer)//使用一個開發者自定義的,而非事
先在構建IndexWriter 時聲明的Analyzer 來進行分析
作者:梁章坪 4 / 21 4/16/2009 4:18:00 PM
writer.addDocument(doc1);
4.3.3. 性能參數
1) mergeFactor 控制Lucene 在把索引從內存寫入磁盤上的文件系統時內存中最大的
Document 數量,同時它還控制內存中最大的Segment 數量。默認爲10.
writer.setMergeFactor(10);
2) maxMergeDocs 限制一個Segment 中最大的文檔數量。一個較大的maxMergeDocs 適用
於對大批量的文檔建立索引,增量式的索引則應使用較小的maxMergeDocs。
writer.setMaxMergeDocs(1000);
3) minMergeDocs 用於控制內存中持有的文檔數量的,它對磁盤上的Segment 大小沒有任
何影響。
4.3.4. 限制Field 的長度
maxFieldLength 限制Field 的長度,默認值爲10000.最大值100000 個。
public void setMaxFieldLength(int maxFieldLength)
writer.addDocument(doc1);
writer.setMaxFieldLength(100000);
writer.addDocument(doc2);
4.3.5. 複合索引格式
setUseCompoundFile(Boolean) 默認true
writer.setUseCompoundFile(true);//複合索引
writer.setUseCompoundFile(false);
4.3.6. 優化索引
writer.optimize();
將磁盤上的多個segment 進行合併,組成一個全新的segment。這種方法並不會增加建索時
的速度,反而會降低建索的速度。所以應該在建完索引後在調用這個函數
4.3.7. 示例
IndexWriter writer = new IndexWriter(path, new StandardAnalyzer(), true);
writer.addDocument(doc1);
writer.addDocument(doc2);
Sytem.out.println(writer.docCount());
writer.close();
IndexSearcher searcher = new IndexSearcher(path);
作者:梁章坪 5 / 21 4/16/2009 4:18:00 PM
Hits hits = null;
Query query = null;
QueryParser parser =new QueryParser("name", new StandardAnalyzer());
query =parser.parse("word1");
hits = searcher.search(query);
System.out.println("查找 word1 共" + hits.length() + "個結果");
4.4. Directory 類
Directory:用於索引的存放位置
a) FSDirectory.getDirectory(path, true)第二個參數表示刪除掉目錄內原有內容
IndexWriter writer = new IndexWriter(FSDirectory.getDirectory(path, true), new
StandardAnalyzer(), true);//刪除原有索引

FSDirectory fsDir=FSDirectory.getDirectory(path,true);
IndexWriter writer = new IndexWriter(fsDir, new StandardAnalyzer(), true);
b) RAMDirectory 在內存中存放,讀取速度快,但程序一運行結束,它的內容就不存在了
RAMDirectory ramDir=new RAMDirectory();
IndexWriter writer = new IndexWriter(ramDir, new StandardAnalyzer(), true);

IndexWriter writer = new IndexWriter(new RAMDirectory(), new StandardAnalyzer(), true);
4.5. IndexReader 類
IndexReader 類――索引的讀取工具
4.5.1. 刪除文檔
IndexReader reader=IndexReader.open(path);
reader.deleteDocument(0);//刪除第一個
reader.close();
4.5.2. 反刪除
reader.undeleteAll();
4.5.3. 按字段刪除
reader.deleteDocuments(new Term("name","word1"));
作者:梁章坪 6 / 21 4/16/2009 4:18:00 PM
若要真正物理刪除,則只需使用IndexWriter 對索引optimize 一次即可!
4.5.4. 示例
IndexReader reader=IndexReader.open(path);
for(int i=0;i<reader.numDocs();i++){
System.out.println(reader.document(i));
}
System.out.println("版本:"+reader.getVersion());
System.out.println("索引內的文檔數量:"+reader.numDocs());
//reader.deleteDocuments(new Term("name","word1"));
Term term1=new Term("name","word1");
TermDocs docs=reader.termDocs(term1);
while(docs.next())
{
System.out.println("含有所查找的"+term1+"的Document的編號
爲"+docs.doc());
System.out.println("Term在文檔中的出現次數"+docs.freq());
}
reader.close();
4.6. IndexModifier 類
集成了IndexWriter 的大部分功能和IndexReader 中對索引刪除的功能 ------ Lucene2.0 的新

4.6.1. 示例
public static void main(String[] args) throws Exception {
IndexModifier modifier=new IndexModifier("C:\\Q1",new
StandardAnalyzer(),true);
Document doc1=new Document();
doc1.add(new Field("bookname","鋼鐵是怎樣煉成的
",Field.Store.YES,Field.Index.TOKENIZED));
Document doc2=new Document();
doc2.add(new Field("bookname","山山水水
",Field.Store.YES,Field.Index.TOKENIZED));
modifier.addDocument(doc1);
modifier.addDocument(doc2);
作者:梁章坪 7 / 21 4/16/2009 4:18:00 PM
System.out.println(modifier.docCount());
modifier.setUseCompoundFile(false);
modifier.close();
IndexModifier mo=new IndexModifier("C:\\Q1",new
StandardAnalyzer(),false);
mo.deleteDocument(0);
System.out.println(mo.docCount());
mo.close();
}
4.7. IndexSearcher 類
4.7.1. 構造方法
IndexSearcher searcher = new IndexSearcher(String path);
IndexSearcher searcher = new IndexSearcher(Directory directory);
IndexSearcher searcher = new IndexSearcher(IndexReader r);
IndexSearcher searcher = new IndexSearcher(IndexReader r,Boolean closeReader);
IndexSearcher searcher = new IndexSearcher(path);
IndexSearcher searcher = new IndexSearcher(FSDirectory.getDirectory(path,false) );
4.7.2. search 方法
//返回Hits 對象
public Hits search(Query query)
public Hits search(Query query,Filter filter)
public Hits search(Query query,Sort sort)
public Hits search(Query query,Filter filter,Sort sort)
//檢索只返回得分最高的Document
public TopDocs search(Query query,Filter filter,int n)
public TopDocs search(Weight weight,Filter filter,int n)
public TopFieldDocs search(Weight weight,Filter filter,int n,Sort sort)
public TopFieldDocs search(Query query,Filter filter,int n,Sort sort)
//傳入HitCollector,將結果保存在HitCollector 中
public void search(Query query,HitCollector results)
public void search(Query query,Filter filter,HitCollector results)
public void search(Weight weight,Filter filter,HitCollector results)
作者:梁章坪 8 / 21 4/16/2009 4:18:00 PM
4.7.3. Searcher 的explain 方法
public Explaination explain(Query query,int doc)throws IOException
for(int i=0;i<hits.length()&&i<10;i++)
{
Document d=hits.doc(i);
System.out.println(i+" "+hits.score(i)+" "+d.get("contents"));
System.out.println(searcher.explain(query,hits.id(i)).toString())
;
}
4.7.4. 示例
IndexSearcher searcher = new IndexSearcher(path);
Hits hits = null;
Query query = null;
QueryParser parser =new QueryParser("contents", new StandardAnalyzer());
query =parser.parse("11");
hits = searcher.search(query);
System.out.println("查找 word1 共" + hits.length() + "個結果");
for(int i=0;i<hits.length()&&i<10;i++)
{
Document d=hits.doc(i);
System.out.println(d+" "+i+" "+hits.score(i)+"
"+d.get("contents"));
}
searcher.close();
4.8. Hits 類
4.8.1. 概述
Hits 類――檢索結果
4.8.2. 常用方法
作者:梁章坪 9 / 21 4/16/2009 4:18:00 PM
方法名 描述
int length() 返回搜索到結果的總數量
Document doc(int i) 返回第i 個文檔
int id(int i) 返回第i 個文檔的內部ID 號
float score(int i) 返回第i 個文檔的得分
Iterator iterator() 取得Hits 集合的遍歷對象
4.8.3. 示例
for(int i=0;i<hits.length()&&i<10;i++)
{
Document d=hits.doc(i);
System.out.println(d+" "+" "+hits.score(i)+" "+d.get("contents"));
System.out.println("文檔的內部ID號:" + hits.id(i));
}
4.9. QueryParser 類
4.9.1. 改變默認的布爾邏輯
Ø 默認爲“或”關係
Query query = null;
QueryParser parser =new QueryParser("contents", new StandardAnalyzer());
query =parser.parse("hello world!");
System.out.println(query.toString());
Ø 改變默認布爾邏輯
Query query = null;
QueryParser parser =new QueryParser("contents", new StandardAnalyzer());
parser.setDefaultOperator(QueryParser.AND_OPERATOR);
query =parser.parse("hello world");//若world後加!會出錯
System.out.println(query.toString());
Ø AND OR NOT – 關鍵字
也可以不用改變默認布爾邏輯,而直接讓用戶在輸入關鍵字時指定不同詞條間的布爾聯繫。
例如,用戶輸入 hello AND world 必須爲大寫
邏輯與:AND (大寫)
邏輯或:OR (大寫)
邏輯非:- 例如: hello - world
也可以是NOT 例如: hello NOT world
作者:梁章坪 10 / 21 4/16/2009 4:18:00 PM
4.9.2. 不需要分詞
不進行分詞,將其完整的作爲一個詞條進行處理,則需要在詞組的外面加上引號
String queryStr="\"God helps those who help themselves\"";
QueryParser parser = new QueryParser("bookname",new StandardAnalyzer());
parser.setDefaultOperator(QueryParser.AND_OPERATOR);
Query query=parser.parse(queryStr);
System.out.println(query.toString());
4.9.3. 設置坡度值,支持FuzzyQuery
String queryStr="\"God helps those who help themselves\"~1";//設置坡度
爲1
QueryParser parser = new QueryParser("bookname",new StandardAnalyzer());
Query query=parser.parse(queryStr);
System.out.println(query.toString());
4.9.4. 設置通配符,支持WildcardQuery
String queryStr="wor?"
QueryParser parser = new QueryParser("bookname",new StandardAnalyzer());
parser.setDefaultOperator(QueryParser.AND_OPERATOR);
Query query=parser.parse(queryStr);
System.out.println(query.toString());
4.9.5. 查找指定的Field
String queryStr="linux publishdate:2006-09-01";
QueryParser parser = new QueryParser("bookname",new StandardAnalyzer());
parser.setDefaultOperator(QueryParser.AND_OPERATOR);
Query query=parser.parse(queryStr);
System.out.println(query.toString());
例如:要求用戶選擇某一方面的
作者:梁章坪 11 / 21 4/16/2009 4:18:00 PM
4.9.6. 範圍的查找,支持RangeQuery
String queryStr="[1990-01-01 TO 1998-12-31]";
QueryParser parser=new QueryParser("publishdate",
new StandardAnalyzer());
Query query=parser.parse(queryStr);
System.out.println(query.toString());
輸出結果爲publishdate:[081xmghs0 TO 0boeetj3z]
因爲建立索引時,如果按照日期表示的字符串來進行索引,實際上比較的是字符串的字典順
序。而首先將日期轉爲以毫秒計算的時間後,則可以精確地比較兩個日期的大小了。於是,
lucene 提供DateTools 工具,用來完成其內部對時間的轉化和處理,將毫秒級的時間轉化爲
一個長字符串來進行表示,並進行索引。所以,遇到日期型數據時,最好用DateTools 進行
轉換,再進行索引!
4.9.7. 現在還不支持SpanQuery
4.10. MultiFieldQueryParser 類--多域搜索
//在不同的Field 上進行不同的查找
public static Query parse(String []queries,String[] fields,Analyzer analyzer)throws ParseException
//在不同的Field 上進行同一個查找,指定它們之間的布爾關係
public static Query parse(String query,String[] fields,BooleanClause.Occur[] flags,Analyzer
analyzer) throws ParseException
//在不同的Field 上進行不同的查找,指定它們之間的布爾關係
public static Query parse(String []queries,String [] fields,BooleanClause.Occur[] flags,Analyzer
analyzer)throws ParseException
String [] queries={"鋼", "[10 TO 20]"};
String[] fields={“bookname”,”price”};
BooleanClause.Occur[]
clauses={BooleanClause.Occur.MUST,BooleanClause.Occur.MUST};
Query query=MultiFieldQueryParser.parse(queries,fields,clauses,new
StandardAnalyzer());
System.out.println(query.toString());
4.11. MultiSearcher 類--多個索引搜索
IndexSearcher searcher1=new IndexSearcher(path1);
作者:梁章坪 12 / 21 4/16/2009 4:18:00 PM
IndexSearcher searcher2=new IndexSearcher(path2);
IndexSeacher [] searchers={searcher1,seacher2};
MultiSearcher searcher=new MultiSearcher(searchers);
Hits hits=searcher.search(query);
for(int i=0;i<hits.length();i++){
System.out.println(hits.doc(i));
}
4.12. ParalellMultiSearcher 類---多線程搜索
IndexSearcher searcher1=new IndexSearcher(path1);
IndexSearcher searcher2=new IndexSearcher(path2);
IndexSearcher [] searchers={searcher1,searcher2};
ParallelMultiSearcher searcher=new ParallelMultiSearcher(searchers);
long start=System.currentTimeMillis();
Hits hits=searcher.search(query);
long end=System.currentTimeMillis();
System.out.println((end-start)+"ms");
5. 排序
5.1. Sort 類
public Sort()
public Sort(String field)
public Sort(String field,Boolean reverse) //默認爲false,降序排序
public Sort(String[] fields)
public Sort(SortField field)
public Sort(SortField[] fields)
Sort sort=new Sort(“bookname”);按照“bookname“這個Field值進行降序排序
Sort sort=new Sort(“bookname”,true) //升序排序
Sort sort=new Sort(new String[]{“bookNumber”,”bookname”,”publishdate”});
按照三個Field進行排序,但無法指定升序排序,所以用SortField
5.2. SortField 類
public SortField(String field)
public SortField(String field,Boolean reverse)
public SortField(String field,int type) //type表示當前Field值的類型
public SortField(String field,int type,boolean reverse) //默認爲false,
升序
作者:梁章坪 13 / 21 4/16/2009 4:18:00 PM
Field值的類型:SortField.STRING、SortField.INT、SortField.FLOAT
SortField sf1=new SortField(“bookNumber”,SortField.INT,false);
SortField sf2=new SortField(“bookname”,SortField.STRING,false);
5.3. 指定排序的法則
5.3.1. 按照文檔的得分降序排序
Hits hits=searcher.search(query,Sort.RELEVANCE);
5.3.2. 按文檔的內部ID 升序排序
Hits hits=searcher.search(query, Sort.INDEXORDER);
5.3.3. 按照一個Field 來排序
Sort sort=new Sort();
SortField sf=new SortField(“bookNumber”,SortField.INT,false);
sort.setSort(sf);
Hits hits=searcher.search(query,sort);
5.3.4. 按照多個Field 來排序
Sort sort=new Sort();
SortField sf1=new SortField(“bookNumber”,SortField.INT,false);//升序
SortField sf2=new SortField(“publishdate”,SortField.STRING,true);//
降序
sort.setSort(new SortField[]{sf1,sf2});
Hits hits=searcher.search(query,sort);
5.3.5. 改變SortField 中的Locale 信息
String str1=”我”; String str2=”你”;
Collator co1=Collator.getInstance(Locale.CHINA);
Collator co2=Collator.getInstance(Locale.JAPAN);
System.out.println(Locale.CHINA+”:”+co1.compare(str1,str2));
System.out.println(Locale.JAPAN+”:”+co2.compare(str1,str2));
輸出結果爲:
zh_CN:1
ja_JP:-1
作者:梁章坪 14 / 21 4/16/2009 4:18:00 PM
所以
public SortField(String field,Locale locale)
public SortField(String field,Locale locale,boolean reverse)
6. 過濾器
使用public Hits search(Query query,Filter filter)
(1)簡單過濾
Hits hits=searcher.search(query,new AdvancedSecurityFilter());//過濾掉
securitylevel爲0的結果
(2)範圍過濾—RangeFilter
只顯示中間的
RangeFilter filter=new
RangeFilter(“publishdate”,”1970-01-01”,”1998-12-31”,true,true”);
Hits hits=searcher.search(query,filter);
無上邊界
public static RangeFilter More(String fieldname,String lowerTerm)
無下邊界
public static RangeFilter Less(String fieldname,String upperTerm)
(3)在結果中查詢QueryFilter
RangeQuery q=new RangeQuery(new Term(“publicshdate”,”1970-01-01”),
new Term(“publishdate”,”1999-01-01”),true);
QueryFilter filter=new QueryFilter(q);
Hits hits=searcher.search(query,filter);
7. 分析器Analysis
7.1. 自帶分析器和過濾器
Ø 標準過濾器:StandardAnalyzer
Ø 大小寫轉換器:LowerCaseFilter
Ø 忽略詞過濾器:StopFilter
public StopFilter(TokenStream input,String [] stopWords)
public StopFilter(TokenStream in,String [] stopWords,boolean ignoreCase)
public StopFilter(TokenStream input,Set stopWords,boolean ignoreCase)
public StopFilter(TokenStream in, Set stopWords)
其中,參數TokenStream 代表當前正在進行處理的流;String 類型的數組代表一個用數組表
示的忽略詞集合;Set 類型的參數與String 一樣,是用來表示忽略詞集合的;boolean 表示當
作者:梁章坪 15 / 21 4/16/2009 4:18:00 PM
與忽略詞集合中的詞進行匹配時,是否需要忽略大小寫。
Ø 長度過濾器:LengthFilter
Ø PerFieldAnalyzerWrapper
Ø WhitespaceAnalyzer
String str="str1 str2 str3";
StringReader reader=new StringReader(str);
Analyzer anlyzer=new WhitespaceAnalyzer();
TokenStream ts=anlyzer.tokenStream("", reader);
Token t=null;
while( (t=ts.next())!=null ){
System.out.println(t.termText());
}
7.2. 第三方過分析器
Ø 單字分詞
Ø 二分法:CJKAnalyzer、中科院ICTCLAS 分詞、JE 分詞
Ø 詞典分詞
7.2.1. JE 分詞用法
7.2.1.1. 示例
import jeasy.analysis.MMAnalyzer;
IndexWriter writer = new IndexWriter(INDEX_STORE_PATH, new MMAnalyzer()
, true);
String str=" Lucene是一個全文檢索引擎的架構,"+
"提供了完整的查詢引擎和索引引擎。Lucene以其方便使用、快" +
"速實施以及靈活性受到廣泛的關注。它可以方便地嵌入到各種應用" +
"中實現針對應用的全文索引、檢索功能,本總結使用lucene--2.3.2。";
MMAnalyzer analyzer=new MMAnalyzer();
try{
System.out.println(analyzer.segment(str, "|"));
}
catch(Exception e)
{
e.printStackTrace();
}
輸出結果:lucene|一個|全文|檢索|引擎|架構|提供|完整|查詢|。。。。
作者:梁章坪 16 / 21 4/16/2009 4:18:00 PM
7.2.1.2. 設定正向最大匹配的字數
MMAnalyzer analyzer=new MMAnalyzer(4);
7.2.1.3. 添加新詞
MMAnalyzer.addWord(String word);
MMAnalyzer.addDictionary(Reader reader);
MMAnalyzer analyzer=new MMAnalyzer();
MMAnalyzer.addWord("邁克爾雷第");
8. 索引的合併
RAMDirectory RAMDir=new RAMDirectory();
IndexWriter writer = new IndexWriter(RAMDir, new StandardAnalyzer(),
true);//刪除原有索引
IndexWriter writer2=new
IndexWriter(FSDirectory.getDirectory(path,true),
new StandardAnalyzer(), true);
writer.addDocument(doc1);
writer2.addDocument(doc2);
writer.close();
writer2.addIndexes(new Directory[]{RAMDir});
writer2.close();
注意:在合併前一定要先關閉要加的索引器。
9. 各種Query
9.1. 概述
query.toString()查看原子查詢
9.2. 使用特定的分析器搜索
IndexSearcher searcher = new IndexSearcher(path );
Hits hits = null;
作者:梁章坪 17 / 21 4/16/2009 4:18:00 PM
Query query = null;
QueryParser parser =new QueryParser("contents", new StandardAnalyzer());
query =parser.parse("11 a and hello");
hits=searcher.search(query); //查找 name:11 name:hello 共1個結果
System.out.println("查找 "+query.toString()+" 共" + hits.length() + "個
結果");
9.3. 按詞條搜索—TermQuery
Query query = null;
query=new TermQuery(new Term("name","word1 a and"));
hits=searcher.search(query);// 查找 name:word1 a and 共0個結果
System.out.println("查找 "+query.toString()+" 共" + hits.length() + "個
結果");
9.4. 按“與或”搜索—BooleanQuery
1.和: MUST 與MUST_NOT
2.或: SHOULD 與SHOULD
3.A 與B 的並集-B MUST 與MUST_NOT
Query query1=null;
Query query2=null;
BooleanQuery query=null;
query1=new TermQuery(new Term("name","word1"));
query2=new TermQuery(new Term("name","word2"));
query=new BooleanQuery();
query.add(query1,BooleanClause.Occur.MUST);
query.add(query2,BooleanClause.Occur.MUST_NOT);
9.5. 在某一範圍內搜索—RangeQuery
Term beginTime=new Term("time","200001");
Term endTime=new Term("time","200005");
RangeQuery query=null;
query=new RangeQuery(beginTime,endTime,false);//不包含邊界值
9.6. 使用前綴搜索—PrefixQuery
Term pre1=new Term("name","wor");
PrefixQuery query=null;
query = new PrefixQuery(pre1);
作者:梁章坪 18 / 21 4/16/2009 4:18:00 PM
9.7. 短語搜索—PhraseQuery
a)默認坡度爲0
PhraseQuery query = new PhraseQuery();
query.add(new Term(“bookname”,”鋼”));
query.add(new Term(“bookname”,”鐵”));
Hits hits=searcher.search(query); //搜索“鋼鐵”短語,而非“鋼”和“鐵”
b)設置坡度,默認爲0
PhraseQuery query = new PhraseQuery();
query.add(new Term(“bookname”,”鋼”));
query.add(new Term(“bookname”,”鐵”));
query.setSlop(1);
Hits hits=searcher.search(query);//搜索“鋼鐵”或“鋼*鐵”中含一字
9.8. 多短語搜索—MultiPhraseQuery
a)
MultiPhraseQuery query=new MultiPhraseQuery();
//首先向其中加入要查找的短語的前綴
query.add(new Term(“bookname”,”鋼”));
//構建3個Term,作爲短語的後綴
Term t1=new Term(“bookname”,”鐵”);
Term t2=new Term(“bookname”,”和”);
Term t3=new Term(“bookname”,”要”);
//再向query中加入所有的後綴,與前綴一起,它們將組成3個短語
query.add(new Term[]{t1,t2,t3});
Hits hits=searcher.search(query);
for(int i=0;i<hits.length();i++)
System.out.println(hits.doc(i));
b)
MultiPhraseQuery query=new MultiPhraseQuery();
Term t1=new Term(“bookname”,”鋼”);
Term t2 = new Term(“bookname”,”和”);
query.add(new Term[]{t1,t2});
query.add(new Term(“bookname”,”鐵”));
c)
MultiPhraseQuery query=new MultiPhraseQuery();
Term t1=new Term(“bookname”,”鋼”);
Term t2 = new Term(“bookname”,”和”);
query.add(new Term[]{t1,t2});
query.add(new Term(“bookname”,”鐵”));
Term t3=new Term(“bookname”,”是”);
Term t4=new Term(“bookname”,”戰”);
作者:梁章坪 19 / 21 4/16/2009 4:18:00 PM
query.add(new Term[]{t3,t4});
9.9. 模糊搜索—FuzzyQuery
使用的算法爲levenshtein 算法,在比較兩個字符串時,將動作分爲3 種:
l 加一個字母
l 刪一個字母
l 改變一個字母
FuzzyQuery query=new FuzzyQuery(new Term(“content”,”work”));
public FuzzyQuery(Term term)
public FuzzyQuery(Term term,float minimumSimilarity)throws
IllegalArgumentException
public FuzzyQuery(Term term,float minimumSimilarity,int
prefixLength)throws IllegalArgumentException
其中minimumSimilarity 爲最小相似度,越小則文檔的數量越多。默認爲0.5.其值必須<1.0
FuzzyQuery query=new FuzzyQuery(new Term(“content”,”work”),0.1f);
其中prefixLength 表示要有多少個前綴字母必須完全匹配
FuzzyQuery query=new FuzzyQuery(new Term(“content”,”work”),0.1f,1);
9.10. 通配符搜索—WildcardQuery
* 表示0 到多個字符
? 表示一個單一的字符
WildcardQuery query=new WildcardQuery(new Term(“content”,”?qq*”));
9.11. 跨度搜索
9.11.1. SpanTermQuery
效果和TermQuery 相同
SpanTermQuery query=new SpanTermQuery(new Term(“content”,”abc”));
9.11.2. SpanFirstQuery
從Field 內容的起始位置開始,在一個固定的寬度內查找所指定的詞條
SpanFirstQuery query=new SpanFirstQuery(new Term(“content”,”abc”),3);//
是第3個word,不是byte
作者:梁章坪 20 / 21 4/16/2009 4:18:00 PM
9.11.3. SpanNearQuery
SpanNearQuery 相當與PhaseQuery
SpanTermQuery people=new SpanTermQuery(new Term(“content”,”mary”));
SpanTermQuery how=new SpanTermQuery(new Term(“content”,”poor”));
SpanNearQuery query=new SpanNearQuery(new
SpanQuery[]{people,how},3,false);
9.11.4. SpanOrQuery
把所有SpanQuery 的結果合起來
SpanTermQuery s1=new SpanTermQuery(new Term(“content”,”aa”);
SpanTermQuery s2=new SpanTermQuery(new Term(“content”,”cc”);
SpanTermQuery s3=new SpanTermQuery(new Term(“content”,”gg”);
SpanTermQuery s4=new SpanTermQuery(new Term(“content”,”kk”);
SpanNearQuery query1=new SpanNearQuery(new
SpanQuery[]{s1,s2},1,false);
SpanNearQuery query2=new SpanNearQuery(new
SpanQuery[]{s3,s4},3,false);
SpanOrQuery query=new SpanOrQuery(new SpanQuery[]{query1,query2});
9.11.5. SpanNotQuery
從第1 個SpanQuery 的查詢結果中,去掉第2 個SpanQuery 的查詢結果
SpanTermQuery s1=new SpanTermQuery(new Term(“content”,”aa”);
SpanFirstQuery query1=new SpanFirstQuery(s1,3);
SpanTermQuery s3=new SpanTermQuery(new Term(“content”,”gg”);
SpanTermQuery s4=new SpanTermQuery(new Term(“content”,”kk”);
SpanNearQuery query2=new SpanNearQuery(new
SpanQuery[]{s3,s4},4,false);
SpanNotQuery query=new SpanNotQuery(query1,query2);
9.12. RegexQuery—正則表達式的查詢
String regex="http://[a-z]{1,3}\\.abc\\.com/.*";
RegexQuery query=new RegexQuery(new Term("url",regex));
作者:梁章坪 21 / 21 4/16/2009 4:18:00 PM
10. 評分機制
10.1. 概述
通過searcher.explain(Query query, int doc)方法可以查看某個文檔的得分的具體構成。
在Lucene 中score 簡單說是由 tf * idf * boost * lengthNorm 計算得出的。
1) tf:Term Frequency.詞條頻率,是查詢的詞在文檔中出現的次數的平方根
2) idf:表示反轉文檔頻率,Math.log(numDocs/(double)(docFreq+1))+1.0 docDocs 表示當
前檢索的詞條的文檔總數, numDocs 表示索引中總共的文檔數量
3) boost:激勵因子,可以通過setBoost 方法設置,需要說明的通過field 和doc 都可以設
置,所設置的值會同時起作用 。默認爲1.boost 的值是在索引建立的時候已經寫入了,
而不像其他計算得分的因子是在查詢時實時得出的。因此,一旦boost 值被寫入,就不
能修改它,除非重新建立文檔索引。
4) lengthNorm:是由搜索的field 的長度決定了,越長文檔的分值越低。
11. Lucene 的索引“鎖”
1. write.lock
2. commit.lock
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章