SOLR-1149 -- Made QParserPlugin and related classes extendible as an experimental API

git-svn-id: https://svn.apache.org/repos/asf/lucene/solr/trunk@777656 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Shalin Shekhar Mangar 2009-05-22 18:58:38 +00:00
parent 7d80857e70
commit b1447effbe
6 changed files with 255 additions and 216 deletions

View File

@ -467,6 +467,9 @@ Other Changes
32. Upgraded to Lucene 2.9-dev r776177 (shalin)
33. SOLR-1149: Made QParserPlugin and related classes extendible as an experimental API.
(Kaktu Chakarabati via shalin)
Build
----------------------
1. SOLR-776: Added in ability to sign artifacts via Ant for releases (gsingers)

View File

@ -0,0 +1,228 @@
/**
* 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.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.DefaultSolrParams;
import org.apache.solr.common.params.DisMaxParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.util.SolrPluginUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Query parser for dismax queries
* <p/>
* <b>Note: This API is experimental and may change in non backward-compatible ways in the future</b>
*
* @version $Id$
*/
public class DisMaxQParser extends QParser {
/**
* A field we can't ever find in any schema, so we can safely tell DisjunctionMaxQueryParser to use it as our
* defaultField, and map aliases from it to any field in our schema.
*/
private static String IMPOSSIBLE_FIELD_NAME = "\uFFFC\uFFFC\uFFFC";
public DisMaxQParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
super(qstr, localParams, params, req);
}
protected Map<String, Float> queryFields;
protected Query parsedUserQuery;
protected String[] boostParams;
protected List<Query> boostQueries;
protected Query altUserQuery;
protected QParser altQParser;
public Query parse() throws ParseException {
SolrParams solrParams = localParams == null ? params : new DefaultSolrParams(localParams, params);
IndexSchema schema = req.getSchema();
queryFields = SolrPluginUtils.parseFieldBoosts(solrParams.getParams(DisMaxParams.QF));
Map<String, Float> phraseFields = SolrPluginUtils.parseFieldBoosts(solrParams.getParams(DisMaxParams.PF));
float tiebreaker = solrParams.getFloat(DisMaxParams.TIE, 0.0f);
int pslop = solrParams.getInt(DisMaxParams.PS, 0);
int qslop = solrParams.getInt(DisMaxParams.QS, 0);
/* a generic parser for parsing regular lucene queries */
QueryParser p = schema.getSolrQueryParser(null);
/* a parser for dealing with user input, which will convert
* things to DisjunctionMaxQueries
*/
SolrPluginUtils.DisjunctionMaxQueryParser up =
new SolrPluginUtils.DisjunctionMaxQueryParser(schema, IMPOSSIBLE_FIELD_NAME);
up.addAlias(IMPOSSIBLE_FIELD_NAME,
tiebreaker, queryFields);
up.setPhraseSlop(qslop);
/* for parsing sloppy phrases using DisjunctionMaxQueries */
SolrPluginUtils.DisjunctionMaxQueryParser pp =
new SolrPluginUtils.DisjunctionMaxQueryParser(schema, IMPOSSIBLE_FIELD_NAME);
pp.addAlias(IMPOSSIBLE_FIELD_NAME,
tiebreaker, phraseFields);
pp.setPhraseSlop(pslop);
/* the main query we will execute. we disable the coord because
* this query is an artificial construct
*/
BooleanQuery query = new BooleanQuery(true);
/* * * Main User Query * * */
parsedUserQuery = null;
String userQuery = getString();
altUserQuery = null;
if (userQuery == null || userQuery.trim().length() < 1) {
// If no query is specified, we may have an alternate
String altQ = solrParams.get(DisMaxParams.ALTQ);
if (altQ != null) {
altQParser = subQuery(altQ, null);
altUserQuery = altQParser.parse();
query.add(altUserQuery, BooleanClause.Occur.MUST);
} else {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "missing query string");
}
} else {
// There is a valid query string
userQuery = SolrPluginUtils.partialEscape(SolrPluginUtils.stripUnbalancedQuotes(userQuery)).toString();
userQuery = SolrPluginUtils.stripIllegalOperators(userQuery).toString();
String minShouldMatch = solrParams.get(DisMaxParams.MM, "100%");
Query dis = up.parse(userQuery);
parsedUserQuery = dis;
if (dis instanceof BooleanQuery) {
BooleanQuery t = new BooleanQuery();
SolrPluginUtils.flattenBooleanQuery(t, (BooleanQuery) dis);
SolrPluginUtils.setMinShouldMatch(t, minShouldMatch);
parsedUserQuery = t;
}
query.add(parsedUserQuery, BooleanClause.Occur.MUST);
/* * * Add on Phrases for the Query * * */
/* build up phrase boosting queries */
/* if the userQuery already has some quotes, strip them out.
* we've already done the phrases they asked for in the main
* part of the query, this is to boost docs that may not have
* matched those phrases but do match looser phrases.
*/
String userPhraseQuery = userQuery.replace("\"", "");
Query phrase = pp.parse("\"" + userPhraseQuery + "\"");
if (null != phrase) {
query.add(phrase, BooleanClause.Occur.SHOULD);
}
}
/* * * Boosting Query * * */
boostParams = solrParams.getParams(DisMaxParams.BQ);
//List<Query> boostQueries = SolrPluginUtils.parseQueryStrings(req, boostParams);
boostQueries = null;
if (boostParams != null && boostParams.length > 0) {
boostQueries = new ArrayList<Query>();
for (String qs : boostParams) {
if (qs.trim().length() == 0) continue;
Query q = subQuery(qs, null).parse();
boostQueries.add(q);
}
}
if (null != boostQueries) {
if (1 == boostQueries.size() && 1 == boostParams.length) {
/* legacy logic */
Query f = boostQueries.get(0);
if (1.0f == f.getBoost() && f instanceof BooleanQuery) {
/* if the default boost was used, and we've got a BooleanQuery
* extract the subqueries out and use them directly
*/
for (Object c : ((BooleanQuery) f).clauses()) {
query.add((BooleanClause) c);
}
} else {
query.add(f, BooleanClause.Occur.SHOULD);
}
} else {
for (Query f : boostQueries) {
query.add(f, BooleanClause.Occur.SHOULD);
}
}
}
/* * * Boosting Functions * * */
String[] boostFuncs = solrParams.getParams(DisMaxParams.BF);
if (null != boostFuncs && 0 != boostFuncs.length) {
for (String boostFunc : boostFuncs) {
if (null == boostFunc || "".equals(boostFunc)) continue;
Map<String, Float> ff = SolrPluginUtils.parseFieldBoosts(boostFunc);
for (String f : ff.keySet()) {
Query fq = subQuery(f, FunctionQParserPlugin.NAME).parse();
Float b = ff.get(f);
if (null != b) {
fq.setBoost(b);
}
query.add(fq, BooleanClause.Occur.SHOULD);
}
}
}
return query;
}
@Override
public String[] getDefaultHighlightFields() {
return queryFields.keySet().toArray(new String[queryFields.keySet().size()]);
}
@Override
public Query getHighlightQuery() throws ParseException {
return parsedUserQuery;
}
public void addDebugInfo(NamedList<Object> debugInfo) {
super.addDebugInfo(debugInfo);
debugInfo.add("altquerystring", altUserQuery);
if (null != boostQueries) {
debugInfo.add("boost_queries", boostParams);
debugInfo.add("parsed_boost_queries",
QueryParsing.toString(boostQueries, req.getSchema()));
}
debugInfo.add("boostfuncs", req.getParams().getParams(DisMaxParams.BF));
}
}

View File

@ -16,22 +16,10 @@
*/
package org.apache.solr.search;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.DefaultSolrParams;
import org.apache.solr.common.params.DisMaxParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.util.SolrPluginUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Create a dismax query from the input value.
* <br>Other parameters: all main query related parameters from the {@link org.apache.solr.handler.DisMaxRequestHandler} are supported.
@ -46,193 +34,6 @@ public class DisMaxQParserPlugin extends QParserPlugin {
}
public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
return new DismaxQParser(qstr, localParams, params, req);
}
}
class DismaxQParser extends QParser {
/**
* A field we can't ever find in any schema, so we can safely tell
* DisjunctionMaxQueryParser to use it as our defaultField, and
* map aliases from it to any field in our schema.
*/
private static String IMPOSSIBLE_FIELD_NAME = "\uFFFC\uFFFC\uFFFC";
public DismaxQParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
super(qstr, localParams, params, req);
}
Map<String,Float> queryFields;
Query parsedUserQuery;
private String[] boostParams;
private List<Query> boostQueries;
private Query altUserQuery;
private QParser altQParser;
public Query parse() throws ParseException {
SolrParams solrParams = localParams == null ? params : new DefaultSolrParams(localParams, params);
IndexSchema schema = req.getSchema();
queryFields = SolrPluginUtils.parseFieldBoosts(solrParams.getParams(DisMaxParams.QF));
Map<String,Float> phraseFields = SolrPluginUtils.parseFieldBoosts(solrParams.getParams(DisMaxParams.PF));
float tiebreaker = solrParams.getFloat(DisMaxParams.TIE, 0.0f);
int pslop = solrParams.getInt(DisMaxParams.PS, 0);
int qslop = solrParams.getInt(DisMaxParams.QS, 0);
/* a parser for dealing with user input, which will convert
* things to DisjunctionMaxQueries
*/
SolrPluginUtils.DisjunctionMaxQueryParser up =
new SolrPluginUtils.DisjunctionMaxQueryParser(schema, IMPOSSIBLE_FIELD_NAME);
up.addAlias(IMPOSSIBLE_FIELD_NAME,
tiebreaker, queryFields);
up.setPhraseSlop(qslop);
/* for parsing sloppy phrases using DisjunctionMaxQueries */
SolrPluginUtils.DisjunctionMaxQueryParser pp =
new SolrPluginUtils.DisjunctionMaxQueryParser(schema, IMPOSSIBLE_FIELD_NAME);
pp.addAlias(IMPOSSIBLE_FIELD_NAME,
tiebreaker, phraseFields);
pp.setPhraseSlop(pslop);
/* the main query we will execute. we disable the coord because
* this query is an artificial construct
*/
BooleanQuery query = new BooleanQuery(true);
/* * * Main User Query * * */
parsedUserQuery = null;
String userQuery = getString();
altUserQuery = null;
if( userQuery == null || userQuery.trim().length() < 1 ) {
// If no query is specified, we may have an alternate
String altQ = solrParams.get( DisMaxParams.ALTQ );
if (altQ != null) {
altQParser = subQuery(altQ, null);
altUserQuery = altQParser.parse();
query.add( altUserQuery , BooleanClause.Occur.MUST );
} else {
throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "missing query string" );
}
}
else {
// There is a valid query string
userQuery = SolrPluginUtils.partialEscape(SolrPluginUtils.stripUnbalancedQuotes(userQuery)).toString();
userQuery = SolrPluginUtils.stripIllegalOperators(userQuery).toString();
String minShouldMatch = solrParams.get(DisMaxParams.MM, "100%");
Query dis = up.parse(userQuery);
parsedUserQuery = dis;
if (dis instanceof BooleanQuery) {
BooleanQuery t = new BooleanQuery();
SolrPluginUtils.flattenBooleanQuery(t, (BooleanQuery)dis);
SolrPluginUtils.setMinShouldMatch(t, minShouldMatch);
parsedUserQuery = t;
}
query.add(parsedUserQuery, BooleanClause.Occur.MUST);
/* * * Add on Phrases for the Query * * */
/* build up phrase boosting queries */
/* if the userQuery already has some quotes, strip them out.
* we've already done the phrases they asked for in the main
* part of the query, this is to boost docs that may not have
* matched those phrases but do match looser phrases.
*/
String userPhraseQuery = userQuery.replace("\"","");
Query phrase = pp.parse("\"" + userPhraseQuery + "\"");
if (null != phrase) {
query.add(phrase, BooleanClause.Occur.SHOULD);
}
}
/* * * Boosting Query * * */
boostParams = solrParams.getParams(DisMaxParams.BQ);
//List<Query> boostQueries = SolrPluginUtils.parseQueryStrings(req, boostParams);
boostQueries=null;
if (boostParams!=null && boostParams.length>0) {
boostQueries = new ArrayList<Query>();
for (String qs : boostParams) {
if (qs.trim().length()==0) continue;
Query q = subQuery(qs, null).parse();
boostQueries.add(q);
}
}
if (null != boostQueries) {
if(1 == boostQueries.size() && 1 == boostParams.length) {
/* legacy logic */
Query f = boostQueries.get(0);
if (1.0f == f.getBoost() && f instanceof BooleanQuery) {
/* if the default boost was used, and we've got a BooleanQuery
* extract the subqueries out and use them directly
*/
for (Object c : ((BooleanQuery)f).clauses()) {
query.add((BooleanClause)c);
}
} else {
query.add(f, BooleanClause.Occur.SHOULD);
}
} else {
for(Query f : boostQueries) {
query.add(f, BooleanClause.Occur.SHOULD);
}
}
}
/* * * Boosting Functions * * */
String[] boostFuncs = solrParams.getParams(DisMaxParams.BF);
if (null != boostFuncs && 0 != boostFuncs.length) {
for (String boostFunc : boostFuncs) {
if(null == boostFunc || "".equals(boostFunc)) continue;
Map<String,Float> ff = SolrPluginUtils.parseFieldBoosts(boostFunc);
for (String f : ff.keySet()) {
Query fq = subQuery(f, FunctionQParserPlugin.NAME).parse();
Float b = ff.get(f);
if (null != b) {
fq.setBoost(b);
}
query.add(fq, BooleanClause.Occur.SHOULD);
}
}
}
return query;
}
@Override
public String[] getDefaultHighlightFields() {
String[] highFields = queryFields.keySet().toArray(new String[0]);
return highFields;
}
@Override
public Query getHighlightQuery() throws ParseException {
return parsedUserQuery;
}
public void addDebugInfo(NamedList<Object> debugInfo) {
super.addDebugInfo(debugInfo);
debugInfo.add("altquerystring", altUserQuery);
if (null != boostQueries) {
debugInfo.add("boost_queries", boostParams);
debugInfo.add("parsed_boost_queries",
QueryParsing.toString(boostQueries, req.getSchema()));
}
debugInfo.add("boostfuncs", req.getParams().getParams(DisMaxParams.BF));
return new DisMaxQParser(qstr, localParams, params, req);
}
}

View File

@ -27,14 +27,19 @@ import org.apache.solr.request.SolrQueryRequest;
import java.util.*;
/**
* <b>Note: This API is experimental and may change in non backward-compatible ways in the future</b>
*
* @version $Id$
*/
public abstract class QParser {
String qstr;
SolrParams params;
SolrParams localParams;
SolrQueryRequest req;
int recurseCount;
protected String qstr;
protected SolrParams params;
protected SolrParams localParams;
protected SolrQueryRequest req;
protected int recurseCount;
Query query;
protected Query query;
public QParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {

View File

@ -470,20 +470,20 @@ public class QueryParsing {
}
}
// simple class to help with parsing a string
static class StrParser {
/**
* Simple class to help with parsing a string
* <b>Note: This API is experimental and may change in non backward-compatible ways in the future</b>
*/
public static class StrParser {
String val;
int pos;
int end;
StrParser(String val) {
public StrParser(String val) {
this(val,0,val.length());
}
StrParser(String val, int start, int end) {
public StrParser(String val, int start, int end) {
this.val = val;
this.pos = start;
this.end = end;

View File

@ -27,6 +27,8 @@ import java.util.Set;
* Returns a score for each document based on a ValueSource,
* often some function of the value of a field.
*
* <b>Note: This API is experimental and may change in non backward-compatible ways in the future</b>
*
* @version $Id$
*/
public class FunctionQuery extends Query {
@ -51,9 +53,9 @@ public class FunctionQuery extends Query {
public void extractTerms(Set terms) {}
protected class FunctionWeight implements Weight {
Searcher searcher;
float queryNorm;
float queryWeight;
protected Searcher searcher;
protected float queryNorm;
protected float queryWeight;
public FunctionWeight(Searcher searcher) {
this.searcher = searcher;