本篇要介紹的是關於過濾方面的知識,也就是Filter,若是瞭解Solr的朋友,確定都會知道Solr裏面fq這個參數,這個參數的做用其實就是lucene裏面的過濾,對一些q參數查詢的結果集,作過濾或者限制返回一些咱們須要的內容,能夠理解成小搜索空間的一種策略。
java
在這裏先介紹一下查詢預過濾的區別和聯繫,其實查詢(各類Query)和過濾(各類Filter)之間很是類似,能夠這樣說,主要用Query能完成的事,用過濾也均可以完成,它們之間能夠相互轉換,最大的區別就是使用過濾返回的結果集不帶評分操做,而使用Query返回的結果都是帶相關性評分的,因此當咱們若是有一些跟評分操做沒有關係的業務,優先使用Filter操做,將會獲取更好的性能,其實這也是Solr裏面q參數和fq參數的區別。
數據庫
下面進入正題,在這以前,先來了解lucene裏面有關於Filter的總體知識。
apache
下面,咱們看下具體的在代碼裏怎麼實現,先看下咱們的測試數據編程
id score bookname ename type price date 1 1 飄渺之旅 pmzl 小說 52.23 201005 2 1 三國演義 sgyy 小說 36.13 201207 3 1 數據庫實戰 sjksz 技術 77.13 200811 4 1 編程寶典 bcbd 技術 100.3 200501 5 1 職場關係論 zcgxl 職場 36.59 200501 6 1 健康生活 jksh 生活 20.47 200008 7 1 看清本質 kqbz 社會 10.37 201004 8 1 編程,編程 bcbc 社會 10.37 201004
核心代碼緩存
//使用過濾器 最後一個爲true時包含邊界部分,爲false時不包含邊界部分 //倒數第二個爲true時,包含查詢邊界,爲false時不包含 TermRangeFilter filter=new TermRangeFilter("ename", new BytesRef("h"), new BytesRef("n"), true, true); TopDocs topDocs=searcher.search(new MatchAllDocsQuery(),filter,10000);//默認無排序方式
輸出結果app
6 1 健康生活 jksh 生活 20.47 200008 7 1 看清本質 kqbz 社會 10.37 201004
核心代碼
ide
NumericRangeFilter<Double> filter=NumericRangeFilter.newDoubleRange("price", 10D, 40D, true, false); TopDocs topDocs=searcher.search(new MatchAllDocsQuery(),filter,10000);//默認無排序方式
輸出結果性能
2 1 三國演義 sgyy 小說 36.13 201207 5 1 職場關係論 zcgxl 職場 36.59 200501 6 1 健康生活 jksh 生活 20.47 200008 7 1 看清本質 kqbz 社會 10.37 201004 8 1 編程,編程 bcbc 社會 10.37 201004
核心代碼測試
//使用緩存過濾 Filter filter=FieldCacheRangeFilter.newDoubleRange("price", 20D, 50D, true, true); TopDocs topDocs=searcher.search(new MatchAllDocsQuery(),filter,10000);//默認無排序方式
輸出結果
this
2 1 三國演義 sgyy 小說 36.13 201207 5 1 職場關係論 zcgxl 職場 36.59 200501 6 1 健康生活 jksh 生活 20.47 200008
核心代碼
// 緩存域過濾特定的類別 Filter filter=new FieldCacheTermsFilter("type", new String[]{"技術","社會"}); TopDocs topDocs=searcher.search(new MatchAllDocsQuery(),filter,10000);//默認無排序方式
輸出結果
3 1 數據庫實戰 sjksz 技術 77.13 200811 4 1 編程寶典 bcbd 技術 100.3 200501 7 1 看清本質 kqbz 社會 10.37 201004 8 1 編程,編程 bcbc 社會 10.37 201004
核心代碼
//使用QueryWrapperFilter類包裝一個Query QueryWrapperFilter filter=new QueryWrapperFilter(new TermQuery(new Term("type", "技術"))); TopDocs topDocs=searcher.search(new MatchAllDocsQuery(),filter,10000);//默認無排序方式
輸出結果
3 1 數據庫實戰 sjksz 技術 77.13 200811 4 1 編程寶典 bcbd 技術 100.3 200501
如何繼承Filter基類,來定製咱們本身的Filter,自定義的Filter,雖然某些時候,功能很強大靈活,可是有幾個缺點,咱們的瞭解1,保證是內容不重複的字段,例如主鍵,若是重複,默認返回第一個做爲結果集顯示2,保證不能被分詞的內容,若是是分詞的字段,則可能會出現一些不正確的結果。
自定義Filter類
package com.sanjiesanxian.test; import java.io.IOException; import java.util.BitSet; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.index.DocsEnum; import org.apache.lucene.index.Term; import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.Filter; import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.Bits; import org.apache.lucene.util.DocIdBitSet; import org.apache.lucene.util.FixedBitSet; import org.apache.lucene.util.OpenBitSet; /*** *^_^ ^_^ ^_^ * 自定義過濾器 * @author 三劫散仙 * */ public class MyCustomFilter extends Filter{ public MyCustomFilter() { // TODO Auto-generated constructor stub } private String[] terms;//限制返回的數據字典 public MyCustomFilter(String ...terms) { // TODO Auto-generated constructor stub this.terms=terms; } @Override public DocIdSet getDocIdSet(AtomicReaderContext arg0, Bits arg1) throws IOException { //獲取沒有全部的docid包括未刪除的 FixedBitSet bits=new FixedBitSet(arg0.reader().maxDoc()) ; int base=arg0.docBase;//段的相對基數,保證多個段時相對位置正確 //int limit=base+arg0.reader().maxDoc();//計算最大限制值 for(String s:terms){ //必須是惟一的不重複 DocsEnum doc=arg0.reader().termDocsEnum(new Term("id", s)); //保證是單個不重複的term,若是重複的話,默認會取第一個做爲返回結果集,分詞後的term也不適用自定義term if(doc.nextDoc()!=-1){ bits.set(doc.docID());//對付符合條件約束的docid循環添加到bits裏面 } } return bits; } }
測試查詢代碼
MyCustomFilter filter=new MyCustomFilter("3","5","2");//隨意指定1之多個須要過濾的項 TopDocs topDocs=searcher.search(new MatchAllDocsQuery(),filter,10000);
輸出結果
2 1 三國演義 sgyy 小說 36.13 201207 3 1 數據庫實戰 sjksz 技術 77.13 200811 5 1 職場關係論 zcgxl 職場 36.59 200501
自定義過濾器雖然有缺點,可是某些場景下卻能發揮很靈活的做用,特別是對沒有分詞的字段進行過濾操做。