Over the years working with Sitecore I’ve had to create custom indexes and add items to them for most clients I’ve worked for. I’ve generally written a Search Crawler and Search Indexer to handle this but it’s always seemed like a lot of code to manage just to add a few items to an index and temperamental to control the indexing frequency accurately. I’ve also had many issues with Indexes being out of Sync in the past due to Sitecore Events not firing on CD instances etc.
I’ve tried various approaches to simplifying this in the past but unfortunately never got this working. However this came up again on a recent project and I was successful this time – so decided I’d share my approach and code.
Note in this example I’m using Solr but in Theory this same code should work with Azure Search also.
In simple terms the approach is to:
1) Create a Custom Index – to store my content (in this case Blogs)
2) Create a Search Indexing Service – which will retrieve the Items and add them to the Custom index
3) Create an SiteCron Indexing Job – which will call my Indexing Service to Index the Items on a regular basis
4) Create a Search Results Page – which will display the search results from the Index
Benefits of this approach
- Less Code to write and manage
- Can control how often the indexing runs very accurately (using SiteCron) and this persists across App Service / IIS Restarts.
- Easy to test and maintain
1) Creating a Custom Solr Index
I’m not going to go into this process too much as it’s documented well elsewhere but essentially you need to copy on of the out of the box solr folders, rename it and also update the core.properties file. For this example I’ve created and index called sc93_blogs_index:
Configuration
You will also need to add 2 configuration files for the custom Index like so to define the index name, strategy (of manual) and configure the fields to include. Amend these as required for your use-case:
Index Config:
Index Fields Config:
2) Search Indexing Service
The next step is to create our Search Indexing Service. This will get the blog items and add them to the index. This could easily be pulling Info from an datatabase, API or File instead if needed. I’ve called mine BlogPostSearchService:
public class BlogPostSearchService : ISearchService { ... }
I also added an interface with two methods:
public interface ISearchService { int IndexContent(); BlogPostSearchResultsModel GetResults(BlogPostSearchResultsModel blogPostSearchResultsModel, string searchTerm, int resultsPerPage, int currentPage); }
Index Content Method
The IndexContent() Method is like so. Note this code is not optimal if you have more than a few hundred items within a folder, you may wish to re-structure your items differently:
Get Content Method
The GetContent() Method is as follows:
Supporting Models / Classes
There are various supporting models and classes used in the above code. Below are the key ones.
BlogPostSearchResult
public class BlogPostSearchResult: SearchResultItem { [DataMember] [IndexField("Title")] public string Title { get; internal set; } [DataMember] [IndexField("Description")] public string Description { get; internal set; } }
BlogPostSearchResultsModel
This Model is used to hold my search results and some other properties about the search results for use in the View:
public class BlogPostSearchResultsModel { public string SearchTerm { get; set; } public IPagedList<BlogPostSearchResult> SearchResults { get; set; } public int TotalNumberOfResults { get; set; } public int NoOfResults { get; set; } public int Page { get; set; } }
Settings
You will notice there are some settings used in the code such as for the Blog Post Items Path. Add a Sitecore patch file for these and configure them as needed.
Paged List
I’m using an Nuget Package for PagedList, this is a good one if you want to use one too: https://github.com/dncuug/X.PagedList
3) SiteCron Indexing Job
The next step is to create our SiteCron Job which will be responsible for indexing the content. This calls the IndexContent() method on the service. Obviously this needs to match your SiteCron Job name above.
See my post here about logging to the last run log etc if you’d like to do that too.
This is then setup in SiteCron to run like so, schedule it to run as needed:
4) Search Results Page
The last step is to display the Search Results. Create a page in Sitecore using whatever template you use. Then Create an Controller Rendering and View in Sitecore, reference the Controller below and add the rendering to the page.
Controller
The Controller looks like so:
View
The View, this is a simplified version:
The Result
So once you’ve done all the above you should end up with something like the following:
Hopefully this helps someone else who need to implement a custom search and illustrates an alternative approach that could work for them.