Many Sitecore developers these days use the Advanced Database Crawler (ADC) as their interface into the Lucene.NET world. The ADC is a great tool because it builds on top of the Sitecore.Search
namespace which in its own right wraps over Lucene.NET. Many Sitecore instances will contain multiple sites and share data across them. Sometimes its necessary to build a site-specific search mechanism that functionally works the same for each site, but ensures results are only for the given site. This blog post will go over two simple ways to accomplish this with the Advanced Database Crawler.
Location Filter
The easiest way to accomplish this task to filter results by a managed site is to use the LocationIds
filter on the search parameter object. This location filter will only return SkinnyItem
results that fall at or under the provided location. The LocationIds
also happens to be a delimited list of GUIDs, so we can easily leverage this to filter results by site:
- Get the context site path
- Filter with the ADC using
LocationIds
by passing the home page’s or site root’s GUID
For example, here’s some basic code to do just that:
[csharp]
Item homeItem = Sitecore.Context.Database.GetItem(Sitecore.Context.Site.StartPath);
if(homeItem != null)
{
searchParams.LocationIds = homeItem.ID.ToString();
}
[/csharp]
This example assumes your home page is below the site root path, which is common if you have some other data items for your site that are not pages.
Full Path Dynamic Field
Another way to do the same type of operation takes a bit more work and doesn’t necessarily yield any better results, however it’s good to have options! This approach requires to you define a dynamic field in your index for the full path of each item. If you’re using v1 of the ADC, this exists as the “_fullcontentpath” dynamic field. If you’re using the ADC v2, you’ll need to define it (grab it from here).
Once you configure that dynamic field, simply write some code to compare the skinny items from a search operation based on the full path vs. the context site’s start path. Here’s an example:
[csharp]
public static IEnumerable<SkinnyItem> FilterSkinnyItemsByContextSite(IEnumerable<SkinnyItem> items)
{
return FilterSkinnyItemsBySite(items, Sitecore.Context.Site);
}
public static IEnumerable<SkinnyItem> FilterSkinnyItemsBySite(IEnumerable<SkinnyItem> items, Sitecore.Sites.SiteContext site)
{
return FilterSkinnyItemsByRootPath(items, site.RootPath);
}
public static IEnumerable<SkinnyItem> FilterSkinnyItemsByRootPath(IEnumerable<SkinnyItem> items, string siteRootPath)
{
// isolate the path query to a finite item path, not a prefix of a longer path
// e.g. ensures a filter on /sitecore/content/brand as /sitecore/content/brand/ to avoid allowing /sitecore/content/brand2
if (!siteRootPath.EndsWith("/"))
siteRootPath = siteRootPath + "/";
return items.Where(si => si.Fields["_fullcontentpath"].StartsWith(siteRootPath, StringComparison.InvariantCultureIgnoreCase));
}
[/csharp]
As I said before, leveraging the LocationIds
filter at the search-level is easier and more efficient as it won’t return unnecessary results. The second approach is good if you have existing search code that you don’t want to adjust too much and instead want to easily filter the results by site.
I would like to index the full path, but where exactly do I put the code snippet you give that defines FullPathField?
There are two links in the post you should look at, the sample config file that defines the field and the class that resolves the value of the field:
http://svn.sitecore.net/AdvancedDatabaseCrawler/Trunk/App_Config/Include/Sitecore.SharedSource.Search.config
http://svn.sitecore.net/AdvancedDatabaseCrawler/Trunk/DynamicFields/FullPathField.cs