本文參考的是文章是:
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聯合使用,也可能會存在這樣的問題,解決思路一樣。