Value providers in SAP Commerce(Hybris) Solr

There are two ways for indexing Item Types in Solr. The first way is when data requires no change or transformation. The data can be taken as it is from the database. The second way is when data does require a change and for this SAP Hybris allows us to write some custom logic on that data and send it to Solr for indexing.

The steps for creating Value provider are:

(The example is for new attribute- customName in ProductModel which will index customName if in the database we have value for this attribute else it will index “TEST”):

  1. Create a class by extending the AbstractFieldValueProvider class or implementing FieldValueProvider interface. FieldValueProvider interface exposes a method called getFieldValues with appropriate parameters to facilitate this change. We must implement this interface and override the getFieldValues() method as per our needs.

Let’s first create the attribute in the Product model in items.xml

<itemtype code="Product" autocreate="false" generate="false">
<description>Extending Product type with additional attributes.</description>
<attribute qualifier="customName" type="localized:java.lang.String">
<description>Localized Custom product Name</description>
<modifiers read="true" write="true" search="true" optional="true"/>
<persistence type="property"/>
<custom-properties>
<property name="hmcIndexField"><value>"thefield"</value></property>
</custom-properties>
</attribute>
</attributes>
</itemtype>

Now we can create ValueProvider:

package com.custom.core.search.solrfacetsearch.provider.impl;import de.hybris.platform.core.model.c2l.LanguageModel;
import de.hybris.platform.core.model.product.ProductModel;
import de.hybris.platform.servicelayer.i18n.CommonI18NService;
import de.hybris.platform.servicelayer.i18n.I18NService;
import de.hybris.platform.solrfacetsearch.config.IndexConfig;
import de.hybris.platform.solrfacetsearch.config.IndexedProperty;
import de.hybris.platform.solrfacetsearch.config.exceptions.FieldValueProviderException;
import de.hybris.platform.solrfacetsearch.provider.FieldNameProvider;
import de.hybris.platform.solrfacetsearch.provider.FieldValue;
import de.hybris.platform.solrfacetsearch.provider.FieldValueProvider;
import org.springframework.beans.factory.annotation.Required;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Created by EXQ02122 on 3/10/2017.
*/
public class ProductNameValueProvider implements FieldValueProvider {
private I18NService i18nService;
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 names by language
i18nService.setLocalizationFallbackEnabled(false);
final String customName = getCustomName(product, language);
i18nService.setLocalizationFallbackEnabled(true);
addFieldValues(fieldValues, indexedProperty, language, customName != null && !customName.equals("") ? customName : "TEST");
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 getHybrisName(ProductModel product, LanguageModel language) {
return product.getHybrisName(commonI18NService.getLocaleForLanguage(language));
}
@Required
public void setFieldNameProvider(final FieldNameProvider fieldNameProvider)
{
this.fieldNameProvider = fieldNameProvider;
}
@Required
public void setCommonI18NService(final CommonI18NService commonI18NService)
{
this.commonI18NService = commonI18NService;
}
@Required
public void setI18nService(final I18NService i18nService)
{
this.i18nService = i18nService;
}
}

Note: i18nService.setLocalizationFallbackEnabled(true) is for enable/disable the localization fallback feature.

3. Define the spring bean of the ValueProvider in the spring.xml file:

<bean id="productNameValueProvider"
class="com.custom.core.search.solrfacetsearch.provider.impl.ProductNameValueProvider" >
<property name="fieldNameProvider" ref="solrFieldNameProvider"/>
<property name="commonI18NService" ref="commonI18NService"/>
<property name="i18nService" ref="i18nService" />
</bean>

4. Specify the indexing attribute in Solr.index:

INSERT_UPDATE SolrIndexedProperty;solrIndexedType(identifier)[unique = true];name[unique = true];type(code);sortableType(code);currency[default = false];localized[default = false];multiValue[default = false];useForSpellchecking[default = false];useForAutocomplete[default = false];fieldValueProvider;valueProviderParameter;
;$solrIndexedType;customName ;text ;sortabletext;;true;;true;true;productNameValueProvider;5. To use the attribute on the storefront we create the attribute in ProductData:
<bean class="de.hybris.platform.commercefacades.product.data.ProductData">
<property name="customName" type="String"/>
</bean>

6. Override CustomProductPopulator , to populate unit values retrieved by Solr search.

public class CustomProductPopulator extends ProductPopulator{private I18NService i18nService;@Override
public void populate(final ProductModel source, final ProductData target) {
super.populate(source, target);
i18nService.setLocalizationFallbackEnabled(false);
if(source.getCustomName() != null && !source.getCustomName().equals("")){
target.setCustomName(source.getCustomName());
}
i18nService.setLocalizationFallbackEnabled(true);
}
@Required
public void setI18nService(final I18NService i18nService)
{
this.i18nService = i18nService;
}
}

7. Register newly created populator as a spring bean and link it to the existing populator using alias.

<alias name="customProductPopulator " alias="productPopulator" />
<bean id="customProductPopulator " parent="defaultProducPopulator"
class="com.custom.facades.populators.CustomProductPopulator ">
<property name="i18nService" ref="i18nService" />
</bean>

When To Use a Hybris Value Provider?

Value Providers should only be leveraged when data from the database must be, without exception or work around, altered before entering them in Apache Solr.

Make sure you give this post a clap and follow my blog if you find it helpful.

--

--

--

Software Development Lead @Coca-Cola HBC

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Design Patterns With TypeScript Examples: Singleton

TreeMapping in Java !

Non-blocking 2pc

My first hackathon (as a dev)

Blow up your cloud using cloud-nuke

Progress Euler

Per-Table Autovacuum Tuning

Sending Multipart / Form Data with InvokeHTTP in Apache NiFi 1.12-SNAPSHOT

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Nuray Fahri

Nuray Fahri

Software Development Lead @Coca-Cola HBC

More from Medium

Head First Java (Chapter 03) Know Your Variables

Headfirst Java Chapter 02 summary -A Trip to Objectville

How to profile java application with IntelliJ

Let’s talk about head first Java