Lucene笔记28-Lucene的使用-自定义Filter

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36059561/article/details/83592310

一、应用场景

假如某些字段被删除了,重建索引,开销较大,所以可以自定义索引过滤掉被删的索引信息。假如某商场搞活动,把某些商品定义成特价商品,于是我们添加字段,定义成特价商品,再次建索引,这样的开销也是很大,而且今天一个活动,明天一个活动,那岂不是要天天更新索引了,开销太大,所以可以在活动的时候使用自定义过滤器,专门处理,活动结束后,还是使用原来的过滤器。

二、过滤器原理

新建一个类,继承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是实现设置好的一组常量,实际开发过程中,应该将这里优化掉,使用面向接口编程的特点,需要什么样的数据,就提供对应的实现类,从而读取数据,详细请看下一节介绍。

猜你喜欢

转载自blog.csdn.net/qq_36059561/article/details/83592310