Skip to content

Latest commit

 

History

History
162 lines (133 loc) · 4.79 KB

File metadata and controls

162 lines (133 loc) · 4.79 KB

Ranges

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

Here is an example range query:
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
    }
}

Ranges on Dates

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)
    }
}
  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].

Ranges on Strings

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