Sorting the Results on Relevancy Score

We can sort the documents based on one or more fields in addition to sorting on the document’s relevancy score.

The results returned by the engine are sorted by default on the relevancy score (_score): the higher the score, the higher on the list that the engine returns. However, Elasticearch not only lets us manage the sort order of the relevancy score (from ascending to descending), we can also sort on other fields including multiple fields.

To sort the results, we must provide a sort object at the same level as the query (see the following snippet). The sort object consists of an array of fields, where each field contains a few “tweakable” parameters.

GET movies/_search
{
"query": {
"match": {
"genre": "crime"
}
},
"sort": [
{ "rating" :{ "order": "desc" } }
]
}

Here, the results of the match query that searches for all the movies in the crime genre are sorted by the movie’s rating. The sort object defines the field (rating) and the order in which the results are expected to be sorted, descending order in this case.

Sorting on the relevancy score

The documents carrying the relevancy score are sorted on _score in descending order by default if no sorting is specified in the query. For example, the query in the following listing sorts the results in a descending order because a sort order is not mentioned.

GET movies/_search
{
"size": 10,
"query": {
"match": {
"title": "Godfather"
}
}
}

This is equivalent to issuing the sort block in a query. The following listing provides the code for this.

GET movies/_search
{
"size": 10,
"query": {
"match": {
"title": "Godfather"
}
},
"sort": [
"_score"
]
}

If you want to reverse the order with an ascending sort, meaning the lower scored documents are at the top of the list, we simply need to add the _scorefield to specify the order. The following listing shows how to do this.

GET movies/_search
{
"size": 10,
"query": {
"match": {
"title": "Godfather"
}
},
"sort": [
{"_score":{"order":"asc"}}
]
}

You probably have guessed the query to sort on a non scoring document field. The next listing demonstrates exactly this by sorting the data based on rating from highest to lowest in descending order.

GET movies/_search
{
"size": 10,
"query": {
"match": {
"genre": "crime"
}
},
"sort": [
{"rating":{"order":"desc"}}
]
}

After running this query, you’ll find the results sorted with the highest rating movie on top of the list. (I am omitting the results here for brevity.) If you carefully observe the results, you’ll see that the score is set to null.

When we use any field for sorting, Elasticsearch does not compute the score. However, there is a way you can ask Elasticsearch to compute the score even if you move away from sorting on _score. To do that, you would use the track_scores Boolean field. The following listing shows how to set the track_score for the engine to calculate the scores in this instance.

GET movies/_search
{
"track_scores":true,
"size": 10,
"query": {
"match": {
"genre": "crime"
}
},
"sort": [
{"rating":{"order":"asc"}}
]
}

The highlighted track_scores attribute in the listing provides a cue to the engine to calculate the relevancy scores of the document. They will not be sorted on the _score attribute, though, because a custom field is used for sorting.

We can also enable sorting on multiple fields. The query in the following listing shows us how we can enable sorting on the rating and release_date fields.

GET movies/_search
{
"size": 10,
"query": {
"match": {
"genre": "crime"
}
},
"sort": [
{"rating":{"order":"asc"}},
{"release_date":{"order":"asc"}}
]
}

When we sort on multiple fields, the sort order is important! The query’s results in the listing above are sorted in ascending order on the ratingfield first. If any of the movies are of the same rating, then the second field (release_date) is used to break the tie, so the results with the same rating will be sorted by release_date in ascending order.

That’s pretty much about sorting the documents in Elasticsearch.

The excerpts are taken from my book Elasticsearch in Action, Second Edition. The code is available in my GitHub repository. You can find executable Kibana scripts in the repository so you can run the commands in Kibana straight away. All code is tested against Elasticsearch 8.4 version