Как сделать вложенные фильтры AND и OR в 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. Это на правильном пути или мне нужно использовать другой фильтр?
Ответы
Ответ 1
Это должно быть оно (переведено с данного псевдо-SQL)
{
"sort": [
{
"orderDate": "desc"
}
],
"size": 25,
"query":
{
"filtered":
{
"filter":
{
"and":
[
{ "term": { "CategoryA":"A" } },
{
"or":
[
{ "term": { "CategoryB":"B" } },
{ "term": { "CategoryB":"C" } }
]
}
]
}
}
}
}
Я понимаю, что вы не упоминаете грани, а только ради полноты:
Вы также можете использовать filter
в качестве основы (как и вы) вместо filtered query
(как и я). Полученный json почти идентичен разнице:
- отфильтрованный запрос будет фильтровать как основные результаты, так и грани
- фильтр будет фильтровать только основные результаты NOT facets.
Наконец, вложенные фильтры (которые вы пытались использовать) не связаны с "фильтрами вложенности", как вы, казалось, верили, но связаны с фильтрацией на вложенных документах (parent-child)
Ответ 2
Хотя я полностью не понимаю вашу структуру, это может быть то, что вам нужно.
Вы должны думать по-деревенски. Вы создаете bool, где вы должны (= и) выполнять встроенные bools. Каждый встроенный проверяет, не существует ли поле или нет (вместо этого нужно использовать здесь здесь) поле должно (условия здесь) быть одним из значений в списке.
Не уверен, есть ли лучший способ и не знает производительности.
{
"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"
]
}
}
]
}
}
]
}
}
}
}
}