Unified search
Introduction
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.
Components
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.
ISearchContent
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
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).
SearchClient.Instance.Conventions.UnifiedSearchRegistry<br/>
.Add<MySearchableClass>();
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.SearchThe 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.
SearchClient.Instance.UnifiedSearchFor(searchQuery).GetResult()
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
ProjectTitleFrom
To register the Title for a specific document type:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.ProjectTitleFrom(x => x.MyTitleProperty);
ProjectTypeNameFrom
To register the TypeName for a specific document type:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.ProjectTypeNameFrom(x => x.MyTypeNameProperty);
ProjectUrlFrom
To register the Url for a specific document type:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.ProjectUrlFrom(x => x.MyUrlProperty);
ProjectImageUriFrom
To register the ImageUri for a specific document type:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.ProjectImageUriFrom(x => x.MyImageUriProperty);
UseHitType
To register the type of the result item for a specific document type:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.UseHitType<MySearchableHitClass>();
ProjectHighlightedExcerptUsing
To register the highlighted excerpt for a specific document type:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.ProjectHighlightedExcerptUsing<ISearchContent>(spec =>
x => x.MyHighlightedProperty.AsHighlighted(
new HighlightSpec { FragmentSize = spec.ExcerptLength, NumberOfFragments = 1 }));
AlwaysApplyFilter
To register a filter always applied for UnifiedSearch:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.AlwaysApplyFilter(f => f.BuildFilter<MyType>().And(x => !x.MyProperty.Match("Something")));
PublicSearchFilter
To register a filter always applied for public UnifiedSearch:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.PublicSearchFilter(f => f.BuildFilter<MySearchableClass>().And(x => !x.MyProperty.Match("Something")));
CustomizeProjection
If none of the other projection options are enough the CustomizeProjection extension gives full access to the HitProjectionBuilder.
Last updated: Apr 03, 2014