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:

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

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"
}
}

Be Careful of Cardinality

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.