package org.jai.search.query.impl;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.mlt.MoreLikeThisRequestBuilder;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.suggest.SuggestRequestBuilder;
import org.elasticsearch.action.suggest.SuggestResponse;
import org.elasticsearch.index.get.GetField;
import org.elasticsearch.index.query.AndFilterBuilder;
import org.elasticsearch.index.query.FilterBuilder;
import org.elasticsearch.index.query.FilterBuilders;
import org.elasticsearch.index.query.FilteredQueryBuilder;
import org.elasticsearch.index.query.NestedFilterBuilder;
import org.elasticsearch.index.query.OrFilterBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.TermFilterBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
import org.elasticsearch.index.query.functionscore.script.ScriptScoreFunctionBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHitField;
import org.elasticsearch.search.facet.Facet;
import org.elasticsearch.search.facet.FacetBuilders;
import org.elasticsearch.search.facet.Facets;
import org.elasticsearch.search.facet.range.RangeFacet;
import org.elasticsearch.search.facet.range.RangeFacetBuilder;
import org.elasticsearch.search.facet.terms.TermsFacet;
import org.elasticsearch.search.facet.terms.TermsFacet.ComparatorType;
import org.elasticsearch.search.facet.terms.TermsFacetBuilder;
import org.elasticsearch.search.rescore.RescoreBuilder;
import org.elasticsearch.search.rescore.RescoreBuilder.Rescorer;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.suggest.Suggest.Suggestion.Entry.Option;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.term.TermSuggestion;
import org.elasticsearch.search.suggest.term.TermSuggestionBuilder;
import org.jai.search.client.SearchClientService;
import org.jai.search.config.ElasticSearchIndexConfig;
import org.jai.search.model.AutoSuggestionEntry;
import org.jai.search.model.Category;
import org.jai.search.model.FacetResult;
import org.jai.search.model.FacetResultEntry;
import org.jai.search.model.Product;
import org.jai.search.model.ProductProperty;
import org.jai.search.model.ProductSearchResult;
import org.jai.search.model.SearchCriteria;
import org.jai.search.model.SearchDocumentFieldName;
import org.jai.search.model.SearchFacetName;
import org.jai.search.model.Specification;
import org.jai.search.query.ProductQueryService;
import org.jai.search.util.SearchDateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ProductQueryServiceImpl implements ProductQueryService {
@Autowired
private SearchClientService searchClientService;
private static final Logger logger = LoggerFactory
.getLogger(ProductQueryServiceImpl.class);
@Override
public ProductSearchResult searchProducts(
final SearchCriteria searchCriteria) {
final QueryBuilder queryBuilder = getQueryBuilder(searchCriteria);
final SearchRequestBuilder requestBuilder = getSearchRequestBuilder(
searchCriteria.getIndexes(), searchCriteria.getDocumentTypes(),
searchCriteria.getFrom(), searchCriteria.getSize());
requestBuilder.addFields(SearchDocumentFieldName.productQueryFields);
if (searchCriteria.isRescoreOnSoldOut()) {
final Rescorer rescorer = RescoreBuilder
.queryRescorer(
QueryBuilders.termQuery(
SearchDocumentFieldName.SOLD_OUT
.getFieldName(), false))
.setQueryWeight(1.0f) // default
.setRescoreQueryWeight(1.5f);
requestBuilder.setRescorer(rescorer);
}
if (searchCriteria.hasFilters()) {
final AndFilterBuilder andFilterBuilder = getFilterBuilderForSearchCriteria(searchCriteria);
requestBuilder.setQuery(QueryBuilders.filteredQuery(queryBuilder,
andFilterBuilder));
} else {
requestBuilder.setQuery(queryBuilder);
}
if (!searchCriteria.isNoFacets()
&& searchCriteria.getFacets().size() > 0) {
addFacets(searchCriteria, requestBuilder);
}
// Add sorting
if (searchCriteria.getSortOrder() != null) {
// First on given field
requestBuilder.addSort(SortBuilders
.fieldSort(
SearchDocumentFieldName.AVAILABLE_DATE
.getFieldName())
.order(searchCriteria.getSortOrder()).missing("_last"));
// then on score based
requestBuilder.addSort(SortBuilders.scoreSort());
}
logger.debug("Executing following search request:"
+ requestBuilder.internalBuilder().toString());
final SearchResponse searchResponse = requestBuilder.execute()
.actionGet();
printSearchResponseForDebug(searchResponse);
return getProductSearchResults(searchResponse);
}
@SuppressWarnings("unchecked")
@Override
public Product getProduct(final ElasticSearchIndexConfig config,
final Long productId) {
final GetResponse getResponse = searchClientService
.getClient()
.prepareGet(config.getIndexAliasName(),
config.getDocumentType(), String.valueOf(productId))
.setFields(SearchDocumentFieldName.productDocumentFields).get();
if (getResponse.isExists()) {
final Product product = new Product();
product.setId(Long.valueOf(getResponse.getId()));
product.setTitle(getResponse
.getField(SearchDocumentFieldName.TITLE.getFieldName())
.getValue().toString());
product.setDescription(getResponse
.getField(
SearchDocumentFieldName.DESCRIPTION.getFieldName())
.getValue().toString());
product.setSoldOut(Boolean.valueOf(getResponse
.getField(SearchDocumentFieldName.SOLD_OUT.getFieldName())
.getValue().toString()));
product.setAvailableOn(SearchDateUtils.getFormattedDate(getResponse
.getField(
SearchDocumentFieldName.AVAILABLE_DATE
.getFieldName()).getValue().toString()));
product.setKeywords(getListFieldValueOrNull(getResponse
.getField(SearchDocumentFieldName.KEYWORDS.getFieldName())));
product.setPrice(BigDecimal.valueOf(Double.valueOf(getResponse
.getField(SearchDocumentFieldName.PRICE.getFieldName())
.getValue().toString())));
product.setBoostFactor(Float.valueOf(getResponse
.getField(
SearchDocumentFieldName.BOOSTFACTOR.getFieldName())
.getValue().toString()));
final GetField catField = getResponse
.getField(SearchDocumentFieldName.CATEGORIES_ARRAY
.getFieldName());
if (catField != null) {
for (final Object ListOfMapValues : catField.getValues()) {
for (final java.util.Map.Entry<String, String> entry : ((Map<String, String>) ListOfMapValues)
.entrySet()) {
// Only main facet values should be set.key ending with
// a number.
if (entry.getKey().matches("^.*.facet$")) {
product.addCategory(new Category(entry.getValue(),
null, entry.getKey().split("\\.facet")[0]));
}
}
}
}
return product;
}
return null;
}
@Override
public List<AutoSuggestionEntry> getAutoSuggestions(
final ElasticSearchIndexConfig config, final String queryString) {
final TermSuggestionBuilder suggesBuilder = SuggestBuilder
.termSuggestion(SearchFacetName.AUTO_SUGGESTION.getCode())
.field(SearchDocumentFieldName.KEYWORDS.getFieldName())
.analyzer(config.getAutoSuggestionAnalyzerName()).size(20)
.text(queryString)
// .suggestMode("always")
// .stringDistance("ngram")
;
// CompletionSuggestionBuilder suggesBuilder = new
// CompletionSuggestionBuilder(SearchFacetName.AUTO_SUGGESTION.getCode())
// .field(SearchDocumentFieldName.KEYWORDS.getFieldName())
// .analyzer(config.getAutoSuggestionAnalyzerName())
// .size(20)
// .text(queryString)
// // .stringDistance("ngram")
// ;
// PhraseSuggestionBuilder suggesBuilder =
// SuggestBuilder.phraseSuggestion(SearchFacetName.AUTO_SUGGESTION.getCode())
// .field(SearchDocumentFieldName.TITLE.getFieldName())
// .analyzer(config.getAutoSuggestionAnalyzerName())
// .size(10)
// .text(queryString)
// ;
final SuggestRequestBuilder addSuggestion = searchClientService
.getClient().prepareSuggest(config.getIndexAliasName())
.addSuggestion(suggesBuilder);
try {
logger.debug("Auto Suggestion request is {}", suggesBuilder
.toXContent(jsonBuilder().startObject(), null)
.prettyPrint().string());
} catch (final IOException e) {
// Do nothing
logger.error("Error in to string", e);
}
final SuggestResponse suggestResponse = addSuggestion.get();
logger.debug("Auto Suggestion response is {}", suggestResponse);
final List<AutoSuggestionEntry> suggestions = new ArrayList<AutoSuggestionEntry>();
if (suggestResponse != null
&& suggestResponse.getSuggest() != null
&& suggestResponse.getSuggest().getSuggestion(
SearchFacetName.AUTO_SUGGESTION.getCode()) != null) {
for (final org.elasticsearch.search.suggest.Suggest.Suggestion.Entry<? extends Option> suggestEntry : suggestResponse
.getSuggest()
.getSuggestion(SearchFacetName.AUTO_SUGGESTION.getCode())
.getEntries()) {
for (final Option option : suggestEntry.getOptions()) {
final int count = ((TermSuggestion.Entry.Option) option)
.getFreq();
final AutoSuggestionEntry autoSuggestionEntry = new AutoSuggestionEntry(
option.getText().string(), count);
suggestions.add(autoSuggestionEntry);
}
}
}
return suggestions;
}
@Override
public List<AutoSuggestionEntry> getAutoSuggestionsUsingTermsFacet(
final ElasticSearchIndexConfig config, final String queryString) {
final List<AutoSuggestionEntry> autoSuggestEntries = new ArrayList<AutoSuggestionEntry>();
final SearchRequestBuilder searchRequestBuilder = searchClientService
.getClient().prepareSearch(config.getIndexAliasName())
.setTypes(config.getDocumentType()).setSize(0)
.setQuery(QueryBuilders.matchAllQuery());
final TermsFacetBuilder termsFacetBuilder = FacetBuilders
.termsFacet(SearchFacetName.AUTO_SUGGESTION.getCode());
final String[] fieldsArray = new String[SearchFacetName.autoSuggestionFields
.size() + 1];
SearchFacetName.autoSuggestionFields.toArray(fieldsArray);
fieldsArray[fieldsArray.length - 1] = SearchDocumentFieldName.KEYWORDS
.getFieldName();
termsFacetBuilder.fields(fieldsArray);
final String lowerCaseQueryString = queryString.toLowerCase();
final String filteredSpecialCharsQueryString = escapeQueryChars(lowerCaseQueryString);
final String matchingRegExString = filteredSpecialCharsQueryString
+ ".*";
termsFacetBuilder.regex(matchingRegExString).size(20)
.order(ComparatorType.TERM);
searchRequestBuilder.addFacet(termsFacetBuilder);
logger.debug("Auto Suggestion request is {}", searchRequestBuilder
.internalBuilder().toString());
final SearchResponse searchResponse = searchRequestBuilder.get();
try {
logger.debug("Auto Suggestion response is {}", searchResponse
.toXContent(jsonBuilder().startObject(), null)
.prettyPrint().string());
} catch (final IOException e) {
logger.error("Search response tostring error:", e);
}
final Facets facets = searchResponse.getFacets();
for (final Facet facet : facets) {
if (facet.getName().equals(
SearchFacetName.AUTO_SUGGESTION.getCode())) {
final TermsFacet termsFacet = (TermsFacet) facet;
for (final org.elasticsearch.search.facet.terms.TermsFacet.Entry entry : termsFacet
.getEntries()) {
final AutoSuggestionEntry term = new AutoSuggestionEntry(
entry.getTerm().string(), entry.getCount());
autoSuggestEntries.add(term);
}
}
}
return autoSuggestEntries;
}
@Override
public List<Product> findSimilarProducts(
final ElasticSearchIndexConfig config, final String[] fields,
final Long productId) {
final MoreLikeThisRequestBuilder moreLikeThisRequestBuilder = searchClientService
.getClient()
.prepareMoreLikeThis(config.getIndexAliasName(),
config.getDocumentType(), String.valueOf(productId))
.setField(fields).setMinDocFreq(1).setMinTermFreq(1)
.setSearchSize(10);
logger.debug("Executing following search request, fields {}",
new Object[] { moreLikeThisRequestBuilder.request().fields() });
final SearchResponse searchResponse = moreLikeThisRequestBuilder.get();
printSearchResponseForDebug(searchResponse);
final List<Product> products = new ArrayList<Product>();
for (final SearchHit searchHit : searchResponse.getHits()) {
final Product product = new Product();
product.setId(Long.valueOf(searchHit.getId()));
product.setTitle(searchHit.getSource()
.get(SearchDocumentFieldName.TITLE.getFieldName())
.toString());
product.setPrice(BigDecimal.valueOf(Double.valueOf(searchHit
.getSource()
.get(SearchDocumentFieldName.PRICE.getFieldName())
.toString())));
product.setSoldOut(Boolean.valueOf(searchHit.getSource()
.get(SearchDocumentFieldName.SOLD_OUT.getFieldName())
.toString()));
products.add(product);
}
return products;
}
private AndFilterBuilder getFilterBuilderForSearchCriteria(
final SearchCriteria searchCriteria) {
final AndFilterBuilder andFilterBuilder = FilterBuilders.andFilter();
// process single select filters
for (final java.util.Map.Entry<String, String> entry : searchCriteria
.getSingleSelectFilters().entrySet()) {
andFilterBuilder.add(getBaseFilterBuilder(entry.getKey(),
entry.getValue()));
}
// process field value filters
// Processing logic for field values
final List<Map<String, Object>> fieldValueFilters = searchCriteria
.getFieldValueFilters();
if (fieldValueFilters.size() > 0) {
// process multiple entries in or filter
final OrFilterBuilder orFilterForFieldValueList = FilterBuilders
.orFilter();
// processing of fieldValueFilters is following:
// each list of filter items containing in fieldValueFilters joins
// with 'OR'
// each filter item in list joins with 'AND'
for (final Map<String, Object> filterItems : fieldValueFilters) {
// process all entries in map in and operation.
final AndFilterBuilder andFilterBuilderForFieldValueMapInList = FilterBuilders
.andFilter();
for (final Entry<String, Object> entry : filterItems.entrySet()) {
// retrieve filter builder
final FilterBuilder filterBuilder = getTermFilter(
entry.getKey(), String.valueOf(entry.getValue()));
// add to and condition
andFilterBuilderForFieldValueMapInList.add(filterBuilder);
}
orFilterForFieldValueList
.add(andFilterBuilderForFieldValueMapInList);
}
andFilterBuilder.add(orFilterForFieldValueList);
}
// process multi select filters
for (final java.util.Map.Entry<String, List<String>> entry : searchCriteria
.getMultiSelectFilters().entrySet()) {
// Empty list, continue to next one.
// Only process multi select other than specifications
// (resolution/memory)
if (entry.getValue().size() == 0
|| entry.getKey().equals(
SearchFacetName.SPECIFICATION_RESOLUTION.getCode())
|| entry.getKey().endsWith(
SearchFacetName.SPECIFICATION_MEMORY.getCode())) {
continue;
}
if (entry.getValue().size() > 1) {
// process multiple entries in or filter
final OrFilterBuilder orFilter = FilterBuilders.orFilter();
for (final String filterName : entry.getValue()) {
orFilter.add(getBaseFilterBuilder(entry.getKey(),
filterName));
}
andFilterBuilder.add(orFilter);
} else {
// process single entry directly in and filter
andFilterBuilder.add(getBaseFilterBuilder(entry.getKey(), entry
.getValue().get(0)));
}
}
// process resolution/memory facets
andFilterBuilder.add(FilterBuilders.nestedFilter(
SearchDocumentFieldName.SPECIFICATIONS.getFieldName(),
getSpecificationsFacetFilterBuilder(searchCriteria)));
// process child product properties
if (searchCriteria.getProductProperties().size() > 0) {
FilterBuilder propertyFilterBuilder = null;
if (searchCriteria.getProductProperties().size() > 1) {
final OrFilterBuilder OrPropertyFilterBuilder1 = FilterBuilders
.orFilter();
for (final ProductProperty productProperty : searchCriteria
.getProductProperties()) {
final AndFilterBuilder andPropertyTermFilter = FilterBuilders
.andFilter(
FilterBuilders.termFilter(
SearchDocumentFieldName.SIZE
.getFieldName(),
productProperty.getSize()
.toLowerCase()),
FilterBuilders.termFilter(
SearchDocumentFieldName.COLOR
.getFieldName(),
productProperty.getColor()
.toLowerCase()));
OrPropertyFilterBuilder1.add(andPropertyTermFilter);
}
propertyFilterBuilder = OrPropertyFilterBuilder1;
} else {
final ProductProperty productProperty = searchCriteria
.getProductProperties().get(0);
propertyFilterBuilder = FilterBuilders.andFilter(FilterBuilders
.termFilter(
SearchDocumentFieldName.SIZE.getFieldName(),
productProperty.getSize()), FilterBuilders
.termFilter(
SearchDocumentFieldName.COLOR.getFieldName(),
productProperty.getColor()));
}
final FilteredQueryBuilder filteredQueryBuilder = new FilteredQueryBuilder(
QueryBuilders.matchAllQuery(), propertyFilterBuilder);
// TODO: config replace
andFilterBuilder
.add(FilterBuilders.hasChildFilter(
ElasticSearchIndexConfig.COM_WEBSITE
.getPropertiesDocumentType(),
filteredQueryBuilder));
}
// Another approach for specifications, in case faceting not used.
if (searchCriteria.getSpecifications().size() > 0) {
FilterBuilder specificationFilterBuilder = null;
specificationFilterBuilder = getSpecificationsFilterBuilder(searchCriteria);
andFilterBuilder.add(FilterBuilders.nestedFilter(
SearchDocumentFieldName.SPECIFICATIONS.getFieldName(),
specificationFilterBuilder));
}
return andFilterBuilder;
}
private FilterBuilder getSpecificationsFilterBuilder(
final SearchCriteria searchCriteria) {
// This is used in case you want to search items based on specifications
// itself.
FilterBuilder specificationFilterBuilder;
final List<Specification> specifications = searchCriteria
.getSpecifications();
if (specifications.size() > 1) {
final OrFilterBuilder OrSpecificationFilterBuilder = FilterBuilders
.orFilter();
for (final Specification specification : specifications) {
final FilterBuilder filterBuilder = FilterBuilders.andFilter(
FilterBuilders.termFilter(
SearchDocumentFieldName.RESOLUTION
.getFieldName(), specification
.getResolution()), FilterBuilders
.termFilter(SearchDocumentFieldName.MEMORY
.getFieldName(), specification
.getMemory()));
OrSpecificationFilterBuilder.add(filterBuilder);
}
specificationFilterBuilder = OrSpecificationFilterBuilder;
} else {
final Specification specification = searchCriteria
.getSpecifications().get(0);
final FilterBuilder filterBuilder = FilterBuilders
.andFilter(FilterBuilders.termFilter(
SearchDocumentFieldName.RESOLUTION.getFieldName(),
specification.getResolution()), FilterBuilders
.termFilter(SearchDocumentFieldName.MEMORY
.getFieldName(), specification.getMemory()));
specificationFilterBuilder = filterBuilder;
}
return specificationFilterBuilder;
}
private FilterBuilder getSpecificationsFacetFilterBuilder(
final SearchCriteria searchCriteria) {
// This is used in case you want to search based on separate
// resolution/memory facets
final Map<String, List<String>> multiSelectFilters = searchCriteria
.getMultiSelectFilters();
final List<String> resolutionFilters = new ArrayList<String>();
final List<String> memoryFilters = new ArrayList<String>();
for (final Entry<String, List<String>> entry : multiSelectFilters
.entrySet()) {
if (entry.getKey().equals(
SearchFacetName.SPECIFICATION_RESOLUTION.getCode())) {
resolutionFilters.addAll(entry.getValue());
} else if (entry.getKey().equals(
SearchFacetName.SPECIFICATION_MEMORY.getCode())) {
memoryFilters.addAll(entry.getValue());
}
}
if (resolutionFilters.size() == 0 && memoryFilters.size() == 0) {
return FilterBuilders.queryFilter(QueryBuilders.matchAllQuery());
}
final AndFilterBuilder andResolutionAndMemoryFilterBuilder = FilterBuilders
.andFilter();
if (resolutionFilters.size() > 0) {
final OrFilterBuilder OrResolutionFilterBuilder = FilterBuilders
.orFilter();
for (final String resolution : resolutionFilters) {
OrResolutionFilterBuilder.add(FilterBuilders.termFilter(
SearchDocumentFieldName.RESOLUTION.getFieldName(),
resolution));
}
andResolutionAndMemoryFilterBuilder.add(OrResolutionFilterBuilder);
}
if (memoryFilters.size() > 0) {
final OrFilterBuilder OrMemoryFilterBuilder = FilterBuilders
.orFilter();
for (final String memory : memoryFilters) {
OrMemoryFilterBuilder.add(FilterBuilders.termFilter(
SearchDocumentFieldName.MEMORY.getFieldName(), memory));
}
andResolutionAndMemoryFilterBuilder.add(OrMemoryFilterBuilder);
}
// else if(specifications.size() == 1)
// {
// Specification specification =
// searchCriteria.getSpecifications().get(0);
//
// FilterBuilder filterBuilder = FilterBuilders.andFilter(FilterBuilders
// .termFilter(SearchDocumentFieldName.RESOLUTION.getFieldName(),
// specification.getResolution()),
// FilterBuilders.termFilter(SearchDocumentFieldName.MEMORY.getFieldName(),
// specification.getMemory()));
//
// specificationFilterBuilder = filterBuilder;
// }
// else
// {
// specificationFilterBuilder = FilterBuilders.matchAllFilter();
// }
return andResolutionAndMemoryFilterBuilder;
}
private FilterBuilder getBaseFilterBuilder(final String facetName,
final String fieldValue) {
if (facetName
.startsWith(SearchFacetName.SEARCH_FACET_TYPE_FACET_PREFIX)) {
return getTermFilter(
SearchFacetName.CATEGORIES_FIELD_PREFIX
+ facetName
+ "."
+ SearchDocumentFieldName.FACETFILTER
.getFieldName(),
fieldValue.toLowerCase());
} else if (facetName.startsWith(SearchFacetName.PRODUCT_PRICE_RANGE
.getCode())) {
return FilterBuilders
.rangeFilter(SearchDocumentFieldName.PRICE.getFieldName())
.includeLower(true).includeUpper(false)
.from(fieldValue.split("-")[0])
.to(fieldValue.split("-")[1]);
} else {
return FilterBuilders.termFilter(facetName, fieldValue);
}
// return null;
}
private TermFilterBuilder getTermFilter(final String fieldName,
final String fieldValue) {
return FilterBuilders.termFilter(fieldName, fieldValue);
}
private void addFacets(final SearchCriteria searchCriteria,
final SearchRequestBuilder requestBuilder) {
for (final String facetCode : searchCriteria.getFacets()) {
if (SearchFacetName.categoryFacetFields.contains(facetCode)) {
requestBuilder.addFacet(getNewTermsFacet(facetCode, facetCode
+ "." + SearchDocumentFieldName.FACET.getFieldName()));
} else if (SearchFacetName.PRODUCT_PRICE_RANGE.getCode().equals(
facetCode)) {
requestBuilder.addFacet(getPriceRangeFacet(facetCode));
} else if (SearchFacetName.PRODUCT_PROPERTY_SIZE.getCode().equals(
facetCode)
|| SearchFacetName.PRODUCT_PROPERTY_COLOR.getCode().equals(
facetCode)) {
// QueryBuilder filter = HasChildFilterBuilder;
// HasParentFilterBuilder hasParentFilter =
// FilterBuilders.hasParentFilter(ElasticSearchIndexConfig.COM_WEBSITE.getDocumentType(),
// QueryBuilders.matchAllQuery());
//
// String field =
// SearchFacetName.PRODUCT_PROPERTY_SIZE.getCode().equals(facetfield)
// ?
// SearchDocumentFieldName.SIZE.getFieldName() :
// SearchDocumentFieldName.COLOR.getFieldName();
// requestBuilder.addFacet(FacetBuilders.termsFacet(facetfield).field(field).facetFilter(hasParentFilter));
} else if (SearchFacetName.SPECIFICATION_RESOLUTION.getCode()
.equals(facetCode)) {
// TODO, not working
// NestedFilterBuilder nestedFilterBuilder =
// FilterBuilders.nestedFilter(SearchDocumentFieldName.SPECIFICATIONS.getFieldName(),
// getSpecificationsFacetFilterBuilder(searchCriteria)).join(false);
final NestedFilterBuilder nestedFilterBuilder = FilterBuilders
.nestedFilter(
SearchDocumentFieldName.SPECIFICATIONS
.getFieldName(),
FilterBuilders.matchAllFilter()).join(false);
final TermsFacetBuilder facetFilter = FacetBuilders
.termsFacet(facetCode)
.field(SearchDocumentFieldName.SPECIFICATIONS
.getFieldName()
+ "."
+ SearchDocumentFieldName.RESOLUTION
.getFieldName())
.facetFilter(nestedFilterBuilder)
.nested(SearchDocumentFieldName.SPECIFICATIONS
.getFieldName());
requestBuilder.addFacet(facetFilter);
} else if (SearchFacetName.SPECIFICATION_MEMORY.getCode().equals(
facetCode)) {
// TODO, not working
final NestedFilterBuilder nestedFilterBuilder = FilterBuilders
.nestedFilter(
SearchDocumentFieldName.SPECIFICATIONS
.getFieldName(),
FilterBuilders.matchAllFilter()).join(false);
final TermsFacetBuilder facetFilter = FacetBuilders
.termsFacet(facetCode)
.field(SearchDocumentFieldName.SPECIFICATIONS
.getFieldName()
+ "."
+ SearchDocumentFieldName.MEMORY.getFieldName())
.facetFilter(nestedFilterBuilder)
.nested(SearchDocumentFieldName.SPECIFICATIONS
.getFieldName());
requestBuilder.addFacet(facetFilter);
}
}
}
private RangeFacetBuilder getPriceRangeFacet(final String facetCode) {
return FacetBuilders.rangeFacet(facetCode)
.field(SearchDocumentFieldName.PRICE.getFieldName())
.addRange(0, 10).addRange(10, 20).addRange(20, 100);
}
protected TermsFacetBuilder getNewTermsFacet(final String facetName,
final String facetField) {
final TermsFacetBuilder termsFacetBuilder = new TermsFacetBuilder(
facetName);
termsFacetBuilder.field(facetField);
termsFacetBuilder.order(ComparatorType.TERM);
termsFacetBuilder.size(100);
return termsFacetBuilder;
}
private ProductSearchResult getProductSearchResults(
final SearchResponse response) {
logger.debug("Total search hits returned for the query totalHits:"
+ response.getHits().getTotalHits());
final ProductSearchResult productSearchResult = new ProductSearchResult();
productSearchResult.setTotalCount(response.getHits().totalHits());
for (final SearchHit searchHit : response.getHits()) {
final Product product = new Product();
product.setId(Long.valueOf(searchHit.getId()));
product.setTitle(getFieldValueOrNull(searchHit,
SearchDocumentFieldName.TITLE.getFieldName()));
product.setPrice(BigDecimal.valueOf(getDoubleFieldValueOrNull(
searchHit, SearchDocumentFieldName.PRICE.getFieldName())));
product.setSoldOut(Boolean.valueOf(getFieldValueOrNull(searchHit,
SearchDocumentFieldName.SOLD_OUT.getFieldName())));
productSearchResult.addProduct(product);
}
if (response.getFacets() != null) {
for (final Facet facet : response.getFacets()) {
final FacetResult facetResult = new FacetResult();
facetResult.setCode(facet.getName());
if (TermsFacet.TYPE.equals(facet.getType())) {
final TermsFacet termsFacet = (TermsFacet) facet;
if (termsFacet.getEntries().size() == 0) {
continue;
}
for (final TermsFacet.Entry entry : termsFacet.getEntries()) {
final FacetResultEntry facetResultEntry = new FacetResultEntry();
// final String term =
// entry.getTerm().substring(entry.getTerm().indexOf("_")
// + 1);
facetResultEntry.setTerm(entry.getTerm().string());
facetResultEntry.setCount(entry.getCount());
facetResult.addFacetResultEntry(facetResultEntry);
}
} else if (RangeFacet.TYPE.equals(facet.getType())) {
final RangeFacet rangeFacet = (RangeFacet) facet;
if (rangeFacet.getEntries().size() == 0) {
continue;
}
for (final RangeFacet.Entry entry : rangeFacet.getEntries()) {
final FacetResultEntry facetResultEntry = new FacetResultEntry();
facetResultEntry.setTerm(entry.getFromAsString()
+ " - " + entry.getToAsString());
facetResultEntry.setCount(entry.getCount());
facetResult.addFacetResultEntry(facetResultEntry);
}
} else {
// NOT supported
}
productSearchResult.addFacet(facetResult);
}
}
logger.debug("Total Product created from response:"
+ productSearchResult.getProducts().size());
return productSearchResult;
}
protected String getFieldValueOrNull(final SearchHit searchHit,
final String fieldName) {
final SearchHitField searchHitField = searchHit.field(fieldName);
if (searchHitField != null && searchHitField.value() != null) {
return searchHitField.value().toString();
}
return null;
}
protected Double getDoubleFieldValueOrNull(final SearchHit searchHit,
final String fieldName) {
final SearchHitField searchHitField = searchHit.field(fieldName);
if (searchHitField != null && searchHitField.value() != null) {
return Double.valueOf(searchHitField.value().toString());
}
return null;
}
protected void printSearchResponseForDebug(final SearchResponse response) {
try {
if (logger.isDebugEnabled()) {
logger.debug("Search response:"
+ response
.toXContent(
jsonBuilder().startObject()
.prettyPrint(), null)
.prettyPrint().string());
}
} catch (final IOException ex) {
// ignore
logger.error(
"Error occured while printing search response for debug.",
ex);
}
}
protected QueryBuilder getQueryBuilder(final SearchCriteria searchCriteria) {
QueryBuilder matchQueryBuilder = null;
final String queryString = searchCriteria.getQuery();
if (StringUtils.isBlank(queryString)) {
matchQueryBuilder = QueryBuilders.matchAllQuery();
} else {
final String filterSpecialCharsQueryString = escapeQueryChars(queryString);
final QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders
.queryString(filterSpecialCharsQueryString);
// Add fields
queryStringQueryBuilder.field(
SearchDocumentFieldName.TITLE.getFieldName(), (float) 0.5)
.field(SearchDocumentFieldName.DESCRIPTION.getFieldName(),
(float) 0.15);
for (final String contentCategoryFieldName : SearchFacetName.categoryFacetFields) {
queryStringQueryBuilder.field(
SearchDocumentFieldName.CATEGORIES_ARRAY.getFieldName()
+ "." + contentCategoryFieldName, 1);
}
matchQueryBuilder = queryStringQueryBuilder;
}
if (searchCriteria.isUseBoostingFactor()) {
final FunctionScoreQueryBuilder queryBuilder = new FunctionScoreQueryBuilder(
matchQueryBuilder);
final ScoreFunctionBuilder scoreFunctionBuilder = new ScriptScoreFunctionBuilder()
.script(SearchDocumentFieldName
.getCalculatedScoreScriptForBostFactor());
queryBuilder.add(scoreFunctionBuilder);
return queryBuilder;
}
return matchQueryBuilder;
}
protected SearchRequestBuilder getSearchRequestBuilder(
final String[] indexName, final String[] types, final int from,
final int size) {
final SearchRequestBuilder requestBuilder = searchClientService
.getClient().prepareSearch(indexName).setTypes(types)
.setFrom(from).setSize(size);
return requestBuilder;
}
private String escapeQueryChars(final String queryString) {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < queryString.length(); i++) {
final char c = queryString.charAt(i);
// These characters are part of the query syntax and must be escaped
// The list if retrieved from Solr escape characters.
if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '('
|| c == ')' || c == ':' || c == '^' || c == '[' || c == ']'
|| c == '\"' || c == '{' || c == '}' || c == '~'
|| c == '*' || c == '?' || c == '|' || c == '&' || c == ';'
|| c == '/' || Character.isWhitespace(c)) {
sb.append('\\');
}
sb.append(c);
}
return sb.toString();
}
protected String getStringFieldValue(final GetField field) {
if (field != null) {
return String.valueOf(field.getValue());
}
return null;
}
protected Date getDateFieldValueOrNull(final GetField field) {
if (field != null) {
final String dateString = String.valueOf(field.getValue());
if (dateString != null && !dateString.isEmpty()) {
return SearchDateUtils.getFormattedDate(dateString);
}
}
return null;
}
protected boolean getBooleanFieldValueOrFalse(final GetField field) {
if (field != null) {
return Boolean.valueOf(String.valueOf(field.getValue()));
}
return false;
}
@SuppressWarnings("unchecked")
protected List<String> getListFieldValueOrNull(final GetField field) {
if (field != null) {
final List<String> list = new ArrayList<String>();
for (final Object object : field.getValues()) {
if (object instanceof List) {
for (final String valueString : (List<String>) object) {
list.add(String.valueOf(valueString));
}
} else {
list.add(String.valueOf(object));
}
}
return list;
}
return null;
}
}