All Products
Search
Document Center

Tablestore:Sort and paginate results

Last Updated:Jul 28, 2026

When querying a search index by using the Tablestore SDK for Java, use index sort or query-time sort to control the result order and use an offset or token to paginate results.

Prerequisites

Install the Tablestore SDK for Java and initialize a client.

How it works

Search indexes support the following sorting mechanisms:

  • Index sort: When creating a search index, configure IndexSchema.indexSort to define the default result order. If index sort is not configured, results are sorted by primary key. Index sort supports only PrimaryKeySort and FieldSort. A search index that contains a Nested field does not support index sort.

  • Query-time sort: Configure SearchQuery.sort for an individual query. Results can be sorted by relevance score, primary key, field value, or geographical distance. Multiple sorters can be combined for multi-level sorting. Except for primary key fields, a sort field must have enableSortAndAgg set to true in the search index schema.

When a query-time sorter other than a primary key sorter is specified, the server appends a primary key sorter by default so that rows with the same sort value have a deterministic order. To disable this behavior, set Sort.disableDefaultPkSorter to true.

Use one of the following pagination methods for large result sets:

Method

Use case

Characteristics

limit and offset

The result set contains no more than 100,000 rows and a specific position must be accessed.

Supports page jumps. The sum of limit and offset cannot exceed 100,000.

token

Deep pagination or sequentially reading all results.

Does not have the 100,000-row depth limit, but results can be read only in sequence.

Call the search method to query data.

SearchResponse search(SearchRequest request)

The following example returns the first 10 rows sorted by the score field in descending order and then by primary key in ascending order.

SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(new MatchAllQuery());
searchQuery.setLimit(10);
searchQuery.setSort(new Sort(Arrays.<Sort.Sorter>asList(
        new FieldSort("score", SortOrder.DESC),
        new PrimaryKeySort(SortOrder.ASC))));

SearchRequest request =
        new SearchRequest("example_table", "example_index", searchQuery);
SearchResponse response = client.search(request);

Parameters

Query request

The type of request is SearchRequest. The following table describes its parameters.

Name

Type

Description

tableName (required)

String

The name of the data table.

indexName (required)

String

The name of the search index.

searchQuery (required)

SearchQuery

The query condition and the sort and pagination configurations.

columnsToGet (optional)

SearchRequest.ColumnsToGet

The columns to return. If this parameter is not configured, only primary key columns are returned.

Query configuration

The type of request.searchQuery is SearchQuery. The following table describes only the parameters related to sorting and pagination.

Name

Type

Description

query (required)

Query

The query condition.

sort (optional)

Sort

The query-time sort configuration. If this parameter is not configured, index sort is used. Do not configure this parameter for token-based pagination. After setToken is called, the SDK clears the existing sort configuration.

offset (optional)

Integer

The position from which the current query starts. Default value: 0. This parameter cannot be configured for token-based pagination.

limit (optional)

Integer

The maximum number of rows to return. Default value: 10. The maximum value is 1000 if all returned columns are read from the search index, or 100 if any returned column must be read from the data table.

token (optional)

byte[]

The pagination token. Set this parameter to the nextToken value in the previous response to read the next page.

trackTotalCount (optional)

int

The expected maximum number of matching rows to count. Default value: TRACK_TOTAL_COUNT_DISABLED, which disables counting. Set the value to TRACK_TOTAL_COUNT to count all matching rows. A smaller value provides better query performance.

Sort configuration

The type of request.searchQuery.sort is Sort. The following table describes its parameters.

Name

Type

Description

sorters (required)

List<Sort.Sorter>

The list of sorters. The order of the list determines the priority of multi-level sorting. Supported sorters are ScoreSort, PrimaryKeySort, FieldSort, and GeoDistanceSort.

disableDefaultPkSorter (optional)

Boolean

Specifies whether to prevent the server from automatically appending a primary key sorter. Default value: false.

Relevance score sort

ScoreSort sorts rows by the relevance score calculated by using the BM25 algorithm. The following table describes its parameter.

Name

Type

Description

order (optional)

SortOrder

The sort order. ASC specifies ascending order, and DESC specifies descending order. Default value: DESC.

To sort by relevance score, explicitly configure ScoreSort. Otherwise, index sort is used.

Primary key sort

PrimaryKeySort sorts rows by primary key. The following table describes its parameter.

Name

Type

Description

order (optional)

SortOrder

The sort order. Default value: ASC.

Field sort

FieldSort sorts rows by field value. The following table describes its parameters.

Name

Type

Description

fieldName (required)

String

The name of the sort field. Sorting and aggregation must be enabled for the field.

order (optional)

SortOrder

The sort order. Default value: ASC.

mode (optional)

SortMode

The value to use when sorting a multi-valued field. MIN, MAX, and AVG use the minimum, maximum, and average values.

missingFields (optional)

List<String>

The list of fallback sort fields. If the current sort field is missing, the first field in the list that has a value is used. A fallback field must have the same type as the sort field.

missingValue (optional)

ColumnValue

The sort value to use if the sort field and all fallback fields are missing. Set this parameter to FIRST_WHEN_MISSING or LAST_WHEN_MISSING to always place missing rows first or last. A custom value of the same type as the field can also be used. If this parameter is not configured, missing rows are placed last.

nestedFilter (optional)

NestedFilter

The Nested sort configuration that specifies the Nested path and the child rows that participate in sorting. Configure this parameter only when sorting a Nested subfield.

Nested filter

The type of FieldSort.nestedFilter is NestedFilter. The following table describes its parameters.

Name

Type

Description

path (required)

String

The path of the Nested field.

query (required)

Query

The query condition that selects the Nested child rows that participate in sorting. Set the parameter to MatchAllQuery to use all child rows.

Geographical distance sort

GeoDistanceSort sorts rows by the distance between a geographical point field and target points. The following table describes its parameters.

Name

Type

Description

fieldName (required)

String

The name of the Geopoint field.

points (required)

List<String>

The target geographical points. Each point uses the latitude,longitude format.

order (optional)

SortOrder

The sort order. ASC sorts from nearest to farthest, and DESC sorts from farthest to nearest.

mode (optional)

SortMode

The value to use when multiple distances exist. Supported values are MIN, MAX, and AVG.

distanceType (optional)

GeoDistanceType

The distance calculation method. ARC performs a spherical calculation for higher accuracy. PLANE performs a planar calculation with less computation. Default value: ARC.

nestedFilter (optional)

NestedFilter

The Nested sort configuration. Configure this parameter only when sorting a Nested subfield.

Columns to return

The type of request.columnsToGet is SearchRequest.ColumnsToGet. Whether returned columns must be read from the data table affects the maximum limit value.

Name

Type

Description

columns (optional)

List<String>

The names of the attribute columns to return. Data can be read directly from the search index only if all specified attribute columns are indexed and have store enabled.

returnAll (optional)

boolean

Specifies whether to return all attribute columns in the data table. Default value: false. If this parameter is true, attribute columns must be read from the data table and the maximum limit value is 100.

returnAllFromIndex (optional)

boolean

Specifies whether to return all stored attribute columns in the search index. Default value: false. If this parameter is true, the maximum limit value is 1000. Do not set both this parameter and returnAll to true.

Response

The search method returns SearchResponse. The following table describes the fields related to sorting and pagination.

Name

Type

Description

rows

List<Row>

The rows returned by the current query. Call getRows() to obtain the value. The number of rows does not exceed limit.

searchHits

List<SearchHit>

The search hits. Call getSearchHits() to obtain the value.

totalCount

long

The number of matching rows. Call getTotalCount() to obtain the value. The value depends on trackTotalCount and is not the number of rows on the current page.

nextToken

byte[]

The token for the next page. Call getNextToken() to obtain the value. A null value indicates that no more data exists or the current query has no deterministic sort order.

isAllSuccess

boolean

Indicates whether all index partitions were queried. Call isAllSuccess() to obtain the value. If this field is false, the response contains partial results.

Examples

Configure index sort

The following example configures the score field as an index sort field when a search index is created. If sort is not configured for a query, results are returned in ascending order of score.

FieldSchema score = new FieldSchema("score", FieldType.LONG)
        .setEnableSortAndAgg(true);

IndexSchema indexSchema = new IndexSchema();
indexSchema.setFieldSchemas(Collections.singletonList(score));
indexSchema.setIndexSort(new Sort(
        Collections.<Sort.Sorter>singletonList(
                new FieldSort("score", SortOrder.ASC))));

Sort by relevance score

The following example returns results in descending order of BM25 relevance score.

TermQuery termQuery = new TermQuery();
termQuery.setFieldName("category");
termQuery.setTerm(ColumnValue.fromString("book"));

SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(termQuery);
searchQuery.setSort(new Sort(
        Collections.<Sort.Sorter>singletonList(new ScoreSort())));

Handle missing field values

The following example sorts rows by the score field in descending order. If a row does not contain the field, the value of score_backup is used. If both fields are missing, the row is placed last.

FieldSort fieldSort = new FieldSort("score", SortOrder.DESC);
fieldSort.setMissingFields(Collections.singletonList("score_backup"));
fieldSort.setMissingValue(FieldSort.LAST_WHEN_MISSING);

SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(new MatchAllQuery());
searchQuery.setSort(new Sort(
        Collections.<Sort.Sorter>singletonList(fieldSort)));

Sort multi-valued and Nested fields

When sorting an array or another multi-valued field, use mode to specify the value that participates in sorting. The following example sorts rows in descending order by the maximum value in the scores array.

FieldSort fieldSort = new FieldSort("scores", SortOrder.DESC);
fieldSort.setMode(SortMode.MAX);

SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(new MatchAllQuery());
searchQuery.setSort(new Sort(
        Collections.<Sort.Sorter>singletonList(fieldSort)));

When sorting a Nested subfield, also configure the Nested path and select the child rows that participate in sorting. The following example uses only child rows where items.age is 1 and sorts rows in ascending order by the minimum value of items.name.

TermQuery ageQuery = new TermQuery();
ageQuery.setFieldName("items.age");
ageQuery.setTerm(ColumnValue.fromLong(1));

FieldSort fieldSort = new FieldSort("items.name", SortOrder.ASC);
fieldSort.setMode(SortMode.MIN);
fieldSort.setNestedFilter(new NestedFilter("items", ageQuery));

SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(new MatchAllQuery());
searchQuery.setSort(new Sort(
        Collections.<Sort.Sorter>singletonList(fieldSort)));

Sort by geographical distance

The following example returns rows from nearest to farthest based on the spherical distance between the location field and 30.23,120.19.

GeoDistanceSort geoSort = new GeoDistanceSort(
        "location", Collections.singletonList("30.23,120.19"));
geoSort.setOrder(SortOrder.ASC);
geoSort.setDistanceType(GeoDistanceType.ARC);

SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(new MatchAllQuery());
searchQuery.setSort(new Sort(
        Collections.<Sort.Sorter>singletonList(geoSort)));

Paginate by using limit and offset

The following example skips the first 100 rows and returns the next 100 rows. When this method is used, the sum of limit and offset cannot exceed 100,000.

SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(new MatchAllQuery());
searchQuery.setLimit(100);
searchQuery.setOffset(100);

Paginate by using a token

The following example reads all results in a loop. The token is null for the first query. Each subsequent query directly uses the nextToken from the previous response. After setToken is called, the SDK clears sort because the token contains the sort conditions of the previous page.

List<Row> rows = new ArrayList<Row>();
byte[] nextToken = null;
do {
    SearchQuery searchQuery = new SearchQuery();
    searchQuery.setQuery(new MatchAllQuery());
    searchQuery.setLimit(100);
    searchQuery.setToken(nextToken);

    SearchRequest request =
            new SearchRequest("example_table", "example_index", searchQuery);
    SearchResponse response = client.search(request);
    rows.addAll(response.getRows());
    nextToken = response.getNextToken();
} while (nextToken != null);
Important
  • Offset cannot be configured and pages cannot be skipped during token-based pagination. To return to a previous page, cache the token used to request each page and issue another query by using the token for the target page.

  • A search index that contains a Nested field has no index sort. To use token-based pagination with this type of index, explicitly configure sort in the first query. Otherwise, the server does not return nextToken.

For sequential queries in the same process, pass nextToken directly as a byte array. Use Base64 encoding only when the token must be persisted or transferred across processes or between a frontend and backend. Do not convert the token by using new String(nextToken), which corrupts the token.

String encodedToken = Base64.getEncoder().encodeToString(nextToken);
byte[] decodedToken = Base64.getDecoder().decode(encodedToken);