Sort and pagination #
Control which documents come back and in what order — sort, from/size,
search_after/search_before, and total-hit accounting.
POST /my-collection/_search
How it works #
sort is an array of sort clauses evaluated in order; the first clause
that produces a difference decides the order. Sorting on an indexed field
lets the collector skip documents that cannot make the cut (early
termination), so field sorts — and _doc above all — are cheaper than
score sorts, not just differently ordered.
Three details the engine guarantees:
- Ties break by internal doc order. Documents whose sort keys are equal (including two missing values) keep a stable, repeatable order across pages — safe for cursor pagination.
- Sort keys echo per-field precision. Sorting a
datefield returns millisecond keys; adate_nanosfield returns full nanosecond keys (.123456789survives), with the key rendered according to each field’s mapping — and the sort works through wildcard index patterns (conformance case240_date_nanos). - Geo proximity is a score, not a sort key. There is no
_geo_distancesort clause; order by distance with thedistance_featurequery, which scores every hit byboost × pivot / (pivot + distance)from an origin — nearest first simply falls out of relevance order.
Sort #
Parameters #
field
(Required, string) The field to sort by. Two pseudo-fields are always available:_score(relevance, descending by default) and_doc(index order — the cheapest possible sort).order
(Optional,asc|desc) Sort direction. When omitted in a canonical clause the engine sorts descending — for_scoreand regular fields alike. The Elasticsearch shorthand forms ("sort": "date", bare"date"in the array) are the exception: the gateway normalizes them toasc, so the direction you see depends on the form you send. When in doubt, spellorderout.missing
(Optional,first|last; the gateway also accepts the Elasticsearch spellings_first/_last) Where documents without a value for the field land, independent of the sort direction. Default:last. Documents whose keys tie (including two missing values) break the tie by internal doc order, so pages are repeatable.script
(Optional, string | object) Withfield: "_script"only: the sort key is computed per hit of the returned page by this script (docandparamsin scope) instead of an indexed field. At most one_scriptclause per request — see scripted queries.
Index-time sorted fields (see
field parameters) join _doc
among the fastest keys.
Pagination #
from
(Optional, integer, default:0) Offset of the first hit to return.size
(Optional, integer, default:10) Number of hits to return.0with aggregations skips hit assembly entirely.track_total_hits
(Optional, boolean | integer) Whether to compute the exact hit count.falseskips counting when you only need the page; a number caps the counting work. The gateway accepts the Elasticsearch form, default cap 10000.collect_size
(Optional, integer) Upper bound on candidate documents collected before ranking — a guard rail for very broad queries.
Deep from paging re-ranks everything before the offset. Prefer cursors:
search_after
(Optional, array) Return the rows that follow the given sort-key tuple. Take the tuple from the last hit of the previous page (sortvalues of that hit) and pass it back.search_before
(Optional, array) The mirror image — the rows that precede the tuple. Together withsearch_afterthis enables bidirectional cursored paging.
For a stable view across pages, run the search against a point-in-time
snapshot (pit — see
API conventions).
Examples #
Cheapest first page of everything, newest first:
Cursor to the next page with the last hit’s sort tuple — the engine
answers the rows strictly AFTER the tuple:
The first page’s newest document is S120 (epoch 1745276400000);
the cursor page starts at the second-newest. A multi-key sort array
gives the cursor a unique tuple per document (see the wasm note below
about float-typed single keys).
Notes #
- Sorting by a field that is only in the document source (not indexed, not a column) forces full materialization — index the field or accept the cost.
- The gateway also accepts the shorthand forms
(
"sort": ["date"],"sort": [{"date":"asc"}]) and normalizes them to the canonical clause above.
Use cases #
- Newest-first feeds.
sort: [{field: date, order: desc}]over the 120-sale history (or the 150-log stream) withtrack_total_hitsfor the total and cursors for endless scroll. - Deterministic exports.
_docorder — index order, the cheapest key the engine has — for dump jobs that must replay identically. - Composite leaderboards. Multi-clause sorts (
price desc, date asc) with explicitmissingplacement so documents without the field land where the product spec says, not wherever ties dump them. - Geo-ordered results.
placesnearest-first: no_geo_distancesort — sort by_scoreunder adistance_featurequery centered on the user (see How it works). - Deep pagination at scale.
search_after/search_beforecursor walks instead offromoffsets, pinned to apitsnapshot when the index keeps moving.
Related #
- Field collapsing and rescore — the other two result-shaping stages; collapse pages over groups of the sorted list, rescore re-sorts the top window by blended score.
distance_featurequery — proximity ordering as scoring, for dates and geo points.- Scripted queries — the
_scriptsort key andscript_score, the query-time scripting surface. - API conventions —
pitsnapshots and the cursor contract in the wider API.