`
lxwt909
  • 浏览: 565841 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Lucene5学习之自定义排序

阅读更多

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

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

/** 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;
	}

	@Override
	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) {
			return -1;
		}
		if (bottom > distance) {
			return 1;
		}
		return 0;
	}

	public int compareTop(int doc) throws IOException {
		float distance = getDistance(doc);
		if (top < distance) {
			return -1;
		}
		if (top > distance) {
			return 1;
		}
		return 0;
	}

	public void copy(int slot, int doc) throws IOException {
		//为values赋值
		values[slot] = getDistance(doc);  
	}

	@Override
	public void setTopValue(String value) {
		top = Float.valueOf(value);
	}

	@Override
	public String value(int slot) {
		return values[slot] + "";  
	}
}

    

package com.yida.framework.lucene5.sort.custom;

import java.io.IOException;

import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.search.FieldComparatorSource;
/**
 * 域比较器自定义ValueSource
 * @author Lanxiaowei
 *
 */
public class DistanceComparatorSource extends FieldComparatorSource {
	private  int x;  
    private int y;  
     
    public DistanceComparatorSource(int x,int y){  
        this.x = x;  
        this.y = y;  
    }

	@Override
	public FieldComparator<?> newComparator(String fieldname, int numHits,
			int sortPos, boolean reversed) throws IOException {
		return new DistanceSourceLookupComparator(fieldname, numHits,x,y);
	}
}

    

package com.yida.framework.lucene5.sort.custom;

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;
import org.apache.lucene.util.BytesRef;

/**
 * 自定义排序测试
 * @author Lanxiaowei
 *
 */
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源码一如既往的会上传到底下的附件里。

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

    群号: 

 

         

  • 大小: 145.7 KB
  • 大小: 232.3 KB
  • 大小: 727.9 KB
  • 大小: 6 KB
0
0
分享到:
评论
2 楼 世界杯2009 2016-03-15  
为毛位置不同,最后得分相同?
1 楼 青春的、脚步 2015-04-13  

相关推荐

    lucene自定义排序实现

    lucene自定义排序实现,大家有兴趣关注我的博客http://blog.csdn.net/wuyinggui10000/article/category/3173543

    java Lucene 中自定义排序的实现

    Lucene中的自定义排序功能和Java集合中的自定义排序的实现方法差不多,都要实现一下比较接口. 在Java中只要实现Comparable接口就可以了.但是在Lucene中要实现SortComparatorSource接口和ScoreDocComparator接口.在...

    lucene排序.zip

    Lucene根据关键词出现次数排序以及自定义排序,可以自定义优先级,包含list字段排序与pom等

    Lucene 3.6 学习笔记

    (5) 根据文件大小排序 36 (6) 根据日期排序 37 (7) 根据文件名排序(倒序) 37 (8) 多条件排序 38 5.2 搜索过滤 39 (1) 建立搜索类 39 (2) 文本域范围过滤(TermRangeFilter) 40 (3) 数字域范围过滤...

    lucene5.5demo

    一个简单的lucene demo,使用Lucene5.5+springmvc+mysql开发,包括索引的增删改查,查询中可以高亮显示+分页+自定义排序,有兴趣的朋友可以看看

    Lucene IndexApplication:使用lucene索引文本文档-开源

    按任何字段进行日期范围搜索和排序。 增量索引与批量索引一样快。 Quartz.NET 引擎,用于搜索索引服务的自定义作业调度。 自动和安排 Lucene 搜索索引的构建。 用于记录系统消息的通用日志框架。 您可以为严重和非...

    J2EE spring mvc mybatis bootstrap HTML5 后台框架 控制台 mysql版本_spring3.0

    菜单管理:增删改查菜单 ztree(自定义菜单)业务菜单和系统菜单分离 5. 数据字典:无限级别,支持多级别无限分类。内设编号,排序等 6. 系统设置:修改系统名称,邮件服务器配置,短信账号设置,图片水印配置,...

    J2EE spring mvc mybatis bootstrap HTML5 后台框架 控制台 oracle版本_spring3.0

    菜单管理:增删改查菜单 ztree(自定义菜单)业务菜单和系统菜单分离 5. 数据字典:无限级别,支持多级别无限分类。内设编号,排序等 6. 系统设置:修改系统名称,邮件服务器配置,短信账号设置,图片水印配置,...

    Hbase 二级索引方案

    在 Hbase 中,表的 RowKey 按照字典排序, Region 按照 RowKey 设置 split point 进行 shard, 通过这种方式实现的全局、分布式索引. 成为了其成功的最大的砝码。 然而单一的通过 RowKey 检索数据的方式,不再满足更多...

    大数据技术 Hadoop开发者第二期 MapReduce HDFS Hive Mahout HBase 共64页.pdf

    5、Java RMI + Lucene 构建分布式检索应用初探 ................ - 17 - 6、一对多的表关联在mapreduce中的应用(续) .................. - 26 - 7、InputSplit文件格式分析................................. - 32 -...

    hadoop开发者文档

    5、Java RMI + Lucene 构建分布式检索应用初探 ................ - 17 - 6、一对多的表关联在mapreduce中的应用(续) .................. - 26 - 7、InputSplit文件格式分析................................. - 32 -...

    minerva:计算机科学项目

    密涅瓦 计算机科学项目。 依赖关系 指南 Cross validation: $ java -cp liblinear-1.94.jar de.bwaldvogel.liblinear.Train -s 7 -v 10 ".scale file" ... 排名者包含用于对段落结果进行排序和重新排序的类

    NutzWk企业级开源开发框架

    NutzWk是基于Nutz的Java开源企业级开发框架。...5、添加数据字典及排序功能; 6、添加微信前台栏目和文章显示可关联微信菜单; 7、添加测试基类; 8、添加常用的Dao方法; 9、其他问题的解决及优化;

    Java EE常用框架.xmind

    5.PermissionsAuthorizationFilter对item:query 和从realm中获取权限进行对比,如果“item:query”在realm返回的权限列表中,授权通过。 6. realm中获取认证的信息,查询出该用户对应的权限,封装到...

    searchengineer:垂直搜索

    searchengineer 垂直搜索 实现了一个小型完整的搜索引擎系统...最后是搜索引擎的核心全文索引,了解了自定义的数据结构,数据类型,怎样以二进制的形式读写文本,怎样以utf-8编码形式存储文本,快速排序,二分查找的运用。

    word源码java-ElasticSearch-Simple-Share:组内关于ElasticSearch的简单使用说明内容分享

    自定义配置 集群内的原理 映射和分析 排序与相关性 实际使用中的Q&A 检索包含中文的关键字时返回结果不准确 中文分词器 字典 中文参数预处理 索引重建 Reindex API 索引别名实现零停机 检索关键字包含特殊字符 保留...

Global site tag (gtag.js) - Google Analytics