SOLR-14073: Fix segment look ahead NPE in CollapsingQParserPlugin

This commit is contained in:
Joel Bernstein 2020-03-06 15:03:25 -05:00
parent 4501b3d3fd
commit 01688cd8f1
2 changed files with 88 additions and 4 deletions

View File

@ -526,9 +526,15 @@ public class CollapsingQParserPlugin extends QParserPlugin {
int segments,
DocValuesProducer collapseValuesProducer,
int nullPolicy,
IntIntHashMap boostDocsMap) throws IOException {
IntIntHashMap boostDocsMap,
IndexSearcher searcher) throws IOException {
this.maxDoc = maxDoc;
this.contexts = new LeafReaderContext[segments];
List<LeafReaderContext> con = searcher.getTopReaderContext().leaves();
for(int i=0; i<con.size(); i++) {
contexts[i] = con.get(i);
}
this.collapsedSet = new FixedBitSet(maxDoc);
this.collapseValuesProducer = collapseValuesProducer;
this.collapseValues = collapseValuesProducer.getSorted(null);
@ -756,9 +762,15 @@ public class CollapsingQParserPlugin extends QParserPlugin {
int nullPolicy,
int size,
String field,
IntIntHashMap boostDocsMap) {
IntIntHashMap boostDocsMap,
IndexSearcher searcher) {
this.maxDoc = maxDoc;
this.contexts = new LeafReaderContext[segments];
List<LeafReaderContext> con = searcher.getTopReaderContext().leaves();
for(int i=0; i<con.size(); i++) {
contexts[i] = con.get(i);
}
this.collapsedSet = new FixedBitSet(maxDoc);
this.nullValue = nullValue;
this.nullPolicy = nullPolicy;
@ -928,6 +940,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
*/
private static class OrdFieldValueCollector extends DelegatingCollector {
private LeafReaderContext[] contexts;
private DocValuesProducer collapseValuesProducer;
private SortedDocValues collapseValues;
protected OrdinalMap ordinalMap;
@ -958,6 +971,10 @@ public class CollapsingQParserPlugin extends QParserPlugin {
this.maxDoc = maxDoc;
this.contexts = new LeafReaderContext[segments];
List<LeafReaderContext> con = searcher.getTopReaderContext().leaves();
for(int i=0; i<con.size(); i++) {
contexts[i] = con.get(i);
}
this.collapseValuesProducer = collapseValuesProducer;
this.collapseValues = collapseValuesProducer.getSorted(null);
if(collapseValues instanceof MultiDocValues.MultiSortedDocValues) {
@ -1151,6 +1168,10 @@ public class CollapsingQParserPlugin extends QParserPlugin {
this.maxDoc = maxDoc;
this.contexts = new LeafReaderContext[segments];
List<LeafReaderContext> con = searcher.getTopReaderContext().leaves();
for(int i=0; i<con.size(); i++) {
contexts[i] = con.get(i);
}
this.collapseField = collapseField;
this.nullValue = nullValue;
this.nullPolicy = nullPolicy;
@ -1346,7 +1367,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
if (collapseFieldType instanceof StrField) {
return new OrdScoreCollector(maxDoc, leafCount, docValuesProducer, nullPolicy, boostDocs);
return new OrdScoreCollector(maxDoc, leafCount, docValuesProducer, nullPolicy, boostDocs, searcher);
} else if (isNumericCollapsible(collapseFieldType)) {
@ -1365,7 +1386,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
}
}
return new IntScoreCollector(maxDoc, leafCount, nullValue, nullPolicy, size, collapseField, boostDocs);
return new IntScoreCollector(maxDoc, leafCount, nullValue, nullPolicy, size, collapseField, boostDocs, searcher);
} else {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,

View File

@ -343,6 +343,69 @@ public class TestCollapseQParserPlugin extends SolrTestCaseJ4 {
}
}
@Test
public void testDoubleCollapse() {
testDoubleCollapse("group_s", "");
testDoubleCollapse("group_i", "");
}
/*
* SOLR-14073
* The double collapse causes a look ahead in the second collapse to a segment that was not visited by
* the by finally method of the first collapse. This specific test is meant to confirm that any feature
* that causes searches to not visit each segment (such as early query termination) doesn't break collapse.
*/
private void testDoubleCollapse(String group, String hint) {
String[] doc = {"id","1", "term_s", "YYYY", group, "1", "test_i", "5", "test_l", "10", "test_f", "2000"};
assertU(adoc(doc));
assertU(commit());
String[] doc1 = {"id","2", "term_s","YYYY", group, "2", "test_i", "50", "test_l", "100", "test_f", "200"};
assertU(adoc(doc1));
String[] doc2 = {"id","3", "term_s", "YYYY", "test_i", "5000", "test_l", "100", "test_f", "200"};
assertU(adoc(doc2));
assertU(commit());
String[] doc3 = {"id","4", "term_s", "YYYY", "test_i", "500", "test_l", "1000", "test_f", "2000"};
assertU(adoc(doc3));
String[] doc4 = {"id","5", "term_s", "YYYN", group, "2", "test_i", "4", "test_l", "10", "test_f", "2000"};
assertU(adoc(doc4));
assertU(commit());
String[] doc5 = {"id","6", "term_s","YYYY", group, "2", "test_i", "10", "test_l", "100", "test_f", "200"};
assertU(adoc(doc5));
assertU(commit());
String[] doc6 = {"id","7", "term_s", "YYYY", group, "1", "test_i", "8", "test_l", "50", "test_f", "300"};
assertU(adoc(doc6));
assertU(commit());
ModifiableSolrParams params = new ModifiableSolrParams();
params.add("q", "id:(1 2 5)");
params.add("fq", "{!collapse cost=200 field=term_s "+hint+"}");
params.add("fq", "{!collapse cost=400 field="+group+""+hint+"}");
params.add("defType", "edismax");
params.add("bf", "field(test_i)");
assertQ(req(params, "indent", "on"), "*[count(//doc)=1]",
"//result/doc[1]/str[@name='id'][.='2']"
);
params = new ModifiableSolrParams();
params.add("q", "id:(1 2 5)");
params.add("fq", "{!collapse cost=200 max=test_i field=term_s "+hint+"}");
params.add("fq", "{!collapse cost=400 max=test_i field="+group+""+hint+"}");
params.add("defType", "edismax");
params.add("bf", "field(test_i)");
assertQ(req(params, "indent", "on"), "*[count(//doc)=1]",
"//result/doc[1]/str[@name='id'][.='2']"
);
}
private void testCollapseQueries(String group, String hint, boolean numeric) throws Exception {