For large datasets or deep navigation, use SearchAfter (forward) or SearchBefore (backward) pagination. This method keeps resource usage proportional to the page size rather than the depth of the page.
Rules for usage:
- Use either
SearchAfter or SearchBefore, but never both in a single request. - The length of the
search_after or search_before array must exactly match the length of the sort array. - Values in the array must be strings representing the sort keys in the same order as defined in
sort. - You must maintain the same
query and sort parameters across all pages to ensure consistent navigation.
How to get sort keys:
- For each hit in the result set, Bleve provides a
Sort array. - For forward pagination (
SearchAfter), take the sort keys from the last hit of the current page. - For backward pagination (
SearchBefore), take the sort keys from the first hit of the current page.
Handling non-string types (Numeric, Datetime, Geo):
Internal representations of numeric, datetime, or geo data can appear garbled in the standard Sort field. To use these as pagination keys, use the DecodedSort field (available in Bleve v2.5.2+).
When using DecodedSort, your sort array must explicitly declare the field type using SortField (for numeric/datetime) or SortGeoDistance (for geo) objects instead of simple field name strings.
// Forward pagination example
{
"query": { "match": "California" },
"sort": ["_id", "_score"],
"search_after": ["hotel_10180", "0.998"],
"size": 3
}
// Backward pagination example
{
"query": { "match": "California" },
"sort": ["_id", "_score"],
"search_before": ["hotel_17595", "0.623"],
"size": 4
}
// Pagination with complex types (Numeric, Date, Geo)
{
"query": {
"match_all": {}
},
"size": 10,
"sort": [
{"by": "field", "field": "price", "type": "number"},
{"by": "field", "field": "created_at", "type": "date"},
{"by": "geo_distance", "field": "location", "location": {"lat": 40.7128, "lon": -74.0060}}
],
"search_after": ["99.99", "2023-10-15T10:30:00Z", "5.2"]
}