Ao consultar dados em um índice de busca, ordene os resultados com base em uma ordem predefinida ou especificada no momento da consulta. Para grandes conjuntos de resultados, use a paginação baseada em deslocamento (offset) ou em token para localizar rapidamente os dados necessários.
Casos de uso
Categoria | Método | Recurso | Caso de uso |
Ordenação | Defina na criação | Por padrão, o Tablestore ordena os dados em um índice de busca usando o método de pré-ordenação de índice ( | |
Defina na consulta | Ordena os resultados da consulta pela pontuação de relevância, calculada pelo algoritmo BM25. Ideal para cenários baseados em relevância, como busca de texto completo. | ||
Classifica os resultados pela chave primária. Útil para organizar itens pelos identificadores exclusivos. | |||
Organiza os resultados pelo valor do campo. Aplicável a cenários de e-commerce ou redes sociais, nos quais a ordenação ocorre por atributos como volume de vendas ou visualizações de página. Para campos com múltiplos valores, como campos do tipo array ou nested, use o parâmetro | |||
Classifica os resultados pela distância de um ponto geográfico. Adequado para serviços baseados em localização, como mapas ou logística; por exemplo, ordenar restaurantes próximos por distância. | |||
Paginação | Defina na consulta | Use a paginação baseada em deslocamento quando o número total de linhas a recuperar for inferior a 100.000. | |
Use a paginação baseada em token para recuperar sequencialmente grandes conjuntos de resultados. Por padrão, a navegação ocorre apenas para frente. No entanto, como o token permanece válido durante todo o processo de consulta, armazene em cache um token anterior para paginar para trás. |
SDKs
Implemente a ordenação e a paginação usando os SDKs das linguagens a seguir.
Pré-ordenação de índice
Por padrão, o Tablestore organiza os dados em um índice de busca com base em uma ordem predefinida, denominada pré-ordenação de índice (IndexSort). Durante a consulta de dados, o IndexSort determina a ordem padrão dos resultados retornados.
Ao criar um índice de busca, personalize o IndexSort. Se você não especificar essa configuração, o índice adotará a ordenação por chave primária como padrão.
A pré-ordenação de índice suporta apenas
PrimaryKeySort(ordenação por chave primária) eFieldSort(ordenação por campo).Não use a pré-ordenação de índice em um índice de busca que contenha campos do tipo nested.
Após criar um índice de busca, use o recurso de modificação dinâmica de esquema para alterar as configurações de
IndexSort.
Ordenação no momento da consulta
Ordene apenas campos cuja propriedade enableSortAndAgg esteja definida como true.
Especifique um método de ordenação para cada consulta. Um índice de busca suporta os quatro tipos de classificadores a seguir. Combine vários classificadores para ordenar os resultados com base em uma sequência de critérios.
ScoreSort
Classifica os resultados da consulta pela pontuação de relevância, calculada pelo algoritmo BM25. Este método é adequado para cenários baseados em relevância, como busca de texto completo.
Para ordenar por pontuação de relevância, especifique explicitamente o
ScoreSort. Caso contrário, o Tablestore classificará os resultados conforme as configurações deIndexSortdo índice.Ao usar o
ScoreSort, campos do tipo FuzzyKeyword não são incluídos na ordenação, e o parâmetroweightnão tem efeito sobre esses campos.
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()))); // In ascending order.
//searchQuery.setSort(new Sort(Arrays.asList(new PrimaryKeySort(SortOrder.DESC)))); // In descending order.
FieldSort
Classifica os resultados pelo valor do campo.
Ordenação por campo único
Organiza os resultados com base nos valores de um único campo.
SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(new FieldSort("col", SortOrder.ASC))));
Ordenação por múltiplos campos
Classifica os resultados primeiramente pelos valores de um campo e, em seguida, pelos valores de outro campo.
SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(
new FieldSort("col1", SortOrder.ASC), new FieldSort("col2", SortOrder.ASC))));
Campo de fallback
Ao ordenar por um campo do tipo Long, Double ou Date, defina o parâmetro missingField. Esse parâmetro especifica outro campo do mesmo tipo a ser usado como valor de fallback para ordenação caso uma linha não possua valor no campo de ordenação principal.
/**
* Sort results in descending order based on the values in the Col_Long field.
* If a row is missing a value in the Col_Long field (Long type),
* the value from the Col_Long_sec field (Long type) is used for sorting instead.
*/
SearchQuery searchQuery = new SearchQuery();
FieldSort fieldSort = new FieldSort("Col_Long");
// Specify the Col_Long_sec field as the fallback for sorting when a value is missing in the Col_Long field.
fieldSort.setMissingField("Col_Long_sec");
fieldSort.setOrder(SortOrder.DESC);
Valores ausentes
O parâmetro missingValue define a posição de ordenação para documentos sem o campo de classificação. Configure esse parâmetro para controlar onde esses documentos aparecerão nos resultados.
O comportamento da ordenação é o seguinte:
Se
missingValuefor definido comoFieldSort.FIRST_WHEN_MISSING, os documentos com valores ausentes serão sempre colocados no início dos resultados, independentemente da ordem de classificação (ascendente ou descendente).-
Caso
missingValueseja definido comoFieldSort.LAST_WHEN_MISSINGounull, os documentos com valores ausentes serão sempre posicionados ao final dos resultados, independentemente da ordem de classificação./** * Sort results in descending order based on the values in the Col_Long field (Long type). * If a row is missing a value in the Col_Long field, place that document at the beginning of the results. */ SearchQuery searchQuery = new SearchQuery(); FieldSort fieldSort = new FieldSort("Col_Long"); // Place documents with missing values first. fieldSort.setMissingValue(FieldSort.FIRST_WHEN_MISSING); fieldSort.setOrder(SortOrder.DESC); searchQuery.setSort(new Sort(Arrays.asList(fieldSort)));
Campos com múltiplos valores
Para campos com múltiplos valores, como campos do tipo array ou nested, use o parâmetro mode para especificar qual elemento deve ser usado na ordenação.
Ordene por um valor específico em um array com múltiplos valores.
// Assume you have two rows, doc1 and doc2. Both have a field1 of array type.
// The value of field1 in doc1 is [2,3]. The value of field1 in doc2 is [1,3,4].
// You can set the mode parameter to specify which value in the array to use for sorting.
{
// When mode is set to SortMode.MAX, the sort order is doc2 (sorted by 4), then doc1 (sorted by 3).
FieldSort fieldSort = new FieldSort("field1", SortOrder.DESC);
fieldSort.setMode(SortMode.MAX);
}
{
// When mode is set to SortMode.MIN, the sort order is doc1 (sorted by 2), then doc2 (sorted by 1).
FieldSort fieldSort = new FieldSort("field1", SortOrder.DESC);
fieldSort.setMode(SortMode.MIN);
}
Também é possível ordenar as sublinhas de um campo do tipo nested.
// Assume you have two rows, doc1 and doc2. Both have a field1 of nested type.
// The value of field1 in doc1 is [{"name":"b", "age":1},{"name":"a", "age":7}].
// The value of field1 in doc2 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 use for sorting.
// When mode is set to SortMode.MAX and you sort by the age field, the result is doc1 (sorted by 7), 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 use.
{
// When mode is set to SortMode.MAX and you sort by the name field, the result is doc2 (sorted by "c"), 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);
}
{
// When mode is set to SortMode.MIN and you sort by the name field, the result is doc1 (sorted by "b"), 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 de um ponto geográfico.
SearchQuery searchQuery = new SearchQuery();
// The 'geo' field is of the GeoPoint type. Sort results by the distance
// from the value in this field 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 paginar pelos resultados da consulta, use os parâmetros limit e offset ou um token.
Paginação baseada em deslocamento
Use a paginação baseada em deslocamento quando o número total de linhas a recuperar for inferior a 100.000. A soma de limit e offset deve ser menor ou igual a 100.000, e o valor máximo para limit é 100.
Para aumentar o limiar de limit, consulte Como aumento o limite da API de busca para 1.000?.
Se os parâmetros limit e offset não forem definidos, limit assumirá o valor padrão 10 e offset assumirá o valor padrão 0.
SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(new MatchAllQuery());
searchQuery.setLimit(100);
searchQuery.setOffset(100);
Paginação baseada em token
A paginação baseada em token é recomendada para paginação profunda, pois não possui limite de profundidade.
Se uma resposta não contiver todos os dados correspondentes, o servidor retornará um nextToken.
Por padrão, a paginação baseada em token permite apenas avançar pelos resultados. No entanto, como o token permanece válido durante todo o processo de consulta, armazene em cache um token anterior para paginar para trás.
Caso precise persistir um nextToken ou enviá-lo a uma aplicação front-end, use Base64 para codificá-lo em uma string. O token é um array de bytes, não uma string. Convertê-lo diretamente para string com new String(nextToken) causa perda de dados.
Ao paginar com um token, a ordem de classificação é a mesma da solicitação anterior, seja usando o IndexSort padrão ou uma ordenação personalizada. Portanto, não defina um parâmetro Sort ao usar um token. Também não defina um offset, pois a leitura dos dados ocorre apenas de forma sequencial.
Um índice de busca que contém um campo do tipo nested não suporta pré-ordenação de índice. Se precisar paginar pelos resultados desse índice, especifique uma ordem de classificação na consulta. Caso contrário, o servidor não retornará um nextToken, mesmo que haja mais dados disponíveis.
private static void readMoreRowsWithToken(SyncClient client) {
SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(new MatchAllQuery());
searchQuery.setGetTotalCount(true);// Set to return the total count of matched rows.
// Specify the data table name (for example, sampleTable) and the search index name (for example, sampleSearchIndex).
// You can find the search index name on the Index Management tab for the table in the Tablestore console, or by listing search indexes with the SDK.
SearchRequest searchRequest = new SearchRequest("sampleTable", "sampleSearchIndex", 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 read.
// Get the nextToken.
byte[] nextToken = resp.getNextToken();
{
// If you need to persist the nextToken or send it to a front-end application,
// use Base64 to encode the nextToken into a string for storage and transfer.
// A token is a byte array. Directly using new String(nextToken) will cause data loss.
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 number of matched rows, not the number of returned rows.
}