BooleanQuery介绍

BooleanQuery常用来对实现多个Query子类对象的进行组合,这些Query子类对象会组成一个Cluase实现组合查询。每一个Query都有四种可选,分别描述了匹配的文档需要满足的要求,定义在 BooleanClause类中,如下:

MUST (+)

满足查询要求的文档中必须包含查询的关键字。

SHOULD (" ")

满足查询要求的文档中包含一个或多个查询的关键字。

FILTER (#)

满足查询要求的文档中必须包含查询的关键字,但是这个Query不会参与文档的打分。

MUST_NOT (-)

满足查询要求的文档中必须不能包含查询的关键字。

组合查询

转化为代码如下:

满足查询要求的文档必须包含 "a",,不能包含“c”,,可以包含“b”,“d”中一个或者多个,包含的越多,文档的分数越高

BooleanQuery的方法

设置minimumNumberShouldMatch

当查询有多个SHOULD的Query对象时,满足查询要求的文档中必须包含minimumNumberShouldMatch个Query的关键字

构建CreateWeight对象

Query对象的子类都会重写这个方法。对于BooleanQuery的createWeight(...)实现,只是调用了对象组合中的所有Query子类的createWeight(...)方法分别生成Weight对象,然后将这些对象封装到BooleanWeight对象中。TermQuery的createWeight()的具体实现看博客的文章 TermQuery。

重写Query

BooleanQuery的rewrite(..)跟createWeight(...)相同的是都是调用对象组合中所有Query子类的rewrite(...)方法,但是并不是所有的Query都需要重写。比如TermQuery,他就没有重写父类的rewrite(...)方法,而对于PrefixQuery(前缀查询),则必须要重写, 重写后的PrefixQuery会生成多个TermQuery,最后组合成BooleanQuery。

BooleanQuery的rewrite(...)实现中一共有9个逻辑(下面的会对每一种逻辑进行标注,比如说 逻辑一),根据BooleanQuery中的不同的组合(MUST, SHOULD, MUST_NOT, FILTER的任意组合), 会至少执行1个多个重写逻辑,我们对最常用的组合来描述重写的过程。

只有一个SHOULD或MUST的TermQuery

重写第一步

直接返回。。。不需要重写。

多个SHOULD的TermQuery

重写第一步

首先遍历BooleanQuery中的所有Query对象,调用他们自身的重写方法,由于TermQuery不需要重写,所以直接返回自身。

重写第二步(可选)

如果minimumNumberShouldMatch的值 <= 1那么需要执行第二步。 当有多个相同的TermQuery,并且是SHOULD,会将这些相同的TermQuery封住成一个BoostQuery,增加boost的值。

下图中左边是重写前的BooleanQuery,右边是重写后的BooleanQuery。

SHOULD(至少一个)和MUST(至少一个)的TermQuery

重写第一步

同样先要执行 逻辑二,不赘述。

重写第二步(可选)

同样先要执行 逻辑七,不赘述。 下图中左边是重写前的BooleanQuery,右边是重写后的BooleanQuery。

重写第三步

当有多个相同的TermQuery,并且是MUST,会将这些相同的TermQuery封住成一个BoostQuery,增加boost的值。

下图中左边是重写前的BooleanQuery,右边是重写后的BooleanQuery。

多个MUST的TermQuery

重写第一步

同样先要执行 逻辑二,不赘述。

重写第二步

当有多个相同的TermQuery,并且是MUST,会将这些相同的TermQuery封住成一个BoostQuery,增加boost的值。然后执行逻辑八,已说明,不赘述。

MUST(至少一个)和MUST_NOT(至少一个)的TermQuery

重写第一步

同样先要执行 逻辑二,不赘述。

重写第二步

如果在这个逻辑中返回了,那么就会返回一个MatchNoDocsQuery对象,也就是不会搜索到任何结果。

重写第三步

当有多个相同的TermQuery,并且是MUST,会将这些相同的TermQuery封住成一个BoostQuery,增加boost的值。然后执行逻辑八,已说明,不赘述。 下图中左边是重写前的BooleanQuery,右边是重写后的BooleanQuery。

SHOULD(至少一个)和MUST_NOT(至少一个)的TermQuery

重写第一步

同样先要执行 逻辑二,不赘述。

重写第二步

执行逻辑四,不赘述。

重写第三步(可选)

执行逻辑七,不赘述。 下图中左边是重写前的BooleanQuery,右边是重写后的BooleanQuery。

SHOULD(至少一个)和MUST(至少一个)和MUST_NOT(至少一个)的TermQuery

重写第一步

同样先要执行 逻辑二,不赘述。

重写第二步

执行逻辑四,不赘述。

重写第三步(可选)

执行逻辑七,不赘述。

重写第四步

执行逻辑八,不赘述。 下图中左边是重写前的BooleanQuery,右边是重写后的BooleanQuery。

SHOULD(至少一个)和FILTER(至少一个)的TermQuery

重写第一步

同样先要执行 逻辑二,不赘述。

重写第二步

因为对于FILTER的Query中的term,他只是不参与打分,但是搜索结果必须包含这个term,如果SHOULD的Query中也有这个term,那么将这个Query的SHOULD改为MUST, 然后minShouldMatch的值就必须少一个,注意的是FILTER的这个Query没有放到新的BooleanQuery中。

重写第三步(可选)

执行逻辑七,不赘述。

重写第四步

执行逻辑八,不赘述。 下图中左边是重写前的BooleanQuery,右边是重写后的BooleanQuery。

MUST(至少一个)和FILTER(至少一个)的TermQuery

重写第一步

同样先要执行 逻辑二,不赘述。

重写第二步

判断是否存在一个term对应的Query即是 MUST又是FILTER,如果存在,那么移除FILTER的Query。

重写第三步

执行逻辑八,不赘述。 下图中左边是重写前的BooleanQuery,右边是重写后的BooleanQuery。

结语

BooleanQuery类中最重要的方法就是rewrite()方法,上面的例子中列举了最常用的几种BooleanQuery的情况,MUST,SHOULD,FILTER,MUST_NOT的他们之间不同数量的组合有着不一样的rewrite过程,无法一一详细列出。BooleanQuery中的rewrite一共有9个逻辑,都在关键处给出了注释,大家可以到我们的GitHub看这个类的源码https://github.com/luxugang/Lucene-7.5.0/blob/master/solr-7.5.0/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java

点击下载Markdown文件