本文引言: 利用别人的东西写东西,最好看别人的源码! :shock: 思路最重要!
自定义排序思路:[b]继承FieldComparatorSource类并在此类的newComparator方法中返回一个FieldComparator类的子类[/b]
可以参考lucene的org.apache.lucene.search.FieldComparator.StringValComparator
类的源码,自己做做实验 就搞定啦!
背景:初始化自定义排序类的时候,其构造方法我这里有两个参数,但是可以有多个的,我们首先用总行数(总行数是我们自己设定的,
我们在TopDocs topDocs = indexSearcher.search(query, null, 3004, sort);这句话中 的第三个参数就是了。如果结果集总数小于我们设定的总个数,则按照结果集总数来确定)初始化values数组,用 Field的name值来初始化自定义排序类里面的field属性,这个属性lucene用来拿到相关的数据集
1、setNextReader : lucene首先会调用此方法进行数据的初始化,我们这里用一个String数组currentReaderValues来接收,当然也可以用其他的,如float,这个大家可以慢慢用FieldCache.DEFAULT.getStrings(reader, this.field);这句话来试。或者 直接debug 看看里面的东西,就OK! 看API描述 "Set a new Reader"
2、copy : 第一次将currentReaderValues里面的两个值拿出来,以后都是一个,然后放到values(注意初始时此数组的值都是null)中的指定位置上看API描述 "This method is called when a new hit is competitive"
3、compare :自定义排序 我们可以将我们的代码写到这里,看PAI描述" Compare hit at slot1 with hit at slot2." ,解释一下slot2 和 slot1 是索引文件中的索引号,注意slot1的值大于slot2的值,也就是说 val1为后一个的值,val2为前一个的值
看API描述 "Compare hit at slot1 with hit at slot2."
4、compareBottom :看API描述"Compare the bottom of the queue with doc." 这个方法lucene时候调用呢,从描述来看是doc序列的尾部,呵呵,自定义排序列中的bottom属性值就是,我们要拿出来的序列中最后面的那个。 流程是: 如果优先队列满了,则先和最低层的比较,如果大于最底层的则先替代最底层的,然后对优先队列重新排序 ,队列的最大值是 通过ndexSearcher.search方法中可以设置的,当然 lucene的队列的长度最大值 我看了 应该是 2亿多。所以不用担心了。那么对列什么时候满了呢?队列的最大值是什么呢?答案是: 队列的最大值 由用户自己设定,TopDocs topDocs = indexSearcher.search(query, null, 3004, sort);这句话中 的第三个参数就是了
package com;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.search.FieldComparatorSource;
//这里继承FieldComparatorSource类 ,然后返回DateValComparator的自定义子类,并传递两个参数
public class MySortComparatorSource extends FieldComparatorSource {
private static final long serialVersionUID = 1L;
@Override
public FieldComparator newComparator(String field, int allCounts,
int newCount, boolean reversed) throws IOException {
//打印出来大家就知道了
System.out.println(field);
System.out.println(allCounts);
System.out.println(newCount);
System.out.println(reversed);
//第一个参数是 总行数,第二个参数是 field的name值。就是需要比较的name值,例如 "createDate"
return new DateValComparator(allCounts, field);
}
}
//我们自定义排序类DateValComparator 继承FieldComparator 类实现里面的方法
final class DateValComparator extends FieldComparator {
private String[] values;
private String[] currentReaderValues;
private final String field;
private String bottom;
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
DateValComparator(int numHits, String field) {
this.values = new String[numHits];
this.field = field;
}
//第三步调用的比较方法,如果查询结果没有超过超过了我们设定的总行数那么会调用这个方法进行比较
public int compare(int slot1, int slot2) {
try {
Date val1 = format.parse(this.values[slot1]);
Date val2 = format.parse(this.values[slot2]);
if(null == val1) {
if(null == val2) {
return 0;
}
return -1;
}
if(null == val2) {
return 1;
}
if(val1.after(val2)) {
return 1;
}
if(val2.after(val1)) {
return -1;
}
} catch(Exception e) {
e.printStackTrace();
}
return 0;
}
//Lucene的查询结果是放在优先队列里面的,优先对象是通过compare进行比较,如果查询结果超过了我们设定的总行数那么会第二步调用这个方法
public int compareBottom(int doc) {
try {
Date val2 = format.parse(this.currentReaderValues[doc]);
Date tempBottom = format.parse(this.bottom);
if (tempBottom == null) {
if (val2 == null) {
return 0;
}
return -1;
}
if (val2 == null) {
return 1;
}
if(val2.after(tempBottom)) {
return 1;
}
if(tempBottom.after(val2)) {
return -1;
}
} catch(Exception e) {
e.printStackTrace();
}
return 0;
}
//第二步调用的方法,将currentReaderValues时间数组中的第一个值 copy到 values中对应的位置中,注意此方法第一次调用了两次
public void copy(int slot, int doc) {
this.values[slot] = this.currentReaderValues[doc];
}
// 第一步调用的方法: 本方法是得到所有搜索到的时间数组并初始化currentValues,docBase用来确定需要几个数组
public void setNextReader(IndexReader reader, int docBase) throws IOException {
this.currentReaderValues = FieldCache.DEFAULT.getStrings(reader, this.field);
}
//如果查询结果超过了我们设定的总行数那么会第一步调用这个方法
public void setBottom(int bottom) {
this.bottom = this.values[bottom];
}
//要输出的拍好序的结果集
public Comparable value(int slot) {
return this.values[slot];
}
}
最后在 lucene主方法中 引用一下就Ok,如下代码
//按照时间的正序排列,如果SortField的第三个参数为true , 则为倒序
SortField sortField = new SortField("createDate", new MySortComparatorSource(), true);
Sort sort = new Sort ();
sort.setSort(sortField);
TopDocs topDocs = indexSearcher.search(query, null, 1000, sort); //这里的第三个参数要注意,设定将要返回结果集的长度。
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
写的 很匆忙,,继续留个备用。。。 “唯有努力”