Range query

Range query #

Returns documents that contain terms within a provided range.

Use it for intervals: prices between two numbers, events inside a time window, names inside an alphabetical span — anything expressible as “from / to” bounds rather than a list of exact values.

Inside a nested query: supported — the bounds apply per array element.

How it works #

The engine picks the index by field type:

  • Numeric and date fields — the per-field BKD range index (or the column store’s value-sorted region on merged segments without a BKD index). The BKD traversal returns an exact, pre-computed document-id list — no posting verification, no false positives. Date bounds go through the engine’s date parser: epoch numerics parse as epoch milliseconds, and ISO-8601 strings (2024-06-01, 2024-06-01T00:00:00Z) parse to their UTC instant before the traversal.
  • keyword / text fields — a lexicographic term range over the ordered dictionary: every term between the bounds is expanded and their postings unioned, exactly like a should of term queries. Bounds are first run through the field’s normalizer, if one is mapped, so date-descending keys sort as they were indexed.

Dual bounds conjoin. When you send both gt and gte (or both lt and lte), the engine applies them conjunctively and keeps the tighter bound — a tie resolves to the exclusive variant, so gt: 100, gte: 150 reads as ≥ 150. At most one bound per side is usually written; the conjoin exists so machine-generated bodies that carry both still behave deterministically.

Scoring. Range matches carry a constant score — the boost (1.0 by default) — with no BM25 input. A range is therefore the natural shape for bool.filter clauses: sliding time windows and price bands constrain the candidate set without touching relevance.

Date knobs. format and time_zone are accepted on the wire for compatibility; today the engine parses bounds with its built-in date parser and does not yet apply these two knobs.

Examples #

The following search returns the sales whose price is between 45 and 60 — 20 of the 120 documents in the sales dataset.

GET /_search
{
  "query": {
    "range": {
      "field": "age",
      "gte": 10,
      "lte": 20
    }
  }
}

Use cases #

  • Time windows. sales.date ≥ 2025-01-01 returns the 28 newest sales of 120 — the rolling-window filter behind every “last N months” dashboard. customers.since ≥ 2025-01-01 scopes to the 7 newest customers of 20.
  • Price bands. price ≤ 30 over sales matches the 90 economy sales (60 at 15, 30 at 30); pair one range with a terms on status for segmented funnels.
  • Lexicographic spans. Over keyword fields the same query slices alphabetically — id ranges, A*–M* name partitions — through the dictionary walk described above.
  • Alerting thresholds. Latency or disk-usage bounds as a must_not.range (the violation detector) inside a monitoring bool.

Parameters for range #

  • field
    (Required, string) Field you wish to search.
  • gt
    (Optional) Greater than.
  • gte
    (Optional) Greater than or equal to.
  • lt
    (Optional) Less than.
  • lte
    (Optional) Less than or equal to.
  • format
    (Optional, string) Date format for date-field range bounds. Accepted for body compatibility; not yet applied.
  • time_zone
    (Optional, string) Time zone for date-field range bounds, e.g. +08:00. Accepted for body compatibility; not yet applied.
  • boost
    (Optional, float, default: 1.0) Decrease or increase the relevance scores of the query.
  • relation
    (Optional, string) How the range matches range-typed fields: INTERSECTS (default), CONTAINS, or WITHIN.
  • range aggregation — bucket the same field into named intervals; the query filters, the aggregation counts.
  • date_range / date_histogram aggregations — time-bucketed views of the date windows a range query filters on.
  • term — the single-point special case, served by the same BKD index on numeric and date fields.
  • exists — the boundless question: does the field carry any value at all?
Calendar October 6, 2026
Edit Edit this page