As of Umbraco 4.5, Examine, which is a custom search engine built on Lucene.NET, comes standard as part of the backoffice search feature. Because of that, setting up indexers that you can use to search the content that is published on your website is relatively easy.
To setup Examine for your website, follow these simple steps.
LISTING 9-5: ExamineIndex-partial.config
<IndexSet SetName=“RunwayIndexSet” IndexPath=“∼/App_Data/ExamineIndexes/Runway/”> <!-- fields specific to Umbraco --> <IndexAttributeFields> <add Name=“id” /> <!-- required --> <add Name=“nodeName” /> <!-- required --> <add Name=“updateDate” /> <add Name=“writerName” /> <add Name=“path” /> <add Name=“nodeTypeAlias” /> <!-- required --> </IndexAttributeFields> <!-- fields that you have defined in your various document types --> <IndexUserFields> <add Name=“bodyText” /> <add Name=“sidebarContent” /> </IndexUserFields> <IncludeNodeTypes /> <!-- specify any document types that you do NOT want to be indexed --> <ExcludeNodeTypes> <add Name=“FAQArea” /> </ExcludeNodeTypes> </IndexSet>
The IndexPath that you specify must be writable by IIS. If IIS does not have write privileges on this folder, the index won't be created and therefore cannot be searched.
LISTING 9-6: ExamineSettings-partial.config
<Examine> <ExamineIndexProviders> <providers> … <add name=“RunwayIndexer” type=“UmbracoExamine.MemberLuceneExamineIndexer, UmbracoExamine” runAsync=“true” supportUnpublished=“true” supportProtected=“true” interval=“10” analyzer=“Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net”/> … </providers> </ExamineIndexProviders> <ExamineSearchProviders defaultProvider=“InternalSearcher”> <providers> … <add name=“RunwaySearcher” type=“UmbracoExamine.LuceneExamineSearcher, UmbracoExamine” analyzer=“Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net” indexSet=“RunwayIndexSet”/> … </providers> </ExamineSearchProviders> </Examine>
LISTING 9-7: SearchResults.ascx
<%@ Control Language=“C#” AutoEventWireup=“true” CodeBehind=“SearchResults.ascx.cs” Inherits=“UmbracoUsersGuide.usercontrols.SearchResults” %> <%@ Import Namespace=“UmbracoUsersGuide.usercontrols” %> <%-- provide some stats of the search here --%> <p> Your search for : <b><u><%=SearchTerm%></u></b> returned <i><b><%=this.SearchResultsCollection.Count()%></b> result(s)</i> </p> <%-- Create a simple repeater template to use for output --%> <asp:Repeater ID=“SearchResultListing” runat=“server” > <HeaderTemplate> <ul class=“search-results”> </HeaderTemplate> <ItemTemplate> <li> <a class=“title” href=“<%#((Examine.SearchResult)Container.DataItem).FullUrl()%>”> <%# ((Examine.SearchResult)Container.DataItem).Fields[“nodeName”]%> </a> <div class=“details”> <p> <%#((Examine.SearchResult)Container.DataItem).GetDetails(300)%></p> </div> <div class=“url”> <a href=“<%#((Examine.SearchResult)Container.DataItem).FullUrl()%>”><%#((Examine. SearchResult)Container.DataItem).FullUrl()%></a> </div> </li> </ItemTemplate> <FooterTemplate> </ul> </FooterTemplate> </asp:Repeater>
LISTING 9-8: SearchResults.ascx.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using Examine; using UmbracoExamine; using UmbracoExamine.SearchCriteria; namespace UmbracoUsersGuide.usercontrols { public static class SearchResultExtensions { // Create a set of helper methods to make output // cleaner. public static string FullUrl(this SearchResult sr) { // Generate the URL for the returned node using // the umbraco library method NiceUrl. var urlStr = umbraco.library.NiceUrl(sr.Id); return urlStr; } public static string GetDetails (this SearchResult sr, int length) { var contentStr = “”; var truncateStr = “…”; if (sr.Fields.ContainsKey(“bodyText”)) { contentStr = sr.Fields[“bodyText”]; } else if (sr.Fields.ContainsKey(“question”)) { contentStr = sr.Fields[“question”]; } else if (sr.Fields.ContainsKey(“answer”)) { contentStr = sr.Fields[“answer”]; } // Only show the first 300 characters of the node // contents and use that as the preview of the // page content in the repeater. if (contentStr.Length > length) contentStr=contentStr.Substring(0, length) + truncateStr; return contentStr; } } public partial class SearchResults : System.Web.UI.UserControl { /// <summary> /// The term being searched on /// </summary> protected string SearchTerm { get; private set; } /// <summary> /// The search results list /// </summary> protected IEnumerable<SearchResult> SearchResultsCollection { get; private set; } public SearchResults() { // Initialize the class with some default values SearchTerm = string.Empty; SearchResultsCollection = new List<SearchResult>(); } protected void Page_Load(object sender, EventArgs e) { // Grab the search term from the URL query string // ‘s’, if it's null or empty break out of this load // event. SearchTerm = Request.QueryString[“s”]; if (string.IsNullOrEmpty(SearchTerm)) return; // Setup the search criteria by pointing to the searcher // that you created in ExamineSettings.config var criteria = ExamineManager.Instance .SearchProviderCollection[“RunwaySearcher”] .CreateSearchCriteria(IndexTypes.Content); // Configure a filter that will query all of the fields // that you have specified below and that you can feed to // searcher below. var filter = criteria .GroupedOr(new string[] { “nodeName”, “bodyText”, “question”, “answer” }, SearchTerm) .Not() .Field(“umbracoNaviHide”, “1”) // filter out the hidden pages .Compile(); // Execute the actual search, again pointing to // the searcher that was configured in // ExamineSettings.config. SearchResultsCollection = ExamineManager.Instance .SearchProviderCollection[“RunwaySearcher”] .Search(filter); // Bind the results to the repeater that's in the view SearchResultListing.DataSource = SearchResultsCollection; SearchResultListing.DataBind(); } } }
LISTING 9-9: SearchFieldForTemplate.txt
<input type=“text” id=“search-term” name=“search” value=“” /> <input type=“button” name=“searchBtn” value=“Search” onclick=“runSearch();” /> <script type=“text⁄ javascript”> function runSearch(){ var searchResultsUrl = “http://umbracousersguide.local/search-results.aspx”; document.location.href = searchResultsUrl + “?s=” + document.getElementById(“search-term”).value; } </script>