Понадобилось как-то в SAP Hybris настроить поиск по составному полю (состоящему из нескольких атрибутов продукта). Так, чтобы при запросе вида «желтый ботинок» в листинге товаров сначала выдавались не просто товары желтого цвета, а именно желтые ботинки (а затем — остальные ботинки). Решить это регулировкой коэффициентов усиления поиска по отдельным свойствам (boost) не удалось, пришлось городить огород с созданием и индексацией составного поля.
Модель товара ProductModel
Итак, в предлагаемом примере товар (Product) имеет два атрибута (помимо прочих), по которым надо искать в связке:
- Name — название товара
- Color — его цвет
Создание Value Resolver
В простом случае (а рассматривается именно такой), resolver может выглядеть следующим образом:
public class ProductNameColorValueResolver extends AbstractApparelStyleValueResolver<ProductModel, Object> {
@Override
protected void addFieldValues(InputDocument inputDocument, IndexerBatchContext indexerBatchContext,
IndexedProperty indexedProperty, ProductModel model,
ValueResolverContext<Object, Object>valueResolverContext)throws FieldValueProviderException
{
if (model != null && model.getName() != null && model.getColor() != null) {
List<String> fieldNames = List.of(model.getName(), model.getColor().getName());
for (String name : fieldNames) {
inputDocument.addField(indexedProperty, name, valueResolverContext.getFieldQualifier());
}
}
}
}
Что здесь нужно помнить: структура продуктов может содержать несколько уровней. Например, отдельно — Товар (родитель) и отдельно — Товар с Цветом (потомок). В этом случае в resolver попадает сущность «нижнего» уровня, которая может не содержать всех требуемых атрибутов. То есть, возможна ситуация, когда атрибут Color нужно получить непосредственно из сущности, пришедшей в resolver, а атрибут Name — из её родителя.
Добавление Value Resolver в контекст приложения
Чтобы resolver работал — нужно не забыть добавить его в контекст приложения. Обычным для Spring с XML-конфигурацией образом — определить бин в spring.xml
Добавление индексируемого свойства в Solr
Наконец, необходимо добавить новое составное поле в индексируемые свойства товара, с которыми работает поиск Solr. Это можно сделать вручную при помощи BackOffice, но проще и удобней — составить impex и затем импортировать его из Hybris Administration Console (HAC).
$solrIndexedType = myProductType
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;valueProviderParameters[map-delimiter=|];ftsPhraseQuery[default=false];ftsPhraseQueryBoost;ftsQuery[default=false];ftsQueryBoost;ftsFuzzyQuery[default=false];ftsFuzzyQueryBoost;ftsWildcardQuery[default=false];ftsWildcardQueryType(code)[default=POSTFIX];ftsWildcardQueryBoost;ftsWildcardQueryMinTermLength;
;$solrIndexedType; productNameColorMultiField; text;;; true; true; true; true; productNameColorValueResolver;; true; 40;; ; true; 20;;;;
Из интересного здесь — указание ранее описанного бина productNameColorValueResolver в качестве fieldValueProvider и создание начальных коэффициентов усиления (boost) для разных типов поиска — ftsPhraseQueryBoost (40), ftsFuzzyQueryBoost (20). Можно задать boost и для остальных видов поиска. Впрочем, в дальнейшем эти коэффициенты (как и остальные атрибуты индексируемого свойства) не сложно поменять в BackOffice.
Индексируемое свойство Solr — итоги
Таким способом можно добавить в индекс Solr произвольное поле, по которому будет производиться поиск, отсутствующее в модели товара — без изменения самой модели. И задать этому полю коэффициенты усиления для ранжирования результатов выполнения поискового запроса. Пример не самый сложный, но общий принцип иллюстрирует. На этом всё 🙂