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

org.apache.solr.search.SwitchQParserPlugin Maven / Gradle / Ivy

There is a newer version: 9.7.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.solr.search;

import org.apache.lucene.search.Query;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.handler.component.SearchHandler; // jdoc

import org.apache.commons.lang3.StringUtils;

/**
 * 

A QParserPlugin that acts like a "switch/case" statement.

* *

* QParser's produced by this plugin will take their primary input string, * trimmed and prefixed with "case.", to use as a key to lookup a * "switch case" in the parser's local params. If a matching local param is * found the resulting param value will then be parsed as a subquery, and * returned as the parse result. *

*

* The "case" local param can be optionally be specified as a * switch case to match missing (or blank) input strings. * The "default" local param can optionally be specified * as a default case to use if the input string does not match any other * switch case local params. If default is not specified, * then any input which does not match a switch case local param will result * in a syntax error. *

* *

* In the examples below, the result of each query would be XXX.... *

*
 *  q={!switch case.foo=XXX case.bar=zzz case.yak=qqq}foo
 *  q={!switch case.foo=qqq case.bar=XXX case.yak=zzz} bar  // extra whitespace
 *  q={!switch case.foo=qqq case.bar=zzz default=XXX}asdf   // fallback on default
 *  q={!switch case=XXX case.bar=zzz case.yak=qqq}          // blank input
 * 
* *

* A practical usage of this QParsePlugin, is in specifying "appends" * fq params in the configuration of a {@link SearchHandler}, to * provide a fixed set of filter options for clients using custom parameter * names. * Using the example configuration below, clients can optionally specify the * custom parameters in_stock and shipping to * override the default filtering behavior, but are limited to the specific * set of legal values (shipping=any|free, * in_stock=yes|no|all). *

* *
 * <requestHandler name="/select" class="solr.SearchHandler">
 *   <lst name="defaults">
 *     <str name="in_stock">yes</str>
 *     <str name="shipping">any</str>
 *   </lst>
 *   <lst name="appends">
 *     <str name="fq">{!switch case.all='*:*'
 *                             case.yes='inStock:true'
 *                             case.no='inStock:false'
 *                             v=$in_stock}</str>
 *     <str name="fq">{!switch case.any='*:*'
 *                             case.free='shipping_cost:0.0'
 *                             v=$shipping}</str>
 *   </lst>
 * </requestHandler>
* *

* A slightly more interesting variant of the shipping example above, would be * to combine the switch parser with the frange parser, to allow the client to specify an * arbitrary "max shipping" amount that will be used to build a filter if and only if a * value is specified. Example: *

*
 * <requestHandler name="/select" class="solr.SearchHandler">
 *   <lst name="invariants">
 *     <str name="shipping_fq">{!frange u=$shipping}shipping_cost</str>
 *   </lst>
 *   <lst name="defaults">
 *     <str name="shipping">any</str>
 *   </lst>
 *   <lst name="appends">
 *     <str name="fq">{!switch case='*:*'
 *                             case.any='*:*'
 *                             default=$shipping_fq
 *                             v=$shipping}</str>
 *   </lst>
 * </requestHandler>
* *

* With the above configuration a client that specifies shipping=any, or * does not specify a shipping param at all, will not have the results * filtered. But if a client specifies a numeric value (ie: shipping=10, * shipping=5, etc..) then the results will be limited to documents whose * shipping_cost field has a value less then that number. *

* *

* A similar use case would be to combine the switch parser with the bbox parser to * support an optional geographic filter that is applied if and only if the client * specifies a location param containing a lat,lon pair to be used as * the center of the bounding box: *

*
 * <requestHandler name="/select" class="solr.SearchHandler">
 *   <lst name="invariants">
 *     <str name="bbox_fq">{!bbox pt=$location sfield=geo d=$dist}</str>
 *   </lst>
 *   <lst name="defaults">
 *     <str name="dist">100</str>
 *   </lst>
 *   <lst name="appends">
 *     <str name="fq">{!switch case='*:*' 
 *                             default=$bbox_fq 
 *                             v=$location}</str>
 *   </lst>
 * </requestHandler>
*/ public class SwitchQParserPlugin extends QParserPlugin { public static final String NAME = "switch"; /** * Used as both a local params key to find the "default" if no * blank input is provided to the parser, as well as a prefix (followed by * '.' for looking up the switch input. */ public static String SWITCH_CASE = "case"; /** * A local param whose value, if specified, is used if no switch case * matches the parser input. If this param is not specified, and no * switch case matches the parser input, an error is returned. */ public static String SWITCH_DEFAULT = "default"; @Override public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) { return new QParser(qstr, localParams, params, req) { QParser subParser; @Override public Query parse() throws SyntaxError { String val = localParams.get(QueryParsing.V); // we don't want to wrapDefaults arround params, because then // clients could add their own switch options String subQ = localParams.get(SWITCH_DEFAULT); subQ = StringUtils.isBlank(val) ? localParams.get(SWITCH_CASE, subQ) : localParams.get(SWITCH_CASE + "." + val.trim(), subQ); if (null == subQ) { throw new SyntaxError("No "+SWITCH_DEFAULT+", and no switch case matching specified query string: \"" + val + "\""); } subParser = subQuery(subQ, null); return subParser.getQuery(); } @Override public String[] getDefaultHighlightFields() { return subParser.getDefaultHighlightFields(); } @Override public Query getHighlightQuery() throws SyntaxError { return subParser.getHighlightQuery(); } @Override public void addDebugInfo(NamedList debugInfo) { subParser.addDebugInfo(debugInfo); } }; } }