A constant score query (ConstScoreQuery) wraps a subquery and treats it as a filter. It returns every matched document with a fixed relevance score of 1.0, bypassing scoring algorithms such as BM25.
Prerequisites
-
You have initialized the Tablestore Client. For details, see Initialize Tablestore Client.
-
You have created a data table and written data to it.
-
You have created a Search Index for the data table. For details, see Create a search index.
Parameters
|
Parameter |
Description |
|
|
The name of the data table. |
|
|
The name of the Search Index. |
|
|
Sets the query type to |
|
|
The subquery used as a filter. Supports any Query type. A |
|
|
The maximum number of rows to return. To retrieve only the total row count without data, set |
|
|
The columns to return. Contains the |
Examples
Basic usage
Wraps a MatchQuery in a ConstScoreQuery to find documents where the Col_Text column contains the keyword tablestore. All matched documents receive a fixed relevance score of 1.0. Results are sorted by score in descending order to demonstrate the fixed-score effect.
/**
* Use ConstScoreQuery to perform a constant score query.
* All matched documents have a score of 1.0, regardless of factors like text length or term frequency.
*/
func constScoreQuery(client *tablestore.TableStoreClient) {
// Create the inner subquery: a MatchQuery that matches the keyword "tablestore" in the Col_Text column.
// Wrap the MatchQuery in a ConstScoreQuery. All matched documents will receive a fixed relevance score of 1.0.
query := &search.ConstScoreQuery{
Filter: &search.MatchQuery{
FieldName: "Col_Text",
Text: "tablestore",
},
}
searchQuery := search.NewSearchQuery()
searchQuery.SetQuery(query)
searchQuery.SetLimit(20)
// searchQuery.SetGetTotalCount(true) // Set to return the total count of matched rows.
// Sort by score to verify the effect of the fixed score.
searchQuery.SetSort(&search.Sort{
Sorters: []search.Sorter{
&search.ScoreSort{Order: search.SortOrder_DESC.Enum()},
},
})
searchRequest := &tablestore.SearchRequest{}
searchRequest.SetTableName("<TABLE_NAME>")
searchRequest.SetIndexName("<SEARCH_INDEX_NAME>")
searchRequest.SetSearchQuery(searchQuery)
resp, err := client.Search(searchRequest)
if err != nil {
fmt.Printf("%#v\n", err)
return
}
fmt.Println("RowCount:", len(resp.Rows))
// Verify that all matched documents have a score of 1.0.
for _, row := range resp.Rows {
jsonBody, _ := json.Marshal(row)
fmt.Println("Row:", string(jsonBody))
}
}
Return specified columns
By default, only primary key columns are returned. Use ColumnsToGet to return all columns or a custom set of columns. Add the following code after creating the searchRequest object in the basic usage example.
// Use ColumnsToGet to control which columns are returned. By default, only primary key columns are returned.
// Option 1: Return all columns.
searchRequest.SetColumnsToGet(&tablestore.ColumnsToGet{ReturnAll: true})
// Option 2: Return specified columns.
// searchRequest.SetColumnsToGet(&tablestore.ColumnsToGet{Columns: []string{"Col_Text", "Col_Keyword"}})
resp, err := client.Search(searchRequest)
if err != nil {
fmt.Printf("%#v\n", err)
return
}
fmt.Println("RowCount:", len(resp.Rows))
for _, row := range resp.Rows {
jsonBody, _ := json.Marshal(row)
fmt.Println("Row:", string(jsonBody))
}
Use with a BoolQuery
Combines a ConstScoreQuery and a MatchQuery in the MustQueries clause of a BoolQuery. The ConstScoreQuery wraps a TermQuery and contributes a fixed score of 1.0. The MatchQuery is scored by the BM25 algorithm. The final score is the sum of the ConstScoreQuery score (1.0) and the MatchQuery BM25 score.
func constScoreInBoolQuery(client *tablestore.TableStoreClient) {
// Subquery 1: A ConstScoreQuery wraps a TermQuery to perform an exact match on the "status" field, contributing a fixed score of 1.0.
constScoreQuery := &search.ConstScoreQuery{
Filter: &search.TermQuery{
FieldName: "status",
Term: "active",
},
}
// Subquery 2: A MatchQuery that is scored using the BM25 algorithm on the "title" field.
matchQuery := &search.MatchQuery{
FieldName: "title",
Text: "tablestore",
}
// Create a BoolQuery that includes both the ConstScoreQuery and MatchQuery in its MustQueries clause.
// The final score is the sum of the fixed score from ConstScoreQuery (1.0) and the BM25 score from the MatchQuery.
boolQuery := &search.BoolQuery{
MustQueries: []search.Query{
constScoreQuery,
matchQuery,
},
}
searchQuery := search.NewSearchQuery()
searchQuery.SetQuery(boolQuery)
searchQuery.SetLimit(20)
// searchQuery.SetGetTotalCount(true) // Set to return the total count of matched rows.
searchQuery.SetSort(&search.Sort{
Sorters: []search.Sorter{
&search.ScoreSort{Order: search.SortOrder_DESC.Enum()},
},
})
searchRequest := &tablestore.SearchRequest{}
searchRequest.SetTableName("<TABLE_NAME>")
searchRequest.SetIndexName("<SEARCH_INDEX_NAME>")
searchRequest.SetSearchQuery(searchQuery)
resp, err := client.Search(searchRequest)
if err != nil {
fmt.Printf("%#v\n", err)
return
}
fmt.Println("RowCount:", len(resp.Rows))
for _, row := range resp.Rows {
jsonBody, _ := json.Marshal(row)
fmt.Println("Row:", string(jsonBody))
}
}
Use with a ParallelScan
In concurrent export scenarios, use a ConstScoreQuery as the query condition for a ScanQuery to skip BM25 score calculation. For the complete concurrent export workflow, see Export data in parallel.
func constScoreInParallelScan(client *tablestore.TableStoreClient, sessionId []byte) {
// Create a ConstScoreQuery that wraps a MatchQuery. All matched documents will receive a fixed relevance score of 1.0.
constScoreQuery := &search.ConstScoreQuery{
Filter: &search.MatchQuery{
FieldName: "Col_Text",
Text: "tablestore",
},
}
// Create a ScanQuery and set the ConstScoreQuery as its query condition.
scanQuery := search.NewScanQuery().
SetQuery(constScoreQuery).
SetLimit(2000)
scanRequest := &tablestore.ParallelScanRequest{}
scanRequest.SetTableName("<TABLE_NAME>")
scanRequest.SetIndexName("<SEARCH_INDEX_NAME>")
scanRequest.SetScanQuery(scanQuery)
// The session ID is obtained from the `ComputeSplits` API call. The type is `[]byte`.
// All workers share the same session ID. The client uses `splitsSize` to implicitly distribute concurrent tasks.
scanRequest.SetSessionId(sessionId)
scanResponse, err := client.ParallelScan(scanRequest)
if err != nil {
fmt.Printf("%#v\n", err)
return
}
fmt.Println("RowCount:", len(scanResponse.Rows))
for _, row := range scanResponse.Rows {
jsonBody, _ := json.Marshal(row)
fmt.Println("Row:", string(jsonBody))
}
}