Sitecore Solr – Tips if you are working with Sitecore Solr

As I mentioned in my last post Sitecore Solr – Highlight Search Keyword to manage or handle the sorting and pagination directly from Solr instead of calculating it after getting results.

If you haven’t read my last post you can read here It will give you some idea how we can modify Solr api call.

In this post will share my recent learning about manage pagination, sorting and other functionality directly from Solr API instead of adding it to after getting results –

While working with Search Highlight I found that to highlight keyword we need to run foreach loop for all the items and then we can make it highlight the keyword there I thought if we can do it just the results which is part of current pagination it would be perfect. So I started looking into it and from here I got an idea to add the sorting in Solr API call.

For this you need to add the refrence of below dll’s

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

And some of the info you can find in my last post for same.

Now create a object for QueryOptions there we can define multiple properties value to calculate the results as per our need.

So as I did for Result Highlight sharing same code here but with additional features.

<pre>

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
                },
                OrderBy = new[] { new SolrNet.SortOrder("publicationdate_tdt", sorOrder) },
                Rows = Settings.GetIntSetting("Search.Pagination.ResultPerPage", 20),
                Start = Settings.GetIntSetting("Search.Pagination.ResultPerPage", 20) * (pageNumber - 1),
                ExtraParams = new List
    {
        new KeyValuePair("hl.method", "unified")
    }

            };

</pre>

So the first property Highlight I already explained in my previous post. Here we will discuss about other properties  –

  1. Pagination  – For pagination we need to add the values to Rows and Start property as given in above code.
    1. Rows – Number of results we need to show on Page.
    2. Start – Calculation where to start getting result (For example if we are on page 2 and showing 10 results on page then value here will be 11)
  2. OrderBy – You can also specify order by result if you are using any sorting options for your result as in y case I am having Sort dropdown where user can select Oldest to Newest and Newest to Oldest.
    For this we need to create object of Solr.Net.Order as given below –
SolrNet.Order sorOrder = SolrNet.Order.DESC;
            if (!string.IsNullOrEmpty(sortBy)) {
                if (sortBy == "otn") {
                    sorOrder = SolrNet.Order.ASC;
                }
                if (sortBy == "nto") {
                    sorOrder = SolrNet.Order.DESC;
                }
            }

So in the above code I am passing the sortOrder to QueryOptions.

In my code I am sorting result on the bases of Publication Date so defined it for Publication dates only.

3. ExtraParams – Here we can define Collection of key value pairs if we want to define more options to Solr API call or want to get the selected result list.

As I have provided just for example  you can get complete list of Parameters with details here.

Now to get the calculated resuts we are passing in QueryOptions we need to make it as below –

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

With this code I don’t need to query results for pagination it was only returning me results as per my pagination component needs.

Sorting  – Firstly I added sort by to after querying the results but somehow with the same code it was not working for me and then I tried this options and I found it great to implement. I didn’t check this performance wise but I think it’s faster then what we do with basic pagination code.

If you want to check how it is adding to Solr query then after executing the code you can go to Search.log.xxx.xxx under App_Date folder and there you can see what is the final query call.

 

There are many more options to do the same and I would like to here those in comments below 🙂

 

Posted in Sitecore, Sitecore Solr, Uncategorized | Tagged , , , | Leave a comment

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 = "&amp;amp;lt;em style='color:red'&amp;amp;gt;",
                    AfterTerm = "&amp;amp;lt;/em&amp;amp;gt;",
                    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 =&gt; item.Templates.Contains(DocumentMap.TemplateId));
            predicate = predicate.And(item =&gt; !item.Name.Equals(HelixConstants.StandardValues));
            predicate = predicate.And(item =&gt; !item.Name.Equals(HelixConstants.NameToken));
            if (!string.IsNullOrEmpty(searchKeyword)) {
                    string[] querySplit = searchKeyword.Split(' ');
                    Expression&lt;Func&gt; contentPredicate = PredicateBuilder.True();
                    var ignoreKeywordList = Settings.GetSetting("Search.IgnoreKeywords.FromSearch");
                    foreach (string query in querySplit) {
                        if (ignoreKeywordList != null &amp;&amp; !ignoreKeywordList.Contains(query)) {
                            contentPredicate = contentPredicate.Or(item =&gt; item.Body.Contains(query));
                        }
                    }
                    predicate = predicate.And(contentPredicate);
                }
            }

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

            if (keywords != null &amp;&amp; keywords.Any()) {
foreach (var key in keywords) {
predicate = predicate.And(item =&gt; 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.

 

Posted in Sitecore, Sitecore Solr, Solr, Uncategorized | Tagged , , , | 1 Comment

Field Validation on Specific Template Types

Recently I asked to add validation on specific field.  That is out of the box provided by Sitecore you need to go to field item and then select the validation items in the Validation Rule Section. But here is the point I am using same field in many different template types.

So I created a separate data template for specific field type (For example Title) and inherited this field template into many data templates and I was asked to add validation on the field but on some data templates not all of them.

So if I am adding validation rules to field then it will get added to all the data template where it inherited. And this is we don’t need to do. So here I started thinking that how can implement this as per data template specific.

I finally decided to create custom validation rule this was the only way I found to handle the same.

  1. Created a Folder with name of my site under /sitecore/system/Settings/Validation Rules/Field Rules location. I did it to make my rule separate.
  2. Created Validation Rule item by /sitecore/templates/System/Validation/Validation Rule template. (For example I am creating Required field validation).
  3.  Add the basic field value like Title, Description etc.
  4. In this step we need to add value in Type and Parameter but those are depend on the class which we need to create for this.

Below is the class which created for this –

/// <summary>
    /// Class CustomRequiredFieldValidator.
    /// Implements the 
    /// </summary>
    /// 
    [Serializable]
    public class CustomRequiredFieldValidator : StandardValidator
    {
        /// <summary>
        /// Initializes a new instance of the  class.
        /// </summary>
        public CustomRequiredFieldValidator()
        {
        }

        /// <summary>
        /// Initializes a new instance of the  class.
        /// </summary>
        /// The Serialization info.
        /// The context.
        public CustomRequiredFieldValidator(SerializationInfo info, StreamingContext context) : base(info, context)
        {
        }

        /// <summary>
        /// Gets the name.
        /// </summary>
        /// The validator name.
        public override string Name
        {
            get
            {
                return "Required";
            }
        }

        /// <summary>
        /// When overridden in a derived class, this method contains the code to determine whether the value in the input control is valid.
        /// </summary>
        /// The result of the evaluation.
        protected override ValidatorResult Evaluate()
        {
            var templateID = MainUtil.GetStringList(true, this.Parameters["templateids"].Split('|'));
            if (templateID.Contains(this.GetItem().TemplateID.ToString()))
            {
                if (!string.IsNullOrEmpty(this.ControlValidationValue))
                {
                    return ValidatorResult.Valid;
                }

                this.Text = this.GetText("Field \"{0}\" must contain a value.", this.GetFieldDisplayName());
                return this.GetFailedResult(ValidatorResult.CriticalError);
            }

            return ValidatorResult.Valid;
        }

        /// <summary>
        /// Gets the max validator result.
        /// </summary>
        /// The max validator result.
        /// This is used when saving and the validator uses a thread. If the Max Validator Result
        /// is Error or below, the validator does not have to be evaluated before saving.
        /// If the Max Validator Result is CriticalError or FatalError, the validator must have
        /// been evaluated before saving.
        protected override ValidatorResult GetMaxValidatorResult()
        {
            return this.GetFailedResult(ValidatorResult.Error);
        }

 

So in this class we are just checking the condition for required value.

Now lets switch to steps above specially moving back to Step 4 our last step –

So we need to add assembly reference in type field as below –

dm1

And in Parameter field we need to provide pipe separated template id’s where we need to apply the validation.

So here the template id’s are the one where we wan’t to specially add the validations.

 

Now the final steps we need to add this custom validation to the field item.

Navigate to your field item and add the validation in Validation rules section as below – I added it in all four fields but it’s on you what is your requirement – Quick Action Bar, Validate Button, Validator Bar and Workflow. –

dm_2.png

 

This was the interesting implementation I did there are may be many more ways but I found this easy for me.

Stay connected for my next post for adding custom validation for max length 700/300 char again template specific.

 

 

Posted in Sitecore, Sitecore Validation Rules, Uncategorized | Tagged , | Leave a comment

Add specific value to any Link of Website in Sitecore

In my recent project I came across with a requirement where client need specific values or actually contactid of current visitor to added into specific links so that whenever user is clicking the link that will redirect user with contact id in query string and they can store that value for custom reporting.

Actual implementation need is client want to collect actual contact who clicked on the links and complete the transaction or functionality which they want user to do. So they just wanted to track the contacts/users it can be either logged in user or anonymous user.

And for this content editor can add to any link field General Link Field, General Link with Search, Richtext etc…

Also content editor should have functionality to add the link anywhere and it should work.

So I thought to add a token for content editor so that they can add the token to link they want to add contact id and from the backend we can replace the token with actual value.

Now to track this down and update the token value with the actual contact id I didn’t found any direct way to implement it so I started looking over the internet and found that I can update RenderField pipeline of Sitecore. There actually I can get the field value before rendering or serving it to page and I can make the change there.

I created a class file to make this change as below –


public class GetLinkFieldValueExtend
    {
        public void Process(RenderFieldArgs args)
        {
            Assert.ArgumentNotNull(args, nameof(args));
            if ((args.FieldTypeKey != "general link with search" && args.FieldTypeKey != "general link") || args.FieldTypeKey != "rich text" || string.IsNullOrWhiteSpace(args.Result.FirstPart))
            {
                return;
            }

            args.Result.FirstPart = UpdateToken(args.Result.FirstPart);
            args.Result.LastPart = args.Result.LastPart;
        }

        private string UpdateToken(string fieldValue)
        {
            if (fieldValue.Contains("$$contactid$$"))
            {
                fieldValue = GetTokenUpdateLink(fieldValue);
            }
            return fieldValue;
        }

        public static string GetTokenUpdateLink(string url)
        {

            try
            {
                var contactId = "contact id"; // write logic to get the contact id;
                return url.Replace(ConfigSettings.ContactIdTokenName, contactId);
            }
            catch (Exception ex)
            {
                Log.Error("Issue with update token value for link" + ex.Message, true);
            }
            return url;
        }

        /// <summary>
        /// Checks if the field should not be handled by the processor.
        /// </summary>
        /// <param name="args">The arguments.</param>
        /// <returns>true if the field should not be handled by the processor; otherwise false</returns>
        protected virtual bool SkipProcessor(RenderFieldArgs args)
        {
            if (args == null)
            {
                return true;
            }

            string fieldTypeKey = args.FieldTypeKey;
            if (fieldTypeKey != "link")
            {
                return fieldTypeKey != "general link";
            }

            return false;
        }

    }

After that I added config for this to execute this code to just after the RenderField processor.


<?xml version="1.0"?>

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:env="http://www.sitecore.net/xmlconfig/env/">
  <sitecore>
    <pipelines>
      <renderField>
        <processor type="Xcentium.Foundation.SitecoreExtensions.Pipelines.RenderField.GetLinkFieldValueExtend, Xcentium.Foundation.SitecoreExtensions" patch:after="processor[@type='Sitecore.Buckets.Pipelines.RenderField.GetLinkFieldValue, Sitecore.Buckets']">
        </processor>
      </renderField>
    </pipelines>
  </sitecore>
</configuration>

 

This is not for only link field you can use it with any field in Sitecore and make it more specific if you need.

 

Hope it can save some of your time 🙂

 

Posted in Sitecore, Uncategorized | Tagged | Leave a comment

Edit Frame Implementation for Sitecore Experience Editor

As I mentioned in my last post in this post we will learn how we can make field editable which are not editable from Experience Editor for example treelist, multilist, checkbox etc.

Sometime we make everything as per the recommended way in experience editor but some of the fields which we can’t edit directly from Experience editor as there is no specific view for them so Sitecore provided a nice way to handle this.

To handle these types of requirements we need to create EditFrames.  EditFrames in the Experience Editor is a feature that you can use to give users front-end access to fields that are not directly accessible, either because they are not visible or they are of a type that are not directly front-end editable.

To start with it first identify the field on components which you want to make editable and follow the below steps  –

  1. Go to Core Database and navigate to /sitecore/content/Applications/WebEdit/Edit Frame Buttons location.
  2. Create a Folder with /sitecore/templates/System/WebEdit/Edit Frame Button Folder  folder data template. (On the above given location this folder is already part of insert option)
  3. Add item with Field Editor Button data template from /sitecore/templates/System/WebEdit/Field Editor Button template location. (This is also part of insert option so you will get suggestion while adding the item.)
  4. This item has 4 fields as below –
    1. Header – It is just for to show the name
    2. Icon – If you want to add any icon to show on Experience Editor you can add here.
    3. Fields  – Pipe-separated list of field names to be edited by the Field Editor.
    4. Tooltip – If you want to add any.
  5. After making the updates in Core Db we need to make some updates in our code file (.cshtml) also as below –

We need to Surround the section to show the button with a using block as follows:

@using (Html.BeginEditFrame(Model.Item.ID.Guid.ToString(), “Xcentium/Link CTA”)) { // HTML here }
Now once you are running this into Experience Editor it will show you a toolbar appearing on Editor as below –
ee_1

Clicking on the icon will open a modal window with all the fields which we defined in Fields field in step 3rd as below –

ee_2
So the use of this functionality is content editor don’t need to go to Content Editor area or Item directly to update the field which is not editable from Experience editor but they can edit field from Experience editor it self and it makes them easy to understand that these fields are also in use for the component.

 

I found it useful when your content editor’s are not much trained in Sitecore Content Editor area but more familiar with Experience editor.

 

Stay tuned for new post ……

 

Posted in Sitecore, Sitecore Experience Editor, Uncategorized | Tagged | Leave a comment

Best practices to implement Editable components in Experience Editor

In this post I am going to share some useful tips while creating static components in Sitecore what are the recommended configurations we need to do to make a component completely editable from Experience Editor.

This topic may be old but still I can see many of us doesn’t follow the ways to make a component editable from Experience Editor  and sometime after implementation we need to do many things which we haven’t think.

We all are already familiar with creating data templates and renderings (Controller and View Renderings). In this post will only learn some of the points which we need to follow while building a component in Sitecore which is Editable from Experience Editor.

Follow the below steps to make your components better –

Go to Rendering Item and –

 

  1. Update the Datasource Location field with the location where you want to create the datasource item.
  2. Update Datasource Template field with the Datasource template item so that when you are adding the Rendering on item either from Content Editor or Experience Editor it will automatically create item by added Datasource Template.
  3. Update Experience Editor Buttons if you need to insert the items or want more functionality from Experience Editor.
  4. Add the Thumbnail image in Appearance section field called Thumbnail. It will help you to get the understanding of component that what type of component it is by seeing the Image.

These are the few basic steps we can follow to make our component more easy for content editors.

These small steps you can simply follow in Sitecore but also we need to be more careful while adding code in .cshtml file.

We need to use the Code which make field Editable not just render the value. As in current version of Sitecore we are using

@Html.Sitecore().Field(Xcentium.Foundation.Items.Templates.Title.Fields.Title, item)

This will help to make content editable in Experience Editor also this is only for Text fields there are more HTML Helper extension for Link, Image and Date fields are available out of the box.

We also need to create Placeholder Settings under /sitecore/layout/Placeholder Settings location for our placeholders which we have added on layout as well as on container components.

To get more details about Power of Placeholder Settings read this post.

So after creating the placeholder setting update the Placeholder Key field by the key you added in .cshtml file for placeholder. This field value should exactly same what you have defined in your layout or container cshtml file.

Few points for placeholder settings –

  1. Editable checkbox should checked.
  2. Set the rendering which you want to add on this placeholder in Allowed Controls field. Advantage of this field is when you click on add button of placeholder it will show a list of components which we can add to this placeholder with the thumbnail image if  we have added the thumbnail image on rendering as I discussed in step 4 above.

It will restrict content editor to choose the component which actually we want to add on the specific placeholder.

These are the small set of steps we can follow and make our component more easy to add/update.

In my next post will share some examples of add Edit Frames to edit fields which we can’t directly edit from Experience Editor for example Multilist, Treelist, Checkbox etc. from Experience Editor.

 

Please share if I am missing anything or you have something to add here in comments below I’ll add your points to this post and we can make it more better for developers.

Happy Editing 🙂

 

Posted in Sitecore, Sitecore Experience Editor, Uncategorized | Tagged | 1 Comment

Field specific Computed Index in Coveo/Solr In Sitecore

As per my last post which was for Out of the box computed index in Reference fields now in this post I’ll share what I have recently implemented and can save your development time if you are using Coveo For Sitecore in your project.

If you have multi-select fields and you want to use them in facets.

Here are few scenarios where you can use this post and it can make your solution more easy and clean.

  1. If you have multi select field and value item of your multi list field is also having any reference/multi-select field and here you need to index specific field of that field then you can use this post.
  2. Any specific case of multi select field
  3. Making field level computed indexed for example checkbox, sing line text etc.

So let me now start with what I have implemented with covering all the scenarios.

Advantage of this post to make it easier on the level where you don’t need to make classes for every facet or field index.

First of all I created a configuration helper class file to handle to custom configurations  –

       public static class CoveoSearchCustomizationHelper
    {
        public static string GetConfigurationValue(string configurationKey, XmlNode configuration)
        {
            string configurationValue = null;

            if (configuration != null && configuration.Attributes != null)
            {
                XmlAttribute configurationAttribute = configuration.Attributes[configurationKey];
                if (configurationAttribute != null)
                {
                    configurationValue = configurationAttribute.Value;
                }
            }

            return configurationValue;
        }
    }
    

 

This configuration file to execute the configuration setting which we are going to define for computed index.

After that I created a class file for computed index for multilist field as below –

 

  public class MultiselectField : IComputedIndexField
    {
        private readonly XmlNode configuration;

        public MultiselectField(XmlNode configuration)
        {
            this.configuration = configuration;
        }

        public string FieldName { get; set; }

        public string ReturnType { get; set; }

        public object ComputeFieldValue(IIndexable indexable)
        {
            try
            {
                var sourceField = CoveoSearchCustomizationHelper.GetConfigurationValue("sourceField", this.configuration);
                var referenceField = CoveoSearchCustomizationHelper.GetConfigurationValue("referenceField", this.configuration);
                var indexableItem = indexable as SitecoreIndexableItem;
                if (indexableItem == null)
                {
                    return null;
                }

                var item = (Item)indexableItem;
                var fieldValue = string.Empty;

                if (item != null)
                {
                    fieldValue = this.GetItemValue(item, sourceField, referenceField);
                    return fieldValue;
                }
            }
            catch (Exception ex)
            {
                LogManager.Error("Error: Multiselect computed field" + ex.Message.ToString(), this);
            }

            return null;
        }

        public string GetItemValue(Item indexableSourceItem, string sourceField, string referenceField)
        {
            if (indexableSourceItem != null)
            {
                if (indexableSourceItem.Fields[sourceField] != null && !string.IsNullOrEmpty(indexableSourceItem[sourceField]))
                {
                    string[] referencedItemGuids = indexableSourceItem.Fields[sourceField].Value.Split('|');
                    List referencedFieldValues = new List();
                    foreach (string referencedItemGuid in referencedItemGuids)
                    {
                        Item item = indexableSourceItem.Database.GetItem(referencedItemGuid);
                        if (item != null)
                        {
                            referencedFieldValues.Add(item[referenceField]);
                        }
                    }

                    return string.Join(";", referencedFieldValues.ToArray());
                }
            }

            return null;
        }
    

 

And final step to set the configurations for multi-select fields. Now with these configurations we can define any number of multi-select fields. We don’t need to create class file for each mutli-list field.

Now we just need to define the settings which we are doing for computed index as below –

<field fieldName="fieldname1" sourceField="Multilist field name" referenceField="Reference Field Name">Xcentium.Feature.CoveoSearch.Infrastructure.Fields.MultiselectField, Xcentium.Feature.CoveoSearch</field>
<field fieldName="fieldname2" sourceField="Multilist field name" referenceField="Reference Field Name">Xcentium.Feature.CoveoSearch.Infrastructure.Fields.MultiselectField, Xcentium.Feature.CoveoSearch</field>
<field fieldName="fieldname3" sourceField="Multilist field name" referenceField="Reference Field Name">Xcentium.Feature.CoveoSearch.Infrastructure.Fields.MultiselectField, Xcentium.Feature.CoveoSearch</field>
 

 

It saved lots of efforts and also redundancy of code and code files.

There may be some other methods which can save line of codes also better then this. But I found this useful so wrote my findings here.

If you have anything which can improve this more feel free to share in comments below.

 

Stay tuned for my next post where I can going to share about more field types…..

Posted in Coveo, Coveo For Sitecore, Sitecore, Sitecore Multilist, Sitecore Solr, Solr, Uncategorized | Tagged , , , | 2 Comments