All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencms.search.solr.CmsSolrQuery Maven / Gradle / Ivy

Go to download

OpenCms is an enterprise-ready, easy to use website content management system based on Java and XML technology. Offering a complete set of features, OpenCms helps content managers worldwide to create and maintain beautiful websites fast and efficiently.

There is a newer version: 18.0
Show newest version
/*
 * File   : $Source$
 * Date   : $Date$
 * Version: $Revision$
 *
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (C) 2002 - 2008 Alkacon Software (http://www.alkacon.com)
 *
 * 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.
 *
 * For further information about Alkacon Software, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.search.solr;

import org.opencms.file.CmsObject;
import org.opencms.file.CmsPropertyDefinition;
import org.opencms.i18n.CmsEncoder;
import org.opencms.main.OpenCms;
import org.opencms.search.fields.CmsSearchField;
import org.opencms.util.CmsPair;
import org.opencms.util.CmsRequestUtil;
import org.opencms.util.CmsStringUtil;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.common.params.CommonParams;

/**
 * A Solr search query.

*/ public class CmsSolrQuery extends SolrQuery { /** A constant to add the score field to the result documents. */ public static final String ALL_RETURN_FIELDS = "*,score"; /** The default facet date gap. */ public static final String DEFAULT_FACET_DATE_GAP = "+1DAY"; /** The default query. */ public static final String DEFAULT_QUERY = "*:*"; /** The query type. */ public static final String DEFAULT_QUERY_TYPE = "edismax"; /** The default search result count. */ public static final Integer DEFAULT_ROWS = new Integer(10); /** A constant to add the score field to the result documents. */ public static final String MINIMUM_FIELDS = CmsSearchField.FIELD_PATH + "," + CmsSearchField.FIELD_TYPE + "," + CmsSearchField.FIELD_ID; /** A constant to add the score field to the result documents. */ public static final String STRUCTURE_FIELDS = CmsSearchField.FIELD_PATH + "," + CmsSearchField.FIELD_TYPE + "," + CmsSearchField.FIELD_ID + "," + CmsSearchField.FIELD_CATEGORY + "," + CmsSearchField.FIELD_DATE_CONTENT + "," + CmsSearchField.FIELD_DATE_CREATED + "," + CmsSearchField.FIELD_DATE_EXPIRED + "," + CmsSearchField.FIELD_DATE_LASTMODIFIED + "," + CmsSearchField.FIELD_DATE_RELEASED + "," + CmsSearchField.FIELD_SUFFIX + "," + CmsSearchField.FIELD_DEPENDENCY_TYPE + "," + CmsSearchField.FIELD_DESCRIPTION + "," + CmsPropertyDefinition.PROPERTY_TITLE + CmsSearchField.FIELD_DYNAMIC_PROPERTIES + "," + CmsSearchField.FIELD_RESOURCE_LOCALES + "," + CmsSearchField.FIELD_CONTENT_LOCALES + "," + CmsSearchField.FIELD_SCORE + "," + CmsSearchField.FIELD_PARENT_FOLDERS; /** The serial version UID. */ private static final long serialVersionUID = -2387357736597627703L; /** The facet date gap to use for date facets. */ private String m_facetDateGap = DEFAULT_FACET_DATE_GAP; /** Ignore expiration flag. */ private boolean m_ignoreExpiration; /** The parameters given by the 'query string'. */ private Map m_queryParameters = new HashMap(); /** The search words. */ private String m_text; /** The name of the field to search the text in. */ private List m_textSearchFields = new ArrayList(); /** * Default constructor.

*/ public CmsSolrQuery() { this(null, null); } /** * Public constructor.

* * @param cms the current OpenCms context * @param queryParams the Solr query parameters */ public CmsSolrQuery(CmsObject cms, Map queryParams) { setQuery(DEFAULT_QUERY); setFields(ALL_RETURN_FIELDS); setRequestHandler(DEFAULT_QUERY_TYPE); setRows(DEFAULT_ROWS); // set the values from the request context if (cms != null) { setLocales(Collections.singletonList(cms.getRequestContext().getLocale())); setSearchRoots(Collections.singletonList(cms.getRequestContext().getSiteRoot() + "/")); } if (queryParams != null) { m_queryParameters = queryParams; } ensureParameters(); ensureReturnFields(); ensureExpiration(); } /** * Returns the resource type if only one is set as filter query.

* * @param fqs the field queries to check * * @return the type or null */ public static String getResourceType(String[] fqs) { String ret = null; int count = 0; if (fqs != null) { for (String fq : fqs) { if (fq.startsWith(CmsSearchField.FIELD_TYPE + ":")) { String val = fq.substring((CmsSearchField.FIELD_TYPE + ":").length()); val = val.replaceAll("\"", ""); if (OpenCms.getResourceManager().hasResourceType(val)) { count++; ret = val; } } } } return (count == 1) ? ret : null; } /** * Creates and adds a filter query.

* * @param fieldName the field name to create a filter query on * @param vals the values that should match for the given field * @param all true to combine the given values with 'AND', false for 'OR' * @param useQuotes true to surround the given values with double quotes, false otherwise */ public void addFilterQuery(String fieldName, List vals, boolean all, boolean useQuotes) { if (getFilterQueries() != null) { for (String fq : getFilterQueries()) { if (fq.startsWith(fieldName + ":")) { removeFilterQuery(fq); } } } addFilterQuery(createFilterQuery(fieldName, vals, all, useQuotes)); } /** * Adds the given fields/orders to the existing sort fields.

* * @param sortFields the sortFields to set */ public void addSortFieldOrders(Map sortFields) { if ((sortFields != null) && !sortFields.isEmpty()) { // add the sort fields to the query for (Map.Entry entry : sortFields.entrySet()) { addSort(entry.getKey(), entry.getValue()); } } } /** * @see java.lang.Object#clone() */ @Override public CmsSolrQuery clone() { CmsSolrQuery sq = new CmsSolrQuery(null, CmsRequestUtil.createParameterMap(toString())); sq.m_ignoreExpiration = m_ignoreExpiration; return sq; } /** * Ensures that the initial request parameters will overwrite the member values.

* * You can initialize the query with an HTTP request parameter then make some method calls * and finally re-ensure that the initial request parameters will overwrite the changes * made in the meanwhile.

*/ public void ensureParameters() { // overwrite already set values with values from query String if ((m_queryParameters != null) && !m_queryParameters.isEmpty()) { for (Map.Entry entry : m_queryParameters.entrySet()) { if (!entry.getKey().equals(CommonParams.FQ)) { // add or replace all parameters from the query String setParam(entry.getKey(), entry.getValue()); } else { // special handling for filter queries replaceFilterQueries(entry.getValue()); } } } } /** * Removes the expiration flag. */ public void removeExpiration() { if (getFilterQueries() != null) { for (String fq : getFilterQueries()) { if (fq.startsWith(CmsSearchField.FIELD_DATE_EXPIRED + ":") || fq.startsWith(CmsSearchField.FIELD_DATE_RELEASED + ":")) { removeFilterQuery(fq); } } } m_ignoreExpiration = true; } /** * Sets the categories only if not set in the query parameters.

* * @param categories the categories to set */ public void setCategories(List categories) { if ((categories != null) && !categories.isEmpty()) { addFilterQuery(CmsSearchField.FIELD_CATEGORY + CmsSearchField.FIELD_DYNAMIC_EXACT, categories, true, true); } } /** * Sets the categories only if not set in the query parameters.

* * @param categories the categories to set */ public void setCategories(String... categories) { setCategories(Arrays.asList(categories)); } /** * Sets date ranges.

* * This call will overwrite all existing date ranges for the given keys (name of the date facet field).

* * The parameter Map uses as:

*

    *
  • keys: Solr field name {@link org.opencms.search.fields.CmsSearchField} and *
  • values: pairs with min date as first and max date as second {@link org.opencms.util.CmsPair} *
* Alternatively you can use Solr standard query syntax like:

*

    *
  • +created:[* TO NOW] *
  • +lastmodified:[' + date + ' TO NOW] *
* whereby date is Solr formated: * {@link org.opencms.search.solr.CmsSolrDocument#DF} *

* * @param dateRanges the ranges map with field name as key and a CmsPair with min date as first and max date as second */ public void setDateRanges(Map> dateRanges) { if ((dateRanges != null) && !dateRanges.isEmpty()) { // remove the date ranges for (Map.Entry> entry : dateRanges.entrySet()) { removeFacetField(entry.getKey()); } // add the date ranges for (Map.Entry> entry : dateRanges.entrySet()) { addDateRangeFacet( entry.getKey(), entry.getValue().getFirst(), entry.getValue().getSecond(), m_facetDateGap); } } } /** * Sets the facetDateGap.

* * @param facetDateGap the facetDateGap to set */ public void setFacetDateGap(String facetDateGap) { m_facetDateGap = facetDateGap; } /** * Sets the highlightFields.

* * @param highlightFields the highlightFields to set */ public void setHighlightFields(List highlightFields) { setParam("hl.fl", CmsStringUtil.listAsString(highlightFields, ",")); } /** * Sets the highlightFields.

* * @param highlightFields the highlightFields to set */ public void setHighlightFields(String... highlightFields) { setParam("hl.fl", CmsStringUtil.arrayAsString(highlightFields, ",")); } /** * Sets the locales only if not set in the query parameters.

* * @param locales the locales to set */ public void setLocales(List locales) { m_textSearchFields = new ArrayList(); if ((locales == null) || locales.isEmpty()) { m_textSearchFields.add(CmsSearchField.FIELD_TEXT); if (getFilterQueries() != null) { for (String fq : getFilterQueries()) { if (fq.startsWith(CmsSearchField.FIELD_CONTENT_LOCALES + ":")) { removeFilterQuery(fq); } } } } else { List localeStrings = new ArrayList(); for (Locale locale : locales) { localeStrings.add(locale.toString()); if (!m_textSearchFields.contains("text") && !OpenCms.getLocaleManager().getAvailableLocales().contains(locale)) { // if the locale is not configured in the opencms-system.xml // there will no localized text fields, so take the general one m_textSearchFields.add("text"); } else { m_textSearchFields.add("text_" + locale); } } addFilterQuery(CmsSearchField.FIELD_CONTENT_LOCALES, localeStrings, false, false); } if (m_text != null) { setText(m_text); } } /** * Sets the locales only if not set in the query parameters.

* * @param locales the locales to set */ public void setLocales(Locale... locales) { setLocales(Arrays.asList(locales)); } /** * @see org.apache.solr.client.solrj.SolrQuery#setRequestHandler(java.lang.String) */ @Override public SolrQuery setRequestHandler(String qt) { SolrQuery q = super.setRequestHandler(qt); if (m_text != null) { setText(m_text); } return q; } /** * Sets the resource types only if not set in the query parameters.

* * @param resourceTypes the resourceTypes to set */ public void setResourceTypes(List resourceTypes) { if ((resourceTypes != null) && !resourceTypes.isEmpty()) { addFilterQuery(CmsSearchField.FIELD_TYPE, resourceTypes, false, false); } } /** * Sets the resource types only if not set in the query parameters.

* * @param resourceTypes the resourceTypes to set */ public void setResourceTypes(String... resourceTypes) { setResourceTypes(Arrays.asList(resourceTypes)); } /** * Sets the search roots only if not set as query parameter.

* * @param searchRoots the searchRoots to set */ public void setSearchRoots(List searchRoots) { if ((searchRoots != null) && !searchRoots.isEmpty()) { addFilterQuery(CmsSearchField.FIELD_PARENT_FOLDERS, searchRoots, false, true); } } /** * Sets the search roots only if not set as query parameter.

* * @param searchRoots the searchRoots to set */ public void setSearchRoots(String... searchRoots) { setSearchRoots(Arrays.asList(searchRoots)); } /** * Sets the return fields 'fl' to a predefined set that does not contain content specific fields.

* * @param structureQuery the true to return only structural fields */ public void setStructureQuery(boolean structureQuery) { if (structureQuery) { setFields(STRUCTURE_FIELDS); } } /** * Sets the text.

* * @param text the text to set */ public void setText(String text) { m_text = text; if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(text)) { setQuery(createTextQuery(text)); } } /** * Sets the textSearchFields.

* * @param textSearchFields the textSearchFields to set */ public void setTextSearchFields(List textSearchFields) { m_textSearchFields = textSearchFields; if (m_text != null) { setText(m_text); } } /** * Sets the textSearchFields.

* * @param textSearchFields the textSearchFields to set */ public void setTextSearchFields(String... textSearchFields) { setTextSearchFields(Arrays.asList(textSearchFields)); } /** * @see org.apache.solr.common.params.ModifiableSolrParams#toString() */ @Override public String toString() { return CmsEncoder.decode(super.toString()); } /** * Creates a filter query on the given field name.

* * Creates and adds a filter query.

* * @param fieldName the field name to create a filter query on * @param vals the values that should match for the given field * @param all true to combine the given values with 'AND', false for 'OR' * @param useQuotes true to surround the given values with double quotes, false otherwise * * @return a filter query String e.g. fq=fieldname:val1 */ private String createFilterQuery(String fieldName, List vals, boolean all, boolean useQuotes) { String filterQuery = null; if ((vals != null)) { if (vals.size() == 1) { if (useQuotes) { filterQuery = fieldName + ":" + "\"" + vals.get(0) + "\""; } else { filterQuery = fieldName + ":" + vals.get(0); } } else if (vals.size() > 1) { filterQuery = fieldName + ":("; for (int j = 0; j < vals.size(); j++) { String val; if (useQuotes) { val = "\"" + vals.get(j) + "\""; } else { val = vals.get(j); } filterQuery += val; if (vals.size() > (j + 1)) { if (all) { filterQuery += " AND "; } else { filterQuery += " OR "; } } } filterQuery += ")"; } } return filterQuery; } /** * Creates a OR combined 'q' parameter.

* * @param text * * @return returns the 'q' parameter */ private String createTextQuery(String text) { if (m_textSearchFields.isEmpty()) { m_textSearchFields.add(CmsSearchField.FIELD_TEXT); } String q = "{!q.op=OR type=" + getRequestHandler() + " qf="; boolean first = true; for (String textField : m_textSearchFields) { if (!first) { q += " "; } q += textField; } q += "}" + text; return q; } /** * Ensures that expired and not yet released resources are not returned by default.

*/ private void ensureExpiration() { boolean expirationDateSet = false; boolean releaseDateSet = false; if (getFilterQueries() != null) { for (String fq : getFilterQueries()) { if (fq.startsWith(CmsSearchField.FIELD_DATE_EXPIRED + ":")) { expirationDateSet = true; } if (fq.startsWith(CmsSearchField.FIELD_DATE_RELEASED + ":")) { releaseDateSet = true; } } } if (!expirationDateSet) { addFilterQuery(CmsSearchField.FIELD_DATE_EXPIRED + ":[NOW TO *]"); } if (!releaseDateSet) { addFilterQuery(CmsSearchField.FIELD_DATE_RELEASED + ":[* TO NOW]"); } } /** * Ensures that at least the 'path' and the 'type' are part of the fields returned field list.

* * @see CommonParams#FL */ private void ensureReturnFields() { String[] fl = getParams(CommonParams.FL); if ((fl != null) && (fl.length > 0)) { List result = new ArrayList(); for (String field : fl) { String commasep = field.replaceAll(" ", ","); List list = CmsStringUtil.splitAsList(commasep, ','); if (!list.contains("*")) { for (String reqField : CmsStringUtil.splitAsList(MINIMUM_FIELDS, ",")) { if (!list.contains(reqField)) { list.add(reqField); } } } result.addAll(list); } setParam(CommonParams.FL, CmsStringUtil.arrayAsString(result.toArray(new String[0]), ",")); } } /** * Removes those filter queries that restrict the fields used in the given filter query Strings.

* * Searches in the given Strings for a ":", then takes the field name part * and removes the already set filter queries queries that are matching the same field name.

* * @param fqs the filter query Strings in the format fq=fieldname:value that should be removed */ private void removeFilterQueries(String[] fqs) { // iterate over the given filter queries to remove for (String fq : fqs) { int idx = fq.indexOf(':'); if (idx != -1) { // get the field name of the fq to remove String fieldName = fq.substring(0, idx); // iterate over the fqs of the already existing fqs from the solr query if (getFilterQueries() != null) { for (String sfq : getFilterQueries()) { if (sfq.startsWith(fieldName + ":")) { // there exists a filter query for exact the same field, remove it removeFilterQuery(sfq); } } } } } } /** * Removes the given filter queries, if already set and then adds the filter queries again.

* * @param fqs the filter queries to remove */ private void replaceFilterQueries(String[] fqs) { removeFilterQueries(fqs); addFilterQuery(fqs); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy