前言
Solr支持布尔查询,使用AND、OR、&&、!、+、-符号,具体可参考社区的文档介绍。
但是,在使用过程中,可能有些查询的结果会引起困扰,需要深入理解Lucene的boolean查询规则。本文就拿具体的例子介绍如何理解其中的规则。
规则
布尔查询在代码中主要有下面四种标识,BooleanClause.java。
- MUST,用
+
标识 - SHOULD,用
空字符
标识 - MUST_NOT,用
-
标识 - FILTER(不常用,先忽略)
结果按照下面规则返回。
1.MUST和MUST:取得连个查询子句的交集。
2.MUST和MUST_NOT:表示查询结果中不能包含MUST_NOT所对应得查询子句的检索结果。
3.SHOULD与MUST_NOT:连用时,功能同MUST和MUST_NOT。
4.SHOULD与MUST连用时,结果为MUST子句的检索结果,但是SHOULD可影响排序。
5.SHOULD与SHOULD:表示“或”关系,最终检索结果为所有检索子句的并集。
6.MUST_NOT和MUST_NOT:无意义,检索无结果。
在使用布尔查询时,最容易引起误解的是-
语法,因此,下面的例子主要讲述-
的使用。其它语法的使用和普通的布尔逻辑语义类似。
举例
在使用Solr查询时,如何确定布尔查询的符号,可以通过debugQeury获取到parsedquery_toString。
写入四条数据:
id,update_version_l,name_s,age_i
1,1,zhangsan,10
2,2,lisi,10
3,3,wangwu,20
4,4,zhaoliu,10
- 示例1
age_i:10 OR -name_s:zhangsan
#找到age_i等于10的数据,或者name_s不等于zhangsan的数据。按照正常布尔逻辑的理解,应该返回4条数据,但实际查询只返回2条数据
编译后的语法是
age_i:[10 TO 10] -name_s:zhangsan
代表的是SHOULD和MUST_NOT的组合
,参照规则3。
序号 | 查询条件 | 命中的id |
---|---|---|
1 | age_i:[10 TO 10] | 1,2,4 |
2 | name_s:zhangsan | 1 |
按照规则3:首先拿到序号1条件的结果,再排除序号2条件的结果,也就是最终结果为2, 4。
- 示例2
age_i:10 OR (-name_s:zhangsan)
#业务要达到的目的和示例1一致,期望返回4条数据,但实际结果返回3条数据。
编译后的语法
age_i:[10 TO 10](-name_s:zhangsan)
注意到这里(-name_s:zhangsan)
代表的是MUST NOT,实际意义是文档集中不应该有name_s:zhangsan的数据,但实际是有的,因此这个子查询返回0条数据。
参考规则5。
序号 | 查询条件 | 命中的id |
---|---|---|
1 | age_i:[10 TO 10] | 1,2,4 |
2 | (-name_s:zhangsan) | NA |
按照规则5,两个结果取并集,最终结果就是1,2,4
- 示例3
age_i:10 AND -name_s:zhangsan
#找到age_i:10的数据,并且name_s不等于zhangsan,理论应该返回2条数据,实际结果也是符合预期。
- 示例4
id:("1" "2" "3" "4") AND (-name_s:zhangsan OR age_i:10)
编译后的语法是
+(id:1 id:2 id:3 id:4) +(-name_s:a age_i:[10 TO 10])
代表的是 MUST和MUST(MUST_NOT和SHOULD的组合)的组合
name_s:a => 1
age_i:[10 TO 10] => 1, 2, 4
(-name_s:a age_i:[10 TO 10]) => 2, 4
(id:1 id:2 id:3 id:4) => 1, 2, 3, 4
+(id:1 id:2 id:3 id:4) +(-name_s:a age_i:[10 TO 10]) => 2, 4
最疑惑的-符号如何解?
当使用-
语法时,主动用*:*
来和-
组成一个AND
语法。
即:-name_s:zhangsan
转换为如下写法(*:* AND -name_s:zhangsan)
那么,我们来回顾上面的三个例子:
- 示例1
age_i:10 OR -name_s:zhangsan
改成如下写法,结果符合预期。
age_i:10 OR (*:* AND -name_s:zhangsan)
- 示例2
age_i:10 OR (-name_s:zhangsan)
改成如下写法,结果符合预期。
age_i:10 OR (*:* AND -name_s:zhangsan)
- 示例3
age_i:10 AND -name_s:zhangsan
改成如下写法,结果仍然符合预期
age_i:10 AND (*:* AND -name_s:zhangsan)
- 示例4
id:("1" "2" "3" "4") AND (-name_s:zhangsan OR age_i:10)
改成如下写法,结果符合预期
id:("1" "2" "3" "4") AND ((*:* AND -name_s:zhangsan) OR age_i:10)