Lucene5学习之自定义排序

简介:

         在Lucene5学习之排序-Sort中,我们已经学习了Sort的用法,已经了解了,Lucene搜索返回的命中结果默认是按照索引文档跟搜索关键字的相关度已经排序的,而相关度又是基于内部的打分机制和索引文档id,内部的打分机制则是根据Term的IDF-TF以及创建索引时Field的boost等决定的,默认是按照得分降序排序,得分相同再按docId升序排序。如果你觉得默认的排序方式满足不了你的需求,你可以设置SortField按照特定的域来排序,特定的域排序其实根据域的type类型去调用相应的compareTo方法来比较的,String,Long等都有对象的compareTo实现,其实SortField构造函数还有一个重载:

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

Java代码   收藏代码
  1. /** Creates a sort, possibly in reverse, with a custom comparison function. 
  2.    * @param field Name of field to sort by; cannot be <code>null</code>. 
  3.    * @param comparator Returns a comparator for sorting hits. 
  4.    * @param reverse True if natural order should be reversed. 
  5.    */  
  6.   public SortField(String field, FieldComparatorSource comparator, boolean reverse) {  
  7.     initFieldType(field, Type.CUSTOM);  
  8.     this.reverse = reverse;  
  9.     this.comparatorSource = comparator;  
  10.   }  

    这个构造重载多了一个reverse参数,设置为true即表示反转排序结果。默认不设置即为false.

 

    

 

    假如有这样一个案例:给定一个地点(x,y),搜索附近最近的某家饭店。

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

     

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

       

Java代码   收藏代码
  1. package com.yida.framework.lucene5.sort.custom;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.apache.lucene.index.BinaryDocValues;  
  6. import org.apache.lucene.index.LeafReaderContext;  
  7. import org.apache.lucene.search.SimpleFieldComparator;  
  8. import org.apache.lucene.util.BytesRef;  
  9. /** 
  10.  * 自定义排序器[按照两点距离远近进行比较] 
  11.  * @author Lanxiaowei 
  12.  * 
  13.  */  
  14. public class DistanceSourceLookupComparator extends  
  15.         SimpleFieldComparator<String> {  
  16.     private float[] values;  
  17.     private float top;  
  18.     private float bottom;  
  19.     private String fieldName;  
  20.   
  21.     private int x;  
  22.     private int y;  
  23.   
  24.     private BinaryDocValues binaryDocValues;  
  25.   
  26.     public DistanceSourceLookupComparator(String fieldName, int numHits, int x,  
  27.             int y) {  
  28.         values = new float[numHits];  
  29.         this.fieldName = fieldName;  
  30.         this.x = x;  
  31.         this.y = y;  
  32.     }  
  33.   
  34.     @Override  
  35.     public int compare(int slot1, int slot2) {  
  36.         if (values[slot1] > values[slot2]) {  
  37.             return 1;  
  38.         }  
  39.         if (values[slot1] < values[slot2]) {  
  40.             return -1;  
  41.         }  
  42.         return 0;  
  43.     }  
  44.   
  45.     /** 
  46.      * 求两点连线之间的距离[两点之间直线距离最短] 
  47.      *  
  48.      * @param doc 
  49.      * @return 
  50.      */  
  51.     private float getDistance(int doc) {  
  52.         BytesRef bytesRef = binaryDocValues.get(doc);  
  53.         String xy = bytesRef.utf8ToString();  
  54.         String[] array = xy.split(",");  
  55.         // 求横纵坐标差  
  56.         int deltax = Integer.parseInt(array[0]) - x;  
  57.         int deltay = Integer.parseInt(array[1]) - y;  
  58.         // 开平方根  
  59.         float distance = (float) Math.sqrt(deltax * deltax + deltay * deltay);  
  60.         //System.out.println(distance);  
  61.         return distance;  
  62.     }  
  63.   
  64.     @Override  
  65.     protected void doSetNextReader(LeafReaderContext context)  
  66.             throws IOException {  
  67.         binaryDocValues = context.reader().getBinaryDocValues(fieldName);  
  68.     }  
  69.   
  70.     public void setBottom(int slot) {  
  71.         bottom = values[slot];  
  72.     }  
  73.   
  74.     public int compareBottom(int doc) throws IOException {  
  75.         float distance = getDistance(doc);  
  76.         if (bottom < distance) {  
  77.             return -1;  
  78.         }  
  79.         if (bottom > distance) {  
  80.             return 1;  
  81.         }  
  82.         return 0;  
  83.     }  
  84.   
  85.     public int compareTop(int doc) throws IOException {  
  86.         float distance = getDistance(doc);  
  87.         if (top < distance) {  
  88.             return -1;  
  89.         }  
  90.         if (top > distance) {  
  91.             return 1;  
  92.         }  
  93.         return 0;  
  94.     }  
  95.   
  96.     public void copy(int slot, int doc) throws IOException {  
  97.         //为values赋值  
  98.         values[slot] = getDistance(doc);    
  99.     }  
  100.   
  101.     @Override  
  102.     public void setTopValue(String value) {  
  103.         top = Float.valueOf(value);  
  104.     }  
  105.   
  106.     @Override  
  107.     public String value(int slot) {  
  108.         return values[slot] + "";    
  109.     }  
  110. }  

    

Java代码   收藏代码
  1. package com.yida.framework.lucene5.sort.custom;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.apache.lucene.search.FieldComparator;  
  6. import org.apache.lucene.search.FieldComparatorSource;  
  7. /** 
  8.  * 域比较器自定义ValueSource 
  9.  * @author Lanxiaowei 
  10.  * 
  11.  */  
  12. public class DistanceComparatorSource extends FieldComparatorSource {  
  13.     private  int x;    
  14.     private int y;    
  15.        
  16.     public DistanceComparatorSource(int x,int y){    
  17.         this.x = x;    
  18.         this.y = y;    
  19.     }  
  20.   
  21.     @Override  
  22.     public FieldComparator<?> newComparator(String fieldname, int numHits,  
  23.             int sortPos, boolean reversed) throws IOException {  
  24.         return new DistanceSourceLookupComparator(fieldname, numHits,x,y);  
  25.     }  
  26. }  

    

Java代码   收藏代码
  1. package com.yida.framework.lucene5.sort.custom;  
  2.   
  3. import org.apache.lucene.analysis.Analyzer;  
  4. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  5. import org.apache.lucene.document.BinaryDocValuesField;  
  6. import org.apache.lucene.document.Document;  
  7. import org.apache.lucene.document.Field;  
  8. import org.apache.lucene.index.DirectoryReader;  
  9. import org.apache.lucene.index.IndexReader;  
  10. import org.apache.lucene.index.IndexWriter;  
  11. import org.apache.lucene.index.IndexWriterConfig;  
  12. import org.apache.lucene.index.IndexWriterConfig.OpenMode;  
  13. import org.apache.lucene.index.Term;  
  14. import org.apache.lucene.search.IndexSearcher;  
  15. import org.apache.lucene.search.Query;  
  16. import org.apache.lucene.search.ScoreDoc;  
  17. import org.apache.lucene.search.Sort;  
  18. import org.apache.lucene.search.SortField;  
  19. import org.apache.lucene.search.TermQuery;  
  20. import org.apache.lucene.search.TopFieldDocs;  
  21. import org.apache.lucene.store.RAMDirectory;  
  22. import org.apache.lucene.util.BytesRef;  
  23.   
  24. /** 
  25.  * 自定义排序测试 
  26.  * @author Lanxiaowei 
  27.  * 
  28.  */  
  29. public class CustomSortTest {  
  30.     public static void main(String[] args) throws Exception {  
  31.         RAMDirectory directory = new RAMDirectory();    
  32.         Analyzer analyzer = new StandardAnalyzer();  
  33.         IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);  
  34.         indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);  
  35.         IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);  
  36.         addPoint(indexWriter, "El charro""restaurant"12);    
  37.         addPoint(indexWriter, "Cafe Poca Cosa""restaurant"59);    
  38.         addPoint(indexWriter, "Los Betos""restaurant"96);    
  39.         addPoint(indexWriter, "Nico's Toco Shop""restaurant"38);    
  40.         indexWriter.close();    
  41.             
  42.         IndexReader reader = DirectoryReader.open(directory);  
  43.         IndexSearcher searcher = new IndexSearcher(reader);    
  44.         Query query = new TermQuery(new Term("type","restaurant"));    
  45.         Sort sort = new Sort(new SortField("location",new DistanceComparatorSource(1010)));    
  46.         TopFieldDocs topDocs = searcher.search(query, null, Integer.MAX_VALUE,sort,true,false);    
  47.         ScoreDoc[] docs = topDocs.scoreDocs;  
  48.         for(ScoreDoc doc : docs){  
  49.             Document document = searcher.doc(doc.doc);    
  50.             System.out.println(document.get("name") + ":" + doc.score);  
  51.         }  
  52.     }  
  53.       
  54.     private static void addPoint(IndexWriter writer,String name,String type,int x,int y) throws Exception{    
  55.         Document document = new Document();    
  56.         String xy = x + "," + y;  
  57.         document.add(new Field("name",name,Field.Store.YES,Field.Index.NOT_ANALYZED));    
  58.         document.add(new Field("type",type,Field.Store.YES,Field.Index.NOT_ANALYZED));    
  59.         document.add(new Field("location",xy,Field.Store.YES,Field.Index.NOT_ANALYZED));    
  60.         document.add(new BinaryDocValuesField("location"new BytesRef(xy.getBytes())));    
  61.         writer.addDocument(document);    
  62.     }    
  63. }  

   这是测试运行结果截图:


 

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

     哥的QQ: 7-3-6-0-3-1-3-0-5,欢迎加入哥的Java技术群一起交流学习。

    群号: 

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

目录
相关文章
|
6月前
|
算法 索引
一篇文章讲明白Lucene学习总结之九:Lucene的查询对象(2)
一篇文章讲明白Lucene学习总结之九:Lucene的查询对象(2)
26 0
|
自然语言处理 算法 Java
11Lucene相关度排序
11Lucene相关度排序
63 0
|
存储 自然语言处理 算法
Lucene学习总结
Lucene学习总结
107 0
Lucene学习总结
|
自然语言处理 索引 存储
|
索引
lucene Sort 文档排序
1.Sort org.apache.lucene.search.Sort 封装排序标准的类。 SortField[] org.apache.lucene.search.Sort.fields 字段。 org.apache.lucene.search.Sort.Sort(SortField field) 构造函数。按照指定的SortField进行排序。 org.apache.l
1279 0
|
Java 索引 机器学习/深度学习