When dealing with numbers in this chapter, we have so far searched for only exact numbers. In practice, filtering on ranges is often more useful. For example, you might want to find all products with a price greater than $20 and less than $40.
In SQL terms, a range can be expressed as follows:
SELECT document
FROM products
WHERE price BETWEEN 20 AND 40
Elasticsearch has a range
query, which, unsurprisingly,
can be used to find documents falling inside a range:
"range" : {
"price" : {
"gte" : 20,
"lte" : 40
}
}
The range
query supports both inclusive and exclusive ranges, through
combinations of the following options:
-
gt
:>
greater than -
lt
:<
less than -
gte
:>=
greater than or equal to -
lte
:⇐
less than or equal to
GET /my_store/products/_search
{
"query" : {
"constant_score" : {
"filter" : {
"range" : {
"price" : {
"gte" : 20,
"lt" : 40
}
}
}
}
}
}
If you need an unbounded range (for example, just >20), omit one of the boundaries:
"range" : {
"price" : {
"gt" : 20
}
}
The range
query can be used on date fields too:
"range" : {
"timestamp" : {
"gt" : "2014-01-01 00:00:00",
"lt" : "2014-01-07 00:00:00"
}
}
When used on date fields, the range
query supports date math operations.
For example, if we want to find all documents that have a timestamp sometime
in the last hour:
"range" : {
"timestamp" : {
"gt" : "now-1h"
}
}
This filter will now constantly find all documents with a timestamp greater than the current time minus 1 hour, making the filter a sliding window across your documents.
Date math can also be applied to actual dates, rather than a placeholder like
now. Just add a double pipe (||
) after the date and follow it with a date
math expression:
"range" : {
"timestamp" : {
"gt" : "2014-01-01 00:00:00",
"lt" : "2014-01-01 00:00:00||+1M" (1)
}
}
-
Less than January 1, 2014 plus one month
Date math is calendar aware, so it knows the number of days in each month, days in a year, and so forth. More details about working with dates can be found in the {ref}/mapping-date-format.html[date format reference documentation].
The range
query can also operate on string fields.
String ranges are
calculated lexicographically or alphabetically. For example, these values
are sorted in lexicographic order:
-
5, 50, 6, B, C, a, ab, abb, abc, b
Note
|
Terms in the inverted index are sorted in lexicographical order, which is why string ranges use this order. |
If we want a range from a
up to but not including b
, we can use the same
range
query syntax:
"range" : {
"title" : {
"gte" : "a",
"lt" : "b"
}
}
Numeric and date fields are indexed in such a way that ranges are efficient
to calculate. This is not the case for string fields, however. To perform
a range on a string field, Elasticsearch is effectively performing a term
filter for every term that falls in the range. This is much slower than
a date or numeric range.
String ranges are fine on a field with low cardinality—a small number of unique terms. But the more unique terms you have, the slower the string range will be.