查询是一个复杂过程,特别是当查询过程中有多个条件,在 ES 中当有多个条件的时候,就得使用组合查询了。
组合查询是通过 bool 关键字来实现的,通过 must
、must_not
、should
将不同的条件组合到一起,再用 bool 包裹一下作为一个整体。用来实现各种且、非、或的条件组合。
“且”条件
给定需求:
查询 class 索引中姓 deng 并且年龄是 16 的学生。
下面的查询语句中不难看出,bool 包裹了条件整体,使用 must 组合两个条件实现了“且”。
GET class/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "deng"
}
},
{
"term": {
"age": 16
}
}
]
}
}
}
image
“非”条件
给定需求:
查找姓名中不包含 deng,且年龄要大于 16 岁的。
下面这条查询语句,使用 must_not
不难理解是对里面的条件做了一个“非”操作。首先使用 match Phrase
查询姓名中包含 deng 的,然后再用范围查询,查询年龄小于 16 的,再取个“非”,达到了我们想要的效果。
GET class/_search
{
"query": {
"bool": {
"must_not": [
{
"match": {
"name": "deng"
}
},
{
"range": {
"age": {
"lte": 16
}
}
}
]
}
}
}
image
“或”条件
给定需求:
查询性别为“男性”或者“女性”的学生数据。
因为性别是确定的字符串,要么是 man 要么是 female,所以这是一个精确值查询的需求,因此使用 term 查询,并且因为是 sex 的字段类型是“字符串”所以加上 keyword。(这里思考一下,上个课时中说了如果不加 keyword 将不会返回查询结果,但是这里如果把 keyword 去掉也能查询相同的数据,请问是为什么?结合上节课对 keyword 的解释,你一定会找到答案的。)
GET class/_search
{
"query": {
"bool": {
"should": [
{
"term": {
"sex.keyword": "man"
}
},
{
"term": {
"sex.keyword":"female"
}
}
]
}
}
}
image
对于性别的过滤这里使用了两个 term 查询,但是是对同一个字段做出的判断,写两个 term 查询条件显得比较繁琐,这里对于同一个字段的条件判断有更简洁的写法,就是把条件放到数组中去。
这里有两个地方需要注意,第一就是 terms
而不是之前的 term,第二个就是字段后面加的是数组,而不是之前的花括号。
GET class/_search
{
"query": {
"bool": {
"should": [
{
"terms": {
"sex.keyword": [
"man",
"famale"
]
}
}
]
}
}
}
must
与 should
的组合
这里一定要注意,ES 中的条件组合跟 SQL 的逻辑稍微有点不同,ES 中 must
与 should
不能够同时使用,当使用了 must
后,should
将不会在发生作用 。
因为 should
只是一个增加相关性分数的一个条件,当你只使用 should
的时候,如果不满足条件,那么相关性分数会比较低,就不会返回数据给你。像下面这个条件,稍微把性别改成一个不存在的 a 和 b,跟我们想的一样,并没有返回任何数据。
GET class/_search
{
"query": {
"bool": {
"should": [
{
"terms": {
"sex.keyword": [
"a",
"b"
]
}
}
]
}
}
}
image
这里我再加上一个 must
条件做测试,结果返回了很多数据,仔细观察 _score 字段都是有值的,这些值都是来源于 must
条件,should
条件因为没有满足的所以对 _score 没有任何贡献,因此 should
字段只是能影响 _score 字段,当其他条件能够给 _score 字段带来相关性分数时候,should
条件将不会对查询结果有任何贡献,只能够让 _score 变得大一点或者没有。
GET class/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "deng"
}
}
],
"should": [
{
"terms": {
"sex.keyword": [
"a",
"b"
]
}
}
]
}
}
}
image
这个问题怎么解决呢?must
与 should
组合是经常会遇到的问题。
网友评论