欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

lucene-使用自定义排序方法

程序员文章站 2022-05-15 16:03:45
...

计算基点与索引库中每个地理位置的距离,按距离大小排序。基点为(0,0),计算从(0,0)到地图中各个地方的距离,然后依此排序,但地方进行了分类,包括restaurant、school、shop。这些类放在一个type域中,

1、通过实现SortComparatorSource接口来完成自定义排序。对每个类分别完成计算基点到这些类的地方的距离

public class DistanceComparatorSource implementsSortComparatorSource{

private int x;

private int y;

publicDistanceComparatorSource(int x,int y){

this.x=x;

this.y=y;

}

//SortComparatorSource唯一需要实现的方法是newComparator

publicScoreDocComparator newComparator(IndexReader reader,Stringfieldname)

throwsIOException

{

//返回一个自定义比较器

return newDistanceScoreDocLookupComparator(reader,fieldname,x,y);

}

//lucene会负责对ScoreDocComparator对象存储,每个基点对应于一个比较器

privatestatic class DistanceScoreDocLookupComparator implements ScoreDocComparator{

final TermEnum enumerator=reader.terms(newTerm(filedname,""));//定义一个项枚举器

//,对reader的所有文档的坐标项进行迭代

distances=newfloat[reader.maxDoc()];//定义该基点与所有文档坐标项的距离数组

if (distances.length>0) {//保证至少有一个文档

TermDocstermDocs=reader.termDocs();//取出所有文档的项

try{

if (enumerator.term()==null){

throw new RuntimeException("no terms infield"+fieldname);

}

do{//开始计算距离数组

Term term=enumerator.term();

if (term.field()!=fieldname) break;

termDocs.seek(enumeartor);

while (termDocs.next()){

String[] xy=term.text().split(",");//从项值得出坐标

//计算,存储基点与该项坐标之间的距离

intdeltax=Integer.parseInt(xy[0])-x;

int deltay=Integer.parseInt(xy[1])-y;

 

distances[termDocs.doc()]=

(float) Math.sqrt(deltax*deltax_delay*deltay);

 

}//完成包含当前项的文档的遍历完成距离计算

}while(enumerator.next());//对指定域内的所有项进行遍历,笔者认为fieldname

//是指query中指定的域名,即这些地点的类型,因为地方可能至少要几种类

//型,所以要对域内的项进行遍历。

}fianlly{

termDocs.close();

}

}

}

public intcompare(){//调用完成排序

if (distances[i.doc]<distances[j.doc]) return-1;

if (distances[i.doc]>distances[j.doc]) return1;

return0;

}

publicComparable sortValue(ScoreDoc i){//输出确切的实际距离值

returnnew Float(distances[i.doc]);

}

public intsortType(){

return SortField.FLOAT;

}

}

public String toString(){

return "distance from("x","+y+")";

}

2、我们为每个地点都指定了三个域,即一个地名,一个用X和Y坐标表示的位置。

public class DistanceSortingTest extends tetstcase{

privateRAMDirectory directory;

privateIndexSearcher searcher;

privateQueryquery;

 

protectedvoid setUp() throws Exception{

directory=new RAMDirectory();

IndexWriter writer=new IndexWriter(directory,newWhitespaceAnalyzer(),true);

addPoint(writer,"E1 Charro","restaurant",1,2);

addPoint(writer,"cafe poca cosa","restaurant",5,9);

addPoint(writer,"os betos","restaurant",9,6);

addPoint(writer,"nico's tacoshop","restaurant",3,8);

writer.close();

searcher=newIndexSearcher(directory);

query=new TermQuery(new Term("type","restaurant"));

}

privatevoid addPoint(IndexWriter writer,String name,String type,int x,inty)

throws IOExceptoin{

Document doc=new Document();

doc.add(Field.Keyword("name",name));

doc.add(Field.Keyword("type",type));

doc.add(Field.Keyword("location",x+","+y));

}

}

下面进行测试

Sort sort=new Sort(newSortField("location",new DistanceComparatorSource(0,0)));

Hits hits=searcher.search(query,sort);

3、访问自定义排序的值

使用IndexSearcher的重载的search方法:

pulbic TopFieldDocs search(Query query,Filter filter,final intnDocs,Sort sort)

1)TopFieldDocs类中包括了HIts对象的总数,用来排序的SortField数组、FieldDoc对象的集合。FieldDoc封装了已经计算出来的原始评分、文档ID及Comparables集合,Comparable的值被每个SortField对象调用。

2)如果没有使用与排序相关的类,lucene为我们提供了类似的底层API,返回一个包含ScoreDoc对象的TopDocs对象。

3)

Sort sort=new Sort(newSortField("location",new DistanceComparatorSource(0,0)));

//指定返回的hit对象上限为3

TopFieldDocs docs=searcher.search(query,null,3,sort);

//hits对象的总数

assertEquals(4,docs.totalHits);//总数为4,因为要对所有hits进行评估找出3个最优的命中结果

assertEquals(3,docs.scoreDocs.length);//返回文档总数

FieldDoc fieldDoc=(FieldDoc)docs.scoreDocs[0];//获得排序值

assertEquals("(10,10)->(9,6)=sqrt(17)",newFloat(Math.sqrt(17)),fieldDoc.fields[0]);//断言距离最近的餐厅

Documentdocument=searcher.doc(fieldDoc.doc);//获得实际的文档

相关标签: lucene OS J#