Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * #%L
   * BroadleafCommerce Framework
   * %%
   * Copyright (C) 2009 - 2013 Broadleaf Commerce
   * %%
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
  * 
  *       http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * #L%
  */
 package org.broadleafcommerce.core.search.service.solr;
 
 
 import java.io.File;
 import java.util.List;
 import java.util.Map;
 
An implementation of SearchService that uses Solr. Note that prior to 2.2.0, this class used to contain all of the logic for interaction with Solr. Since 2.2.0, this class has been refactored and parts of it have been split into the other classes you can find in this package.

Author(s):
Andre Azzolini (apazzolini)
 
 public class SolrSearchServiceImpl implements SearchServiceDisposableBean {
     private static final Log LOG = LogFactory.getLog(SolrSearchServiceImpl.class);
 
     @Resource(name = "blProductDao")
     protected ProductDao productDao;
 
     @Resource(name = "blFieldDao")
    protected FieldDao fieldDao;
    @Resource(name = "blSearchFacetDao")
    protected SearchFacetDao searchFacetDao;
    @Resource(name = "blSolrHelperService")
    protected SolrHelperService shs;
    @Resource(name = "blSolrIndexService")
    @Resource(name = "blSolrSearchServiceExtensionManager")
        if ("solrhome".equals(solrServer)) {
            final String baseTempPath = System.getProperty("java.io.tmpdir");
            File tempDir = new File(baseTempPath + . + System.getProperty("user.name") + . + "solrhome");
            if (System.getProperty("tmpdir.solrhome") != null) {
                //allow for an override of tmpdir
                tempDir = new File(System.getProperty("tmpdir.solrhome"));
            }
            if (!tempDir.exists()) {
                tempDir.mkdirs();
            }
            solrServer = tempDir.getAbsolutePath();
        }
        
        File solrXml = new File(new File(solrServer), "solr.xml");
        if (!solrXml.exists()) {
            copyConfigToSolrHome(this.getClass().getResourceAsStream("/solr-default.xml"), solrXml);
        }
        .debug(String.format("Using [%s] as solrhome"solrServer));
        .debug(String.format("Using [%s] as solr.xml"solrXml.getAbsoluteFile()));
        
        if (.isTraceEnabled()) {
            .trace("Contents of solr.xml:");
            BufferedReader br = null;
            try {
                br = new BufferedReader(new FileReader(solrXml));
                String line;
                while ((line = br.readLine()) != null) {
                    .trace(line);
                }
            } finally {
                if (br != null) {
                    try {
                        br.close();
                    } catch (Throwable e) {
                        //do nothing
                    }
                }
            }
            .trace("Done printing solr.xml");
        }
        CoreContainer coreContainer = CoreContainer.createAndLoad(solrServersolrXml);
        EmbeddedSolrServer primaryServer = new EmbeddedSolrServer(coreContainer.);
        EmbeddedSolrServer reindexServer = new EmbeddedSolrServer(coreContainer.);
        SolrContext.setPrimaryServer(primaryServer);
        SolrContext.setReindexServer(reindexServer);
    }
    public void copyConfigToSolrHome(InputStream configIsFile destFilethrows IOException {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            bis = new BufferedInputStream(configIs);
            bos = new BufferedOutputStream(new FileOutputStream(destFilefalse));
            boolean eof = false;
            while (!eof) {
                int temp = bis.read();
                if (temp == -1) {
                    eof = true;
                } else {
                    bos.write(temp);
                }
            }
            bos.flush();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (Throwable e) {
                    //do nothing
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (Throwable e) {
                    //do nothing
                }
            }
        }
    }
    public SolrSearchServiceImpl(SolrServer solrServer) {
        SolrContext.setPrimaryServer(solrServer);
    }

    
This constructor serves to mimic the one below this, which takes in two org.apache.solr.client.solrj.SolrServer arguments. By having this and then simply disregarding the second parameter, we can more easily support 2-core Solr configurations that use embedded/standalone per environment.

    public SolrSearchServiceImpl(String solrServerString reindexServerthrows IOExceptionParserConfigurationExceptionSAXException {
        this(solrServer);
    }
    public SolrSearchServiceImpl(SolrServer solrServerSolrServer reindexServer) {
        SolrContext.setPrimaryServer(solrServer);
        SolrContext.setReindexServer(reindexServer);
    }
    @Override
    public void rebuildIndex() throws ServiceExceptionIOException {
    }
    @Override
    public void destroy() throws Exception {
        if (SolrContext.getServer() instanceof EmbeddedSolrServer) {
            ((EmbeddedSolrServer) SolrContext.getServer()).shutdown();
        }
    }
    @Override
            throws ServiceException {
        List<SearchFacetDTOfacets = getCategoryFacets(category);
        String query = .getExplicitCategoryFieldName() + ":" + .getCategoryId(category.getId());
        return findProducts("*:*"facetssearchCriteria.getCategorySortFieldName(category) + " asc"query);
    }
    @Override
    public ProductSearchResult findProductsByCategory(Category categoryProductSearchCriteria searchCriteria)
            throws ServiceException {
        List<SearchFacetDTOfacets = getCategoryFacets(category);
        String query = .getCategoryFieldName() + ":" + .getCategoryId(category.getId());
        return findProducts("*:*"facetssearchCriteria.getCategorySortFieldName(category) + " asc"query);
    }
    @Override
    public ProductSearchResult findProductsByQuery(String queryProductSearchCriteria searchCriteria)
            throws ServiceException {
        List<SearchFacetDTOfacets = getSearchFacets();
        query = "(" + sanitizeQuery(query) + ")";
        return findProducts(queryfacetssearchCriterianull);
    }
    @Override
            ProductSearchCriteria searchCriteriathrows ServiceException {
        List<SearchFacetDTOfacets = getSearchFacets();
        String catFq = .getCategoryFieldName() + ":" + .getCategoryId(category.getId());
        query = "(" + sanitizeQuery(query) + ")";
        
        return findProducts(queryfacetssearchCriterianullcatFq);
    }
    public String getLocalePrefix() {
        if (BroadleafRequestContext.getBroadleafRequestContext() != null) {
            Locale locale = BroadleafRequestContext.getBroadleafRequestContext().getLocale();
            if (locale != null) {
                return locale.getLocaleCode() + "_";
            }
        }
        return "";
    }
    protected String buildQueryFieldsString() {
        StringBuilder queryBuilder = new StringBuilder();
        List<Fieldfields = .readAllProductFields();
        for (Field currentField : fields) {
            if (currentField.getSearchable()) {
                appendFieldToQuery(queryBuildercurrentField);
            }
        }
        return queryBuilder.toString();
    }
    protected void appendFieldToQuery(StringBuilder queryBuilderField currentField) {
        List<FieldTypesearchableFieldTypes = .getSearchableFieldTypes(currentField);
        for (FieldType currentType : searchableFieldTypes) {
            queryBuilder.append(.getPropertyNameForFieldSearchable(currentFieldcurrentType)).append(" ");
        }
    }

    

Deprecated:
in favor of the other findProducts() method
    protected ProductSearchResult findProducts(String qualifiedSolrQueryList<SearchFacetDTOfacets,
            ProductSearchCriteria searchCriteriaString defaultSortthrows ServiceException {
        return findProducts(qualifiedSolrQueryfacetssearchCriteriadefaultSortnull);
    }

    
Given a qualified solr query string (such as "category:2002"), actually performs a solr search. It will take into considering the search criteria to build out facets / pagination / sorting.

Parameters:
qualifiedSolrQuery
facets
searchCriteria
Returns:
the ProductSearchResult of the search
Throws:
org.broadleafcommerce.common.exception.ServiceException
    protected ProductSearchResult findProducts(String qualifiedSolrQueryList<SearchFacetDTOfacets,
            ProductSearchCriteria searchCriteriaString defaultSortString... filterQueriesthrows ServiceException {
        Map<StringSearchFacetDTOnamedFacetMap = getNamedFacetMap(facetssearchCriteria);
        // Build the basic query
        SolrQuery solrQuery = new SolrQuery()
                .setQuery(qualifiedSolrQuery)
                .setFields(.getProductIdFieldName())
                .setRows(searchCriteria.getPageSize())
                .setStart((searchCriteria.getPage() - 1) * searchCriteria.getPageSize());
        if (filterQueries != null) {
            solrQuery.setFilterQueries(filterQueries);
        }
        solrQuery.addFilterQuery(.getNamespaceFieldName() + ":(\"" + .getCurrentNamespace() + "\")");
        solrQuery.set("defType""edismax");
        solrQuery.set("qf"buildQueryFieldsString());
        // Attach additional restrictions
        attachSortClause(solrQuerysearchCriteriadefaultSort);
        attachActiveFacetFilters(solrQuerynamedFacetMapsearchCriteria);
        attachFacets(solrQuerynamedFacetMap);
        
        .getProxy().modifySolrQuery(solrQueryqualifiedSolrQueryfacets,
                searchCriteriadefaultSort);
        if (.isTraceEnabled()) {
            try {
                .trace(URLDecoder.decode(solrQuery.toString(), "UTF-8"));
            } catch (Exception e) {
                .trace("Couldn't UTF-8 URL Decode: " + solrQuery.toString());
            }
        }
        // Query solr
        QueryResponse response;
        List<SolrDocumentresponseDocuments;
        int numResults = 0;
        try {
            response = SolrContext.getServer().query(solrQuery);
            responseDocuments = getResponseDocuments(response);
            numResults = (intresponse.getResults().getNumFound();
            if (.isTraceEnabled()) {
                .trace(response.toString());
                for (SolrDocument doc : responseDocuments) {
                    .trace(doc);
                }
            }
        } catch (SolrServerException e) {
            throw new ServiceException("Could not perform search"e);
        }
        // Get the facets
        setFacetResults(namedFacetMapresponse);
        sortFacetResults(namedFacetMap);
        // Get the products
        List<Productproducts = getProducts(responseDocuments);
        ProductSearchResult result = new ProductSearchResult();
        result.setFacets(facets);
        result.setProducts(products);
        setPagingAttributes(resultnumResultssearchCriteria);
        return result;
    }
    
    protected List<SolrDocumentgetResponseDocuments(QueryResponse response) {
        List<SolrDocumentdocs;
        
        if (response.getGroupResponse() == null) {
            docs = response.getResults();
        } else {
            docs = new ArrayList<SolrDocument>();
            GroupResponse gr = response.getGroupResponse();
            for (GroupCommand gc : gr.getValues()) {
                for (Group g : gc.getValues()) {
                    for (SolrDocument d : g.getResult()) {
                        docs.add(d);
                    }
                }
            }
        }
        
        return docs;
    }
    @Override
    public List<SearchFacetDTOgetSearchFacets() {
    }
    @Override
    public List<SearchFacetDTOgetCategoryFacets(Category category) {
        List<CategorySearchFacetcategorySearchFacets = category.getCumulativeSearchFacets();
        List<SearchFacetsearchFacets = new ArrayList<SearchFacet>();
        for (CategorySearchFacet categorySearchFacet : categorySearchFacets) {
            searchFacets.add(categorySearchFacet.getSearchFacet());
        }
        return buildSearchFacetDTOs(searchFacets);
    }

    
Sets up the sorting criteria. This will support sorting by multiple fields at a time

Parameters:
query
searchCriteria
    protected void attachSortClause(SolrQuery queryProductSearchCriteria searchCriteriaString defaultSort) {
        Map<StringStringsolrFieldKeyMap = getSolrFieldKeyMap(searchCriteria);
        String sortQuery = searchCriteria.getSortQuery();
        if (StringUtils.isBlank(sortQuery)) {
            sortQuery = defaultSort;
        }
        if (StringUtils.isNotBlank(sortQuery)) {
            String[] sortFields = sortQuery.split(",");
            for (String sortField : sortFields) {
                String field = sortField.split(" ")[0];
                if (solrFieldKeyMap.containsKey(field)) {
                    field = solrFieldKeyMap.get(field);
                }
                ORDER order = "desc".equals(sortField.split(" ")[1]) ? . : .;
                if (field != null) {
                    query.addSortField(fieldorder);
                }
            }
        }
    }

    
Restricts the query by adding active facet filters.

Parameters:
query
namedFacetMap
searchCriteria
    protected void attachActiveFacetFilters(SolrQuery queryMap<StringSearchFacetDTOnamedFacetMap,
            ProductSearchCriteria searchCriteria) {
        for (Entry<StringString[]> entry : searchCriteria.getFilterCriteria().entrySet()) {
            String solrKey = null;
            for (Entry<StringSearchFacetDTOdtoEntry : namedFacetMap.entrySet()) {
                if (dtoEntry.getValue().getFacet().getField().getAbbreviation().equals(entry.getKey())) {
                    solrKey = dtoEntry.getKey();
                    dtoEntry.getValue().setActive(true);
                }
            }
            if (solrKey != null) {
                String solrTag = getSolrFieldTag(.getGlobalFacetTagField(), "tag");
                String[] selectedValues = entry.getValue().clone();
                for (int i = 0; i < selectedValues.lengthi++) {
                    if (selectedValues[i].contains("range[")) {
                        String rangeValue = selectedValues[i].substring(selectedValues[i].indexOf('[') + 1,
                                selectedValues[i].indexOf(']'));
                        String[] rangeValues = StringUtils.split(rangeValue':');
                        if (rangeValues[1].equals("null")) {
                            rangeValues[1] = "*";
                        }
                        selectedValues[i] = solrKey + ":[" + rangeValues[0] + " TO " + rangeValues[1] + "]";
                    } else {
                        selectedValues[i] = solrKey + ":\"" + selectedValues[i] + "\"";
                    }
                }
                String valueString = StringUtils.join(selectedValues" OR ");
                StringBuilder sb = new StringBuilder();
                sb.append(solrTag).append("(").append(valueString).append(")");
                query.addFilterQuery(sb.toString());
            }
        }
    }

    
Notifies solr about which facets you want it to determine results and counts for

Parameters:
query
namedFacetMap
    protected void attachFacets(SolrQuery queryMap<StringSearchFacetDTOnamedFacetMap) {
        query.setFacet(true);
        for (Entry<StringSearchFacetDTOentry : namedFacetMap.entrySet()) {
            SearchFacetDTO dto = entry.getValue();
            String facetTagField = entry.getValue().isActive() ? .getGlobalFacetTagField() : entry.getKey();
            // Clone the list - we don't want to remove these facets from the DB
            List<SearchFacetRangefacetRanges = new ArrayList<SearchFacetRange>(dto.getFacet().getSearchFacetRanges());
            if ( != null) {
                .getProxy().filterSearchFacetRanges(dtofacetRanges);
            }
            if (facetRanges != null && facetRanges.size() > 0) {
                for (SearchFacetRange range : facetRanges) {
                    query.addFacetQuery(getSolrTaggedFieldString(entry.getKey(), facetTagField"ex"range));
                }
            } else {
                query.addFacetField(getSolrTaggedFieldString(entry.getKey(), facetTagField"ex"null));
            }
        }
    }

    
Builds out the DTOs for facet results from the search. This will then be used by the view layer to display which values are available given the current constraints as well as the count of the values.

Parameters:
namedFacetMap
response
    protected void setFacetResults(Map<StringSearchFacetDTOnamedFacetMapQueryResponse response) {
        if (response.getFacetFields() != null) {
            for (FacetField facet : response.getFacetFields()) {
                String facetFieldName = facet.getName();
                SearchFacetDTO facetDTO = namedFacetMap.get(facetFieldName);
                for (Count value : facet.getValues()) {
                    SearchFacetResultDTO resultDTO = new SearchFacetResultDTO();
                    resultDTO.setFacet(facetDTO.getFacet());
                    resultDTO.setQuantity(new Long(value.getCount()).intValue());
                    resultDTO.setValue(value.getName());
                    facetDTO.getFacetValues().add(resultDTO);
                }
            }
        }
        if (response.getFacetQuery() != null) {
            for (Entry<StringIntegerentry : response.getFacetQuery().entrySet()) {
                String key = entry.getKey();
                String facetFieldName = key.substring(key.indexOf("}") + 1, key.indexOf(':'));
                SearchFacetDTO facetDTO = namedFacetMap.get(facetFieldName);
                String minValue = key.substring(key.indexOf("[") + 1, key.indexOf(" TO"));
                String maxValue = key.substring(key.indexOf(" TO ") + 4, key.indexOf("]"));
                if (maxValue.equals("*")) {
                    maxValue = null;
                }
                SearchFacetResultDTO resultDTO = new SearchFacetResultDTO();
                resultDTO.setFacet(facetDTO.getFacet());
                resultDTO.setQuantity(entry.getValue());
                resultDTO.setMinValue(new BigDecimal(minValue));
                resultDTO.setMaxValue(maxValue == null ? null : new BigDecimal(maxValue));
                facetDTO.getFacetValues().add(resultDTO);
            }
        }
    }

    
Invoked to sort the facet results. This method will use the natural sorting of the value attribute of the facet (or, if value is null, the minValue of the facet result). Override this method to customize facet sorting for your given needs.

Parameters:
namedFacetMap
    protected void sortFacetResults(Map<StringSearchFacetDTOnamedFacetMap) {
        for (Entry<StringSearchFacetDTOentry : namedFacetMap.entrySet()) {
            Collections.sort(entry.getValue().getFacetValues(), new Comparator<SearchFacetResultDTO>() {
                public int compare(SearchFacetResultDTO o1SearchFacetResultDTO o2) {
                    if (o1.getValue() != null && o2.getValue() != null) {
                        return o1.getValue().compareTo(o2.getValue());
                    } else if (o1.getMinValue() != null && o2.getMinValue() != null) {
                        return o1.getMinValue().compareTo(o2.getMinValue());
                    }
                    return 0; // Don't know how to compare
                }
            });
        }
    }

    
Sets the total results, the current page, and the page size on the ProductSearchResult. Total results comes from solr, while page and page size are duplicates of the searchCriteria conditions for ease of use.

Parameters:
result
response
searchCriteria
    public void setPagingAttributes(ProductSearchResult resultint numResultsProductSearchCriteria searchCriteria) {
        result.setTotalResults(numResults);
        result.setPage(searchCriteria.getPage());
        result.setPageSize(searchCriteria.getPageSize());
    }

    
Given a list of product IDs from solr, this method will look up the IDs via the productDao and build out actual Product instances. It will return a Products that is sorted by the order of the IDs in the passed in list.

Parameters:
response
Returns:
the actual Product instances as a result of the search
    protected List<ProductgetProducts(List<SolrDocumentresponseDocuments) {
        final List<LongproductIds = new ArrayList<Long>();
        for (SolrDocument doc : responseDocuments) {
            productIds.add((Longdoc.getFieldValue(.getProductIdFieldName()));
        }
        List<Productproducts = .readProductsByIds(productIds);
        // We have to sort the products list by the order of the productIds list to maintain sortability in the UI
        if (products != null) {
            Collections.sort(productsnew Comparator<Product>() {
                public int compare(Product o1Product o2) {
                    Long o1id = .getProductId(o1.getId());
                    Long o2id = .getProductId(o2.getId());
                    return new Integer(productIds.indexOf(o1id)).compareTo(productIds.indexOf(o2id));
                }
            });
        }
        return products;
    }

    
Create the wrapper DTO around the SearchFacet

Parameters:
searchFacets
Returns:
the wrapper DTO
    protected List<SearchFacetDTObuildSearchFacetDTOs(List<SearchFacetsearchFacets) {
        List<SearchFacetDTOfacets = new ArrayList<SearchFacetDTO>();
        Map<StringString[]> requestParameters = BroadleafRequestContext.getRequestParameterMap();
        for (SearchFacet facet : searchFacets) {
            if (facetIsAvailable(facetrequestParameters)) {
                SearchFacetDTO dto = new SearchFacetDTO();
                dto.setFacet(facet);
                dto.setShowQuantity(true);
                facets.add(dto);
            }
        }
        return facets;
    }

    
Checks to see if the requiredFacets condition for a given facet is met.

Parameters:
facet
request
Returns:
whether or not the facet parameter is available
    protected boolean facetIsAvailable(SearchFacet facetMap<StringString[]> params) {
        // Facets are available by default if they have no requiredFacets
        if (CollectionUtils.isEmpty(facet.getRequiredFacets())) {
            return true;
        }
        // If we have at least one required facet but no active facets, it's impossible for this facet to be available
        if (MapUtils.isEmpty(params)) {
            return false;
        }
        // We must either match all or just one of the required facets depending on the requiresAllDependentFacets flag
        int requiredMatches = facet.getRequiresAllDependentFacets() ? facet.getRequiredFacets().size() : 1;
        int matchesSoFar = 0;
        for (RequiredFacet requiredFacet : facet.getRequiredFacets()) {
            if (requiredMatches == matchesSoFar) {
                return true;
            }
            // Check to see if the required facet has a value in the current request parameters
            for (Entry<StringString[]> entry : params.entrySet()) {
                String key = entry.getKey();
                if (key.equals(requiredFacet.getRequiredFacet().getField().getAbbreviation())) {
                    matchesSoFar++;
                    break;
                }
            }
        }
        return requiredMatches == matchesSoFar;
    }

    
Perform any necessary query sanitation here. For example, we disallow open and close parentheses, colons, and we also ensure that quotes are actual quotes (") and not the URL encoding (") so that Solr is able to properly handle the user's intent.

Parameters:
query
Returns:
the sanitized query
    protected String sanitizeQuery(String query) {
        return query.replace("(""").replace("%28""")
                .replace(")""").replace("%29""")
                .replace(":""").replace("%3A""").replace("%3a""")
                .replace("&quot;""\""); // Allow quotes in the query for more finely tuned matches
    }

    
Returns a field string. Given indexField = a and a non-null range, would produce the following String: a:[minVal TO maxVal]
    protected String getSolrFieldString(String indexFieldSearchFacetRange range) {
        StringBuilder sb = new StringBuilder();
        sb.append(indexField);
        if (range != null) {
            String minValue = range.getMinValue().toPlainString();
            String maxValue = range.getMaxValue() == null ? "*" : range.getMaxValue().toPlainString();
            sb.append(":[").append(minValue).append(" TO ").append(maxValue).append("]");
        }
        return sb.toString();
    }

    
Returns a fully composed solr field string. Given indexField = a, tag = ex, and a non-null range, would produce the following String: {!ex=a}a:[minVal TO maxVal]
    protected String getSolrTaggedFieldString(String indexFieldString tagFieldString tagSearchFacetRange range) {
        return getSolrFieldTag(tagFieldtag) + getSolrFieldString(indexFieldrange);
    }

    
Returns a solr field tag. Given indexField = a, tag = ex, would produce the following String: {!ex=a}
    protected String getSolrFieldTag(String tagFieldString tag) {
        StringBuilder sb = new StringBuilder();
        if (StringUtils.isNotBlank(tag)) {
            sb.append("{!").append(tag).append("=").append(tagField).append("}");
        }
        return sb.toString();
    }

    

Parameters:
facets
searchCriteria
Returns:
a map of fully qualified solr index field key to the searchFacetDTO object
            final ProductSearchCriteria searchCriteria) {
        return BLCMapUtils.keyedMap(facetsnew TypedClosure<StringSearchFacetDTO>() {
            public String getKey(SearchFacetDTO facet) {
                return getSolrFieldKey(facet.getFacet().getField(), searchCriteria);
            }
        });
    }

    
This method will be used to map a field abbreviation to the appropriate solr index field to use. Typically, this default implementation that maps to the facet field type will be sufficient. However, there may be cases where you would want to use a different solr index depending on other currently active facets. In that case, you would associate that mapping here. For example, for the "price" abbreviation, we would generally want to use "defaultSku.retailPrice_td". However, if a secondary facet on item condition is selected (such as "refurbished", we may want to index "price" to "refurbishedSku.retailPrice_td". That mapping occurs here.

Parameters:
fields
searchCriteria the searchCriteria in case it is needed to determine the field key
Returns:
the solr field index key to use
    protected String getSolrFieldKey(Field fieldProductSearchCriteria searchCriteria) {
        return .getPropertyNameForFieldFacet(field);
    }

    

Parameters:
searchCriteria
Returns:
a map of abbreviated key to fully qualified solr index field key for all product fields
    protected Map<StringStringgetSolrFieldKeyMap(ProductSearchCriteria searchCriteria) {
        List<Fieldfields = .readAllProductFields();
        Map<StringStringsolrFieldKeyMap = new HashMap<StringString>();
        for (Field field : fields) {
            solrFieldKeyMap.put(field.getAbbreviation(), getSolrFieldKey(fieldsearchCriteria));
        }
        return solrFieldKeyMap;
    }
New to GrepCode? Check out our FAQ X