Skip to main content

Keynotes for Solr Index in Sitecore 9

I've recently implemented a product list page and -as you can guess- I've needed to configure a custom index for my products. I will share some keynotes about that, I believe they might be useful for anyone who needs a similar thing.

How to configure a custom index in Solr?
Luckily, we already have a good article which shows how to create custom Solr indexes in Sitecore 9. I followed the steps and created my product indexes (my Sitecore version is 9.0.1).

I added necessary fields and templates to my config file:

                <!-- Included fields -->
                <include hint="list:AddIncludedField">
                  <Name>{A00DA813-46FF-47E4-ADD7-75C1333ACF32}</Name>
                  <CommercialShortText>{0AFE5D2A-8172-46BA-BD96-FD6838E3D65B}</CommercialShortText>
                  <TitleProductPage>{E7E6F859-F989-4BA3-8F31-7A03C9BD69E4}</TitleProductPage>
                  <ProductDescription>{14EC7D7E-D6ED-4F95-936B-6988F49A8D9B}</ProductDescription>
                </ProductClasses>
                </include>

                <!-- Included templates -->
                <include hint="list:AddIncludedTemplate">
                  <Product>{032168C8-4E59-485A-8FBC-0E587AB41EA6}</Product>
                </include>

However, it was not enough for my case, I needed to add product image field as well.

If you add an Image field to index like other text fields above, it only returns "alt" information of image. You don't get image url or any other details.

You can see why it returns alt info by checking default Solr config file:


ImageFieldRenderer is responsible class for image field type and it is implemented to return alt tag:


What should we do then?

Computed index field.

How to add a computed index field?

It should be added under "raw:AddComputedIndexField" key.

                <fields hint="raw:AddComputedIndexField">
                  <field fieldName="product_image_url" returnType="string">Namespace.ProductImageComputedIndexField, DLL</field>
                </fields>

And your class will look like this:

public class ProductImageComputedIndexField : AbstractComputedIndexField
    {
        public override object ComputeFieldValue(IIndexable indexable)
        {
            var item = (Item)(indexable as SitecoreIndexableItem);

            if (item == null)
                return null;

            if (!item.TemplateID.Equals(IProductConstants.TemplateId)) return null;

            var imageField = (ImageField)item.Fields[IProductConstants.Product_ImageFieldName];

            if (imageField?.MediaItem == null) return null;

            using (new SecurityDisabler())
            {
                using (new SiteContextSwitcher(Factory.GetSite("website")))
                {
                    var uri = MediaManager.GetMediaUrl(imageField.MediaItem, new MediaUrlOptions { UseItemPath = true });
                    return uri;
                }
            }
        }

You think you configured everything correctly but it still doesn't work somehow. Maybe you forgot something and then, you need to check your indexed results.

How to check your indexed items?
There are several options but I will show the basic one: Use Solr panel!

Open your solr; most probably, it works here.

Select your custom index from core selector dropdown, click query and then execute:


You can see the fields are in index and check the results are as expected or not. If not, you can reindex from Sitecore panel or check your code if something configured wrong.

How to create custom SearchResultItem?
After you add fields to config file, they will be added to index. But how will you get those in code?
To do that, you will need to create your own search result class and bind your fields like example below:

public class SearchProductResultItem : SearchResultItem
    {
        [DataMember]
        [IndexField("name")]
        public string ProductName { get; set; }

        [DataMember]
        [IndexField("product_description")]
        public string ProductDescription { get; set; }


        [DataMember]
        [IndexField("product_image_url")]
        public string ProductImageUrl { get; set; }

    }

Then, you can use in query:

using (var context = Index.CreateSearchContext())
{
                    var filter = context.GetQueryable<SearchProductResultItem>()
                        .Filter(x => x.TemplateId == IProductConstants.TemplateId &&
                                   x.Language == Context.Language.Name)
                        .OrderBy(x => x.Name)
                        .Skip(pageInfo.SkipIndex)
                        .Take(pageInfo.PageSize)
                        .ToList();

Hope, it helps!

Comments

Popular posts from this blog

Sitecore 9 - Custom Page Events & Filtering with XConnect

This is the first article of a series. I am going to start with creating a custom page event and will show how we can fetch event data using xconnect api. Let's start with reminding demo scenario: Imagine that you have a website displaying movies. Visitors are able to see movie details and take some actions like save movie or share it.  You want to follow the visitors' activities and you want to take some marketing actions based on those activities. For example, if a contact visits a movie more than X time or she/he saves a movie, you want to send those movies to an external system. In addition, there is going to be a limit to send same movie. Such as, it will not be possible to send same movie more than 2 times.  You want to configure this as a marketing automation plan to give flexibility to your marketing managers. They should be able to add configurable rules and activities.  My first focus is movie detail page. I want to track visitors when they visit the

A React Example in Sitecore

That's true, Sitecore components are useful and provide lots of facilities. They allow to build fully flexible website. And there is not much problem using post-backs to display your contents. However, if your website has user interactions, then it could be a headache. Too many post-backs would occur a poor user experience. That's why client-side technologies are really powerful and popular for a long time. There are plenty of javascript libraries and frameworks which all try to provide better user experience in different ways. It is not a topic of this article why I chose React. There are some good articles about it (e.g. Jonne Kats' great article ). However, one of the reasons is React only focus on view part. It is not a fully framework like Angular, it is rich featured library instead. And that's what I was looking for! The idea was to benefit Sitecore server-side and React client-side power. It seems they are very good match! Let's dive into code... I&#

Sitecore 9 - Creating Custom Segmentation Rule

Predicates are important to create rules for marketing automation and segmented lists. Before going through the details, I am going to remind what I am implementing again. Imagine that you have a website displaying movies. Visitors are able to see movie details and take some actions like save movie or share it.  You want to follow the visitors' activities and you want to take some marketing actions based on those activities. For example, if a contact visits a movie more than X time or she/he saves a movie, you want to send those movies to an external system. In addition, there is going to be a limit to send same movie. Such as, it will not be possible to send same movie more than 2 times.  According to my scenario, I need a rule to filter contacts who visits a movie more than X time. Maybe, we can add one more condition there like in Y days. To creating rule will give flexibility to marketing managers that then they can easily add or remove multiple rules and proceed the