天天看点

Lucene5学习之自定义排序

Lucene5学习之自定义排序

       对,没错我们只需要提供一个比较器即可,实现该接口重写相应方法即可。

Lucene5学习之自定义排序

/** 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),搜索附近最近的某家饭店。

Lucene5学习之自定义排序

    类似这样的场景,我们可以使用自定义排序实现,即返回的饭店需要按照距离当前地点远近排序,离的越近越靠前显示。即需要按照两个地点的距离排序,而给点的地点的坐标,排序需要的两点之间的距离与实际域的值需要一个转换过程,不能直接按照域的值进行排序,这时就不能按照默认排序也不能按照指定域排序了,我们需要一个数据转换过程,即计算两点之间的距离。

      下面是有关上面案例场景的示例代码:

Lucene5学习之自定义排序

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] + "";    

}  

Lucene5学习之自定义排序

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);  

Lucene5学习之自定义排序

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);    

    }    

   这是测试运行结果截图:

Lucene5学习之自定义排序

     ok,自定义排序就说完了,精华都在代码里,看代码运行测试例子去理解,如果代码有哪里看不懂,请联系我,demo源码一如既往的会上传到底下的附件里。

    群号: 

Lucene5学习之自定义排序

转载:http://iamyida.iteye.com/blog/2201372