Last week I upgraded a Sitecore 6.0.2 solution to a Sitecore 7.0. There’s quite a leap between the two, but all in all the upgrade was no problem at all. The biggest task in the upgrade was to rewrite the code they had, that was utilizing lucene indexes.

I approached the problem by reading the Sitecore Search and Indexing Guide, to get the full understanding of how indexes are configured, while achieving that, I was missing some guide to build your own custom index.

The requirements for the custom index was to only index one extra field, on one type of template. I didn’t want the index to be filled with all kinds of templates, and I wanted to do it with as little as possible configuration.

To achieve the requirements you need to create a new configuration for the index. There is already defined a default configuration for the tree built in indexes; you’ll find it in the App_Config/Include/Sitecore.ContentSearch.Lucene.DefaultIndexConfiguration.config file, and its 983! lines. One of the reasons for the file being so large is that it defines all the templates that should be excluded from the index, and that’s quite a lot. The reason for using the exclude strategy is that the include isn’t implemented! I wasn’t the only one missing the include template function, fortunately Alexander Doroshenko had run into the same, and fixed it by overriding the LuceneIndexConiguration, and adding the IncludeTemplate method.

Having implemented the include template method, the new configuration could be done like this:

<customSearch>
<Configuration type="CustomizeSitecore.LuceneProvider.ExtendedIndexConfiguration, CustomizeSitecore"> <IndexAllFields>true</IndexAllFields> <Analyzer ref="contentSearch/configuration/DefaultIndexConfiguration/Analyzer" /> <fieldMap type="Sitecore.ContentSearch.FieldMap, Sitecore.ContentSearch"> <!-- Add fields to the Default Index Configuration --> <fieldNames hint="raw:AddFieldByFieldName"> <fieldType fieldName="categories" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider" /> </fieldNames> </fieldMap> <IndexFieldStorageValueFormatter type="Sitecore.ContentSearch.LuceneProvider.Converters.LuceneIndexFieldStorageValueFormatter, Sitecore.ContentSearch.LuceneProvider" /> <IndexDocumentPropertyMapper type="Sitecore.ContentSearch.LuceneProvider.DefaultLuceneDocumentTypeMapper, Sitecore.ContentSearch.LuceneProvider" /> <include hint="list:IncludeTemplate"> <MyCustomTemplate>{XXE604B9-02B1-48FB-8DCB-A773216B8CB3}</MyCustomTemplate> </include> </Configuration>
</customSearch>

In the above configuration notice the AddFieldByName, which is where the fields you need to be indexed should be configured, in this case "categories", and notice the IncludeTemplate, where the template is defined.

 

With the above configuration in place, you need to actually define the index the way you want. This is also done through configuration:

<contentSearch>
    <configuration type="Sitecore.ContentSearch.LuceneProvider.LuceneSearchConfiguration, Sitecore.ContentSearch.LuceneProvider">
        <indexes hint="list:AddIndex">
            <index id="my_custom_index" type="Sitecore.ContentSearch.LuceneProvider.LuceneIndex, Sitecore.ContentSearch.LuceneProvider">
                <param desc="name">$(id)</param>
                <param desc="folder">$(id)</param>
                <!-- This initializes index property store. Id has to be set to the index id -->
                <param desc="propertyStore" ref="contentSearch/databasePropertyStore" param1="$(id)" />
                <Configuration ref="customSearch/Configuration" />
                <strategies hint="list:AddStrategy">
                    <!-- NOTE: order of these is controls the execution order -->
                    <strategy ref="contentSearch/indexUpdateStrategies/onPublishEndAsync" />
                </strategies>
                <commitPolicy hint="raw:SetCommitPolicy">
                    <policy type="Sitecore.ContentSearch.TimeIntervalCommitPolicy, Sitecore.ContentSearch" />
                </commitPolicy>
                <commitPolicyExecutor hint="raw:SetCommitPolicyExecutor">
                    <policyExecutor type="Sitecore.ContentSearch.CommitPolicyExecutor, Sitecore.ContentSearch" />
                </commitPolicyExecutor>
                <locations hint="list:AddCrawler">
                    <crawler type="Sitecore.Support.ContentSearch.LuceneProvider.Crawlers.DefaultCrawler, Sitecore.Support.389569">
                        <Database>web</Database>
                        <Root>{XXE64B2A-EE62-4556-8075-7A4542AF4786}</Root>
                    </crawler>
                </locations>
            </index>
        </indexes>
    </configuration>
</contentSearch>

Let me try to explain the most important stuff in the configuration:

  • index id; the id of the index "my_custom_index", will be used in code later
  • Configuration; notice that it references the configuration we made earlier.
  • Strategy; I’ve utilized the onPublishEndAsync, as it will be running on the web database, and should be updated when items are published.
  • Crawler; defines which database it should crawl, and where to start.

That’s it, the index is defined, and you can find it in the Index Manager and rebuild it.

Utilizing the index

When utilizing the index, you should create a custom class that inherits from SearchResultItem, and then implements the field we added to the index. This is done like this:

public class CategorySearchItem : SearchResultItem
{
    [IndexField("categories")]
    public string Categories { get; set; }
}

This will enable you to utilize LINQ to Sitecore (or what it is called), like this:

var query = context.GetQueryable<CategorySearchItem>().Where(i => i.Categories.Contains(categoryID));

Where categoryID is a string containing an id.

That’s it, very simple, once you get the configuration in place. Happy coding

N.B: I ran the stuff conserning IncludeTemplate through Sitecore Support, and got a fix from them, you are in the same position as me, you could also run it through Support, and maby reference 389569. Hopefully this will be included in one of the next Sitecore revisions.

IMPORTANT: This was done in Sitecore 7.0 rev 130424. Some of the configuration was changed for Update-2, the line for the analyzer should be changed to this

<Analyzer ref="contentSearch/configuration/defaultIndexConfiguration/analyzer" />

They changed their casing to start with lower case. That shuold be it for update-2

EDIT: 

As of Sitecore 7.0 rev 131124 Update-3, the include template method has been implemented by Sitecore themselfe. This means that you dont need custom code to implement the functionality