欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于functionQuery的一个误区

程序员文章站 2022-04-27 21:14:42
...

        之前我在跟别人分享solr(lucene)的时候,在谈论到一些特殊的query,比如prefixquery、wildcardQuery的时候,我曾经说过一句话:query就是得到词典表中的term,然后判断是不是符合条件,有的query(比如termquery)仅仅是判断词典表中的词和要查找的词是否相等,prefixQuery是判断是不是以制定的字符串开头,wildcardQuery是判断是不是符合某个正则表达式,等等,我们可以实现更加复杂的query来实现更加复杂的条件,比如function query。当然这句话纯粹是我自己的判断,没有实际的例子证明。

       今天我在读了function query的代码后,发现我想错了,funcitonQuery并不是为了实现复杂的判断逻辑而存在的。我先说一下他都是做了什么吧,他里面有一个vlaueSource(就是获得索引中的某些值,可能是来自于doc的某个属性,也可能是需要现计算出来的一些值,在下面会有介绍),然后他在计算得分的时候使用了这个valueSouce中对于某个id的doc的值,是作为一个数字加到默认的得分上去的,默认的得分只有一个参数,那就是使用的query的boost,他的结果是返回所有的doc,看看FunctionQuery生成的FunctionWeight的scorer方法,

 @Override
public Scorer scorer(AtomicReaderContext context, Bits acceptDocs) throws IOException {
      return new AllScorer(context, acceptDocs, this, queryWeight);
}

他是返回了一个AllScorer,顾名思义也知道他是返回所有的doc的scorer,看看他的next方法吧:

 @Override
public int nextDoc() throws IOException {
  for(;;) {
    ++doc;
    if (doc>=maxDoc) {
      return doc=NO_MORE_DOCS;
    }
    if (acceptDocs != null && !acceptDocs.get(doc)) continue;
    return doc;
  }
}

  可以看出,只要一个doc没有被删除就会被返回,所以可以确定的说这个AllScorer就是返回所有的doc。

我用solr做了一个例子,使用function query,发现他获得了所有doc,例子为:使用edismax的queryParser,q设置为:{!func}sub(someField,22),在debugQuery的情况下,我看到了他的确是生成了一个FunctionQuery。

 

  上面我说的复杂的倒排表的选择是这个意思:比如我要在一个人才的lucene的索引中查找身高和体重符合一定条件的人(比如加起来是300的,如果一个人身高170,130斤,那么就应该召回),本来我以为function query就是要实现这种复杂逻辑的呢,但是在我看了他的源码之后,发现他不是做这个的。因为他仅仅是突出的使用了valueSource,valueSource是来自于field cache(也就是词典表或者docValue),而这个显然无法和倒排表扯上关系,所以我可以肯定的说,function query的作用很简单,就是利用valueSource来计算一个简单的得分的。

  那么既然FunctionQuery的作用那么小,那用它来做啥子呢?

 

  很简单,作为排序的一个条件,因为他只能计算valueSource的值和自己的boost,那就可以很方便的使用它计算一个值作为排序的标准,在solr里面使用它就是一个很好的例子!

 

  既然用到了value source,就说一句吧,value source就是获得一个doc的某个值,比如可以是一个域的值,或者是多个域的值得函数值(比如域中某些term的tf),也可以是指定的某个常数的值(比如常数类型的valueSource),这就能很好的理解solr中的那些函数了,比如max、sub、div,这些就是对一个doc的多个域的值进行一个函数操作后把最后的结果用来计算得分的。所以这样一来,理解solr的那些函数就很简单了,我们也就能自己实现一些函数来实现更加复杂的功能了!

 

  最后再重复一边,functionquery并不是一个复杂的query,我之前理解错了,纠正这个误区!