布尔查询把多个子查询组合(combine)成一个布尔表达式,所有子查询之间的逻辑关系是与(and);只有当一个文档满足布尔查询中的所有子查询条件时,ElasticSearch引擎才认为该文档满足查询条件。
布尔查询支持的子查询类型共有四种,分别是:must,should,must_not和filter:
- must子句:文档必须匹配must查询条件;
- should子句:文档应该匹配should子句查询的一个或多个;
- must_not子句:文档不能匹配该查询条件;
- filter子句:过滤器,文档必须匹配该过滤条件,跟must子句的唯一区别是,filter不影响查询的score;
通常情况下,should子句是数组字段,包含多个should子查询,默认情况下,匹配的文档必须满足其中一个子查询条件。
注意:布尔查询的四个子句,都可以是数组字段,因此,支持嵌套逻辑操作的查询。
1.布尔查询子句的逻辑关系
在布尔查询中,各个子句之间的逻辑关系是与(and)。对于单个子句,只要一个文档满足该子句的查询条件,返回的逻辑结果就是true,而对于should子句,它一般包含多个子查询条件,参数 minimum_should_match 控制文档必须满足should子句中的子查询条件的数量,只有当文档满足指定数量的should查询条件时,should子句返回的逻辑结果才是true。
{
"bool" : {
"must" : {
"term" : { "user" : "kimchy" }
},
"filter": {
"term" : { "tag" : "tech" }
},
"must_not" : {
"range" : {
"age" : { "from" : 10, "to" : 20 }
}
},
"should" : [
{ "term" : { "tag" : "wow" } },
{ "term" : { "tag" : "elasticsearch" } }
],
"minimum_should_match" : 1
}
}
在上述布尔查询中,should子句中包含两个词条查询,由于参数 minimum_should_match的值是1,因此,只要一个稳定满足任意一个词条查询的条件,should子句就匹配成功,返回逻辑结果true,然后和其他子查询进行逻辑运算,只有当该文档满足所有的子查询条件时,才作为查询结果返回到客户端。
使用布尔查询实现复杂的分组查询
复杂的分组查询,例如:(A and B) or (C and D) or (E and F) ,把布尔查询作为should子句的一个子查询:
"query": {
"bool": {
"should": [
{
"bool": {
"must": [
{ "term": { "topics": 1} },
{ "term": { "topics": 2} }
]
}
},
{
"bool": {
"must": [
{"term": { "topics": 3 } },
{"term": { "topics": 4}}
]
}
}
],
"minimum_should_match": 1
}
}
2.例子
1、搜索发帖日期为2017-01-01,或者帖子ID为XHDK-A-1293-#fJ3的帖子,同时要求帖子的发帖日期绝对不为2017-01-02
以上需求类似sql:
select *
from forum.article
where (post_date='2017-01-01' or article_id='XHDK-A-1293-#fJ3')
and post_date!='2017-01-02'
复合查询语句
思考:这个查询语句应该怎么写
其实这里我们有两个条件
(1) post_date='2017-01-01' or article_id='XHDK-A-1293-#fJ3'
(2) post_date!='2017-01-02'
条件1是or关系,所以使用should,条件2是不能匹配,所以使用must_not
{
"query":{
"bool":{
"should":[{},{}],
"must_not":{}
}
}
}
最终如下:
GET http://localhost:9202/forum/article/_search
{
"query":{
"bool":{
"should":[
{"term":{"postDate":"2017-01-01"}},
{"term":{"articleID":"XHDK-A-1293-#fJ3"}}
],
"must_not":{
"term":{"postDate":"2017-01-02"}
}
}
}
}
2、搜索帖子ID为XHDK-A-1293-#fJ3,或者是帖子ID为JODL-X-1937-#pV7而且发帖日期为2017-01-01的帖子
以上需求类似sql:
select *
from forum.article
where article_id='XHDK-A-1293-#fJ3'
or (article_id='JODL-X-1937-#pV7' and post_date='2017-01-01')
相比于上一个sql,这里用到了嵌套查询
这里其实是一个should子句中有两个条件,只要匹配其中一个即可
{
"query":{
"bool":{
"should":[
{条件1},
{条件2}
],
}
}
}
条件1非常简单,就是精确匹配{"term":{"articleID":"XHDK-A-1293-#fJ3"}}
条件2则相对复杂的,涉及到嵌套查询,需要使用到must[{},{}],而如果使用must,则必须要在bool中使用,因为should中无法直接写must子句
GET http://localhost:9202/forum/article/_search
{
"query":{
"bool":{
"should":[
{"term":{"articleID":"XHDK-A-1293-#fJ3"}},
{
"bool":{
"must":[
{"term":{"articleID":"JODL-X-1937-#pV7"}},
{"term":{"postDate":"2017-01-01"}}
]
}
}
]
}
}
}