blob: c6d8d81548775f3bb9dcf99e913da398f3a5777a [file] [log] [blame]
/***********************************************************************************************************************
* Copyright (c) 2008 empolis GmbH and brox IT Solutions GmbH. All rights reserved. This program and the accompanying
* materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors: Peter Wissel (brox IT Solutions GmbH) - initial API and implementation
**********************************************************************************************************************/
package org.eclipse.smila.solr.search;
import static java.lang.String.format;
import static org.apache.commons.lang.StringUtils.defaultString;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.apache.commons.lang.StringUtils.startsWith;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.collections.Factory;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrQuery.ORDER;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.FacetParams;
import org.apache.solr.common.params.GroupParams;
import org.apache.solr.common.params.ShardParams;
import org.eclipse.smila.datamodel.Any;
import org.eclipse.smila.datamodel.AnyMap;
import org.eclipse.smila.datamodel.AnySeq;
import org.eclipse.smila.datamodel.InvalidValueTypeException;
import org.eclipse.smila.datamodel.Value;
import org.eclipse.smila.datamodel.impl.DefaultDataFactoryImpl;
import org.eclipse.smila.search.api.QueryConstants;
import org.eclipse.smila.solr.SolrConstants;
import org.eclipse.smila.solr.util.SolrQueryUtils;
/**
* This class converts a smila's solr search record into a solr(j) query.
*
* @author tmenzel
*
*/
public class SolrQueryConverter {
private static final String SOLR_LOCAL_PARAMS_OPERATOR = "o.op";
private static final String SMILA_RANKING_PARAMETER_OPERATOR = "Operator";
/** The logger. */
protected final org.apache.commons.logging.Log _log = org.apache.commons.logging.LogFactory.getLog(this
.getClass());
/** holds the filter groups, keyed by their name. */
private final Map<String, FilterGroup> _filterGroups;
/**
* shared buffer to build the query strings and obtained thru {@link #resetBuffer()}.
*/
private transient StringBuilder _buffer = new StringBuilder(0xfff);
/**
* The SolrQueryParameterAccessor.
*/
private final SolrQueryParameterAccessor _accessor;
/**
* The SolrQuery.
*/
private final SolrQuery _solrQuery = new SolrQuery();
/**
* Constructor.
*
* @param accessor
* the solr query parameter accessor.
*/
@SuppressWarnings("unchecked")
public SolrQueryConverter(final SolrQueryParameterAccessor accessor) {
_accessor = accessor;
_filterGroups = LazyMap.decorate(new HashMap<String, FilterGroup>(), new Factory() {
@Override
public Object create() {
return new FilterGroup();
}
});
}
/**
* Convert the record to a solr query string.
*
* @return the SolrQuery.
*/
public SolrQuery toSolrQuery(final List<String> schemaAttributes) {
final String qt = _accessor.getRequestHandler();
_solrQuery.setQueryType(qt);
doQuery(schemaAttributes);
doSortOrder();
doTermsSettings();
doSmilaFilters();
doFacetSettings();
doFilterGroups();
doGroupSettings();
if (_solrQuery.getQuery() != null || _solrQuery.getFields() != null) {
doQuerySettings();
doHighlightingSettings();
doShardsSettings();
doSpellCheckSettings();
doMoreLikeThis();
}
final AnyMap map = _accessor.getSolrQueryParams().getMap(QueryConstants.NATIVE_PARAMETERS);
addAsSolrParameters(map);
return _solrQuery;
}
/**
* Build the query string. Takes it either from smila's query string and which must be then a native solr query OR if
* that is empty, constructs one from smila's fielded search syntax.
*/
private void doQuery(final List<String> schemaAttributes) {
final String q = _accessor.getQuery();
if (StringUtils.isNotEmpty(q)) {
_filterGroups.get(SolrConstants.FILTER_GROUP_Q).filterStrings.add(q);
} else {
// search in dedicated fields instead of simple query string
if (schemaAttributes != null && !schemaAttributes.isEmpty()) {
final StringBuilder fieldQuery = resetBuffer();
for (final String field : schemaAttributes) {
final List<Value> fieldQueryValues = _accessor.getQueryAttributeValues(field);
if (fieldQueryValues != null) {
// there seems to be no SolrQuery API for querying
// fields so we have to build our query manually
SolrQueryUtils.appendFieldQueryPart(fieldQuery, field, fieldQueryValues);
}
}
final String fq = fieldQuery.toString().trim();
if (StringUtils.isNotEmpty(fq)) {
_filterGroups.get(SolrConstants.FILTER_GROUP_Q).filterStrings.add(fq);
}
}
}
if (_filterGroups.containsKey(SolrConstants.FILTER_GROUP_Q)) {
// set operator via localParams (o.op) from SMILA ranking
final Any ranking = _accessor.getRankingConfig();
if (ranking != null) {
final Value value = ranking.asMap().getValue(SMILA_RANKING_PARAMETER_OPERATOR);
if (value != null) {
_filterGroups.get(SolrConstants.FILTER_GROUP_Q).localParams.put(SOLR_LOCAL_PARAMS_OPERATOR, value);
}
}
}
}
/**
* Do query settings such as offset, maxCount, ...
*/
private void doQuerySettings() {
// Paging
final int start = _accessor.getOffset();
_solrQuery.setStart(start);
final int rows = _accessor.getMaxCount();
_solrQuery.setRows(rows);
// Field list
final String[] fl = _accessor.getResultAttributes().toArray(new String[_accessor.getResultAttributes().size()]);
_solrQuery.setFields(fl);
// TODO: setIncludeScore is evidently not working, add score field
// manually.
// _solrQuery.setIncludeScore(true);
// must always have these or else building the result will fail
_solrQuery.addField(SolrConstants.CORE_FIELD_SCORE);
_solrQuery.addField(SolrConstants.CORE_FIELD_ID);
}
/**
*
*/
private void doSortOrder() {
// for (Entry<String, SortOrder> item :
// _accessor.getSortByConfig().entrySet()) {
// final ORDER sortOrder = item.getValue() == SortOrder.ASCENDING ?
// ORDER.asc : ORDER.desc;
// _solrQuery.addSortField(item.getKey(), sortOrder);
// }
// faster impl. than above but more prone to migration changes
final List<AnyMap> annotations = _accessor.getSubParameters(QueryConstants.SORTBY);
if (annotations != null) {
for (final AnyMap annotation : annotations) {
final String attributeName = annotation.getStringValue(QueryConstants.ATTRIBUTE);
final String orderModeValue = annotation.getStringValue(QueryConstants.ORDER);
if (startsWith(orderModeValue, "asc")) {
_solrQuery.addSortField(attributeName, ORDER.asc);
} else {
_solrQuery.addSortField(attributeName, ORDER.desc);
}
}
}
}
/**
* process the filter groups by ANDing all parts and prefixng the tags. Note, that the main query q is also a special
* filter group.
*/
private void doFilterGroups() {
// process the
for (final Entry<String, FilterGroup> entry : _filterGroups.entrySet()) {
final FilterGroup filterGroup = entry.getValue();
final String groupName = entry.getKey();
final StringBuilder fq = resetBuffer();
// local params
appendLocalParams(fq, _accessor.getFilterLocalParams(groupName, false), filterGroup.localParams);
// make all fq parts as MUST (ANDing)
switch (filterGroup.filterStrings.size()) {
case 0:
throw new IllegalStateException();
case 1:
fq.append(filterGroup.filterStrings.get(0));
break;
default:
for (final String part : filterGroup.filterStrings) {
if (!("*:*".equals(part) || isBlank(part))) {
fq.append("+(");
fq.append(part);
fq.append(")");
}
}
}
final String solrQueryString = fq.toString();
if (SolrConstants.FILTER_GROUP_Q.equals(groupName)) {
_solrQuery.setQuery(solrQueryString);
} else {
_solrQuery.addFilterQuery(solrQueryString);
}
if (_log.isTraceEnabled()) {
_log.trace(format("adding filter group: %s=%s", groupName, solrQueryString));
} // if
}
addFilterSolrSyntax();
}
/**
* Adds the filter in smila syntax to the filter groups.
*/
private void doSmilaFilters() {
if (!_accessor.hasFilters()) {
return;
}
// Iterate over all filter configurations
final List<AnyMap> filters = _accessor.getSubParameters(QueryConstants.FILTER);
for (int filterConfigIndex = 0; filterConfigIndex < filters.size(); filterConfigIndex++) {
final AnyMap filterConfig = filters.get(filterConfigIndex);
final String attribute = filterConfig.getStringValue(QueryConstants.ATTRIBUTE);
if (StringUtils.isEmpty(attribute)) {
final String msg =
MessageFormat.format("Skip filter configuration at index: {0}. No attribute defined", filterConfigIndex);
_log.warn(msg);
continue;
}
final String groupName = defaultString(filterConfig.getStringValue(SolrConstants.FILTER_GROUP), attribute);
// Add filter query to matching StringBuilder
final StringBuilder fq = resetBuffer();
// addLocalParams(fq, localParams);
addFilterSmilaSyntax(fq, attribute, filterConfig, filterConfigIndex);
_filterGroups.get(groupName).filterStrings.add(fq.toString());
}
}
/**
* adds the filters for the given attribute.
*/
private void addFilterSmilaSyntax(final StringBuilder fq, final String attribute, final AnyMap filter,
final int index) {
for (final Entry<String, Any> condition : filter.entrySet()) {
final String filterType = condition.getKey();
if (QueryConstants.ATTRIBUTE.equals(filterType) || SolrConstants.FILTER_GROUP.equals(filterType)) {
continue;
} else if (QueryConstants.FILTER_ONEOF.equals(filterType)) {
final AnySeq values = condition.getValue().asSeq();
appendFilterSetExpression(fq, attribute, values, "");
} else if (QueryConstants.FILTER_ALLOF.equals(filterType)) {
final AnySeq values = condition.getValue().asSeq();
appendFilterSetExpression(fq, attribute, values, "+");
} else if (QueryConstants.FILTER_NONEOF.equals(filterType)) {
final AnySeq values = condition.getValue().asSeq();
appendFilterSetExpression(fq, attribute, values, "-");
} else if (QueryConstants.FILTER_ATLEAST.equals(filterType)) {
final String value = condition.getValue().asValue().asString();
appendFilterRangeExpression(fq, attribute, value, "*", false);
} else if (QueryConstants.FILTER_GREATERTHAN.equals(filterType)) {
final String value = condition.getValue().asValue().asString();
appendFilterRangeExpression(fq, attribute, value, "*", true);
} else if (QueryConstants.FILTER_ATMOST.equals(filterType)) {
final String value = condition.getValue().asValue().asString();
appendFilterRangeExpression(fq, attribute, "*", value, false);
} else if (QueryConstants.FILTER_LESSTHAN.equals(filterType)) {
final String value = condition.getValue().asValue().asString();
appendFilterRangeExpression(fq, attribute, "*", value, true);
} else {
_log.warn(format("unknown (filter) element in filters encountered on attribute %s: %s[%s]. It is ignored.",
attribute, filterType, index));
}
if (fq.length() == 0) {
_log.warn(format("Filter on attribute %s: %s[%d] has no values and is ignored!", attribute, filterType,
index));
} else {
final String fqString = fq.toString();
if (_log.isDebugEnabled()) {
_log.debug(format("Filter converted from Smila Syntax on attribute %s: %s[%d]: %s", attribute,
filterType, index, fqString));
} // if
}
}
}
/**
* @param attribute
* @param fq
*/
private void appendFilterRangeExpression(final StringBuilder fq, final String attribute, String lower,
String upper, final boolean exclusive) {
if (isBlank(lower)) {
throw new IllegalArgumentException("lower bound must not be blank");
}
if (isBlank(upper)) {
throw new IllegalArgumentException("upper bound must not be blank");
}
lower = appendFilterRangeExpressionBoundExclusionIfNotStar(fq, attribute, lower, exclusive);
upper = appendFilterRangeExpressionBoundExclusionIfNotStar(fq, attribute, upper, exclusive);
fq.append(" +(");
fq.append(attribute);
fq.append(":[");
fq.append(lower);
fq.append(" TO ");
fq.append(upper);
fq.append("])");
}
/**
* appends a not expresion if a range bound if it is {@code != "*" } and exlusive is true.
*/
private String appendFilterRangeExpressionBoundExclusionIfNotStar(final StringBuilder fq, final String attribute,
String value, final boolean exclusive) {
if (!"*".equals(value)) {
value = SolrQueryUtils.escapeQuery(value, SolrQueryUtils.ESCAPE_CHARS_WS);
// in case of exclusive we must add a NOT query
if (exclusive) {
fq.append(" -(");
fq.append(attribute);
fq.append(":");
fq.append(value);
fq.append(")");
}
}
return value;
}
/**
* converts the smila filter syntax into lucene's for the filters: oneOf, noneOf, allOf.
*
* @param fq
* the fq
* @param attribute
* the attribute
* @param values
* @param operator
* of of '+', '-', "" (for OR == oneOf)
*/
private void appendFilterSetExpression(final StringBuilder fq, final String attribute, final AnySeq values,
final String operator) {
final List<String> filterValues;
try {
filterValues = values.asStrings();
} catch (final InvalidValueTypeException e) {
throw new InvalidValueTypeException(
"Filter Syntax Error: Filter must be of Type Seq and contain only Val elements.", e);
}
for (final String filterValue : filterValues) {
final String filterValueEscaped = SolrQueryUtils.escapeQuery(filterValue, SolrQueryUtils.ESCAPE_CHARS_WS);
fq.append(operator);
fq.append("(");
fq.append(attribute);
fq.append(":");
fq.append(filterValueEscaped);
fq.append(")");
}
}
/**
* just adds all {@link SolrConstants#QUERY_MAP}/fq Vals as filters to solr.
*/
private void addFilterSolrSyntax() {
final AnySeq filterQueries = _accessor.getFilterQuery();
if (filterQueries != null && filterQueries.size() > 0) {
final String[] fq = filterQueries.asStrings().toArray(new String[filterQueries.size()]);
_solrQuery.setFilterQueries(fq);
}
}
/**
* Do facet settings.
*/
private void doFacetSettings() {
final List<AnyMap> facetByConfigs = _accessor.getFacetByConfig();
if (facetByConfigs.isEmpty()) {
return;
}
// turn on facetting if the map is present
_solrQuery.add(FacetParams.FACET, "true");
int facetByIndex = 0;
for (final AnyMap facetConfig : facetByConfigs) {
facetByIndex++;
/*
* PERF: do this faster by just iterating thru all childeren and collecting all vars on the fly instead of pulling
* them from the map | TM @ Jan 18, 2012
*/
final String attribute = facetConfig.getStringValue(QueryConstants.ATTRIBUTE);
if (attribute == null) {
_log
.warn(MessageFormat.format("no attribute defined for facet @ index: {0}. It is ignored.", facetByIndex));
continue;
}
/*
* BETTER | TM | facetting: apply record attribute -> solr field mapping from piplet config ? | TM @ Jan 18, 2012
*/
final String fieldName = attribute;
final String facetType =
defaultString(facetConfig.getStringValue(SolrConstants.FACET_TYPE), FacetParams.FACET_FIELD);
final String facetName = defaultString(facetConfig.getStringValue(SolrConstants.FACET_NAME), attribute);
final boolean multiselect = BooleanUtils.isTrue(facetConfig.getBooleanValue(SolrConstants.FACET_MULTISELECT));
// custom range facet
if (facetType.equals(SolrConstants.FACET_TYPE_CUSTOM_RANGES)) {
addCustomRangesFacet(fieldName, facetName, multiselect, facetConfig);
continue;
}
// Handle localParams
final AnyMap localParams = facetConfig.getMap(SolrConstants.LOCAL_PARAMS, true);
if (!facetName.equals(attribute)) {
localParams.put("key", facetName);
}
final String filterGroupName;
if (multiselect) {
filterGroupName = "facet_" + facetName;
localParams.put("ex", filterGroupName);
} else {
filterGroupName =
defaultString(facetConfig.getStringValue(SolrConstants.FILTER_GROUP), "facet_" + facetName);
}
// the local params as well as the field e.g.
// facet.field={!key=facetName ex=groupName}
final StringBuilder facetParam = resetBuffer();
appendLocalParams(facetParam, localParams);
facetParam.append(fieldName);
// Add facet with with localParams
_solrQuery.add(facetType, facetParam.toString());
// Add maxCount
final String maxCount = facetConfig.getStringValue(QueryConstants.MAXCOUNT);
if (maxCount != null) {
addFieldParameter(fieldName, FacetParams.FACET_LIMIT, maxCount);
}
// Add sortby
final AnyMap sortby = facetConfig.getMap(QueryConstants.SORTBY);
if (sortby != null) {
final String criterion = sortby.getStringValue(QueryConstants.FACETBY_SORTCRITERION);
addFieldParameter(fieldName, FacetParams.FACET_SORT, criterion);
if (_log.isWarnEnabled()) {
if (sortby.containsKey(QueryConstants.ORDER)) {
_log.warn(format("facet config for field %s contains value for unsupported sort order. It is ignored",
fieldName));
}
} // if
}
// add all native parameters as given for the current field
final AnyMap map = facetConfig.getMap(QueryConstants.NATIVE_PARAMETERS);
addAsSolrParameters(map, fieldName);
// Add filter
final AnySeq filterConfig = facetConfig.getSeq(QueryConstants.FILTER_ONEOF);
if (filterConfig != null) {
final StringBuilder fq = resetBuffer();
appendFilterSetExpression(fq, attribute, filterConfig, "");
if (fq.length() > 0) {
final FilterGroup filterGroup = _filterGroups.get(filterGroupName);
filterGroup.filterStrings.add(fq.toString());
filterGroup.localParams.put(SolrConstants.LOCAL_PARAM_TAG, filterGroupName);
}
}
} // facet config
}
/**
* handles custom range facets.
*
* @todo BETTER this method doesnt use the generic {@link #_filterGroups} but should, if it makes sense at all.
* However, this needs to be investigated for which i dont have the time right now.
*/
private void addCustomRangesFacet(final String attribute, final String facetName, final Boolean multiselect,
final AnyMap facetConfig) {
// add facet query
final AnySeq ranges = facetConfig.getSeq(SolrConstants.FACET_RANGES);
if (ranges == null) {
return;
}
int position = 0;
for (final Any range : ranges) {
final StringBuilder facetQuery = new StringBuilder();
String ex = "";
if (multiselect) {
ex = " ex=facet_" + facetName;
}
facetQuery.append("{!key=");
facetQuery.append(facetName);
facetQuery.append("_");
facetQuery.append(position);
facetQuery.append(ex);
facetQuery.append("}");
facetQuery.append(attribute);
facetQuery.append(":");
facetQuery.append(range.asValue().asString());
position++;
_solrQuery.addFacetQuery(facetQuery.toString());
}
// add filter query, if present
final AnySeq oneOf = facetConfig.getSeq(QueryConstants.FILTER_ONEOF);
if (oneOf != null) {
final StringBuilder filterQuery = new StringBuilder();
if (multiselect) {
filterQuery.append("{!tag=facet_" + facetName + "}");
}
for (final Any filter : oneOf) {
try {
final String filterReferenze = filter.asValue().asString();
final String[] split = StringUtils.split(filterReferenze, "_");
final int index = NumberUtils.toInt(split[split.length - 1]);
final String resolvedFilter = ranges.getStringValue(index);
filterQuery.append("");
filterQuery.append("(");
filterQuery.append(attribute);
filterQuery.append(":");
filterQuery.append(resolvedFilter);
filterQuery.append(")");
} catch (Exception e) {
throw new RuntimeException(format("custom range filter cannot be resolved: %s oneOf %s", facetName,
filter.asValue().asString()), e);
}
}
_solrQuery.addFilterQuery(filterQuery.toString());
}
}
/**
* resets the global buffer for this object and returns it. Must not use this method in a nested method, as the parent
* might be using the same instance!
*/
private StringBuilder resetBuffer() {
_buffer.setLength(0);
return _buffer;
}
/**
* Adds the values in the given maps as local params in same order. The surrounding !{} are added, if any params got
* really added
*
* @param sb
* the sb
* @param localParams
* the local params
* @return the string builder
*/
private StringBuilder appendLocalParams(final StringBuilder sb, final AnyMap... localParams) {
final int originalLength = sb.length();
if (localParams != null) {
sb.append("{!");
for (AnyMap anyMap : localParams) {
if (!MapUtils.isEmpty(anyMap)) {
for (final Entry<String, Any> localParam : anyMap.entrySet()) {
appendLocalParam(sb, localParam.getKey(), localParam.getValue());
}
}
}
if (sb.length() == originalLength + 2) { // no local params were
// added -> remove {!
sb.setLength(originalLength);
} else {
sb.setCharAt(sb.length() - 1, '}');
}
}
return sb;
}
/**
* append {@code name[=value.asValue().asString()]+ " "}. Since a space is always appended it should be removed by the
* calling method before closing the local params.
*
* @param sb
* @param name
* @param value
*/
private void appendLocalParam(final StringBuilder sb, final String name, final Any value) {
sb.append(name);
final String stringValue = value.asValue().asString();
if (isNotBlank(stringValue)) {
sb.append("=");
sb.append(stringValue);
}
sb.append(" ");
}
/**
* Do terms settings.
*/
private void doTermsSettings() {
final AnyMap terms = _accessor.getTerms();
if (terms != null) {
_solrQuery.setParam(CommonParams.QT, "/terms");
addAsSolrParameters(terms);
}
}
/**
* Do highlighting settings.
*/
private void doHighlightingSettings() {
if (_accessor.hasHighlightConfig()) {
for (Any config : _accessor.getHighlightConfig()) {
if (config.isMap()) {
final AnyMap highlight = config.asMap();
final String fieldName = highlight.getStringValue(QueryConstants.ATTRIBUTE);
_solrQuery.addHighlightField(fieldName);
final AnyMap nativeParameters = highlight.getMap(QueryConstants.NATIVE_PARAMETERS);
addAsSolrParameters(nativeParameters, fieldName);
}
}
}
}
/**
* Adds contained values as solr query parameters. Only Value items is supported. An item with the name "attribute" is
* skipped.
*
* @param map
* the map containing parameter as key value pairs. If null does nothing.
* @param field
* if not blank then the config is added for the given field name (field level config, e.g.
* f.${field}.${key}) otherwise global
*/
private void addAsSolrParameters(final AnyMap map, final String field) {
if (map == null) {
return;
}
for (final Entry<String, Any> entry : map.entrySet()) {
final String key = entry.getKey();
if (key.equals(QueryConstants.ATTRIBUTE)) {
continue;
}
final String value = entry.getValue().asValue().asString();
if (isBlank(field)) {
_solrQuery.add(key, value);
} else {
addFieldParameter(field, key, value);
}
}
}
/**
* Adds contained values as solr query parameters. Value and Seq items are supported, the latter result in multiple
* params with the same name.
*
* @param map
* the map containing parameter as key value pairs. If null does nothing.
*/
private void addAsSolrParameters(final AnyMap map) {
if (map == null) {
return;
}
for (final Entry<String, Any> entry : map.entrySet()) {
final String key = entry.getKey();
final Any value = entry.getValue();
if (value.isSeq()) {
final AnySeq values = value.asSeq();
for (Any any : values) {
_solrQuery.add(key, any.asValue().asString());
}
} else if (value.isValue()) {
final String single = value.asValue().asString();
_solrQuery.add(key, single);
}
}
}
/**
* adds the given parameter for a field after the form f.${field}.${paramName}.
*/
private void addFieldParameter(final String field, final String paramName, final String value) {
final String parmName = SolrConstants.FIELD_PREFIX + field + SolrConstants.FIELD_SUFFIX + paramName;
_solrQuery.add(parmName, value);
}
/**
* Do shards settings.
*/
private void doShardsSettings() {
final AnySeq seq = _accessor.getShards();
if (seq != null) {
final String shards = StringUtils.join(seq.asStrings(), ",");
_solrQuery.setParam(ShardParams.SHARDS, shards);
}
}
/**
* Do spellcheck settings.
*/
private void doSpellCheckSettings() {
final AnyMap spellcheck = _accessor.getSpellcheck();
if (spellcheck != null) {
addAsSolrParameters(spellcheck);
}
}
/**
*
*/
private void doMoreLikeThis() {
final AnyMap moreLikeThis = _accessor.getMoreLikeThis();
if (moreLikeThis != null) {
addAsSolrParameters(moreLikeThis);
}
}
/**
* Do group settings.
*/
private void doGroupSettings() {
// only process if a groupby config is present
if (_accessor.hasGroupbyConfig()) {
AnySeq method = null;
String asMainResult = null;
// Iterate thru groupby AnyMap
for (Entry<String, Any> entry : _accessor.getGroupbyConfig().entrySet()) {
final String key = entry.getKey();
final Any any = entry.getValue();
// if AnySeq check if key is 'attributes'
if (any.isSeq()) {
if (key.equals(SolrConstants.GROUPBY_METHOD_ATTRIBUTES)) {
method = any.asSeq();
}
// if AnyMap get the underlying AnySeq 'attributes'
} else if (any.isMap()) {
method = any.asMap().getSeq(SolrConstants.GROUPBY_METHOD_ATTRIBUTES);
// if Value check if key is 'asMainResult'
} else if (any.isValue()) {
if (key.equals(SolrConstants.GROUPBY_AS_MAIN_RESULT)) {
asMainResult = any.asValue().asString();
}
}
}
// check if a groupby method is defined
if (method == null) {
throw new NullArgumentException("groupby method AnySeq");
}
// handle first AnyMap within groupby method AnySeq
final AnyMap groupby = method.getMap(0);
if (groupby != null) {
// turn on grouping (field collapsing)
_solrQuery.add(GroupParams.GROUP, "true");
// set group.field = attribute
final String attribute = groupby.getStringValue(QueryConstants.ATTRIBUTE);
if (StringUtils.isEmpty(attribute)) {
throw new NullArgumentException("attribute");
}
_solrQuery.add(GroupParams.GROUP_FIELD, attribute);
// set group.limit = maxcount
final Long maxcount = groupby.getLongValue(QueryConstants.MAXCOUNT);
if (maxcount != null) {
_solrQuery.add(GroupParams.GROUP_LIMIT, String.valueOf(maxcount));
}
// if Value 'asMainResult' is not empty set group.main = true
if (StringUtils.isNotEmpty(asMainResult)) {
_solrQuery.add(GroupParams.GROUP_MAIN, "true");
}
}
}
}
}
// CHECKSTYLE:OFF
/**
* simple struct to hold elements regarding the filter
*/
class FilterGroup {
final List<String> filterStrings = new ArrayList<String>();
final AnyMap localParams = DefaultDataFactoryImpl.INSTANCE.createAnyMap();
}
// CHECKSTYLE:ON