LUCENE-5450: fix getField() NPE issues with span queries that have empty clauses

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1569503 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Robert Muir 2014-02-18 19:41:06 +00:00
parent e04cf308ea
commit 2991d657e4
6 changed files with 148 additions and 6 deletions

View File

@ -65,6 +65,14 @@ Optimizations
on Windows if NIOFSDirectory is used, mmapped files are still locked. on Windows if NIOFSDirectory is used, mmapped files are still locked.
(Michael Poindexter, Robert Muir, Uwe Schindler) (Michael Poindexter, Robert Muir, Uwe Schindler)
======================= Lucene 4.8.0 =======================
Bug fixes
* LUCENE-5450: Fix getField() NPE issues with SpanOr/SpanNear when they have an
empty list of clauses. This can happen for example, when a wildcard matches
no terms. (Tim Allison via Robert Muir)
======================= Lucene 4.7.0 ======================= ======================= Lucene 4.7.0 =======================
New Features New Features

View File

@ -64,9 +64,9 @@ public class SpanNearQuery extends SpanQuery implements Cloneable {
this.clauses = new ArrayList<SpanQuery>(clauses.length); this.clauses = new ArrayList<SpanQuery>(clauses.length);
for (int i = 0; i < clauses.length; i++) { for (int i = 0; i < clauses.length; i++) {
SpanQuery clause = clauses[i]; SpanQuery clause = clauses[i];
if (i == 0) { // check field if (field == null) { // check field
field = clause.getField(); field = clause.getField();
} else if (!clause.getField().equals(field)) { } else if (clause.getField() != null && !clause.getField().equals(field)) {
throw new IllegalArgumentException("Clauses must have same field."); throw new IllegalArgumentException("Clauses must have same field.");
} }
this.clauses.add(clause); this.clauses.add(clause);

View File

@ -62,7 +62,7 @@ public class SpanNotQuery extends SpanQuery implements Cloneable {
this.pre = (pre >=0) ? pre : 0; this.pre = (pre >=0) ? pre : 0;
this.post = (post >= 0) ? post : 0; this.post = (post >= 0) ? post : 0;
if (!include.getField().equals(exclude.getField())) if (include.getField() != null && exclude.getField() != null && !include.getField().equals(exclude.getField()))
throw new IllegalArgumentException("Clauses must have same field."); throw new IllegalArgumentException("Clauses must have same field.");
} }

View File

@ -54,7 +54,7 @@ public class SpanOrQuery extends SpanQuery implements Cloneable {
public final void addClause(SpanQuery clause) { public final void addClause(SpanQuery clause) {
if (field == null) { if (field == null) {
field = clause.getField(); field = clause.getField();
} else if (!clause.getField().equals(field)) { } else if (clause.getField() != null && !clause.getField().equals(field)) {
throw new IllegalArgumentException("Clauses must have same field."); throw new IllegalArgumentException("Clauses must have same field.");
} }
this.clauses.add(clause); this.clauses.add(clause);
@ -132,7 +132,6 @@ public class SpanOrQuery extends SpanQuery implements Cloneable {
final SpanOrQuery that = (SpanOrQuery) o; final SpanOrQuery that = (SpanOrQuery) o;
if (!clauses.equals(that.clauses)) return false; if (!clauses.equals(that.clauses)) return false;
if (!clauses.isEmpty() && !field.equals(that.field)) return false;
return getBoost() == that.getBoost(); return getBoost() == that.getBoost();
} }

View File

@ -34,7 +34,11 @@ public abstract class SpanQuery extends Query {
* to search for spans. */ * to search for spans. */
public abstract Spans getSpans(AtomicReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts) throws IOException; public abstract Spans getSpans(AtomicReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts) throws IOException;
/** Returns the name of the field matched by this query.*/ /**
* Returns the name of the field matched by this query.
* <p>
* Note that this may return null if the query matches no terms.
*/
public abstract String getField(); public abstract String getField();
@Override @Override

View File

@ -24,6 +24,8 @@ import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.search.FuzzyQuery; import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.RegexpQuery;
import org.apache.lucene.search.WildcardQuery; import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.LuceneTestCase;
@ -95,4 +97,133 @@ public class TestSpanMultiTermQueryWrapper extends LuceneTestCase {
SpanPositionRangeQuery sprq = new SpanPositionRangeQuery(sfq, 0, 100); SpanPositionRangeQuery sprq = new SpanPositionRangeQuery(sfq, 0, 100);
assertEquals(1, searcher.search(sprq, 10).totalHits); assertEquals(1, searcher.search(sprq, 10).totalHits);
} }
public void testNoSuchMultiTermsInNear() throws Exception {
//test to make sure non existent multiterms aren't throwing null pointer exceptions
FuzzyQuery fuzzyNoSuch = new FuzzyQuery(new Term("field", "noSuch"), 1, 0, 1, false);
SpanQuery spanNoSuch = new SpanMultiTermQueryWrapper<FuzzyQuery>(fuzzyNoSuch);
SpanQuery term = new SpanTermQuery(new Term("field", "brown"));
SpanQuery near = new SpanNearQuery(new SpanQuery[]{term, spanNoSuch}, 1, true);
assertEquals(0, searcher.search(near, 10).totalHits);
//flip order
near = new SpanNearQuery(new SpanQuery[]{spanNoSuch, term}, 1, true);
assertEquals(0, searcher.search(near, 10).totalHits);
WildcardQuery wcNoSuch = new WildcardQuery(new Term("field", "noSuch*"));
SpanQuery spanWCNoSuch = new SpanMultiTermQueryWrapper<WildcardQuery>(wcNoSuch);
near = new SpanNearQuery(new SpanQuery[]{term, spanWCNoSuch}, 1, true);
assertEquals(0, searcher.search(near, 10).totalHits);
RegexpQuery rgxNoSuch = new RegexpQuery(new Term("field", "noSuch"));
SpanQuery spanRgxNoSuch = new SpanMultiTermQueryWrapper<RegexpQuery>(rgxNoSuch);
near = new SpanNearQuery(new SpanQuery[]{term, spanRgxNoSuch}, 1, true);
assertEquals(0, searcher.search(near, 10).totalHits);
PrefixQuery prfxNoSuch = new PrefixQuery(new Term("field", "noSuch"));
SpanQuery spanPrfxNoSuch = new SpanMultiTermQueryWrapper<PrefixQuery>(prfxNoSuch);
near = new SpanNearQuery(new SpanQuery[]{term, spanPrfxNoSuch}, 1, true);
assertEquals(0, searcher.search(near, 10).totalHits);
//test single noSuch
near = new SpanNearQuery(new SpanQuery[]{spanPrfxNoSuch}, 1, true);
assertEquals(0, searcher.search(near, 10).totalHits);
//test double noSuch
near = new SpanNearQuery(new SpanQuery[]{spanPrfxNoSuch, spanPrfxNoSuch}, 1, true);
assertEquals(0, searcher.search(near, 10).totalHits);
}
public void testNoSuchMultiTermsInNotNear() throws Exception {
//test to make sure non existent multiterms aren't throwing non-matching field exceptions
FuzzyQuery fuzzyNoSuch = new FuzzyQuery(new Term("field", "noSuch"), 1, 0, 1, false);
SpanQuery spanNoSuch = new SpanMultiTermQueryWrapper<FuzzyQuery>(fuzzyNoSuch);
SpanQuery term = new SpanTermQuery(new Term("field", "brown"));
SpanNotQuery notNear = new SpanNotQuery(term, spanNoSuch, 0,0);
assertEquals(1, searcher.search(notNear, 10).totalHits);
//flip
notNear = new SpanNotQuery(spanNoSuch, term, 0,0);
assertEquals(0, searcher.search(notNear, 10).totalHits);
//both noSuch
notNear = new SpanNotQuery(spanNoSuch, spanNoSuch, 0,0);
assertEquals(0, searcher.search(notNear, 10).totalHits);
WildcardQuery wcNoSuch = new WildcardQuery(new Term("field", "noSuch*"));
SpanQuery spanWCNoSuch = new SpanMultiTermQueryWrapper<WildcardQuery>(wcNoSuch);
notNear = new SpanNotQuery(term, spanWCNoSuch, 0,0);
assertEquals(1, searcher.search(notNear, 10).totalHits);
RegexpQuery rgxNoSuch = new RegexpQuery(new Term("field", "noSuch"));
SpanQuery spanRgxNoSuch = new SpanMultiTermQueryWrapper<RegexpQuery>(rgxNoSuch);
notNear = new SpanNotQuery(term, spanRgxNoSuch, 1, 1);
assertEquals(1, searcher.search(notNear, 10).totalHits);
PrefixQuery prfxNoSuch = new PrefixQuery(new Term("field", "noSuch"));
SpanQuery spanPrfxNoSuch = new SpanMultiTermQueryWrapper<PrefixQuery>(prfxNoSuch);
notNear = new SpanNotQuery(term, spanPrfxNoSuch, 1, 1);
assertEquals(1, searcher.search(notNear, 10).totalHits);
}
public void testNoSuchMultiTermsInOr() throws Exception {
//test to make sure non existent multiterms aren't throwing null pointer exceptions
FuzzyQuery fuzzyNoSuch = new FuzzyQuery(new Term("field", "noSuch"), 1, 0, 1, false);
SpanQuery spanNoSuch = new SpanMultiTermQueryWrapper<FuzzyQuery>(fuzzyNoSuch);
SpanQuery term = new SpanTermQuery(new Term("field", "brown"));
SpanOrQuery near = new SpanOrQuery(new SpanQuery[]{term, spanNoSuch});
assertEquals(1, searcher.search(near, 10).totalHits);
//flip
near = new SpanOrQuery(new SpanQuery[]{spanNoSuch, term});
assertEquals(1, searcher.search(near, 10).totalHits);
WildcardQuery wcNoSuch = new WildcardQuery(new Term("field", "noSuch*"));
SpanQuery spanWCNoSuch = new SpanMultiTermQueryWrapper<WildcardQuery>(wcNoSuch);
near = new SpanOrQuery(new SpanQuery[]{term, spanWCNoSuch});
assertEquals(1, searcher.search(near, 10).totalHits);
RegexpQuery rgxNoSuch = new RegexpQuery(new Term("field", "noSuch"));
SpanQuery spanRgxNoSuch = new SpanMultiTermQueryWrapper<RegexpQuery>(rgxNoSuch);
near = new SpanOrQuery(new SpanQuery[]{term, spanRgxNoSuch});
assertEquals(1, searcher.search(near, 10).totalHits);
PrefixQuery prfxNoSuch = new PrefixQuery(new Term("field", "noSuch"));
SpanQuery spanPrfxNoSuch = new SpanMultiTermQueryWrapper<PrefixQuery>(prfxNoSuch);
near = new SpanOrQuery(new SpanQuery[]{term, spanPrfxNoSuch});
assertEquals(1, searcher.search(near, 10).totalHits);
near = new SpanOrQuery(new SpanQuery[]{spanPrfxNoSuch});
assertEquals(0, searcher.search(near, 10).totalHits);
near = new SpanOrQuery(new SpanQuery[]{spanPrfxNoSuch, spanPrfxNoSuch});
assertEquals(0, searcher.search(near, 10).totalHits);
}
public void testNoSuchMultiTermsInSpanFirst() throws Exception {
//this hasn't been a problem
FuzzyQuery fuzzyNoSuch = new FuzzyQuery(new Term("field", "noSuch"), 1, 0, 1, false);
SpanQuery spanNoSuch = new SpanMultiTermQueryWrapper<FuzzyQuery>(fuzzyNoSuch);
SpanQuery spanFirst = new SpanFirstQuery(spanNoSuch, 10);
assertEquals(0, searcher.search(spanFirst, 10).totalHits);
WildcardQuery wcNoSuch = new WildcardQuery(new Term("field", "noSuch*"));
SpanQuery spanWCNoSuch = new SpanMultiTermQueryWrapper<WildcardQuery>(wcNoSuch);
spanFirst = new SpanFirstQuery(spanWCNoSuch, 10);
assertEquals(0, searcher.search(spanFirst, 10).totalHits);
RegexpQuery rgxNoSuch = new RegexpQuery(new Term("field", "noSuch"));
SpanQuery spanRgxNoSuch = new SpanMultiTermQueryWrapper<RegexpQuery>(rgxNoSuch);
spanFirst = new SpanFirstQuery(spanRgxNoSuch, 10);
assertEquals(0, searcher.search(spanFirst, 10).totalHits);
PrefixQuery prfxNoSuch = new PrefixQuery(new Term("field", "noSuch"));
SpanQuery spanPrfxNoSuch = new SpanMultiTermQueryWrapper<PrefixQuery>(prfxNoSuch);
spanFirst = new SpanFirstQuery(spanPrfxNoSuch, 10);
assertEquals(0, searcher.search(spanFirst, 10).totalHits);
}
} }