EPiServer  /  Find May 06, 2013

Related content with EPiServer Find

Wether it's done for editorial content, products or recipes, linking to related content can be a good way to enrich a site. For visitors, for business and for SEO. While manually selecting what content to link to often produces the best results automatic functionality for displaying related complement can be a good complement.

EPiServer Find has a number of methods that can be used for finding related or similar content. Combine them and they can offer a powerful way to help visitors find interesting content and improve search engine rankings through internal links.

Find similar pages using MoreLike

Built into Find's .NET API is a method named MoreLike. It requires a string as argument and adds a query to a search request that will match indexed objects with similar text.


When using MoreLike the search results are ranked by how similar their texts are to the one we pass as argument to it. The similarity is essentially based on common words and there are a number of adjustments that can be made to the algorithm to optimise it to suit the specific nature of the content on a specific site.

Add business logic using BoostMatching

On its own the result of the MoreLike method is highly dependent on the textual content on the site, producing varying results in terms of quality depending on the nature of the content on the site. It produces results based on similarity between texts but doesn't guarantee that there is any relation between the content other than shared usages of words in the text.

Find's .NET API also features a method named BoostMatching which can be used to apply boost factors using whatever criteria that can be described using a filter. In other words, pretty much anything. Using that we can upgrade a MoreLike query from producing similar content to related content.

    .BoostMatching(x => x.InCategory(42), 3)

What conditions we use for boosting is, naturally, dependent on the nature of the site and the type of content for which we want to find related content. If it's a blog post we may boost blog posts that share the same categories and tags. If it's a recipe site we may boost recipes that share the same ingredients. If it's a product we can boost based on categories, price and stock balance.

In other words, BoostMatching allows us to apply custom business logic tailored for our specific site and needs of the business.

An example

On this site I have functionality to relate content using a number of mechanisms such as categories, tags and topics. If an article is grouped in a topic other articles in the same topic is listed.

For articles that doesn't have such lists I still want to display a list of, as far as it's possible, related articles. That's accomplished using the below method.

//using System.Collections.Generic;
//using EPiServer.Find;
//using EPiServer.Find.Cms;
//using EPiServer.Find.Framework;

public virtual IEnumerable<EditorialPageBase> GetSimilarPages(EditorialPageBase page)
  //Create search request for pages of the type(s) that we're interested in
  //and apply a MoreLike query using the concatenated values of all searchable
  //properties on the current page.
  IQueriedSearch<EditorialPageBase> query = SearchClient.Instance

  //Apply major boost to articles in the same category.
  foreach (var category in page.Categories)
    query = query.BoostMatching(x => x.Categories.Match(category), 4);

  //Apply a smaller but still significant boost to articles sharing tags with
  //the current page.
  foreach (var tagLink in page.TagReferences)
    query = query.BoostMatching(x => x.TagReferences.Match(tagLink.ToString()), 2);

  return query
    //Utilize/apply editorial settings for how desirable a certain page
    //is in the results.
    .BoostMatching(x => x.SearchPriority.Match(Priority.VeryLow), 0.1)
    .BoostMatching(x => x.SearchPriority.Match(Priority.Low), 0.3)
    .BoostMatching(x => x.SearchPriority.Match(Priority.High), 1.5)
    .BoostMatching(x => x.SearchPriority.Match(Priority.VeryHigh), 2.5)
    //Exclude the current page (which is naturally the most similar page).
    .Filter(x => !x.ContentLink.Match(page.ContentLink))
    //Exclude unpublished and filter based on access rights and language.    
    //Execute the query
    .GetContentResult(cacheForSeconds: 3600, cacheForEditorsAndAdmins: true);

PS. For updates about new posts, sites I find useful and the occasional rant you can follow me on Twitter. You are also most welcome to subscribe to the RSS-feed.

Joel Abrahamsson

Joel Abrahamsson

I'm a passionate web developer and systems architect living in Stockholm, Sweden. I work as CTO for a large media site and enjoy developing with all technologies, especially .NET, Node.js, and ElasticSearch. Read more


comments powered by Disqus

My book

Want a structured way to learn EPiServer 7 development? Check out my book on Leanpub!

More about EPiServer Find