Mixed filters, using OR as well as AND


(gkwelding) #1

In your opinion what would be the best way to do the following?

I want to filter an ElasticSearch query by several ranges that are grouped
in an OR filter, and then by one final range that needs to be included as
an AND filter. The explanation is a bit crappy but hopefully the
pseudo-code below will help...

Basically I tried structuring the following query:

{
"query":{
"multi_match":{
"query":"blue",
"fields":[
"name"
]
}
},
"sort":{
"_score":{
"order":"desc",
"missing":"_last"
}
},
"from":"0",
"size":"24",
"facets":{
"rating":{
"range":{
"field":"rating",
"ranges":[
{
"from":1
},
{
"from":2
},
{
"from":3
},
{
"from":4
}
]
}
},
"price":{
"range":{
"field":"price",
"ranges":[
{
"to":10
},
{
"from":10,
"to":100
},
{
"from":100,
"to":1000
}
{
"from":1000
}
]
}
}
},
"filter":{
"or":[
{
"range":{
"price":{
"from":"10",
"to":"100"
}
}
},
{
"range":{
"price":{
"from":"100",
"to":"1000"
}
}
}
],
"and":{
"numeric_range":{
"rating":{
"gte":"4"
}
}
}
}
}

This failed with the error that there was "No parser for element
[numeric_range]". So I tried replacing:

     "and":{
        "numeric_range":{
           "rating":{
              "gte":"4"
           }
        }
     }

with:

    "numeric_range":{
       "rating":{
          "gte":"4"
       }
    }

The query now returns results but it's returning results with prices in the
ranges 10-100, 100-1000 and ANY results with a rating greater than 4 (even
if their price is outside of the defined range).

Any clues on how I could do this query? Do I need to be using a bool filter?

--
You received this message because you are subscribed to the Google Groups "elasticsearch" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elasticsearch+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elasticsearch/f2dee635-794b-45e4-bc20-45429e233e14%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


(Boaz Leskes) #2

Hi,

You should use the boolean filter, where you put your AND filter under must
and the OR filter under should

filter: {
bool: {
must: [ {
"numeric_range":{
"rating":{
"gte":"4"
}
}
}],
should: [
{
"range":{
"price":{
"from":"10",
"to":"100"
}
}
},
{
"range":{
"price":{
"from":"100",
"to":"1000"
}
}
}
]

}

}

Also I noticed you use the top level filter option (on the same level as
facets and query). This means it will not affect the facets but just the
hits returned. Is this your intention?

If not, you should use the filtered query:
{
query: {
filtered: {
query: {...}
filter: {...}
}
},
facets: {...}
}

Cheers,
Boaz

On Wednesday, December 4, 2013 11:59:38 AM UTC+1, Garry Welding wrote:

In your opinion what would be the best way to do the following?

I want to filter an ElasticSearch query by several ranges that are grouped
in an OR filter, and then by one final range that needs to be included as
an AND filter. The explanation is a bit crappy but hopefully the
pseudo-code below will help...

Basically I tried structuring the following query:

{
"query":{
"multi_match":{
"query":"blue",
"fields":[
"name"
]
}
},
"sort":{
"_score":{
"order":"desc",
"missing":"_last"
}
},
"from":"0",
"size":"24",
"facets":{
"rating":{
"range":{
"field":"rating",
"ranges":[
{
"from":1
},
{
"from":2
},
{
"from":3
},
{
"from":4
}
]
}
},
"price":{
"range":{
"field":"price",
"ranges":[
{
"to":10
},
{
"from":10,
"to":100
},
{
"from":100,
"to":1000
}
{
"from":1000
}
]
}
}
},
"filter":{
"or":[
{
"range":{
"price":{
"from":"10",
"to":"100"
}
}
},
{
"range":{
"price":{
"from":"100",
"to":"1000"
}
}
}
],
"and":{
"numeric_range":{
"rating":{
"gte":"4"
}
}
}
}
}

This failed with the error that there was "No parser for element
[numeric_range]". So I tried replacing:

     "and":{
        "numeric_range":{
           "rating":{
              "gte":"4"
           }
        }
     }

with:

    "numeric_range":{
       "rating":{
          "gte":"4"
       }
    }

The query now returns results but it's returning results with prices in
the ranges 10-100, 100-1000 and ANY results with a rating greater than 4
(even if their price is outside of the defined range).

Any clues on how I could do this query? Do I need to be using a bool
filter?

--
You received this message because you are subscribed to the Google Groups "elasticsearch" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elasticsearch+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elasticsearch/cca9d0bc-1a9e-4681-980a-6950e45bff34%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


(gkwelding) #3

Thanks very much, yes, the intention is for the filter to not affect the
facets.

On Wednesday, December 4, 2013 11:58:09 AM UTC, Boaz Leskes wrote:

Hi,

You should use the boolean filter, where you put your AND filter under
must and the OR filter under should

filter: {
bool: {
must: [ {
"numeric_range":{
"rating":{
"gte":"4"
}
}
}],
should: [
{
"range":{
"price":{
"from":"10",
"to":"100"
}
}
},
{
"range":{
"price":{
"from":"100",
"to":"1000"
}
}
}
]

}

}

Also I noticed you use the top level filter option (on the same level as
facets and query). This means it will not affect the facets but just the
hits returned. Is this your intention?

If not, you should use the filtered query:
{
query: {
filtered: {
query: {...}
filter: {...}
}
},
facets: {...}
}

Cheers,
Boaz

On Wednesday, December 4, 2013 11:59:38 AM UTC+1, Garry Welding wrote:

In your opinion what would be the best way to do the following?

I want to filter an ElasticSearch query by several ranges that are
grouped in an OR filter, and then by one final range that needs to be
included as an AND filter. The explanation is a bit crappy but hopefully
the pseudo-code below will help...

Basically I tried structuring the following query:

{
"query":{
"multi_match":{
"query":"blue",
"fields":[
"name"
]
}
},
"sort":{
"_score":{
"order":"desc",
"missing":"_last"
}
},
"from":"0",
"size":"24",
"facets":{
"rating":{
"range":{
"field":"rating",
"ranges":[
{
"from":1
},
{
"from":2
},
{
"from":3
},
{
"from":4
}
]
}
},
"price":{
"range":{
"field":"price",
"ranges":[
{
"to":10
},
{
"from":10,
"to":100
},
{
"from":100,
"to":1000
}
{
"from":1000
}
]
}
}
},
"filter":{
"or":[
{
"range":{
"price":{
"from":"10",
"to":"100"
}
}
},
{
"range":{
"price":{
"from":"100",
"to":"1000"
}
}
}
],
"and":{
"numeric_range":{
"rating":{
"gte":"4"
}
}
}
}
}

This failed with the error that there was "No parser for element
[numeric_range]". So I tried replacing:

     "and":{
        "numeric_range":{
           "rating":{
              "gte":"4"
           }
        }
     }

with:

    "numeric_range":{
       "rating":{
          "gte":"4"
       }
    }

The query now returns results but it's returning results with prices in
the ranges 10-100, 100-1000 and ANY results with a rating greater than 4
(even if their price is outside of the defined range).

Any clues on how I could do this query? Do I need to be using a bool
filter?

--
You received this message because you are subscribed to the Google Groups "elasticsearch" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elasticsearch+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elasticsearch/74286bff-b63a-4c8c-8fe9-b560559a052b%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


(system) #4