Reason
Sometimes the information you’d like to run a Sitecore Content Search query against isn’t readily available via the items you’re trying to retrieve, e.g. information stored somewhere else in the Sitecore content tree or not stored in Sitecore at all. This can result in complex queries or require you to mix Linq-to-Sitecore with Linq-to-objects which lowers performance.
Computed index fields can in some cases be used to circumvent such issues by storing the required information in a more “query friendly” manner as outlined below.
Examples are based on Sitecore CMS 7.1 Update-1 (rev. 140130).
Code
To implement a computed index field the following is required:
- Create a class which implements
Sitecore.ContentSearch.ComputedFields.IComputedIndexField
. - Create a config-include file which adds the computed index field to the index configuration.
In the following example an index field called AuthorPublications
is implemented and configured. The example uses…
- several
Publication
items, each having a reference to anAuthor
item - an
Author
item (I felt lazy and created only one) - an index field called
AuthorPublications
which is computed for all items derived from theAuthor
template, existing only in the index and containing the IDs of all publications associated with the author
The Author
and Publication
templates are set up as shown below. The main point to note is that the Author
item template doesn’t contain a field called AuthorPublications
.
The code shown below is the IComputedIndexField
implementation itself. The properties FieldName
and ReturnType
are set based on the configuration shown later and in this case serve no other purpose than being required by the interface.
using System; using System.Collections.Generic; using System.Linq; using Sitecore; using Sitecore.ContentSearch; using Sitecore.ContentSearch.ComputedFields; using Sitecore.Data.Items; public class AuthorPublications : IComputedIndexField { public object ComputeFieldValue(IIndexable indexable) { Item item = indexable as SitecoreIndexableItem; if (item == null) return null; if (item.TemplateName != "Author") return null; return GetPublicationIDs(item); } private IEnumerable<Guid> GetPublicationIDs(Item authorItem) { return (from link in Globals.LinkDatabase.GetItemReferrers(authorItem, false) let sourceItem = link.GetSourceItem() where sourceItem != null where sourceItem.TemplateName == "Publication" select sourceItem.ID.Guid).ToArray(); } public string FieldName { get; set; } public string ReturnType { get; set; } }
Shown below is the Author
class which can be used in Linq-to-Sitecore queries, including a property configured to match the AuthorPublications
computed index field.
using System; using System.Collections.Generic; using Sitecore.ContentSearch; public class Author { [IndexField("AuthorGivenName")] public string GivenName { get; set; } [IndexField("AuthorFamilyName")] public string FamilyName { get; set; } [IndexField("AuthorPublications")] public IEnumerable<Guid> Publications { get; set; } }
The configuration shown below sets up the computed index field – save it in a .config-file in a subfolder of “App_Config/Include/” (e.g. “App_Config/Include/MyCompany/ComputedIndexFields.config”). Modify namespace and assembly names as needed.
<?xml version="1.0" encoding="utf-8" ?> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <contentSearch> <configuration> <defaultIndexConfiguration> <fields hint="raw:AddComputedIndexField"> <field fieldName="AuthorPublications" storageType="YES" indexType="TOKENIZED">NamespaceName.AuthorPublications, AssemblyName</field> </fields> </defaultIndexConfiguration> </configuration> </contentSearch> </sitecore> </configuration>
When creating configurations for your own computed index fields, I suggest using “App_Config/Include/Sitecore.ContentSearch.Lucene.DefaultIndexConfiguration.config” for inspiration.
Example
Shown below is a screenshot from Luke showing the indexed data: