Switch solr client on POST requests

From time to time I have been receiving from customer support service messages that filter functionality on PLP returns no results. Finally, after 1 year of such messages our QA team was able to reproduce the issue. The root of the issue is too many filters, which causes creation of very long requests, which can’t be processed by solr server. Solr server is shipped with Jetty, which has 8KB limit to URL length. You can change this limit by adding <Set name="requestHeaderSize"> 200000 </Set> to server/contexts/solr-jetty-context.xml.

After discussions with DevOps Lead and Tech Lead we decided that in our case will be better to force hybris solr client to use POST requests instead of GET and don’t change solr server OOTB settings (by default Jetty has limitation to 200KB for POST body). Unfortunately hybris doesn’t provide any configuration for such switching, and it must be done manually by overriding DefaultFacetSearchStrategy.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.blog.core.search.solrfacetsearch;

import de.hybris.platform.solrfacetsearch.config.FacetSearchConfig;
import de.hybris.platform.solrfacetsearch.config.IndexedType;
import de.hybris.platform.solrfacetsearch.model.SolrIndexModel;
import de.hybris.platform.solrfacetsearch.search.FacetSearchException;
import de.hybris.platform.solrfacetsearch.search.SearchQuery;
import de.hybris.platform.solrfacetsearch.search.SearchResult;
import de.hybris.platform.solrfacetsearch.search.context.FacetSearchContext;
import de.hybris.platform.solrfacetsearch.search.impl.DefaultFacetSearchStrategy;
import de.hybris.platform.solrfacetsearch.search.impl.SearchQueryConverterData;
import de.hybris.platform.solrfacetsearch.search.impl.SearchResultConverterData;
import de.hybris.platform.solrfacetsearch.solr.Index;
import de.hybris.platform.solrfacetsearch.solr.SolrSearchProvider;
import de.hybris.platform.solrfacetsearch.solr.exceptions.SolrServiceException;
import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.util.IOUtils;

import java.io.IOException;
import java.util.Map;

public class CustomFacetSearchStrategy extends DefaultFacetSearchStrategy {

    private static final Logger LOG = Logger.getLogger(CustomFacetSearchStrategy.class);

    @Override
    public SearchResult search(SearchQuery searchQuery, Map<String, String> searchHints) throws FacetSearchException {
        this.checkQuery(searchQuery);
        SolrClient solrClient = null;

        SearchResult result;
        try {
            FacetSearchConfig e = searchQuery.getFacetSearchConfig();
            IndexedType indexedType = searchQuery.getIndexedType();
            FacetSearchContext facetSearchContext = super.getFacetSearchContextFactory().createContext(e, indexedType, searchQuery);
            facetSearchContext.getSearchHints().putAll(searchHints);
            super.getFacetSearchContextFactory().initializeContext();
            SolrSearchProvider solrSearchProvider = super.getSolrSearchProviderFactory().getSearchProvider(e, indexedType);
            SolrIndexModel activeIndex = super.getSolrIndexService().getActiveIndex(e.getName(), indexedType.getIdentifier());
            Index index = solrSearchProvider.resolveIndex(e, indexedType, activeIndex.getQualifier());
            solrClient = solrSearchProvider.getClient(index);
            SearchQueryConverterData searchQueryConverterData = new SearchQueryConverterData();
            searchQueryConverterData.setFacetSearchContext(facetSearchContext);
            searchQueryConverterData.setSearchQuery(searchQuery);
            SolrQuery solrQuery = super.getFacetSearchQueryConverter().convert(searchQueryConverterData);
            if (LOG.isDebugEnabled()) {
                LOG.debug(solrQuery);
            }

            // Change solr client to do post request
            QueryResponse queryResponse = solrClient.query(index.getName(), solrQuery, SolrRequest.METHOD.POST);

            SearchResultConverterData searchResultConverterData = new SearchResultConverterData();
            searchResultConverterData.setFacetSearchContext(facetSearchContext);
            searchResultConverterData.setQueryResponse(queryResponse);
            SearchResult searchResult = super.getFacetSearchResultConverter().convert(searchResultConverterData);
            super.getFacetSearchContextFactory().getContext().setSearchResult(searchResult);
            super.getFacetSearchContextFactory().destroyContext();
            result = searchResult;
        } catch (SolrServerException | IOException | RuntimeException | SolrServiceException var19) {
            super.getFacetSearchContextFactory().destroyContext(var19);
            throw new FacetSearchException(var19.getMessage(), var19);
        } finally {
            IOUtils.closeQuietly(solrClient);
        }

        return result;

    }
}

UPD 2018-09-16

Hybris 6.6+ versions has possibility to define which method to use for requests. SolrServerConfigModel was extended with SolrQueryMethod, where you can define POST or GET. Default value is GET.

comments powered by Disqus