There are a lot of cases when we need to boost search results. One of them is when we need to prepare a list of recommended results based on the entered keywords.
Suppose we have an Item Tags field with Multilist type. The Multilist field is a reference field and contains IDs of selected items. First of all, we need to implement a computed field which would be store a tag title instead of ID:
using System.Linq;
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.ComputedFields;
using Sitecore.Data.Items;
namespace SearchBoosting
{
public class ItemTagsComputedField
{
public class MediaDownloadCenterGroupComputedField : IComputedIndexField
{
public object ComputeFieldValue(IIndexable indexable)
{
Item item = indexable as SitecoreIndexableItem;
if (item != null)
{
//I guess the tags field will have a multilist typle.
Sitecore.Data.Fields.MultilistField field = item.Fields["Item Tags"]; //Name of field with tags
if (field != null)
{
var items = field.GetItems();
return items.Select(q => q.DisplayName).ToList(); //You can use some field for getting title of tag.
}
}
return null;
}
public string FieldName { get; set; }
public string ReturnType { get; set; }
}
}
}
Below I've described another solution how you can boost an item based on keywords, which a user has entered.
Then we need to add them to an index configuration. Just add the following row to the section. Below is an example of what it will look like:
The next step is to add the search model:
using System.Collections.Generic;
using System.ComponentModel;
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.Converters;
using Sitecore.ContentSearch.SearchTypes;
namespace SearchBoosting
{
public class BoostingExampleSearchResultItem : SearchResultItem
{
[IndexField("item_tags")]
[TypeConverter(typeof(IndexFieldEnumerableConverter))]
public virtual IEnumerable<string> Tags { get; set; }
}
}
Now we are ready to use this field for boosting:
using System.Collections.Generic;
using System.Linq;
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.Linq;
using Sitecore.ContentSearch.Linq.Utilities;
using Sitecore;
namespace SearchBoosting
{
public class SearchBoosting
{
protected virtual string SearchIndexName
{
get
{
return "your_search_index";
}
}
private ISearchIndex _index;
private ISearchIndex Index
{
get { return _index ?? (_index = ContentSearchManager.GetIndex(SearchIndexName)); }
}
public SearchResults<BoostingExampleSearchResultItem> ApplySearch(List<string> keywords)
{
using (IProviderSearchContext searchContext = Index.CreateSearchContext())
{
var query = searchContext.GetQueryable<BoostingExampleSearchResultItem>(new CultureExecutionContext(Context.Language.CultureInfo));
var predicateRoots = PredicateBuilder.True<BoostingExampleSearchResultItem>();
if (keywords != null && keywords.Any())
{
foreach (var keyword in keywords)
{
//If we want just boost some items without theirs filtering, we need to process both conditions:
//if item contains a tag which is equals to entered word and if it doesn't:
predicateRoots = predicateRoots.Or(itm => (itm.Tags.Contains(keyword)).Boost(5f));
predicateRoots = predicateRoots.Or(itm => (!itm.Tags.Contains(keyword)).Boost(1f));
}
}
var results = query.Where(predicateRoots).GetResults();
return results;
}
}
}
}
Do you like this approach? Tell us what you think!