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.indexSortto define the default result order. If index sort is not configured, results are sorted by primary key. Index sort supports onlyPrimaryKeySortandFieldSort. A search index that contains a Nested field does not support index sort.Query-time sort: Configure
SearchQuery.sortfor 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 haveenableSortAndAggset totruein 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 |
|
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 |
|
offset (optional) |
Integer |
The position from which the current query starts. Default value: |
|
limit (optional) |
Integer |
The maximum number of rows to return. Default value: |
|
token (optional) |
byte[] |
The pagination token. Set this parameter to the |
|
trackTotalCount (optional) |
int |
The expected maximum number of matching rows to count. Default value: |
Sort configuration
The type of request.searchQuery.sort is Sort. The following table describes its parameters.
|
Name |
Type |
Description |
|
sorters (required) |
|
The list of sorters. The order of the list determines the priority of multi-level sorting. Supported sorters are |
|
disableDefaultPkSorter (optional) |
Boolean |
Specifies whether to prevent the server from automatically appending a primary key sorter. Default value: |
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. |
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: |
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: |
|
mode (optional) |
SortMode |
The value to use when sorting a multi-valued field. |
|
missingFields (optional) |
|
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 |
|
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 |
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) |
|
The target geographical points. Each point uses the |
|
order (optional) |
SortOrder |
The sort order. |
|
mode (optional) |
SortMode |
The value to use when multiple distances exist. Supported values are |
|
distanceType (optional) |
GeoDistanceType |
The distance calculation method. |
|
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) |
|
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: |
|
returnAllFromIndex (optional) |
boolean |
Specifies whether to return all stored attribute columns in the search index. Default value: |
Response
The search method returns SearchResponse. The following table describes the fields related to sorting and pagination.
|
Name |
Type |
Description |
|
rows |
|
The rows returned by the current query. Call |
|
searchHits |
|
The search hits. Call |
|
totalCount |
long |
The number of matching rows. Call |
|
nextToken |
byte[] |
The token for the next page. Call |
|
isAllSuccess |
boolean |
Indicates whether all index partitions were queried. Call |
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);
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);