lucene-使用自定义排序方法
计算基点与索引库中每个地理位置的距离,按距离大小排序。基点为(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-搜索过滤
推荐阅读
-
vue在自定义组件中使用v-model进行数据绑定的方法
-
html5的自定义data-*属性与jquery的data()方法的使用
-
Angularjs使用directive自定义指令实现attribute继承的方法详解
-
MySQL按常规排序、自定义排序和按中文拼音字母排序的方法
-
Element-ui tree组件自定义节点使用方法
-
CKeditor富文本编辑器使用技巧之添加自定义插件的方法
-
SpringBoot使用自定义json解析器的使用方法
-
基于python list对象中嵌套元组使用sort时的排序方法
-
vue使用自定义icon图标的方法
-
使用jquery.validate自定义方法教程实现手机号码或者固话至少填写一个的逻辑验证