diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 0f12f453a71..c56ee4a6977 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -65,6 +65,14 @@ Optimizations on Windows if NIOFSDirectory is used, mmapped files are still locked. (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 ======================= New Features diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java index 7c7781c99a1..c412f133953 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java @@ -64,9 +64,9 @@ public class SpanNearQuery extends SpanQuery implements Cloneable { this.clauses = new ArrayList(clauses.length); for (int i = 0; i < clauses.length; i++) { SpanQuery clause = clauses[i]; - if (i == 0) { // check field + if (field == null) { // check field 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."); } this.clauses.add(clause); diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java index 7a7fcf91c80..055ced6b14b 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java @@ -62,7 +62,7 @@ public class SpanNotQuery extends SpanQuery implements Cloneable { this.pre = (pre >=0) ? pre : 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."); } diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java index 689eb5e6185..d4ab76f4f18 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java @@ -54,7 +54,7 @@ public class SpanOrQuery extends SpanQuery implements Cloneable { public final void addClause(SpanQuery clause) { if (field == null) { 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."); } this.clauses.add(clause); @@ -132,7 +132,6 @@ public class SpanOrQuery extends SpanQuery implements Cloneable { final SpanOrQuery that = (SpanOrQuery) o; if (!clauses.equals(that.clauses)) return false; - if (!clauses.isEmpty() && !field.equals(that.field)) return false; return getBoost() == that.getBoost(); } diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanQuery.java index 37672799a9b..d6176163180 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanQuery.java @@ -34,7 +34,11 @@ public abstract class SpanQuery extends Query { * to search for spans. */ public abstract Spans getSpans(AtomicReaderContext context, Bits acceptDocs, Map termContexts) throws IOException; - /** Returns the name of the field matched by this query.*/ + /** + * Returns the name of the field matched by this query. + *

+ * Note that this may return null if the query matches no terms. + */ public abstract String getField(); @Override diff --git a/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanMultiTermQueryWrapper.java b/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanMultiTermQueryWrapper.java index 9a310a92cf2..4dad29342dc 100644 --- a/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanMultiTermQueryWrapper.java +++ b/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanMultiTermQueryWrapper.java @@ -24,6 +24,8 @@ import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.search.FuzzyQuery; 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.store.Directory; import org.apache.lucene.util.LuceneTestCase; @@ -95,4 +97,133 @@ public class TestSpanMultiTermQueryWrapper extends LuceneTestCase { SpanPositionRangeQuery sprq = new SpanPositionRangeQuery(sfq, 0, 100); 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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(prfxNoSuch); + spanFirst = new SpanFirstQuery(spanPrfxNoSuch, 10); + assertEquals(0, searcher.search(spanFirst, 10).totalHits); + } }