`
ForgiDaved
  • 浏览: 56674 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

lucence自定义搜索结果的排序代码分享

阅读更多
    最近做lucence的应用,趁着一个节点的间歇,总结了下lucence中有关自定义搜索结果排序的相关代码,一来和大家共同探讨,二来也便于备忘。
    众所周知,lucence默认的结果是根据Score从高到低,当Score相等时,则会根据建立索引时创建的docID由小到大排序。通过自定义搜索结果的排序,则可以实现完全按照真实业务的需要,自定义结果的排序。
    下面以一个查询餐馆距离的例子配合代码进行讲解(该例很多地方都有,但是我参考的时候发现很多地方提供的例子都是不能直接运行的)。并提供可以直接运行的例子代码如下:
    DistanceComparatorSource.java
package com.xxx.demo;

import java.io.IOException;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.search.FieldComparatorSource;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.FieldCache.IntParser;

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 DistanceScoreDocLookupComparator(fieldname,numHits);
	}
	
	private class DistanceScoreDocLookupComparator extends FieldComparator{
		private int[] xDoc,yDoc;
		private float[]  values;
		private float bottom;
		String fieldName;
	
		public DistanceScoreDocLookupComparator(String fieldName,int numHits){
			values = new float[numHits];
			this.fieldName = fieldName;
		}
		
		private class DistanceXIntParser implements IntParser{
			@Override
			public int parseInt(String string){
				return Integer.parseInt(string.split(",")[0]);
			}
			
		}

		private class DistanceYIntParser implements IntParser{
			@Override
			public int parseInt(String string){
				return Integer.parseInt(string.split(",")[1]);
			}
			
		}

		@Override
		public int compare(int slot1,int slot2){
			if(values[slot1]<values[slot2]) return -1;
			if(values[slot1]>values[slot2]) return 1;
			return 0;
		}

		@Override
		public int compareBottom(int doc) throws IOException{
			float docDistance = getDistance(doc); 
			if(bottom<docDistance) return -1;
			if(bottom>docDistance) return 1;
			return 0;
		}

		@Override
		public void copy(int slot,int doc) throws IOException{
			values[slot] = getDistance(doc);
		}

		@Override
		public void setBottom(int slot){
			bottom = values[slot];
		}

		@Override
		public void setNextReader(IndexReader reader,int docBase)
				throws IOException{
			xDoc = FieldCache.DEFAULT.getInts(reader,this.fieldName,new DistanceXIntParser());
			yDoc = FieldCache.DEFAULT.getInts(reader,this.fieldName,new DistanceYIntParser());
		}
		
		@Override
		public Float value(int slot){
			return new Float(values[slot]);
		}
		
		private float getDistance(int doc){
			int deltax = xDoc[doc] - x;
			int deltay = yDoc[doc] - y;
			return (float)Math.sqrt(deltax*deltax + deltay*deltay);
		}
		
		public int sortType(){
			return SortField.CUSTOM;
		}
	}
	
	public String toString(){
		return "Distance from ("+x+","+y+")";
	}

}

     DistanceSortingTest.java
package com.xxx.demo;

import java.io.IOException;

import junit.framework.TestCase;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.FieldDoc;
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.TopDocs;
import org.apache.lucene.search.TopFieldDocs;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;


public class DistanceSortingTest extends TestCase{
	private RAMDirectory directory;
	private IndexSearcher searcher ;
	private Query query;
	
	protected void setUp() throws Exception{
		directory = new RAMDirectory();
		IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_33,new StandardAnalyzer(Version.LUCENE_33));
		config.setOpenMode(OpenMode.CREATE);
		IndexWriter writer = new IndexWriter(directory,config);
		addPoint(writer,"El Charro","restaurant restaurant restaurant",1,2);//5
		addPoint(writer,"Cafe Poca Cosa","restaurant",5,9);//25+81=106
		addPoint(writer,"Los Betos","restaurant",9,6);//81+36=117
		addPoint(writer,"Nico's Taco Shop","restaurant restaurant",3,8);//9+64=73
		
		writer.close();
		
		searcher = new IndexSearcher(directory);
		QueryParser parser = new QueryParser(Version.LUCENE_33, "type", new StandardAnalyzer(Version.LUCENE_33));
		query = parser.parse("type:restaurant");
	}
	
	private void addPoint(IndexWriter writer,String name,String type,int x,int y) 
	throws CorruptIndexException, IOException{
		Document doc = new Document();
		doc.add(new Field("name",name,Field.Store.YES,Field.Index.ANALYZED));
		doc.add(new Field("type",type,Field.Store.YES,Field.Index.ANALYZED));
		doc.add(new Field("location",x+","+y,Field.Store.YES,Field.Index.NOT_ANALYZED));
		writer.addDocument(doc);
	}
	
	public void testNormRestaurant() throws IOException{
		TopDocs hits = searcher.search(query,10);
		System.out.println("--------testNormRestaurant---------- ");
		for(ScoreDoc doc : hits.scoreDocs){
			System.out.println("docId:"+doc.doc+"score:"+doc.score+", name:"+searcher.doc(doc.doc).get("name"));
		}
		assertEquals("first","Cafe Poca Cosa",searcher.doc(hits.scoreDocs[0].doc).get("name"));
		assertEquals("second","Los Betos",searcher.doc(hits.scoreDocs[1].doc).get("name"));
		assertEquals("third","Nico's Taco Shop",searcher.doc(hits.scoreDocs[2].doc).get("name"));
		assertEquals("forth","El Charro",searcher.doc(hits.scoreDocs[3].doc).get("name"));
	}
	
	public void testNearestRestaurantToHome() throws IOException{
		Sort sort = new Sort(new SortField("location",new DistanceComparatorSource(0,0)));
		TopDocs hits = searcher.search(query,null,10,sort);
		System.out.println("--------testNearestRestaurantToHome---------- ");
		for(ScoreDoc doc : hits.scoreDocs){
			System.out.println("docId:"+doc.doc+"name:"+searcher.doc(doc.doc).get("name"));
		}
		assertEquals("cloest","El Charro",searcher.doc(hits.scoreDocs[0].doc).get("name"));
		assertEquals("second","Nico's Taco Shop",searcher.doc(hits.scoreDocs[1].doc).get("name"));
		assertEquals("third","Cafe Poca Cosa",searcher.doc(hits.scoreDocs[2].doc).get("name"));
		assertEquals("furthest","Los Betos",searcher.doc(hits.scoreDocs[3].doc).get("name"));
	}
	
	public void testNearestRestaurantToWork() throws IOException{
		Sort sort = new Sort(new SortField("location",new DistanceComparatorSource(10,10)));
		TopFieldDocs docs = searcher.search(query,null,3,sort);
		assertEquals(4,docs.totalHits);
		assertEquals(3,docs.scoreDocs.length);
		
		FieldDoc fieldDoc = (FieldDoc)docs.scoreDocs[0];
		assertEquals("(10,10) -> (9,6) = sqrt(17)",new Float(Math.sqrt(17)),fieldDoc.fields[0]);
		
		Document document = searcher.doc(fieldDoc.doc);
		assertEquals("Los Betos", document.get("name"));
	}
}
分享到:
评论
2 楼 ForgiDaved 2012-01-30  
feizhang666 写道
代码没写全吧~~~

哥们,你是指哪里呢,我这个代码可是在我的机器上跑通了的,只是相应的jar包要自己导入。
1 楼 feizhang666 2012-01-07  
代码没写全吧~~~

相关推荐

    Lucence搜索

    7. **Filter**和**Collector**:用于进一步优化搜索结果,例如根据时间、地理位置等条件过滤,或自定义结果排序。 ### Lucene搜索技术Demo 在“LuceneIndexDemo”中,我们通常会经历以下步骤: 1. **初始化索引**...

    AJAX LUCENCE

    深入学习AJAX Lucene,你可以探索更多高级特性,如模糊搜索、短语搜索、过滤器、分页以及自定义排序算法。同时,理解JavaScript和Lucene的相关概念,如DOM操作、Promise、ES6语法、分析器和查询解析器,都将有助于你...

    lucene+nutch开发自己的搜索引擎一书源代码

    《lucene+nutch开发自己的搜索引擎一书源代码》是一份专为初学者设计的资源,旨在教授如何利用Apache Lucene和Nutch构建自定义搜索引擎。Lucene是Java编写的一个高性能全文检索库,而Nutch则是一个开源的网络爬虫...

    lucence in action 2nd Edtion 完整英文版

    5. **高级特性**:介绍如命中高亮、排序、 faceted search(分面搜索)、实时索引、分布式搜索等进阶主题,这些特性使得Lucene能应对更复杂的搜索需求。 6. **性能优化**:讨论如何提升搜索性能,包括索引优化、...

    Lucence资料大全

    Lucene的核心功能包括索引创建、搜索以及结果排序。其索引机制允许快速地对大量文本数据进行搜索,同时支持多种查询语法,提供丰富的搜索功能。通过使用倒排索引,Lucene可以高效地处理大规模文档的检索需求。 二、...

    lucene4.7 开发简单实例

    如果需要自定义排序规则,可以实现Comparator接口,对结果进行二次排序。 分页查询是大型数据集检索中常见的需求。通过设置TopDocs的skipTo()方法和setMaxDocs()方法,我们可以轻松实现分页。同时,Lucene还提供了...

    search-lucence-service

    4. **结果处理** - 处理返回的搜索结果,如排序、过滤和展示。 在Java中,Lucene提供了`Analyzer`类用于分词,`IndexWriter`类用于写入索引,`Directory`类用于存储索引,`QueryParser`类用于解析查询字符串,以及`...

    Lucene介绍,全文检索

    Lucene的灵活性允许开发者对其进行深入定制,如简化查询分析器、实现删除功能、自定义排序逻辑以及扩展应用接口。这些高级特性让Lucene能适应更广泛的需求场景。 **学习Lucene的收获** 学习Lucene不仅可以掌握全文...

    lucene4.3.0的使用

    它提供了一套完整的文本搜索功能,包括索引创建、文档存储、查询解析、排序等。在大数据时代,Lucene因其高效、灵活的特性而被广泛应用于企业级搜索解决方案中。 #### 二、Lucene 4.3.0的安装 1. **下载**:首先从...

    lucenceInAction 代码例子

    - 排序和评分:理解如何根据相关性对结果进行排序,以及如何自定义评分函数。 - 前向索引与倒排索引:了解这两种索引结构及其在搜索中的作用。 - 查询优化:如何通过缓存、近似搜索等手段提高查询性能。 通过这个...

    lucene可视化工具 Luck-6.5.0

    8. **代码友好**:Luck 作为一款开源工具,其源代码可供学习,开发者可以通过查看代码了解 Lucene 内部工作原理,甚至可以根据需要自定义功能。 在使用 Luck-6.5.0 压缩包时,你需要解压文件得到 "luke-6.5.0" ...

    Lucene如何使用TokenFilter进行再分词

    它提供了丰富的功能,包括文档索引、搜索、排序等。在Lucene中,为了提高搜索效率和精度,我们需要对输入的文本进行分词处理。而`TokenFilter`是Lucene中用于分词过滤的一个关键组件,它允许我们在分词过程中对原始...

    全文搜索lucene知识

    Lucene的核心功能包括文本分析、索引创建、查询解析以及搜索结果的排序。在本文中,我们将深入探讨Lucene 3.0版本的原理与代码分析。 ### 1. 文本分析 Lucene的文本分析过程是将输入的文本转换为可搜索的索引项。...

    lunence2.4例题

    4. **排序与评分**:学习如何根据文档的相关性(由`ScoreDoc`表示)进行排序,以及自定义排序策略。 5. **过滤与高亮**:使用`Filter`来限制搜索结果,以及`Highlighter`来突出显示匹配的搜索词。 6. **多字段搜索...

    LogSearch:使用Apache Lucene的Java日志搜索

    Lucene包含了从文本分析到结果排序的一系列功能,使得开发者无需从头开始构建复杂的搜索逻辑。 首先,要构建日志搜索系统,我们需要对日志数据进行预处理。这包括读取日志文件、解析日志格式(如JSON、CSV或自定义...

Global site tag (gtag.js) - Google Analytics