Lucene检索结果的排序问题、boost(激励因子)

转自:http://www.cnblogs.com/lvpei/articles/1732474.html

关于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的内部编号为 : 0
Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人>>
Document得分为 : 0.81767845
Explanation为 : 
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.81767845
Explanation的getDescription()为 : fieldWeight(contents:一人 in 0), product of:
********************************************************************
Document的内部编号为 : 3
Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 做事 一人当 一人做事一人当>>
Document得分为 : 0.5059127
Explanation为 : 
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.5059127
Explanation的getDescription()为 : fieldWeight(contents:一人 in 3), product of:
********************************************************************
Document的内部编号为 : 4
Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 做事 一人當 一人做事一人當>>
Document得分为 : 0.5059127
Explanation为 : 
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.5059127
Explanation的getDescription()为 : fieldWeight(contents:一人 in 4), product of:
********************************************************************
Document的内部编号为 : 1
Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 之交 一人之交>>
Document得分为 : 0.40883923
Explanation为 : 
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.40883923
Explanation的getDescription()为 : fieldWeight(contents:一人 in 1), product of:
********************************************************************
Document的内部编号为 : 2
Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 之下 一人之下>>
Document得分为 : 0.40883923
Explanation为 : 
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.40883923
Explanation的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的内部编号为 : 3
Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 做事 一人当 一人做事一人当>>
Document得分为 : 1.0
Explanation为 : 
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.0118254
Explanation的getDescription()为 : fieldWeight(contents:一人 in 3), product of:
********************************************************************
Document的内部编号为 : 4
Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 做事 一人當 一人做事一人當>>
Document得分为 : 0.5
Explanation为 : 
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.5059127
Explanation的getDescription()为 : fieldWeight(contents:一人 in 4), product of:
********************************************************************
Document的内部编号为 : 1
Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 之交 一人之交>>
Document得分为 : 0.40406102
Explanation为 : 
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.40883923
Explanation的getDescription()为 : fieldWeight(contents:一人 in 1), product of:
********************************************************************
Document的内部编号为 : 2
Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人 之下 一人之下>>
Document得分为 : 0.40406102
Explanation为 : 
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.40883923
Explanation的getDescription()为 : fieldWeight(contents:一人 in 2), product of:
********************************************************************
Document的内部编号为 : 0
Document内容为 : Document<stored/uncompressed,indexed,tokenized<contents:一人>>
Document得分为 : 0.075761445
Explanation为 : 
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.076657355
Explanation的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的内部编号为 : 3
Document内容为 : 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的内部编号为 : 1
Document内容为 : 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的内部编号为 : 2
Document内容为 : 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的内部编号为 : 4
Document内容为 : 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的内部编号为 : 0
Document内容为 : 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 SortField
implements 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 dynamically
private Locale locale;    // defaults to "natural order" (no Locale)
boolean reverse = false; // defaults to natural order
private SortComparatorSource factory;

// 下面定义了8种构造SortField的方法 

// 以一个Field的名字的Sing串作为参数构造一个SortField
public 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的构造方法,构造更加复杂的排序规则。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值