All Products
Search
Document Center

Tablestore:Post-query filter

Last Updated:Nov 28, 2025

The post-query filter is a new feature for Tablestore Search Index that applies an additional filter to query results. This feature lets you manually influence the internal query optimizer by forcing specific filter conditions to run in the final stage. If used correctly, this feature can significantly improve query performance.

Note

The post-query filter feature is supported from Java SDK version 5.17.5. To use this feature, contact Tablestore technical support to enable it.

Feature architecture

The post-query filter is based on a multilayer query architecture:

  • SearchRequest: The top-level container for a query request. It includes the table name, index name, and specific query configurations.

  • SearchQuery: The core query configuration. It includes the main query condition (Query) and an optional query filter (SearchFilter).

  • Query: The main query condition. It supports all query types and data types of Search Index and is used for initial data retrieval.

  • SearchFilter: The secondary filter. It contains filter conditions for fine-grained filtering on the main query results.

Limits

  • Post-query filters must be used with Search Index query conditions. The supported query types are TermQuery, TermsQuery, RangeQuery, ExistsQuery, and BoolQuery, which combines these query types.

  • When using a BoolQuery, only `mustQueries`, `mustNotQueries`, and `shouldQueries` clauses are supported. The `filterQueries` clause is not supported.

  • Filtering is supported only for Keyword (non-tokenized string), Long, and Double field types. The `enableSortAndAgg` property must be enabled for these fields.

  • Post-query filters do not support setting weights.

Prerequisites

Method description

public SearchResponse search(SearchRequest searchRequest) throws TableStoreException, ClientException

Parameters for the query filter in the `SearchQuery` of a `SearchRequest`

  • query (required) Query: The configuration for the main query condition. This parameter supports all Search Index query types and contains the following parameters:

    Name

    Data type

    Description

    type (required)

    QueryType

    The query type. All query types of the Search API are supported. Using `MatchAllQuery` is not recommended.

    query (required)

    bytes

    The query condition.

  • filter (optional) SearchFilter: The configuration for the secondary filter. This parameter applies a fine-grained filter to the main query results and contains the following parameters:

    • query (required) Query: The configuration for the filter condition. This parameter supports only specific query types and contains the following parameters:

      Name

      Data type

      Description

      type (required)

      QueryType

      The query type. Only `TermQuery`, `TermsQuery`, `RangeQuery`, `ExistsQuery`, and a `BoolQuery` composed of these types are supported.

      query (required)

      bytes

      The query condition.

Sample code

The following example shows how to use the post-query filter feature. The main query condition first matches data where the `col_keyword` field is `value`. Then, the filter condition selects records where the `col_long` field value is between 1 and 10.

  • Imperative API call

    private static void queryUsingSetter(SyncClient client) {
        // [Required] Replace with your table name.
        String tableName = "<TABLE_NAME>";
        // [Required] Replace with your search index name.
        String indexName = "<SEARCH_INDEX_NAME>";
    
        // Build the main query: an exact match using terms query.
        TermsQuery termsQuery = new TermsQuery();
        termsQuery.setFieldName("col_keyword");
        termsQuery.addTerm(ColumnValue.fromString("value"));
    
        // Build the filter condition: the value of the col_long field is in the range (1, 10).
        RangeQuery rangeQuery = new RangeQuery();
        rangeQuery.setFieldName("col_long");
        rangeQuery.setFrom(ColumnValue.fromLong(1));
        rangeQuery.setTo(ColumnValue.fromLong(10));
    
        // Assemble the SearchFilter.
        SearchFilter searchFilter = new SearchFilter();
        searchFilter.setQuery(rangeQuery);
    
        // Combine into a complete SearchQuery.
        SearchQuery searchQuery = new SearchQuery();
        searchQuery.setQuery(termsQuery);
        searchQuery.setFilter(searchFilter);
    
        // Construct the request.
        SearchRequest searchRequest = new SearchRequest(tableName, indexName, searchQuery);
        
        // By default, only primary key columns are returned. Set the columns to return as needed.
        SearchRequest.ColumnsToGet columnsToGet = new SearchRequest.ColumnsToGet();
        // Set to return all columns from the search index.
        columnsToGet.setReturnAllFromIndex(true); 
        searchRequest.setColumnsToGet(columnsToGet);
        
        try {
            SearchResponse resp = client.search(searchRequest);
            System.out.println("Rows: " + resp.getRows());     
        } catch (Exception e) {
            System.err.println("Search failed: " + e.getMessage());
        }
    }
    • You can configure the query to return specific columns or all columns.

      SearchRequest.ColumnsToGet columnsToGet = new SearchRequest.ColumnsToGet();
      // Return specific columns.
      columnsToGet.setColumns(Arrays.asList("col_long", "col_keyword")); // Specify columns.
      // Or: return all columns.
      // columnsToGet.setReturnAll(true);  
      searchRequest.setColumnsToGet(columnsToGet);
    • To count the total number of matched rows, you can enable the `totalCount` feature and retrieve the count from the response.

       // Enable totalCount statistics in searchQuery.
       searchQuery.setTrackTotalCount(SearchQuery.TRACK_TOTAL_COUNT); 
       // Print the total number of rows from the result.
       System.out.println("Total Count (matched): " + resp.getTotalCount());
  • Builder pattern API call

    private static void queryUsingBuilder(SyncClient client) {
        // [Required] Replace with your table name.
        String tableName = "<TABLE_NAME>";
        // [Required] Replace with your search index name.
        String indexName = "<SEARCH_INDEX_NAME>";
        
        try {
            // Build SearchQuery: main query and filter condition.
            SearchQuery searchQuery = SearchQuery.newBuilder()
                    .query(QueryBuilders.terms("col_keyword").terms("value")) // Exact match for the keyword.
                    .filter(SearchFilter.newBuilder()
                            .query(QueryBuilders.range("col_long")
                                    .greaterThan(1)   // Range (1, 10).
                                    .lessThan(10))
                            .build())
                    // .trackTotalCount(SearchQuery.TRACK_TOTAL_COUNT)  // Enable total match count statistics as needed.
                    .build();
    
            // Construct the request.
            SearchRequest searchRequest = new SearchRequest(tableName, indexName, searchQuery);
        
            // By default, only primary key columns are returned. Set the columns to return as needed.
            SearchRequest.ColumnsToGet columnsToGet = new SearchRequest.ColumnsToGet();
            // Set to return all columns from the search index.
            columnsToGet.setReturnAllFromIndex(true); 
            searchRequest.setColumnsToGet(columnsToGet);
    
            SearchResponse resp = client.search(searchRequest);
            System.out.println("Rows: " + resp.getRows());
    
        } catch (Exception e) {
            System.err.println("Search request failed: " + e.getMessage());
        }
    }