lucene6中的创建正排索引以及进行字段排序的方法

通过一个例子来说明lucene6中的各种排序,lucene中的排序需要正排索引(uninverted index),所以对于创建索引时就要考虑后面的排序需求。

先说明一下这个例子的背景。在D:\indexFile\test-search-advance-files文件夹下有5个文件

每个文件中都写一句包含java的英文语句

 

我们的排序需求是:对文本内容执行“java”的查询,对查询结果进行以下排序

1. 通过评分来排序(也是默认的排序规则)

2. 通过doc的id来进行排序,也就是数据写入索引时的顺序

3. 根据文件大小来排序

这里需要对LongPoint字段进行排序

4. 根据文件修改日期来排序

这里需要对LongPoint的日期形式进行排序

5. 根据文件名来排序

这里需要对字符串文本域进行排序

6. 根据多个域进行排序,如先根据文件大小排序,如果相同,再根据名字排序

7. 根据多个域进行排序,如先根据文件大小排序,如果相同,再根据评分排序

创建索引

把索引创建的D:\indexFile\test-search-advance\下

public class FileIndexUtils {
    private static Directory directory = null;

    static {
        try {
            directory = FSDirectory.open(Paths.get("D:\\indexFile\\test-search-advance\\"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Directory getDirectory() {
        return directory;
    }

    public static void index() {
        IndexWriter writer = null;
        IndexWriterConfig iwc = new IndexWriterConfig(new StandardAnalyzer());
        iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
        try {
            writer = new IndexWriter(directory, iwc);
            File file = new File("D:\\indexFile\\test-search-advance-files");
            Document doc;
            for (File f :
                    file.listFiles()) {
                doc = new Document();
                FileReader fileReader = new FileReader(f);
                StringBuffer sb = new StringBuffer();
                char[] buffer = new char[1];
                while ((fileReader.read(buffer)) != -1) {
                    sb.append(buffer);
                }
                //TextField会对内容进行索引并分词,存储内容,但不建立正排索引
                doc.add(new TextField("content", sb.toString(), Field.Store.YES));
                doc.add(new TextField("filename", f.getName(), Field.Store.YES));
                //对文本域建立正排索引,需要使用SortedDocValuesField
                doc.add(new SortedDocValuesField("fname",new BytesRef(f.getName())));
                //StringField不分词,建立索引,存储内容
                doc.add(new StringField("path", f.getAbsolutePath(), Field.Store.YES));
                //NumericDocValuesField为LongPoint类型建立正排索引用于排序 聚合,不存储内容
                doc.add(new NumericDocValuesField("date", f.lastModified()));
                //用于存储
                doc.add(new StoredField("date_store", f.lastModified()));
                doc.add(new NumericDocValuesField("size", f.length()));
                doc.add(new StoredField("size_store", f.length()));

                writer.addDocument(doc);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

用luke看一下我们创建的index,注意标识出的创建了正排索引的字段

注意:NumericDocValuesField是用于排序的,如果需要存储内容需要另一个字段

创建Searcher

public class SearchTest {
    private static IndexReader reader = null;

    static{
        try {
            reader = DirectoryReader.open(FileIndexUtils.getDirectory());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

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

    public void search(String queryStr, Sort sort) {
        IndexSearcher searcher = getSearcher();
        //Term term = new Term("content", queryStr);
        QueryParser parser = new QueryParser("content", new StandardAnalyzer());
        try {
            //Query query = new TermQuery(term);
            Query query = parser.parse(queryStr);
            System.out.println("Query:"+query);
            TopDocs tds;
            if (sort != null) {
                tds = searcher.search(query, 5, sort);
            } else {
                tds = searcher.search(query, 5);
            }
            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+":(score:"+sd.score+")[filename:"+d.get("filename")+"][path:"+d.get("path")
                        +"][size:"+d.get("size_store")+"][date:"+sdf.format(Long.valueOf(d.get("date_store")))
                        +"]");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

测试

public class MainTest {
    private SearchTest st;

    @Before
    public void init() {
        //先创建索引
        FileIndexUtils.index();
        st = new SearchTest();
    }

    @Test
    public void test() {
        //默认,通过评分来排序
//        st.search("java",null);

        //Sort.INDEXORDER 通过doc的id进行排序
//        st.search("java", Sort.INDEXORDER);
);

        //显式通过评分来排序
//        st.search("java", Sort.RELEVANCE);

        //根据文件大小进行排序
//        st.search("java", new Sort(new SortField("size", SortField.Type.LONG,true)));

        //根据日期进行排序 最新在最前面
//        st.search("java", new Sort(new SortField("date", SortField.Type.LONG,true)));

        //根据文件名排序
//        st.search("java", new Sort(new SortField("fname", SortField.Type.STRING,true)));

        //Sort的构造函数 支持对多个域进行排序
/*          public Sort(SortField... fields) {
            setSort(fields);
        }*/
        //先根据大小排 如果相同 再通过名字排
        /*st.search("java",new Sort(new SortField("size", SortField.Type.LONG,true),new SortField("fname",
                SortField.Type.STRING,true)));*/

        //先根据大小排 如果相同 再通过评分排
        st.search("java",new Sort(new SortField("size", SortField.Type.LONG,true),SortField.FIELD_DOC));

    }
}

猜你喜欢

转载自blog.csdn.net/u013905744/article/details/81162616