欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

8、搜索排序和搜索过滤(lucene笔记)

程序员文章站 2022-07-09 10:23:05
...

一、搜索排序(工程lucene_analyzer03

这里我们使用之前工程中创建索引的一个工具类```FileIndexUtil.java

package cn.itcast.util;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
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.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.util.Version;

public class FileIndexUtil {

    private static Directory directory = null;
    static {
        try {
            directory = FSDirectory.open(new File(
                    "E:/myeclipse/Lucene/index"));

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Directory getDirectory() {
        return directory;
    }

    // 创建索引
    public static void index(boolean hasNew) {
        IndexWriter writer = null;
        try {
            writer = new IndexWriter(directory, new IndexWriterConfig(
                    Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
            if (hasNew) {
                writer.deleteAll();//如果我们要新建索引,那么将之前创建的删除
            }
            File file = new File("E:/myeclipse/Lucene/somefile");

            Document document = null;
            for (File f : file.listFiles()) {
                document = new Document();
                document.add(new Field("content", new FileReader(f)));
                document.add(new Field("filename", f.getName(),
                        Field.Store.YES, Field.Index.NOT_ANALYZED));
                document.add(new Field("path", f.getAbsolutePath(),
                        Field.Store.YES, Field.Index.NOT_ANALYZED));
                document.add(new NumericField("date", Field.Store.YES, true)
                        .setLongValue(f.lastModified()));
                // 最后我们将字节数转换成kb
                document.add(new NumericField("size", Field.Store.YES, true)
                        .setIntValue((int) (f.length())));
                writer.addDocument(document);
            }
        } catch (CorruptIndexException e) {
            e.printStackTrace();
        } catch (LockObtainFailedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (CorruptIndexException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

说明:此类是之前我们写的一个创建索引的类。下面再写一个类用于测试排序的类SearchTest.java

package cn.lucene.test;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.util.Version;
import cn.itcast.util.FileIndexUtil;

public class SearchTest {

    private static IndexReader reader;
    static {
        try {
            reader = IndexReader.open(FileIndexUtil.getDirectory());
        } catch (CorruptIndexException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public IndexSearcher getSearcher() {
        try {
            if (reader == null) {
                reader = IndexReader.open(FileIndexUtil.getDirectory());
            } else {
                IndexReader tr = IndexReader.openIfChanged(reader);
                if (tr != null) {
                    reader.close();
                    reader = tr;
                }
            }
            return new IndexSearcher(reader);
        } catch (CorruptIndexException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public void searcher(String queryStr, Sort sort) {
        try {
            IndexSearcher searcher = getSearcher();
            QueryParser parser = new QueryParser(Version.LUCENE_35, "content",
                    new StandardAnalyzer(Version.LUCENE_35));
            Query query = parser.parse(queryStr);
            TopDocs tds = null;
            if (sort != null) {
                tds = searcher.search(query, 50, sort);
            } else {
                tds = searcher.search(query, 50);
            }
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            for (ScoreDoc sd : tds.scoreDocs) {
                Document doc = searcher.doc(sd.doc);
                System.out.println("id:" + sd.doc + ",评分:" + sd.score + ",名称:"
                        + doc.get("filename") + ",路径:" + doc.get("path")
                        + ",文件大小:" + doc.get("size") + ",日期:"
                        + sdf.format(new Date(Long.valueOf(doc.get("date")))));
            }
            searcher.close();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

相关的代码我们在之前已经讲过,下面我们进行排序测试TestAnalyzer.java

package cn.lucene.test;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.junit.Before;
import org.junit.Test;
import cn.itcast.util.FileIndexUtil;

public class TestAnalyzer {
    private SearchTest st;
    
    @Before
    public void init(){
        st = new SearchTest();
    }
    
    //重新创建索引
    @Test
    public void Index(){
        FileIndexUtil.index(true);
    }
    
    @Test
    public void test01(){
        //只要设置了排序,那么评分就没有了
        //st.searcher("java", Sort.INDEXORDER);//以序号排序
        //st.searcher("java", Sort.RELEVANCE);//通过评分排序
        
        //st.searcher("java", new Sort(new SortField("size", SortField.INT)));//通过文件大小排序
        //st.searcher("java", new Sort(new SortField("date", SortField.LONG)));//通过日期排序
        //st.searcher("java", new Sort(new SortField("filename", SortField.STRING)));//通过文件名排序,升序
        //st.searcher("java", new Sort(new SortField("filename", SortField.STRING, true)));//通过文件名排序,降序
        //先按大小排序,再按评分排序
        st.searcher("java", new Sort(new SortField("size", SortField.INT), SortField.FIELD_SCORE));
    }
}

说明:通过上面的测试代码我们可以看到,lucene默认有很多排序的规则,只要我们自行设置好便可达到相关排序的目的,当然在后面我们还需要自定义排序规则来达到我们的要求,这里只是入门。

二、搜索过滤

这里我们说三个进行搜索过滤的过滤器,其实前面已经提到,这里作为复习.
SearchTest.java

    public void searcher(String queryStr, Filter filter){
        try {
            IndexSearcher searcher = getSearcher();
            QueryParser parser = new QueryParser(Version.LUCENE_35, "content",
                    new StandardAnalyzer(Version.LUCENE_35));
            Query query = parser.parse(queryStr);
            TopDocs tds = null;
            if (filter != null) {
                //这里我们使用过滤器
                tds = searcher.search(query, filter, 50);
            } else {
                tds = searcher.search(query, 50);
            }
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            for (ScoreDoc sd : tds.scoreDocs) {
                Document doc = searcher.doc(sd.doc);
                System.out.println("id:" + sd.doc + ",评分:" + sd.score + ",名称:"
                        + doc.get("filename") + ",路径:" + doc.get("path")
                        + ",文件大小:" + doc.get("size") + ",日期:"
                        + sdf.format(new Date(Long.valueOf(doc.get("date")))));
            }
            searcher.close();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

说明:在这个方法中我们传入的不是排序类,而是过滤器。下面进行测试。

    @Test
    public void test02(){
        //范围搜索,从json.c到json.php的分为内搜索json,最后两个参数表示是前后都是闭区间
        Filter tr = new TermRangeFilter("filename", "json.c", "json.php", true, true);
        //大小范围搜索
        tr = NumericRangeFilter.newIntRange("size", 10, 100, true, true);
        //可以通过一个query进行过滤
        tr = new QueryWrapperFilter(new WildcardQuery(new Term("filename", "*.c")));
        st.searcher("json", tr);
    }

说明:这里我们给出了三个过滤器,分别进行名字范围、发笑范围过滤器和一个可以通过Query进行过滤去过滤器。