com.liferay.portal.search.solr.SolrIndexSearcherImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.portal.search.solr.SolrIndexSearcherImpl.java

Source

/**
 * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library 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 Lesser General Public License for more
 * details.
 */

package com.liferay.portal.search.solr;

import com.liferay.portal.kernel.configuration.Filter;
import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.json.JSONArray;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.search.Document;
import com.liferay.portal.kernel.search.DocumentImpl;
import com.liferay.portal.kernel.search.Field;
import com.liferay.portal.kernel.search.Hits;
import com.liferay.portal.kernel.search.HitsImpl;
import com.liferay.portal.kernel.search.IndexSearcher;
import com.liferay.portal.kernel.search.Query;
import com.liferay.portal.kernel.search.QueryConfig;
import com.liferay.portal.kernel.search.QueryTranslatorUtil;
import com.liferay.portal.kernel.search.SearchContext;
import com.liferay.portal.kernel.search.SearchException;
import com.liferay.portal.kernel.search.Sort;
import com.liferay.portal.kernel.search.facet.Facet;
import com.liferay.portal.kernel.search.facet.RangeFacet;
import com.liferay.portal.kernel.search.facet.collector.FacetCollector;
import com.liferay.portal.kernel.search.facet.config.FacetConfiguration;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Time;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.search.solr.facet.SolrFacetFieldCollector;
import com.liferay.portal.search.solr.facet.SolrFacetQueryCollector;
import com.liferay.portal.search.solr.util.PortletPropsKeys;
import com.liferay.portal.search.solr.util.PortletPropsValues;
import com.liferay.util.portlet.PortletProps;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.solr.client.solrj.SolrQuery.ORDER;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;

/**
 * @author Bruno Farache
 * @author Zsolt Berentey
 * @author Raymond Aug
 */
public class SolrIndexSearcherImpl implements IndexSearcher {

    public Hits search(SearchContext searchContext, Query query) throws SearchException {

        try {
            return doSearch(searchContext, query);
        } catch (Exception e) {
            _log.error(e, e);

            throw new SearchException(e.getMessage());
        }
    }

    public Hits search(String searchEngineId, long companyId, Query query, Sort[] sorts, int start, int end)
            throws SearchException {

        try {
            SolrQuery solrQuery = translateQuery(companyId, query, sorts, start, end);

            QueryResponse queryResponse = _solrServer.query(solrQuery);

            boolean allResults = false;

            if (solrQuery.getRows() == 0) {
                allResults = true;
            }

            return subset(solrQuery, query, query.getQueryConfig(), queryResponse, allResults);
        } catch (Exception e) {
            _log.error(e, e);

            if (!_swallowException) {
                throw new SearchException(e.getMessage());
            }

            return new HitsImpl();
        }
    }

    public void setSolrServer(SolrServer solrServer) {
        _solrServer = solrServer;
    }

    public void setSwallowException(boolean swallowException) {
        _swallowException = swallowException;
    }

    protected Hits doSearch(SearchContext searchContext, Query query) throws Exception {

        SolrQuery solrQuery = translateQuery(searchContext.getCompanyId(), query, searchContext.getSorts(),
                searchContext.getStart(), searchContext.getEnd());

        Map<String, Facet> facets = searchContext.getFacets();

        for (Facet facet : facets.values()) {
            if (facet.isStatic()) {
                continue;
            }

            FacetConfiguration facetConfiguration = facet.getFacetConfiguration();

            if (facet instanceof RangeFacet) {
                solrQuery.addFacetField(facetConfiguration.getFieldName());

                JSONObject dataJSONObject = facetConfiguration.getData();

                JSONArray rangesJSONArray = dataJSONObject.getJSONArray("ranges");

                if (rangesJSONArray == null) {
                    continue;
                }

                for (int i = 0; i < rangesJSONArray.length(); i++) {
                    JSONObject rangeJSONObject = rangesJSONArray.getJSONObject(i);

                    String range = rangeJSONObject.getString("range");

                    String facetQuery = facetConfiguration.getFieldName() + StringPool.COLON + range;

                    solrQuery.addFacetQuery(facetQuery);
                }
            } else {
                solrQuery.addFacetField(facetConfiguration.getFieldName());
            }
        }

        solrQuery.setFacetLimit(-1);

        QueryResponse queryResponse = _solrServer.query(solrQuery);

        boolean allResults = false;

        if (solrQuery.getRows() == 0) {
            allResults = true;
        }

        List<FacetField> facetFields = queryResponse.getFacetFields();

        if (facetFields != null) {
            for (FacetField facetField : facetFields) {
                Facet facet = facets.get(facetField.getName());

                FacetCollector facetCollector = null;

                if (facet instanceof RangeFacet) {
                    facetCollector = new SolrFacetQueryCollector(facetField.getName(),
                            queryResponse.getFacetQuery());
                } else {
                    facetCollector = new SolrFacetFieldCollector(facetField.getName(), facetField);
                }

                facet.setFacetCollector(facetCollector);
            }
        }

        return subset(solrQuery, query, query.getQueryConfig(), queryResponse, allResults);
    }

    protected String getSnippet(SolrDocument solrDocument, Set<String> queryTerms,
            Map<String, Map<String, List<String>>> highlights) {

        if (Validator.isNull(highlights)) {
            return StringPool.BLANK;
        }

        String key = (String) solrDocument.getFieldValue(Field.UID);

        List<String> snippets = highlights.get(key).get(Field.CONTENT);

        String snippet = StringUtil.merge(snippets, "...");

        if (Validator.isNotNull(snippet)) {
            snippet = snippet + "...";
        } else {
            snippet = StringPool.BLANK;
        }

        Matcher matcher = Pattern.compile("<em>(.*?)</em>").matcher(snippet);

        while (matcher.find()) {
            queryTerms.add(matcher.group(1));
        }

        snippet = StringUtil.replace(snippet, "<em>", "");
        snippet = StringUtil.replace(snippet, "</em>", "");

        return snippet;
    }

    protected Hits subset(SolrQuery solrQuery, Query query, QueryConfig queryConfig, QueryResponse queryResponse,
            boolean allResults) throws Exception {

        long startTime = System.currentTimeMillis();

        Hits hits = new HitsImpl();

        SolrDocumentList solrDocumentList = queryResponse.getResults();

        long total = solrDocumentList.getNumFound();

        if (allResults && (total > 0)) {
            solrQuery.setRows((int) total);

            queryResponse = _solrServer.query(solrQuery);

            return subset(solrQuery, query, queryConfig, queryResponse, false);
        }

        float maxScore = 1;

        if (queryConfig.isScoreEnabled()) {
            maxScore = solrDocumentList.getMaxScore();
        }

        int subsetTotal = solrDocumentList.size();

        Document[] documents = new DocumentImpl[subsetTotal];
        String[] snippets = new String[subsetTotal];
        float[] scores = new float[subsetTotal];

        int j = 0;

        Set<String> queryTerms = new HashSet<String>();

        Map<String, Map<String, List<String>>> highlights = queryResponse.getHighlighting();

        for (SolrDocument solrDocument : solrDocumentList) {
            Document document = new DocumentImpl();

            Collection<String> names = solrDocument.getFieldNames();

            for (String name : names) {
                Collection<Object> fieldValues = solrDocument.getFieldValues(name);

                Field field = new Field(name,
                        ArrayUtil.toStringArray(fieldValues.toArray(new Object[fieldValues.size()])));

                document.add(field);
            }

            float score = 1;

            if (queryConfig.isScoreEnabled()) {
                score = GetterUtil.getFloat(String.valueOf(solrDocument.getFieldValue("score")));
            }

            documents[j] = document;

            if (queryConfig.isHighlightEnabled()) {
                snippets[j] = getSnippet(solrDocument, queryTerms, highlights);
            } else {
                snippets[j] = StringPool.BLANK;
            }

            scores[j] = score / maxScore;

            j++;
        }

        float searchTime = (float) (System.currentTimeMillis() - startTime) / Time.SECOND;

        hits.setDocs(documents);
        hits.setLength((int) total);
        hits.setQuery(query);
        hits.setQueryTerms(queryTerms.toArray(new String[queryTerms.size()]));
        hits.setScores(scores);
        hits.setSearchTime(searchTime);
        hits.setSnippets(snippets);
        hits.setStart(startTime);

        return hits;
    }

    protected SolrQuery translateQuery(long companyId, Query query, Sort[] sorts, int start, int end)
            throws Exception {

        QueryTranslatorUtil.translateForSolr(query);

        String queryString = query.toString();

        QueryConfig queryConfig = query.getQueryConfig();

        SolrQuery solrQuery = new SolrQuery();

        solrQuery.setHighlight(queryConfig.isHighlightEnabled());
        solrQuery.setHighlightFragsize(queryConfig.getHighlightFragmentSize());
        solrQuery.setHighlightSnippets(queryConfig.getHighlightSnippetSize());
        solrQuery.setIncludeScore(queryConfig.isScoreEnabled());
        solrQuery.setQuery(queryString);

        if ((start == QueryUtil.ALL_POS) && (end == QueryUtil.ALL_POS)) {
            solrQuery.setRows(0);
        } else {
            solrQuery.setRows(end - start);
            solrQuery.setStart(start);
        }

        if ((sorts != null) && (sorts.length > 0)) {
            for (Sort sort : sorts) {
                if (sort == null) {
                    continue;
                }

                String sortFieldName = sort.getFieldName();

                if (ArrayUtil.contains(PortletPropsValues.SOLR_SORTABLE_TEXT_FIELDS, sortFieldName)) {

                    sortFieldName = GetterUtil.getString(
                            PortletProps.get(PortletPropsKeys.SOLR_COPY_FIELDS, new Filter(sortFieldName)));
                }

                ORDER order = ORDER.asc;

                if (sortFieldName == null) {
                    sortFieldName = "score";

                    order = ORDER.desc;
                } else if (sort.isReverse()) {
                    order = ORDER.desc;
                }

                solrQuery.addSortField(sortFieldName, order);
            }
        }

        return solrQuery;
    }

    private static Log _log = LogFactoryUtil.getLog(SolrIndexSearcherImpl.class);

    private SolrServer _solrServer;
    private boolean _swallowException;

}