从1.4版本开始,Lucene开始支持自定义的结果排序,而在之前,结果只能按照评分结果倒序排列(desc)。
通常,在查询时我们使用IndexSearcher的search(Query query)方法,这个方法默认返回的结果是按照评分结果倒序排列.要实现自定义排序,则应该使用search方法的overload版本search(Query query,Sort sort).
public class SortingExample {
private Directory directory;
public SortingExample(Directory directory) {
this.directory = directory;
}
private Directory directory;
public SortingExample(Directory directory) {
this.directory = directory;
}
public void displayHits(Query query, Sort sort)
throws IOException {
IndexSearcher searcher = new IndexSearcher(directory);
Hits hits = searcher.search(query, sort);
System.out.println("\nResults for: " +query.toString() + " sorted by " + sort);
System.out.println(StringUtils.rightPad("Title", 30) + StringUtils.rightPad("pubmonth", 10) + StringUtils.center("id", 4) +
StringUtils.center("score", 15));
DecimalFormat scoreFormatter = new DecimalFormat("0.######");
for (int i = 0; i < hits.length(); i++) {
Document doc = hits.doc(i);
System.out.println(
throws IOException {
IndexSearcher searcher = new IndexSearcher(directory);
Hits hits = searcher.search(query, sort);
System.out.println("\nResults for: " +query.toString() + " sorted by " + sort);
System.out.println(StringUtils.rightPad("Title", 30) + StringUtils.rightPad("pubmonth", 10) + StringUtils.center("id", 4) +
StringUtils.center("score", 15));
DecimalFormat scoreFormatter = new DecimalFormat("0.######");
for (int i = 0; i < hits.length(); i++) {
Document doc = hits.doc(i);
System.out.println(
StringUtils.rightPad
StringUtils.abbreviate(doc.get("title"), 29), 30) +
StringUtils.rightPad(doc.get("pubmonth"), 10) +
StringUtils.center("" + hits.id(i), 4) +
StringUtils.leftPad(
scoreFormatter.format(hits.score(i)), 12));
System.out.println(" " + doc.get("category"));
// System.out.println(searcher.explain(query, hits.id(i)));
}
searcher.close();
}
StringUtils.abbreviate(doc.get("title"), 29), 30) +
StringUtils.rightPad(doc.get("pubmonth"), 10) +
StringUtils.center("" + hits.id(i), 4) +
StringUtils.leftPad(
scoreFormatter.format(hits.score(i)), 12));
System.out.println(" " + doc.get("category"));
// System.out.println(searcher.explain(query, hits.id(i)));
}
searcher.close();
}
}
不用理会具体的输出的细节.
通过在查询时传入自定义的Sort对象,我们就可以实现自定义的排序规则.
首先,我们应该有一个概念,在Lucene的内置排序方法中,升降序规则默认都是natural ording,即在Sorting by relevance中默认desc,在其他排序中则是asc。
1.Sorting by relevance,中文可以叫"适当的排序"?好象有点别扭,呵呵.这也是Lucene的默认排序,即按评分结果倒序排列.
以下几种search方法都是实现的同样的效果:
search(Query query,null),search(Query query,Sort.RELEVANCE),search(Query query,new Sort())
结果首先按照评分结果desc排序,如果评分相同,则按照document id asc排序,其中,document id是document在索引时的先后顺序。
2.Sorting by index order,按照索引的先后顺序asc排列。
3.Sorting by a field,按field排序。field是在索引时建立的单元。这里需要注意的一点是,如果想按照field来排序,需要几个规则:首先,这个field必须是indexed and not tokenized,就是需要索引,但是不能分词,例如Field.KEYWORD()方法;这个field必须可以转换成Integers,Floats,Strings,可以在用Field生成Sort对象的时候指定field的类型。
正像前边提到的,在lucene中的默认结果升降序规则是natural ording,当然我们也可以自己指定排序的升降序规则。
首先,我们指定结果按照某一个field来desc排序(如果不指定,field是按照asc排序)。例如,IndexSearcher.search(Query query,new Sort("date",true)),这里参数true的作用既是使得结果按照date field按照降序排列,这样我们就可以将日期最近的结果排列到最前面。
通常,排序规则不会这么简单。例如,在某一个图书查询系统中,我们需要的排序规则是,首先按照图书的目录排序,然后同一目录的图书按照评分结果排序,评分结果相同并且目录相同的图书按照出版日期降序排列,代码片段如下:
indexSearcher.search(Query query,new Sort(
new SortField[]{
new SortField("category"),
SortField.FIELD_SCORE,
new SortField("pubmonth", SortField.INT, true)
}
)
这里,我们指定了一个SortField的数组,图书目录按照字典升序排列,然后目录相同的按照评分结果降序排列,最后按照出版日期降序排列。
其实,在lucene内部自动维护了一个排序的数组,只是在这个例子中,我们显示的指定了排序的规则而已。
排序对查询性能的影响。排序需要额外的资源消耗,更多的内存消耗。lucene只是缓存实际需要排序的field。即使如此,如果需要自定义排序,仍然需要仔细的规划,记住,按照一个String来排序将花费最大的资源。
以下几种search方法都是实现的同样的效果:
search(Query query,null),search(Query query,Sort.RELEVANCE),search(Query query,new Sort())
结果首先按照评分结果desc排序,如果评分相同,则按照document id asc排序,其中,document id是document在索引时的先后顺序。
2.Sorting by index order,按照索引的先后顺序asc排列。
3.Sorting by a field,按field排序。field是在索引时建立的单元。这里需要注意的一点是,如果想按照field来排序,需要几个规则:首先,这个field必须是indexed and not tokenized,就是需要索引,但是不能分词,例如Field.KEYWORD()方法;这个field必须可以转换成Integers,Floats,Strings,可以在用Field生成Sort对象的时候指定field的类型。
正像前边提到的,在lucene中的默认结果升降序规则是natural ording,当然我们也可以自己指定排序的升降序规则。
首先,我们指定结果按照某一个field来desc排序(如果不指定,field是按照asc排序)。例如,IndexSearcher.search(Query query,new Sort("date",true)),这里参数true的作用既是使得结果按照date field按照降序排列,这样我们就可以将日期最近的结果排列到最前面。
通常,排序规则不会这么简单。例如,在某一个图书查询系统中,我们需要的排序规则是,首先按照图书的目录排序,然后同一目录的图书按照评分结果排序,评分结果相同并且目录相同的图书按照出版日期降序排列,代码片段如下:
indexSearcher.search(Query query,new Sort(
new SortField[]{
new SortField("category"),
SortField.FIELD_SCORE,
new SortField("pubmonth", SortField.INT, true)
}
)
这里,我们指定了一个SortField的数组,图书目录按照字典升序排列,然后目录相同的按照评分结果降序排列,最后按照出版日期降序排列。
其实,在lucene内部自动维护了一个排序的数组,只是在这个例子中,我们显示的指定了排序的规则而已。
排序对查询性能的影响。排序需要额外的资源消耗,更多的内存消耗。lucene只是缓存实际需要排序的field。即使如此,如果需要自定义排序,仍然需要仔细的规划,记住,按照一个String来排序将花费最大的资源。