diff --git a/CHANGES.txt b/CHANGES.txt
index 621c0838b2b..60352713a66 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -84,6 +84,13 @@ Changes in backwards compatibility policy
be passed upon instantiation. As a result, IndexWriter was removed
as a method argument from all MergePolicy methods. (Shai Erera via
Mike McCandless)
+
+ 6. LUCENE-1748: LUCENE-1001 introduced PayloadSpans, but this was a back
+ compat break and caused custom SpanQuery implementations to fail at runtime
+ in a variety of ways. This issue attempts to remedy things by causing
+ a compile time break on custom SpanQuery implementations and removing
+ the PayloadSpans class, with its functionality now moved to Spans.
+ (Hugh Cayless, Mark Miller)
Changes in runtime behavior
@@ -363,6 +370,13 @@ API Changes
new QueryParser framework in Lucene 3.0, that is currently located
in contrib. (see New Features 35.)
(Luis Alves and Adriano Campos via Michael Busch)
+
+36. LUCENE-1748: LUCENE-1001 introduced PayloadSpans, but this was a back
+ compat break and caused custom SpanQuery implementations to fail at runtime
+ in a variety of ways. This issue attempts to remedy things by causing
+ a compile time break on custom SpanQuery implementations and removing
+ the PayloadSpans class, with its functionality now moved to Spans.
+ (Hugh Cayless, Mark Miller)
Bug fixes
diff --git a/common-build.xml b/common-build.xml
index e6f69b0f31d..18176a1ff4e 100644
--- a/common-build.xml
+++ b/common-build.xml
@@ -42,7 +42,7 @@
t1 t2 .. t3*
t1 .. t2 t3*/ -class NearSpansOrdered implements PayloadSpans { +class NearSpansOrdered implements Spans { private final int allowedSlop; private boolean firstTime = true; private boolean more = false; /** The spans in the same order as the SpanNearQuery */ - private final PayloadSpans[] subSpans; + private final Spans[] subSpans; /** Indicates that all subSpans have same doc() */ private boolean inSameDoc = false; @@ -64,7 +63,7 @@ class NearSpansOrdered implements PayloadSpans { private int matchEnd = -1; private List/*
- * WARNING: The status of the Payloads feature is experimental.
- * The APIs introduced here might change in the future and will not be
- * supported anymore in such a case.
- *
- * @return a List of byte arrays containing the data of this payload, otherwise null if isPayloadAvailable is false
- * @throws java.io.IOException
- */
- // TODO: Remove warning after API has been finalized
- Collection/*
- * WARNING: The status of the Payloads feature is experimental.
- * The APIs introduced here might change in the future and will not be
- * supported anymore in such a case.
- *
- * @return true if there is a payload available at this position that can be loaded
- */
- // TODO: Remove warning after API has been finalized
- public boolean isPayloadAvailable();
-
-}
diff --git a/src/java/org/apache/lucene/search/spans/SpanFirstQuery.java b/src/java/org/apache/lucene/search/spans/SpanFirstQuery.java
index b65233aa91e..4dbc61281c5 100644
--- a/src/java/org/apache/lucene/search/spans/SpanFirstQuery.java
+++ b/src/java/org/apache/lucene/search/spans/SpanFirstQuery.java
@@ -74,13 +74,9 @@ public class SpanFirstQuery extends SpanQuery implements Cloneable {
match.extractTerms(terms);
}
- public PayloadSpans getPayloadSpans(IndexReader reader) throws IOException {
- return (PayloadSpans) getSpans(reader);
- }
-
public Spans getSpans(final IndexReader reader) throws IOException {
- return new PayloadSpans() {
- private PayloadSpans spans = match.getPayloadSpans(reader);
+ return new Spans() {
+ private Spans spans = match.getSpans(reader);
public boolean next() throws IOException {
while (spans.next()) { // scan to next match
diff --git a/src/java/org/apache/lucene/search/spans/SpanNearQuery.java b/src/java/org/apache/lucene/search/spans/SpanNearQuery.java
index f4f29cb3712..a7509970643 100644
--- a/src/java/org/apache/lucene/search/spans/SpanNearQuery.java
+++ b/src/java/org/apache/lucene/search/spans/SpanNearQuery.java
@@ -125,18 +125,14 @@ public class SpanNearQuery extends SpanQuery implements Cloneable {
public Spans getSpans(final IndexReader reader) throws IOException {
if (clauses.size() == 0) // optimize 0-clause case
- return new SpanOrQuery(getClauses()).getPayloadSpans(reader);
+ return new SpanOrQuery(getClauses()).getSpans(reader);
if (clauses.size() == 1) // optimize 1-clause case
- return ((SpanQuery)clauses.get(0)).getPayloadSpans(reader);
+ return ((SpanQuery)clauses.get(0)).getSpans(reader);
return inOrder
- ? (PayloadSpans) new NearSpansOrdered(this, reader, collectPayloads)
- : (PayloadSpans) new NearSpansUnordered(this, reader);
- }
-
- public PayloadSpans getPayloadSpans(IndexReader reader) throws IOException {
- return (PayloadSpans) getSpans(reader);
+ ? (Spans) new NearSpansOrdered(this, reader, collectPayloads)
+ : (Spans) new NearSpansUnordered(this, reader);
}
public Query rewrite(IndexReader reader) throws IOException {
diff --git a/src/java/org/apache/lucene/search/spans/SpanNotQuery.java b/src/java/org/apache/lucene/search/spans/SpanNotQuery.java
index 8ae5ffb296f..2094c3a2322 100644
--- a/src/java/org/apache/lucene/search/spans/SpanNotQuery.java
+++ b/src/java/org/apache/lucene/search/spans/SpanNotQuery.java
@@ -75,8 +75,8 @@ public class SpanNotQuery extends SpanQuery implements Cloneable {
}
public Spans getSpans(final IndexReader reader) throws IOException {
- return new PayloadSpans() {
- private PayloadSpans includeSpans = include.getPayloadSpans(reader);
+ return new Spans() {
+ private Spans includeSpans = include.getSpans(reader);
private boolean moreInclude = true;
private Spans excludeSpans = exclude.getSpans(reader);
@@ -157,10 +157,6 @@ public class SpanNotQuery extends SpanQuery implements Cloneable {
};
}
- public PayloadSpans getPayloadSpans(IndexReader reader) throws IOException {
- return (PayloadSpans) getSpans(reader);
- }
-
public Query rewrite(IndexReader reader) throws IOException {
SpanNotQuery clone = null;
diff --git a/src/java/org/apache/lucene/search/spans/SpanOrQuery.java b/src/java/org/apache/lucene/search/spans/SpanOrQuery.java
index 2171f59c7b0..5af10626874 100644
--- a/src/java/org/apache/lucene/search/spans/SpanOrQuery.java
+++ b/src/java/org/apache/lucene/search/spans/SpanOrQuery.java
@@ -167,22 +167,18 @@ public class SpanOrQuery extends SpanQuery implements Cloneable {
}
}
- public PayloadSpans getPayloadSpans(final IndexReader reader) throws IOException {
- return (PayloadSpans)getSpans(reader);
- }
-
public Spans getSpans(final IndexReader reader) throws IOException {
if (clauses.size() == 1) // optimize 1-clause case
- return ((SpanQuery)clauses.get(0)).getPayloadSpans(reader);
+ return ((SpanQuery)clauses.get(0)).getSpans(reader);
- return new PayloadSpans() {
+ return new Spans() {
private SpanQueue queue = null;
private boolean initSpanQueue(int target) throws IOException {
queue = new SpanQueue(clauses.size());
Iterator i = clauses.iterator();
while (i.hasNext()) {
- PayloadSpans spans = ((SpanQuery)i.next()).getPayloadSpans(reader);
+ Spans spans = ((SpanQuery)i.next()).getSpans(reader);
if ( ((target == -1) && spans.next())
|| ((target != -1) && spans.skipTo(target))) {
queue.put(spans);
@@ -209,7 +205,7 @@ public class SpanOrQuery extends SpanQuery implements Cloneable {
return queue.size() != 0;
}
- private PayloadSpans top() { return (PayloadSpans)queue.top(); }
+ private Spans top() { return (Spans)queue.top(); }
public boolean skipTo(int target) throws IOException {
if (queue == null) {
@@ -239,7 +235,7 @@ public class SpanOrQuery extends SpanQuery implements Cloneable {
// TODO: Remove warning after API has been finalized
public Collection/*
+ * WARNING: The status of the Payloads feature is experimental.
+ * The APIs introduced here might change in the future and will not be
+ * supported anymore in such a case.
+ *
+ * @return a List of byte arrays containing the data of this payload, otherwise null if isPayloadAvailable is false
+ * @throws java.io.IOException
+ */
+ // TODO: Remove warning after API has been finalized
+ Collection/*
+ * WARNING: The status of the Payloads feature is experimental.
+ * The APIs introduced here might change in the future and will not be
+ * supported anymore in such a case.
+ *
+ * @return true if there is a payload available at this position that can be loaded
+ */
+ // TODO: Remove warning after API has been finalized
+ public boolean isPayloadAvailable();
}
diff --git a/src/java/org/apache/lucene/search/spans/TermSpans.java b/src/java/org/apache/lucene/search/spans/TermSpans.java
index ec4efb1ed13..7127f56e8dc 100644
--- a/src/java/org/apache/lucene/search/spans/TermSpans.java
+++ b/src/java/org/apache/lucene/search/spans/TermSpans.java
@@ -27,7 +27,7 @@ import java.util.Collection;
* Expert:
* Public for extension only
*/
-public class TermSpans implements PayloadSpans {
+public class TermSpans implements Spans {
protected TermPositions positions;
protected Term term;
protected int doc;
diff --git a/src/test/org/apache/lucene/search/TestPositionIncrement.java b/src/test/org/apache/lucene/search/TestPositionIncrement.java
index 9d82e416cba..4056c2dfba5 100644
--- a/src/test/org/apache/lucene/search/TestPositionIncrement.java
+++ b/src/test/org/apache/lucene/search/TestPositionIncrement.java
@@ -45,7 +45,6 @@ import org.apache.lucene.analysis.LowerCaseTokenizer;
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.index.Payload;
import org.apache.lucene.search.payloads.PayloadSpanUtil;
-import org.apache.lucene.search.spans.PayloadSpans;
import org.apache.lucene.search.spans.SpanNearQuery;
import org.apache.lucene.search.spans.SpanQuery;
import org.apache.lucene.search.spans.SpanTermQuery;
@@ -279,7 +278,7 @@ public class TestPositionIncrement extends LuceneTestCase {
count = 0;
boolean sawZero = false;
//System.out.println("\ngetPayloadSpans test");
- PayloadSpans pspans = snq.getPayloadSpans(is.getIndexReader());
+ Spans pspans = snq.getSpans(is.getIndexReader());
while (pspans.next()) {
//System.out.println(pspans.doc() + " - " + pspans.start() + " - "+ pspans.end());
Collection payloads = pspans.getPayload();
diff --git a/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java b/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java
index 38e2fe3aff2..59dbf58eb2a 100644
--- a/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java
+++ b/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java
@@ -57,6 +57,14 @@ final class JustCompileSearchSpans {
public int start() {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
+
+ public Collection getPayload() throws IOException {
+ throw new UnsupportedOperationException(UNSUPPORTED_MSG);
+ }
+
+ public boolean isPayloadAvailable() {
+ throw new UnsupportedOperationException(UNSUPPORTED_MSG);
+ }
}
@@ -81,7 +89,7 @@ final class JustCompileSearchSpans {
}
- static final class JustCompilePayloadSpans implements PayloadSpans {
+ static final class JustCompilePayloadSpans implements Spans {
public Collection getPayload() throws IOException {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
diff --git a/src/test/org/apache/lucene/search/spans/TestPayloadSpans.java b/src/test/org/apache/lucene/search/spans/TestPayloadSpans.java
index 3bd6d0312be..26beb01be9f 100644
--- a/src/test/org/apache/lucene/search/spans/TestPayloadSpans.java
+++ b/src/test/org/apache/lucene/search/spans/TestPayloadSpans.java
@@ -26,7 +26,6 @@ import java.util.Set;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.LowerCaseTokenizer;
-import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.PayloadAttribute;
@@ -51,7 +50,7 @@ import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.LuceneTestCase;
public class TestPayloadSpans extends LuceneTestCase {
- private final static boolean DEBUG = false;
+ private final static boolean DEBUG = true;
private IndexSearcher searcher;
private Similarity similarity = new DefaultSimilarity();
protected IndexReader indexReader;
@@ -73,14 +72,14 @@ public class TestPayloadSpans extends LuceneTestCase {
public void testSpanTermQuery() throws Exception {
SpanTermQuery stq;
- PayloadSpans spans;
+ Spans spans;
stq = new SpanTermQuery(new Term(PayloadHelper.FIELD, "seventy"));
- spans = stq.getPayloadSpans(indexReader);
+ spans = stq.getSpans(indexReader);
assertTrue("spans is null and it shouldn't be", spans != null);
checkSpans(spans, 100, 1, 1, 1);
stq = new SpanTermQuery(new Term(PayloadHelper.NO_PAYLOAD_FIELD, "seventy"));
- spans = stq.getPayloadSpans(indexReader);
+ spans = stq.getSpans(indexReader);
assertTrue("spans is null and it shouldn't be", spans != null);
checkSpans(spans, 100, 0, 0, 0);
}
@@ -91,7 +90,7 @@ public class TestPayloadSpans extends LuceneTestCase {
SpanFirstQuery sfq;
match = new SpanTermQuery(new Term(PayloadHelper.FIELD, "one"));
sfq = new SpanFirstQuery(match, 2);
- PayloadSpans spans = sfq.getPayloadSpans(indexReader);
+ Spans spans = sfq.getSpans(indexReader);
checkSpans(spans, 109, 1, 1, 1);
//Test more complicated subclause
SpanQuery[] clauses = new SpanQuery[2];
@@ -99,20 +98,49 @@ public class TestPayloadSpans extends LuceneTestCase {
clauses[1] = new SpanTermQuery(new Term(PayloadHelper.FIELD, "hundred"));
match = new SpanNearQuery(clauses, 0, true);
sfq = new SpanFirstQuery(match, 2);
- checkSpans(sfq.getPayloadSpans(indexReader), 100, 2, 1, 1);
+ checkSpans(sfq.getSpans(indexReader), 100, 2, 1, 1);
match = new SpanNearQuery(clauses, 0, false);
sfq = new SpanFirstQuery(match, 2);
- checkSpans(sfq.getPayloadSpans(indexReader), 100, 2, 1, 1);
+ checkSpans(sfq.getSpans(indexReader), 100, 2, 1, 1);
}
+ public void testSpanNot() throws Exception {
+ SpanQuery[] clauses = new SpanQuery[2];
+ clauses[0] = new SpanTermQuery(new Term(PayloadHelper.FIELD, "one"));
+ clauses[1] = new SpanTermQuery(new Term(PayloadHelper.FIELD, "three"));
+ SpanQuery spq = new SpanNearQuery(clauses, 5, true);
+ SpanNotQuery snq = new SpanNotQuery(spq, new SpanTermQuery(new Term(PayloadHelper.FIELD, "two")));
+ checkSpans(snq.getSpans(getSpanNotSearcher().getIndexReader()), 1,new int[]{2});
+ }
+
+ public IndexSearcher getSpanNotSearcher()
+ throws IOException {
+ RAMDirectory directory = new RAMDirectory();
+ PayloadAnalyzer analyzer = new PayloadAnalyzer();
+ IndexWriter writer = new IndexWriter(directory, analyzer, true);
+ writer.setSimilarity(similarity);
+
+ Document doc = new Document();
+ doc.add(new Field(PayloadHelper.FIELD, "one two three one four three",
+ Field.Store.YES, Field.Index.ANALYZED));
+ writer.addDocument(doc);
+
+ writer.close();
+
+ IndexSearcher searcher = new IndexSearcher(directory);
+ searcher.setSimilarity(similarity);
+ return searcher;
+
+ }
+
public void testNestedSpans() throws Exception {
SpanTermQuery stq;
- PayloadSpans spans;
+ Spans spans;
IndexSearcher searcher = getSearcher();
stq = new SpanTermQuery(new Term(PayloadHelper.FIELD, "mark"));
- spans = stq.getPayloadSpans(searcher.getIndexReader());
+ spans = stq.getSpans(searcher.getIndexReader());
assertTrue("spans is null and it shouldn't be", spans != null);
checkSpans(spans, 0, null);
@@ -123,7 +151,7 @@ public class TestPayloadSpans extends LuceneTestCase {
clauses[2] = new SpanTermQuery(new Term(PayloadHelper.FIELD, "xx"));
SpanNearQuery spanNearQuery = new SpanNearQuery(clauses, 12, false);
- spans = spanNearQuery.getPayloadSpans(searcher.getIndexReader());
+ spans = spanNearQuery.getSpans(searcher.getIndexReader());
assertTrue("spans is null and it shouldn't be", spans != null);
checkSpans(spans, 2, new int[]{3,3});
@@ -135,7 +163,7 @@ public class TestPayloadSpans extends LuceneTestCase {
spanNearQuery = new SpanNearQuery(clauses, 6, true);
- spans = spanNearQuery.getPayloadSpans(searcher.getIndexReader());
+ spans = spanNearQuery.getSpans(searcher.getIndexReader());
assertTrue("spans is null and it shouldn't be", spans != null);
checkSpans(spans, 1, new int[]{3});
@@ -157,13 +185,13 @@ public class TestPayloadSpans extends LuceneTestCase {
// yy within 6 of xx within 6 of rr
- spans = nestedSpanNearQuery.getPayloadSpans(searcher.getIndexReader());
+ spans = nestedSpanNearQuery.getSpans(searcher.getIndexReader());
assertTrue("spans is null and it shouldn't be", spans != null);
checkSpans(spans, 2, new int[]{3,3});
}
public void testFirstClauseWithoutPayload() throws Exception {
- PayloadSpans spans;
+ Spans spans;
IndexSearcher searcher = getSearcher();
SpanQuery[] clauses = new SpanQuery[3];
@@ -187,13 +215,13 @@ public class TestPayloadSpans extends LuceneTestCase {
SpanNearQuery nestedSpanNearQuery = new SpanNearQuery(clauses3, 6, false);
- spans = nestedSpanNearQuery.getPayloadSpans(searcher.getIndexReader());
+ spans = nestedSpanNearQuery.getSpans(searcher.getIndexReader());
assertTrue("spans is null and it shouldn't be", spans != null);
checkSpans(spans, 1, new int[]{3});
}
public void testHeavilyNestedSpanQuery() throws Exception {
- PayloadSpans spans;
+ Spans spans;
IndexSearcher searcher = getSearcher();
SpanQuery[] clauses = new SpanQuery[3];
@@ -222,7 +250,7 @@ public class TestPayloadSpans extends LuceneTestCase {
SpanNearQuery nestedSpanNearQuery = new SpanNearQuery(clauses3, 6, false);
- spans = nestedSpanNearQuery.getPayloadSpans(searcher.getIndexReader());
+ spans = nestedSpanNearQuery.getSpans(searcher.getIndexReader());
assertTrue("spans is null and it shouldn't be", spans != null);
checkSpans(spans, 2, new int[]{8, 8});
}
@@ -243,7 +271,7 @@ public class TestPayloadSpans extends LuceneTestCase {
SpanTermQuery stq2 = new SpanTermQuery(new Term("content", "k"));
SpanQuery[] sqs = { stq1, stq2 };
SpanNearQuery snq = new SpanNearQuery(sqs, 1, true);
- PayloadSpans spans = snq.getPayloadSpans(is.getIndexReader());
+ Spans spans = snq.getSpans(is.getIndexReader());
TopDocs topDocs = is.search(snq, 1);
Set payloadSet = new HashSet();
@@ -277,7 +305,7 @@ public class TestPayloadSpans extends LuceneTestCase {
SpanTermQuery stq2 = new SpanTermQuery(new Term("content", "k"));
SpanQuery[] sqs = { stq1, stq2 };
SpanNearQuery snq = new SpanNearQuery(sqs, 0, true);
- PayloadSpans spans = snq.getPayloadSpans(is.getIndexReader());
+ Spans spans = snq.getSpans(is.getIndexReader());
TopDocs topDocs = is.search(snq, 1);
Set payloadSet = new HashSet();
@@ -311,7 +339,7 @@ public class TestPayloadSpans extends LuceneTestCase {
SpanTermQuery stq2 = new SpanTermQuery(new Term("content", "k"));
SpanQuery[] sqs = { stq1, stq2 };
SpanNearQuery snq = new SpanNearQuery(sqs, 0, true);
- PayloadSpans spans = snq.getPayloadSpans(is.getIndexReader());
+ Spans spans = snq.getSpans(is.getIndexReader());
TopDocs topDocs = is.search(snq, 1);
Set payloadSet = new HashSet();
@@ -364,7 +392,7 @@ public class TestPayloadSpans extends LuceneTestCase {
}
- private void checkSpans(PayloadSpans spans, int expectedNumSpans, int expectedNumPayloads,
+ private void checkSpans(Spans spans, int expectedNumSpans, int expectedNumPayloads,
int expectedPayloadLength, int expectedFirstByte) throws IOException {
assertTrue("spans is null and it shouldn't be", spans != null);
//each position match should have a span associated with it, since there is just one underlying term query, there should
@@ -420,7 +448,7 @@ public class TestPayloadSpans extends LuceneTestCase {
return searcher;
}
- private void checkSpans(PayloadSpans spans, int numSpans, int[] numPayloads) throws IOException {
+ private void checkSpans(Spans spans, int numSpans, int[] numPayloads) throws IOException {
int cnt = 0;
while (spans.next() == true) {
+ *
+ * Note that the return type is a collection, thus the ordering should not be relied upon.
+ *
+ *