Sitecore Solr – Highlight Search Keyword in Search Summary


This is not new topic which I am sharing here but with all the articles earlier I found something different. Also it will be add-on learning over old ones.

So as title suggest I am going to share about Highlighting keyword for search result summary with some useful tips/details.

First of all we will discuss how we can do word highlight in search summary with our search filters.

First of all you need to add the references of below dll’s –

  • SolrNet.dll
  • Sitecore.ContentSearch.SolrProvider.dll
  • Sitecore.ContentSearch.SolrNetExtension.dll

And add the refrences to class file as below –

using Sitecore.ContentSearch.SolrProvider.SolrNetIntegration;
using SolrNet;
using SolrNet.Commands.Parameters;
using Sitecore.ContentSearch.Linq.Utilities;
using Sitecore.ContentSearch.Utilities;

 

Note – We don’t need to make any updates in Solr side for this.

Now let’s do the updates so firstly I implemented all my code for filters by adding predicate builders and in between of that added the code for highlight.

First we need to add the the object for query options and update the properties as below –

string searchField = "body_t";
            var queryOptions = new QueryOptions {
                Highlight = new HighlightingParameters {
                    Fields = new[] { searchField },
                    BeforeTerm = "<em style='color:red'>",
                    AfterTerm = "</em>",
                    Fragsize = 100,
                    MergeContiguous = true,
                    Snippets=5,
                },
            };

searchField is the field which we want to use for search as I am using body_t (Body) field of Sitecore/Solr to search the keyword.

I am using only 1 field but you can add n number of fields as Fields property is an array. So we add multiple field if we want.

Before Term And After Term – So whatever HTML element you want to add before and after the searched keyword define here.

Fragsize –Specifies the approximate size, in characters, of fragments to consider for highlighting. The default is 100. Using 0 indicates that no fragmenting should be considered and the whole field value should be used.

MergeContignous – Instructs Solr to collapse contiguous fragments into a single fragment. A value of true indicates contiguous fragments will be collapsed into single fragment. The default value, false, is also the backward-compatible setting.

Snippets – Specifies maximum number of highlighted snippets to generate per field. It is possible for any number of snippets from zero to this value to be generated.

More attributes you can find on Solr site.

Now let me come to the point how it will work with your existing filter code so after creating the Query Options you need to merge it with Solr API as below –

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using Sitecore.Configuration;
using Sitecore.Data;
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.Linq.Parsing;
using Sitecore.ContentSearch.SearchTypes;
using Sitecore.ContentSearch.SolrProvider.SolrNetIntegration;
using SolrNet;
using SolrNet.Commands.Parameters;
using Sitecore.ContentSearch.Linq.Utilities;
using Sitecore.ContentSearch.Utilities;

namespace Xcentium.Feature.Search.Services {
    [Service(typeof(ISearchService))]
    public class SearchService : ISearchService {
        private readonly IRenderingRepository _renderingRepository;
        private readonly IContentRepository _contentRepository;

        public SearchService(IRenderingRepository renderingRepository, IContentRepository contentRepository) {
            _renderingRepository = renderingRepository;
            _contentRepository = contentRepository;
        }

        public SearchResultViewModel GetSearchResults(string selectedCategory, string selectedContentTypes, string[] keywords,  string searchKeyword,  int pageNumber) {
            SearchResultViewModel model = new SearchResultViewModel();
            var index = Sitecore.ContentSearch.ContentSearchManager.GetIndex(SearchUtilities.GetSearchIndexName());
            Expression predicate = PredicateBuilder.True();
            predicate = predicate.And(item => item.Templates.Contains(DocumentMap.TemplateId));
            predicate = predicate.And(item => !item.Name.Equals(HelixConstants.StandardValues));
            predicate = predicate.And(item => !item.Name.Equals(HelixConstants.NameToken));
            if (!string.IsNullOrEmpty(searchKeyword)) {
                    string[] querySplit = searchKeyword.Split(' ');
                    Expression<Func> contentPredicate = PredicateBuilder.True();
                    var ignoreKeywordList = Settings.GetSetting("Search.IgnoreKeywords.FromSearch");
                    foreach (string query in querySplit) {
                        if (ignoreKeywordList != null && !ignoreKeywordList.Contains(query)) {
                            contentPredicate = contentPredicate.Or(item => item.Body.Contains(query));
                        }
                    }
                    predicate = predicate.And(contentPredicate);
                }
            }

            if (!string.IsNullOrEmpty(selectedCategory)) {
predicate = predicate.And(item => item.DocumentCategoryId.Equals(selectedCategory));
}
            if (!string.IsNullOrEmpty(selectedContentTypes)) {
var selectedContentType = new ID(selectedContentTypes);
predicate = predicate.And(item => item[Foundation.Core.Constants.IndexFieldName.DocumentTypeIndexFieldName] == IdHelper.NormalizeGuid(selectedContentType));
}

            if (keywords != null && keywords.Any()) {
foreach (var key in keywords) {
predicate = predicate.And(item => item.KeywordComputedIds.Contains(key));
}
}
            string searchField = "body_t";
            var queryOptions = new QueryOptions {
                Highlight = new HighlightingParameters {
                   Fields = new[] { searchField },
BeforeTerm = "<em style="color:red;">",
AfterTerm = "</em>",
Fragsize = 100,
MergeContiguous = true,
Snippets=5,
                }
            };
            using (var context = index.CreateSearchContext()) {
                  IQueryable query = context.GetQueryable().Where(predicate);
                 List highlightResults = new List();

                 var solrQuery = new SolrQuery(((IHasNativeQuery) query).Query.ToString());
var results = context.Query(solrQuery, queryOptions);

                foreach (var result in results) {
                    var highlights = results.Highlights[result.Fields["_uniqueid"].ToString()];
                    if (highlights.Any()) { foreach (var highlightResult in highlights) {
                            var highValue = string.Join(", ", highlightResult.Value);
                            highlightResults.Add(new DocumentSearchResultItem { Name = result.Name, Body = (!string.IsNullOrEmpty(highValue) ? highValue : result.Body), DocumentTitle=result.DocumentTitle, PublicationDate=result.PublicationDate, PageURL = result.PageURL, DocumentCategory = result.DocumentCategory, DocumentTypeTitle = result.DocumentTypeTitle }); } }
                }

                model.SearchResults = highlightResults;
                return model;
            }
        }
    }
}

 

So this is the complete code which I have implemented search with filters as well as Highlight search keyword.

In the given above code we are getting highlighter value and adding it to list of object with required property values –

foreach (var result in results) {
                    var highlights = results.Highlights[result.Fields["_uniqueid"].ToString()];
                    if (highlights.Any()) { foreach (var highlightResult in highlights) {
                            var highValue = string.Join(", ", highlightResult.Value);
                            highlightResults.Add(new DocumentSearchResultItem { Name = result.Name, Body = (!string.IsNullOrEmpty(highValue) ? highValue : result.Body), DocumentTitle=result.DocumentTitle, PublicationDate=result.PublicationDate, PageURL = result.PageURL, DocumentCategory = result.DocumentCategory, DocumentTypeTitle = result.DocumentTypeTitle }); } }
                }

Article by CHRIS PERKS was very helpful to implement the same.

In the above code after creating the query we need to add it to Solr API url.

 var solrQuery = new SolrQuery(((IHasNativeQuery) query).Query.ToString());

This is the code which is executing our query and making search solr API with all the factes/filters and other options we have added to predicate builder or directly to our query.

Hope this can help you to achieve if you are looking to similar functionality with Sitecore Solr.

In my next post I am going to share how we can use/control the pagination from Solr API and how we can add the query string parameters to Solr API call for example hl.score.b, hl.bs.variant etc.

 

This entry was posted in Sitecore, Sitecore Solr, Solr, Uncategorized and tagged , , , . Bookmark the permalink.

1 Response to Sitecore Solr – Highlight Search Keyword in Search Summary

  1. Pingback: Sitecore Solr – Manage pagination and sorting directly from Solr | Sitecore Tweaks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s