How To Set Up A Custom Lucene Index With Umbraco
Umbraco, like a lot of CMS systems, decided against creating a custom search functionality from scratch, instead, they implement one of the most widely used search providers available, Lucene. Lucene is a really powerful search library that is also super quick. In today's guide, I'm going to cover the basics to get you up and running with your own custom indexes with Umbraco.
Where Are My Indexes?If you are new to Umbraco, in your websites webroot, in 'App_Data' -> 'TEMP' -> 'ExamineIndexes' you will find all your websites Lucene files. Out of the box, you should see some folder called 'Internal' and 'External'. The first tip I'm going to go over is how to force Umbraco to re-index your website. Open your Umbraco backend up in a browser: Click on the 'Developer' section and then the 'Examine Management' tab. Under the Indexes section, you should see a list of Indexes that have been set-up in your site. If you click on any of the indexes, you should see a 'Rebuild index' button. Clicking on this should generate your indexes for you.
How Are Umbraco Indexes Defined?If you are wondering how these indexes magically appear on your website, then you can take a look in your 'Config' folder: In here you will see two files called, 'ExamineIndex.config' and 'ExamineSettings.config'. If you look inside both files, you should be able to see where the indexes are defined.
Custom Umbraco IndexesYou might be wondering why you would need to create a custom Umbraco index, a few examples include:
- Locking down your search for security by only exposing certain Umbraco items
- Creating a specialist search that only contains results for a given language
<IndexSet SetName="Contacts" IndexPath="~/App_Data/TEMP/ExamineIndexes/Contacts/" IndexParentId="1"> <IndexAttributeFields> <add Name="id" /> <add Name="nodeName"/> <add Name="updateDate" /> <add Name="writerName" /> <add Name="nodeTypeAlias" /> </IndexAttributeFields> <IndexUserFields> <!-- Contact Page --> <add Name="companyHQTitle" /> <add Name="hQAddressLine1" /> <add Name="hQAddressLine2" /> <add Name="hQAddressLine3" /> <add Name="hQPostcode" /> </IndexUserFields> <IncludeNodeTypes> <add Name="ContactPage"/> </IncludeNodeTypes> <ExcludeNodeTypes> </ExcludeNodeTypes> </IndexSet>This indexset can be added anywhere in the section. The element might look scary at first, but it's quite easy when you break it down:
- SetName This is the name of the index (or alias in Umbraco talk). This is the name you will use in your code to reference the index
- IndexPath Where the index will live on disk
- IndexAttributeFields Defines the in-built Umbraco fields to include in the index
- IndexUserFields The custom fields in your doctypes to include
- IncludeNodeTypesThe doctypes you want to include
- ExcludeNodeTypesThe doctypes you want to exclude
<add name="Contacts" type="UmbracoExamine.UmbracoContentIndexer, UmbracoExamine" supportUnpublished="false" supportProtected="false" analyzer="Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net" />Next, you will need to register the ExamineSearchProviders, in the -> section.
<add name="Contacts" indexSet="Contacts" type="UmbracoExamine.UmbracoExamineSearcher, UmbracoExamine" analyzer="Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net"/>The most import part of this section is that the IndexSet' property matches your index name that was defined in the ExamineIndexProviders.
Searching The IndexSo, now you've defined an index, if you follow the steps above you should see the files populate on disk. The next step is to use it in code:
var searchTerm = "search term"; var searcher = ExamineManager.Instance.SearchProviderCollection["Contact"]; if (searcher == null) return null; var searchCriteria = searcher.CreateSearchCriteria(BooleanOperation.Or); ISearchCriteria query = searchCriteria.RawQuery(searchTerm); IOrderedEnumerable<SearchResult> searchResults = searcher.Search(query).OrderByDescending(x => x.Score); return searchResults;In the code above we use the ExamineManager, passing in the index name to select which provider to query. We set a searchCriteria and passed in a search term. You can be very detailed in how you want to query the index, but, in this example, I'm just doing a basic search. Lastly, we query the index and order the results based on the 'score' property. When Lucene searches and indexes, it will also rate how close a match it is, so filtering with most relevant results first is a pretty standard factor.