组合过滤器
前面的两个例子都是单个过滤器(filter)的使用方式。 在实际应用中,我们很有可能会过滤多个值或字段。比方说,怎样用 Elasticsearch 来表达下面的 SQL ?
SELECT product
FROM products
WHERE (price = 20 OR productID = "XHDK-A-1293-#fJ3")
AND (price != 30)
这种情况下,我们需要 bool
(布尔)过滤器。 这是个 复合过滤器(compound filter) ,它可以接受多个其他过滤器作为参数,并将这些过滤器结合成各式各样的布尔(逻辑)组合。
布尔过滤器
一个 bool
过滤器由三部分组成:
{
"bool" : {
"must" : [],
"should" : [],
"must_not" : [],
}
}
must
所有的语句都 必须(must) 匹配,与 AND
等价。
must_not
所有的语句都 不能(must not) 匹配,与 NOT
等价。
should
至少有一个语句要匹配,与 OR
等价。
用 Elasticsearch 来表示本部分开始处的 SQL 例子,将两个 term
过滤器置入 bool
过滤器的 should
语句内,再增加一个语句处理 NOT
非的条件:
# 5.0版本 filtered 已被淘汰
GET /my_store/products/_search
{
"query" : {
"filtered" : { 1
"filter" : {
"bool" : {
"should" : [
{ "term" : {"price" : 20}}, 2
{ "term" : {"productID" : "XHDK-A-1293-#fJ3"}} 3
],
"must_not" : {
"term" : {"price" : 30} 4
}
}
}
}
}
}
# 5.0版本后语法为
GET _search
{
"query": {
"bool": {
"must": {
"match": {
"text": "quick brown fox"
}
},
"filter": {
"term": {
"status": "published"
}
}
}
}
}
1 注意,我们仍然需要一个 filtered
查询将所有的东西包起来。
2 3 在 should
语句块里面的两个 term
过滤器与 bool
过滤器是父子关系,两个 term
条件需要匹配其一。
4 如果一个产品的价格是 30
,那么它会自动被排除,因为它处于 must_not
语句里面。
我们搜索的结果返回了 2 个命中结果,两个文档分别匹配了 bool
过滤器其中的一个条件:
"hits" : [
{
"_id" : "1",
"_score" : 1.0,
"_source" : {
"price" : 10,
"productID" : "XHDK-A-1293-#fJ3" 1
}
},
{
"_id" : "2",
"_score" : 1.0,
"_source" : {
"price" : 20, 2
"productID" : "KDKE-B-9947-#kL5"
}
}
]
1 与 term
过滤器中 productID = "XHDK-A-1293-#fJ3"
条件匹配
2 与 term
过滤器中 price = 20
条件匹配
嵌套布尔过滤器
尽管 bool
是一个复合的过滤器,可以接受多个子过滤器,需要注意的是 bool
过滤器本身仍然还只是一个过滤器。 这意味着我们可以将一个 bool
过滤器置于其他 bool
过滤器内部,这为我们提供了对任意复杂布尔逻辑进行处理的能力。
对于以下这个 SQL 语句:
SELECT document
FROM products
WHERE productID = "KDKE-B-9947-#kL5"
OR ( productID = "JODL-X-1937-#pV7"
AND price = 30 )
我们将其转换成一组嵌套的 bool
过滤器:
GET /my_store/products/_search
{
"query" : {
"filtered" : {
"filter" : {
"bool" : {
"should" : [
{ "term" : {"productID" : "KDKE-B-9947-#kL5"}}, 1
{ "bool" : { 2
"must" : [
{ "term" : {"productID" : "JODL-X-1937-#pV7"}}, 3
{ "term" : {"price" : 30}} 4
]
}}
]
}
}
}
}
}
1 因为 term 和 bool 过滤器是兄弟关系,他们都处于外层的布尔逻辑 should 的内部,返回的命中文档至少须匹配其中一个过滤器的条件。
2 这两个 term 语句作为兄弟关系,同时处于 must 语句之中,所以返回的命中文档要必须都能同时匹配这两个条件。
得到的结果有两个文档,它们各匹配 should
语句中的一个条件:
"hits" : [
{
"_id" : "2",
"_score" : 1.0,
"_source" : {
"price" : 20,
"productID" : "KDKE-B-9947-#kL5" 1
}
},
{
"_id" : "3",
"_score" : 1.0,
"_source" : {
"price" : 30, 2
"productID" : "JODL-X-1937-#pV7" 3
}
}
]
1 这个 productID 与外层的 bool 过滤器 should 里的唯一一个 term 匹配。
2 这两个字段与嵌套的 bool 过滤器 must 里的两个 term 匹配。