在Lucene 5.0中将字符串字段按字母顺序排序

7

我在Lucene 5.0中遇到了对字符串字段进行排序的问题。显然,自从Lucene 4以来,排序的方式已经改变。下面展示了一些为我的文档索引的字段片段。

@Override
public Document generateDocument(Process entity)
{
    Document doc = new Document();
    doc.add(new IntField(id, entity.getID(), Field.Store.YES));
    doc.add(new TextField(title, entity.getProcessName(), Field.Store.YES));
    doc.add(new IntField(organizationID, entity.getOrganizationID(), Field.Store.YES));
    doc.add(new StringField(versionDate, DateTools.dateToString(entity.getVersionDate(), DateTools.Resolution.SECOND), Field.Store.YES));
    doc.add(new LongField(entityDate, entity.getVersionDate().getTime(), Field.Store.YES)); 
    return doc;
}

我希望首先按相关性进行排序,这部分已经很好地实现了。但是我遇到的问题是按标题字段排序无法正常工作。我创建了一个排序字段,然后在一系列方法调用之后尝试使用TopFieldCollector。

public BaseSearchCore<Process, ProcessSearchResultScore>.SearchContainer search(String searchQuery, Filter filter, int page, int hitsPerPage) throws IOException, ParseException
    {
    SortField titleSort = new SortField(title, SortField.Type.STRING, true);
    return super.search(searchQuery, filter, page, hitsPerPage, title);
    }

这将会导致:

public SearchContainer search(String searchQuery, Filter filter, int page, int hitsPerPage, SortField... sortfields) throws IOException, ParseException 
    {
        Query query = getQuery(searchQuery);
        TopFieldCollector paginate = getCollector(sortfields);
        int startIndex = (page -1) * hitsPerPage;
        ScoreDoc[] hits = executeSearch(query, paginate, filter, startIndex, hitsPerPage);

        return collectResults(query, filter, hitsPerPage, hits, page);
  }

最后是应用排序字段的方法:

private TopFieldCollector getCollector(SortField sortfield) throws IOException
    {
        SortField[] sortFields = new SortField[] {SortField.FIELD_SCORE, sortField};
        Sort sorter = new Sort(sortFields);
        TopFieldCollector collector = TopFieldCollector.create(sorter, 25000, true, false, true);
        return collector;
    }

使用返回的收集器执行常规查询,并返回结果。但是,如果我尝试使用此SortField进行排序,将会出现以下异常:
java.lang.IllegalStateException:字段“title”的docvalues类型为NONE(期望=SORTED)。使用UninvertingReader或具有docvalues的索引。
我应该如何索引字符串字段以便能够按字母顺序对其进行排序(使用sortfields)在Lucene 5中?任何代码示例或片段都将非常赞赏。
通过相关性搜索工作正常,但当用户输入空搜索查询时,所有结果的相关性相同。对于这些查询,我宁愿按结果标题排序,在这个Lucene迭代中会出现问题。
2个回答

12

提示:如果您尝试将错误简化到最小的示例,那么找出错误就会更加容易(无论是对于自己还是要求帮助的人)。相比于查看您的架构、类和其他我无法访问或不了解的内容,我将首先解决通过以下方式再现的问题:

Sort sort = new Sort(new SortField("title", SortField.Type.STRING));
TopDocs docs = searcher.search(new TermQuery(new Term("title", "something")), 10, sort);

标题的定义类似于:

doc.add(new TextField("title", term, Field.Store.YES));

在这里最好的排序方法可能是采用文档值(docvalues)的建议。将DocValues添加到字段中本质上是为了对其进行排序索引,并且比我所理解的Lucene 4.X中的典型排序方法要高效得多。在同一个字段(名称)中同时添加典型的TextFieldSortedDocValuesField似乎效果很不错,支持使用相同的字段名称进行搜索和排序:

doc.add(new TextField("title", term, Field.Store.YES));
doc.add(new SortedDocValuesField("title", new BytesRef(term)));

感谢您的输入,您对我之前结构化问题的评论是正确的。我将答案标记为正确,因为我也得出了使用SortedDocValuesField来排序所需字段的结论。感谢您的帮助! - Muppenz
@femtoRgon 是否可以创建一个单一的字段来代替“标题”的两个独立字段,即使这意味着创建一个自定义字段? - Basil Musa
1
@BasilMusa- 在所有方面来讲,这就是它所做的。如果它被分析了,你可能会遇到问题,否则你需要的一切都在FieldType中。(https://lucene.apache.org/core/5_3_1/core/org/apache/lucene/document/FieldType.html)。 - femtoRgon

3

在Lucene 5.0及以上版本中,索引时请使用以下内容进行排序:

doc.add(new SortedDocValuesField("title", new BytesRef(term)));

搜索时请使用:

Sort sort = new Sort();
sort.setSort(new SortField("title", SortField.Type.STRING));            
TopDocs hits = searcher.search(bQuery.build(), pageSize, sort);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接