青鸟中文版月莎:Lucene的打分机制

来源:百度文库 编辑:九乡新闻网 时间:2024/05/01 01:52:20

 

§  1。配置Lucene,对ccer数据建立索引和查询系统
    中文分词模块(IKAnalyzer可选)

§ 2。阅读代码,分析Lucene的ranking算法。写一个简短的报告文档。

§ 3。改进ranking算法,并进行评估,给出一个实验报告。
    算法改进可用方法:PageRank Combination, LSI, Language Model, or…
    评估指标可用:P@10, MAP, F1, or …
    评估方法可用:human judgment or auto compare with google result or …

 

1.      使用IKAnalyzer对ccer下的18652左右的网页进行了索引建立和查询系统的建立,索引建立的过程大概持续了10分钟,CPU使用率持续100%。下面是索引建立之后的文件。



Index文件 (调用了optimize之后的结果)

 

实现代码如下。(附件中)

 

(我们做的是将目标的URL和所得的分数显示出来)

查询结果如下:

(1)搜“北京大学”

ReadNews.asp?NewsID=1487 0.14996947

readview.asp?reviewID=2296&NewsID=24960.14321162

ReadNews.asp?NewsID=83950.14157297

ReadNews.asp?NewsID=4173 0.14049698

ReadNews.asp?NewsID=1890 0.14018208

ReadNews.asp?NewsID=3450 0.13792434

readview.asp?reviewID=2958&NewsID=30200.13510498

ReadNews.asp?NewsID=6009 0.13157436

ReadNews.asp?NewsID=2808 0.13154271

ReadNews.asp?NewsID=1587 0.12664454

18292 pages(s) found (in 63 milliseconds)

 

我看了下网页中的内容,搜索结果中,第一个网页有39处匹配,文档内容也较长。第二个网页有3处匹配,文档内容很短。第三个网页有27处匹配,文档内容较长。。。

 

(2)第二次搜索是针对第一次搜索结果中,排在第三位的网页中的内容。网页中有一个获得全国三好学生的学生名字,叫“曾垚”。试下看看结果。

ReadNews.asp?NewsID=8395 0.73862696

ReadNews.asp?NewsID=8448 0.10303292

ReadNews.asp?NewsID=10894  0.10303292

news.asp?alllistpage=91 0.09587039

ReadNews.asp?NewsID=10557  0.09587039

ReadNews.asp?NewsID=6889 0.09587039

6 pages(s) found (in 31 milliseconds)

 

果然,第一个匹配的网页是第一次搜索的第三个网页,结果还不错。

 

2.通过阅读相关文档和源代码,LuceneRanking算法中,包括score的计算和相似度分析。

 

Lucene 将信息检索中的Boolean model (BM)和Vector Space Model(VSM)联合起来,实现了自己的评分机制。VSM模型如下:

 



计算某个查询q的文档d得分如下(摘自API文档注释)

其中每个因子的分析如下:

1)         在Lucene的实现中,使用了
 

2)         反映有多少个文档包含了该term,文档数越多,该因子的值越小,反之越大。计算idf的常用方法为   

3)         查询时期t的加权,或者由t.setBoost(int boost)来指定

4)         压缩几个索引期间的加权和长度因子。计算公式如下:
其中的因子解释如下:

Document boost:

文档加权。在索引创建过程中写入了索引中。用 doc.setBoost()

Field boost:

字段加权,在索引创建过程中写入了索引中。 field.setBoost()

lengthNorm(field):

由字段(Field)内的 Token 的个数来计算此值,字段越短,评分越高,在做索引的时候由Similarity.lengthNorm 计算。

5)   评分因子,是基于文档中出现查询项的个数。越多的查询项在一个文档中,说明些文档的匹配程序越高。

6)  查询的标准查询,使不同查询之间可以比较。此因子不影响文档的排序,因为所有有文档都会使用此因子。这个因子是在查询的时候计算的。

 

而sumOfSquareWeights的计算由下面来得到:



(注:以上部分摘自Lucene的API文档的英文部分,自己进行了理解和翻译)

 

  • 在Lucene中计算的具体过程分析如下:

 

   在Lucene的Ranking计算过程中,包括了Query、Weight、Score、Similarity,Collector几个不同的类。文档匹配阶段主要调用Searcher对象的search方法,在search方法内部,通过直接或间接调用,search(Weightweight, Filter filter, Collectorcollector)方法。通过阅读源代码,使用search的时候都将得到一个Weight对象(第一个的search方法显示调用了Query的createWeight方法来创建一个Weight对象),Weight对象会创建一个Scorer对象,Scorer对象来进行score函数的调用并将结果保存在Collector对象中。如下:

public void search(Query query,Collector results)

   throwsIOException {

  search(createWeight(query), null, results);

 }

 

  @Override

  public voidsearch(Weight weight, Filter filter, Collectorcollector)

     throws IOException {

   

    if(filter == null) {//没有使用Filter对象的时候

     for (int i = 0; i < subReaders.length;i++) { // 遍历每个subReader,但在indexSearcher中,只有一个reader

       collector.setNextReader(subReaders[i], docStarts[i]);

       Scorer scorer = weight.scorer(subReaders[i],!collector.acceptsDocsOutOfOrder(),true);//创建了一个scorer对象

       if (scorer != null) {

         scorer.score(collector);//将结果保存在collector中,以便后边使用

       }

     }

    }else {

     for (int i = 0; i < subReaders.length;i++) { // search each subreader

       collector.setNextReader(subReaders[i], docStarts[i]);

       searchWithFilter(subReaders[i], weight, filter,collector);

     }

    }

  }

 

  public Weightweight(Searcher searcher) throws IOException {

    Query query= searcher.rewrite(this);

    Weightweight = query.createWeight(searcher);

    floatsum = weight.sumOfSquaredWeights();

    floatnorm = getSimilarity(searcher).queryNorm(sum);

    if(Float.isInfinite(norm) || Float.isNaN(norm))

     norm = 1.0f;

   weight.normalize(norm);//归一化

   return weight;

  }

 

   在源代码中可以看出(没有列出),在IndexReader中的subReaders数组中存放的只有原reader,没有其他的reader,那么docStarts数组中也是一个只包含一个0的长度为1的数组。构造Weight对象,通过调用scorer函数来构造Score对象,得到所有符合要求的文档序列。

 

IDF的计算:(在DefaultSimilarity类中)

  public floatidf(int docFreq, int numDocs) {

   return(float)(Math.log(numDocs/(double)(docFreq+1))+ 1.0);

  }

 

TF的计算:(在DefaultSimilarity中)

   publicfloat tf(float freq) {

   return (float)Math.sqrt(freq);

 

得到Boost:(在Query类中。虽然在Fieldable接口和Document类中也有setBoost方法,但是还是建议在Query中调用,因为在Fieldable和Document中定义boost的话,会一同写到index中,想改变boost会变得困难。如果确实想提高一个文档或文档中某个Field的分值,可以同index一起写到索引文件中)

public float getBoost() { return boost;}//Query类中的方法

 

3. LuceneRanking算法的结果主要有ScoreSimilarity来进行计算,所以要改进Ranking算法,要从这两个方面入手。

思路:

1)    网页的重要性

对网页的链接分析得到。网页的链接分析主要根据外部链接网页的数量和链接网页的质量,网页内容的主题相关性等内容,确定网页重要性。来改变Score的计算结果。

2)    关键词匹配程度:

根据关键字匹配的算法,对基本的检索理论进行改进,针对不同位置、不同格式、不同形式的关键词,进行综合计算,最终得到每个文档与检索相关的匹配程度。