`
weitao1026
  • 浏览: 1034614 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Lucene的几种评分方式

阅读更多
介绍的Lucene的几种评分方式,大部分的时候都能满足我们的大多数业务场景,但有些场合下可能我们使用另外一种评分策略,会更加灵活一点,上次介绍的评分主要是围绕着DefaultSimilarity这个类来介绍的,其实这个类控制评分的方式更加倾向于底层控制,而散仙下文要介绍的CustomScoreQuery这个类,则更加倾向于应用层面的控制。


为什么,有时候我们需要借助这个类来完成评分呢?
可能有时候我们会遇到如下类似的需求:
在一份论坛的索引里面有帖子的标题和帖子发布的日期(为了简化程序,假设按年来记录的),这个时候有如下需求,要求我们检索标题时,不仅要检索出与关键词最相关的帖子,而且还得是年份距现在相距不远的帖子,进行提拔加权,综上所述,这里面有2个关键因素,第一内容相关,
第二,近期时间的日期拥有的更高的加权。可以看出那么这个文档的评分是要结合这两个因素来完成最后的总的评分。

到这里可能有些人就会有疑问,为什么不对检索完的内容,按时间排序降序排序呢,这里可能会出现一个问题,如果是硬性的按时间降序排序,可能会破坏评分机制,因为默认的排序是按照评分降序排的,如果按照时间排序可能就会破坏原有的顺序,所以这个时候就需要我们统一下方式,要么用评分的方式来解决问题,那么用排序的问题来解决,显然统一评分的方式会更加适合这个场景。

测试的数据如下:

Java代码 复制代码 收藏代码
1.Document doc=new Document();         
2.        doc.add(new StringField("id", "1", Store.YES)); 
3.        doc.add(new TextField("name", "中国是一个多民族国家", Store.YES)); 
4.        doc.add(new IntField("date", 2012, Store.NO)); 
5.        writer.addDocument(doc); 
6.                 
7.        doc=new Document(); 
8.         
9.        doc.add(new StringField("id", "2", Store.YES)); 
10.        doc.add(new TextField("name", "伟大的人啊", Store.YES)); 
11.        doc.add(new IntField("date", 2013, Store.NO)); 
12.        writer.addDocument(doc); 
13.                 
14.        doc=new Document(); 
15.         
16.        doc.add(new StringField("id", "3", Store.YES)); 
17.        doc.add(new TextField("name", "伟大的祖国", Store.YES)); 
18.        doc.add(new IntField("date", 2010, Store.NO)); 
19.        writer.addDocument(doc); 


没采用自定义评分的时候检索结果:

Java代码 复制代码 收藏代码
1.2    伟大的人啊    0.5 
2.3    伟大的祖国    0.5 


我们可以采取两种方式,来完成这个方式,下面看第一种方式:基于CustomScoreProvider的方式, 我们统一对2010年的帖子加权为2,默认是与原来的评分是相乘的关系,代码如下:



Java代码 复制代码 收藏代码
1.package com.qin.lucene20140123; 
2. 
3.import java.io.IOException; 
4. 
5.import org.apache.lucene.index.AtomicReaderContext; 
6.import org.apache.lucene.queries.CustomScoreProvider; 
7.import org.apache.lucene.search.FieldCache; 
8.import org.apache.lucene.search.FieldCache.Ints; 
9.import org.apache.lucene.search.similarities.DefaultSimilarity; 
10. 
11. 
12./**
13. * @author 秦东亮
14. * Lucene技术交流群:324714439
15. * 实现评分提供的方式
16. * **/ 
17.public class MyScoreProvider extends CustomScoreProvider { 
18.    AtomicReaderContext reader=null; 
19.    public MyScoreProvider(AtomicReaderContext context) { 
20.        super(context); 
21.        reader=context; 
22.         
23.        // TODO Auto-generated constructor stub 
24.    } 
25. 
26.     
27.    @Override 
28.    public float customScore(int doc, float subQueryScore, float valSrcScore) 
29.            throws IOException { 
30.      
31.        //FieldCache.DEFAULT.getTerms(reader.reader(), "date"); 
32.        //从域缓存里面加载索引字段的信息 
33.      Ints ints=FieldCache.DEFAULT.getInts(reader.reader(), "date", false); 
34.       
35.       int date=ints.get(doc); 
36.       
37.       float ss=1;//判断加权  
38.       if(date==2010){ 
39.           ss=2; 
40.       } 
41.       
42.        /*
43.         * 通过得分相乘放大分数
44.         * 此处可以控制与原有得分结合的方式,加减乘除都可以
45.         * **/ 
46.        return  subQueryScore*valSrcScore*ss; 
47.    } 
48.     
49. 
50.     
51.     
52.} 


然后我们继承CustomScoreQuery,引用上文,我们定义的评分提供者,代码如下:



Java代码 复制代码 收藏代码
1.package com.qin.lucene20140123; 
2. 
3.import java.io.IOException; 
4. 
5.import org.apache.lucene.index.AtomicReaderContext; 
6.import org.apache.lucene.queries.CustomScoreProvider; 
7.import org.apache.lucene.queries.CustomScoreQuery; 
8.import org.apache.lucene.search.Query; 
9./**
10. * 重写CustomScoreQuery
11. * 的CustomScoreProvider方法
12. * 引用我们自己的Provider
13. * 
14. * **/ 
15.public class MyQuery extends CustomScoreQuery { 
16. 
17.    public MyQuery(Query subQuery) { 
18.        super(subQuery); 
19.          
20.        // TODO Auto-generated constructor stub 
21.    } 
22.     
23.     
24.     
25.     
26.     
27.    @Override 
28.    protected CustomScoreProvider getCustomScoreProvider( 
29.            AtomicReaderContext context) throws IOException { 
30.          
31.         
32.        /**
33.         * 自定义的评分provider
34.         * 
35.         * **/ 
36.        return new MyScoreProvider(context); 
37.    } 
38.     
39.     
40.     
41.     
42.     
43.     
44. 
45.} 


最后,在检索的时候,使用我们自定义的的评分query,代码如下:



Java代码 复制代码 收藏代码
1.QueryParser p=new QueryParser(Version.LUCENE_44, "name", new IKAnalyzer(true)); 
2.   Query query=p.parse(temp); 
3.MyQuery myq=new MyQuery(query); 
4.   TopDocs top=searcher.search(myq, 10); 



此时的检索结果和我们预期的一样:



Java代码 复制代码 收藏代码
1.3    伟大的祖国    1.0 
2.2    伟大的人啊    0.5 



下面散仙,介绍第二种方式基于FunctionQuery的方式,这种方式需要我们自己重写ValueSource,来完成,代码如下:



Java代码 复制代码 收藏代码
1.package com.qin.lucene20140123; 
2. 
3.import java.io.IOException; 
4.import java.util.Map; 
5. 
6.import org.apache.lucene.index.AtomicReaderContext; 
7.import org.apache.lucene.queries.function.FunctionValues; 
8.import org.apache.lucene.queries.function.ValueSource; 
9.import org.apache.lucene.queries.function.docvalues.FloatDocValues; 
10.import org.apache.lucene.search.FieldCache; 
11.import org.apache.lucene.search.FieldCache.Ints; 
12. 
13./**
14. * 
15. * @author 秦东亮
16. * 
17. * 重写ValueSource
18. * 返回外部的加权方式
19. * 
20. * 
21. * **/ 
22.public class ScoreFunction extends ValueSource { 
23. 
24.     
25.     
26.      
27. 
28.    @Override 
29.    public FunctionValues getValues(Map arg0, final AtomicReaderContext arg1) 
30.            throws IOException { 
31.          
32.         
33.         
34.        return new FloatDocValues(this) { 
35.             
36.             
37.            @Override 
38.            public float floatVal(int doc) { 
39.              float s=1; 
40.                try { 
41.                    /**
42.                     * 从域缓存里面
43.                     * 读取所需数据
44.                     * 
45.                     * */ 
46.                    Ints ints=FieldCache.DEFAULT.getInts(arg1.reader(),"date", false); 
47.                     
48.                     
49.                    int a=ints.get(doc); 
50.                    /**
51.                     * 对2010加权
52.                     * 
53.                     * */ 
54.                    if(a==2010){ 
55.                        s=2; 
56.                    } 
57.                } catch (IOException e) { 
58.                    // TODO Auto-generated catch block 
59.                    e.printStackTrace(); 
60.                } 
61.                 
62.                return s; 
63.            } 
64.        }; 
65.    } 
66. 
67.    @Override 
68.    public int hashCode() { 
69.        // TODO Auto-generated method stub 
70.        return 0; 
71.    } 
72. 
73.    @Override 
74.    public String description() { 
75.        // TODO Auto-generated method stub 
76.        return null; 
77.    } 
78. 
79.    @Override 
80.    public boolean equals(Object arg0) { 
81.        // TODO Auto-generated method stub 
82.        return false; 
83.    } 
84.     
85.     
86.     
87. 
88.} 


然后,在检索时,就可以构造我们自己的自定义评分了,
核心代码如下:



Java代码 复制代码 收藏代码
1.QueryParser p=new QueryParser(Version.LUCENE_44, "name", new IKAnalyzer(true)); 
2.        Query query=p.parse(temp); 
3.        /*
4.         * 
5.         * 引用自己的
6.         * 评分query
7.         * **/ 
8.         CustomScoreQuery csq=new CustomScoreQuery(query,new FunctionQuery(new ScoreFunction())); 
9.        TopDocs top=searcher.search(csq, 10); 



基于上次同样的检索条件,打印输出结果如下:



Java代码 复制代码 收藏代码
1.3    伟大的祖国    0.49999997 
2.2    伟大的人啊    0.24999999 



除了,得分方式的不一样,我们发现对结果的排序都是一样的,由此,我们可以灵活选择我们所需要的方式,来完成我们的业务。
分享到:
评论

相关推荐

    lucene3源码分析

    Lucene的索引文件格式是其高效检索性能的基础,主要包括以下几个方面: - **基本概念**:介绍Lucene索引文件的基本术语和概念。 - **基本类型**:定义了索引文件中使用的数据类型。 - **基本规则**:阐述了文件格式...

    lucene源码和程序

    在Lucene中,主要涉及以下几个核心概念: 1. **文档(Document)**:在Lucene中,文档是信息的基本单位,可以代表网页、电子邮件或者其他形式的数据。文档由一系列字段(Field)组成,每个字段有名称和内容,比如...

    lucene自定义排序实现

    在 Lucene 中,实现自定义排序主要有两种方式: 1. **FieldCache排序**:这是最简单的方法,适用于基于文档字段值的排序。你需要在索引时为需要排序的字段创建一个专用的“排序字段”,并确保其存储(stored)和可...

    lucene原理与代码分析完整版

    索引过程是Lucene的核心功能之一,主要包括以下几个步骤: 1. **文档解析**:将原始文档转换为Lucene能够处理的格式。 2. **分词**:将文档内容分解成一系列单词或词组。 3. **规范化**:对分词结果进行标准化处理...

    LUCENE的搜索引擎例子

    2. **索引存储**:索引构建完成后,Lucene会将其保存到磁盘上,形成一种倒排索引结构,便于快速查找包含特定词汇的文档。索引文件包括字段信息、词典、Posting List等。 3. **查询处理**:当用户在前端输入查询时,...

    Lucene索引和查询

    - 匹配评分(Scoring):Lucene使用TF-IDF(Term Frequency-Inverse Document Frequency)或其他评分算法,计算每个文档与查询的相关性。 - 结果排序(Sorting):根据评分对匹配到的文档进行排序,返回最相关的文档...

    一个非常好的检测lucene索引库的工具

    Lucene支持多种操作,如创建、更新和删除索引,以及复杂的查询语法,这个工具可能是为了辅助这些操作,提供一种便捷的方式来诊断可能出现的问题。 至于“压缩包子文件的文件名称列表”中提到的“lucene tool”,这...

    lucene学习总结

    Lucene的索引文件主要包括以下几个部分: - **段(Segment)**:是Lucene的基本存储单元,每个段包含一组文档和对应的倒排索引。段是不可变的,新的文档会被添加到新的段中,旧的段会被合并以优化存储和检索效率。 ...

    lucene演示需要的数据

    5. **评分和排序**:Lucene根据相关性对匹配结果进行评分,并根据分数进行排序,以便用户得到最相关的搜索结果。 6. **更新和删除**:Lucene支持对已有索引的文档进行更新和删除操作,以保持数据的实时性。 综上所...

    Lucene5学习之拼音搜索

    4. **评分与排序**:为了提供准确的搜索结果,Lucene会根据匹配度对结果进行评分,并按评分高低进行排序。拼音搜索时,可以结合汉字和拼音的匹配情况来计算评分。 5. **优化**:为了提升性能,可以采用一些优化策略...

    Lucene.Net 实现全文检索

    搜索结果通常按照相关性排序,相关性由 Lucene.Net 内部的评分算法计算得出。 5. **结果展示**:最后,将搜索结果以用户友好的方式呈现出来,可以是列表形式,包括匹配的文档标题、摘要等信息。 在整个过程中,还...

    搜索引擎的搭建(Lucene)代码

    在IT领域,搜索引擎的搭建是一项复杂而重要的任务,它涉及到数据的索引、查询和检索。本篇将重点讨论如何使用Java和Lucene库来构建一个基础的...记住,实践是检验理论的最好方式,动手操作才能真正掌握Lucene的精髓。

    基于Lucene的中型搜索引擎(C#)

    总的来说,基于Lucene的中型搜索引擎(C#)结合了开源的全文检索库和C#语言的优势,为企业或个人开发自定义搜索引擎提供了一种高效且灵活的解决方案。通过深入理解Lucene的原理和ShootSearch的优化策略,开发者可以...

    Lucene.net开发最全文档

    - `Document` 和 `Field`:构建索引的基本单位,`Document` 包含多个 `Field`,每个 `Field` 代表一种信息,如标题、内容等。 - `Query`:表示一个查询,如 TermQuery、PhraseQuery、BooleanQuery 等。 - `...

    最全的lucene-2.4.0jar包

    在使用Lucene-2.4.0时,开发者需要理解以下几个关键概念: - **索引**:Lucene通过创建倒排索引来实现快速搜索。索引过程将文档内容转换为可搜索的数据结构,包括词项(Term)、词项频率(TF)和位置信息。 - **...

    lucene的排序过滤和分页.zip

    Lucene支持两种类型的排序:基于评分(Score Sorting)和基于字段(Field Sorting)。基于评分的排序默认按照相关性排序,即每个文档与查询匹配的程度。而基于字段的排序则可以根据文档的特定字段值进行排序,如日期...

    Lucene检索文本,建立索引

    6. **排序与评分**: Lucene提供了一种基于TF-IDF(词频-逆文档频率)的默认评分机制,以确定哪些文档与查询更相关。我们还可以自定义评分函数,以适应特定的业务需求。 接下来,我们要将Lucene与**Struts** 结合,...

    lucene-core-3.0.0.rar_lucene_lucene-core3

    1. **索引**:Lucene的索引机制是一种倒排索引(Inverted Index),它将文档中的词汇映射到包含这些词汇的文档列表。这种数据结构使得搜索效率极高,能够在短时间内返回相关结果。 2. **分词器(Tokenizer)**:...

Global site tag (gtag.js) - Google Analytics