Index: lucene/src/java/org/apache/lucene/search/spans/SpanFirstQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanFirstQuery.java (revision 1034745) +++ lucene/src/java/org/apache/lucene/search/spans/SpanFirstQuery.java (working copy) @@ -37,8 +37,14 @@ } @Override - protected boolean acceptPosition(Spans spans) throws IOException { - return spans.end() <= end; + protected AcceptStatus acceptPosition(Spans spans) throws IOException { + assert spans.start() != spans.end(); + if (spans.start() >= end) + return AcceptStatus.NO_AND_ADVANCE; + else if (spans.end() <= end) + return AcceptStatus.YES; + else + return AcceptStatus.NO; } Index: lucene/src/java/org/apache/lucene/search/spans/SpanPayloadCheckQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanPayloadCheckQuery.java (revision 1034745) +++ lucene/src/java/org/apache/lucene/search/spans/SpanPayloadCheckQuery.java (working copy) @@ -50,7 +50,7 @@ } @Override - protected boolean acceptPosition(Spans spans) throws IOException { + protected AcceptStatus acceptPosition(Spans spans) throws IOException { boolean result = spans.isPayloadAvailable(); if (result == true){ Collection candidate = spans.getPayload(); @@ -62,16 +62,16 @@ for (byte[] candBytes : candidate) { //if one is a mismatch, then return false if (Arrays.equals(candBytes, toMatchIter.next()) == false){ - return false; + return AcceptStatus.NO; } } //we've verified all the bytes - return true; + return AcceptStatus.YES; } else { - return false; + return AcceptStatus.NO; } } - return result; + return AcceptStatus.YES; } public String toString(String field) { Index: lucene/src/java/org/apache/lucene/search/spans/SpanNearPayloadCheckQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanNearPayloadCheckQuery.java (revision 1034745) +++ lucene/src/java/org/apache/lucene/search/spans/SpanNearPayloadCheckQuery.java (working copy) @@ -43,7 +43,7 @@ } @Override - protected boolean acceptPosition(Spans spans) throws IOException { + protected AcceptStatus acceptPosition(Spans spans) throws IOException { boolean result = spans.isPayloadAvailable(); if (result == true) { Collection candidate = spans.getPayload(); @@ -62,15 +62,15 @@ } if (matches == payloadToMatch.size()){ //we've verified all the bytes - return true; + return AcceptStatus.YES; } else { - return false; + return AcceptStatus.NO; } } else { - return false; + return AcceptStatus.NO; } } - return false; + return AcceptStatus.NO; } public String toString(String field) { Index: lucene/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java (revision 1034745) +++ lucene/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java (working copy) @@ -20,6 +20,7 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.search.Query; +import org.apache.lucene.util.BytesRef; import java.io.IOException; import java.util.ArrayList; @@ -57,6 +58,12 @@ match.extractTerms(terms); } + /** Return value if the match should be accepted {@code YES}, rejected {@code NO}, + * or rejected and enumeration should advance to the next document {@code NO_AND_ADVANCE}. + * @see #acceptPosition(Spans) + */ + protected static enum AcceptStatus { YES, NO, NO_AND_ADVANCE }; + /** * Implementing classes are required to return whether the current position is a match for the passed in * "match" {@link org.apache.lucene.search.spans.SpanQuery}. @@ -66,37 +73,13 @@ * * * @param spans The {@link org.apache.lucene.search.spans.Spans} instance, positioned at the spot to check - * @return true if it is a match, else false. + * @return whether the match is accepted, rejected, or rejected and should move to the next doc. * * @see org.apache.lucene.search.spans.Spans#next() * */ - protected abstract boolean acceptPosition(Spans spans) throws IOException; + protected abstract AcceptStatus acceptPosition(Spans spans) throws IOException; - /** - * Implementing classes are required to return whether the position at the target is someplace that - * can be skipped to. For instance, the {@link org.apache.lucene.search.spans.SpanFirstQuery} returns - * false if the target position is beyond the maximum position allowed or if {@link Spans#next()} is true. - *

- * Note, this method is only called if the underlying match {@link org.apache.lucene.search.spans.SpanQuery} can - * skip to the target. - *

- * It is safe to assume that the passed in {@link org.apache.lucene.search.spans.Spans} object for the underlying {@link org.apache.lucene.search.spans.SpanQuery} is - * positioned at the target. - *

- * The default implementation is to return true if either {@link #acceptPosition(Spans)} or {@link org.apache.lucene.search.spans.Spans#next()} is true for the - * passed in instance of Spans. - *

- * @param spans The {@link org.apache.lucene.search.spans.Spans} to check - * @return true if the instance can skip to this position - * - * @see Spans#skipTo(int) - * @throws java.io.IOException if there is a low-level IO error - */ - protected boolean acceptSkipTo(Spans spans) throws IOException{ - return acceptPosition(spans) || spans.next(); - } - @Override public Spans getSpans(final IndexReader reader) throws IOException { return new PositionCheckSpan(reader); @@ -123,21 +106,16 @@ protected class PositionCheckSpan extends Spans { private Spans spans; - private final IndexReader reader; - public PositionCheckSpan(IndexReader reader) throws IOException { - this.reader = reader; spans = match.getSpans(reader); } @Override public boolean next() throws IOException { - //TODO: optimize to skip ahead to start - while (spans.next()) { // scan to next match - if (acceptPosition(this)) - return true; - } - return false; + if (!spans.next()) + return false; + + return doNext(); } @Override @@ -145,9 +123,24 @@ if (!spans.skipTo(target)) return false; - return acceptSkipTo(this); - + return doNext(); } + + protected boolean doNext() throws IOException { + for (;;) { + switch(acceptPosition(this)) { + case YES: return true; + case NO: + if (!spans.next()) + return false; + break; + case NO_AND_ADVANCE: + if (!spans.skipTo(spans.doc()+1)) + return false; + break; + } + } + } @Override public int doc() { return spans.doc(); } Index: lucene/src/java/org/apache/lucene/search/spans/SpanPositionRangeQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanPositionRangeQuery.java (revision 1034745) +++ lucene/src/java/org/apache/lucene/search/spans/SpanPositionRangeQuery.java (working copy) @@ -39,8 +39,14 @@ @Override - protected boolean acceptPosition(Spans spans) throws IOException { - return spans.start() >= start && spans.end() <= end; + protected AcceptStatus acceptPosition(Spans spans) throws IOException { + assert spans.start() != spans.end(); + if (spans.start() >= end) + return AcceptStatus.NO_AND_ADVANCE; + else if (spans.start() >= start && spans.end() <= end) + return AcceptStatus.YES; + else + return AcceptStatus.NO; }