com.frank.search.solr.core.DefaultQueryParser.java Source code

Java tutorial

Introduction

Here is the source code for com.frank.search.solr.core.DefaultQueryParser.java

Source

/*
 * Copyright 2012 - 2015 the original author or authors.
 *
 * 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.
 */
package com.frank.search.solr.core;

import com.frank.search.solr.VersionUtil;
import com.frank.search.solr.core.query.FacetOptions;
import com.frank.search.solr.core.query.FacetOptions.*;
import com.frank.search.solr.core.query.*;
import com.frank.search.solr.core.query.HighlightOptions.FieldWithHighlightParameters;
import com.frank.search.solr.core.query.HighlightOptions.HighlightParameter;
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrQuery.ORDER;
import org.apache.solr.common.params.*;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;

/**
 * Implementation of {@link QueryParser}. <br/>
 * Creates executable {@link org.apache.solr.client.solrj.SolrQuery} from
 * {@link Query} by traversing {@link Criteria}. Reserved characters like
 * {@code +} or {@code -} will be escaped to form a valid query.
 *
 * @author Christoph Strobl
 * @author John Dorman
 * @author Rosty Kerei
 * @author Luke Corpe
 * @author Andrey Paramonov
 * @author Philipp Jardas
 * @author Francisco Spaeth
 * @author Joachim Uhrla
 */
public class DefaultQueryParser extends QueryParserBase<SolrDataQuery> {

    /**
     * Convert given Query into a SolrQuery executable via
     * {@link org.apache.solr.client.solrj.SolrClient}
     *
     * @param query
     * @return
     */
    @Override
    public final SolrQuery doConstructSolrQuery(SolrDataQuery query) {
        Assert.notNull(query, "Cannot construct solrQuery from null value.");
        Assert.notNull(query.getCriteria(), "Query has to have a criteria.");

        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setParam(CommonParams.Q, getQueryString(query));
        if (query instanceof Query) {
            processQueryOptions(solrQuery, (Query) query);
        }
        if (query instanceof FacetQuery) {
            processFacetOptions(solrQuery, (FacetQuery) query);
        }
        if (query instanceof HighlightQuery) {
            processHighlightOptions(solrQuery, (HighlightQuery) query);
        }
        return solrQuery;
    }

    private void processQueryOptions(SolrQuery solrQuery, Query query) {
        appendPagination(solrQuery, query.getOffset(), query.getRows());
        appendProjectionOnFields(solrQuery, query.getProjectionOnFields());
        appendFilterQuery(solrQuery, query.getFilterQueries());
        appendSort(solrQuery, query.getSort());
        appendDefaultOperator(solrQuery, query.getDefaultOperator());
        appendTimeAllowed(solrQuery, query.getTimeAllowed());
        appendDefType(solrQuery, query.getDefType());
        appendRequestHandler(solrQuery, query.getRequestHandler());

        processGroupOptions(solrQuery, query);
        processStatsOptions(solrQuery, query);
    }

    private void processFacetOptions(SolrQuery solrQuery, FacetQuery query) {
        if (enableFaceting(solrQuery, query)) {
            appendFacetingOnFields(solrQuery, (FacetQuery) query);
            appendFacetingQueries(solrQuery, (FacetQuery) query);
            appendFacetingOnPivot(solrQuery, (FacetQuery) query);
            appendRangeFacetingOnFields(solrQuery, (FacetQuery) query);
        }
    }

    private void setObjectNameOnGroupQuery(Query query, Object object, String name) {

        if (query instanceof NamedObjectsQuery) {
            ((NamedObjectsQuery) query).setName(object, name);
        }
    }

    private void processStatsOptions(SolrQuery solrQuery, Query query) {
        StatsOptions statsOptions = query.getStatsOptions();

        if (statsOptions == null || (CollectionUtils.isEmpty(statsOptions.getFields())
                && CollectionUtils.isEmpty(statsOptions.getFacets())
                && CollectionUtils.isEmpty(statsOptions.getSelectiveFacets()))) {
            return;
        }

        solrQuery.set(StatsParams.STATS, true);

        for (Field field : statsOptions.getFields()) {
            solrQuery.add(StatsParams.STATS_FIELD, field.getName());

            String selectiveCalcDistinctParam = CommonParams.FIELD + "." + field.getName() + "."
                    + StatsParams.STATS_CALC_DISTINCT;
            Boolean selectiveCountDistincts = statsOptions.isSelectiveCalcDistincts(field);

            if (selectiveCountDistincts != null) {
                solrQuery.add(selectiveCalcDistinctParam, String.valueOf(selectiveCountDistincts.booleanValue()));
            }

        }

        for (Field field : statsOptions.getFacets()) {
            solrQuery.add(StatsParams.STATS_FACET, field.getName());
        }

        for (Entry<Field, Collection<Field>> entry : statsOptions.getSelectiveFacets().entrySet()) {

            Field field = entry.getKey();
            String prefix = CommonParams.FIELD + "." + field.getName() + ".";

            String paramName = prefix + StatsParams.STATS_FACET;
            for (Field facetField : entry.getValue()) {
                solrQuery.add(paramName, facetField.getName());
            }

        }

    }

    private void processGroupOptions(SolrQuery solrQuery, Query query) {

        GroupOptions groupOptions = query.getGroupOptions();

        if (groupOptions == null || (CollectionUtils.isEmpty(groupOptions.getGroupByFields())
                && CollectionUtils.isEmpty(groupOptions.getGroupByFunctions())
                && CollectionUtils.isEmpty(groupOptions.getGroupByQueries()))) {
            return;
        }

        solrQuery.set(GroupParams.GROUP, true);
        solrQuery.set(GroupParams.GROUP_MAIN, groupOptions.isGroupMain());
        solrQuery.set(GroupParams.GROUP_FORMAT, "grouped");

        if (!CollectionUtils.isEmpty(groupOptions.getGroupByFields())) {
            for (Field field : groupOptions.getGroupByFields()) {
                solrQuery.add(GroupParams.GROUP_FIELD, field.getName());
            }
        }

        if (!CollectionUtils.isEmpty(groupOptions.getGroupByFunctions())) {
            for (Function function : groupOptions.getGroupByFunctions()) {
                String functionFragment = createFunctionFragment(function, 0);
                setObjectNameOnGroupQuery(query, function, functionFragment);
                solrQuery.add(GroupParams.GROUP_FUNC, functionFragment);
            }
        }

        if (!CollectionUtils.isEmpty(groupOptions.getGroupByQueries())) {
            for (Query groupQuery : groupOptions.getGroupByQueries()) {
                String queryFragment = getQueryString(groupQuery);
                setObjectNameOnGroupQuery(query, groupQuery, queryFragment);
                solrQuery.add(GroupParams.GROUP_QUERY, queryFragment);
            }
        }

        if (groupOptions.getSort() != null) {

            for (Order order : groupOptions.getSort()) {
                solrQuery.add(GroupParams.GROUP_SORT,
                        order.getProperty().trim() + " " + (order.isAscending() ? ORDER.asc : ORDER.desc));
            }
        }

        if (groupOptions.getCachePercent() > 0) {
            solrQuery.add(GroupParams.GROUP_CACHE_PERCENTAGE, String.valueOf(groupOptions.getCachePercent()));
        }

        if (groupOptions.getLimit() != null && groupOptions.getLimit() >= 0) {
            solrQuery.set(GroupParams.GROUP_LIMIT, groupOptions.getLimit());
        }

        if (groupOptions.getOffset() != null && groupOptions.getOffset() >= 0) {
            solrQuery.set(GroupParams.GROUP_OFFSET, groupOptions.getOffset());
        }

        solrQuery.set(GroupParams.GROUP_TOTAL_COUNT, groupOptions.isTotalCount());
        solrQuery.set(GroupParams.GROUP_FACET, groupOptions.isGroupFacets());
        solrQuery.set(GroupParams.GROUP_TRUNCATE, groupOptions.isTruncateFacets());
    }

    /**
     * Append highlighting parameters to
     * {@link org.apache.solr.client.solrj.SolrQuery}
     *
     * @param solrQuery
     * @param query
     */
    protected void processHighlightOptions(SolrQuery solrQuery, HighlightQuery query) {
        if (query.hasHighlightOptions()) {
            HighlightOptions highlightOptions = query.getHighlightOptions();
            solrQuery.setHighlight(true);
            if (!highlightOptions.hasFields()) {
                solrQuery.addHighlightField(HighlightOptions.ALL_FIELDS.getName());
            } else {
                for (Field field : highlightOptions.getFields()) {
                    solrQuery.addHighlightField(field.getName());
                }
                for (FieldWithHighlightParameters fieldWithHighlightParameters : highlightOptions
                        .getFieldsWithHighlightParameters()) {
                    addPerFieldHighlightParameters(solrQuery, fieldWithHighlightParameters);
                }
            }
            for (HighlightParameter option : highlightOptions.getHighlightParameters()) {
                addOptionToSolrQuery(solrQuery, option);
            }
            if (highlightOptions.hasQuery()) {
                solrQuery.add(HighlightParams.Q, getQueryString(highlightOptions.getQuery()));
            }
        }
    }

    private void addOptionToSolrQuery(SolrQuery solrQuery, QueryParameter option) {
        if (option != null && StringUtils.isNotBlank(option.getName())) {
            solrQuery.add(option.getName(), conversionService.convert(option.getValue(), String.class));
        }
    }

    private void addFieldSpecificParameterToSolrQuery(SolrQuery solrQuery, Field field, QueryParameter option) {
        if (option != null && field != null && StringUtils.isNotBlank(option.getName())) {
            if (option.getValue() == null) {
                solrQuery.add(createPerFieldOverrideParameterName(field, option.getName()), (String) null);
            } else {
                String value = option.getValue().toString();
                if (conversionService.canConvert(option.getValue().getClass(), String.class)) {
                    value = conversionService.convert(option.getValue(), String.class);
                }
                solrQuery.add(createPerFieldOverrideParameterName(field, option.getName()), value);
            }
        }
    }

    private void addPerFieldHighlightParameters(SolrQuery solrQuery, FieldWithHighlightParameters field) {
        for (HighlightParameter option : field) {
            addFieldSpecificParameterToSolrQuery(solrQuery, field, option);
        }
    }

    protected String createPerFieldOverrideParameterName(Field field, String parameterName) {
        return "f." + field.getName() + "." + parameterName;
    }

    private boolean enableFaceting(SolrQuery solrQuery, FacetQuery query) {
        FacetOptions facetOptions = query.getFacetOptions();
        if (facetOptions == null || !facetOptions.hasFacets()) {
            return false;
        }
        solrQuery.setFacet(true);
        solrQuery.setFacetMinCount(facetOptions.getFacetMinCount());
        solrQuery.setFacetLimit(facetOptions.getPageable().getPageSize());
        if (facetOptions.getPageable().getPageNumber() > 0) {
            int offset = Math.max(0, facetOptions.getPageable().getOffset());
            solrQuery.set(FacetParams.FACET_OFFSET, offset);
        }
        if (FacetOptions.FacetSort.INDEX.equals(facetOptions.getFacetSort())) {
            solrQuery.setFacetSort(FacetParams.FACET_SORT_INDEX);
        }
        return true;
    }

    private void appendFacetingOnFields(SolrQuery solrQuery, FacetQuery query) {
        FacetOptions facetOptions = query.getFacetOptions();
        solrQuery.addFacetField(convertFieldListToStringArray(facetOptions.getFacetOnFields()));
        if (facetOptions.hasFacetPrefix()) {
            solrQuery.setFacetPrefix(facetOptions.getFacetPrefix());
        }
        for (FacetOptions.FieldWithFacetParameters parametrizedField : facetOptions.getFieldsWithParameters()) {
            addPerFieldFacetParameters(solrQuery, parametrizedField);
            if (parametrizedField.getSort() != null
                    && FacetOptions.FacetSort.INDEX.equals(parametrizedField.getSort())) {
                addFieldSpecificParameterToSolrQuery(solrQuery, parametrizedField,
                        new FacetParameter(FacetParams.FACET_SORT, FacetParams.FACET_SORT_INDEX));
            }

        }
    }

    private void addPerFieldFacetParameters(SolrQuery solrQuery, FieldWithFacetParameters field) {
        for (FacetParameter parameter : field) {
            addFieldSpecificParameterToSolrQuery(solrQuery, field, parameter);
        }
    }

    private void appendRangeFacetingOnFields(SolrQuery solrQuery, FacetQuery query) {
        FacetOptions facetRangeOptions = query.getFacetOptions();

        if (facetRangeOptions == null) {
            return;
        }

        for (FieldWithRangeParameters<?, ?, ?> rangeField : facetRangeOptions.getFieldsWithRangeParameters()) {

            if (rangeField instanceof FieldWithDateRangeParameters) {
                appendFieldFacetingByDateRange(solrQuery, (FieldWithDateRangeParameters) rangeField);
            } else if (rangeField instanceof FieldWithNumericRangeParameters) {
                appendFieldFacetingByNumberRange(solrQuery, (FieldWithNumericRangeParameters) rangeField);
            }

            if (rangeField.getHardEnd() != null && rangeField.getHardEnd()) {
                FacetParameter param = new FacetParameter(FacetParams.FACET_RANGE_HARD_END, true);
                addFieldSpecificParameterToSolrQuery(solrQuery, rangeField, param);
            }
            if (rangeField.getOther() != null) {
                FacetParameter param = new FacetParameter(FacetParams.FACET_RANGE_OTHER, rangeField.getOther());
                addFieldSpecificParameterToSolrQuery(solrQuery, rangeField, param);
            }

            if (rangeField.getInclude() != null) {
                FacetParameter param = new FacetParameter(FacetParams.FACET_RANGE_INCLUDE, rangeField.getInclude());
                addFieldSpecificParameterToSolrQuery(solrQuery, rangeField, param);
            }

        }
    }

    private void appendFieldFacetingByNumberRange(SolrQuery solrQuery, FieldWithNumericRangeParameters field) {
        solrQuery.addNumericRangeFacet( //
                field.getName(), //
                field.getStart(), //
                field.getEnd(), //
                field.getGap());
    }

    private void appendFieldFacetingByDateRange(SolrQuery solrQuery, FieldWithDateRangeParameters field) {
        solrQuery.addDateRangeFacet( //
                field.getName(), //
                field.getStart(), //
                field.getEnd(), //
                field.getGap());
    }

    private void appendFacetingQueries(SolrQuery solrQuery, FacetQuery query) {
        FacetOptions facetOptions = query.getFacetOptions();
        for (SolrDataQuery fq : facetOptions.getFacetQueries()) {
            String facetQueryString = getQueryString(fq);
            if (StringUtils.isNotBlank(facetQueryString)) {
                solrQuery.addFacetQuery(facetQueryString);
            }
        }
    }

    private void appendFacetingOnPivot(SolrQuery solrQuery, FacetQuery query) {
        if (VersionUtil.isSolr3XAvailable()) {
            throw new UnsupportedOperationException(
                    "Pivot Facets are not available for solr version lower than 4.x - Please check your depdendencies.");
        }

        FacetOptions facetOptions = query.getFacetOptions();
        String[] pivotFields = convertFieldListToStringArray(facetOptions.getFacetOnPivots());
        solrQuery.addFacetPivotField(pivotFields);
    }

    /**
     * Set filter filter queries for
     * {@link org.apache.solr.client.solrj.SolrQuery}
     *
     * @param solrQuery
     * @param filterQueries
     */
    protected void appendFilterQuery(SolrQuery solrQuery, List<FilterQuery> filterQueries) {
        if (CollectionUtils.isEmpty(filterQueries)) {
            return;
        }
        List<String> filterQueryStrings = getFilterQueryStrings(filterQueries);

        if (!filterQueryStrings.isEmpty()) {
            solrQuery.setFilterQueries(convertStringListToArray(filterQueryStrings));
        }
    }

    /**
     * Append sorting parameters to
     * {@link org.apache.solr.client.solrj.SolrQuery}
     * 
     * @param solrQuery
     * @param sort
     */
    protected void appendSort(SolrQuery solrQuery, Sort sort) {
        if (sort == null) {
            return;
        }

        for (Order order : sort) {
            solrQuery.addSort(order.getProperty(), order.isAscending() ? ORDER.asc : ORDER.desc);
        }
    }

    private String[] convertFieldListToStringArray(List<? extends Field> fields) {
        String[] strResult = new String[fields.size()];
        for (int i = 0; i < fields.size(); i++) {
            strResult[i] = fields.get(i).getName();
        }
        return strResult;
    }

    private String[] convertStringListToArray(List<String> listOfString) {
        String[] strResult = new String[listOfString.size()];
        listOfString.toArray(strResult);
        return strResult;
    }

    private List<String> getFilterQueryStrings(List<FilterQuery> filterQueries) {
        List<String> filterQueryStrings = new ArrayList<String>(filterQueries.size());

        for (FilterQuery filterQuery : filterQueries) {
            String filterQueryString = getQueryString(filterQuery);
            if (StringUtils.isNotBlank(filterQueryString)) {
                filterQueryStrings.add(filterQueryString);
            }
        }
        return filterQueryStrings;
    }

}