`
lxwt909
  • 浏览: 572689 次
  • 性别: 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  

相关推荐

    Lucene5学习之自定义Collector

    这篇博客“Lucene5学习之自定义Collector”显然聚焦于如何在Lucene 5版本中通过自定义Collector来优化搜索结果的收集过程。Collector是Lucene搜索框架中的一个重要组件,它负责在搜索过程中收集匹配的文档,并根据...

    lucene自定义排序实现

    因此,了解如何在 Lucene 中实现自定义排序是非常关键的。在这个话题中,我们将深入探讨如何根据特定的业务需求对搜索结果进行定制排序。 首先,我们要明白 Lucene 默认的排序机制。默认情况下,Lucene 搜索结果是...

    Lucene5学习之排序-Sort

    “Lucene5学习之排序-Sort”这个标题表明了我们要探讨的是关于Apache Lucene 5版本中的排序功能。Lucene是一个高性能、全文检索库,它提供了强大的文本搜索能力。在这个主题中,我们将深入理解如何在Lucene 5中对...

    Lucene5学习之Filter过滤器

    《深入理解Lucene5:Filter过滤器的奥秘》 在全文搜索引擎的开发过程中,Lucene作为一款强大的开源搜索引擎库,扮演着至关重要的角色。它提供了丰富的功能,使得开发者能够快速构建高效的搜索系统。其中,Filter...

    java Lucene 中自定义排序的实现

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

    lucene4.3 按坐标距离排序

    5. **Sorting**:在Lucene中,我们可以自定义排序规则,包括基于地理位置的距离排序。这可以通过实现`SortComparatorSource`接口来自定义比较器,或者使用`FieldComparatorSource`来创建一个基于特定字段(如地理...

    Lucene5学习之Group分组统计

    "Lucene5学习之Group分组统计" 这个标题指出我们要讨论的是关于Apache Lucene 5版本中的一个特定功能——Grouping。在信息检索领域,Lucene是一个高性能、全文搜索引擎库,而Grouping是它提供的一种功能,允许用户对...

    Lucene5学习之FunctionQuery功能查询

    **标题解析:** "Lucene5学习之FunctionQuery功能查询" Lucene5是Apache Lucene的一个版本,这是一个高性能、全文本搜索库,广泛应用于搜索引擎和其他需要高效文本检索的系统。FunctionQuery是Lucene中的一种查询...

    深入了解Lucene之三 排序算法.doc

    深入了解 Lucene 之三排序算法 Lucene 排序算法是搜索引擎中的核心组件之一,负责将搜索结果按照相关度排序以便用户快速找到所需信息。 Lucene 的排序算法主要基于 tf-idf 模型,以下是 Lucene 排序算法的详细介绍...

    lucene 自定义评分

    这样,Lucene 就会使用我们的自定义评分规则进行匹配和排序。 在实际应用中,可能还需要考虑其他因素,如用户偏好、文档质量、关键词位置等。这些都可以通过自定义相似度类中的方法来实现。例如,对于位置敏感的...

    lucene排序.zip

    本文将深入探讨Lucene如何根据关键词出现次数进行排序,以及如何实现自定义排序,包括处理`List&lt;Map&gt;`字段的情况,并结合项目中的`pom.xml`配置来解析这一过程。 首先,Lucene默认的排序方式是基于文档的相关性,即...

    Lucene5学习之TermVector项向量

    《Lucene5学习之TermVector项向量》 在深入理解Lucene5的搜索引擎功能时,TermVector(项向量)是一个关键的概念,它对于文本分析、信息检索和相关性计算等方面起着至关重要的作用。TermVector是Lucene提供的一种...

    Lucene3.3.0学习Demo

    **Lucene 3.3.0 学习Demo** Lucene是一个开源的全文搜索引擎库,由Apache软件基金会开发。在3.3.0版本中,Lucene提供了强大的文本搜索功能,包括分词、索引创建、查询解析和结果排序等。这个"Lucene3.3.0学习Demo...

    Lucene5学习之评分Scoring

    《Lucene5学习之评分Scoring》 在信息检索领域,Lucene是一个广泛使用的全文搜索引擎库,尤其在Java开发中应用颇广。在Lucene 5版本中,对于搜索结果的排序和评分机制进行了优化,使得搜索体验更加精准。本文将深入...

    Lucene5学习之CustomScoreQuery

    在Lucene5版本中,为了满足用户对查询结果评分的自定义需求,引入了`CustomScoreQuery`这一特性。本文将深入探讨`CustomScoreQuery`的概念、用途以及如何在实际应用中发挥其潜力。 首先,我们来了解什么是`...

    Lucene-2.0学习文档

    结合以上文件,我们可以看到Lucene-2.0的学习不仅需要理解基本的索引构建和搜索原理,还需要掌握如何自定义排序规则和分析器以满足特定需求。此外,通过阅读和分析这些源码,开发者还可以深入理解Lucene的内部工作...

Global site tag (gtag.js) - Google Analytics