- 浏览: 225282 次
- 性别:
- 来自: 深圳
文章分类
最新评论
使用Lucene来搜索内容,搜索结果的显示顺序当然是比较重要的.Lucene中Build-in的几个排序定义在大多数情况下是不适合我们使用的.要适合自己的应用程序的场景,就只能自定义排序功能,本节我们就来看看在Lucene中如何实现自定义排序功能.
Lucene中的自定义排序功能和Java集合中的自定义排序的实现方法差不多,都要实现一下比较接口. 在Java中只要实现Comparable接口就可以了.但是在Lucene中要实现SortComparatorSource接口和ScoreDocComparator接口.在了解具体实现方法之前先来看看这两个接口的定义吧.
SortComparatorSource接口的功能是返回一个用来排序ScoreDocs的comparator(Expert: returns a comparator for sorting ScoreDocs).该接口只定义了一个方法.如下:
- /**
- *Createsacomparatorforthefieldinthegivenindex.
- *@paramreader-Indextocreatecomparatorfor.
- *@paramfieldname-Fieldtocreatecomparatorfor.
- *@returnComparatorofScoreDocobjects.
- *@throwsIOException-Ifanerroroccursreadingtheindex.
- */
- publicScoreDocComparatornewComparator(IndexReaderreader,Stringfieldname)throwsIOException
/** * Creates a comparator for the field in the given index. * @param reader - Index to create comparator for. * @param fieldname - Field to create comparator for. * @return Comparator of ScoreDoc objects. * @throws IOException - If an error occurs reading the index. */ public ScoreDocComparator newComparator(IndexReader reader,String fieldname) throws IOException
该方法只是创造一个ScoreDocComparator 实例用来实现排序.所以我们还要实现ScoreDocComparator 接口.来看看ScoreDocComparator 接口.功能是比较来两个ScoreDoc 对象来排序(Compares two ScoreDoc objects for sorting) 里面定义了两个Lucene实现的静态实例.如下:
- //Specialcomparatorforsortinghitsaccordingtocomputedrelevance(documentscore).
- publicstaticfinalScoreDocComparatorRELEVANCE;
- //Specialcomparatorforsortinghitsaccordingtoindexorder(documentnumber).
- publicstaticfinalScoreDocComparatorINDEXORDER;
//Special comparator for sorting hits according to computed relevance (document score). public static final ScoreDocComparator RELEVANCE; //Special comparator for sorting hits according to index order (document number). public static final ScoreDocComparator INDEXORDER;
有3个方法与排序相关,需要我们实现 分别如下:
- /**
- *ComparestwoScoreDocobjectsandreturnsaresultindicatingtheirsortorder.
- *@paramiFirstScoreDoc
- *@paramjSecondScoreDoc
- *@return-1ifishouldcomebeforej;
- *1ifishouldcomeafterj;
- *0iftheyareequal
- */
- publicintcompare(ScoreDoci,ScoreDocj);
- /**
- *Returnsthevalueusedtosortthegivendocument.Theobjectreturnedmustimplementthejava.io.Serializableinterface.Thisisusedbymultisearcherstodeterminehowtocollateresultsfromtheirsearchers.
- *@paramiDocument
- *@returnSerializableobject
- */
- publicComparablesortValue(ScoreDoci);
- /**
- *Returnsthetypeofsort.ShouldreturnSortField.SCORE,SortField.DOC,SortField.STRING,SortField.INTEGER,SortField.FLOATorSortField.CUSTOM.ItisnotvalidtoreturnSortField.AUTO.Thisisusedbymultisearcherstodeterminehowtocollateresultsfromtheirsearchers.
- *@returnOneoftheconstantsinSortField.
- */
- publicintsortType();
/** * Compares two ScoreDoc objects and returns a result indicating their sort order. * @param i First ScoreDoc * @param j Second ScoreDoc * @return -1 if i should come before j; * 1 if i should come after j; * 0 if they are equal */ public int compare(ScoreDoc i,ScoreDoc j); /** * Returns the value used to sort the given document. The object returned must implement the java.io.Serializable interface. This is used by multisearchers to determine how to collate results from their searchers. * @param i Document * @return Serializable object */ public Comparable sortValue(ScoreDoc i); /** * Returns the type of sort. Should return SortField.SCORE, SortField.DOC, SortField.STRING, SortField.INTEGER, SortField.FLOAT or SortField.CUSTOM. It is not valid to return SortField.AUTO. This is used by multisearchers to determine how to collate results from their searchers. * @return One of the constants in SortField. */ public int sortType();
看个例子吧!
该例子为Lucene in Action中的一个实现,用来搜索距你最近的餐馆的名字. 餐馆坐标用字符串"x,y"来存储.
- packagecom.nikee.lucene;
- importjava.io.IOException;
- importorg.apache.lucene.index.IndexReader;
- importorg.apache.lucene.index.Term;
- importorg.apache.lucene.index.TermDocs;
- importorg.apache.lucene.index.TermEnum;
- importorg.apache.lucene.search.ScoreDoc;
- importorg.apache.lucene.search.ScoreDocComparator;
- importorg.apache.lucene.search.SortComparatorSource;
- importorg.apache.lucene.search.SortField;
- //实现了搜索距你最近的餐馆的名字.餐馆坐标用字符串"x,y"来存储
- //DistanceComparatorSource实现了SortComparatorSource接口
- publicclassDistanceComparatorSourceimplementsSortComparatorSource{
- privatestaticfinallongserialVersionUID=1L;
- //xy用来保存坐标位置
- privateintx;
- privateinty;
- publicDistanceComparatorSource(intx,inty){
- this.x=x;
- this.y=y;
- }
- //返回ScoreDocComparator用来实现排序功能
- publicScoreDocComparatornewComparator(IndexReaderreader,Stringfieldname)throwsIOException{
- returnnewDistanceScoreDocLookupComparator(reader,fieldname,x,y);
- }
- //DistanceScoreDocLookupComparator实现了ScoreDocComparator用来排序
- privatestaticclassDistanceScoreDocLookupComparatorimplementsScoreDocComparator{
- privatefloat[]distances;//保存每个餐馆到指定点的距离
- //构造函数,构造函数在这里几乎完成所有的准备工作.
- publicDistanceScoreDocLookupComparator(IndexReaderreader,Stringfieldname,intx,inty)throwsIOException{
- System.out.println("fieldName2="+fieldname);
- finalTermEnumenumerator=reader.terms(newTerm(fieldname,""));
- System.out.println("maxDoc="+reader.maxDoc());
- distances=newfloat[reader.maxDoc()];//初始化distances
- if(distances.length>0){
- TermDocstermDocs=reader.termDocs();
- try{
- if(enumerator.term()==null){
- thrownewRuntimeException("notermsinfield"+fieldname);
- }
- inti=0,j=0;
- do{
- System.out.println("indo-while:"+i++);
- Termterm=enumerator.term();//取出每一个Term
- if(term.field()!=fieldname)//与给定的域不符合则比较下一个
- break;
- //SetsthistothedataforthecurrentterminaTermEnum.
- //Thismaybeoptimizedinsomeimplementations.
- termDocs.seek(enumerator);//参考TermDocsDoc
- while(termDocs.next()){
- System.out.println("inwhile:"+j++);
- System.out.println("inwhile,Term:"+term.toString());
- String[]xy=term.text().split(",");//去处xy
- intdeltax=Integer.parseInt(xy[0])-x;
- intdeltay=Integer.parseInt(xy[1])-y;
- //计算距离
- distances[termDocs.doc()]=(float)Math.sqrt(deltax*deltax+deltay*deltay);
- }
- }
- while(enumerator.next());
- }finally{
- termDocs.close();
- }
- }
- }
- //有上面的构造函数的准备这里就比较简单了
- publicintcompare(ScoreDoci,ScoreDocj){
- if(distances[i.doc]<distances[j.doc])
- return-1;
- if(distances[i.doc]>distances[j.doc])
- return1;
- return0;
- }
- //返回距离
- publicComparablesortValue(ScoreDoci){
- returnnewFloat(distances[i.doc]);
- }
- //指定SortType
- publicintsortType(){
- returnSortField.FLOAT;
- }
- }
- publicStringtoString(){
- return"Distancefrom("+x+","+y+")";
- }
- }
package com.nikee.lucene; import java.io.IOException; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermDocs; import org.apache.lucene.index.TermEnum; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.ScoreDocComparator; import org.apache.lucene.search.SortComparatorSource; import org.apache.lucene.search.SortField; //实现了搜索距你最近的餐馆的名字. 餐馆坐标用字符串"x,y"来存储 //DistanceComparatorSource 实现了SortComparatorSource接口 public class DistanceComparatorSource implements SortComparatorSource { private static final long serialVersionUID = 1L; // x y 用来保存 坐标位置 private int x; private int y; public DistanceComparatorSource(int x, int y) { this.x = x; this.y = y; } // 返回ScoreDocComparator 用来实现排序功能 public ScoreDocComparator newComparator(IndexReader reader, String fieldname) throws IOException { return new DistanceScoreDocLookupComparator(reader, fieldname, x, y); } //DistanceScoreDocLookupComparator 实现了ScoreDocComparator 用来排序 private static class DistanceScoreDocLookupComparator implements ScoreDocComparator { private float[] distances; // 保存每个餐馆到指定点的距离 // 构造函数 , 构造函数在这里几乎完成所有的准备工作. public DistanceScoreDocLookupComparator(IndexReader reader, String fieldname, int x, int y) throws IOException { System.out.println("fieldName2="+fieldname); final TermEnum enumerator = reader.terms(new Term(fieldname, "")); System.out.println("maxDoc="+reader.maxDoc()); distances = new float[reader.maxDoc()]; // 初始化distances if (distances.length > 0) { TermDocs termDocs = reader.termDocs(); try { if (enumerator.term() == null) { throw new RuntimeException("no terms in field " + fieldname); } int i = 0,j = 0; do { System.out.println("in do-while :" + i ++); Term term = enumerator.term(); // 取出每一个Term if (term.field() != fieldname) // 与给定的域不符合则比较下一个 break; //Sets this to the data for the current term in a TermEnum. //This may be optimized in some implementations. termDocs.seek(enumerator); //参考TermDocs Doc while (termDocs.next()) { System.out.println(" in while :" + j ++); System.out.println(" in while ,Term :" + term.toString()); String[] xy = term.text().split(","); // 去处x y int deltax = Integer.parseInt(xy[0]) - x; int deltay = Integer.parseInt(xy[1]) - y; // 计算距离 distances[termDocs.doc()] = (float) Math.sqrt(deltax * deltax + deltay * deltay); } } while (enumerator.next()); } finally { termDocs.close(); } } } //有上面的构造函数的准备 这里就比较简单了 public int compare(ScoreDoc i, ScoreDoc j) { if (distances[i.doc] < distances[j.doc]) return -1; if (distances[i.doc] > distances[j.doc]) return 1; return 0; } // 返回距离 public Comparable sortValue(ScoreDoc i) { return new Float(distances[i.doc]); } //指定SortType public int sortType() { return SortField.FLOAT; } } public String toString() { return "Distance from (" + x + "," + y + ")"; } }
这是一个实现了上面两个接口的两个类, 里面带有详细注释, 可以看出 自定义排序并不是很难的. 该实现能否正确实现,我们来看看测试代码能否通过吧.
- packagecom.nikee.lucene.test;
- importjava.io.IOException;
- importjunit.framework.TestCase;
- importorg.apache.lucene.analysis.WhitespaceAnalyzer;
- importorg.apache.lucene.document.Document;
- importorg.apache.lucene.document.Field;
- importorg.apache.lucene.index.IndexWriter;
- importorg.apache.lucene.index.Term;
- importorg.apache.lucene.search.FieldDoc;
- importorg.apache.lucene.search.Hits;
- importorg.apache.lucene.search.IndexSearcher;
- importorg.apache.lucene.search.Query;
- importorg.apache.lucene.search.ScoreDoc;
- importorg.apache.lucene.search.Sort;
- importorg.apache.lucene.search.SortField;
- importorg.apache.lucene.search.TermQuery;
- importorg.apache.lucene.search.TopFieldDocs;
- importorg.apache.lucene.store.RAMDirectory;
- importcom.nikee.lucene.DistanceComparatorSource;
- publicclassDistanceComparatorSourceTestextendsTestCase{
- privateRAMDirectorydirectory;
- privateIndexSearchersearcher;
- privateQueryquery;
- //建立测试环境
- protectedvoidsetUp()throwsException{
- directory=newRAMDirectory();
- IndexWriterwriter=newIndexWriter(directory,newWhitespaceAnalyzer(),true);
- addPoint(writer,"ElCharro","restaurant",1,2);
- addPoint(writer,"CafePocaCosa","restaurant",5,9);
- addPoint(writer,"LosBetos","restaurant",9,6);
- addPoint(writer,"Nico'sTacoShop","restaurant",3,8);
- writer.close();
- searcher=newIndexSearcher(directory);
- query=newTermQuery(newTerm("type","restaurant"));
- }
- privatevoidaddPoint(IndexWriterwriter,Stringname,Stringtype,intx,inty)throwsIOException{
- Documentdoc=newDocument();
- doc.add(newField("name",name,Field.Store.YES,Field.Index.TOKENIZED));
- doc.add(newField("type",type,Field.Store.YES,Field.Index.TOKENIZED));
- doc.add(newField("location",x+","+y,Field.Store.YES,Field.Index.UN_TOKENIZED));
- writer.addDocument(doc);
- }
- publicvoidtestNearestRestaurantToHome()throwsException{
- //使用DistanceComparatorSource来构造一个SortField
- Sortsort=newSort(newSortField("location",newDistanceComparatorSource(0,0)));
- Hitshits=searcher.search(query,sort);//搜索
- //测试
- assertEquals("closest","ElCharro",hits.doc(0).get("name"));
- assertEquals("furthest","LosBetos",hits.doc(3).get("name"));
- }
- publicvoidtestNeareastRestaurantToWork()throwsException{
- Sortsort=newSort(newSortField("location",newDistanceComparatorSource(10,10)));//工作的坐标10,10
- //上面的测试实现了自定义排序,但是并不能访问自定义排序的更详细信息,利用
- //TopFieldDocs可以进一步访问相关信息
- TopFieldDocsdocs=searcher.search(query,null,3,sort);
- assertEquals(4,docs.totalHits);
- assertEquals(3,docs.scoreDocs.length);
- //取得FieldDoc利用FieldDoc可以取得关于排序的更详细信息请查看FieldDocDoc
- FieldDocfieldDoc=(FieldDoc)docs.scoreDocs[0];
- assertEquals("(10,10)->(9,6)=sqrt(17)",newFloat(Math.sqrt(17)),fieldDoc.fields[0]);
- Documentdocument=searcher.doc(fieldDoc.doc);
- assertEquals("LosBetos",document.get("name"));
- dumpDocs(sort,docs);//显示相关信息
- }
- //显示有关排序的信息
- privatevoiddumpDocs(Sortsort,TopFieldDocsdocs)throwsIOException{
- System.out.println("Sortedby:"+sort);
- ScoreDoc[]scoreDocs=docs.scoreDocs;
- for(inti=0;i<scoreDocs.length;i++){
- FieldDocfieldDoc=(FieldDoc)scoreDocs[i];
- Floatdistance=(Float)fieldDoc.fields[0];
- Documentdoc=searcher.doc(fieldDoc.doc);
- System.out.println(""+doc.get("name")+"@("+doc.get("location")+")->"+distance);
- }
- }
- }
相关推荐
lucene自定义排序实现,大家有兴趣关注我的博客http://blog.csdn.net/wuyinggui10000/article/category/3173543
Lucene中的自定义排序功能和Java集合中的自定义排序的实现方法差不多,都要实现一下比较接口. 在Java中只要实现Comparable接口就可以了.但是在Lucene中要实现SortComparatorSource接口和ScoreDocComparator接口.在...
NULL 博文链接:https://iamyida.iteye.com/blog/2201372
Lucene根据关键词出现次数排序以及自定义排序,可以自定义优先级,包含list字段排序与pom等
第一章 LUCENE基础 2 1.1 索引部分的核心类 2 1.2 分词部分的核心类 2 1.3 搜索部分的核心类 2 第二章 索引建立 3 2.1 创建Directory 3 2.2 创建Writer 3 2.3 创建文档并且添加索引 4 2.4 查询索引的基本信息 5 2.5 ...
一个简单的lucene demo,使用Lucene5.5+springmvc+mysql开发,包括索引的增删改查,查询中可以高亮显示+分页+自定义排序,有兴趣的朋友可以看看
Lucene 是一个非常流行且快速的搜索库,用于基于 Java 的应用程序中,以非常简单有效的方式为任何类型的应用程序添加文档搜索功能。 Lucene 功能:- 强大、准确且高效的搜索算法。 许多强大的查询类型:短语查询、...
在 Hbase 中,表的 RowKey 按照字典排序, Region 按照 RowKey 设置 split point 进行 shard, 通过这种方式实现的全局、分布式索引. 成为了其成功的最大的砝码。 然而单一的通过 RowKey 检索数据的方式,不再满足更多...
在Shiro中默认是使用ini文件去对比的,但我们开发往往是去数据库比较,因此我们需要自定义realm 自定义也很简单:继承AuthorizingRealm类就好了 自定义的realm支持散列算法 授权方式 编程式:通过写if...
searchengineer 垂直搜索 实现了一个小型完整的搜索引擎系统...最后是搜索引擎的核心全文索引,了解了自定义的数据结构,数据类型,怎样以二进制的形式读写文本,怎样以utf-8编码形式存储文本,快速排序,二分查找的运用。
自定义配置 集群内的原理 映射和分析 排序与相关性 实际使用中的Q&A 检索包含中文的关键字时返回结果不准确 中文分词器 字典 中文参数预处理 索引重建 Reindex API 索引别名实现零停机 检索关键字包含特殊字符 保留...
AutoTips基于搜索引擎Apache Lucene实现。AutoTips提供统一UI。 WAP浏览器 j2wap j2wap 是一个基于Java的WAP浏览器,目前处于BETA测试阶段。它支持WAP 1.2规范,除了WTLS 和WBMP。 Java注册表操作类 jared jared是...
AutoTips基于搜索引擎Apache Lucene实现。AutoTips提供统一UI。 WAP浏览器 j2wap j2wap 是一个基于Java的WAP浏览器,目前处于BETA测试阶段。它支持WAP 1.2规范,除了WTLS 和WBMP。 Java注册表操作类 jared jared是...
10、Mapreduce中value集合的二次排序 ....................... - 38 - 11、Hive SQL手册翻译 ................................... - 47 - 12、Mahout Kmeans简介 .................................... - 57 -
10、Mapreduce中value集合的二次排序 ....................... - 38 - 11、Hive SQL手册翻译 ................................... - 47 12、Mahout Kmeans简介 .................................... - 57 -
密涅瓦 计算机科学项目。 依赖关系 指南 Cross validation: $ java -cp liblinear-1.94.jar de.bwaldvogel.liblinear.Train -s 7 -v 10 ".scale file" ... 排名者包含用于对段落结果进行排序和重新排序的类
Java生成自定义控件源代码 2个目标文件 Java实现HTTP连接与浏览,Java源码下载 1个目标文件 摘要:Java源码,网络相关,HTTP Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件...
这样一来BIZOSS-CMS引入了自主研发的模板引擎技术、自定义标签功能,实现网站程序和界面分离的平台搭建效果,改变了传统的“功能开发→页面设计→整合”制作方式,达到降低人力成本的目的,当然我们内置的可视化编辑...
日历表格面板 [ConfigLine.java] 控制条类 [RoundBox.java] 限定选择控件 [MonthMaker.java] 月份表算法类 [Pallet.java] 调色板,统一配色类 Java扫雷源码 Java生成自定义控件源代码 2个目标文件 Java实现HTTP连接...