1. 程式人生 > >Lucene筆記28-Lucene的使用-自定義Filter

Lucene筆記28-Lucene的使用-自定義Filter

一、應用場景

假如某些欄位被刪除了,重建索引,開銷較大,所以可以自定義索引過濾掉被刪的索引資訊。假如某商場搞活動,把某些商品定義成特價商品,於是我們新增欄位,定義成特價商品,再次建索引,這樣的開銷也是很大,而且今天一個活動,明天一個活動,那豈不是要天天更新索引了,開銷太大,所以可以在活動的時候使用自定義過濾器,專門處理,活動結束後,還是使用原來的過濾器。

二、過濾器原理

新建一個類,繼承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是實現設定好的一組常量,實際開發過程中,應該將這裡優化掉,使用面向介面程式設計的特點,需要什麼樣的資料,就提供對應的實現類,從而讀取資料,詳細請看下一節介紹。