Lucene筆記28-Lucene的使用-自定義Filter
阿新 • • 發佈:2018-11-29
一、應用場景
假如某些欄位被刪除了,重建索引,開銷較大,所以可以自定義索引過濾掉被刪的索引資訊。假如某商場搞活動,把某些商品定義成特價商品,於是我們新增欄位,定義成特價商品,再次建索引,這樣的開銷也是很大,而且今天一個活動,明天一個活動,那豈不是要天天更新索引了,開銷太大,所以可以在活動的時候使用自定義過濾器,專門處理,活動結束後,還是使用原來的過濾器。
二、過濾器原理
新建一個類,繼承Filter,實現getDocIdSet()方法,這個方法的返回值是DocIdSet,什麼是DocIdSet呢?可以理解成一個數組,裡面放著0或1,這個陣列的的大小和maxDocs是一一對應的,當文件查詢出來後,就會根據docId來這個數組裡面比較,如果是0就過濾掉,如果是1就新增到topDocs裡面去,這就是原理。所以,我們可以把要處理的docId獲取到,然後去這個陣列中更改它們的值,來實現自定義過濾的效果。
三、程式碼實現
對於刪除的情況,就先設定所有值都不過濾,通過getDocIdSet()方法讀取要刪除的值,將其過濾。
對於舉辦活動這樣的情況,先設定所有值都過濾,通過getDocIdSet()方法,將活動商品新增進來,使用openBitSet.set()方法即可。
package com.wsy; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.NumericField; import org.apache.lucene.index.*; import org.apache.lucene.search.*; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.util.OpenBitSet; import org.apache.lucene.util.Version; import java.io.File; import java.io.FileReader; import java.io.IOException; public class MyFilter extends Filter { private static Directory directory; private static IndexReader indexReader; private String[] deleteIds = {"1", "3", "5"}; static { try { directory = FSDirectory.open(new File("E:\\Lucene\\IndexLibrary")); indexReader = IndexReader.open(directory); } catch (IOException e) { e.printStackTrace(); } } @Override public DocIdSet getDocIdSet(IndexReader indexReader) throws IOException { // 建立一個OpenBitSet物件,預設裡面全是0 OpenBitSet openBitSet = new OpenBitSet(indexReader.maxDoc()); // 把docId為2的值設定為1 // openBitSet.set(2); // 快速設定,將0-maxDocs()-1都設定為1 openBitSet.set(0, indexReader.maxDoc() - 1); // 獲取需要被過濾掉的docId,將它的值清空 int[] docs = new int[1]; int[] freqs = new int[1]; for (String deleteId : deleteIds) { // 獲取TermDocs TermDocs termDocs = indexReader.termDocs(new Term("id", deleteId)); // 將查詢出來的物件的位置存在docs中,將查詢出現的頻率存放在freqs中,返回查詢出來的條數 int count = termDocs.read(docs, freqs); // count == 1表明這個是主鍵 System.out.println("count=" + count + "\tdocs=" + docs[0] + "\tfreqs=" + freqs[0]); if (count == 1) { // 將這個位置的元素刪除 openBitSet.clear(docs[0]); } } return openBitSet; } public static void index(boolean update) { IndexWriter indexWriter = null; try { indexWriter = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35))); if (update) { indexWriter.deleteAll(); } File[] files = new File("E:\\Lucene\\SearchSource").listFiles(); int index = 0; for (File file : files) { Document document = new Document(); document.add(new Field("id", String.valueOf(index++), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS)); document.add(new Field("content", new FileReader(file))); document.add(new Field("fileName", file.getName(), Field.Store.YES, Field.Index.NOT_ANALYZED)); document.add(new Field("path", file.getAbsolutePath(), Field.Store.YES, Field.Index.NOT_ANALYZED)); document.add(new NumericField("date", Field.Store.YES, true).setLongValue(file.lastModified())); document.add(new NumericField("size", Field.Store.YES, true).setIntValue((int) (file.length() / 1024))); indexWriter.addDocument(document); } } catch (IOException e) { e.printStackTrace(); } finally { if (indexWriter != null) { try { indexWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } } public void search() { try { IndexSearcher indexSearcher = new IndexSearcher(indexReader); Query query = new TermQuery(new Term("content", "java")); TopDocs topDocs = indexSearcher.search(query, new MyFilter(), 100); ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { Document document = indexSearcher.doc(scoreDoc.doc); System.out.println(scoreDoc.doc + "-->" + document.get("fileName") + "-->" + document.get("size") + "-->" + document.get("id")); } indexSearcher.close(); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { MyFilter myFilter = new MyFilter(); myFilter.index(true); myFilter.search(); } }
和前面筆記19和筆記20類似,這裡的deleteIds是實現設定好的一組常量,實際開發過程中,應該將這裡優化掉,使用面向介面程式設計的特點,需要什麼樣的資料,就提供對應的實現類,從而讀取資料,詳細請看下一節介紹。