org.apache.solr.search.SwitchQParserPlugin Maven / Gradle / Ivy
Show all versions of solr-core Show documentation
/*
* 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