本文参考的是文章是:
ES 的shoud和must共用不生效问题 但是这篇博文中最终给出的DSL语法是错误的
在练习的时候,有这样一个需求:
查询姓氏为张,且住址是北京或者上海的人员信息
这个时候会想到使用bool查询:
{
"query":{
"bool":{
"must":[
{
"match":{
"firstname":"张"
}
}
],
"should":[
{
"match":{
"address":"北京"
}
},
{
"match":{
"address":"上海"
}
}
]
}
},
"size":1000
}
通过查询结果可以看出来,不仅地址是北京或者上海的人被搜索出来了,而且其他省份的人信息也被搜索出来了,这个时候should查询时没有起作用的,经过分析,原因在于DSL代码逻辑存在问题:
我们的需求是:查询姓氏为张,且住址是北京或者上海的人员信息,用数学表达书表示为:
(firstname="张") &&(address=北京 || address=上海)
也可以看做是:
(firstname="张"&& address=北京) || (firstname="张" && address=上海)
这点存疑?
现在再来看看上面DSL查询语句的逻辑是: should和must之间并没有指明逻辑关系,因此它只执行了match部分,并没有执行should部分,从搜索结果来看,如果两者单纯的并列的话,那么谁在前就执行谁,后面的就不再执行了。
如上面的语句仅仅会搜索姓氏为张的所有人信息,不管他是哪里的都会显示出来;
如果两者交换位置,那么只会搜索地址为北京或者上海的人信息,不管他姓什么。
为了使得两者都能够起作用,我们可以首先将需求转换成数学逻辑语言,再根据此逻辑编写DSL(使用时去掉注释):
{
"query":{
"bool":{
"should":[ //must和should用活关系连接
{ "bool":{ //firstname="张"&& address=北京
"must":[
{
"match":{
"firstname":"张"
}
},
{
"match":{
"address":"北京"
}
}
]
}
},
{
"bool":{ //firstname="张" && address=上海
"must":[
{
"match":{
"firstname":"张"
}
},
{
"match":{
"address":"上海"
}
}
]
}
}
]
}
}
}
或者写成这样子(使用时去掉注释):
{
"query":{
"bool":{
"must":[ //must和should用must连接
{ "bool":{
"must":[ //firstname="张" 必须满足条件
{
"match":{
"firstname":"张"
}
}
]
}
},
{
"bool":{
"should":[ //address=北京 || address=上海
{
"match":{
"address":"北京"
}
},
{
"match":{
"address":"上海"
}
}
]
}
}
]
}
}
}
Java语言的写法是:
//(firstname="张") &&(address=北京 || address=上海)
QueryBuilder queryBuilder = QueryBuilders.boolQuery()
.must(QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("firstname","张")) //firstname=张
)
.must(QueryBuilders.boolQuery()
.should(QueryBuilders.matchQuery("address","北京"))
.should(QueryBuilders.matchQuery("address","上海")) // address=北京 || address=上海
);
// (firstname="张"&& address=北京) || (firstname="张" && address=上海)
QueryBuilder queryBuilder = QueryBuilders.boolQuery()
.should(QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("firstname","张"))
.must(QueryBuilders.matchQuery("address","北京"))
)
.should(QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("firstname","张"))
.must(QueryBuilders.matchQuery("address","上海"))
);
既然must和should联合使用存在这样的问题,那么must、should、must_not联合使用,也可能会存在这样的问题,解决思路一样。