This content is archived. See latest version here


Unified Search allows us to index and query objects of existing classes, without having to map them to some intermediate type that is then put into the index.


The concept of Unified Search consists of four main parts:
  • A common interface declaring properties that we may want to use when building search (not querying) functionality ISearchContent.
  • An object that maintains a configurable list of types that should be searched when searching for ISearchContent as well as, optional, specific rules for filtering and projecting those types when searching IUnifiedSearchRegistry which is exposed by the IClient.Conventions.UnfiedSearchRegistry property.
  • Classes for search results that are returned when searching for ISearchContent UnifiedSearchResults which contains a number of UnifiedSearchHit.
  • Special method for building and executing search queries UnifiedSearch() and UnifiedSearchFor() and an overloaded GetResult() method.


The ISearchContent interface resides in the EPiServer.Find.UnifiedSearch namespace and is the least common denominator. It declares a large number of properties, all with names prefixed with Search, that we may want to search for. Classes that have been registrated in Unified search does not have to implement ISearchContent. By having a property or extension method with the same name and type as a property in the interface, the property will be treated the same as if it was received from the interface.

  • SearchTitle
  • SearchSummary
  • SearchText
  • SearchHitUrl
  • SearchTypeName
  • SearchHitTypeName
  • SearchSection
  • SearchSubsection
  • SearchAuthors
  • SearchGeoLocation
  • SearchPublishDate
  • SearchUpdateDate
  • SearchAttachment
  • SearchCategories
  • SearchFilename
  • SearchFileExtension
  • SearchMetaData
public class MySearchableClass
    public string Heading { get; set; }
    public string Body { get; set; }
    public string Url { get; set; }

    public virtual string SearchTitle { get { return Heading; } }
    public virtual string SearchSummary { get { return Body; } }
    public virtual string SearchText { get { return String.Format(CultureInfo.InvariantCulture, "{0} {1} {2}", Heading, Body, Url); } }
    public virtual string SearchHitUrl { get { return Url; } }
    public virtual string SearchSection { get { return GetType().Name; } }


IUnifiedSearchRegistry, also residing in EPiServer.Find.UnifiedSearch, exposes methods for building and configuring a list of types that should be included when searching for ISearchContent. Apart from methods for adding (the Add method) and listing types (the List method) it also declares methods that allow us to add rules for how specific types should be filtered when searching as well as how to project found documents to the common hit type (UnifiedSearchHit).


UnifiedSearchResults and UnifiedSearchHit

While ISearchContent provides a decent common denominator for fields to search in it wouldnt be useful to get back instances of it as the result of a search query. For instance, while we may want to search in the full text in an indexed object we typically only want a small snippet of the text back which well show in the search results listing. Also, it would be technically problematic to get instances of ISearchContent back from the search engine as the matched object does not actually implement that interface, or at least they dont have to.

Therefore, when we search for ISearchContent and invoke the GetResult method we wont get back instances of ISearchContent. Instead well get back an instance of the UnifiedSearchResults class which contains a number of UnifiedSearchHit objects. A UnifiedSearchHit object contains a number of properties that we typically would want to show for each search result, such as Title, URL and Excerpt (a snippet of text). It also has a number of other properties such as PublishDate, ImageUri, Section, FileExtension and TypeName.

Methods for building and executing queries

In order to search for ISearchContent we can use the regular Search method, ie client.Search(). In that case well be in charge of what fields to search in when building free text search. However, since ISearchContent is a special type that the .NET API knows about, there are a couple of methods that takes care of adding some sensible defaults for us UnifiedSearch() and UnifiedSearchFor().

The Unified Search concept also adds a new GetResult method. As this has the same name as the regular method for executing search queries we dont really have to do anything special to use it. The compiler will choose to use it for us as it has a more specific generic type constraint than the other GetResult methods. But, we should be aware of what it does. The GetResult method will modify the search query that we have built up so that it will not just search for objects that implement ISearchContent but also for all types that have been added to the UnifiedSearchRegistry. It will also proceed to add a projection from ISearchContent to UnifiedSearchHit with some nice sensible defaults, along with any type specific projections that have been added to the UnifiedSearchRegistry.

Finally, before executing the search query like the regular GetResult method, it will also add any type specific filters that have been added to the UnifiedSearchRegistry. Once we invoke GetResult the search query will search over types that may not implement ISearchContent, but as we (hopefully) have specified that we should only search in, or filter on, a number of fields that are declared by ISearchContent well only search in fields with those names, even if the objects dont implement ISearchContent. The GetResult method has an overload that requires an argument of type HitSpecification. Using this we can control the length of the excerpt, whether titles and excerpts should be highlighted, as well as a number of other things.


Customize default projections

It is possible to customize the projection of the unified search results in a number of ways. Currently the UnifiedSearchRegistry supports the following customization options:

  • ProjectTitleFrom
  • ProjectTypeNameFrom
  • ProjectUrlFrom
  • ProjectImageUriFrom
  • UseHitType
  • ProjectHighlightedExcerptUsing
  • AlwaysApplyFilter
  • PublicSearchFilter
  • CustomizeProjection


To register the Title for a specific document type:

                .ProjectTitleFrom(x => x.MyTitleProperty);


To register the TypeName for a specific document type:

                .ProjectTypeNameFrom(x => x.MyTypeNameProperty);


To register the Url for a specific document type:

                .ProjectUrlFrom(x => x.MyUrlProperty);


To register the ImageUri for a specific document type:

                .ProjectImageUriFrom(x => x.MyImageUriProperty);


To register the type of the result item for a specific document type:



To register the highlighted excerpt for a specific document type:

                .ProjectHighlightedExcerptUsing<ISearchContent>(spec =>
                            x => x.MyHighlightedProperty.AsHighlighted(
                                new HighlightSpec { FragmentSize = spec.ExcerptLength, NumberOfFragments = 1 }));


To register a filter always applied for UnifiedSearch:

                .AlwaysApplyFilter(f => f.BuildFilter<MyType>().And(x => !x.MyProperty.Match("Something")));


To register a filter always applied for public UnifiedSearch:

                .PublicSearchFilter(f => f.BuildFilter<MySearchableClass>().And(x => !x.MyProperty.Match("Something")));


If none of the other projection options are enough the CustomizeProjection extension gives full access to the HitProjectionBuilder.

Last updated: Apr 03, 2014