Index a custom product attribute with Solr in Hybris

Hybris featured image

1. Overview

In Hybris, product list page, search page, product sorting and faceting are powered by Apache Solr.

In this article, I will show you how to index a custom product attribute with Solr and display it on the product list page.

We will index the unit attribute (no need to create a custom attribute) and display it on the PLP.

2.Implementation

1. First of all, create a custom FieldValueProvider, to convert Unit to a sample/indexable value.

package com.stackextend.training.core.search.solrfacetsearch.provider.impl;

// imports...

public class ProductUnitValueProvider implements FieldValueProvider, Serializable {

    private FieldNameProvider fieldNameProvider;
    private CommonI18NService commonI18NService;

    @Override
    public Collection<FieldValue> getFieldValues(final IndexConfig indexConfig, final IndexedProperty indexedProperty, final Object model) throws FieldValueProviderException
    {
        if (model instanceof ProductModel)
        {
            final ProductModel product = (ProductModel) model;
            final Collection<FieldValue> fieldValues = new ArrayList<FieldValue>();

            // case of the indexed property is localized
            if (indexedProperty.isLocalized())
            {
                // retrieve and iterate over all the configured languages
                final Collection<LanguageModel> languages = indexConfig.getLanguages();
                for (final LanguageModel language : languages)
                {
                    fieldValues.addAll(createFieldValue(product, language, indexedProperty));
                }
            }
            // case of the indexed property is not localized
            else
            {
                fieldValues.addAll(createFieldValue(product, null, indexedProperty));
            }
            return fieldValues;
        }

        throw new FieldValueProviderException("Error: item is not a Product type !");
    }

    protected List<FieldValue> createFieldValue(final ProductModel product, final LanguageModel language, final IndexedProperty indexedProperty)
    {
        final List<FieldValue> fieldValues = new ArrayList<FieldValue>();
        // get Unit name by language
        final String unitName = getUnitName(product, language);
        if (unitName != null)
        {
            // add Unit name value to the fieldValues list
            addFieldValues(fieldValues, indexedProperty, language, unitName);
        }
        return fieldValues;
    }

    protected void addFieldValues(final List<FieldValue> fieldValues, final IndexedProperty indexedProperty, final LanguageModel language, final Object value)
    {
        // generate all Solr fields based on different qualifiers
        final Collection<String> fieldNames = fieldNameProvider.getFieldNames(indexedProperty, language == null ? null : language.getIsocode());
        for (final String fieldName : fieldNames)
        {
            fieldValues.add(new FieldValue(fieldName, value));
        }
    }

    private String getUnitName(ProductModel product, LanguageModel language) {
        return product.getUnit().getName(commonI18NService.getLocaleForLanguage(language));
    }

    @Required
    public void setFieldNameProvider(final FieldNameProvider fieldNameProvider)
    {
        this.fieldNameProvider = fieldNameProvider;
    }

    @Required
    public void setCommonI18NService(final CommonI18NService commonI18NService)
    {
        this.commonI18NService = commonI18NService;
    }
}

Note that no special value provider is needed if you want just to index a basic attribute (boolean, int, String…), check this article.

2. Register the ProductUnitValueProvider as a Spring bean.

<!-- ...\trainingecore\resources\trainingecore-spring.xml -->

<bean id="productUnitValueProvider" 
	class="com.stackextend.training.core.search.solrfacetsearch.provider.impl.ProductUnitValueProvider" >
	<property name="fieldNameProvider" ref="solrFieldNameProvider"/>
	<property name="commonI18NService" ref="commonI18NService"/>
</bean>

3. Create a SolrIndexedProperty instance called unit and attach productUnitValueProvider bean to it, using an impex.

# .../traininginitialdata/import/coredata/stores/hybris/solr.impex

$solrIndexedType=...

INSERT_UPDATE SolrIndexedProperty	;solrIndexedType(identifier)[unique=true]	;name[unique=true]	;type(code)	;localized[default=false]	;fieldValueProvider		
									;$solrIndexedType							;unit              	;string		;true						;productUnitValueProvider

4. Add unit attribute to ProductData and run ant all to generate it.

<!-- ...\trainingfacades\resources\trainingfacades-beans.xml -->

<bean class="de.hybris.platform.commercefacades.product.data.ProductData">
	<property name="unit" type="String"/>
</bean>

5. Override SearchResultVariantProductPopulator, to populate unit values retrieved by Solr search.

package com.stackextend.training.facades.populators.CustomSearchResultVariantProductPopulator;

// imports...

public class CustomSearchResultVariantProductPopulator extends SearchResultVariantProductPopulator {

    @Override
    public void populate(SearchResultValueData source, ProductData target) {
	
        super.populate(source, target);

        // populate unit property values
        target.setUnit(this.<String> getValue(source, "unit"));
    }
}

6. Register the CustomSearchResultVariantProductPopulator as a Spring bean, with commerceSearchResultProductPopulator as an alias.

<!-- ...\trainingfacades\resources\trainingfacades-spring.xml -->

<alias name="customSearchResultProductPopulator" alias="commerceSearchResultProductPopulator"/>
<bean id="customSearchResultProductPopulator"
	  class="com.stackextend.training.facades.populators.CustomSearchResultVariantProductPopulator"
	  parent="variantCommerceSearchResultProductPopulator">
</bean>

7. Display the unit value where ever you want inside productListerItem.tag.

<!-- ...\trainingstorefront\web\webroot\WEB-INF\tags\desktop\product\productListerItem.tag -->

...

${product.unit}

...

8. Finally, run a full indexation to force Solr to index the unit attribute of all existing products.
Navigate to HMC -> System -> Facet Search -> Indexer operation wizard.
HMC run Solr full indexation in Hybris

9. Navigate to the PLP, if everything goes well, you will be able to see units.

Indexed property on PLP in Hybris

 

14
Leave a Reply

avatar
5 Comment threads
9 Thread replies
6 Followers
 
Most reacted comment
Hottest comment thread
7 Comment authors
selvaSrinuvinayMd Hamid ZiaYashwanth Recent comment authors

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
newest oldest most voted
Notify of
Nick
Guest
Nick

Hey Mouad,

Great tutorials! Your website is extremely useful.
Looking forward to your further Hybris tutorials.
Personally, I would be interested in the next topics: adding facets to the plp, backoffice customization, promotions, pricing, product boosts in the search.

Just a couple of ideas if you want 🙂

Thank you a lot!

Yashwanth
Guest
Yashwanth

Hi

How does the solr indexes the different language for the attribute as you have provided “localized=true”. Where does it taking the language isocode from – Hybris or the solr.

Regards,
Yashwanth

vinay
Guest
vinay

piece

Srinu
Guest
Srinu

Hi Mouad EL Fakir; This tutorial is excellent and help me lot .thanks for providing this.but i have small issue. I am getting solr value in valueprovider class and in populator class but iam not getting this solr custom value in search result page.Can you help me on this issue.

selva
Guest
selva

While indexing time I’m getting ERROR could you please help me on here.
“Failed to resolve values for item with PK: 8796096954369, by resolver: wisProductVarientValueProvider, for property: unit, reason: Index: 0, Size: 0