SOLR-281 -- adding a search component framework

git-svn-id: https://svn.apache.org/repos/asf/lucene/solr/trunk@594268 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Ryan McKinley 2007-11-12 19:39:01 +00:00
parent 8e339464dc
commit 2b53d139be
19 changed files with 1190 additions and 397 deletions

View File

@ -153,6 +153,13 @@ New Features
solrconfig.xml rather then using the <pingQuery></pingQuery> syntax.
(Karsten Sperling via ryan)
30. SOLR-281: Added a 'Search Component' interface and converted StandardRequestHandler
and DisMaxRequestHandler to use this framework.
(Sharad Agarwal, Henri Biestro, yonik, ryan)
31. SOLR-176: Add detailed timing data to query response output. The SearchHandler
interface now returns how long each section takes. (klaas)
Changes in runtime behavior

View File

@ -287,6 +287,20 @@
</lst>
</requestHandler>
<requestHandler name="/search" class="solr.SearchHandler">
<lst name="defaults">
<str name="echoParams">explicit</str>
</lst>
<arr name="components">
<str>org.apache.solr.handler.component.QueryComponent</str>
<str>org.apache.solr.handler.component.FacetComponent</str>
<str>org.apache.solr.handler.component.MoreLikeThisComponent</str>
<str>org.apache.solr.handler.component.HighlightComponent</str>
<str>org.apache.solr.handler.component.DebugComponent</str>
</arr>
</requestHandler>
<!-- DisMaxRequestHandler allows easy searching across multiple fields
for simple user-entered phrases.
see http://wiki.apache.org/solr/DisMaxRequestHandler

View File

@ -0,0 +1,146 @@
/**
* 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.common.util;
import java.lang.System;
import java.lang.Thread;
import java.util.*;
/** A recursive timer.
*
* RTimers are started automatically when instantiated; subtimers are also
* started automatically when created.
*
* @since solr 1.3
* @revision $Id$
*/
public class RTimer {
public static final int STARTED = 0;
public static final int STOPPED = 1;
public static final int PAUSED = 2;
protected int state;
protected double startTime;
protected double time;
protected double culmTime;
protected SimpleOrderedMap<RTimer> children;
public RTimer() {
time = 0;
culmTime = 0;
children = new SimpleOrderedMap<RTimer>();
startTime = now();
state = STARTED;
}
/** Get current time
*
* May override to implement a different timer (CPU time, etc).
*/
protected double now() { return System.currentTimeMillis(); }
/** Recursively stop timer and sub timers */
public double stop() {
assert state == STARTED || state == PAUSED;
time = culmTime;
if(state == STARTED)
time += now() - startTime;
state = STOPPED;
for( Map.Entry<String,RTimer> entry : children ) {
RTimer child = entry.getValue();
if(child.state == STARTED || child.state == PAUSED)
child.stop();
}
return time;
}
public void pause() {
assert state == STARTED;
culmTime += now() - startTime;
state = PAUSED;
}
public void resume() {
if(state == STARTED)
return;
assert state == PAUSED;
state = STARTED;
startTime = now();
}
/** Get total elapsed time for this timer.
*
* Timer must be STOPped.
*/
public double getTime() {
assert state == STOPPED;
return time;
}
/** Create new subtimer with given name
*
* Subtimer will be started.
*/
public RTimer sub(String desc) {
RTimer child = children.get( desc );
if( child == null ) {
child = new RTimer();
children.add(desc, child);
}
return child;
}
@Override
public String toString() {
return asNamedList().toString();
}
public NamedList asNamedList() {
NamedList<Object> m = new SimpleOrderedMap<Object>();
m.add( "time", time );
if( children.size() > 0 ) {
for( Map.Entry<String, RTimer> entry : children ) {
m.add( entry.getKey(), entry.getValue().asNamedList() );
}
}
return m;
}
/*************** Testing *******/
public static void main(String []argv) throws InterruptedException {
RTimer rt = new RTimer(), subt, st;
Thread.sleep(100);
subt = rt.sub("sub1");
Thread.sleep(50);
st = subt.sub("sub1.1");
st.resume();
Thread.sleep(10);
st.pause();
Thread.sleep(50);
st.resume();
Thread.sleep(10);
st.pause();
subt.stop();
rt.stop();
System.out.println( rt.toString());
}
}

View File

@ -17,34 +17,15 @@
package org.apache.solr.handler;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Map;
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.lucene.search.BooleanClause.Occur;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.DisMaxParams;
import org.apache.solr.common.params.FacetParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrCore;
import org.apache.solr.highlight.SolrHighlighter;
import org.apache.solr.request.SimpleFacets;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.search.DocListAndSet;
import org.apache.solr.search.DocSet;
import org.apache.solr.search.DisMaxQParserPlugin;
import org.apache.solr.search.QueryParsing;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.util.SolrPluginUtils;
import java.net.MalformedURLException;
import java.net.URL;
/**
* <p>
* A Generic query plugin designed to be given a simple query expression
@ -133,260 +114,33 @@ import org.apache.solr.util.SolrPluginUtils;
*
* </pre>
*/
public class DisMaxRequestHandler extends RequestHandlerBase {
@Deprecated
public class DisMaxRequestHandler extends StandardRequestHandler
{
/**
* 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";
/** shorten the class references for utilities */
private static class U extends SolrPluginUtils {
/* :NOOP */
}
/** shorten the class references for utilities */
private static interface DMP extends DisMaxParams {
/* :NOOP */
}
public DisMaxRequestHandler() {
super();
}
/** Sets the default variables for any useful info it finds in the config.
* If a config option is not in the format expected, logs a warning
* and ignores it.
*/
@Override
public void init(NamedList args) {
// Handle an old format
if (-1 == args.indexOf("defaults",0)) {
super.init( args );
NamedList def = null;
// redo "defaults"
Object o = args.get("defaults");
if (o != null && o instanceof NamedList) {
def = (NamedList)o;
} else {
// no explict defaults list, use all args implicitly
// indexOf so "<null name="defaults"/> is valid indicator of no defaults
defaults = SolrParams.toSolrParams(args);
} else {
// otherwise use the new one.
super.init( args );
def = args;
}
// Make the default query type "dismax" if not specified
if (def.get(QueryParsing.DEFTYPE) == null) {
def = def.clone();
def.add(QueryParsing.DEFTYPE, DisMaxQParserPlugin.NAME);
defaults = SolrParams.toSolrParams( def );
}
}
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception
{
SolrParams params = req.getParams();
int flags = 0;
SolrIndexSearcher s = req.getSearcher();
IndexSchema schema = req.getSchema();
Map<String,Float> queryFields = U.parseFieldBoosts(params.getParams(DMP.QF));
Map<String,Float> phraseFields = U.parseFieldBoosts(params.getParams(DMP.PF));
float tiebreaker = params.getFloat(DMP.TIE, 0.0f);
int pslop = params.getInt(DMP.PS, 0);
int qslop = params.getInt(DMP.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
*/
U.DisjunctionMaxQueryParser up =
new U.DisjunctionMaxQueryParser(schema, IMPOSSIBLE_FIELD_NAME);
up.addAlias(IMPOSSIBLE_FIELD_NAME,
tiebreaker, queryFields);
up.setPhraseSlop(qslop);
/* for parsing sloppy phrases using DisjunctionMaxQueries */
U.DisjunctionMaxQueryParser pp =
new U.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 * * */
Query parsedUserQuery = null;
String userQuery = params.get( CommonParams.Q );
Query altUserQuery = null;
if( userQuery == null || userQuery.trim().length() < 1 ) {
// If no query is specified, we may have an alternate
String altQ = params.get( DMP.ALTQ );
if (altQ != null) {
altUserQuery = p.parse(altQ);
query.add( altUserQuery , Occur.MUST );
} else {
throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "missing query string" );
}
}
else {
// There is a valid query string
userQuery = U.partialEscape(U.stripUnbalancedQuotes(userQuery)).toString();
String minShouldMatch = params.get(DMP.MM, "100%");
Query dis = up.parse(userQuery);
parsedUserQuery = dis;
if (dis instanceof BooleanQuery) {
BooleanQuery t = new BooleanQuery();
U.flattenBooleanQuery(t, (BooleanQuery)dis);
U.setMinShouldMatch(t, minShouldMatch);
parsedUserQuery = t;
}
query.add(parsedUserQuery, Occur.MUST);
/* * * Add on Phrases for the Query * * */
/* build up phrase boosting queries */
/* if the userQuery already has some quotes, stip 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, Occur.SHOULD);
}
}
/* * * Boosting Query * * */
String[] boostParams = params.getParams(DMP.BQ);
List<Query> boostQueries = U.parseQueryStrings(req, boostParams);
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 = params.getParams(DMP.BF);
if (null != boostFuncs && 0 != boostFuncs.length) {
for (String boostFunc : boostFuncs) {
if(null == boostFunc || "".equals(boostFunc)) continue;
List<Query> funcs = U.parseFuncs(schema, boostFunc);
for (Query f : funcs) {
query.add(f, Occur.SHOULD);
}
}
}
/* * * Restrict Results * * */
List<Query> restrictions = U.parseFilterQueries(req);
/* * * Generate Main Results * * */
flags |= U.setReturnFields(req,rsp);
DocListAndSet results = new DocListAndSet();
NamedList facetInfo = null;
if (params.getBool(FacetParams.FACET,false)) {
results = s.getDocListAndSet(query, restrictions,
SolrPluginUtils.getSort(req),
req.getStart(), req.getLimit(),
flags);
facetInfo = getFacetInfo(req, rsp, results.docSet);
} else {
results.docList = s.getDocList(query, restrictions,
SolrPluginUtils.getSort(req),
req.getStart(), req.getLimit(),
flags);
}
rsp.add("response",results.docList);
// pre-fetch returned documents
U.optimizePreFetchDocs(results.docList, query, req, rsp);
if (null != facetInfo) rsp.add("facet_counts", facetInfo);
/* * * Debugging Info * * */
try {
NamedList debug = U.doStandardDebug(req, userQuery, query, results.docList);
if (null != debug) {
debug.add("altquerystring", altUserQuery);
if (null != boostQueries) {
debug.add("boost_queries", boostParams);
debug.add("parsed_boost_queries",
QueryParsing.toString(boostQueries, req.getSchema()));
}
debug.add("boostfuncs", params.getParams(DMP.BF));
if (null != restrictions) {
debug.add("filter_queries", params.getParams(CommonParams.FQ));
debug.add("parsed_filter_queries",
QueryParsing.toString(restrictions, req.getSchema()));
}
rsp.add("debug", debug);
}
} catch (Exception e) {
SolrException.logOnce(SolrCore.log, "Exception during debug", e);
rsp.add("exception_during_debug", SolrException.toStr(e));
}
/* * * Highlighting/Summarizing * * */
SolrHighlighter highlighter = req.getCore().getHighlighter();
if(highlighter.isHighlightingEnabled( params ) && parsedUserQuery != null) {
String[] highFields = queryFields.keySet().toArray(new String[0]);
NamedList sumData = highlighter.doHighlighting(
results.docList,
parsedUserQuery.rewrite(req.getSearcher().getReader()),
req,
highFields);
if(sumData != null)
rsp.add("highlighting", sumData);
}
}
/**
* Fetches information about Facets for this request.
*
* Subclasses may with to override this method to provide more
* advanced faceting behavior.
* @see SimpleFacets#getFacetCounts
*/
protected NamedList getFacetInfo(SolrQueryRequest req,
SolrQueryResponse rsp,
DocSet mainSet) {
SimpleFacets f = new SimpleFacets(req.getSearcher(),
mainSet,
req.getParams());
return f.getFacetCounts();
}
//////////////////////// SolrInfoMBeans methods //////////////////////
@Override

View File

@ -51,6 +51,7 @@ import org.apache.solr.request.SolrQueryResponse;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.search.DocIterator;
import org.apache.solr.search.DocSet;
import org.apache.solr.search.DocList;
import org.apache.solr.search.DocListAndSet;
import org.apache.solr.search.QueryParsing;

View File

@ -0,0 +1,159 @@
/**
* 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.handler;
import org.apache.lucene.queryParser.ParseException;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.RTimer;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.handler.component.ResponseBuilder;
import org.apache.solr.handler.component.SearchComponent;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
/**
*
* Refer SOLR-281
*
*/
public class SearchHandler extends RequestHandlerBase
{
private static final String RESPONSE_BUILDER_CONTEXT_KEY = "ResponseBuilder";
protected static Logger log = Logger.getLogger(SearchHandler.class.getName());
protected Collection<SearchComponent> components;
@Override
public void init(NamedList args) {
super.init( args );
initComponents(args);
}
// TODO: should there be a way to append components from solrconfig w/o having to
// know the complete standard list (which may expand over time?)
protected void initComponents(NamedList args){
if( args != null ) {
try {
Object declaredComponents = args.get("components");
if (declaredComponents != null && declaredComponents instanceof List) {
List list = (List) declaredComponents;
components = new ArrayList<SearchComponent>(list.size());
for(Object c : list){
// TODO: an init() with args for components?
SearchComponent comp = (SearchComponent) Class.forName((String) c).newInstance();
components.add(comp);
log.info("Adding component:"+comp);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public static ResponseBuilder getResponseBuilder(SolrQueryRequest req)
{
return (ResponseBuilder) req.getContext().get( RESPONSE_BUILDER_CONTEXT_KEY );
}
@Override
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException, ParseException, InstantiationException, IllegalAccessException
{
ResponseBuilder builder = new ResponseBuilder();
req.getContext().put( RESPONSE_BUILDER_CONTEXT_KEY, builder );
// The semantics of debugging vs not debugging are different enough that
// it makes sense to have two control loops
if( !req.getParams().getBool( CommonParams.DEBUG_QUERY, false ) ) {
// Prepare
for( SearchComponent c : components ) {
c.prepare( req, rsp );
}
// Process
for( SearchComponent c : components ) {
c.process( req, rsp );
}
}
else {
builder.setDebug( true );
RTimer timer = new RTimer();
// Prepare
RTimer subt = timer.sub( "prepare" );
for( SearchComponent c : components ) {
builder.setTimer( subt.sub( c.getName() ) );
c.prepare( req, rsp );
builder.getTimer().stop();
}
subt.stop();
// Process
subt = timer.sub( "process" );
for( SearchComponent c : components ) {
builder.setTimer( subt.sub( c.getName() ) );
c.process( req, rsp );
builder.getTimer().stop();
}
subt.stop();
timer.stop();
// add the timing info
if( builder.getDebugInfo() == null ) {
builder.setDebugInfo( new SimpleOrderedMap<Object>() );
}
builder.getDebugInfo().add( "timing", timer.asNamedList() );
}
}
//////////////////////// SolrInfoMBeans methods //////////////////////
@Override
public String getDescription() {
StringBuilder sb = new StringBuilder();
sb.append("Search using components: ");
for(SearchComponent c : components){
sb.append(c.getName());
sb.append(",");
}
return sb.toString();
}
@Override
public String getVersion() {
return "$Revision$";
}
@Override
public String getSourceId() {
return "$Id$";
}
@Override
public String getSource() {
return "$URL$";
}
}

View File

@ -17,26 +17,17 @@
package org.apache.solr.handler;
import org.apache.lucene.search.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.apache.solr.util.SolrPluginUtils;
import org.apache.solr.request.SimpleFacets;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse;
import org.apache.solr.search.*;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.FacetParams;
import org.apache.solr.common.params.MoreLikeThisParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrCore;
import org.apache.solr.highlight.SolrHighlighter;
import org.apache.solr.handler.component.DebugComponent;
import org.apache.solr.handler.component.FacetComponent;
import org.apache.solr.handler.component.HighlightComponent;
import org.apache.solr.handler.component.MoreLikeThisComponent;
import org.apache.solr.handler.component.QueryComponent;
import org.apache.solr.handler.component.SearchComponent;
/**
* @version $Id$
@ -57,112 +48,18 @@ import org.apache.solr.highlight.SolrHighlighter;
* </ul>
*
*/
public class StandardRequestHandler extends SearchHandler {
public class StandardRequestHandler extends RequestHandlerBase {
/** shorten the class references for utilities */
private static class U extends SolrPluginUtils {
/* :NOOP */
@Override
protected void initComponents(NamedList args) {
components = new ArrayList<SearchComponent>(5);
components.add( new QueryComponent() );
components.add( new FacetComponent() );
components.add( new MoreLikeThisComponent() );
components.add( new HighlightComponent() );
components.add( new DebugComponent() );
}
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception
{
SolrParams p = req.getParams();
String qstr = p.required().get(CommonParams.Q);
// find fieldnames to return (fieldlist)
// TODO: make this per-query and add method to QParser to get?
String fl = p.get(CommonParams.FL);
int flags = 0;
if (fl != null) {
flags |= U.setReturnFields(fl, rsp);
}
QParser parser = QParser.getParser(qstr, OldLuceneQParserPlugin.NAME, req);
Query query = parser.getQuery();
QueryParsing.SortSpec sortSpec = parser.getSort(true);
DocListAndSet results = new DocListAndSet();
NamedList facetInfo = null;
List<Query> filters = U.parseFilterQueries(req);
SolrIndexSearcher s = req.getSearcher();
if (p.getBool(FacetParams.FACET,false)) {
results = s.getDocListAndSet(query, filters, sortSpec.getSort(),
sortSpec.getOffset(), sortSpec.getCount(),
flags);
facetInfo = getFacetInfo(req, rsp, results.docSet);
} else {
results.docList = s.getDocList(query, filters, sortSpec.getSort(),
sortSpec.getOffset(), sortSpec.getCount(),
flags);
}
// pre-fetch returned documents
U.optimizePreFetchDocs(results.docList, query, req, rsp);
rsp.add("response",results.docList);
if (null != facetInfo) rsp.add("facet_counts", facetInfo);
// Include "More Like This" results for *each* result
if( p.getBool( MoreLikeThisParams.MLT, false ) ) {
MoreLikeThisHandler.MoreLikeThisHelper mlt
= new MoreLikeThisHandler.MoreLikeThisHelper( p, s );
int mltcount = p.getInt( MoreLikeThisParams.DOC_COUNT, 5 );
rsp.add( "moreLikeThis", mlt.getMoreLikeThese(results.docList, mltcount, flags));
}
try {
NamedList dbg = U.doStandardDebug(req, qstr, query, results.docList);
if (null != dbg) {
if (null != filters) {
dbg.add("filter_queries",req.getParams().getParams(CommonParams.FQ));
List<String> fqs = new ArrayList<String>(filters.size());
for (Query fq : filters) {
fqs.add(QueryParsing.toString(fq, req.getSchema()));
}
dbg.add("parsed_filter_queries",fqs);
}
rsp.add("debug", dbg);
}
} catch (Exception e) {
SolrException.logOnce(SolrCore.log, "Exception during debug", e);
rsp.add("exception_during_debug", SolrException.toStr(e));
}
SolrHighlighter highlighter = req.getCore().getHighlighter();
NamedList sumData = highlighter.doHighlighting(
results.docList,
parser.getHighlightQuery().rewrite(req.getSearcher().getReader()),
req,
parser.getDefaultHighlightFields());
if(sumData != null)
rsp.add("highlighting", sumData);
}
/**
* Fetches information about Facets for this request.
*
* Subclasses may with to override this method to provide more
* advanced faceting behavior.
* @see SimpleFacets#getFacetCounts
*/
protected NamedList getFacetInfo(SolrQueryRequest req,
SolrQueryResponse rsp,
DocSet mainSet) {
SimpleFacets f = new SimpleFacets(req.getSearcher(),
mainSet,
req.getParams());
return f.getFacetCounts();
}
//////////////////////// SolrInfoMBeans methods //////////////////////
@Override

View File

@ -0,0 +1,105 @@
/**
* 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.handler.component;
import static org.apache.solr.common.params.CommonParams.FQ;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;
import org.apache.solr.handler.SearchHandler;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse;
import org.apache.solr.search.QueryParsing;
import org.apache.solr.util.SolrPluginUtils;
/**
* TODO!
*
* @version $Id$
* @since solr 1.3
*/
public class DebugComponent extends SearchComponent
{
@Override
public void prepare(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException, ParseException
{
}
@Override
public void process(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException
{
ResponseBuilder builder = SearchHandler.getResponseBuilder( req );
if( builder.isDebug() ) {
builder.setDebugInfo( SolrPluginUtils.doStandardDebug( req,
builder.getQueryString(), builder.getQuery(), builder.getResults().docList) );
if (builder.getQparser() != null) {
builder.getQparser().addDebugInfo(builder.getDebugInfo());
}
if (null != builder.getDebugInfo() ) {
if (null != builder.getFilters() ) {
builder.getDebugInfo().add("filter_queries",req.getParams().getParams(FQ));
List<String> fqs = new ArrayList<String>(builder.getFilters().size());
for (Query fq : builder.getFilters()) {
fqs.add(QueryParsing.toString(fq, req.getSchema()));
}
builder.getDebugInfo().add("parsed_filter_queries",fqs);
}
// Add this directly here?
rsp.add("debug", builder.getDebugInfo() );
}
}
}
/////////////////////////////////////////////
/// SolrInfoMBean
////////////////////////////////////////////
@Override
public String getDescription() {
return "Debug Information";
}
@Override
public String getVersion() {
return "$Revision$";
}
@Override
public String getSourceId() {
return "$Id$";
}
@Override
public String getSource() {
return "$URL$";
}
@Override
public URL[] getDocs() {
return null;
}
}

View File

@ -0,0 +1,96 @@
/**
* 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.handler.component;
import java.io.IOException;
import java.net.URL;
import org.apache.lucene.queryParser.ParseException;
import org.apache.solr.common.params.FacetParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.handler.SearchHandler;
import org.apache.solr.request.SimpleFacets;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse;
/**
* TODO!
*
* @version $Id$
* @since solr 1.3
*/
public class FacetComponent extends SearchComponent
{
@Override
public void prepare(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException, ParseException
{
SolrParams params = req.getParams();
if (params.getBool(FacetParams.FACET,false)) {
ResponseBuilder builder = SearchHandler.getResponseBuilder( req );
builder.setNeedDocSet( true );
}
}
/**
* Actually run the query
*/
@Override
public void process(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException
{
SolrParams params = req.getParams();
if (params.getBool(FacetParams.FACET,false)) {
ResponseBuilder builder = SearchHandler.getResponseBuilder( req );
SimpleFacets f = new SimpleFacets(req.getSearcher(),
builder.getResults().docSet,
params );
// TODO ???? add this directly to the response?
rsp.add( "facet_counts", f.getFacetCounts() );
}
}
/////////////////////////////////////////////
/// SolrInfoMBean
////////////////////////////////////////////
@Override
public String getDescription() {
return "Handle Faceting";
}
@Override
public String getVersion() {
return "$Revision$";
}
@Override
public String getSourceId() {
return "$Id$";
}
@Override
public String getSource() {
return "$URL$";
}
@Override
public URL[] getDocs() {
return null;
}
}

View File

@ -0,0 +1,112 @@
/**
* 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.handler.component;
import org.apache.lucene.queryParser.ParseException;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.handler.SearchHandler;
import org.apache.solr.highlight.SolrHighlighter;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse;
import java.io.IOException;
import java.net.URL;
/**
* TODO!
*
* @version $Id$
* @since solr 1.3
*/
public class HighlightComponent extends SearchComponent {
@Override
public void prepare(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException, ParseException {
}
@Override
public void process(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException {
SolrHighlighter highlighter = req.getCore().getHighlighter();
if (highlighter.isHighlightingEnabled(req.getParams())) {
ResponseBuilder builder = SearchHandler.getResponseBuilder( req );
SolrParams params = req.getParams();
String[] defaultHighlightFields; //TODO: get from builder by default?
if (builder.getQparser() != null) {
defaultHighlightFields = builder.getQparser().getDefaultHighlightFields();
} else {
defaultHighlightFields = params.getParams(CommonParams.DF);
}
if(builder.getHighlightQuery()==null) {
if (builder.getQparser() != null) {
try {
builder.setHighlightQuery( builder.getQparser().getHighlightQuery() );
} catch (Exception e) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
}
} else {
builder.setHighlightQuery( builder.getQuery() );
}
}
NamedList sumData = highlighter.doHighlighting(
builder.getResults().docList,
builder.getHighlightQuery().rewrite(req.getSearcher().getReader()),
req, defaultHighlightFields );
if(sumData != null) {
// TODO ???? add this directly to the response?
rsp.add("highlighting", sumData);
}
}
}
/////////////////////////////////////////////
/// SolrInfoMBean
////////////////////////////////////////////
@Override
public String getDescription() {
return "Highlighting";
}
@Override
public String getVersion() {
return "$Revision$";
}
@Override
public String getSourceId() {
return "$Id$";
}
@Override
public String getSource() {
return "$URL$";
}
@Override
public URL[] getDocs() {
return null;
}
}

View File

@ -0,0 +1,96 @@
/**
* 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.handler.component;
import java.io.IOException;
import java.net.URL;
import org.apache.lucene.queryParser.ParseException;
import org.apache.solr.common.params.MoreLikeThisParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.handler.MoreLikeThisHandler;
import org.apache.solr.handler.SearchHandler;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse;
import org.apache.solr.search.DocList;
import org.apache.solr.search.SolrIndexSearcher;
/**
* TODO!
*
* @version $Id$
* @since solr 1.3
*/
public class MoreLikeThisComponent extends SearchComponent
{
@Override
public void prepare(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException, ParseException
{
}
@Override
public void process(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException
{
SolrParams p = req.getParams();
if( p.getBool( MoreLikeThisParams.MLT, false ) ) {
ResponseBuilder builder = SearchHandler.getResponseBuilder( req );
SolrIndexSearcher searcher = req.getSearcher();
MoreLikeThisHandler.MoreLikeThisHelper mlt
= new MoreLikeThisHandler.MoreLikeThisHelper( p, searcher );
int mltcount = p.getInt( MoreLikeThisParams.DOC_COUNT, 5 );
NamedList<DocList> sim = mlt.getMoreLikeThese(
builder.getResults().docList, mltcount, builder.getFieldFlags() );
// TODO ???? add this directly to the response?
rsp.add( "moreLikeThis", sim );
}
}
/////////////////////////////////////////////
/// SolrInfoMBean
////////////////////////////////////////////
@Override
public String getDescription() {
return "More Like This";
}
@Override
public String getVersion() {
return "$Revision$";
}
@Override
public String getSourceId() {
return "$Id$";
}
@Override
public String getSource() {
return "$URL$";
}
@Override
public URL[] getDocs() {
return null;
}
}

View File

@ -0,0 +1,146 @@
/**
* 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.handler.component;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.handler.SearchHandler;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse;
import org.apache.solr.search.*;
import org.apache.solr.util.SolrPluginUtils;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* TODO!
*
* @version $Id$
* @since solr 1.3
*/
public class QueryComponent extends SearchComponent
{
@Override
public void prepare(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException, ParseException
{
ResponseBuilder builder = SearchHandler.getResponseBuilder( req );
SolrParams params = req.getParams();
// Set field flags
String fl = params.get(CommonParams.FL);
int fieldFlags = 0;
if (fl != null) {
fieldFlags |= SolrPluginUtils.setReturnFields(fl, rsp);
}
builder.setFieldFlags( fieldFlags );
String defType = params.get(QueryParsing.DEFTYPE);
defType = defType==null ? OldLuceneQParserPlugin.NAME : defType;
if (builder.getQueryString() == null) {
builder.setQueryString( params.get( CommonParams.Q ) );
}
QParser parser = QParser.getParser(builder.getQueryString(), defType, req);
builder.setQuery( parser.getQuery() );
builder.setSortSpec( parser.getSort(true) );
String[] fqs = req.getParams().getParams(org.apache.solr.common.params.CommonParams.FQ);
if (fqs!=null && fqs.length!=0) {
List<Query> filters = builder.getFilters();
if (filters==null) {
filters = new ArrayList<Query>();
builder.setFilters( filters );
}
for (String fq : fqs) {
if (fq != null && fq.trim().length()!=0) {
QParser fqp = QParser.getParser(fq, null, req);
filters.add(fqp.getQuery());
}
}
}
}
/**
* Actually run the query
*/
@Override
public void process(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException
{
ResponseBuilder builder = SearchHandler.getResponseBuilder( req );
SolrIndexSearcher searcher = req.getSearcher();
SolrParams params = req.getParams();
if( builder.isNeedDocSet() ) {
builder.setResults( searcher.getDocListAndSet(
builder.getQuery(), builder.getFilters(), builder.getSortSpec().getSort(),
builder.getSortSpec().getOffset(), builder.getSortSpec().getCount(),
builder.getFieldFlags() ) );
}
else {
DocListAndSet results = new DocListAndSet();
results.docList = searcher.getDocList(
builder.getQuery(), builder.getFilters(), builder.getSortSpec().getSort(),
builder.getSortSpec().getOffset(), builder.getSortSpec().getCount(),
builder.getFieldFlags() );
builder.setResults( results );
}
//pre-fetch returned documents
if (builder.getResults().docList != null && builder.getResults().docList.size()<=50) {
// TODO: this may depend on the highlighter component (or other components?)
SolrPluginUtils.optimizePreFetchDocs(builder.getResults().docList, builder.getQuery(), req, rsp);
}
rsp.add("response",builder.getResults().docList);
}
/////////////////////////////////////////////
/// SolrInfoMBean
////////////////////////////////////////////
@Override
public String getDescription() {
return "query";
}
@Override
public String getVersion() {
return "$Revision$";
}
@Override
public String getSourceId() {
return "$Id$";
}
@Override
public String getSource() {
return "$URL$";
}
@Override
public URL[] getDocs() {
return null;
}
}

View File

@ -0,0 +1,159 @@
/**
* 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.handler.component;
import org.apache.lucene.search.Query;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.RTimer;
import org.apache.solr.search.DocListAndSet;
import org.apache.solr.search.QParser;
import org.apache.solr.search.QueryParsing;
import java.util.List;
/**
* TODO!
*
* @version $Id$
* @since solr 1.3
*/
public class ResponseBuilder
{
private boolean needDocList = false;
private boolean needDocSet = false;
private int fieldFlags = 0;
private boolean debug = false;
private QParser qparser = null;
private String queryString = null;
private Query query = null;
private List<Query> filters = null;
private QueryParsing.SortSpec sortSpec = null;
private DocListAndSet results = null;
private NamedList<Object> debugInfo = null;
private RTimer timer = null;
private Query highlightQuery = null;
//-------------------------------------------------------------------------
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
public NamedList<Object> getDebugInfo() {
return debugInfo;
}
public void setDebugInfo(NamedList<Object> debugInfo) {
this.debugInfo = debugInfo;
}
public int getFieldFlags() {
return fieldFlags;
}
public void setFieldFlags(int fieldFlags) {
this.fieldFlags = fieldFlags;
}
public List<Query> getFilters() {
return filters;
}
public void setFilters(List<Query> filters) {
this.filters = filters;
}
public Query getHighlightQuery() {
return highlightQuery;
}
public void setHighlightQuery(Query highlightQuery) {
this.highlightQuery = highlightQuery;
}
public boolean isNeedDocList() {
return needDocList;
}
public void setNeedDocList(boolean needDocList) {
this.needDocList = needDocList;
}
public boolean isNeedDocSet() {
return needDocSet;
}
public void setNeedDocSet(boolean needDocSet) {
this.needDocSet = needDocSet;
}
public QParser getQparser() {
return qparser;
}
public void setQparser(QParser qparser) {
this.qparser = qparser;
}
public String getQueryString() {
return queryString;
}
public void setQueryString(String qstr) {
this.queryString = qstr;
}
public Query getQuery() {
return query;
}
public void setQuery(Query query) {
this.query = query;
}
public DocListAndSet getResults() {
return results;
}
public void setResults(DocListAndSet results) {
this.results = results;
}
public QueryParsing.SortSpec getSortSpec() {
return sortSpec;
}
public void setSortSpec(QueryParsing.SortSpec sort) {
this.sortSpec = sort;
}
public RTimer getTimer() {
return timer;
}
public void setTimer(RTimer timer) {
this.timer = timer;
}
}

View File

@ -0,0 +1,64 @@
/**
* 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.handler.component;
import java.io.IOException;
import java.net.URL;
import org.apache.lucene.queryParser.ParseException;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.SolrInfoMBean;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse;
/**
* TODO!
*
* @version $Id$
* @since solr 1.3
*/
public abstract class SearchComponent implements SolrInfoMBean
{
public abstract void prepare( SolrQueryRequest req, SolrQueryResponse rsp ) throws IOException, ParseException;
public abstract void process( SolrQueryRequest req, SolrQueryResponse rsp ) throws IOException;
//////////////////////// SolrInfoMBeans methods //////////////////////
public String getName() {
return this.getClass().getName();
}
public abstract String getDescription();
public abstract String getSourceId();
public abstract String getSource();
public abstract String getVersion();
public Category getCategory() {
return Category.OTHER;
}
public URL[] getDocs() {
return null; // this can be overridden, but not required
}
public NamedList getStatistics() {
NamedList lst = new SimpleOrderedMap();
return lst;
}
}

View File

@ -43,15 +43,16 @@ public class BoostQParserPlugin extends QParserPlugin {
public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
return new QParser(qstr, localParams, params, req) {
QParser baseParser;
ValueSource vs;
String b;
public Query parse() throws ParseException {
String b = localParams.get(BOOSTFUNC);
b = localParams.get(BOOSTFUNC);
baseParser = subQuery(localParams.get(QueryParsing.V), null);
Query q = baseParser.parse();
if (b == null) return q;
Query bq = subQuery(b, FunctionQParserPlugin.NAME).parse();
ValueSource vs;
if (bq instanceof FunctionQuery) {
vs = ((FunctionQuery)bq).getValueSource();
} else {
@ -64,6 +65,17 @@ public class BoostQParserPlugin extends QParserPlugin {
public String[] getDefaultHighlightFields() {
return baseParser.getDefaultHighlightFields();
}
public Query getHighlightQuery() throws ParseException {
return baseParser.getHighlightQuery();
}
public void addDebugInfo(NamedList<Object> debugInfo) {
// encapsulate base debug info in a sub-list?
baseParser.addDebugInfo(debugInfo);
debugInfo.add("boost_str",b);
debugInfo.add("boost_parsed",vs);
}
};
}

View File

@ -79,6 +79,13 @@ class DismaxQParser extends QParser {
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);
@ -120,12 +127,13 @@ class DismaxQParser extends QParser {
/* * * Main User Query * * */
parsedUserQuery = null;
String userQuery = getString();
Query altUserQuery = null;
altUserQuery = null;
if( userQuery == null || userQuery.trim().length() < 1 ) {
// If no query is specified, we may have an alternate
String altQ = solrParams.get( DMP.ALTQ );
if (altQ != null) {
altUserQuery = p.parse(altQ);
altQParser = subQuery(altQ, null);
altUserQuery = altQParser.parse();
query.add( altUserQuery , BooleanClause.Occur.MUST );
} else {
throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "missing query string" );
@ -166,12 +174,13 @@ class DismaxQParser extends QParser {
/* * * Boosting Query * * */
String[] boostParams = solrParams.getParams(DMP.BQ);
boostParams = solrParams.getParams(DMP.BQ);
//List<Query> boostQueries = U.parseQueryStrings(req, boostParams);
List<Query> boostQueries=null;
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);
}
@ -228,4 +237,15 @@ class DismaxQParser extends QParser {
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

@ -20,6 +20,7 @@ import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;
public abstract class QParser {
@ -176,6 +177,10 @@ public abstract class QParser {
return getQuery();
}
public void addDebugInfo(NamedList<Object> debugInfo) {
debugInfo.add("QParser", this.getClass().getSimpleName());
}
/** Create a <code>QParser</code> to parse <code>qstr</code>,
* assuming that the default query type is <code>defaultType</code>.
* The query type may be overridden by local parameters in the query

View File

@ -183,7 +183,7 @@ public class QueryParsing {
* "<!prefix f=myfield v=$p>" returns type="prefix",f="myfield",v=params.get("p")
*/
public static SolrParams getLocalParams(String txt, SolrParams params) throws ParseException {
if (!txt.startsWith("<!")) {
if (txt==null || !txt.startsWith("<!")) {
return null;
}
Map<String,String> localParams = new HashMap<String,String>();

View File

@ -29,7 +29,6 @@ import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrInfoMBean;
import org.apache.solr.core.SolrInfoRegistry;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.util.OpenBitSet;
@ -38,6 +37,7 @@ import java.net.URL;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.solr.core.SolrInfoMBean.Category;
/**