Course outline

Elasticsearch / Basic: document and query contracts / Lesson 6

Sorting, pagination and result contracts

Return stable catalog pages while controlling result shape, deep pagination and changing search views.

About 4 min readContent reviewed
On this page

Lesson goals

  • Build a total sort order using suitable field types.
  • Explain search_after, point-in-time and total-hit semantics.

A page includes more than a size

A catalog page needs an eligibility query, selected response fields, a total ordering and a continuation rule. Sorting by year alone leaves ties, so a stable unique artifact_id keyword can complete the order for a fixed data set. Do not sort on analyzed title text when an exact keyword representation is intended. Sorting directly on _id has restrictions and is not a general substitute for a doc-values-enabled business identifier field. Explain missing-year placement and ascending or descending direction explicitly. A user changing filters must start a new continuation sequence rather than reusing an unrelated cursor.

Read the returned sort values

The body below requests two artifacts in year and identifier order. In a fixed synthetic population ordered as (1880, art-100), (1890, art-101), (1890, art-102), the first two rows end at (1890, art-101). Search hits include their sort values when explicit sorting is used. The application should preserve the server-returned values and their types rather than reconstructing a cursor from formatted display text. Source filtering limits the returned source fields, but does not establish field-level authorization or eliminate all internal document work.

json Illustrative technical example; logical results are reasoned, not engine-tested.
{"size":2,"query":{"match_all":{}},"sort":[{"year":"asc"},{"artifact_id":"asc"}],"_source":["artifact_id","title","year"]}

For the fixed three-document teaching order, the last returned sort array is [1890,"art-101"]. This is reasoned fixture behavior.

search_after continues the same order

search_after asks for hits following the supplied sort tuple. Keep the query and sort definition unchanged between requests. The second body continues after the synthetic last tuple and therefore reaches art-102 in the fixed fixture. Without a stable search view, concurrent insertions, updates or refreshes can still change the population. A point-in-time context can preserve a consistent search view across requests when supported and correctly maintained. Use the latest returned PIT identifier and include all required tie-breaker values; do not assume an example two-value cursor applies unchanged when PIT adds a shard-document tie-breaker.

json Illustrative technical example; logical results are reasoned, not engine-tested.
{"size":2,"query":{"match_all":{}},"sort":[{"year":"asc"},{"artifact_id":"asc"}],"search_after":[1890,"art-101"],"_source":["artifact_id","title","year"]}

Continuation for the fixed-data ordinary-search example, without PIT. It is not a snapshot-consistency guarantee under concurrent changes.

Deep offsets ask shards to retain more candidates

from plus size is convenient for shallow pages, but each shard may need to collect candidates for earlier offsets as well as the visible page. Raising a result-window limit does not remove this cost. Prefer a supported continuation pattern for long traversals and define whether the user actually needs arbitrary page numbers. PIT contexts also retain resources and need bounded keep-alive and cleanup, so they are not free permanent bookmarks. Scroll serves particular bulk traversal scenarios and should not be chosen merely because its name resembles UI scrolling. Match the mechanism to a clear consistency and interaction requirement.

Read the total-hit relation

A total-hit value can carry relation eq for an exact count or gte for a lower bound under the tracking policy. Displaying every returned value as an exact catalog count can mislead users. track_total_hits can request stronger counting behavior at additional cost where appropriate. Search responses can also report timed_out and failed shards; a nonempty hit list is not proof of complete results. Define whether the application accepts partial search or displays an explicit incomplete state. Keep continuation tokens bound to the callerโ€™s allowed filters so a copied cursor cannot bypass access restrictions.

Common errors and fixes

Pages repeat artifacts with equal years

Why it happens
The sort lacks a stable unique tie-breaker.
How to fix it
Add a suitable keyword identity and preserve returned sort tuples.
Prevent it next time
Test multiple artifacts with identical primary sort values.

search_phase_execution_exception

Why it happens
A requested sort or result window conflicts with field behavior or limits.
How to fix it
Inspect the detailed cause and use mapped sort fields and an appropriate continuation.
Prevent it next time
Review pagination with realistic depth before release.

A lower-bound hit count is displayed as exact

Why it happens
The application ignored hits.total.relation.
How to fix it
Preserve the relation or request the justified exact-count policy.
Prevent it next time
Include partial, timed-out and lower-bound responses in UI fixtures.

Check your understanding

1. After sort tuple [1890,"art-101"], which fixture row follows in ascending order?

Show worked solution

The row (1890, art-102) follows because the year ties and the keyword identifier is greater. Preserve the exact tuple types. This answer assumes a fixed population; add a correctly managed PIT when the product requires a consistent view across concurrent refreshes.

2. Why is increasing the maximum result window not a complete deep-pagination strategy?

Show worked solution

It permits more retained candidates without removing per-shard collection and memory costs. Define the traversal requirement and evaluate search_after with a suitable consistency context. Keep a resource lifetime budget and handle partial responses rather than equating a larger limit with a scalable user experience.

Key takeaways

  • Stable pages require a total order and a defined search view.
  • Counts and partial-result indicators belong in the result contract.

Official references