Thursday, October 30, 2014

Basic Search Index and Search Code in Sitecore 7.5

Setting up search in Sitecore can be a learning curve, especially when the configurations change from version to version (such as 6.xx - 7.5). The following is a basic implementation which I used to set-up lucene search on a Sitecore implementation with two main content (page) types: content pages and blog posts.

Setting up the index

The first step is to create a custom search index, this is created in root/Website/App_Config/Include -  an example configuration file is available in there called Sitecore.ContentSearch.Lucene.Indexes.Sharded.Core.config.example. Using this example I modified it to the following (and saved it in the same location as search.config):

<configuration xmlns:patch="">
      <configuration type="Sitecore.ContentSearch.ContentSearchConfiguration, Sitecore.ContentSearch">
        <indexes hint="list:AddIndex">
          <!-- Change this to Sitecore.ContentSearch.LuceneProvider.SwitchOnRebuildLuceneIndex, Sitecore.ContentSearch.LuceneProvider if you would like indexes to be
               built in a temporary directory i.e. while rebuilding is happening, your old indexes work like normal until the rebuild is finished. -->
          <index id="content_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/indexConfigurations/databasePropertyStore" param1="$(id)" />
            <configuration ref="contentSearch/indexConfigurations/defaultLuceneIndexConfiguration">
              <include hint="list:IncludeTemplate">
            <strategies hint="list:AddStrategy">
              <!-- NOTE: order of these is controls the execution order -->
              <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/onPublishEndAsync" />
            <locations hint="list:AddCrawler">
              <crawler type="Sitecore.ContentSearch.SitecoreItemCrawler, Sitecore.ContentSearch">

In this example I have named the index content_index and set it to index the web database. It indexes items under the main content item ("/sitecore/content") and will only include the templates declared. All fields are also set to be indexed as well, however you could modify the file to meet any template/field indexing strategies you may have - multiple indexes could also be used for larger implementations with advanced information architecture. The index has also been set to update on publish and async.

Once saving the index xml, I went to the sitecore desktop and loaded the index manager (control panel > indexing > indexing manager). Here the index name was selected and the rebuild button clicked to build the index. If there are any errors in the index's XML, this page will show the stack trace. Once built the index is now accesible in code to complete actual searches.

Making a search

My templates all included fields called Heading and Content, these two fields would be what needed to be actually searched - as they would return the most relevant results. To allow linq to access these fields in the sitecore search I needed to Inherit the SearchResultItem object and add these fields in, this is achieved by using IndexField:
public class MyResultItem : SearchResultItem
    public string PageHeading { get; set; }

    public string PageContent { get; set; }
Then the actual search can be made with the following code:
var searchResults = new List<SearchResult>();
string searchTerm = Request.QueryString["term"];
var index = ContentSearchManager.GetIndex("content_index");

using (var context = index.CreateSearchContext())
    var results = context.GetQueryable<MyResultItem>().Where(resultItem => resultItem.PageHeading.Like(searchTerm) || resultItem.PageContent.Contains(searchTerm)).GetResults();

    foreach (var result in results)
        var searchResult = new SearchResult();
        var item = result.Document.GetItem();

        searchResult.Title = item.Fields["Heading"].ToString();
        string content = Utilities.Utility.HtmlRemoval.StripTags(item.Fields["Content"].ToString());
        searchResult.Summary = Utilities.Utility.TruncateString(content, 300);

        searchResult.Url = Sitecore.Links.LinkManager.GetItemUrl(item);

return View(searchResults);
Linq is returning any results from the index where the title is like the search term and the content contains the search term - remember this is very simple search and a search term of "cat" would match "concatenate". The results are then put into a custom object which can be rendered on the front end.

1 comment:

  1. SearchResult() doesn't function as described. Please can you update if there were changes made to the approach or the code? Thanks.