关于Lucene检索结果的排序问题。
已经知道,Lucene的默认排序是按照Document的得分进行排序的。当检索结果集中的两个Document的具有相同的得分时,默认按照Document的ID对结果进行排序。
下面研究几种设置/改变检索结果排序的方法。
■ 改变Document的boost(激励因子)
改变boost的值实现改变检索结果集的排序,是最简单的方法,只需要在建立索引的过程中,设置指定的Document的boost值,来改变排序结果中Document位置的提前或者靠后。
根据在文章 Lucene-2.2.0 源代码阅读学习(39) 中说明的关于Lucene得分的计算,实际上改变boost的大小,会导致Document的得分的改变,从而按照Lucene默认的对检索结果集的排序方式,改变检索结果中Document的排序的提前或者靠后。在计算得分的时候,使用到了boost的值,默认boost的值为1.0,也就说默认情况下Document的得分与boost的无关的。一旦改变了默认的boost的值,也就从Document的得分与boost无关,变为相关了:boost值越大,Document的得分越高。
下面这个例子在文章 Lucene-2.2.0 源代码阅读学习(39) 中测试过,这里,在建立索引的时候,设置了一下Document的boost,看看排序结果的改变情况:
package org.shirdrn.lucene.learn.sort;
import java.io.IOException;import java.util.Date;
import net.teamhot.lucene.ThesaurusAnalyzer;
import org.apache.lucene.document.Document;import org.apache.lucene.document.Field;import org.apache.lucene.index.CorruptIndexException;import org.apache.lucene.index.IndexWriter;import org.apache.lucene.index.Term;import org.apache.lucene.index.TermDocs;import org.apache.lucene.search.Explanation;import org.apache.lucene.search.Hits;import org.apache.lucene.search.IndexSearcher;import org.apache.lucene.search.Query;import org.apache.lucene.search.TermQuery;import org.apache.lucene.store.LockObtainFailedException;
public class AboutLuceneDefaultSort {
private String path = "F:\\index";
public void createIndex() { IndexWriter writer; try { writer = new IndexWriter(path, new ThesaurusAnalyzer(), true);
Field fieldA = new Field("contents", "一人", Field.Store.YES, Field.Index.TOKENIZED); Document docA = new Document(); docA.add(fieldA); docA.setBoost(0.1f); // 减小boost值
Field fieldB = new Field("contents", "一人 之交 一人之交", Field.Store.YES, Field.Index.TOKENIZED); Document docB = new Document(); docB.add(fieldB);
Field fieldC = new Field("contents", "一人 之下 一人之下", Field.Store.YES, Field.Index.TOKENIZED); Document docC = new Document(); docC.add(fieldC);
Field fieldD = new Field("contents", "一人 做事 一人当 一人做事一人当", Field.Store.YES, Field.Index.TOKENIZED); Document docD = new Document(); docD.setBoost(2.0f); // 提高boost值 docD.add(fieldD);
Field fieldE = new Field("contents", "一人 做事 一人當 一人做事一人當", Field.Store.YES, Field.Index.TOKENIZED); Document docE = new Document(); docE.add(fieldE);
writer.addDocument(docA); writer.addDocument(docB); writer.addDocument(docC); writer.addDocument(docD); writer.addDocument(docE);
writer.close(); } catch (CorruptIndexException e) { e.printStackTrace(); } catch (LockObtainFailedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }}
public static void main(String[] args) { AboutLuceneDefaultSort aus = new AboutLuceneDefaultSort(); aus.createIndex(); // 建立索引 try { String keyword = "一人"; Term term = new Term("contents", keyword); Query query = new TermQuery(term); IndexSearcher searcher = new IndexSearcher(aus.path); Date startTime = new Date(); Hits hits = searcher.search(query); TermDocs termDocs = searcher.getIndexReader().termDocs(term); while (termDocs.next()) { System.out .print("搜索关键字<" + keyword + ">在编号为 " + termDocs.doc()); System.out.println(" 的Document中出现过 " + termDocs.freq() + " 次"); } System.out .println("********************************************************************"); for (int i = 0; i < hits.length(); i++) { System.out.println("Document的内部编号为 : " + hits.id(i)); System.out.println("Document内容为 : " + hits.doc(i)); System.out.println("Document得分为 : " + hits.score(i)); Explanation e = searcher.explain(query, hits.id(i)); System.out.println("Explanation为 : \n" + e); System.out.println("Document对应的Explanation的一些参数值如下: "); System.out.println("Explanation的getValue()为 : " + e.getValue()); System.out.println("Explanation的getDescription()为 : " + e.getDescription()); System.out .println("********************************************************************"); } System.out.println("共检索出符合条件的Document " + hits.length() + " 个。"); Date finishTime = new Date(); long timeOfSearch = finishTime.getTime() - startTime.getTime(); System.out.println("本次搜索所用的时间为 " + timeOfSearch + " ms"); } catch (CorruptIndexException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
}}
如果不设置docA.setBoost(0.1f);和docD.setBoost(2.0f);,则按照默认进行排序,即boost激励因子的值为1.0,执行后,检索结果如下所示:
词库尚未被初始化,开始初始化词库.初始化词库结束。用时:3766毫秒;共添加195574个词语。搜索关键字<一人>在编号为 0 的Document中出现过 1 次搜索关键字<一人>在编号为 1 的Document中出现过 1 次搜索关键字<一人>在编号为 2 的Document中出现过 1 次搜索关键字<一人>在编号为 3 的Document中出现过 2 次搜索关键字<一人>在编号为 4 的Document中出现过 2 次********************************************************************Document的内部编号为 : 0Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人>>Document得分为 : 0.81767845Explanation为 : 0.81767845 = (MATCH) fieldWeight(contents:一人 in 0), product of:1.0 = tf(termFreq(contents:一人)=1)0.81767845 = idf(docFreq=5)1.0 = fieldNorm(field=contents, doc=0)
Document对应的Explanation的一些参数值如下: Explanation的getValue()为 : 0.81767845Explanation的getDescription()为 : fieldWeight(contents:一人 in 0), product of:********************************************************************Document的内部编号为 : 3Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 做事 一人当 一人做事一人当>>Document得分为 : 0.5059127Explanation为 : 0.5059127 = (MATCH) fieldWeight(contents:一人 in 3), product of:1.4142135 = tf(termFreq(contents:一人)=2)0.81767845 = idf(docFreq=5)0.4375 = fieldNorm(field=contents, doc=3)
Document对应的Explanation的一些参数值如下: Explanation的getValue()为 : 0.5059127Explanation的getDescription()为 : fieldWeight(contents:一人 in 3), product of:********************************************************************Document的内部编号为 : 4Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 做事 一人當 一人做事一人當>>Document得分为 : 0.5059127Explanation为 : 0.5059127 = (MATCH) fieldWeight(contents:一人 in 4), product of:1.4142135 = tf(termFreq(contents:一人)=2)0.81767845 = idf(docFreq=5)0.4375 = fieldNorm(field=contents, doc=4)
Document对应的Explanation的一些参数值如下: Explanation的getValue()为 : 0.5059127Explanation的getDescription()为 : fieldWeight(contents:一人 in 4), product of:********************************************************************Document的内部编号为 : 1Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 之交 一人之交>>Document得分为 : 0.40883923Explanation为 : 0.40883923 = (MATCH) fieldWeight(contents:一人 in 1), product of:1.0 = tf(termFreq(contents:一人)=1)0.81767845 = idf(docFreq=5)0.5 = fieldNorm(field=contents, doc=1)
Document对应的Explanation的一些参数值如下: Explanation的getValue()为 : 0.40883923Explanation的getDescription()为 : fieldWeight(contents:一人 in 1), product of:********************************************************************Document的内部编号为 : 2Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 之下 一人之下>>Document得分为 : 0.40883923Explanation为 : 0.40883923 = (MATCH) fieldWeight(contents:一人 in 2), product of:1.0 = tf(termFreq(contents:一人)=1)0.81767845 = idf(docFreq=5)0.5 = fieldNorm(field=contents, doc=2)
Document对应的Explanation的一些参数值如下: Explanation的getValue()为 : 0.40883923Explanation的getDescription()为 : fieldWeight(contents:一人 in 2), product of:********************************************************************共检索出符合条件的Document 5 个。本次搜索所用的时间为 188 ms
检索结果排序为:0——3——4——1——2
如果,我们认为ID为4的Document比较重要,而ID为0的Document不重要,希望在检索的时候,ID为4的Document位置靠前一些,因为它重要,ID为0的Document靠后一些,因为它不如其它的重要,可以通过如下设置:
docA.setBoost(0.1f); docD.setBoost(2.0f);
来改变指定的Document的boost值,从而改变这两个Document的得分,进而获取所期望的排序位置。这样设置以后,排序结果就改变了,如下所示:
词库尚未被初始化,开始初始化词库.初始化词库结束。用时:3641毫秒;共添加195574个词语。搜索关键字<一人>在编号为 0 的Document中出现过 1 次搜索关键字<一人>在编号为 1 的Document中出现过 1 次搜索关键字<一人>在编号为 2 的Document中出现过 1 次搜索关键字<一人>在编号为 3 的Document中出现过 2 次搜索关键字<一人>在编号为 4 的Document中出现过 2 次********************************************************************Document的内部编号为 : 3Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 做事 一人当 一人做事一人当>>Document得分为 : 1.0Explanation为 : 1.0118254 = (MATCH) fieldWeight(contents:一人 in 3), product of:1.4142135 = tf(termFreq(contents:一人)=2)0.81767845 = idf(docFreq=5)0.875 = fieldNorm(field=contents, doc=3)
Document对应的Explanation的一些参数值如下: Explanation的getValue()为 : 1.0118254Explanation的getDescription()为 : fieldWeight(contents:一人 in 3), product of:********************************************************************Document的内部编号为 : 4Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 做事 一人當 一人做事一人當>>Document得分为 : 0.5Explanation为 : 0.5059127 = (MATCH) fieldWeight(contents:一人 in 4), product of:1.4142135 = tf(termFreq(contents:一人)=2)0.81767845 = idf(docFreq=5)0.4375 = fieldNorm(field=contents, doc=4)
Document对应的Explanation的一些参数值如下: Explanation的getValue()为 : 0.5059127Explanation的getDescription()为 : fieldWeight(contents:一人 in 4), product of:********************************************************************Document的内部编号为 : 1Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 之交 一人之交>>Document得分为 : 0.40406102Explanation为 : 0.40883923 = (MATCH) fieldWeight(contents:一人 in 1), product of:1.0 = tf(termFreq(contents:一人)=1)0.81767845 = idf(docFreq=5)0.5 = fieldNorm(field=contents, doc=1)
Document对应的Explanation的一些参数值如下: Explanation的getValue()为 : 0.40883923Explanation的getDescription()为 : fieldWeight(contents:一人 in 1), product of:********************************************************************Document的内部编号为 : 2Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 之下 一人之下>>Document得分为 : 0.40406102Explanation为 : 0.40883923 = (MATCH) fieldWeight(contents:一人 in 2), product of:1.0 = tf(termFreq(contents:一人)=1)0.81767845 = idf(docFreq=5)0.5 = fieldNorm(field=contents, doc=2)
Document对应的Explanation的一些参数值如下: Explanation的getValue()为 : 0.40883923Explanation的getDescription()为 : fieldWeight(contents:一人 in 2), product of:********************************************************************Document的内部编号为 : 0Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人>>Document得分为 : 0.075761445Explanation为 : 0.076657355 = (MATCH) fieldWeight(contents:一人 in 0), product of:1.0 = tf(termFreq(contents:一人)=1)0.81767845 = idf(docFreq=5)0.09375 = fieldNorm(field=contents, doc=0)
Document对应的Explanation的一些参数值如下: Explanation的getValue()为 : 0.076657355Explanation的getDescription()为 : fieldWeight(contents:一人 in 0), product of:********************************************************************共检索出符合条件的Document 5 个。本次搜索所用的时间为 140 ms
这时,检索结果排序变为:3——4——1——2——0
可见,改变了检索结果集中Document的排序位置。
■ 改变Field的boost(激励因子)
改变Field的boost值,和改变Document的boost值是一样的。因为Document的boost是通过添加到Docuemnt中Field体现的,所以改变Field的boost值,可以改变Document的boost值。设置如下所示:
fieldA.setBoost(0.1f); fieldD.setBoost(2.0f);
排序结果与上面设置:
docA.setBoost(0.1f); docD.setBoost(2.0f);
对排序结果排序的改变是相同的:
3——4——1——2——0
■ 使用Sort排序工具实现排序
Lucene在查询的时候,可以通过以一个Sort作为参数构造一个检索器IndexSearcher,在构造Sort的时候,指定排序规则,例如下面的测试类:
package org.shirdrn.lucene.learn.sort;
import java.io.IOException;import java.util.Date;
import net.teamhot.lucene.ThesaurusAnalyzer;
import org.apache.lucene.document.Document;import org.apache.lucene.document.Field;import org.apache.lucene.index.CorruptIndexException;import org.apache.lucene.index.IndexWriter;import org.apache.lucene.index.Term;import org.apache.lucene.index.TermDocs;import org.apache.lucene.search.Hits;import org.apache.lucene.search.IndexSearcher;import org.apache.lucene.search.Query;import org.apache.lucene.search.Sort;import org.apache.lucene.search.TermQuery;import org.apache.lucene.store.LockObtainFailedException;
public class AboutLuceneSort {private String path = "F:\\index";
public void createIndex() { IndexWriter writer; try { writer = new IndexWriter(path, new ThesaurusAnalyzer(), true);
Field fieldA1 = new Field("contents", "孤身一人闯天宫,居然像旅游一下轻松,还有谁能做到这样啊?一人!", Field.Store.YES,Field.Index.TOKENIZED); Field fieldA2 = new Field("count", "27", Field.Store.YES,Field.Index.UN_TOKENIZED); Document docA = new Document(); docA.add(fieldA1); docA.add(fieldA2);
Field fieldB1 = new Field("contents", "一人之交与万人之交,一人。", Field.Store.YES, Field.Index.TOKENIZED); Field fieldB2 = new Field("count", "12", Field.Store.YES, Field.Index.UN_TOKENIZED); Document docB = new Document(); docB.add(fieldB1); docB.add(fieldB2);
Field fieldC1 = new Field("contents", "一人之见:千里之行,始于足下。", Field.Store.YES, Field.Index.TOKENIZED); Field fieldC2 = new Field("count", "12", Field.Store.YES, Field.Index.UN_TOKENIZED); Document docC = new Document(); docC.add(fieldC1); docC.add(fieldC2);
Field fieldD1 = new Field("contents", "一人做事一人当,一人。",Field.Store.YES, Field.Index.TOKENIZED); Field fieldD2 = new Field("count", "9", Field.Store.YES, Field.Index.UN_TOKENIZED); Document docD = new Document(); docD.add(fieldD1); docD.add(fieldD2);
Field fieldE1 = new Field("contents", "两人、一人、然后怎么数下去呀——晕~。",Field.Store.YES, Field.Index.TOKENIZED); Field fieldE2 = new Field("count", "13", Field.Store.YES, Field.Index.UN_TOKENIZED); Document docE = new Document(); docE.add(fieldE1); docE.add(fieldE2);
writer.addDocument(docA); writer.addDocument(docB); writer.addDocument(docC); writer.addDocument(docD); writer.addDocument(docE); writer.optimize(); writer.close(); } catch (CorruptIndexException e) { e.printStackTrace(); } catch (LockObtainFailedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }}
public static void main(String[] args) { AboutLuceneSort aus = new AboutLuceneSort(); aus.createIndex(); // 建立索引 try { String keyword = "一人"; Term term = new Term("contents", keyword); Query query = new TermQuery(term); IndexSearcher searcher = new IndexSearcher(aus.path); Date startTime = new Date(); Sort sort = new Sort("count"); // 根据名称为count的Field进行排序 Hits hits = searcher.search(query,sort); TermDocs termDocs = searcher.getIndexReader().termDocs(term); while (termDocs.next()) { System.out .print("搜索关键字<" + keyword + ">在编号为 " + termDocs.doc()); System.out.println(" 的Document中出现过 " + termDocs.freq() + " 次"); } System.out .println("********************************************************************"); for (int i = 0; i < hits.length(); i++) { System.out.println("Document的内部编号为 : " + hits.id(i)); System.out.println("Document内容为 : " + hits.doc(i)); System.out.println("Document得分为 : " + hits.score(i)); for(int j=0;j<hits.doc(i).getFields().size();j++){ Field field = (Field)hits.doc(i).getFields().get(j); System.out.println("--- ---Field的name为 : " + field.name()); System.out.println("--- ---Field的StringValue为 : " + field.stringValue()); } System.out.println("********************************************************************"); } System.out.println("共检索出符合条件的Document " + hits.length() + " 个。"); Date finishTime = new Date(); long timeOfSearch = finishTime.getTime() - startTime.getTime(); System.out.println("本次搜索所用的时间为 " + timeOfSearch + " ms"); } catch (CorruptIndexException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
}}
使用了Sort类的一个只有一个参数的构造方法:
public final void setSort(String field) { setSort(field, false);}
可见,实际上调用了 setSort(field, false);方法,第一个field为指定一个Field的名称,按照给Field进行排序,第二个为boolean型值,该值指定是否按照降序进行排序,默认情况下为false,表示按照升序排序,即如果按照指定的field排序是作为第一排序的,而且是按照升序排序的,第二排序默认按照Document的ID号码(编号)进行升序排序。
setSort(field, false)方法定义:
public void setSort(String field, boolean reverse) { SortField[] nfields = new SortField[] { new SortField(field, SortField.AUTO, reverse), SortField.FIELD_DOC }; fields = nfields;}
在setSort(field, false)方法中,可以看到,实际上使用了SortField类实现了排序,SortField类具有更加丰富的关于排序的规则和内容。
指定:根据Field名称为“count”进行排序,这里,count是字数的意思,因此在分词的时候没有对其进行分词。期望的排序结果是,根据count,即字数进行排序,而不是根据Document的得分来排序。
运行结果如下所示:
词库尚未被初始化,开始初始化词库.初始化词库结束。用时:3656毫秒;共添加195574个词语。搜索关键字<一人>在编号为 0 的Document中出现过 1 次搜索关键字<一人>在编号为 1 的Document中出现过 1 次搜索关键字<一人>在编号为 2 的Document中出现过 1 次搜索关键字<一人>在编号为 3 的Document中出现过 1 次搜索关键字<一人>在编号为 4 的Document中出现过 1 次********************************************************************Document的内部编号为 : 3Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人做事一人当,一人。> stored/uncompressed,indexed<count:9>>Document得分为 : 0.51104903--- ---Field的name为 : contents--- ---Field的StringValue为 : 一人做事一人当,一人。--- ---Field的name为 : count--- ---Field的StringValue为 : 9********************************************************************Document的内部编号为 : 1Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人之交与万人之交,一人。> stored/uncompressed,indexed<count:12>>Document得分为 : 0.35773432--- ---Field的name为 : contents--- ---Field的StringValue为 : 一人之交与万人之交,一人。--- ---Field的name为 : count--- ---Field的StringValue为 : 12********************************************************************Document的内部编号为 : 2Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人之见:千里之行,始于足下。> stored/uncompressed,indexed<count:12>>Document得分为 : 0.40883923--- ---Field的name为 : contents--- ---Field的StringValue为 : 一人之见:千里之行,始于足下。--- ---Field的name为 : count--- ---Field的StringValue为 : 12********************************************************************Document的内部编号为 : 4Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:两人、一人、然后怎么数下去呀——晕~。> stored/uncompressed,indexed<count:13>>Document得分为 : 0.25552452--- ---Field的name为 : contents--- ---Field的StringValue为 : 两人、一人、然后怎么数下去呀——晕~。--- ---Field的name为 : count--- ---Field的StringValue为 : 13********************************************************************Document的内部编号为 : 0Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:孤身一人闯天宫,居然像旅游一下轻松,还有谁能做到这样啊?一人!> stored/uncompressed,indexed<count:27>>Document得分为 : 0.20441961--- ---Field的name为 : contents--- ---Field的StringValue为 : 孤身一人闯天宫,居然像旅游一下轻松,还有谁能做到这样啊?一人!--- ---Field的name为 : count--- ---Field的StringValue为 : 27********************************************************************共检索出符合条件的Document 5 个。本次搜索所用的时间为 125 ms
可见,是按照字数count来进行排序的:9——12——12——13——27
而此时检索结构的对应的得分分别为:0.51104903——0.35773432——0.40883923——0.25552452——0.20441961
可见,并不是按照得分的情况来进行排序的,而且,如果count的值相等,则使用默认的第二排序规则,即按照Document的ID号来排序,从上面的count=12结果可以看出。
关于Sort类,在其内部定义了6种构造方法:
public Sort() public Sort(SortField field) public Sort(SortField[] fields) public Sort(String field) public Sort(String field, boolean reverse) public Sort(String[] fields)
可以根据不同需要指定排序的规则,按照某个或某几个Field进行排序。不带参数的构造方法public Sort(),在实例化一个Sort之后,可以非常方便的通过调用setSort方法设定排序规则,setSort有5个重载的方法:
public void setSort(SortField field) public void setSort(SortField[] fields) public final void setSort(String field) public void setSort(String field, boolean reverse) public void setSort(String[] fieldnames)
当然,public final void setSort(String field)在外部不允许直接调用了,是默认的内部使用的设置排序规则的方法。
■ 直接使用SortField实现排序
首先看一下SortField类的源代码:
package org.apache.lucene.search;
import java.io.Serializable;import java.util.Locale;
public class SortFieldimplements Serializable {
// 按照Document的得分对检索结果进行排序,得分高的排序靠前public static final int SCORE = 0;
// 按照Document的编号(ID)对检索结果进行排序,编号小的排序靠前public static final int DOC = 1;
// 自动检测,自动选择最佳的排序方式,即按照整数类型public static final int AUTO = 2;
// 根据词条的String串排序public static final int STRING = 3;
// 将词条解码为整数,按照整数排序public static final int INT = 4;
// 将词条解码为浮点数,按照浮点数排序public static final int FLOAT = 5;
// 根据定制的排序器,实现客户化排序public static final int CUSTOM = 9;
// IMPLEMENTATION NOTE: the FieldCache.STRING_INDEX is in the same "namespace"// as the above static int values. Any new values must not have the same value// as FieldCache.STRING_INDEX.
/** 根据Document的得分构造一个SortField实例 */public static final SortField FIELD_SCORE = new SortField (null, SCORE);
/** 根据Document的编号构造一个SortField实例 */public static final SortField FIELD_DOC = new SortField (null, DOC);
private String field;private int type = AUTO; // defaults to determining type dynamicallyprivate Locale locale; // defaults to "natural order" (no Locale)boolean reverse = false; // defaults to natural orderprivate SortComparatorSource factory;
//★ 下面定义了8种构造SortField的方法 ★
// 以一个Field的名字的Sing串作为参数构造一个SortFieldpublic SortField (String field) { this.field = field.intern();}
public SortField (String field, boolean reverse) { this.field = field.intern(); this.reverse = reverse;}
public SortField (String field, int type) { this.field = (field != null) ? field.intern() : field; this.type = type;}
public SortField (String field, int type, boolean reverse) { this.field = (field != null) ? field.intern() : field; this.type = type; this.reverse = reverse;}
public SortField (String field, Locale locale) { this.field = field.intern(); this.type = STRING; this.locale = locale;}
public SortField (String field, Locale locale, boolean reverse) { this.field = field.intern(); this.type = STRING; this.locale = locale; this.reverse = reverse;}
public SortField (String field, SortComparatorSource comparator) { this.field = (field != null) ? field.intern() : field; this.type = CUSTOM; this.factory = comparator;}
public SortField (String field, SortComparatorSource comparator, boolean reverse) { this.field = (field != null) ? field.intern() : field; this.type = CUSTOM; this.reverse = reverse; this.factory = comparator;}
public String getField() { return field;}
public int getType() { return type;}
public Locale getLocale() { return locale;}
public boolean getReverse() { return reverse;}
public SortComparatorSource getFactory() { return factory;}
public String toString() { StringBuffer buffer = new StringBuffer(); switch (type) { case SCORE: buffer.append("<score>"); break;
case DOC: buffer.append("<doc>"); break;
case CUSTOM: buffer.append ("<custom:\"" + field + "\": " + factory + ">"); break;
default: buffer.append("\"" + field + "\""); break; }
if (locale != null) buffer.append ("("+locale+")"); if (reverse) buffer.append('!');
return buffer.toString();}}
从上面代码中,可以看出,指定了一种排序的type,这个type对排序的效率是至关重要的,涉及到一个比较的问题。从代码中:
private int type = AUTO;
指定了默认的类型,而AUTO定义如下:
public static final int AUTO = 2;
即按照整数类型,使用整数类型作为排序的type,在进行排序时,效率远远比String类型要高得多。
构造一个SortField实例之后,通过Sort类的setSort方法可以设定详细的排序规则,从而实现对检索结果的排序。
例如:
1、构造一个没有参数的Sort:Sort sort = new Sort();
2、构造一个SortField:SortField sf = new SortField("count",SortField.AUTO,true);
3、使用setSort方法:sort .setSort(sf);
4、构造一个检索器:IndexSearcher is = new IndexSearcher("F:\\index");
5、调用带Sort参数的search检索方法:Hits hits = is.search(query,sort);
这是一个最简单的设置排序的步骤,可以根据SortField的构造方法,构造更加复杂的排序规则。
