eu.prestoprime.search.Searcher.java Source code

Java tutorial

Introduction

Here is the source code for eu.prestoprime.search.Searcher.java

Source

/**
 * Searcher.java
 * Author: Philip Kahle (philip.kahle@uibk.ac.at)
 * 
 * This file is part of PrestoPRIME Preservation Platform (P4).
 * 
 * Copyright (C) 2009-2012 University of Innsbruck, Austria
 *  
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package eu.prestoprime.search;

import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.SpellCheckResponse.Suggestion;

import eu.prestoprime.model.search.SearchResults;
import eu.prestoprime.search.util.ResultProcessor;
import eu.prestoprime.search.util.Schema;
import eu.prestoprime.search.util.Schema.P4SortField;
import eu.prestoprime.search.util.SolrQueryBuilder;
import eu.prestoprime.search.util.SolrQueryUtils;
import eu.prestoprime.search.util.suggestion.P4Suggestion;
import eu.prestoprime.search.util.suggestion.P4Suggestions;

public class Searcher {

    private static final Logger LOGGER = Logger.getLogger(Searcher.class);

    public Searcher() {
        LOGGER.info("Instance of Searcher was created.");
    }

    /**
     * Searches all fields that are quicksearch enabled (i.e. fields that are
     * added to the "text" field in solr's schema.xml via a copyfield
     * directive). The portion of the results that is shown ranges from result
     * #from to #(from+resultCount) Furthermore this method uses Solr's dismax
     * query handler which strips reserved character from the query string.
     * Thus, specifying fields for the search or conjuction/disjunction are not
     * allowed. Including and Excluding terms with +/- is possible though. The
     * user input string can be simply passed through as searchTerm for simple
     * error-prone search.
     * 
     * @param searchTerm
     * @param from
     *            specifies which portion of all results is shown
     * @param resultCount
     *            specifies how many results are displayed
     * @param sortField
     *            the field that is used for sorting
     * @param sortAsc
     *            sortorder, if true -> ascending, else -> descending
     * @param facets
     *            Map object containing all fields to facet on as key and, if
     *            already selected, the filter value for this field
     * @return a SearchResults object containing all POJOs from the
     *         QueryResponse
     */
    public SearchResults simpleSearch(final String searchTerm, final int from, final int resultCount,
            final P4SortField sortField, final boolean sortAsc, Map<Schema.P4FacetField, String> facets) {

        SolrQuery query = new SolrQuery(searchTerm);

        // use this for simple error-prone syntax in simple search field:
        // add dismax requesthandler with deftype=dismax in solrconfig.xml
        // set default searchfield to catchall field in schema.xml
        // use this handler for the simple search:
        query.setQueryType("/dismax");

        SolrQueryUtils.enableHighlightAllFields(query);

        SearchResults results = search(query, from, resultCount, sortField, sortAsc, facets);

        return results;
    }

    /**
     * Searches all fields that are quicksearch enabled if no fieldnames are
     * specified (i.e. fields that are added to the "text" field in solr's
     * schema.xml via a copyfield directive). The portion of the results that is
     * shown ranges from result #from to #(from+resultCount) The query is
     * handled by the Solr's standard queryHandler which allows the full-blown
     * query syntax.
     * 
     * @param searchTerm
     * @param from
     *            specifies which portion of all results is shown
     * @param resultCount
     *            specifies how many results are displayed
     * @param sortField
     *            the field that is used for sorting
     * @param sortAsc
     *            sortorder, if true -> ascending, else -> descending
     * @param facets
     *            Map object containing all fields to facet on as key and, if
     *            already selected, the filter value for this field
     * @return a SearchResults object containing all POJOs from the
     *         QueryResponse
     */
    public SearchResults advancedSearch(final Map<Schema.searchField, String> fieldMap, final int from,
            final int resultCount, final P4SortField sortField, final boolean sortAsc,
            Map<Schema.P4FacetField, String> facets) {
        SearchResults results = new SearchResults();

        String queryString = SolrQueryBuilder.buildQuery(fieldMap);
        if (!queryString.isEmpty()) {
            SolrQuery query = new SolrQuery(queryString);

            SolrQueryUtils.enableHighlight(query, fieldMap);

            results = search(query, from, resultCount, sortField, sortAsc, facets);
        } else {
            results.setErrorMessage("The built query was empty!");
        }
        return results;
    }

    /**
     * Submits the SolrQuery object to SolrServer and handles sorting and
     * faceting. The portion of the results that is shown ranges from result
     * #from to #(from+resultCount)
     * 
     * @param query
     *            SolrQuery object
     * @param from
     *            specifies which portion of all results is shown
     * @param resultCount
     *            specifies how many results are displayed
     * @param sortField
     *            the field that is used for sorting
     * @param sortAsc
     *            sortorder, if true -> ascending, else -> descending
     * @param facetFilters
     *            Map object containing all fields to facet on as key and, if
     *            already selected, the filter value for this field
     * @return a SearchResults object containing all POJOs from the
     *         QueryResponse
     */
    private SearchResults search(SolrQuery query, final int from, final int resultCount,
            final P4SortField sortField, final boolean sortAsc, Map<Schema.P4FacetField, String> facetFilters) {

        QueryResponse response = new QueryResponse();
        SearchResults results = new SearchResults();

        SolrQueryUtils.setResultRange(query, from, resultCount);

        // TODO deal with sorting on multivalued fields -> copyfield of one
        // value to a dedicated sortfield is done in P4IndexObject's respective
        // setters
        if (sortField == null) {
            LOGGER.debug("SortField is NULL! setting sortTitle and descending");
            SolrQueryUtils.setSortField(query, P4SortField.TITLE, sortAsc);
        } else {
            LOGGER.debug("SortField is " + sortField.getFieldName() + ". SortAsc? " + sortAsc);
            SolrQueryUtils.setSortField(query, sortField, sortAsc);
        }

        if (facetFilters == null) {
            SolrQueryUtils.enableFacets(query);
            facetFilters = SolrQueryUtils.getDefaultFacetMap();
        } else {
            SolrQueryUtils.setFacets(query, facetFilters);
        }

        try {
            LOGGER.debug("Query = " + query.getQuery());

            response = SolrServerConnection.getInstance().getSolrServer().query(query);

            results = ResultProcessor.extractResults(response, facetFilters);
            // ResultProcessor.setSelectedFacets(results, facetFilters);

            // set query params in results object
            results.getParams().setQuery(query.getQuery());
            results.getParams().setFrom(from);
            results.getParams().setResultCount(resultCount);
            results.getParams()
                    .setSortField(sortField != null ? sortField.getFieldName() : P4SortField.TITLE.getFieldName());
            results.getParams().setSortAscending(sortAsc);

        } catch (SolrServerException e) {
            LOGGER.fatal(e.getMessage());
            LOGGER.fatal("Invalid Query = '" + query.getQuery() + "'.");
            results.setErrorMessage(e.getMessage());
        }

        return results;
    }

    /**
     * Queries Solr for auto-complete suggestions for an entered term. See
     * SearchHandler "suggest" in solrConfig.xml for tweaking.
     * 
     * @param term
     * @return
     */
    public P4Suggestions getSuggestion(String term) {
        P4Suggestions suggs = new P4Suggestions(term);
        QueryResponse response = new QueryResponse();
        SolrQuery query = new SolrQuery(term);
        query.setQueryType("/suggest");

        try {
            response = SolrServerConnection.getInstance().getSolrServer().query(query);
            if (response.getSpellCheckResponse() != null
                    && !response.getSpellCheckResponse().getSuggestionMap().entrySet().isEmpty()) {
                Map<String, Suggestion> resultMap = response.getSpellCheckResponse().getSuggestionMap();
                for (Entry<String, Suggestion> entry : resultMap.entrySet()) {
                    suggs.suggestions.add(new P4Suggestion(entry.getKey(), entry.getValue().getAlternatives()));
                }
            }
        } catch (SolrServerException e) {
            LOGGER.fatal(e);
            LOGGER.fatal("Could not query Solr for suggestions. Query = '" + query.getQuery() + "'.");
        }
        return suggs;
    }
}