A note from 2026: This article was published in 2016. SAP Commerce Cloud no longer uses the “hybris” branding, and both SAP Commerce search integration and Apache Solr have changed substantially since Solr 6; use the Solr version supported by your current SAP Commerce Cloud release rather than these compatibility steps.

Situation

As of today, SAP hybris officially supports Apache SOLR 5.3. This version of the search engine was released in August 2015.

SOLR 6 was released in April 2016. It has a number of new features, including the following (in order of importance for hybris projects):

[!] It is absolutely clear that SOLR 6 is not yet ready to be used with hybris 6 in a production environment, because SOLR 6 has not yet been tested and approved by SAP. However, there are situations where SOLR 6 is a good choice.

Complexity

It is not enough to replace SOLR 5.3 with SOLR 6.0 to make hybris work with the new version. Indexing and search will not work; there will be too many exceptions.

Challenge

To make hybris 6 and SOLR 6 work together, mainly for educational purposes.

Solution

Technical details

Configuration

The SOLR 5.3 configuration can generally be used in SOLR 6.0.

hybris\config\solr\instances\default\configsets\default\conf ->
      solr-6.0.1\server\solr\configsets\default\conf

The following changes should be made:

MultiMaxScoreQParser

package de.hybris.platform.solr.search;

import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.DisjunctionMaxQuery;
import org.apache.lucene.search.Query;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.search.LuceneQParser;
import org.apache.solr.search.SyntaxError;

import java.util.ArrayList;

public class MultiMaxScoreQParser extends LuceneQParser
{
    float tie = 0.0f;

    public MultiMaxScoreQParser(final String qstr, final SolrParams localParams, final SolrParams params,
                                final SolrQueryRequest req)
    {
        super(qstr, localParams, params, req);

        if (getParam("tie") != null)
        {
            tie = Float.parseFloat(getParam("tie"));
        }
    }

    @Override
    public Query parse() throws SyntaxError
    {
        final Query q = super.parse();

        if (!(q instanceof BooleanQuery))
        {
            return q;
        }

        final BooleanQuery obq = (BooleanQuery) q;
        final BooleanQuery.Builder newq = new BooleanQuery.Builder();

        DisjunctionMaxQuery dmq = null;

        for (final BooleanClause clause : obq.clauses())
        {
            if (clause.isProhibited() || clause.isRequired())
            {
                newq.add(clause);
            }
            else
            {
                final Query subQuery = clause.getQuery();

                if (!(subQuery instanceof BooleanQuery))
                {
                    if (dmq == null)
                    {
                        dmq = new DisjunctionMaxQuery(new ArrayList<Query>(), tie);
                        newq.add(dmq, BooleanClause.Occur.SHOULD);
                    }

                    dmq.getDisjuncts().add(clause.getQuery());
                }
                else
                {
                    ArrayList<Query> queries = new ArrayList<Query>();

                    for (final BooleanClause subQueryClause : ((BooleanQuery) subQuery).clauses())
                    {
                        queries.add(subQueryClause.getQuery());
                    }

                    final DisjunctionMaxQuery subDmq = new DisjunctionMaxQuery(queries, tie);
                    newq.add(subDmq, BooleanClause.Occur.SHOULD);
                }
            }
        }

        BooleanQuery result = newq.build();

        // to do: populate boosting
        // result.setBoost(obq.getBoost());

        return result;
    }
}

Known issues and limitations

Any questions?

Contact me privately using the form below or leave your comment on this article:

© Rauf Aliev, June 2016