![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiInBnauMWYmN2MiJmYhVWYz0iMmBTYtczNlNTL3MzYk1yNhdDM3QjMi9CXzcDO08CX3ATMw8CX05WZth2YhRHdh9CXkF2bsBXdvwVbvNmLllXZ0lmLywGZvw1LcpDc0RHaiojIsJye.jpg)
对,没错我们只需要提供一个比较器即可,实现该接口重写相应方法即可。
/** creates a sort, possibly in reverse, with a custom comparison function.
* @param field name of field to sort by; cannot be <code>null</code>.
* @param comparator returns a comparator for sorting hits.
* @param reverse true if natural order should be reversed.
*/
public sortfield(string field, fieldcomparatorsource comparator, boolean reverse) {
initfieldtype(field, type.custom);
this.reverse = reverse;
this.comparatorsource = comparator;
}
这个构造重载多了一个reverse参数,设置为true即表示反转排序结果。默认不设置即为false.
假如有这样一个案例:给定一个地点(x,y),搜索附近最近的某家饭店。
类似这样的场景,我们可以使用自定义排序实现,即返回的饭店需要按照距离当前地点远近排序,离的越近越靠前显示。即需要按照两个地点的距离排序,而给点的地点的坐标,排序需要的两点之间的距离与实际域的值需要一个转换过程,不能直接按照域的值进行排序,这时就不能按照默认排序也不能按照指定域排序了,我们需要一个数据转换过程,即计算两点之间的距离。
下面是有关上面案例场景的示例代码:
package com.yida.framework.lucene5.sort.custom;
import java.io.ioexception;
import org.apache.lucene.index.binarydocvalues;
import org.apache.lucene.index.leafreadercontext;
import org.apache.lucene.search.simplefieldcomparator;
import org.apache.lucene.util.bytesref;
/**
* 自定义排序器[按照两点距离远近进行比较]
* @author lanxiaowei
*
*/
public class distancesourcelookupcomparator extends
simplefieldcomparator<string> {
private float[] values;
private float top;
private float bottom;
private string fieldname;
private int x;
private int y;
private binarydocvalues binarydocvalues;
public distancesourcelookupcomparator(string fieldname, int numhits, int x,
int y) {
values = new float[numhits];
this.fieldname = fieldname;
this.x = x;
this.y = y;
}
@override
public int compare(int slot1, int slot2) {
if (values[slot1] > values[slot2]) {
return 1;
}
if (values[slot1] < values[slot2]) {
return -1;
return 0;
/**
* 求两点连线之间的距离[两点之间直线距离最短]
*
* @param doc
* @return
*/
private float getdistance(int doc) {
bytesref bytesref = binarydocvalues.get(doc);
string xy = bytesref.utf8tostring();
string[] array = xy.split(",");
// 求横纵坐标差
int deltax = integer.parseint(array[0]) - x;
int deltay = integer.parseint(array[1]) - y;
// 开平方根
float distance = (float) math.sqrt(deltax * deltax + deltay * deltay);
//system.out.println(distance);
return distance;
protected void dosetnextreader(leafreadercontext context)
throws ioexception {
binarydocvalues = context.reader().getbinarydocvalues(fieldname);
public void setbottom(int slot) {
bottom = values[slot];
public int comparebottom(int doc) throws ioexception {
float distance = getdistance(doc);
if (bottom < distance) {
if (bottom > distance) {
public int comparetop(int doc) throws ioexception {
if (top < distance) {
if (top > distance) {
public void copy(int slot, int doc) throws ioexception {
//为values赋值
values[slot] = getdistance(doc);
public void settopvalue(string value) {
top = float.valueof(value);
public string value(int slot) {
return values[slot] + "";
}
import org.apache.lucene.search.fieldcomparator;
import org.apache.lucene.search.fieldcomparatorsource;
* 域比较器自定义valuesource
public class distancecomparatorsource extends fieldcomparatorsource {
private int x;
private int y;
public distancecomparatorsource(int x,int y){
this.x = x;
this.y = y;
public fieldcomparator<?> newcomparator(string fieldname, int numhits,
int sortpos, boolean reversed) throws ioexception {
return new distancesourcelookupcomparator(fieldname, numhits,x,y);
import org.apache.lucene.analysis.analyzer;
import org.apache.lucene.analysis.standard.standardanalyzer;
import org.apache.lucene.document.binarydocvaluesfield;
import org.apache.lucene.document.document;
import org.apache.lucene.document.field;
import org.apache.lucene.index.directoryreader;
import org.apache.lucene.index.indexreader;
import org.apache.lucene.index.indexwriter;
import org.apache.lucene.index.indexwriterconfig;
import org.apache.lucene.index.indexwriterconfig.openmode;
import org.apache.lucene.index.term;
import org.apache.lucene.search.indexsearcher;
import org.apache.lucene.search.query;
import org.apache.lucene.search.scoredoc;
import org.apache.lucene.search.sort;
import org.apache.lucene.search.sortfield;
import org.apache.lucene.search.termquery;
import org.apache.lucene.search.topfielddocs;
import org.apache.lucene.store.ramdirectory;
* 自定义排序测试
public class customsorttest {
public static void main(string[] args) throws exception {
ramdirectory directory = new ramdirectory();
analyzer analyzer = new standardanalyzer();
indexwriterconfig indexwriterconfig = new indexwriterconfig(analyzer);
indexwriterconfig.setopenmode(openmode.create_or_append);
indexwriter indexwriter = new indexwriter(directory, indexwriterconfig);
addpoint(indexwriter, "el charro", "restaurant", 1, 2);
addpoint(indexwriter, "cafe poca cosa", "restaurant", 5, 9);
addpoint(indexwriter, "los betos", "restaurant", 9, 6);
addpoint(indexwriter, "nico's toco shop", "restaurant", 3, 8);
indexwriter.close();
indexreader reader = directoryreader.open(directory);
indexsearcher searcher = new indexsearcher(reader);
query query = new termquery(new term("type","restaurant"));
sort sort = new sort(new sortfield("location",new distancecomparatorsource(10, 10)));
topfielddocs topdocs = searcher.search(query, null, integer.max_value,sort,true,false);
scoredoc[] docs = topdocs.scoredocs;
for(scoredoc doc : docs){
document document = searcher.doc(doc.doc);
system.out.println(document.get("name") + ":" + doc.score);
private static void addpoint(indexwriter writer,string name,string type,int x,int y) throws exception{
document document = new document();
string xy = x + "," + y;
document.add(new field("name",name,field.store.yes,field.index.not_analyzed));
document.add(new field("type",type,field.store.yes,field.index.not_analyzed));
document.add(new field("location",xy,field.store.yes,field.index.not_analyzed));
document.add(new binarydocvaluesfield("location", new bytesref(xy.getbytes())));
writer.adddocument(document);
}
这是测试运行结果截图:
ok,自定义排序就说完了,精华都在代码里,看代码运行测试例子去理解,如果代码有哪里看不懂,请联系我,demo源码一如既往的会上传到底下的附件里。
群号:
转载:http://iamyida.iteye.com/blog/2201372