London Dev Meetup Rescheduled! Due to unavoidable reasons, the event has been moved to 21st May. Speakers remain the same—any changes will be communicated. Seats are limited—register here to secure your spot!
London Dev Meetup Rescheduled! Due to unavoidable reasons, the event has been moved to 21st May. Speakers remain the same—any changes will be communicated. Seats are limited—register here to secure your spot!
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 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.
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).
SearchClient.Instance.Conventions.UnifiedSearchRegistry<br/>
.Add<MySearchableClass>();
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.
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.
SearchClient.Instance.UnifiedSearchFor(searchQuery).GetResult()
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:
To register the Title for a specific document type:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.ProjectTitleFrom(x => x.MyTitleProperty);
To register the TypeName for a specific document type:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.ProjectTypeNameFrom(x => x.MyTypeNameProperty);
To register the Url for a specific document type:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.ProjectUrlFrom(x => x.MyUrlProperty);
To register the ImageUri for a specific document type:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.ProjectImageUriFrom(x => x.MyImageUriProperty);
To register the type of the result item for a specific document type:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.UseHitType<MySearchableHitClass>();
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 }));
To register a filter always applied for UnifiedSearch:
client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MySearchableClass>()
.AlwaysApplyFilter(f => f.BuildFilter<MyType>().And(x => !x.MyProperty.Match("Something")));
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")));
If none of the other projection options are enough the CustomizeProjection extension gives full access to the HitProjectionBuilder.
Last updated: Apr 03, 2014