lucene3.0.3中的DidjunctionMaxQuery

       solr中的dismax我在lucene中一直没有找到对应的queryParser,但是我倒是找到了一个Query——DisjunctionMaxQuery,他的原理和disMax的原理是一样的。我仔细想了想,solr中的dismax这个queryParser的最终也是形成了一个类似的query,当然其实现可能不同,大致原理应该一样。所以我看了看lucene 3.0.3中的DisjunctionMaxQuery类的源码,再此记录一下笔记,方便我,也方便你。

        DisjunctionMaxQuery,以下简称dmq,和booleanQuery的原理是差不多的,他也是含有多个subQuery,但是如同它的名字一样,是对多个subQuery取并集(他没有minNrShouldMatch的要求,只要某一个subQuery召回了某个doc,这个doc就会被最终召回),与booleanQuery最大的不同是在得分上(我稍后会补充下booleanQuery的得分实现)。

       它的打分公式是:召回当前doc的多个subScorer(并不是全部的subScorer,因为可能有的subScorer可能不会召回这个doc)的得分相加,获得sum,同时记录所有的召回当前doc的subScorer中最大的得分max,最后某个doc的得分是

max + (sum - max) * tieBreakerMultiplier;

在源代码中,他是用数组来保存的,原因很简单,数组是引用类型,在递归中不用重新设置新的值,就能保存上一层递归的值。从他的打分来看,他会优先使用最大的匹配的query,但是对于那些非最大的匹配的query,并不是完全的忽略,而是使用将其得分乘以一个很小的系数,也就是这里的tieBreaderMultiplier,在solr的disMax 的queryParser里面也有这样的一个属性,叫做tie,他们应该是相同的意思。

      我们来思考一下在百度中进行搜索的时候,比如我们搜索一个人名,比如“科比”,我们假设百度在对“科比“进行分词的时候是分为”科比“这一个词(而不是分为 ”科“、”比“),我们得到的第一个排名是科比的百度百科,如果我们把整个html的内容作为一个域的话,按照tf idf的算法,百度百科不可能永远排在第一位,所以html的所有的内容应该不是完全相同的一个域(类似于在solr的copyField,虽然可以把很多的域复制到同一个域中,但是这样就会丢失不同的域的权重),百度的做法应该是和这里的DisjunctionMaxQuery的思想是一样的,在搜科比的时候会搜多个域,比如存在两个域,title和body,title中的字符更少,他的权重更高一些,在body中存在更多的term,所以这个与的权重低一些,我们在搜”科比“的时候,会形成一个DisjunctionMaxQuery,它包含两个子query,title:科比  和 body:科比。使用这个DisjunctionMaxQuery的得分正好匹配了百度的做法,尽管body:科比匹配了众多的网页,但是他的权重很低,而title:科比值匹配了很少量的网页,并且他的权重更高得分也更高,所以百度百科排在前面也就能明白了。

      DisjunctionMaxQuery看来也很适合做电商的搜索,我们在搜一个词的时候,可能在商品的标题、类别、品牌、描述中都会被搜到,但是明显他们的重要性不一样,所以我们可以使用这个query来进行搜索,来实现更准确的搜索效果。

 

 

 

 

猜你喜欢

转载自suichangkele.iteye.com/blog/2347076