org.broadleafcommerce.core.search.service.solr
Class SolrSearchServiceImpl

java.lang.Object
  extended by org.broadleafcommerce.core.search.service.solr.SolrSearchServiceImpl
All Implemented Interfaces:
SearchService, org.springframework.beans.factory.DisposableBean

public class SolrSearchServiceImpl
extends Object
implements SearchService, org.springframework.beans.factory.DisposableBean

An implementation of SearchService that uses Solr

Author:
Andre Azzolini (apazzolini)

Field Summary
protected  FieldDao fieldDao
           
protected static String GLOBAL_FACET_TAG_FIELD
           
protected  ProductDao productDao
           
protected  SearchFacetDao searchFacetDao
           
protected  org.apache.solr.client.solrj.SolrServer server
           
 
Constructor Summary
SolrSearchServiceImpl(org.apache.solr.client.solrj.SolrServer solrServer)
           
SolrSearchServiceImpl(String solrServer)
           
 
Method Summary
protected  void attachActiveFacetFilters(org.apache.solr.client.solrj.SolrQuery query, Map<String,SearchFacetDTO> namedFacetMap, ProductSearchCriteria searchCriteria)
          Restricts the query by adding active facet filters.
protected  void attachFacets(org.apache.solr.client.solrj.SolrQuery query, Map<String,SearchFacetDTO> namedFacetMap)
          Notifies solr about which facets you want it to determine results and counts for
protected  void attachSortClause(org.apache.solr.client.solrj.SolrQuery query, ProductSearchCriteria searchCriteria, String defaultSort)
          Sets up the sorting criteria.
protected  List<SearchFacetDTO> buildSearchFacetDTOs(List<SearchFacet> searchFacets)
          Create the wrapper DTO around the SearchFacet
protected  String convertToMappedProperty(String propertyName, String listPropertyName, String mapPropertyName)
          Converts a propertyName to one that is able to reference inside a map.
 void destroy()
           
 ProductSearchResult findExplicitProductsByCategory(Category category, ProductSearchCriteria searchCriteria)
          Performs a search for products in the given category, taking into consideration the ProductSearchCriteria This method will NOT return products that are in a sub-level of a given category.
protected  ProductSearchResult findProducts(String qualifiedSolrQuery, List<SearchFacetDTO> facets, ProductSearchCriteria searchCriteria, String defaultSort)
          Given a qualified solr query string (such as "category:2002"), actually performs a solr search.
 ProductSearchResult findProductsByCategory(Category category, ProductSearchCriteria searchCriteria)
          Performs a search for products in the given category, taking into consideration the ProductSearchCriteria This method will return products that are in any sub-level of a given category.
 ProductSearchResult findProductsByCategoryAndQuery(Category category, String query, ProductSearchCriteria searchCriteria)
          Performs a search for products in the given category for the given query, taking into consideration the ProductSearchCriteria
 ProductSearchResult findProductsByQuery(String query, ProductSearchCriteria searchCriteria)
          Performs a search for products across all categories for the given query, taking into consideration the ProductSearchCriteria
 List<SearchFacetDTO> getCategoryFacets(Category category)
          Gets all available facets for a given category
protected  String getCategoryFieldName()
           
protected  String getCategorySortField(Category category)
           
protected  String getExplicitCategoryFieldName()
           
protected  String getGlobalPrefix()
          Determines if there is a prefix that needs to be applied to all fields for this particular request.
protected  String getIdFieldName()
           
protected  String getLocalePrefix()
          Determines if there is a locale prefix that needs to be applied to fields for this particular request.
protected  Map<String,SearchFacetDTO> getNamedFacetMap(List<SearchFacetDTO> facets, ProductSearchCriteria searchCriteria)
           
protected  String getPricelistPrefix()
          Determines if there is a pricelist prefix that needs to be applied to fields for this particular request.
protected  List<Product> getProducts(org.apache.solr.client.solrj.response.QueryResponse response)
          Given a list of product IDs from solr, this method will look up the IDs via the productDao and build out actual Product instances.
protected  String getPropertyNameForFieldFacet(Field field)
          Returns the property name for the given field and its configured facet field type.
protected  String getPropertyNameForFieldSearchable(Field field, FieldType searchableFieldType)
          Returns the property name for the given field and field type.
protected  String getSearchableFieldName()
           
 List<SearchFacetDTO> getSearchFacets()
          Gets all available facets for search results page
protected  String getSolrFieldKey(Field field, ProductSearchCriteria searchCriteria)
          This method will be used to map a field abbreviation to the appropriate solr index field to use.
protected  Map<String,String> getSolrFieldKeyMap(ProductSearchCriteria searchCriteria)
           
protected  String getSolrFieldString(String indexField, SearchFacetRange range)
          Returns a field string.
protected  String getSolrFieldTag(String tagField, String tag)
          Returns a solr field tag.
protected  String getSolrTaggedFieldString(String indexField, String tagField, String tag, SearchFacetRange range)
          Returns a fully composed solr field string.
 void rebuildIndex()
          Rebuilds the current index.
protected  String sanitizeQuery(String query)
          Perform any necessary query sanitation here.
protected  void setFacetResults(Map<String,SearchFacetDTO> namedFacetMap, org.apache.solr.client.solrj.response.QueryResponse response)
          Builds out the DTOs for facet results from the search.
 void setPagingAttributes(ProductSearchResult result, org.apache.solr.client.solrj.response.QueryResponse response, ProductSearchCriteria searchCriteria)
          Sets the total results, the current page, and the page size on the ProductSearchResult.
protected  void sortFacetResults(Map<String,SearchFacetDTO> namedFacetMap)
          Invoked to sort the facet results.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

GLOBAL_FACET_TAG_FIELD

protected static final String GLOBAL_FACET_TAG_FIELD
See Also:
Constant Field Values

productDao

protected ProductDao productDao

fieldDao

protected FieldDao fieldDao

searchFacetDao

protected SearchFacetDao searchFacetDao

server

protected org.apache.solr.client.solrj.SolrServer server
Constructor Detail

SolrSearchServiceImpl

public SolrSearchServiceImpl(String solrServer)
                      throws IOException,
                             ParserConfigurationException,
                             SAXException
Throws:
IOException
ParserConfigurationException
SAXException

SolrSearchServiceImpl

public SolrSearchServiceImpl(org.apache.solr.client.solrj.SolrServer solrServer)
Method Detail

destroy

public void destroy()
             throws Exception
Specified by:
destroy in interface org.springframework.beans.factory.DisposableBean
Throws:
Exception

rebuildIndex

@Transactional(value="blTransactionManager")
public void rebuildIndex()
                  throws ServiceException,
                         IOException
Description copied from interface: SearchService
Rebuilds the current index. Note that some search service implementations may not necessarily support rebuilding an index (such as the DatabaseProductSearchService)

Specified by:
rebuildIndex in interface SearchService
Throws:
ServiceException
IOException

findExplicitProductsByCategory

public ProductSearchResult findExplicitProductsByCategory(Category category,
                                                          ProductSearchCriteria searchCriteria)
                                                   throws ServiceException
Description copied from interface: SearchService
Performs a search for products in the given category, taking into consideration the ProductSearchCriteria This method will NOT return products that are in a sub-level of a given category. For example, if you had a "Routers" category and a "Enterprise Routers" sub-category, asking for products in "Routers", would NOT return products that are in the "Enterprise Routers" category.

Specified by:
findExplicitProductsByCategory in interface SearchService
Returns:
Throws:
ServiceException
See Also:
SearchService.findProductsByCategory(Category, ProductSearchCriteria)

findProductsByCategory

public ProductSearchResult findProductsByCategory(Category category,
                                                  ProductSearchCriteria searchCriteria)
                                           throws ServiceException
Description copied from interface: SearchService
Performs a search for products in the given category, taking into consideration the ProductSearchCriteria This method will return products that are in any sub-level of a given category. For example, if you had a "Routers" category and a "Enterprise Routers" sub-category, asking for products in "Routers", would return products that are in the "Enterprise Routers" category.

Specified by:
findProductsByCategory in interface SearchService
Returns:
the result of the search
Throws:
ServiceException
See Also:
SearchService.findExplicitProductsByCategory(Category, ProductSearchCriteria)

findProductsByQuery

public ProductSearchResult findProductsByQuery(String query,
                                               ProductSearchCriteria searchCriteria)
                                        throws ServiceException
Description copied from interface: SearchService
Performs a search for products across all categories for the given query, taking into consideration the ProductSearchCriteria

Specified by:
findProductsByQuery in interface SearchService
Returns:
the result of the search
Throws:
ServiceException

findProductsByCategoryAndQuery

public ProductSearchResult findProductsByCategoryAndQuery(Category category,
                                                          String query,
                                                          ProductSearchCriteria searchCriteria)
                                                   throws ServiceException
Description copied from interface: SearchService
Performs a search for products in the given category for the given query, taking into consideration the ProductSearchCriteria

Specified by:
findProductsByCategoryAndQuery in interface SearchService
Throws:
ServiceException

getSearchFacets

public List<SearchFacetDTO> getSearchFacets()
Description copied from interface: SearchService
Gets all available facets for search results page

Specified by:
getSearchFacets in interface SearchService
Returns:
the available facets

getCategoryFacets

public List<SearchFacetDTO> getCategoryFacets(Category category)
Description copied from interface: SearchService
Gets all available facets for a given category

Specified by:
getCategoryFacets in interface SearchService
Returns:
the available facets

findProducts

protected ProductSearchResult findProducts(String qualifiedSolrQuery,
                                           List<SearchFacetDTO> facets,
                                           ProductSearchCriteria searchCriteria,
                                           String defaultSort)
                                    throws ServiceException
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:
ServiceException

attachSortClause

protected void attachSortClause(org.apache.solr.client.solrj.SolrQuery query,
                                ProductSearchCriteria searchCriteria,
                                String defaultSort)
Sets up the sorting criteria. This will support sorting by multiple fields at a time

Parameters:
query -
searchCriteria -

attachActiveFacetFilters

protected void attachActiveFacetFilters(org.apache.solr.client.solrj.SolrQuery query,
                                        Map<String,SearchFacetDTO> namedFacetMap,
                                        ProductSearchCriteria searchCriteria)
Restricts the query by adding active facet filters.

Parameters:
query -
namedFacetMap -
searchCriteria -

attachFacets

protected void attachFacets(org.apache.solr.client.solrj.SolrQuery query,
                            Map<String,SearchFacetDTO> namedFacetMap)
Notifies solr about which facets you want it to determine results and counts for

Parameters:
query -
namedFacetMap -

setFacetResults

protected void setFacetResults(Map<String,SearchFacetDTO> namedFacetMap,
                               org.apache.solr.client.solrj.response.QueryResponse response)
Builds out the DTOs for facet results from the search. This will then be used by the view layer to display which values are avaialble given the current constraints as well as the count of the values.

Parameters:
namedFacetMap -
response -

sortFacetResults

protected void sortFacetResults(Map<String,SearchFacetDTO> namedFacetMap)
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 -

setPagingAttributes

public void setPagingAttributes(ProductSearchResult result,
                                org.apache.solr.client.solrj.response.QueryResponse response,
                                ProductSearchCriteria searchCriteria)
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 -

getProducts

protected List<Product> getProducts(org.apache.solr.client.solrj.response.QueryResponse response)
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

getSolrTaggedFieldString

protected String getSolrTaggedFieldString(String indexField,
                                          String tagField,
                                          String tag,
                                          SearchFacetRange range)
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]


getSolrFieldTag

protected String getSolrFieldTag(String tagField,
                                 String tag)
Returns a solr field tag. Given indexField = a, tag = ex, would produce the following String: {!ex=a}


getSolrFieldString

protected String getSolrFieldString(String indexField,
                                    SearchFacetRange range)
Returns a field string. Given indexField = a and a non-null range, would produce the following String: a:[minVal TO maxVal]


buildSearchFacetDTOs

protected List<SearchFacetDTO> buildSearchFacetDTOs(List<SearchFacet> searchFacets)
Create the wrapper DTO around the SearchFacet

Parameters:
searchFacets -
Returns:
the wrapper DTO

convertToMappedProperty

protected String convertToMappedProperty(String propertyName,
                                         String listPropertyName,
                                         String mapPropertyName)
Converts a propertyName to one that is able to reference inside a map. For example, consider the property in Product that references a List, "productAttributes". Also consider the utility method in Product called "mappedProductAttributes", which returns a map of the ProductAttributes keyed by the name property in the ProductAttribute. Given the parameters "productAttributes.heatRange", "productAttributes", "mappedProductAttributes" (which would represent a property called "productAttributes.heatRange" that references a specific ProductAttribute inside of a product whose "name" property is equal to "heatRange", this method will convert this property to mappedProductAttributes(heatRange).value, which is then usable by the standard beanutils PropertyUtils class to get the value.

Parameters:
propertyName -
listPropertyName -
mapPropertyName -
Returns:
the converted property name

getSolrFieldKey

protected String getSolrFieldKey(Field field,
                                 ProductSearchCriteria 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

getSolrFieldKeyMap

protected Map<String,String> getSolrFieldKeyMap(ProductSearchCriteria searchCriteria)
Parameters:
searchCriteria -
Returns:
a map of abbreviated key to fully qualified solr index field key for all product fields

getNamedFacetMap

protected Map<String,SearchFacetDTO> getNamedFacetMap(List<SearchFacetDTO> facets,
                                                      ProductSearchCriteria searchCriteria)
Parameters:
facets -
searchCriteria -
Returns:
a map of fully qualified solr index field key to the searchFacetDTO object

sanitizeQuery

protected String sanitizeQuery(String query)
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

getGlobalPrefix

protected String getGlobalPrefix()
Determines if there is a prefix that needs to be applied to all fields for this particular request. For example, if you have multiple sites set up, you may want to filter that here. Note: This method should NOT return null. If there is no prefix, it should return the empty string.

Returns:
the global prefix if there is one, "" if there isn't

getLocalePrefix

protected String getLocalePrefix()
Determines if there is a locale prefix that needs to be applied to fields for this particular request. By default, a locale prefix is not applicable for category, explicitCategory, or fields that have type Price Note: This method should NOT return null. If there is no prefix, it should return the empty string.

Returns:
the global prefix if there is one, "" if there isn't

getPricelistPrefix

protected String getPricelistPrefix()
Determines if there is a pricelist prefix that needs to be applied to fields for this particular request. By default, a pricelist prefix will only apply to fields that have type Price Note: This method should NOT return null. If there is no prefix, it should return the empty string.

Returns:
the global prefix if there is one, "" if there isn't

getPropertyNameForFieldSearchable

protected String getPropertyNameForFieldSearchable(Field field,
                                                   FieldType searchableFieldType)
Returns the property name for the given field and field type. This will apply the global prefix to the field, and it will also apply either the locale prefix or the pricelist prefix, depending on whether or not the field type was set to FieldType.PRICE

Parameters:
field -
searchableFieldType -
Returns:
the property name for the field and fieldtype

getPropertyNameForFieldFacet

protected String getPropertyNameForFieldFacet(Field field)
Returns the property name for the given field and its configured facet field type. This will apply the global prefix to the field, and it will also apply either the locale prefix or the pricelist prefix, depending on whether or not the field type was set to FieldType.PRICE

Parameters:
field -
Returns:
the property name for the facet type of this field

getIdFieldName

protected String getIdFieldName()
Returns:
the id field name, with the global prefix as appropriate

getSearchableFieldName

protected String getSearchableFieldName()
Returns:
the searchable field name, with the global and locale prefixes as appropriate

getCategoryFieldName

protected String getCategoryFieldName()
Returns:
the category field name, with the global prefix as appropriate

getExplicitCategoryFieldName

protected String getExplicitCategoryFieldName()
Returns:
the explicit category field name, with the global prefix as appropriate

getCategorySortField

protected String getCategorySortField(Category category)
Parameters:
category -
Returns:
the default sort field name for this category


Copyright © 2012. All Rights Reserved.