如何在ElasticSearch中执行嵌套的AND和OR过滤器?

时间:2014-04-02 12:22:51

标签: elasticsearch

我的过滤器按类别分组。 我想检索文档可以匹配类别中任何过滤器的文档,但如果设置了两个(或更多)类别,则文档必须与所有类别中的任何过滤器匹配。

如果用伪SQL编写,那将是:

SELECT * FROM Documents WHERE (CategoryA = 'A') AND (CategoryB = 'B' OR CategoryB = 'C')

我尝试过像这样的嵌套过滤器:

{
    "sort": [{
        "orderDate": "desc"
    }],
    "size": 25,
    "query": {
        "match_all": {}
    },
    "filter": {
        "and": [{
            "nested": {
                "path":"hits._source",
                "filter": {
                    "or": [{
                        "term": {
                            "progress": "incomplete"
                        }
                    }, {
                        "term": {
                            "progress": "completed"
                        }
                    }]
                }
            }
        }, {
            "nested": {
                "path":"hits._source",
                "filter": {
                    "or": [{
                        "term": {
                            "paid": "yes"
                        }
                    }, {
                        "term": {
                            "paid": "no"
                        }
                    }]
                }
            }
        }]
    }
}

但显然我不太了解ES语法。这是在正确的轨道上还是我需要使用另一个过滤器?

2 个答案:

答案 0 :(得分:10)

这应该是它(从给定的伪SQL转换)

{
   "sort": [
      {
        "orderDate": "desc"
      }
    ],
    "size": 25,
    "query":
    {
        "filtered":
        {
            "filter":
            {
                "and":
                [
                    { "term": { "CategoryA":"A" } },
                    {
                        "or":
                        [
                            { "term": { "CategoryB":"B" } },
                            { "term": { "CategoryB":"C" } }
                        ]
                    }
                ]
            }
        }
    }
}

我意识到你并没有提到方面,只是为了完整起见:

你也可以使用filter作为基础(就像你一样)而不是filtered query(就像我做的那样)。得到的json几乎完全相同,差别在于:

  • 过滤后的查询将过滤主要结果以及构面
  • 过滤器只会过滤主要结果而非过滤面。

最后,嵌套过滤器(您尝试使用过)与您似乎相信的“嵌套过滤器”无关,但与嵌套文档(父子)的过滤有关

答案 1 :(得分:3)

虽然我完全不了解你的结构,但这可能就是你所需要的。

你必须从树上思考。你创建一个bool,你必须(=和)实现嵌入式bool。每个嵌入式检查字段是否不存在或者(在此处使用而不是必须)字段必须(此处的术语)是列表中的值之一。

不确定是否有更好的方法,并且不知道性能。

{
    "sort": [
        {
            "orderDate": "desc"
        }
    ],
    "size": 25,
    "query": {
        "query": {           #
            "match_all": {}  # These three lines are not necessary
        },                   #
        "filtered": {
            "filter": {
                "bool": {
                    "must": [
                        {
                            "bool": {
                                "should": [
                                    {
                                        "not": {
                                            "exists": {
                                                "field": "progress"
                                            }
                                        }
                                    },
                                    {
                                        "terms": {
                                            "progress": [
                                                "incomplete",
                                                "complete"
                                            ]
                                        }
                                    }
                                ]
                            }
                        },
                        {
                            "bool": {
                                "should": [
                                    {
                                        "not": {
                                            "exists": {
                                                "field": "paid"
                                            }
                                        }
                                    },
                                    {
                                        "terms": {
                                            "paid": [
                                                "yes",
                                                "no"
                                            ]
                                        }
                                    }
                                ]
                            }
                        }
                    ]
                }
            }
        }
    }
}