Lucene的排序算法

来源:互联网 发布:剑侠情缘网络版叁mac 编辑:程序博客网 时间:2024/06/05 13:11

公式: 

 

1                      tf(t in d) term frequencyterm的出现次数(frequency)有关系(correlate to),定义为(defined asterm t在当前算分(currently scored)的文档d中出现(appear in)的次数(number of times)。对一个给定(gived)的term,那些出现此term的次数越多(more occurences)的文档将获得越高的分数(higher score)。缺省的tf(t in d)算法实现在DefaultSimilarity类中,公式如下

2                      idf(t)  Inverse Document Frequency 代表(stand for)反转文档频率(Inverse Document Frequency)。这个分数与反转(inverse of)的docFreq(出现过term t的文档数目)有关系。这个分数的意义是越不常出现(rarer)的term将为最后的总分贡献(contribution)更多的分数。缺省idff(t in d)算法实现在DefaultSimilarity类中,公式如下

 

 

3                      coord(q,d) 是一个评分因子,基于(based on)有多少个查询terms在特定的文档(specified document)中被找到。通常(typically),一篇包含了越多的查询terms的文档将比另一篇包含更少查询terms的文档获得更高的分数。这是一个搜索时的因子(search time factor)是在搜索的时候起作用(in effect at search time),它在Similarity对象的coord(q,d)函数中计算

4                      queryNorm(q) 是一个修正因子(normalizing factor),用来使不同查询间的分数更可比较(comparable)。这个因子不影响文档的排名(ranking)(因为搜索排好序的文档(ranked document)会增加(multiplied)相同的因数(same factor)),更确切地说只是(but rather just)为了尝试(attempt to)使得不同查询条件(甚至不同索引(different indexes))之间更可比较性。这是一个搜索时的因子是在搜索的时候起作用,由Similarity对象计算。缺省queryNorm(q)算法实现在DefaultSimilarity类中,公式如下

sumOfSquaredWeights(查询的terms)是由查询Weight对象计算的,例如一个布尔(boolean)条件查询的计算公式为

5                      t.getBoost() 是一个搜索时(search time)的代表查询q中的term tboost数值,具体指定在(as specified in)查询的文本中(参见查询语法),或者由应用程序调用setBoost()来指定。需要注意的是实际上(really)没有一个直接(direct)的API来访问(accessing)一个多个term的查询(multi term query)中的一个term boost值,更确切地说(but rather),多个termsmulti terms)在一个查询里的表示形式(represent as)是多个TermQuery对象,所以查询里的一个termboost值的访问是通过调用子查询(sub-query)的getBoost()方法实现的。

6                      norm(t,d) 是提炼取得(encapsulate)一小部分boost值(在索引时间)和长度因子(length factor):

ú            document boost 在添加文档到索引之前通过调用doc.setBoost()来设置。

ú            Field boost 在添加Field到文档之前通过调用field.setBoost()来设置。

ú            lengthNorm(field)在文档添加到索引的时候,根据(in accordance with)文档中该fieldtokens数目计算得出,所以更短(shorter)的field会贡献更多的分数。lengthNorm是在索引的时候起作用,由Similarity类计算得出。

当一篇文档被添加到索引的时候,所有上面计算出的因子将相乘起来(multiplied)。如果文档拥有多个相同名字的fieldsmultiple fields with same name),所有这些fieldsboost值也会被一起相乘起来(multiplied together

 

       

1.     score_d: Document(d) 的得分

2.     sum_t: Term(t) 的总和

3.     tf_q: 是查询的词在文档中出现的次数的平方根 (d t 的频度的平方根)

4.     idf_t: 表示反转文档频率,观察了一下所有的文档都一样,所以那就没什么用处,不会起什么决定作用。

组成: idf_t :  log(numDocs/docFreq_t + 1) + 1.0

5.     numDocs: 索引中Document的数量

6.     docFreq_t: 包含tDocument的数量

7.     norm_q: sqrt(sum_t((tf_q*idf_t)^2))

8.     norm_d_t: 在与 t 相同域的 d tokens 数量的平方根

 

下面用代码和运行结果来进行说明:

Java代码

  1. public class ScoreSortTest {   
  2.     public final static String INDEX_STORE_PATH = "index";   
  3.     public static void main(String[] args) throws Exception {   
  4.         IndexWriter writer = new IndexWriter(INDEX_STORE_PATH, new StandardAnalyzer(), true);   
  5.         writer.setUseCompoundFile(false);   
  6.            
  7.         Document doc1 = new Document();   
  8.         Document doc2 = new Document();   
  9.         Document doc3 = new Document();   
  10.            
  11.         Field f1 = new Field("bookname","bc bc", Field.Store.YES, Field.Index.TOKENIZED);   
  12.         Field f2 = new Field("bookname","ab bc", Field.Store.YES, Field.Index.TOKENIZED);   
  13.         Field f3 = new Field("bookname","ab bc cd", Field.Store.YES, Field.Index.TOKENIZED);   
  14.            
  15.         doc1.add(f1);   
  16.         doc2.add(f2);   
  17.         doc3.add(f3);   
  18.            
  19.         writer.addDocument(doc1);   
  20.         writer.addDocument(doc2);   
  21.         writer.addDocument(doc3);   
  22.            
  23.         writer.close();   
  24.            
  25.         IndexSearcher searcher = new IndexSearcher(INDEX_STORE_PATH);   
  26.         TermQuery q = new TermQuery(new Term("bookname", "bc"));   
  27.  //      TermQuery q2 = new TermQuery(new Term(“bookTitle”,”bc”);
  28.  //       BooleanQuery bq = new BooleanQuery();
  29.  //      bq.add(q);
  30.  //       bq.add(q2);
  31.  //       Searcher.search(bq);
  32.  
  33.         q.setBoost(2f);   
  34.         Hits hits = searcher.search(q);   
  35.         for(int i=0; i<hits.length();i++){   
  36.             Document doc = hits.doc(i);   
  37.             System.out.print(doc.get("bookname") + "/t/t");   
  38.             System.out.println(hits.score(i));   
  39.             System.out.println(searcher.explain(q, hits.id(i)));//   
  40.         }   
  41.     }   
  42. }  

public class ScoreSortTest {

  public final static String INDEX_STORE_PATH = "index";

  public static void main(String[] args) throws Exception {

   IndexWriter writer = new IndexWriter(INDEX_STORE_PATH, new StandardAnalyzer(), true);

   writer.setUseCompoundFile(false);

   

   Document doc1 = new Document();

   Document doc2 = new Document();

   Document doc3 = new Document();

  

   Field f1 = new Field("bookname","bc bc", Field.Store.YES, Field.Index.TOKENIZED);

   Field f2 = new Field("bookname","ab bc", Field.Store.YES, Field.Index.TOKENIZED);

   Field f3 = new Field("bookname","ab bc cd", Field.Store.YES, Field.Index.TOKENIZED);

  

   doc1.add(f1);

   doc2.add(f2);

   doc3.add(f3);

  

   writer.addDocument(doc1);

   writer.addDocument(doc2);

   writer.addDocument(doc3);

  

   writer.close();

  

   IndexSearcher searcher = new IndexSearcher(INDEX_STORE_PATH);

   TermQuery q = new TermQuery(new Term("bookname", "bc"));

   q.setBoost(2f);

   Hits hits = searcher.search(q);

   for(int i=0; i<hits.length();i++){

     Document doc = hits.doc(i);

     System.out.print(doc.get("bookname") + "/t/t");

     System.out.println(hits.score(i));

     System.out.println(searcher.explain(q, hits.id(i)));//

   }

  }

}


运行结果:

引用

bc bc 0.629606
0.629606 = (MATCH) fieldWeight(bookname:bc in 0), product of:
  1.4142135 = tf(termFreq(bookname:bc)=2)
  0.71231794 = idf(docFreq=3, numDocs=3)
  0.625 = fieldNorm(field=bookname, doc=0)

ab bc 0.4451987
0.4451987 = (MATCH) fieldWeight(bookname:bc in 1), product of:
  1.0 = tf(termFreq(bookname:bc)=1)
  0.71231794 = idf(docFreq=3, numDocs=3)
  0.625 = fieldNorm(field=bookname, doc=1)

ab bc cd 0.35615897
0.35615897 = (MATCH) fieldWeight(bookname:bc in 2), product of:
  1.0 = tf(termFreq(bookname:bc)=1)
  0.71231794 = idf(docFreq=3, numDocs=3)
  0.5 = fieldNorm(field=bookname, doc=2)


从结果中我们可以看到:
bc bc
文档中bc出现了2次,tf2的平方根,所以是1.4142135。而其他的两个文档出现了一次,所以是
1.0
所有的三个文档的idf值都是一样的,是
0.71231794
默认情况下,boost的值都是1.0,所以lengthNorm就是当前的fieldNorm的值。前两个文档的长度一致,为0.625,而排在最后的文档,因为长度要长一些,所以分值要低,为
0.5

现在对f2这个字段增加激励因子:
f2.setBoost(2.0f);
运行结果变为:

引用

ab bc 0.8903974
0.8903974 = (MATCH) fieldWeight(bookname:bc in 1), product of:
  1.0 = tf(termFreq(bookname:bc)=1)
  0.71231794 = idf(docFreq=3, numDocs=3)
  1.25 = fieldNorm(field=bookname, doc=1)


发现fieldNorm值有0.625变成了1.25,所以就是乘以了2.0

接下来再对第二个文档增加激励因子:
doc2.setBoost(2.0f);
运行结果变为:

引用

ab bc 1.0
1.7807949 = (MATCH) fieldWeight(bookname:bc in 1), product of:
  1.0 = tf(termFreq(bookname:bc)=1)
  0.71231794 = idf(docFreq=3, numDocs=3)
  2.5 = fieldNorm(field=bookname, doc=1)


发现fieldNorm又乘以了2,所以说对于DocumentFieldsetBoost都会乘到一起。

因为该文档的最终的score超过了1.0变成1.7807949,所以其他的两个文档的最终得分都要除以该值,

分别变成:

引用

bc bc 0.35355335
ab bc cd 0.19999999




相信通过上面的解释,大家就可以形象得理解Lucene的打分机制,同时也知道如何来改变文档的得分。

 

要点:
   
查询词在一个 Document 中的位置并不重要。

   
如果一个 Document 中含有该查询词的次数越多,该得分越高。
   
一个命中document中,如果除了该查询词之外,其他的词越多,该得分越少。

 

原创粉丝点击