You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ro...@apache.org on 2015/05/19 11:02:40 UTC

svn commit: r1680205 [1/2] - in /lucene/dev/trunk: lucene/ lucene/core/src/java/org/apache/lucene/search/payloads/ lucene/core/src/java/org/apache/lucene/search/spans/ lucene/core/src/test/org/apache/lucene/search/ lucene/core/src/test/org/apache/lucen...

Author: romseygeek
Date: Tue May 19 09:02:38 2015
New Revision: 1680205

URL: http://svn.apache.org/r1680205
Log:
LUCENE-6371: Add collection API to Spans, remove payload methods

Added:
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadSpanCollector.java   (with props)
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/SpanNearPayloadCheckQuery.java   (with props)
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/SpanPayloadCheckQuery.java   (with props)
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/BufferedSpanCollector.java   (with props)
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanCollector.java   (with props)
Removed:
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/NearSpansPayloadOrdered.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearPayloadCheckQuery.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanPayloadCheckQuery.java
Modified:
    lucene/dev/trunk/lucene/CHANGES.txt
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadNearQuery.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadSpanUtil.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadTermQuery.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/ContainSpans.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/FilterSpans.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/NearSpansOrdered.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/NearSpansUnordered.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainQuery.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainingQuery.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanQuery.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanTermQuery.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanWeight.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanWithinQuery.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/Spans.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/TermSpans.java
    lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestPositionIncrement.java
    lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/payloads/TestPayloadBasics.java
    lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/payloads/TestPayloadSpans.java
    lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java
    lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/spans/MultiSpansWrapper.java
    lucene/dev/trunk/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java
    lucene/dev/trunk/lucene/highlighter/src/test/org/apache/lucene/search/highlight/HighlighterTest.java
    lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpanQuery.java
    lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpans.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/highlight/HighlighterTest.java

Modified: lucene/dev/trunk/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/CHANGES.txt?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/CHANGES.txt (original)
+++ lucene/dev/trunk/lucene/CHANGES.txt Tue May 19 09:02:38 2015
@@ -189,6 +189,12 @@ API Changes
 * LUCENE-6445: Two new methods in Highlighter's TokenSources; the existing
   methods are now marked deprecated. (David Smiley)
 
+* LUCENE-6371: Payload collection from Spans is moved to a more generic
+  SpanCollector framework.  Spans no longer implements .hasPayload() and
+  .getPayload() methods, and instead exposes a collect() method that allows
+  the collection of arbitrary postings information. (Alan Woodward, David
+  Smiley, Paul Elschot)
+
 Other
 
 * LUCENE-6413: Test runner should report the number of suites completed/ 

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadNearQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadNearQuery.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadNearQuery.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadNearQuery.java Tue May 19 09:02:38 2015
@@ -17,11 +17,6 @@ package org.apache.lucene.search.payload
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Objects;
-
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.Explanation;
 import org.apache.lucene.search.IndexSearcher;
@@ -29,8 +24,6 @@ import org.apache.lucene.search.Scorer;
 import org.apache.lucene.search.similarities.DefaultSimilarity;
 import org.apache.lucene.search.similarities.Similarity;
 import org.apache.lucene.search.similarities.Similarity.SimScorer;
-import org.apache.lucene.search.spans.NearSpansOrdered;
-import org.apache.lucene.search.spans.NearSpansUnordered;
 import org.apache.lucene.search.spans.SpanNearQuery;
 import org.apache.lucene.search.spans.SpanQuery;
 import org.apache.lucene.search.spans.SpanScorer;
@@ -40,6 +33,11 @@ import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.ToStringUtils;
 
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Objects;
+
 /**
  * This class is very similar to
  * {@link org.apache.lucene.search.spans.SpanNearQuery} except that it factors
@@ -55,8 +53,10 @@ import org.apache.lucene.util.ToStringUt
  * @see org.apache.lucene.search.similarities.Similarity.SimScorer#computePayloadFactor(int, int, int, BytesRef)
  */
 public class PayloadNearQuery extends SpanNearQuery {
+
   protected String fieldName;
   protected PayloadFunction function;
+  protected final PayloadSpanCollector payloadCollector = new PayloadSpanCollector();
 
   public PayloadNearQuery(SpanQuery[] clauses, int slop, boolean inOrder) {
     this(clauses, slop, inOrder, new AveragePayloadFunction());
@@ -129,17 +129,18 @@ public class PayloadNearQuery extends Sp
   }
 
   public class PayloadNearSpanWeight extends SpanWeight {
+
     public PayloadNearSpanWeight(SpanQuery query, IndexSearcher searcher)
         throws IOException {
-      super(query, searcher);
+      super(query, searcher, payloadCollector);
     }
 
     @Override
     public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException {
-      Spans spans = query.getSpans(context, acceptDocs, termContexts);
+      Spans spans = query.getSpans(context, acceptDocs, termContexts, payloadCollector);
       return (spans == null)
               ? null
-              : new PayloadNearSpanScorer(spans, this, similarity, similarity.simScorer(stats, context));
+              : new PayloadNearSpanScorer(spans, this, similarity.simScorer(stats, context));
     }
     
     @Override
@@ -176,31 +177,11 @@ public class PayloadNearQuery extends Sp
     protected float payloadScore;
     private int payloadsSeen;
 
-    protected PayloadNearSpanScorer(Spans spans, SpanWeight weight,
-        Similarity similarity, Similarity.SimScorer docScorer) throws IOException {
+    protected PayloadNearSpanScorer(Spans spans, SpanWeight weight, Similarity.SimScorer docScorer) throws IOException {
       super(spans, weight, docScorer);
       this.spans = spans;
     }
 
-    // Get the payloads associated with all underlying subspans
-    public void getPayloads(Spans[] subSpans) throws IOException {
-      for (int i = 0; i < subSpans.length; i++) {
-        if (subSpans[i] instanceof NearSpansOrdered) {
-          if (((NearSpansOrdered) subSpans[i]).isPayloadAvailable()) {
-            processPayloads(((NearSpansOrdered) subSpans[i]).getPayload(),
-                subSpans[i].startPosition(), subSpans[i].endPosition());
-          }
-          getPayloads(((NearSpansOrdered) subSpans[i]).getSubSpans());
-        } else if (subSpans[i] instanceof NearSpansUnordered) {
-          if (((NearSpansUnordered) subSpans[i]).isPayloadAvailable()) {
-            processPayloads(((NearSpansUnordered) subSpans[i]).getPayload(),
-                subSpans[i].startPosition(), subSpans[i].endPosition());
-          }
-          getPayloads(((NearSpansUnordered) subSpans[i]).getSubSpans());
-        }
-      }
-    }
-
     // TODO change the whole spans api to use bytesRef, or nuke spans
     BytesRef scratch = new BytesRef();
 
@@ -237,9 +218,9 @@ public class PayloadNearQuery extends Sp
       do {
         int matchLength = spans.endPosition() - startPos;
         freq += docScorer.computeSlopFactor(matchLength);
-        Spans[] spansArr = new Spans[1];
-        spansArr[0] = spans;
-        getPayloads(spansArr);            
+        payloadCollector.reset();
+        spans.collect(payloadCollector);
+        processPayloads(payloadCollector.getPayloads(), startPos, spans.endPosition());
         startPos = spans.nextStartPosition();
       } while (startPos != Spans.NO_MORE_POSITIONS);
     }

Added: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadSpanCollector.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadSpanCollector.java?rev=1680205&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadSpanCollector.java (added)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadSpanCollector.java Tue May 19 09:02:38 2015
@@ -0,0 +1,103 @@
+package org.apache.lucene.search.payloads;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.lucene.index.PostingsEnum;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.spans.BufferedSpanCollector;
+import org.apache.lucene.search.spans.SpanCollector;
+import org.apache.lucene.search.spans.Spans;
+import org.apache.lucene.util.BytesRef;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * SpanCollector implementation that collects payloads from a {@link Spans}
+ */
+public class PayloadSpanCollector implements SpanCollector {
+
+  private final Collection<byte[]> payloads = new ArrayList<>();
+  BufferedPayloadCollector bufferedCollector;
+
+  public Collection<byte[]> getPayloads() {
+    return payloads;
+  }
+
+  @Override
+  public void reset() {
+    payloads.clear();
+  }
+
+  @Override
+  public int requiredPostings() {
+    return PostingsEnum.PAYLOADS;
+  }
+
+  @Override
+  public void collectLeaf(PostingsEnum postings, Term term) throws IOException {
+    BytesRef payload = postings.getPayload();
+    if (payload == null)
+      return;
+    final byte[] bytes = new byte[payload.length];
+    System.arraycopy(payload.bytes, payload.offset, bytes, 0, payload.length);
+    payloads.add(bytes);
+  }
+
+  @Override
+  public BufferedSpanCollector buffer() {
+    if (bufferedCollector == null)
+      bufferedCollector = new BufferedPayloadCollector();
+    bufferedCollector.reset();
+    return bufferedCollector;
+  }
+
+  @Override
+  public SpanCollector bufferedCollector() {
+    if (bufferedCollector == null)
+      bufferedCollector = new BufferedPayloadCollector();
+    return bufferedCollector.candidateCollector;
+  }
+
+  class BufferedPayloadCollector implements BufferedSpanCollector {
+
+    final Collection<byte[]> buffer = new ArrayList<>();
+    PayloadSpanCollector candidateCollector = new PayloadSpanCollector();
+
+    void reset() {
+      buffer.clear();
+    }
+
+    @Override
+    public void collectCandidate(Spans spans) throws IOException {
+      candidateCollector.reset();
+      spans.collect(candidateCollector);
+    }
+
+    @Override
+    public void accept() {
+      buffer.addAll(candidateCollector.payloads);
+    }
+
+    @Override
+    public void replay() {
+      payloads.addAll(buffer);
+    }
+  }
+}

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadSpanUtil.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadSpanUtil.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadSpanUtil.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadSpanUtil.java Tue May 19 09:02:38 2015
@@ -17,15 +17,6 @@ package org.apache.lucene.search.payload
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeSet;
-
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReaderContext;
 import org.apache.lucene.index.LeafReaderContext;
@@ -46,6 +37,15 @@ import org.apache.lucene.search.spans.Sp
 import org.apache.lucene.search.spans.SpanTermQuery;
 import org.apache.lucene.search.spans.Spans;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeSet;
+
 /**
  * Experimental class to get set of payloads for most standard Lucene queries.
  * Operates like Highlighter - IndexReader should only contain doc of interest,
@@ -187,17 +187,16 @@ public class PayloadSpanUtil {
     for (Term term : terms) {
       termContexts.put(term, TermContext.build(context, term));
     }
+
+    PayloadSpanCollector collector = new PayloadSpanCollector();
     for (LeafReaderContext leafReaderContext : context.leaves()) {
-      final Spans spans = query.getSpans(leafReaderContext, leafReaderContext.reader().getLiveDocs(), termContexts);
+      final Spans spans = query.getSpans(leafReaderContext, leafReaderContext.reader().getLiveDocs(), termContexts, collector);
       if (spans != null) {
         while (spans.nextDoc() != Spans.NO_MORE_DOCS) {
           while (spans.nextStartPosition() != Spans.NO_MORE_POSITIONS) {
-            if (spans.isPayloadAvailable()) {
-              Collection<byte[]> payload = spans.getPayload();
-              for (byte [] bytes : payload) {
-                payloads.add(bytes);
-              }
-            }
+            collector.reset();
+            spans.collect(collector);
+            payloads.addAll(collector.getPayloads());
           }
         }
       }

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadTermQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadTermQuery.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadTermQuery.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadTermQuery.java Tue May 19 09:02:38 2015
@@ -17,9 +17,6 @@ package org.apache.lucene.search.payload
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.Objects;
-
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.PostingsEnum;
 import org.apache.lucene.index.Term;
@@ -28,6 +25,8 @@ import org.apache.lucene.search.IndexSea
 import org.apache.lucene.search.similarities.DefaultSimilarity;
 import org.apache.lucene.search.similarities.Similarity;
 import org.apache.lucene.search.similarities.Similarity.SimScorer;
+import org.apache.lucene.search.spans.BufferedSpanCollector;
+import org.apache.lucene.search.spans.SpanCollector;
 import org.apache.lucene.search.spans.SpanQuery;
 import org.apache.lucene.search.spans.SpanScorer;
 import org.apache.lucene.search.spans.SpanTermQuery;
@@ -37,6 +36,9 @@ import org.apache.lucene.search.spans.Te
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
 
+import java.io.IOException;
+import java.util.Objects;
+
 /**
  * This class is very similar to
  * {@link org.apache.lucene.search.spans.SpanTermQuery} except that it factors
@@ -67,19 +69,52 @@ public class PayloadTermQuery extends Sp
 
   @Override
   public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
-    return new PayloadTermWeight(this, searcher);
+    return new PayloadTermWeight(this, searcher, new PayloadTermCollector());
+  }
+
+  protected class PayloadTermCollector implements SpanCollector {
+
+    BytesRef payload;
+
+    @Override
+    public void reset() {
+      payload = null;
+    }
+
+    @Override
+    public int requiredPostings() {
+      return PostingsEnum.PAYLOADS;
+    }
+
+    @Override
+    public void collectLeaf(PostingsEnum postings, Term term) throws IOException {
+      payload = postings.getPayload();
+    }
+
+    @Override
+    public BufferedSpanCollector buffer() {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SpanCollector bufferedCollector() {
+      throw new UnsupportedOperationException();
+    }
   }
 
   protected class PayloadTermWeight extends SpanWeight {
 
-    public PayloadTermWeight(PayloadTermQuery query, IndexSearcher searcher)
+    final PayloadTermCollector payloadCollector;
+
+    public PayloadTermWeight(PayloadTermQuery query, IndexSearcher searcher, PayloadTermCollector collector)
         throws IOException {
-      super(query, searcher);
+      super(query, searcher, collector);
+      this.payloadCollector = collector;
     }
 
     @Override
     public PayloadTermSpanScorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException {
-      TermSpans spans = (TermSpans) query.getSpans(context, acceptDocs, termContexts);
+      TermSpans spans = (TermSpans) query.getSpans(context, acceptDocs, termContexts, payloadCollector);
       return (spans == null)
               ? null
               : new PayloadTermSpanScorer(spans, this, similarity.simScorer(stats, context));
@@ -109,29 +144,22 @@ public class PayloadTermQuery extends Sp
 
           freq += docScorer.computeSlopFactor(matchLength);
           numMatches++;
-          processPayload(similarity);
+          payloadCollector.reset();
+          spans.collect(payloadCollector);
+          processPayload();
 
           startPos = spans.nextStartPosition();
         } while (startPos != Spans.NO_MORE_POSITIONS);
       }
 
-      protected void processPayload(Similarity similarity) throws IOException {
-        if (spans.isPayloadAvailable()) {
-          final PostingsEnum postings = termSpans.getPostings();
-          payload = postings.getPayload();
-          if (payload != null) {
-            payloadScore = function.currentScore(docID(), term.field(),
-                                                 spans.startPosition(), spans.endPosition(), payloadsSeen, payloadScore,
-                                                 docScorer.computePayloadFactor(docID(), spans.startPosition(), spans.endPosition(), payload));
-          } else {
-            payloadScore = function.currentScore(docID(), term.field(),
-                                                 spans.startPosition(), spans.endPosition(), payloadsSeen, payloadScore, 1F);
-          }
-          payloadsSeen++;
-
-        } else {
-          // zero out the payload?
-        }
+      protected void processPayload() throws IOException {
+
+        float payloadFactor = payloadCollector.payload == null ? 1F :
+            docScorer.computePayloadFactor(docID(), spans.startPosition(), spans.endPosition(), payloadCollector.payload);
+        payloadScore = function.currentScore(docID(), term.field(), spans.startPosition(), spans.endPosition(),
+                                             payloadsSeen, payloadScore, payloadFactor);
+        payloadsSeen++;
+
       }
 
       /**

Added: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/SpanNearPayloadCheckQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/SpanNearPayloadCheckQuery.java?rev=1680205&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/SpanNearPayloadCheckQuery.java (added)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/SpanNearPayloadCheckQuery.java Tue May 19 09:02:38 2015
@@ -0,0 +1,125 @@
+package org.apache.lucene.search.payloads;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.spans.FilterSpans.AcceptStatus;
+import org.apache.lucene.search.spans.SpanNearQuery;
+import org.apache.lucene.search.spans.SpanPositionCheckQuery;
+import org.apache.lucene.search.spans.SpanWeight;
+import org.apache.lucene.search.spans.Spans;
+import org.apache.lucene.util.ToStringUtils;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Objects;
+
+
+/**
+ * Only return those matches that have a specific payload at
+ * the given position.
+ */
+public class SpanNearPayloadCheckQuery extends SpanPositionCheckQuery {
+
+  protected final Collection<byte[]> payloadToMatch;
+  protected final PayloadSpanCollector payloadCollector = new PayloadSpanCollector();
+
+  /**
+   * @param match          The underlying {@link org.apache.lucene.search.spans.SpanQuery} to check
+   * @param payloadToMatch The {@link java.util.Collection} of payloads to match
+   */
+  public SpanNearPayloadCheckQuery(SpanNearQuery match, Collection<byte[]> payloadToMatch) {
+    super(match);
+    this.payloadToMatch = Objects.requireNonNull(payloadToMatch);
+  }
+
+  @Override
+  public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
+    return new SpanWeight(this, searcher, payloadCollector);
+  }
+
+  @Override
+  protected AcceptStatus acceptPosition(Spans spans) throws IOException {
+
+    payloadCollector.reset();
+    spans.collect(payloadCollector);
+
+    Collection<byte[]> candidate = payloadCollector.getPayloads();
+    if (candidate.size() == payloadToMatch.size()) {
+      //TODO: check the byte arrays are the same
+      //hmm, can't rely on order here
+      int matches = 0;
+      for (byte[] candBytes : candidate) {
+        //Unfortunately, we can't rely on order, so we need to compare all
+        for (byte[] payBytes : payloadToMatch) {
+          if (Arrays.equals(candBytes, payBytes) == true) {
+            matches++;
+            break;
+          }
+        }
+      }
+      if (matches == payloadToMatch.size()){
+        //we've verified all the bytes
+        return AcceptStatus.YES;
+      } else {
+        return AcceptStatus.NO;
+      }
+    } else {
+      return AcceptStatus.NO;
+    }
+
+  }
+
+  @Override
+  public String toString(String field) {
+    StringBuilder buffer = new StringBuilder();
+    buffer.append("spanPayCheck(");
+    buffer.append(match.toString(field));
+    buffer.append(", payloadRef: ");
+    for (byte[] bytes : payloadToMatch) {
+      ToStringUtils.byteArray(buffer, bytes);
+      buffer.append(';');
+    }
+    buffer.append(")");
+    buffer.append(ToStringUtils.boost(getBoost()));
+    return buffer.toString();
+  }
+
+  @Override
+  public SpanNearPayloadCheckQuery clone() {
+    SpanNearPayloadCheckQuery result = new SpanNearPayloadCheckQuery((SpanNearQuery) match.clone(), payloadToMatch);
+    result.setBoost(getBoost());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (! super.equals(o)) {
+      return false;
+    }
+    SpanNearPayloadCheckQuery other = (SpanNearPayloadCheckQuery) o;
+    return this.payloadToMatch.equals(other.payloadToMatch);
+  }
+
+  @Override
+  public int hashCode() {
+    int h = super.hashCode();
+    h = (h * 15) ^ payloadToMatch.hashCode();
+    return h;
+  }
+}
\ No newline at end of file

Added: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/SpanPayloadCheckQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/SpanPayloadCheckQuery.java?rev=1680205&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/SpanPayloadCheckQuery.java (added)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/payloads/SpanPayloadCheckQuery.java Tue May 19 09:02:38 2015
@@ -0,0 +1,128 @@
+package org.apache.lucene.search.payloads;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.payloads.PayloadSpanCollector;
+import org.apache.lucene.search.spans.FilterSpans.AcceptStatus;
+import org.apache.lucene.search.spans.SpanNearQuery;
+import org.apache.lucene.search.spans.SpanPositionCheckQuery;
+import org.apache.lucene.search.spans.SpanQuery;
+import org.apache.lucene.search.spans.SpanWeight;
+import org.apache.lucene.search.spans.Spans;
+import org.apache.lucene.util.ToStringUtils;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+
+
+/**
+ * Only return those matches that have a specific payload at
+ * the given position.
+ * <p>
+ * Do not use this with a SpanQuery that contains a {@link org.apache.lucene.search.spans.SpanNearQuery}.
+ * Instead, use {@link org.apache.lucene.search.payloads.SpanNearPayloadCheckQuery} since it properly handles the fact that payloads
+ * aren't ordered by {@link org.apache.lucene.search.spans.SpanNearQuery}.
+ */
+public class SpanPayloadCheckQuery extends SpanPositionCheckQuery {
+
+  protected final Collection<byte[]> payloadToMatch;
+  protected final PayloadSpanCollector payloadCollector = new PayloadSpanCollector();
+
+  /**
+   * @param match The underlying {@link org.apache.lucene.search.spans.SpanQuery} to check
+   * @param payloadToMatch The {@link java.util.Collection} of payloads to match
+   */
+  public SpanPayloadCheckQuery(SpanQuery match, Collection<byte[]> payloadToMatch) {
+    super(match);
+    if (match instanceof SpanNearQuery){
+      throw new IllegalArgumentException("SpanNearQuery not allowed");
+    }
+    this.payloadToMatch = payloadToMatch;
+  }
+
+  @Override
+  public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
+    return new SpanWeight(this, searcher, payloadCollector);
+  }
+
+  @Override
+  protected AcceptStatus acceptPosition(Spans spans) throws IOException {
+
+    payloadCollector.reset();
+    spans.collect(payloadCollector);
+
+    Collection<byte[]> candidate = payloadCollector.getPayloads();
+    if (candidate.size() == payloadToMatch.size()){
+      //TODO: check the byte arrays are the same
+      Iterator<byte[]> toMatchIter = payloadToMatch.iterator();
+      //check each of the byte arrays, in order
+      //hmm, can't rely on order here
+      for (byte[] candBytes : candidate) {
+        //if one is a mismatch, then return false
+        if (Arrays.equals(candBytes, toMatchIter.next()) == false){
+          return AcceptStatus.NO;
+        }
+      }
+      //we've verified all the bytes
+      return AcceptStatus.YES;
+    } else {
+      return AcceptStatus.NO;
+    }
+
+  }
+
+  @Override
+  public String toString(String field) {
+    StringBuilder buffer = new StringBuilder();
+    buffer.append("spanPayCheck(");
+    buffer.append(match.toString(field));
+    buffer.append(", payloadRef: ");
+    for (byte[] bytes : payloadToMatch) {
+      ToStringUtils.byteArray(buffer, bytes);
+      buffer.append(';');
+    }
+    buffer.append(")");
+    buffer.append(ToStringUtils.boost(getBoost()));
+    return buffer.toString();
+  }
+
+  @Override
+  public SpanPayloadCheckQuery clone() {
+    SpanPayloadCheckQuery result = new SpanPayloadCheckQuery((SpanQuery) match.clone(), payloadToMatch);
+    result.setBoost(getBoost());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (! super.equals(o)) {
+      return false;
+    }
+    SpanPayloadCheckQuery other = (SpanPayloadCheckQuery)o;
+    return this.payloadToMatch.equals(other.payloadToMatch);
+  }
+
+  @Override
+  public int hashCode() {
+    int h = super.hashCode();
+    h = (h * 63) ^ payloadToMatch.hashCode();
+    return h;
+  }
+}
\ No newline at end of file

Added: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/BufferedSpanCollector.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/BufferedSpanCollector.java?rev=1680205&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/BufferedSpanCollector.java (added)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/BufferedSpanCollector.java Tue May 19 09:02:38 2015
@@ -0,0 +1,67 @@
+package org.apache.lucene.search.spans;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.IOException;
+
+/**
+ * Defines span collection for eager Span implementations, such as
+ * {@link org.apache.lucene.search.spans.NearSpansOrdered}
+ *
+ * @lucene.experimental
+ */
+public interface BufferedSpanCollector {
+
+  /**
+   * Collect information from a possible candidate
+   * @param spans the candidate Spans
+   * @throws IOException on error
+   */
+  public void collectCandidate(Spans spans) throws IOException;
+
+  /**
+   * Confirm that the last candidate Spans has been accepted by the parent algorithm
+   */
+  public void accept();
+
+  /**
+   * Replay buffered information back to the parent SpanCollector
+   */
+  public void replay();
+
+  /**
+   * A default No-op BufferedSpanCollector
+   */
+  public static final BufferedSpanCollector NO_OP = new BufferedSpanCollector() {
+    @Override
+    public void collectCandidate(Spans spans) throws IOException {
+
+    }
+
+    @Override
+    public void accept() {
+
+    }
+
+    @Override
+    public void replay() {
+
+    }
+  };
+
+}

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/ContainSpans.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/ContainSpans.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/ContainSpans.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/ContainSpans.java Tue May 19 09:02:38 2015
@@ -19,7 +19,6 @@ package org.apache.lucene.search.spans;
 
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Objects;
 
 abstract class ContainSpans extends ConjunctionSpans {
@@ -49,12 +48,8 @@ abstract class ContainSpans extends Conj
   }
 
   @Override
-  public boolean isPayloadAvailable() throws IOException {
-    return sourceSpans.isPayloadAvailable();
+  public void collect(SpanCollector collector) throws IOException {
+    sourceSpans.collect(collector);
   }
 
-  @Override
-  public Collection<byte[]> getPayload() throws IOException {
-    return sourceSpans.getPayload();
-  }
 }

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java Tue May 19 09:02:38 2015
@@ -17,21 +17,20 @@ package org.apache.lucene.search.spans;
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
-import java.util.Objects;
-
-import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermContext;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.search.Weight;
 import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.ToStringUtils;
 
+import java.io.IOException;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
 /**
  * <p>Wrapper to allow {@link SpanQuery} objects participate in composite 
  * single-field SpanQueries by 'lying' about their search field. That is, 
@@ -97,8 +96,8 @@ public class FieldMaskingSpanQuery exten
   // ...this is done to be more consistent with things like SpanFirstQuery
   
   @Override
-  public Spans getSpans(LeafReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts) throws IOException {
-    return maskedQuery.getSpans(context, acceptDocs, termContexts);
+  public Spans getSpans(LeafReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts, SpanCollector collector) throws IOException {
+    return maskedQuery.getSpans(context, acceptDocs, termContexts, collector);
   }
 
   @Override

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/FilterSpans.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/FilterSpans.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/FilterSpans.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/FilterSpans.java Tue May 19 09:02:38 2015
@@ -17,12 +17,11 @@ package org.apache.lucene.search.spans;
  * limitations under the License.
  */
 
+import org.apache.lucene.search.TwoPhaseIterator;
+
 import java.io.IOException;
-import java.util.Collection;
 import java.util.Objects;
 
-import org.apache.lucene.search.TwoPhaseIterator;
-
 /**
  * A {@link Spans} implementation wrapping another spans instance,
  * allowing to filter spans matches easily by implementing {@link #accept}
@@ -110,17 +109,12 @@ public abstract class FilterSpans extend
     return atFirstInCurrentDoc ? -1
           : (startPos != NO_MORE_POSITIONS) ? in.endPosition() : NO_MORE_POSITIONS;
   }
-  
-  @Override
-  public final Collection<byte[]> getPayload() throws IOException {
-    return in.getPayload();
-  }
 
   @Override
-  public final boolean isPayloadAvailable() throws IOException {
-    return in.isPayloadAvailable();
+  public void collect(SpanCollector collector) throws IOException {
+    in.collect(collector);
   }
-  
+
   @Override
   public final long cost() {
     return in.cost();

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/NearSpansOrdered.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/NearSpansOrdered.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/NearSpansOrdered.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/NearSpansOrdered.java Tue May 19 09:02:38 2015
@@ -19,12 +19,9 @@ package org.apache.lucene.search.spans;
 
 import java.io.IOException;
 import java.util.List;
-import java.util.Collection;
 
 /** A Spans that is formed from the ordered subspans of a SpanNearQuery
- * where the subspans do not overlap and have a maximum slop between them,
- * and that does not need to collect payloads.
- * To also collect payloads, see {@link NearSpansPayloadOrdered}.
+ * where the subspans do not overlap and have a maximum slop between them.
  * <p>
  * The formed spans only contains minimum slop matches.<br>
  * The matching slop is computed from the distance(s) between
@@ -41,6 +38,9 @@ import java.util.Collection;
  * <pre>t1 t2 .. t3      </pre>
  * <pre>      t1 .. t2 t3</pre>
  *
+ * Because the algorithm used to minimize the size of a match consumes
+ * child Spans eagerly, this uses a BufferedSpanCollector to collect
+ * information from subspans.
  *
  * Expert:
  * Only public for subclassing.  Most implementations should not need this class
@@ -51,9 +51,13 @@ public class NearSpansOrdered extends Ne
   protected int matchStart = -1;
   protected int matchEnd = -1;
 
-  public NearSpansOrdered(SpanNearQuery query, List<Spans> subSpans) throws IOException {
+  protected final SpanCollector collector;
+  protected BufferedSpanCollector buffer;
+
+  public NearSpansOrdered(SpanNearQuery query, List<Spans> subSpans, SpanCollector collector) throws IOException {
     super(query, subSpans);
     this.atFirstInCurrentDoc = true; // -1 startPosition/endPosition also at doc -1
+    this.collector = collector;
   }
 
   @Override
@@ -140,10 +144,15 @@ public class NearSpansOrdered extends Ne
     matchStart = lastSubSpans.startPosition();
     matchEnd = lastSubSpans.endPosition();
 
+    buffer = collector.buffer();
+    buffer.collectCandidate(subSpans[subSpans.length - 1]);
+    buffer.accept();
+
     int matchSlop = 0;
     int lastStart = matchStart;
     for (int i = subSpans.length - 2; i >= 0; i--) {
       Spans prevSpans = subSpans[i];
+      buffer.collectCandidate(prevSpans);
 
       int prevStart = prevSpans.startPosition();
       int prevEnd = prevSpans.endPosition();
@@ -160,8 +169,11 @@ public class NearSpansOrdered extends Ne
         // prevSpans still before (lastStart, lastEnd)
         prevStart = ppStart;
         prevEnd = ppEnd;
+        buffer.collectCandidate(prevSpans);
       }
 
+      buffer.accept();
+
       assert prevStart <= matchStart;
       if (matchStart > prevEnd) { // Only non overlapping spans add to slop.
         matchSlop += (matchStart - prevEnd);
@@ -190,13 +202,10 @@ public class NearSpansOrdered extends Ne
   }
 
   @Override
-  public Collection<byte[]> getPayload() throws IOException {
-    return null;
-  }
-
-  @Override
-  public boolean isPayloadAvailable() {
-    return false;
+  public void collect(SpanCollector collector) {
+    assert collector == this.collector
+        : "You must collect using the same SpanCollector as was passed to the NearSpans constructor";
+    buffer.replay();
   }
 
   @Override

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/NearSpansUnordered.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/NearSpansUnordered.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/NearSpansUnordered.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/NearSpansUnordered.java Tue May 19 09:02:38 2015
@@ -22,10 +22,7 @@ import org.apache.lucene.util.PriorityQu
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
-import java.util.Set;
-import java.util.HashSet;
 
 /**
  * Similar to {@link NearSpansOrdered}, but for the unordered case.
@@ -118,13 +115,8 @@ public class NearSpansUnordered extends
     }
 
     @Override
-    public Collection<byte[]> getPayload() throws IOException {
-      return in.getPayload();
-    }
-
-    @Override
-    public boolean isPayloadAvailable() throws IOException {
-      return in.isPayloadAvailable();
+    public void collect(SpanCollector collector) throws IOException {
+      in.collect(collector);
     }
 
     @Override
@@ -249,31 +241,11 @@ public class NearSpansUnordered extends
           : maxEndPositionCell.endPosition();
   }
 
-
-  /**
-   * WARNING: The List is not necessarily in order of the positions.
-   * @return Collection of <code>byte[]</code> payloads
-   * @throws IOException if there is a low-level I/O error
-   */
   @Override
-  public Collection<byte[]> getPayload() throws IOException {
-    Set<byte[]> matchPayload = new HashSet<>();
+  public void collect(SpanCollector collector) throws IOException {
     for (SpansCell cell : subSpanCells) {
-      if (cell.isPayloadAvailable()) {
-        matchPayload.addAll(cell.getPayload());
-      }
-    }
-    return matchPayload;
-  }
-
-  @Override
-  public boolean isPayloadAvailable() throws IOException {
-    for (SpansCell cell : subSpanCells) {
-      if (cell.isPayloadAvailable()) {
-        return true;
-      }
+      cell.collect(collector);
     }
-    return false;
   }
 
   @Override

Added: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanCollector.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanCollector.java?rev=1680205&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanCollector.java (added)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanCollector.java Tue May 19 09:02:38 2015
@@ -0,0 +1,110 @@
+package org.apache.lucene.search.spans;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.lucene.index.PostingsEnum;
+import org.apache.lucene.index.Term;
+
+import java.io.IOException;
+
+/**
+ * An interface defining the collection of postings information from the leaves
+ * of a {@link org.apache.lucene.search.spans.Spans}
+ *
+ * Typical use would be as follows:
+ * <pre>
+ *   while (spans.nextStartPosition() != NO_MORE_POSITIONS) {
+ *     spanCollector.reset();
+ *     spans.collect(spanCollector);
+ *     doSomethingWith(spanCollector);
+ *   }
+ * </pre>
+ *
+ * @lucene.experimental
+ */
+public interface SpanCollector {
+
+  /**
+   * Called to indicate that the driving {@link org.apache.lucene.search.spans.Spans} has
+   * been moved to a new position
+   */
+  public void reset();
+
+  /**
+   * Returns an integer indicating what postings information should be retrieved
+   *
+   * See {@link org.apache.lucene.index.TermsEnum#postings(org.apache.lucene.util.Bits, org.apache.lucene.index.PostingsEnum, int)}
+   *
+   * @return the postings flag
+   */
+  public int requiredPostings();
+
+  /**
+   * Collect information from postings
+   * @param postings a {@link PostingsEnum}
+   * @param term     the {@link Term} for this postings list
+   * @throws IOException on error
+   */
+  public void collectLeaf(PostingsEnum postings, Term term) throws IOException;
+
+  /**
+   * Return a {@link BufferedSpanCollector} for use by eager spans implementations, such
+   * as {@link NearSpansOrdered}.
+   *
+   * @return a BufferedSpanCollector
+   */
+  public BufferedSpanCollector buffer();
+
+  /**
+   * @return the SpanCollector used by the {@link org.apache.lucene.search.spans.BufferedSpanCollector}
+   *          returned from {@link #buffer()}.
+   */
+  public SpanCollector bufferedCollector();
+
+  /**
+   * A default No-op implementation of SpanCollector
+   */
+  public static final SpanCollector NO_OP = new SpanCollector() {
+
+    @Override
+    public void reset() {
+
+    }
+
+    @Override
+    public int requiredPostings() {
+      return PostingsEnum.POSITIONS;
+    }
+
+    @Override
+    public void collectLeaf(PostingsEnum postings, Term term) {
+
+    }
+
+    @Override
+    public BufferedSpanCollector buffer() {
+      return BufferedSpanCollector.NO_OP;
+    }
+
+    @Override
+    public SpanCollector bufferedCollector() {
+      return this;
+    }
+  };
+
+}

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainQuery.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainQuery.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainQuery.java Tue May 19 09:02:38 2015
@@ -17,19 +17,19 @@ package org.apache.lucene.search.spans;
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.Set;
-import java.util.Objects;
-
-import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermContext;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.util.Bits;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
 abstract class SpanContainQuery extends SpanQuery implements Cloneable {
   SpanQuery big;
   SpanQuery little;
@@ -55,12 +55,12 @@ abstract class SpanContainQuery extends
     little.extractTerms(terms);
   }
 
-  ArrayList<Spans> prepareConjunction(final LeafReaderContext context, final Bits acceptDocs, final Map<Term,TermContext> termContexts) throws IOException {
-    Spans bigSpans = big.getSpans(context, acceptDocs, termContexts);
+  ArrayList<Spans> prepareConjunction(final LeafReaderContext context, final Bits acceptDocs, final Map<Term,TermContext> termContexts, SpanCollector collector) throws IOException {
+    Spans bigSpans = big.getSpans(context, acceptDocs, termContexts, collector);
     if (bigSpans == null) {
       return null;
     }
-    Spans littleSpans = little.getSpans(context, acceptDocs, termContexts);
+    Spans littleSpans = little.getSpans(context, acceptDocs, termContexts, collector);
     if (littleSpans == null) {
       return null;
     }

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainingQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainingQuery.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainingQuery.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainingQuery.java Tue May 19 09:02:38 2015
@@ -17,15 +17,15 @@ package org.apache.lucene.search.spans;
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.Map;
-import java.util.ArrayList;
-
 import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.index.TermContext;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermContext;
 import org.apache.lucene.util.Bits;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Map;
+
 /** Keep matches that contain another Spans. */
 public class SpanContainingQuery extends SpanContainQuery {
   /** Construct a SpanContainingQuery matching spans from <code>big</code>
@@ -54,8 +54,8 @@ public class SpanContainingQuery extends
    * The payload is from the spans of <code>big</code>.
    */
   @Override
-  public Spans getSpans(final LeafReaderContext context, final Bits acceptDocs, final Map<Term,TermContext> termContexts) throws IOException {
-    ArrayList<Spans> containerContained = prepareConjunction(context, acceptDocs, termContexts);
+  public Spans getSpans(final LeafReaderContext context, final Bits acceptDocs, final Map<Term,TermContext> termContexts, SpanCollector collector) throws IOException {
+    ArrayList<Spans> containerContained = prepareConjunction(context, acceptDocs, termContexts, collector);
     if (containerContained == null) {
       return null;
     }

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java Tue May 19 09:02:38 2015
@@ -17,22 +17,22 @@ package org.apache.lucene.search.spans;
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
-import java.util.Objects;
-
-import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermContext;
+import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.lucene.search.MultiTermQuery;
 import org.apache.lucene.search.Query;
-import org.apache.lucene.search.TopTermsRewrite;
 import org.apache.lucene.search.ScoringRewrite;
-import org.apache.lucene.search.BooleanClause.Occur; // javadocs only
+import org.apache.lucene.search.TopTermsRewrite;
 import org.apache.lucene.util.Bits;
 
+import java.io.IOException;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
 /**
  * Wraps any {@link MultiTermQuery} as a {@link SpanQuery}, 
  * so it can be nested within other SpanQuery classes.
@@ -99,7 +99,7 @@ public class SpanMultiTermQueryWrapper<Q
   }
   
   @Override
-  public Spans getSpans(LeafReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts) throws IOException {
+  public Spans getSpans(LeafReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts, SpanCollector collector) throws IOException {
     throw new UnsupportedOperationException("Query should have been rewritten");
   }
 

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java Tue May 19 09:02:38 2015
@@ -17,15 +17,8 @@ package org.apache.lucene.search.spans;
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermContext;
 import org.apache.lucene.index.Terms;
@@ -33,6 +26,13 @@ import org.apache.lucene.search.Query;
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.ToStringUtils;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 /** Matches spans which are near one another.  One can specify <i>slop</i>, the
  * maximum number of intervening unmatched positions, as well as whether
  * matches are required to be in-order.
@@ -118,11 +118,17 @@ public class SpanNearQuery extends SpanQ
   }
 
   @Override
-  public Spans getSpans(final LeafReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts) throws IOException {
-    ArrayList<Spans> subSpans = new ArrayList<>(clauses.size());
+  public Spans getSpans(final LeafReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts, SpanCollector collector) throws IOException {
 
+    Terms terms = context.reader().terms(field);
+    if (terms == null) {
+      return null; // field does not exist
+    }
+
+    ArrayList<Spans> subSpans = new ArrayList<>(clauses.size());
+    SpanCollector subSpanCollector = inOrder ? collector.bufferedCollector() : collector;
     for (SpanQuery seq : clauses) {
-      Spans subSpan = seq.getSpans(context, acceptDocs, termContexts);
+      Spans subSpan = seq.getSpans(context, acceptDocs, termContexts, subSpanCollector);
       if (subSpan != null) {
         subSpans.add(subSpan);
       } else {
@@ -130,15 +136,9 @@ public class SpanNearQuery extends SpanQ
       }
     }
 
-    Terms terms = context.reader().terms(field);
-    if (terms == null) {
-      return null; // field does not exist
-    }
     
     // all NearSpans require at least two subSpans
-    return (! inOrder) ? new NearSpansUnordered(this, subSpans)
-          : collectPayloads && terms.hasPayloads() ? new NearSpansPayloadOrdered(this, subSpans)
-          : new NearSpansOrdered(this, subSpans);
+    return (! inOrder) ? new NearSpansUnordered(this, subSpans) : new NearSpansOrdered(this, subSpans, collector);
   }
 
   @Override

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java Tue May 19 09:02:38 2015
@@ -105,13 +105,13 @@ public class SpanNotQuery extends SpanQu
   }
 
   @Override
-  public Spans getSpans(final LeafReaderContext context, final Bits acceptDocs, final Map<Term,TermContext> termContexts) throws IOException {
-    Spans includeSpans = include.getSpans(context, acceptDocs, termContexts);
+  public Spans getSpans(final LeafReaderContext context, final Bits acceptDocs, final Map<Term,TermContext> termContexts, SpanCollector collector) throws IOException {
+    Spans includeSpans = include.getSpans(context, acceptDocs, termContexts, collector);
     if (includeSpans == null) {
       return null;
     }
 
-    Spans excludeSpans = exclude.getSpans(context, acceptDocs, termContexts);
+    Spans excludeSpans = exclude.getSpans(context, acceptDocs, termContexts, collector);
     if (excludeSpans == null) {
       return includeSpans;
     }

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java Tue May 19 09:02:38 2015
@@ -17,26 +17,24 @@ package org.apache.lucene.search.spans;
  * limitations under the License.
  */
 
-import java.io.IOException;
-
-import java.util.List;
-import java.util.Collection;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermContext;
-import org.apache.lucene.util.Bits;
-import org.apache.lucene.util.ToStringUtils;
-import org.apache.lucene.search.Query;
 import org.apache.lucene.search.DisiPriorityQueue;
 import org.apache.lucene.search.DisiWrapper;
-import org.apache.lucene.search.TwoPhaseIterator;
 import org.apache.lucene.search.DisjunctionDISIApproximation;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TwoPhaseIterator;
+import org.apache.lucene.util.Bits;
+import org.apache.lucene.util.ToStringUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 
 /** Matches the union of its clauses.
@@ -147,13 +145,13 @@ public class SpanOrQuery extends SpanQue
 
 
   @Override
-  public Spans getSpans(final LeafReaderContext context, final Bits acceptDocs, final Map<Term,TermContext> termContexts)
+  public Spans getSpans(final LeafReaderContext context, final Bits acceptDocs, final Map<Term,TermContext> termContexts, SpanCollector collector)
   throws IOException {
 
     ArrayList<Spans> subSpans = new ArrayList<>(clauses.size());
 
     for (SpanQuery sq : clauses) {
-      Spans spans = sq.getSpans(context, acceptDocs, termContexts);
+      Spans spans = sq.getSpans(context, acceptDocs, termContexts, collector);
       if (spans != null) {
         subSpans.add(spans);
       }
@@ -306,17 +304,9 @@ public class SpanOrQuery extends SpanQue
       }
 
       @Override
-      public Collection<byte[]> getPayload() throws IOException {
-        return topPositionSpans == null
-                ? null
-                : topPositionSpans.isPayloadAvailable()
-                ? new ArrayList<>(topPositionSpans.getPayload())
-                : null;
-      }
-
-      @Override
-      public boolean isPayloadAvailable() throws IOException {
-        return (topPositionSpans != null) && topPositionSpans.isPayloadAvailable();
+      public void collect(SpanCollector collector) throws IOException {
+        if (topPositionSpans != null)
+          topPositionSpans.collect(collector);
       }
 
       @Override

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java Tue May 19 09:02:38 2015
@@ -77,8 +77,8 @@ public abstract class SpanPositionCheckQ
   protected abstract AcceptStatus acceptPosition(Spans spans) throws IOException;
 
   @Override
-  public Spans getSpans(final LeafReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts) throws IOException {
-    Spans matchSpans = match.getSpans(context, acceptDocs, termContexts);
+  public Spans getSpans(final LeafReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts, SpanCollector collector) throws IOException {
+    Spans matchSpans = match.getSpans(context, acceptDocs, termContexts, collector);
     return (matchSpans == null) ? null : new FilterSpans(matchSpans) {
       @Override
       protected AcceptStatus accept(Spans candidate) throws IOException {

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanQuery.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanQuery.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanQuery.java Tue May 19 09:02:38 2015
@@ -17,10 +17,6 @@ package org.apache.lucene.search.spans;
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
-
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermContext;
@@ -29,13 +25,17 @@ import org.apache.lucene.search.Query;
 import org.apache.lucene.search.Weight;
 import org.apache.lucene.util.Bits;
 
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
 /** Base class for span-based queries. */
 public abstract class SpanQuery extends Query {
   /** Expert: Returns the matches for this query in an index.  
    *  Used internally to search for spans.
    *  This may return null to indicate that the SpanQuery has no results.
    */
-  public abstract Spans getSpans(LeafReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts) throws IOException;
+  public abstract Spans getSpans(LeafReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts, SpanCollector collector) throws IOException;
 
   /**
    * Extract terms from these spans.
@@ -53,7 +53,7 @@ public abstract class SpanQuery extends
 
   @Override
   public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
-    return new SpanWeight(this, searcher);
+    return new SpanWeight(this, searcher, SpanCollector.NO_OP);
   }
 
 }

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanTermQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanTermQuery.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanTermQuery.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanTermQuery.java Tue May 19 09:02:38 2015
@@ -17,13 +17,8 @@ package org.apache.lucene.search.spans;
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
-import java.util.Objects;
-
-import org.apache.lucene.index.PostingsEnum;
 import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.PostingsEnum;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermContext;
 import org.apache.lucene.index.TermState;
@@ -32,6 +27,11 @@ import org.apache.lucene.index.TermsEnum
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.ToStringUtils;
 
+import java.io.IOException;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
 /** Matches spans containing a term.
  * This should not be used for terms that are indexed at position Integer.MAX_VALUE.
  */
@@ -83,7 +83,7 @@ public class SpanTermQuery extends SpanQ
   }
 
   @Override
-  public Spans getSpans(final LeafReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts) throws IOException {
+  public Spans getSpans(final LeafReaderContext context, Bits acceptDocs, Map<Term,TermContext> termContexts, SpanCollector collector) throws IOException {
     TermContext termContext = termContexts.get(term);
     final TermState state;
     if (termContext == null) {
@@ -115,7 +115,7 @@ public class SpanTermQuery extends SpanQ
     final TermsEnum termsEnum = context.reader().terms(term.field()).iterator();
     termsEnum.seekExact(term.bytes(), state);
 
-    final PostingsEnum postings = termsEnum.postings(acceptDocs, null, PostingsEnum.PAYLOADS);
+    final PostingsEnum postings = termsEnum.postings(acceptDocs, null, collector.requiredPostings());
     return new TermSpans(postings, term);
   }
 }

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanWeight.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanWeight.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanWeight.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanWeight.java Tue May 19 09:02:38 2015
@@ -17,12 +17,6 @@ package org.apache.lucene.search.spans;
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
 import org.apache.lucene.index.IndexReaderContext;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
@@ -37,6 +31,12 @@ import org.apache.lucene.search.similari
 import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.util.Bits;
 
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
 /**
  * Expert-only.  Public for use by other weight implementations
  */
@@ -44,12 +44,14 @@ public class SpanWeight extends Weight {
   protected final Similarity similarity;
   protected final Map<Term,TermContext> termContexts;
   protected final SpanQuery query;
+  protected final SpanCollector collector;
   protected Similarity.SimWeight stats;
 
-  public SpanWeight(SpanQuery query, IndexSearcher searcher) throws IOException {
+  public SpanWeight(SpanQuery query, IndexSearcher searcher, SpanCollector collector) throws IOException {
     super(query);
     this.similarity = searcher.getSimilarity();
     this.query = query;
+    this.collector = collector;
 
     termContexts = new HashMap<>();
     TreeSet<Term> terms = new TreeSet<>();
@@ -97,7 +99,7 @@ public class SpanWeight extends Weight {
     if (terms != null && terms.hasPositions() == false) {
       throw new IllegalStateException("field \"" + query.getField() + "\" was indexed without position data; cannot run SpanQuery (query=" + query + ")");
     }
-    Spans spans = query.getSpans(context, acceptDocs, termContexts);
+    Spans spans = query.getSpans(context, acceptDocs, termContexts, collector);
     return (spans == null) ? null : new SpanScorer(spans, this, similarity.simScorer(stats, context));
   }
 

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanWithinQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanWithinQuery.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanWithinQuery.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/SpanWithinQuery.java Tue May 19 09:02:38 2015
@@ -17,15 +17,15 @@ package org.apache.lucene.search.spans;
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.Map;
-import java.util.ArrayList;
-
 import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.index.TermContext;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermContext;
 import org.apache.lucene.util.Bits;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Map;
+
 /** Keep matches that are contained within another Spans. */
 public class SpanWithinQuery extends SpanContainQuery {
   /** Construct a SpanWithinQuery matching spans from <code>little</code>
@@ -54,8 +54,8 @@ public class SpanWithinQuery extends Spa
    * The payload is from the spans of <code>little</code>.
    */
   @Override
-  public Spans getSpans(final LeafReaderContext context, final Bits acceptDocs, final Map<Term,TermContext> termContexts) throws IOException {
-    ArrayList<Spans> containerContained = prepareConjunction(context, acceptDocs, termContexts);
+  public Spans getSpans(final LeafReaderContext context, final Bits acceptDocs, final Map<Term,TermContext> termContexts, SpanCollector collector) throws IOException {
+    ArrayList<Spans> containerContained = prepareConjunction(context, acceptDocs, termContexts, collector);
     if (containerContained == null) {
       return null;
     }

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/Spans.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/Spans.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/Spans.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/Spans.java Tue May 19 09:02:38 2015
@@ -17,12 +17,11 @@ package org.apache.lucene.search.spans;
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.Collection;
-
 import org.apache.lucene.search.DocIdSetIterator;
 import org.apache.lucene.search.TwoPhaseIterator;
 
+import java.io.IOException;
+
 /** Iterates through combinations of start/end positions per-doc.
  *  Each start/end position represents a range of term positions within the current document.
  *  These are enumerated in order, by increasing document number, within that by
@@ -51,33 +50,12 @@ public abstract class Spans extends DocI
   public abstract int endPosition();
 
   /**
-   * Returns the payload data for the current start/end position.
-   * This is only valid after {@link #nextStartPosition()}
-   * returned an available start position.
-   * This method must not be called more than once after each call
-   * of {@link #nextStartPosition()}. However, most payloads are loaded lazily,
-   * so if the payload data for the current position is not needed,
-   * this method may not be called at all for performance reasons.
-   * <br>
-   * Note that the return type is a collection, thus the ordering should not be relied upon.
-   * <br>
-   * @lucene.experimental
-   *
-   * @return a List of byte arrays containing the data of this payload, otherwise null if isPayloadAvailable is false
-   * @throws IOException if there is a low-level I/O error
-   */
-  public abstract Collection<byte[]> getPayload() throws IOException;
-
-  /**
-   * Checks if a payload can be loaded at the current start/end position.
-   * <p>
-   * Payloads can only be loaded once per call to
-   * {@link #nextStartPosition()}.
+   * Collect data from the current Spans
+   * @param collector a SpanCollector
    *
-   * @return true if there is a payload available at this start/end position
-   *              that can be loaded
+   * @lucene.experimental
    */
-  public abstract boolean isPayloadAvailable() throws IOException;
+  public abstract void collect(SpanCollector collector) throws IOException;
 
   /**
    * Optional method: Return a {@link TwoPhaseIterator} view of this

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/TermSpans.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/TermSpans.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/TermSpans.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/spans/TermSpans.java Tue May 19 09:02:38 2015
@@ -16,14 +16,11 @@ package org.apache.lucene.search.spans;
  */
 
 
-import org.apache.lucene.index.Term;
 import org.apache.lucene.index.PostingsEnum;
+import org.apache.lucene.index.Term;
 import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.util.BytesRef;
 
 import java.io.IOException;
-import java.util.Collections;
-import java.util.Collection;
 import java.util.Objects;
 
 /**
@@ -109,6 +106,7 @@ public class TermSpans extends Spans {
     return postings.cost();
   }
 
+  /*
   @Override
   public Collection<byte[]> getPayload() throws IOException {
     final BytesRef payload = postings.getPayload();
@@ -127,6 +125,12 @@ public class TermSpans extends Spans {
   public boolean isPayloadAvailable() throws IOException {
     return readPayload == false && postings.getPayload() != null;
   }
+  */
+
+  @Override
+  public void collect(SpanCollector collector) throws IOException {
+    collector.collectLeaf(postings, term);
+  }
 
   @Override
   public String toString() {

Modified: lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestPositionIncrement.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestPositionIncrement.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestPositionIncrement.java (original)
+++ lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestPositionIncrement.java Tue May 19 09:02:38 2015
@@ -17,34 +17,37 @@ package org.apache.lucene.search;
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.io.StringReader;
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-
-import org.apache.lucene.analysis.*;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.MockPayloadAnalyzer;
+import org.apache.lucene.analysis.Tokenizer;
+import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
 import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
 import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
-import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
 import org.apache.lucene.document.TextField;
+import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReader;
 import org.apache.lucene.index.MultiFields;
 import org.apache.lucene.index.PostingsEnum;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.RandomIndexWriter;
 import org.apache.lucene.index.SlowCompositeReaderWrapper;
 import org.apache.lucene.index.Term;
-import org.apache.lucene.store.Directory;
+import org.apache.lucene.search.payloads.PayloadSpanCollector;
 import org.apache.lucene.search.payloads.PayloadSpanUtil;
 import org.apache.lucene.search.spans.MultiSpansWrapper;
 import org.apache.lucene.search.spans.SpanNearQuery;
 import org.apache.lucene.search.spans.SpanQuery;
 import org.apache.lucene.search.spans.SpanTermQuery;
 import org.apache.lucene.search.spans.Spans;
-import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.store.Directory;
 import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.LuceneTestCase;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
 
 /**
  * Term position unit test.
@@ -53,7 +56,7 @@ import org.apache.lucene.util.BytesRef;
  */
 public class TestPositionIncrement extends LuceneTestCase {
 
-  final static boolean VERBOSE = false;
+  final static boolean VERBOSE = true;
 
   public void testSetPosition() throws Exception {
     Analyzer analyzer = new Analyzer() {
@@ -238,14 +241,17 @@ public class TestPositionIncrement exten
     if (VERBOSE) {
       System.out.println("\ngetPayloadSpans test");
     }
-    Spans pspans = MultiSpansWrapper.wrap(is.getIndexReader(), snq);
+    PayloadSpanCollector collector = new PayloadSpanCollector();
+    Spans pspans = MultiSpansWrapper.wrap(is.getIndexReader(), snq, collector);
     while (pspans.nextDoc() != Spans.NO_MORE_DOCS) {
       while (pspans.nextStartPosition() != Spans.NO_MORE_POSITIONS) {
         if (VERBOSE) {
           System.out.println("doc " + pspans.docID() + ": span " + pspans.startPosition()
               + " to " + pspans.endPosition());
         }
-        Collection<byte[]> payloads = pspans.getPayload();
+        collector.reset();
+        pspans.collect(collector);
+        Collection<byte[]> payloads = collector.getPayloads();
         sawZero |= pspans.startPosition() == 0;
         for (byte[] bytes : payloads) {
           count++;
@@ -256,7 +262,7 @@ public class TestPositionIncrement exten
       }
     }
     assertTrue(sawZero);
-    assertEquals(5, count);
+    assertEquals(8, count);
 
     // System.out.println("\ngetSpans test");
     Spans spans = MultiSpansWrapper.wrap(is.getIndexReader(), snq);
@@ -282,7 +288,7 @@ public class TestPositionIncrement exten
       //System.out.println(s);
       sawZero |= s.equals("pos: 0");
     }
-    assertEquals(5, count);
+    assertEquals(8, count);
     assertTrue(sawZero);
     writer.close();
     is.getIndexReader().close();

Modified: lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/payloads/TestPayloadBasics.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/payloads/TestPayloadBasics.java?rev=1680205&r1=1680204&r2=1680205&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/payloads/TestPayloadBasics.java (original)
+++ lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/payloads/TestPayloadBasics.java Tue May 19 09:02:38 2015
@@ -17,13 +17,6 @@ package org.apache.lucene.search.payload
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.analysis.MockTokenizer;
 import org.apache.lucene.analysis.SimplePayloadFilter;
@@ -36,9 +29,7 @@ import org.apache.lucene.index.Term;
 import org.apache.lucene.search.CheckHits;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
-import org.apache.lucene.search.spans.SpanNearPayloadCheckQuery;
 import org.apache.lucene.search.spans.SpanNearQuery;
-import org.apache.lucene.search.spans.SpanPayloadCheckQuery;
 import org.apache.lucene.search.spans.SpanPositionRangeQuery;
 import org.apache.lucene.search.spans.SpanQuery;
 import org.apache.lucene.search.spans.SpanTermQuery;
@@ -50,6 +41,13 @@ import org.apache.lucene.util.TestUtil;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
 /** basic test of payload-spans */
 public class TestPayloadBasics extends LuceneTestCase {
   private static IndexSearcher searcher;