Sitecore 7 Computed Fields: All Templates and Datasource Content

Posted 11/22/2013 by techphoria414

Posted in

We've been getting some great practical exposure to Sitecore 7 indexing here at Active Commerce, so I thought I'd quickly share a couple tidbits that others should find very useful.

Index All Templates (no really, ALL templates)

If you are making good use of template inheritance, it's likely that searching on the item template alone does you no good. Your search needs to include base templates as well. Unfortunately, the built-in Sitecore.ContentSearch.ComputedFields.AllTemplates class behaves exactly as its counterpart in the old Sitecore.Search API -- it only goes one level deep into base templates. Bummer! Fortunately it's easy to replace with our own computed field, which actually accounts for all templates. In our version, it stops crawling base templates when the Standard Template is reached. Find the code and configuration example below.

Note: If you are sensitive to indexing performance in your environment, you will definitely want to test the impact of adding this. I've been told that performance constraints are the reason the built-in AllTemplates field does not do this. This renders it pretty useless however.

Indexing Datasource Content

I've covered this topic before in relation to the Page Editor and what used to be called Advanced Database Crawler. If you are building any sort of site search, you need the indexed content for a page to reflect the contents of its datasource items as well. I was really hoping this would be built-in somehow in Sitecore 7, but alas it is not. However as we've done this before for Sitecore.Search, we can do it again for Sitecore.ContentSearch. Now however, we can take advantage of the fact that datasources are accounted for in the Links DB now. Note I don't believe this would include search-based datasources, but someone can correct me there if needed. You can find the code and configuration for the computed field below. Note that once again, you may need to test the performance of this computed field in your environment for very large content databases.

What Sitecore 7 also makes easier is ensuring that the page is re-indexed if the datasource item is saved. The indexing.getDependencies pipeline allows specifying other items that should be re-indexed. The name of the pipeline (and even the documentation in the config file) is a bit misleading. To me it's more of a "get dependents" pipeline as a "get dependencies," as it indicates items that are dependent on the current item. But this is semantics.

Sitecore 7 includes a processor (disabled by default) that finds any items on whom the current item is used as a datasource. Unfortunately on enabling this (7.0 rev. 130918), I got a nasty exception.

Exception: System.InvalidCastException
Message: Unable to cast object of type 'Sitecore.Data.ItemUri' to type 'Sitecore.ContentSearch.IIndexableUniqueId'.
Source: System.Core
   at System.Linq.Enumerable.d__b1`1.MoveNext()
   at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection)
   at Sitecore.ContentSearch.Pipelines.GetDependencies.GetDatasourceDependencies.Process(GetDependenciesArgs context)
   at (Object , Object[] )
   at Sitecore.Pipelines.PipelineMethod.Invoke(Object[] parameters)
   at Sitecore.Pipelines.CoreProcessor.Invoke(Object[] parameters)
   at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
   at Sitecore.Pipelines.CorePipeline.Run(String pipelineName, PipelineArgs args, String pipelineDomain, Boolean failIfNotExists)
   at Sitecore.Pipelines.CorePipeline.Run(String pipelineName, PipelineArgs args, String pipelineDomain)
   at Sitecore.Pipelines.CorePipeline.Run(String pipelineName, PipelineArgs args)
   at Sitecore.ContentSearch.Pipelines.GetDependencies.GetDependenciesPipeline.GetIndexingDependencies(IIndexable indexable)
   at Sitecore.ContentSearch.Crawler`1.UpdateDependents(IProviderUpdateContext context, T indexable)
   at Sitecore.ContentSearch.SitecoreItemCrawler.DoUpdate(IProviderUpdateContext context, SitecoreIndexableItem indexable)
   at Sitecore.ContentSearch.Crawler`1.Update(IProviderUpdateContext context, IIndexableUniqueId indexableUniqueId, IndexingOptions indexingOptions)
   at Sitecore.ContentSearch.LuceneProvider.LuceneIndex.PerformUpdate(IIndexableUniqueId indexableUniqueId, IndexingOptions indexingOptions)
   at Sitecore.ContentSearch.LuceneProvider.LuceneIndex.Update(IIndexableUniqueId indexableUniqueId)

I've reported the issue to Sitecore, but in the mean time, included below is code and config for a replacement processor. Utilizing this will ensure that when your datasource is updated, the page will be reindexed as well.

Code below. Happy Sitecoring.



Pre-Disqus Comments

  • Nick's gravatar Nick said:
    6/1/2015 2:50 PM

    Got a fast response from Sitecore when I requested follow up on this: The issue isn't fixed yet, but should be fixed in 7.2 update-5 and merged to upcoming 7.5 and 8.x. To track the future status of this bug report, please use the reference number 408894. More information about public reference numbers can be found here:

  • Nick's gravatar Nick said:
    6/1/2015 2:42 PM

    Hi Rob. I took a look and Sitecore never responded to the ticket, other than to register it as a bug. I just submitted a follow up to see if it's been fixed. If you are seeing the same error with the same stack trace when enabling this processor, I would venture that it's still an issue.

  • Rob's gravatar Rob said:
    5/29/2015 3:23 PM

    Curious if this error / solution was fixed in sitecore 8? Did you get resolution to the ticket? I am seeing the same error, but the cause could be totally different.

  • Nick's gravatar Nick said:
    2/3/2015 3:02 AM

    Thanks Ajit! Sorry the code doesn't format well here...

  • Ajit Sharma's gravatar Ajit Sharma said:
    1/8/2015 8:19 PM

    Hi Nick, I was able to make the changes required to index the sublayouts in French language. Thanks. The modified code is as below: public object ComputeFieldValue(IIndexable indexable) { var item = (Item)(indexable as SitecoreIndexableItem); string lan = item.Language.Name; Assert.ArgumentNotNull(item, "item"); if (!ShouldIndexItem(item)) { return null; } IEnumerable<Item> dataSources = Globals.LinkDatabase.GetReferences(item) .Where(link => ShouldProcessLink(link, item)) .Select(link => link.GetTargetItem()) .Where(targetItem => targetItem != null) .Distinct(); var result = new StringBuilder(); foreach (var dataSource in dataSources.Where(ShouldIndexDataSource)) { /* Old Code dataSource.Fields.ReadAll(); foreach (var field in dataSource.Fields.Where(ShouldIndexField)) { result.AppendLine(field.Value); } */ var i = dataSource.Database.GetItem(dataSource.ID, item.Language); if (i.Versions.Count > 0) { i.Fields.ReadAll(); foreach (var field in i.Fields.Where(ShouldIndexField)) { result.AppendLine(field.Value); } } } return result.ToString(); } Best Regards, Ajit Sharma

  • Ajit Sharma's gravatar Ajit Sharma said:
    1/8/2015 5:23 PM

    Hi Nick, We have a similar kind of requirement that you have mentioned and I have used your code to index the content of the sublayouts along with the page content. However in my case only the English language version content is being indexed when changes are made to sublayouts or the main page. For French version the sublayout content is not getting indexed. I am using Sitecore 7.5 (rev. 141003). Just wanted to understand if this is due to some code limitation or something wrong which I might have done. Any help would be highly appreciated. Thanks. Best Regards, Ajit Sharma