Todos os produtos
Search
Central de documentação

Tablestore:Sort and paginate results

Última atualização: Jul 03, 2026

Ao consultar dados com um índice de busca, defina uma ordem de classificação antecipadamente ou especifique-a no momento da consulta para obter os resultados em uma sequência específica. Se o conjunto de resultados for grande, use a paginação baseada em offset ou em token para localizar rapidamente os dados necessários.

Classificação do índice

Por padrão, um índice de busca ordena os dados com base na sua index sort. Ao consultar dados com esse índice, a configuração IndexSort determina a ordem de classificação padrão.

Durante a criação de um índice de busca, você pode definir uma IndexSort personalizada. Caso nenhuma seja especificada, o índice adota a ordenação pela chave primária como padrão.

Importante
  • A classificação do índice suporta apenas PrimaryKeySort (ordenação por chave primária) e FieldSort (ordenação por valor de campo).

  • Índices de busca que contêm campos do tipo nested não suportam classificação de índice.

Classificação no momento da consulta

A ordenação só é permitida em campos onde enableSortAndAgg esteja definido como true.

Especifique uma ordem de classificação para cada consulta. Um índice de busca oferece suporte aos quatro tipos de classificadores (Sorter) listados abaixo. Combine classificadores para criar uma ordenação multinível.

ScoreSort

Ordena os resultados pela pontuação de relevância, calculada pelo algoritmo BM25. Este método é adequado para cenários como busca de texto completo.

Importante

Para ordenar os resultados pela pontuação de relevância, especifique explicitamente ScoreSort. Caso contrário, a ordenação seguirá a configuração IndexSort do índice de busca.

SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(new ScoreSort())));

PrimaryKeySort

Ordena os resultados pela chave primária.

SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(new PrimaryKeySort()))); // Ascending order.
//searchQuery.setSort(new Sort(Arrays.asList(new PrimaryKeySort(SortOrder.DESC)))); // Descending order.

FieldSort

Ordena os resultados pelo valor de uma coluna especificada.

Classificação por coluna única

Ordena os resultados pelos valores de uma única coluna.

SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(new FieldSort("col", SortOrder.ASC))));

Classificação por múltiplas colunas

Ordena os resultados pelos valores de uma coluna e, em seguida, pelos valores de outra coluna.

SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(
    new FieldSort("col1", SortOrder.ASC), new FieldSort("col2", SortOrder.ASC))));

Classificação com fallback

Ao ordenar por uma coluna do tipo Long, Double ou Date, use o parâmetro missingField para especificar uma coluna de fallback do mesmo tipo. Esse fallback será usado para qualquer linha sem valor na coluna de classificação primária.

/**
* Sorts by `Col_Long` in descending order. If a row is missing a `Col_Long` value, it uses the value from `Col_Long_sec` instead.
*/
SearchQuery searchQuery = new SearchQuery();
FieldSort fieldSort = new FieldSort("Col_Long");
// Specifies `Col_Long_sec` as the fallback for missing values in `Col_Long`.
fieldSort.setMissingField("Col_Long_sec");
fieldSort.setOrder(SortOrder.DESC); 

Classificação de valores ausentes

Se um documento não possuir o campo de ordenação, use o parâmetro missingValue para controlar sua posição nos resultados ordenados.

O comportamento da ordenação é o seguinte:

  • Quando missingValue está definido como FieldSort.FIRST_WHEN_MISSING, documentos com valores ausentes aparecem sempre no início dos resultados, independentemente da ordem de classificação (ascendente ou descendente).

  • Quando missingValue está definido como FieldSort.LAST_WHEN_MISSING ou não está definido (null), documentos com valores ausentes aparecem sempre no final dos resultados, independentemente da ordem de classificação.

    /**
     * Sorts by `Col_Long` in descending order. Places documents with a missing `Col_Long` value at the beginning of the results.
     */
    SearchQuery searchQuery = new SearchQuery();
    FieldSort fieldSort = new FieldSort("Col_Long");
    // Places documents with missing values first.
    fieldSort.setMissingValue(FieldSort.FIRST_WHEN_MISSING);
    fieldSort.setOrder(SortOrder.DESC);
    searchQuery.setSort(new Sort(Arrays.asList(fieldSort)));

Classificação de múltiplos valores

Para campos com múltiplos valores, como arrays ou campos do tipo nested type, use o parâmetro mode para especificar qual valor da coleção deve ser usado na ordenação.

Ordene por um valor específico dentro de um array.

// Rows doc1 and doc2 contain an array field named field1. In doc1, the value of field1 is [2,3]. In doc2, the value is [1,3,4].
// You can set the mode parameter to specify which value in the array to use for sorting.
{
    // If mode is set to SortMode.MAX, the results are doc2 (sorted by 4) and then doc1 (sorted by 3).
    FieldSort fieldSort = new FieldSort("field1", SortOrder.DESC);
    fieldSort.setMode(SortMode.MAX);
}
{
    // If mode is set to SortMode.MIN, the results are doc1 (sorted by 2) and then doc2 (sorted by 1).
    FieldSort fieldSort = new FieldSort("field1", SortOrder.DESC);
    fieldSort.setMode(SortMode.MIN);
}

Também é possível ordenar por valores dentro de subcampos de um tipo nested.

// Rows doc1 and doc2 contain a nested type field named field1.
// In doc1, the value of field1 is [{"name":"b", "age":1},{"name":"a", "age":7}].
// In doc2, the value of field1 is [{"name":"a", "age":1},{"name":"c", "age":1},{"name":"d", "age":5}].

{
    // Sort all sub-rows and use the mode parameter to specify which value to sort by.
    // If you set mode to SortMode.MAX and sort by the age field, the result is doc1 (sorted by 7) and then doc2 (sorted by 5).
    FieldSort fieldSort = new FieldSort("field1.age", SortOrder.DESC);
    fieldSort.setMode(SortMode.MAX);
    String path = "field1";
    NestedFilter nestedFilter = new NestedFilter(path, QueryBuilders.matchAll().build());
    fieldSort.setNestedFilter(nestedFilter);
}
{
    // Sort only the sub-rows where age=1 and use the mode parameter to specify which value to sort by.
    {
        // If you set mode to SortMode.MAX and sort by the name field, the result is doc2 (sorted by "c") and then doc1 (sorted by "b").
        FieldSort fieldSort = new FieldSort("field1.name", SortOrder.DESC);
        fieldSort.setMode(SortMode.MAX);
        String path = "field1";
        NestedFilter nestedFilter = new NestedFilter(path, QueryBuilders.term("field1.age",1).build());
        fieldSort.setNestedFilter(nestedFilter);
    }
    {
        // If you set mode to SortMode.MIN and sort by the name field, the result is doc1 (sorted by "b") and then doc2 (sorted by "a").
        FieldSort fieldSort = new FieldSort("field1.name", SortOrder.DESC);
        fieldSort.setMode(SortMode.MIN);
        String path = "field1";
        NestedFilter nestedFilter = new NestedFilter(path, QueryBuilders.term("field1.age",1).build());
        fieldSort.setNestedFilter(nestedFilter);
    }
}

GeoDistanceSort

Ordena os resultados pela distância a partir de um ponto geográfico.

SearchQuery searchQuery = new SearchQuery();
// Sorts results by distance from the `geo` (Geopoint) column value to the point "0,0".
Sort.Sorter sorter = new GeoDistanceSort("geo", Arrays.asList("0, 0"));
searchQuery.setSort(new Sort(Arrays.asList(sorter)));

Métodos de paginação

Para recuperar resultados, use os parâmetros limit e offset ou um token para paginação.

Paginação com limit e offset

Use limit e offset para paging, mas a soma de limit e offset não pode exceder 100.000, e o valor máximo para limit é 100.

Nota

Para saber como aumentar o limit para 1.000, consulte Como aumentar o limite de resultados da Search API para 1.000 em um índice de busca?.

Se não forem definidos, limit assume o valor padrão 10 e offset assume o valor padrão 0.

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

Paginação baseada em token

Recomendamos a paginação baseada em token para paginações profundas, pois ela não possui limitações de profundidade.

Se uma consulta tiver mais resultados a retornar, a resposta incluirá um nextToken. Use esse token na próxima solicitação para recuperar a página seguinte de resultados.

Por padrão, a paginação baseada em token permite apenas avançar pelos resultados. No entanto, como os tokens permanecem válidos durante toda a sessão de paginação, armazene em cache os tokens anteriores para implementar a navegação para trás.

Importante

Para persistir um nextToken ou enviá-lo a um aplicativo front-end, codifique-o em Base64. O nextToken é um array de bytes, não uma string. Convertê-lo diretamente com new String(nextToken) corromperá o token e causará perda de dados.

Um token preserva a ordem de classificação da solicitação anterior, seja ela a classificação padrão do índice ou uma ordem personalizada. Portanto, não é possível especificar um parâmetro Sort em uma solicitação baseada em token. Também não é permitido usar o parâmetro offset, pois o próprio token dita a posição inicial.

Importante

Um índice de busca com um campo do tipo nested não suporta classificação de índice. Para paginate resultados desse search index, especifique uma ordem de classificação na consulta. Caso contrário, o servidor não retornará um nextToken, mesmo que haja mais resultados disponíveis.

private static void readMoreRowsWithToken(SyncClient client) {
    SearchQuery searchQuery = new SearchQuery();
    searchQuery.setQuery(new MatchAllQuery());
    searchQuery.setGetTotalCount(true);// Set this to true to return the total number of matched rows.
    // Specify the table name (e.g., sampleTable) and the search index name (e.g., sampleSearchIndex). You can find the search index name on the Indexes tab of your table in the Tablestore console or by listing search indexes using the SDK.
    SearchRequest searchRequest = new SearchRequest("<TABLE_NAME>", "<SEARCH_INDEX_NAME>", searchQuery);

    SearchResponse resp = client.search(searchRequest);
    if (!resp.isAllSuccess()) {
        throw new RuntimeException("not all success");
    }
    List<Row> rows = resp.getRows();
    while (resp.getNextToken()!=null) { // A null `nextToken` means all data has been retrieved.
        // Get the nextToken.
        byte[] nextToken = resp.getNextToken();

        {
            // If you need to persist the nextToken or send it to a front-end application, use Base64 encoding to convert it to a string.
            // The token itself is not a string. Directly converting it using new String(nextToken) will corrupt the token.
            String tokenAsString = Base64.toBase64String(nextToken);
            // Decode the string back to a byte array.
            byte[] tokenAsByte = Base64.fromBase64String(tokenAsString);
        }

        // Set the token for the next request.
        searchRequest.getSearchQuery().setToken(nextToken);
        resp = client.search(searchRequest);
        if (!resp.isAllSuccess()) {
            throw new RuntimeException("not all success");
        }
        rows.addAll(resp.getRows());
    }
    System.out.println("RowSize: " + rows.size());
    System.out.println("TotalCount: " + resp.getTotalCount());// Prints the total count of matched rows, not the number of rows returned in this response.
}

FAQ

Referências