- In Part 1 we talked about interacting and consuming the search service
- In Part 2 we discussed a Tagging strategy to allow for a Filtered Search to be possible
- In Part 3 we looked at our service layer which worked with our Ajax calls
Today we are going to dive into our search service and talk about some of the customizations we did to make Lucene and Sitecore do what we wanted from an Indexing and Search standpoint. If you recall from Part 3 (or by looking at the above screenshot) we had a piece of code that would create a new Searcher and call the GetItems method passing in the SearchParams we created based on the Ajax call that was being executed. Now we are going to dive into what the Searcher class is.
Our Searcher class is just a modified version of the code that you can get from Sitecore's Shared Source library and you can watch a webinar to get more detail on it here so I won't go into a lot of detail. Instead I will just go over some of the modifications I have made. Above you can see that we have an additional call to an ApplyTagFilter method that will help us filter by the Tags that were checked by the user in our UI.
The ApplyTagFilter method will iterate through the GUIDs in our Tag collection and add them as an OR criteria to our query. Seeing how that our Tags are GUIDs and therefore unique you will notice we are just querying against the BuiltIn.Content field.
So the AdvancedDatabaseCrawler is inheriting from the standard Sitecore DatabaseCrawler. One requirement our client had is that they want the ability to hide an item from search fairly easily even if the actual content is available on the site. The way I accomplished this is to simply have a Field on the Base Page Template called "Hide From Search". Keying off of this field we can then tell Sitecore to not index the item if this field is checked.
When setting up the configuration for each index you can specify the boost, but I have taken it a step farther here allowing the Content Managers to overwrite the Boost associated with the Template or Page.
So above we are taking the default Boost associated with the document based on the configuration and adjusting it with the Search Boost value if the field exists.
If you look at the article above it is tagged as a White Paper. If the user does a search for items that are tagged as an Article / White Papers then this article wouldn't actually come up in our results because the White Paper GUID is different than its parent. We could dynamically bubble up a Tag's ancestry at Query time but that would be a little bit of a performance hit so instead we are going to crawl up the Tag hierarchy with the crawler. You can see how we are doing this below.
When you are setting up your custom crawler and doing some tricky things with searches you will inevitably need to figure out why-in-the-heck you are not getting the results you are expecting. The best way to do this is to set a break point at the point where your code is about to call RunQuery and copy the LuceneQuery value. Once you have this query you can use the Luke client or Sitecore Rocks VS.NET Plug-in to run the query and see why it is not pulling back what you are expecting.
It's a Wrap
Well it took four posts, but hopefully you got a good understanding of the approach we used for Filtered Search on a recent project. If you want to learn a bit more, there is a great webcast for the Sitecore Virtual User Group in July that has a great overview and some samples as well. Lucene is quite fast and for future projects I will probably take it a step further where we can leverage Lucene for more than just Search and Filtered Search and use it for presentation elements as well such as menus, lists and summaries.