Index a custom product attribute with Solr in Hybris

Hybris Logo

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

 

5 3 votes
Article Rating
Subscribe
Notify of
guest

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

24 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Nick
Nick
5 years ago

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
Yashwanth
5 years ago

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

Yashwanth
Yashwanth
Reply to  Mouad EL Fakir
5 years ago

Hi

Thank you for the quick reply. If I need to add new language, how can I configure this from the solr perspective?

Md Hamid Zia
Md Hamid Zia
Reply to  Mouad EL Fakir
5 years ago

Hi Mouad
I am trying to add new Facets. Ranges are coming in solr but not able to see facets on storefront. Could you please let me know on this

Ansar
Ansar
Reply to  Md Hamid Zia
2 years ago

im facing the same please help me to do

vinay
vinay
5 years ago

piece

Srinu
Srinu
5 years ago

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.

Srinu
Srinu
Reply to  Mouad EL Fakir
5 years ago

Then also iam not geeting in productListerItem.tag page

sachin
sachin
Reply to  Srinu
7 months ago

same

Srinu
Srinu
Reply to  Mouad EL Fakir
5 years ago

yes i added in productListerItem.tag

selva
selva
5 years ago

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

Madhuri
Madhuri
Reply to  selva
11 months ago

Have you found solution for this?

jonaja
jonaja
3 years ago

Do we need the Run Full Index whenever the custom attribute value changes

Ansar
Ansar
Reply to  Mouad EL Fakir
2 years ago

which controller used for productLIterItem.tag

mani
mani
3 years ago

hey, i am indexing a custom table with a collection attribute in it, can u please tell me how to index it in solr indexed property and how to get those custom item type data from solr using controller. i don’t know how to get data from solr for a custom items.

Mike Ross
Mike Ross
2 years ago

How to implement a resolver for the same use case? How a resolver uses context to resolve the localized attributes? What will be the difference in solr document?

Anjan
Anjan
2 years ago

Hi, what if I want to index an attribute other than primitive type like Enum etc.
Could you please tell me how to do it.
If already explained could you send me that link.
Thanks in advance.

24
0
Would love your thoughts, please comment.x
()
x