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

Lucene 中自定义排序的实现

阅读更多
使用Lucene来搜索内容,搜索结果的显示顺序当然是比较重要的.Lucene中Build-in的几个排序定义在大多数情况下是不适合我们使用的.要适合自己的应用程序的场景,就只能自定义排序功能,本节我们就来看看在Lucene中如何实现自定义排序功能.

Lucene中的自定义排序功能和Java集合中的自定义排序的实现方法差不多,都要实现一下比较接口. 在Java中只要实现Comparable接口就可以了.但是在Lucene中要实现SortComparatorSource接口和ScoreDocComparator接口.在了解具体实现方法之前先来看看这两个接口的定义吧.

SortComparatorSource接口的功能是返回一个用来排序ScoreDocs的comparator(Expert: returns a comparator for sorting ScoreDocs).该接口只定义了一个方法.如下:

Java代码 复制代码
  1. /**
  2. *Createsacomparatorforthefieldinthegivenindex.
  3. *@paramreader-Indextocreatecomparatorfor.
  4. *@paramfieldname-Fieldtocreatecomparatorfor.
  5. *@returnComparatorofScoreDocobjects.
  6. *@throwsIOException-Ifanerroroccursreadingtheindex.
  7. */
  8. publicScoreDocComparatornewComparator(IndexReaderreader,Stringfieldname)throwsIOException

该方法只是创造一个ScoreDocComparator 实例用来实现排序.所以我们还要实现ScoreDocComparator 接口.来看看ScoreDocComparator 接口.功能是比较来两个ScoreDoc 对象来排序(Compares two ScoreDoc objects for sorting) 里面定义了两个Lucene实现的静态实例.如下:

Java代码 复制代码
  1. //Specialcomparatorforsortinghitsaccordingtocomputedrelevance(documentscore).
  2. publicstaticfinalScoreDocComparatorRELEVANCE;
  3. //Specialcomparatorforsortinghitsaccordingtoindexorder(documentnumber).
  4. publicstaticfinalScoreDocComparatorINDEXORDER;

有3个方法与排序相关,需要我们实现 分别如下:

Java代码 复制代码
  1. /**
  2. *ComparestwoScoreDocobjectsandreturnsaresultindicatingtheirsortorder.
  3. *@paramiFirstScoreDoc
  4. *@paramjSecondScoreDoc
  5. *@return-1ifishouldcomebeforej;
  6. *1ifishouldcomeafterj;
  7. *0iftheyareequal
  8. */
  9. publicintcompare(ScoreDoci,ScoreDocj);
  10. /**
  11. *Returnsthevalueusedtosortthegivendocument.Theobjectreturnedmustimplementthejava.io.Serializableinterface.Thisisusedbymultisearcherstodeterminehowtocollateresultsfromtheirsearchers.
  12. *@paramiDocument
  13. *@returnSerializableobject
  14. */
  15. publicComparablesortValue(ScoreDoci);
  16. /**
  17. *Returnsthetypeofsort.ShouldreturnSortField.SCORE,SortField.DOC,SortField.STRING,SortField.INTEGER,SortField.FLOATorSortField.CUSTOM.ItisnotvalidtoreturnSortField.AUTO.Thisisusedbymultisearcherstodeterminehowtocollateresultsfromtheirsearchers.
  18. *@returnOneoftheconstantsinSortField.
  19. */
  20. publicintsortType();

看个例子吧!

该例子为Lucene in Action中的一个实现,用来搜索距你最近的餐馆的名字. 餐馆坐标用字符串"x,y"来存储.

Java代码 复制代码
  1. packagecom.nikee.lucene;
  2. importjava.io.IOException;
  3. importorg.apache.lucene.index.IndexReader;
  4. importorg.apache.lucene.index.Term;
  5. importorg.apache.lucene.index.TermDocs;
  6. importorg.apache.lucene.index.TermEnum;
  7. importorg.apache.lucene.search.ScoreDoc;
  8. importorg.apache.lucene.search.ScoreDocComparator;
  9. importorg.apache.lucene.search.SortComparatorSource;
  10. importorg.apache.lucene.search.SortField;
  11. //实现了搜索距你最近的餐馆的名字.餐馆坐标用字符串"x,y"来存储
  12. //DistanceComparatorSource实现了SortComparatorSource接口
  13. publicclassDistanceComparatorSourceimplementsSortComparatorSource{
  14. privatestaticfinallongserialVersionUID=1L;
  15. //xy用来保存坐标位置
  16. privateintx;
  17. privateinty;
  18. publicDistanceComparatorSource(intx,inty){
  19. this.x=x;
  20. this.y=y;
  21. }
  22. //返回ScoreDocComparator用来实现排序功能
  23. publicScoreDocComparatornewComparator(IndexReaderreader,Stringfieldname)throwsIOException{
  24. returnnewDistanceScoreDocLookupComparator(reader,fieldname,x,y);
  25. }
  26. //DistanceScoreDocLookupComparator实现了ScoreDocComparator用来排序
  27. privatestaticclassDistanceScoreDocLookupComparatorimplementsScoreDocComparator{
  28. privatefloat[]distances;//保存每个餐馆到指定点的距离
  29. //构造函数,构造函数在这里几乎完成所有的准备工作.
  30. publicDistanceScoreDocLookupComparator(IndexReaderreader,Stringfieldname,intx,inty)throwsIOException{
  31. System.out.println("fieldName2="+fieldname);
  32. finalTermEnumenumerator=reader.terms(newTerm(fieldname,""));
  33. System.out.println("maxDoc="+reader.maxDoc());
  34. distances=newfloat[reader.maxDoc()];//初始化distances
  35. if(distances.length>0){
  36. TermDocstermDocs=reader.termDocs();
  37. try{
  38. if(enumerator.term()==null){
  39. thrownewRuntimeException("notermsinfield"+fieldname);
  40. }
  41. inti=0,j=0;
  42. do{
  43. System.out.println("indo-while:"+i++);
  44. Termterm=enumerator.term();//取出每一个Term
  45. if(term.field()!=fieldname)//与给定的域不符合则比较下一个
  46. break;
  47. //SetsthistothedataforthecurrentterminaTermEnum.
  48. //Thismaybeoptimizedinsomeimplementations.
  49. termDocs.seek(enumerator);//参考TermDocsDoc
  50. while(termDocs.next()){
  51. System.out.println("inwhile:"+j++);
  52. System.out.println("inwhile,Term:"+term.toString());
  53. String[]xy=term.text().split(",");//去处xy
  54. intdeltax=Integer.parseInt(xy[0])-x;
  55. intdeltay=Integer.parseInt(xy[1])-y;
  56. //计算距离
  57. distances[termDocs.doc()]=(float)Math.sqrt(deltax*deltax+deltay*deltay);
  58. }
  59. }
  60. while(enumerator.next());
  61. }finally{
  62. termDocs.close();
  63. }
  64. }
  65. }
  66. //有上面的构造函数的准备这里就比较简单了
  67. publicintcompare(ScoreDoci,ScoreDocj){
  68. if(distances[i.doc]<distances[j.doc])
  69. return-1;
  70. if(distances[i.doc]>distances[j.doc])
  71. return1;
  72. return0;
  73. }
  74. //返回距离
  75. publicComparablesortValue(ScoreDoci){
  76. returnnewFloat(distances[i.doc]);
  77. }
  78. //指定SortType
  79. publicintsortType(){
  80. returnSortField.FLOAT;
  81. }
  82. }
  83. publicStringtoString(){
  84. return"Distancefrom("+x+","+y+")";
  85. }
  86. }


这是一个实现了上面两个接口的两个类, 里面带有详细注释, 可以看出 自定义排序并不是很难的. 该实现能否正确实现,我们来看看测试代码能否通过吧.

Java代码 复制代码
  1. packagecom.nikee.lucene.test;
  2. importjava.io.IOException;
  3. importjunit.framework.TestCase;
  4. importorg.apache.lucene.analysis.WhitespaceAnalyzer;
  5. importorg.apache.lucene.document.Document;
  6. importorg.apache.lucene.document.Field;
  7. importorg.apache.lucene.index.IndexWriter;
  8. importorg.apache.lucene.index.Term;
  9. importorg.apache.lucene.search.FieldDoc;
  10. importorg.apache.lucene.search.Hits;
  11. importorg.apache.lucene.search.IndexSearcher;
  12. importorg.apache.lucene.search.Query;
  13. importorg.apache.lucene.search.ScoreDoc;
  14. importorg.apache.lucene.search.Sort;
  15. importorg.apache.lucene.search.SortField;
  16. importorg.apache.lucene.search.TermQuery;
  17. importorg.apache.lucene.search.TopFieldDocs;
  18. importorg.apache.lucene.store.RAMDirectory;
  19. importcom.nikee.lucene.DistanceComparatorSource;
  20. publicclassDistanceComparatorSourceTestextendsTestCase{
  21. privateRAMDirectorydirectory;
  22. privateIndexSearchersearcher;
  23. privateQueryquery;
  24. //建立测试环境
  25. protectedvoidsetUp()throwsException{
  26. directory=newRAMDirectory();
  27. IndexWriterwriter=newIndexWriter(directory,newWhitespaceAnalyzer(),true);
  28. addPoint(writer,"ElCharro","restaurant",1,2);
  29. addPoint(writer,"CafePocaCosa","restaurant",5,9);
  30. addPoint(writer,"LosBetos","restaurant",9,6);
  31. addPoint(writer,"Nico'sTacoShop","restaurant",3,8);
  32. writer.close();
  33. searcher=newIndexSearcher(directory);
  34. query=newTermQuery(newTerm("type","restaurant"));
  35. }
  36. privatevoidaddPoint(IndexWriterwriter,Stringname,Stringtype,intx,inty)throwsIOException{
  37. Documentdoc=newDocument();
  38. doc.add(newField("name",name,Field.Store.YES,Field.Index.TOKENIZED));
  39. doc.add(newField("type",type,Field.Store.YES,Field.Index.TOKENIZED));
  40. doc.add(newField("location",x+","+y,Field.Store.YES,Field.Index.UN_TOKENIZED));
  41. writer.addDocument(doc);
  42. }
  43. publicvoidtestNearestRestaurantToHome()throwsException{
  44. //使用DistanceComparatorSource来构造一个SortField
  45. Sortsort=newSort(newSortField("location",newDistanceComparatorSource(0,0)));
  46. Hitshits=searcher.search(query,sort);//搜索
  47. //测试
  48. assertEquals("closest","ElCharro",hits.doc(0).get("name"));
  49. assertEquals("furthest","LosBetos",hits.doc(3).get("name"));
  50. }
  51. publicvoidtestNeareastRestaurantToWork()throwsException{
  52. Sortsort=newSort(newSortField("location",newDistanceComparatorSource(10,10)));//工作的坐标10,10
  53. //上面的测试实现了自定义排序,但是并不能访问自定义排序的更详细信息,利用
  54. //TopFieldDocs可以进一步访问相关信息
  55. TopFieldDocsdocs=searcher.search(query,null,3,sort);
  56. assertEquals(4,docs.totalHits);
  57. assertEquals(3,docs.scoreDocs.length);
  58. //取得FieldDoc利用FieldDoc可以取得关于排序的更详细信息请查看FieldDocDoc
  59. FieldDocfieldDoc=(FieldDoc)docs.scoreDocs[0];
  60. assertEquals("(10,10)->(9,6)=sqrt(17)",newFloat(Math.sqrt(17)),fieldDoc.fields[0]);
  61. Documentdocument=searcher.doc(fieldDoc.doc);
  62. assertEquals("LosBetos",document.get("name"));
  63. dumpDocs(sort,docs);//显示相关信息
  64. }
  65. //显示有关排序的信息
  66. privatevoiddumpDocs(Sortsort,TopFieldDocsdocs)throwsIOException{
  67. System.out.println("Sortedby:"+sort);
  68. ScoreDoc[]scoreDocs=docs.scoreDocs;
  69. for(inti=0;i<scoreDocs.length;i++){
  70. FieldDocfieldDoc=(FieldDoc)scoreDocs[i];
  71. Floatdistance=(Float)fieldDoc.fields[0];
  72. Documentdoc=searcher.doc(fieldDoc.doc);
  73. System.out.println(""+doc.get("name")+"@("+doc.get("location")+")->"+distance);
  74. }
  75. }
  76. }
分享到:
评论

相关推荐

    lucene自定义排序实现

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

    java Lucene 中自定义排序的实现

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

    Lucene5学习之自定义排序

    本文将深入探讨“Lucene5学习之自定义排序”这一主题,帮助你理解如何在Lucene5中实现自定义的排序规则。 首先,Lucene的核心功能之一就是提供高效的全文检索能力,但默认的搜索结果排序通常是基于相关度得分...

    lucene 自定义评分

    本文将深入探讨如何在 Lucene 中实现自定义评分,以及它对提高搜索质量的重要性。 在 Lucene 中,每个匹配文档都会有一个评分,这个评分通常基于 TF-IDF(词频-逆文档频率)算法,它是衡量一个词在文档中重要性的...

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

    Lucene 排序算法的实现主要在 DefaultSimilarity 类中,该类提供了 tf、idf、coord、queryNorm、norm 等方法来计算文档的分数。用户可以根据需要重写该类以实现自定义的排序算法。 在 Lucene 中,搜索结果的排序...

    lucene排序.zip

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

    lucene4.3 按坐标距离排序

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

    Lucene5学习之排序-Sort

    3. **自定义排序**:除了相关性,我们还可以根据文档的其他字段(如日期、价格等)进行排序。这需要定义`FieldComparatorSource`和`FieldComparator`,以实现自定义比较逻辑。 4. **SortField类型**:`SortField`...

    Lucene5学习之自定义Collector

    通过阅读这篇博客,读者应该能够了解到如何根据具体需求编写自定义的Collector,并将其应用到Lucene搜索中,从而提升搜索性能或实现特定的业务需求。同时,博主可能还会分享一些最佳实践和常见陷阱,帮助开发者避免...

    SSH + Lucene + 分页 + 排序 + 高亮 模拟简单新闻网站搜索引擎--data

    - 在SSH框架中,可以使用拦截器或者在Action中实现分页逻辑,结合Struts2的result标签展示分页链接。 4. 排序: - Lucene支持多种排序策略,如按照评分评分(Score排序),按照文档ID排序,或者根据自定义字段排序...

    Lucene4.7+IK Analyzer中文分词入门教程

    这里提供了一个简单的例子,包括一个`DataFactory`类,用于模拟存储药品信息,以及一个`LuceneIKUtil`类,用于实现Lucene索引和搜索功能。`DataFactory`包含了一个`List&lt;Medicine&gt;`,每个`Medicine`对象包含了药品ID...

    Lucene实现全文检索

    5. **分页和排序**:使用TopDocs和Sort对象,可以实现搜索结果的分页和自定义排序。 6. **实时更新**:通过NRT(Near Real Time)模式,Lucene能够在短时间内对索引进行更新并反映到搜索结果中。 **四、Lucene与...

    Lucene5学习之Filter过滤器

    总结起来,Lucene5中的Filter过滤器是实现精确、高效搜索的关键工具。通过理解并熟练运用各种Filter,开发者可以构建出更加灵活和精准的搜索系统。在深入研究源码和实践过程中,我们不仅能掌握Lucene的基本原理,还...

    Lucene group by ,分组实现

    "Lucene group by" 指的就是在 Lucene 中实现基于特定字段的分组操作,类似于 SQL 中的 GROUP BY 子句。这使得用户能够按类别聚合文档,例如,根据作者、日期或其他分类标准来查看搜索结果。 在 Lucene 中,分组...

    C#+Lucene.Net开发完成的一个自定义WEB搜索引擎

    本文将深入探讨如何使用C#编程语言和Lucene.Net库来开发一个自定义的Web搜索引擎,帮助开发者了解这个过程中的关键技术和概念。 **一、C#基础** C#是微软推出的一种面向对象的编程语言,它具有丰富的类库和强大的...

    Lucene-2.0学习文档

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

    lucene实现企业产品检索

    - **排序与评分**:根据相关性(如TF-IDF)对结果进行排序,可以自定义评分函数。 - **过滤与聚合**:通过Filter和QueryWrapperFilter实现特定条件筛选,如价格区间、品牌筛选等。 - **分页与翻页**:限制每次返回的...

Global site tag (gtag.js) - Google Analytics