天天看點

lucene自定義過濾器Filter

業務場景:

  1:假設資料庫中的字段給删了,如果 重建索引的話,就開銷比較大。這個時候就可以考慮自定義過濾器

  2:控制部分查詢權限

為了避免頻繁重構索引,我們可以在查詢的時候定義一個自己的過濾器 ,去過濾掉這些資料。

lucene在package org.apache.lucene.util; 這包中提供了一個非常好的DocIdSet 實作類OpenBitSet,OpenBitSet這個實作類用來儲存 0,1,1,0,0,1 ;每個0 、1  對應着其文檔docid。呈現這樣的鍊裝結構表

大概實作原理:通過繼承Filter,重寫其getDocIdSet方法。。。通過傳回實作類OpenBitSet的對象。這個對象通過不用的業務需求,把不同的文檔docid,綁定 0,1 序列。

通過以下方法,隻需要提供文檔id就直接把0----》1:

lucene自定義過濾器Filter

代碼:

<span style="font-size:14px;">
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.util.OpenBitSet;

public class CustomQueryFilter  extends Filter{
	
	
	private FilterAccessFactory filterAccessFactory;
	
	public CustomQueryFilter(FilterAccessFactory filterAccessFactory){
		this.filterAccessFactory=filterAccessFactory;
	}

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
		/**
		 * 建立一個bit
		 * 假設索引庫中有1W條資料,那麼 就有1W的長度
		 * bit裡面都是儲存0和1 的資料
		 * 剛建立的時候,預設全部為0;
		 */
		OpenBitSet obs=new OpenBitSet(reader.maxDoc());
		//把元素全部設定為1
		obs.set(0,reader.maxDoc());
		
		/**
		 * 方式一
		 * 兩次循環,性能較差
		 */
//		IndexSearcher searcher=new  IndexSearcher(reader);
//		TopDocs tds=searcher.search(new TermQuery(new Term("content","name")), 500);
//		for(ScoreDoc doc:tds.scoreDocs){
//			for(String id:filterAccessFactory.values()){			
//				if(doc.doc==Integer.parseInt(id)){
//					obs.clear(Integer.parseInt(id));
//					System.out.println("-----------去除id---------------"+id);
//				}
//			}
//		}
//		searcher.close();
		
		/**
		 * 方式二
		 */
		int[] docs=new int[1];
		int[] freqs=new int[1];
		for(String id:filterAccessFactory.values()){
			TermDocs tdocs=reader.termDocs(new Term(filterAccessFactory.getField(), id));
			//會把查詢出來的對象位置儲存到docs中,出現的頻率資訊儲存到freqs中,放回擷取的條數
			int count=tdocs.read(docs, freqs);
			if(count==1){
				obs.clear(docs[0]);
				System.out.println("-----------去除id---------------"+id);
			}
		}
		return obs;
	}

	/**
	 * 測試
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			IndexSearcher searcher = new IndexSearcher(IndexReader.open(FileIndexUtils.getDirectory()));
			Query query = new TermQuery(new Term("content","name"));
			TopDocs tds = searcher.search(query,new CustomQueryFilter(new FilterAccessFactory(){
				@Override
				public boolean addOrUpdate() {
					return true;
				}
				@Override
				public String getField() {
					return "id";
				}
				@Override
				public String[] values() {
					return new String[]{"1","5","3","4"};
				}
			}),500);
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
			for(ScoreDoc sd:tds.scoreDocs) {
				Document d = searcher.doc(sd.doc);
				System.out.println(sd.doc+":("+sd.score+")" +
						"["+d.get("filename")+"路徑:"+d.get("path")+"--->"+
						d.get("size")+"-----"+sdf.format(new Date(Long.valueOf(d.get("date"))))+"]");
			}
			searcher.close(); 
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
</span>