SOLR-5986: Fix tests and start returning partial results in case of ExitingReaderException

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1630583 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Anshum Gupta 2014-10-09 20:07:46 +00:00
parent 2da8697230
commit 3f603bdd87
8 changed files with 53 additions and 74 deletions

View File

@ -54,6 +54,8 @@ import org.apache.solr.search.SolrReturnFields;
import org.apache.solr.search.SortSpec;
import org.apache.solr.search.SyntaxError;
import org.apache.solr.util.SolrPluginUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.Reader;
@ -78,6 +80,8 @@ public class MoreLikeThisHandler extends RequestHandlerBase
// Pattern is thread safe -- TODO? share this with general 'fl' param
private static final Pattern splitList = Pattern.compile(",| ");
protected static Logger log = LoggerFactory.getLogger(MoreLikeThisHandler.class);
@Override
public void init(NamedList args) {
super.init(args);
@ -267,8 +271,7 @@ public class MoreLikeThisHandler extends RequestHandlerBase
}
}
} catch (ExitableDirectoryReader.ExitingReaderException ex) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
"MLTHandler Request took too long during query expansion. Terminating request.");
log.warn( "Query: " + req.getParamString() + "; " + ex.getMessage());
} finally {
SolrQueryTimeoutImpl.reset();
}

View File

@ -244,8 +244,6 @@ public class SearchHandler extends RequestHandlerBase implements SolrCoreAware ,
}
} catch (ExitableDirectoryReader.ExitingReaderException ex) {
log.warn( "Query: " + req.getParamString() + "; " + ex.getMessage());
throw new SolrException(ErrorCode.BAD_REQUEST,
"Request took too long during query expansion. Terminating request.");
} finally {
SolrQueryTimeoutImpl.reset();
}

View File

@ -27,6 +27,7 @@ import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.ArrayUtils;
import org.apache.lucene.index.ExitableDirectoryReader;
import org.apache.lucene.index.StorableField;
import org.apache.lucene.queries.function.FunctionQuery;
import org.apache.lucene.queries.function.ValueSource;
@ -452,6 +453,9 @@ public class Grouping {
} catch (TimeLimitingCollector.TimeExceededException x) {
logger.warn( "Query: " + query + "; " + x.getMessage() );
qr.setPartialResults(true);
} catch (ExitableDirectoryReader.ExitingReaderException e) {
logger.warn( "Query: " + query + "; " + e.getMessage() );
qr.setPartialResults(true);
}
}

View File

@ -232,6 +232,9 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable,SolrIn
catch( TimeLimitingCollector.TimeExceededException x ) {
log.warn( "Query: " + query + "; " + x.getMessage() );
qr.setPartialResults(true);
} catch ( ExitableDirectoryReader.ExitingReaderException e) {
log.warn("Query: " + query + "; " + e.getMessage());
qr.setPartialResults(true);
}
}
@ -1217,12 +1220,16 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable,SolrIn
protected DocSet getDocSetNC(Query query, DocSet filter) throws IOException {
DocSetCollector collector = new DocSetCollector(maxDoc()>>6, maxDoc());
if (filter==null) {
super.search(query,null,collector);
try {
if (filter == null) {
super.search(query, null, collector);
} else {
Filter luceneFilter = filter.getTopFilter();
super.search(query, luceneFilter, collector);
}
} catch ( ExitableDirectoryReader.ExitingReaderException e) {
log.warn("Query: " + query + "; " + e.getMessage());
}
return collector.getDocSet();
}

View File

@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.lucene.index.ExitableDirectoryReader;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.Collector;
import org.apache.lucene.search.Filter;
@ -230,6 +231,9 @@ public class CommandHandler {
} catch (TimeLimitingCollector.TimeExceededException x) {
partialResults = true;
logger.warn( "Query: " + query + "; " + x.getMessage() );
} catch (ExitableDirectoryReader.ExitingReaderException e) {
partialResults = true;
logger.warn( "Query: " + query + "; " + e.getMessage() );
}
if (includeHitCount) {

View File

@ -503,24 +503,17 @@ public class TestDistributedSearch extends BaseDistributedSearchTestCase {
ShardParams.SHARDS_TOLERANT, "true");
// test group query
// TODO: Remove this? This doesn't make any real sense now that timeAllowed might trigger early
// termination of the request during Terms enumeration/Query expansion.
// During such an exit, partial results isn't supported as it wouldn't make any sense.
// Increasing the timeAllowed from 1 to 100 for now.
//
// TODO: still failing in jenkins - see SOLR-5986
//
// queryPartialResults(upShards, upClients,
// "q", "*:*",
// "rows", 100,
// "fl", "id," + i1,
// "group", "true",
// "group.query", t1 + ":kings OR " + t1 + ":eggs",
// "group.limit", 10,
// "sort", i1 + " asc, id asc",
// CommonParams.TIME_ALLOWED, 100,
// ShardParams.SHARDS_INFO, "true",
// ShardParams.SHARDS_TOLERANT, "true");
queryPartialResults(upShards, upClients,
"q", "*:*",
"rows", 100,
"fl", "id," + i1,
"group", "true",
"group.query", t1 + ":kings OR " + t1 + ":eggs",
"group.limit", 10,
"sort", i1 + " asc, id asc",
CommonParams.TIME_ALLOWED, 1,
ShardParams.SHARDS_INFO, "true",
ShardParams.SHARDS_TOLERANT, "true");
queryPartialResults(upShards, upClients,
"q", "*:*",

View File

@ -20,15 +20,11 @@ package org.apache.solr.cloud;
import org.apache.lucene.util.LuceneTestCase.Slow;
import org.apache.lucene.util.TestUtil;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.solr.common.SolrException.ErrorCode;
/**
* Distributed test for {@link org.apache.lucene.index.ExitableDirectoryReader}
*/
@ -74,7 +70,7 @@ public class CloudExitableDirectoryReaderTest extends AbstractFullDistribZkTestB
}
public void doTimeoutTests() throws Exception {
assertFail(params("q", "name:a*", "timeAllowed", "1"));
assertPartialResults(params("q", "name:a*", "timeAllowed", "1"));
/*
query rewriting for NUM_DOCS_PER_TYPE terms should take less
@ -86,7 +82,7 @@ public class CloudExitableDirectoryReaderTest extends AbstractFullDistribZkTestB
Long timeAllowed = TestUtil.nextLong(random(), fiveSeconds, Long.MAX_VALUE);
assertSuccess(params("q", "name:a*", "timeAllowed",timeAllowed.toString()));
assertFail(params("q", "name:a*", "timeAllowed", "1"));
assertPartialResults(params("q", "name:a*", "timeAllowed", "1"));
timeAllowed = TestUtil.nextLong(random(), fiveSeconds, Long.MAX_VALUE);
assertSuccess(params("q", "name:b*", "timeAllowed",timeAllowed.toString()));
@ -100,37 +96,14 @@ public class CloudExitableDirectoryReaderTest extends AbstractFullDistribZkTestB
/**
* execute a request, verify that we get an expected error
*/
public void assertFail(ModifiableSolrParams p) throws Exception {
String timeoutMessage = "Request took too long during query expansion. Terminating request.";
try {
ignoreException(timeoutMessage);
queryServer(p);
fail("no exception matching expected: " + ErrorCode.BAD_REQUEST.code + ": " + timeoutMessage);
} catch (SolrServerException e) {
assertTrue("Exception " + e.getCause() + " is not a SolrException:\n" + prettyStackTrace(e.getCause()),
e.getCause() instanceof SolrException);
assertEquals(ErrorCode.BAD_REQUEST.code, ((SolrException)e.getCause()).code());
assertTrue("Expected error message substr not found: " + timeoutMessage + " <!< " + e.getMessage(),
e.getMessage().contains(timeoutMessage));
} finally {
unIgnoreException(timeoutMessage);
}
public void assertPartialResults(ModifiableSolrParams p) throws Exception {
QueryResponse rsp = queryServer(p);
assertEquals("partialResults were expected", true, rsp.getHeader().get("partialResults"));
}
public void assertSuccess(ModifiableSolrParams p) throws Exception {
QueryResponse response = queryServer(p);
assertEquals("Wrong #docs in response", NUM_DOCS_PER_TYPE - 1, response.getResults().getNumFound());
}
public String prettyStackTrace(Throwable t) {
StringBuilder builder = new StringBuilder();
for (StackTraceElement elem : t.getStackTrace()) {
builder.append(" at ");
builder.append(elem.toString());
builder.append('\n');
}
return builder.toString();
}
}

View File

@ -20,6 +20,8 @@ package org.apache.solr.core;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrException;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.junit.BeforeClass;
import org.junit.Test;
@ -31,6 +33,7 @@ public class ExitableDirectoryReaderTest extends SolrTestCaseJ4 {
static int NUM_DOCS_PER_TYPE = 100;
static final String assertionString = "//result[@numFound='"+ (NUM_DOCS_PER_TYPE - 1) + "']";
static final String failureAssertionString = "/responseHeader/partialResults==true]";
@BeforeClass
public static void beforeClass() throws Exception {
@ -57,16 +60,12 @@ public class ExitableDirectoryReaderTest extends SolrTestCaseJ4 {
}
@Test
public void testPrefixQuery() {
assertQEx("", req("q","name:a*", "indent","true","timeAllowed","1")
, SolrException.ErrorCode.BAD_REQUEST
);
public void testPrefixQuery() throws Exception {
assertJQ(req("q", "name:a*", "indent", "true", "timeAllowed", "1"), failureAssertionString);
assertQ(req("q","name:a*", "indent","true", "timeAllowed","10000"), assertionString);
assertQEx("", req("q","name:a*", "indent","true", "timeAllowed","1")
, SolrException.ErrorCode.BAD_REQUEST
);
assertJQ(req("q","name:a*", "indent","true", "timeAllowed","1"), failureAssertionString);
assertQ(req("q","name:b*", "indent","true", "timeAllowed","10000"), assertionString);
@ -78,18 +77,16 @@ public class ExitableDirectoryReaderTest extends SolrTestCaseJ4 {
}
@Test
public void testQueriesOnDocsWithMultipleTerms() {
public void testQueriesOnDocsWithMultipleTerms() throws Exception {
assertQ(req("q","name:dummy", "indent","true", "timeAllowed","10000"), assertionString);
// This should pass even though this may take more than the 'timeAllowed' time, it doesn't take long
// to iterate over 1 term (dummy).
assertQ(req("q","name:dummy", "indent","true", "timeAllowed","10000"), assertionString);
assertQEx("", req("q","name:doc*", "indent","true", "timeAllowed","1")
, SolrException.ErrorCode.BAD_REQUEST
);
assertQ(req("q", "name:dummy", "indent", "true", "timeAllowed", "10000"), assertionString);
assertJQ(req("q", "name:doc*", "indent", "true", "timeAllowed", "1"), failureAssertionString);
}
}