The Solr search provider in Sitecore 7 allows users to rank the search results using different types of boosting methods. This article shows how to use the Query-Time Boosting to sort the search results and highlights the common mistakes that developers should avoid.
Assume that you want to run a search query over a set of Sitecore items, each of which has a title and description fields, and you would like the score of the results that contain the search keyword in the title to be higher than the ones contain the search keyword in the description.
The search query that uses Query-Time Boosting should look like:
var query = "guitar"; var dataQuery = context.GetQueryable<SearchResultItem>() .Where(i => i.Title == query.Boost(3.0f) || i.Description == query.Boost(1.0f))
The generated Solr query will be:
q=(title_t:(guitar))^3 OR page_body_t:(guitar))&fl=*,score
The query uses the ^ operator to specify the boosting value. As Solr doesn’t return the score values by default, the “fl=*,score” query string tells Solr to return all the default fields + the score field.
Back to your Sitecore code, the score values can be retrieved using the SearchHit object as follows:
dataQuery.GetResults().Hits.First().Score;
Which will get the score of the first search result.
Mistake – Using LINQ to Objects
One big sin that a developer can commit is to use LINQ to objects to sort the search results as follows:
var results = dataQuery.GetResults().Hits.OrderByDescending(h => h.Score).Select(h => h.Document);
The above query will retrieve the results from Solr and sort them in memory. This is a very bad coding practice even if the returned data set is small, all the sorting logic should be handled by Solr. This code can be even worse if you want to add pagination to your search results as follows:
var results = dataQuery.Page(page,pageSize).GetResults().Hits.OrderByDescending(h => h.Score).Select(h => h.Document);
The above code will do the pagination on Solr and then will sort each page on the web server!!
The Right Way
To sort the search results on Solr you will need to write the following query:
dataQuery = dataQuery.OrderByDescending(i => i["score"]); var results = dataQuery.GetResults().Hits.Select(h => h.Document);
This will generate the following query, notice the sort sort query string.
q=(title_t:(guitar))^3 OR page_body_t:(guitar))&sort=score desc&fl=*,score
Sort Using Multiple Fields
In some cases you may need to use a secondary sort field, having the score field as your main sorting field. So, your query should look like:
dataQuery = dataQuery.OrderByDescending(i => i["score"]).ThenByDescending(i => i.Title); var results = dataQuery.GetResults().Hits.Select(h => h.Document);
This code won’t work as expected; due to a bug in the Sitecore search provider, the parameter of the ThenBy will go before the parameter of the OrderBy. Hence your query should be:
dataQuery = dataQuery.OrderByDescending(i => i.Title).ThenByDescending(i => i["score"]); var results = dataQuery.GetResults().Hits.Select(h => h.Document);
A very useful article… Keep sharing
Nice, but then how do you sort the right way when using .Page()?
You can do the following:
dataQuery = dataQuery.OrderByDescending(i => i[“score”]).Page(page, pageSize);
The pagination is applied anyway after the sorting is done in Solr
Do you have the link to the issue? I am using 7.2, looks like the issue is still there.
I am also having this issue in 7.2 not sure if it’s been fixed in the newer versions.
Hey, I found your article very useful. Thank you. I am a bit confused and have a problem related to sorting and needed an expert’s advice. I have posted a query in StackOverflow as well. You can reply me on my email. Thank you in advance. !
http://stackoverflow.com/questions/31673002/sitecore-search-get-results-term-by-term
Just posted a comment that might help
Hi, good and useful post! Just looking to the same with Azure search, since our client is using this engine. Anyone has an idea if that is possible? After doing some research and tests, I think is not possible to use the “Score” field in the OrderBy.. So wondering if I need to do it in the bad way (Linq on the server side).. I want to avoid this since I have pagination too!!