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", 1, 2);    
  37.         addPoint(indexWriter, "Cafe Poca Cosa", "restaurant", 5, 9);    
  38.         addPoint(indexWriter, "Los Betos", "restaurant", 9, 6);    
  39.         addPoint(indexWriter, "Nico's Toco Shop", "restaurant", 3, 8);    
  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(10, 10)));    
  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

目录
相关文章
|
SQL 安全 UED
通义灵码在DBA日常SQL优化中的使用分享
通义灵码在DBA日常SQL优化中的使用分享
1194 1
通义灵码在DBA日常SQL优化中的使用分享
|
SQL 人工智能 自然语言处理
通义灵码2.5 | 一个更懂开发者的 AI 编程助手
通义灵码2.5版是一款强大的AI编程助手,具备智能体模式,支持自主决策、环境感知与工具使用等功能。通过工程检索、文件编辑和终端操作,可端到端完成编码任务,并深度适配Qwen3模型,大幅提升开发效率。新版新增行间建议预测、上下文分析及记忆功能,更懂开发者需求。智能体结合MCP工具,能实现从代码生成到部署的全流程自动化,如文中实例展示的数独小游戏开发与在线部署。无论是日常开发还是创意实现,通义灵码都能显著提升工作效率与能力边界。
|
缓存 人工智能 监控
通义灵码进阶指南:解锁智能编程的隐藏技能
通义灵码是阿里云推出的智能编程助手,已突破简单代码补全功能,成为全栈开发导航仪、架构思维催化剂、代码质量监督员和知识检索加速器。本文从基础到进阶,详细介绍了其高效操作技巧,包括精准生成、对话式编程、代码重构及技术文档交互等功能。同时提供团队级最佳实践、专家级配置指南及避坑建议,并展望未来实验性功能。通过将其视为“编程伙伴”,开发者可实现更高效的人机协作,优化工作流并提升生产力。
1245 6
|
人工智能 算法 关系型数据库
AI编码不是梦:手把手教你指挥Agent开发需求
AI编码不是梦:手把手教你指挥Agent开发需求
4021 24
|
存储 网络协议 Linux
Linux网络基础编程|学习笔记
快速学习Linux网络基础编程
Linux网络基础编程|学习笔记
|
索引
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
1472 0
|
14天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
6262 45
|
3天前
|
云安全 人工智能 安全
|
15天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
5167 61
|
9天前
|
Linux 开发工具 iOS开发
2026最新codex下载安装保姆级使用教程(下载+安装+登录+使用,含所有历史版本)
本文详解OpenAI Codex国内快速上手指南:提供Win/macOS/Linux全平台免安装包、npm/Homebrew等多方式安装、账号/API Key双登录、简体中文切换,覆盖下载、安装、汉化、使用及高频避坑(如微软商店失败、npm超时等),10分钟即可跑通。
2523 6

热门文章

最新文章