LibrarySites.Banner

Sorting and Ordering Results in Sitecore 7

Sorting and Ordering Results

Sorting with a Search Provider is a bit of an oxymoron in my opinion. Search engines use complex algorithms to determine the order of the results - normally referred to as relevance order. However with Sitecore 7 and the new ContentSearch namespace, the idea is that you can use this not only for search but for getting quick access to results. We would like to get to the point with the ContentSearch namespace where people are comfortable to treat the index like a datastore instead of something that helps build search pages.

As we have explained a couple of times, LINQ to Lucene is very different to LINQ to SQL or LINQ to XML. Ordering/Sorting is also slightly different and if you are not careful you will think your ordering is not working with the new API. Ordering and Sorting all has a lot to do with Analyzers and Types (always seems to be the culprit). Dependant upon which Analyzer you use for the field you are ordering on and even the Type that you are storing, your results will be sorted differently.

If I asked you to answer the following question, which do you think is the answer?

Given the default Analyzer in Sitecore if I add 3 items, "Hello World" (1), "Something Changed" (2) and "Charged Gorilla" (3). If I sorted by the item name in ascending order what will be the order of the results?

A) Charged Gorilla, Hello World, Something Changed

B) Something Changed, Charged Gorilla, Hello World

C) Who cares?

D) None of the above

If you answered B) then you are correct. Mind...blown. Let me explain why. If you were to use the Standard, built in Analyzer, this is the StandardAnalyzer. It will break all the item names up into the following tokens:

  • Hello
  • World
  • Something
  • Changed
  • Charged
  • Gorilla

When sorted we then get this:

  • Changed (2)
  • Charged (3)
  • Hello (1)
  • Gorilla (3)
  • Something (2)
  • World (1)

The system should now take the first hit that represents a different document. I have marked the document ID above. So then we can take from this that the order will be document 2, 3 then 1.

But let's be honest, you probably want the order to be 3, 1, 2 right? No problem. Enter Analyzers. I won't go into a deep explanation here as you can read this blog post we did earlier and watch our 1 hour Google Hangout on Analyzers. Within that we also provider you with a Github project for testing out different Analyzers.

The LowercaseKeywordAnalyzer that we have in Sitecore 7 will NOT tokenize your item names and will leave you with the following tokens.

  • Hello World
  • Something Changed
  • Charged Gorilla

When sorted we then get this:

  • Charged Gorilla (3)
  • Hello World (1)
  • Something Changed (2)

Great! We got the ordering working correctly. Well....don't be so quick. Just because it works doesn't mean it should be done this way or is recommended. Enter Types.

If I asked you to answer the following question, which do you think is the answer?

Given the default Analyzer in Sitecore if I add 3 items, "40" (1), "5" (2) and "110" (3). If I sorted by the item name in Ascending order what will be the order of the results?

A) "40", "5", "110"

B) "5", "40", "110"

C) "110", "40", "5"

D) I don't believe in dragons

If you answered D) then shame on you. If you answered C) then you are correct. Mind....blown. This is all to do with Types and how a provider like Lucene will sort strings. It will look at the numbers above and look at the first character and order it off that, then the second, then the third etc. Fortunately we have solved this for you. You simply need to mark a specific field as an integer, double, float etc.

However what I really want to get across here is that ordering/sorting by numbers are much more efficient in Lucene and SOLR than sorting by strings as there is a lot more work that the sorting algorithm needs to take into consideration.

Sorting/Ordering with LINQ

Simple Sorting

using (var context = ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
    var results = context.GetQueryable<SearchResultItem>().Where(prod => prod.Content.Contains("search box text").OrderBy(t => t.Name);
}

Multifield Sorting

using (var context = ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
    var results = context.GetQueryable<SearchResultItem>().Where(prod => prod.Content.Contains("search box text").OrderBy(t => t.Name).ThenBy(i => i.CreatedDate);
}

Change Sort Direction

using (var context = ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
    var results = context.GetQueryable<SearchResultItem>().Where(prod => prod.Content.Contains("search box text").OrderByDescending(t => t.Name).ThenByDescending(i => i.CreatedDate);
}

NOTE: If you are working with the LINQ layer, you may notice that when we are building the expression tree for the intermediate search language, we will convert a ThenByNode to an OrderByNode. This is 100% expected as to a search provider they are exactly the same thing.

  • Dev Team
  • Hi there,  When I use the LINQ provider and specify a .Take(20) my result set reduces to just 8 results, is there something I'm doing wrong. I'm specifying the same .where and ordering statements as you've mentioned above.  Thanks

  • Hey Chris,   Can you send me the exact query you are running? This could happen for many reasons.  1) Security can null out the results 2) There may actually be only 8 results but in a typical LINQ to SQL query you are expecting different results. 3) Double check that the right Analyzer and Types are being used.  Thanks,   - Tim

  • "You simply need to mark a specific field as an integer, double, float etc"  Where do I do this? in the index configuration?  Thanks

  • At first glance it seems that all sorting code examples are missing a closing parenthesis on their third line.

  • Any tips for sorting date fields? I have a query where I want to sort a date field descending. I added the LowercaseKeywordAnalyzer to the field and confirmed (using Luke) that the values are being stored correctly in the index, but results are not sorting properly. I can filter on the same date just fine, just cannot sort.

  • Hi. Nice article. I see that default order in Lucene is by relevance and if you add some other order, relevance is not included. I have boolean field like IsSponsor. My order should be IsSponsor = 1 and Relevance, So first I need sponsors with relevance and then not sponsors with relevance. Is it possible to sort Items per field and relevance?

  • Is it possible to sort the items based on how they are structured in the Sitecore.  I know there is a field in sitecore sort order with each item to decide the sorting in the CMS. Is it possible to index that field ?

  • Yes Arun, it is possible.    Take a look at ggullentops.blogspot.be/.../sitecore-indexes.html (search for "sortorder").