You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by jp...@apache.org on 2015/02/17 10:03:31 UTC

svn commit: r1660325 - in /lucene/dev/branches/branch_5x: ./ lucene/ lucene/core/ lucene/core/src/java/org/apache/lucene/search/ lucene/core/src/test/org/apache/lucene/search/

Author: jpountz
Date: Tue Feb 17 09:03:30 2015
New Revision: 1660325

URL: http://svn.apache.org/r1660325
Log:
LUCENE-6251: Add two-phase support to ConstantScorer and most boolean scorers.

Modified:
    lucene/dev/branches/branch_5x/   (props changed)
    lucene/dev/branches/branch_5x/lucene/   (props changed)
    lucene/dev/branches/branch_5x/lucene/CHANGES.txt   (contents, props changed)
    lucene/dev/branches/branch_5x/lucene/core/   (props changed)
    lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/BooleanTopLevelScorers.java
    lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java
    lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ReqExclScorer.java
    lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ReqOptSumScorer.java
    lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestApproximationSearchEquivalence.java
    lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java
    lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java

Modified: lucene/dev/branches/branch_5x/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/lucene/CHANGES.txt?rev=1660325&r1=1660324&r2=1660325&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/lucene/CHANGES.txt (original)
+++ lucene/dev/branches/branch_5x/lucene/CHANGES.txt Tue Feb 17 09:03:30 2015
@@ -57,8 +57,9 @@ Optimizations
   positions lazily if the phrase query is in a conjunction with other queries.
   (Robert Muir, Adrien Grand)
 
-* LUCENE-6244: Pure disjunctions now propagate two-phase iterators of the
-  wrapped scorers (see LUCENE-6198). (Adrien Grand, Robert Muir)
+* LUCENE-6244, LUCENE-6251: All boolean queries but those that have a
+  minShouldMatch > 1 now either propagate or take advantage of the two-phase
+  iteration capabilities added in LUCENE-6198. (Adrien Grand, Robert Muir)
 
 * LUCENE-6241: FSDirectory.listAll() doesnt filter out subdirectories anymore,
   for faster performance. Subdirectories don't matter to Lucene. If you need to

Modified: lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/BooleanTopLevelScorers.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/BooleanTopLevelScorers.java?rev=1660325&r1=1660324&r2=1660325&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/BooleanTopLevelScorers.java (original)
+++ lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/BooleanTopLevelScorers.java Tue Feb 17 09:03:30 2015
@@ -39,6 +39,11 @@ class BooleanTopLevelScorers {
     }
 
     @Override
+    public TwoPhaseDocIdSetIterator asTwoPhaseIterator() {
+      return in.asTwoPhaseIterator();
+    }
+
+    @Override
     public float score() throws IOException {
       return in.score() * boost;
     }

Modified: lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java?rev=1660325&r1=1660324&r2=1660325&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java (original)
+++ lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java Tue Feb 17 09:03:30 2015
@@ -184,6 +184,11 @@ public class ConstantScoreQuery extends
     }
 
     @Override
+    public TwoPhaseDocIdSetIterator asTwoPhaseIterator() {
+      return in.asTwoPhaseIterator();
+    }
+
+    @Override
     public int freq() throws IOException {
       return 1;
     }

Modified: lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ReqExclScorer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ReqExclScorer.java?rev=1660325&r1=1660324&r2=1660325&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ReqExclScorer.java (original)
+++ lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ReqExclScorer.java Tue Feb 17 09:03:30 2015
@@ -22,77 +22,88 @@ import java.util.Collection;
 import java.util.Collections;
 
 /** A Scorer for queries with a required subscorer
- * and an excluding (prohibited) sub DocIdSetIterator.
+ * and an excluding (prohibited) sub {@link Scorer}.
  * <br>
  * This <code>Scorer</code> implements {@link Scorer#advance(int)},
- * and it uses the skipTo() on the given scorers.
+ * and it uses the advance() on the given scorers.
  */
 class ReqExclScorer extends FilterScorer {
-  private Scorer reqScorer;
-  private DocIdSetIterator exclDisi;
-  private int doc = -1;
+
+  private final Scorer reqScorer;
+  // approximations of the scorers, or the scorers themselves if they don't support approximations
+  private final DocIdSetIterator reqApproximation;
+  private final DocIdSetIterator exclApproximation;
+  // two-phase views of the scorers, or null if they do not support approximations
+  private final TwoPhaseDocIdSetIterator reqTwoPhaseIterator;
+  private final TwoPhaseDocIdSetIterator exclTwoPhaseIterator;
 
   /** Construct a <code>ReqExclScorer</code>.
    * @param reqScorer The scorer that must match, except where
-   * @param exclDisi indicates exclusion.
+   * @param exclScorer indicates exclusion.
    */
-  public ReqExclScorer(Scorer reqScorer, DocIdSetIterator exclDisi) {
+  public ReqExclScorer(Scorer reqScorer, Scorer exclScorer) {
     super(reqScorer);
     this.reqScorer = reqScorer;
-    this.exclDisi = exclDisi;
+    reqTwoPhaseIterator = reqScorer.asTwoPhaseIterator();
+    if (reqTwoPhaseIterator == null) {
+      reqApproximation = reqScorer;
+    } else {
+      reqApproximation = reqTwoPhaseIterator.approximation();
+    }
+    exclTwoPhaseIterator = exclScorer.asTwoPhaseIterator();
+    if (exclTwoPhaseIterator == null) {
+      exclApproximation = exclScorer;
+    } else {
+      exclApproximation = exclTwoPhaseIterator.approximation();
+    }
   }
 
   @Override
   public int nextDoc() throws IOException {
-    if (reqScorer == null) {
-      return doc;
-    }
-    doc = reqScorer.nextDoc();
-    if (doc == NO_MORE_DOCS) {
-      reqScorer = null; // exhausted, nothing left
-      return doc;
-    }
-    if (exclDisi == null) {
-      return doc;
-    }
-    return doc = toNonExcluded();
+    return toNonExcluded(reqApproximation.nextDoc());
   }
-  
-  /** Advance to non excluded doc.
-   * <br>On entry:
-   * <ul>
-   * <li>reqScorer != null,
-   * <li>exclScorer != null,
-   * <li>reqScorer was advanced once via next() or skipTo()
-   *      and reqScorer.doc() may still be excluded.
-   * </ul>
-   * Advances reqScorer a non excluded required doc, if any.
-   * @return true iff there is a non excluded required doc.
-   */
-  private int toNonExcluded() throws IOException {
-    int exclDoc = exclDisi.docID();
-    int reqDoc = reqScorer.docID(); // may be excluded
-    do {  
-      if (reqDoc < exclDoc) {
-        return reqDoc; // reqScorer advanced to before exclScorer, ie. not excluded
-      } else if (reqDoc > exclDoc) {
-        exclDoc = exclDisi.advance(reqDoc);
-        if (exclDoc == NO_MORE_DOCS) {
-          exclDisi = null; // exhausted, no more exclusions
-          return reqDoc;
-        }
-        if (exclDoc > reqDoc) {
-          return reqDoc; // not excluded
-        }
+
+  /** Confirms whether or not the given {@link TwoPhaseDocIdSetIterator}
+   *  matches on the current document. */
+  private static boolean matches(TwoPhaseDocIdSetIterator it) throws IOException {
+    return it == null || it.matches();
+  }
+
+  /** Confirm whether there is a match given the current positions of the
+   *  req and excl approximations. This method has 2 important properties:
+   *   - it only calls matches() on excl if the excl approximation is on
+   *     the same doc ID as the req approximation
+   *   - it does NOT call matches() on req if the excl approximation is exact
+   *     and is on the same doc ID as the req approximation */
+  private static boolean matches(int doc, int exclDoc,
+      TwoPhaseDocIdSetIterator reqTwoPhaseIterator,
+      TwoPhaseDocIdSetIterator exclTwoPhaseIterator) throws IOException {
+    assert exclDoc >= doc;
+    if (doc == exclDoc && matches(exclTwoPhaseIterator)) {
+      return false;
+    }
+    return matches(reqTwoPhaseIterator);
+  }
+
+  /** Advance to the next non-excluded doc. */
+  private int toNonExcluded(int doc) throws IOException {
+    int exclDoc = exclApproximation.docID();
+    for (;; doc = reqApproximation.nextDoc()) {
+      if (doc == NO_MORE_DOCS) {
+        return NO_MORE_DOCS;
+      }
+      if (exclDoc < doc) {
+        exclDoc = exclApproximation.advance(doc);
+      }
+      if (matches(doc, exclDoc, reqTwoPhaseIterator, exclTwoPhaseIterator)) {
+        return doc;
       }
-    } while ((reqDoc = reqScorer.nextDoc()) != NO_MORE_DOCS);
-    reqScorer = null; // exhausted, nothing left
-    return NO_MORE_DOCS;
+    }
   }
 
   @Override
   public int docID() {
-    return doc;
+    return reqScorer.docID();
   }
 
   /** Returns the score of the current document matching the query.
@@ -111,17 +122,32 @@ class ReqExclScorer extends FilterScorer
 
   @Override
   public int advance(int target) throws IOException {
-    if (reqScorer == null) {
-      return doc = NO_MORE_DOCS;
-    }
-    if (exclDisi == null) {
-      return doc = reqScorer.advance(target);
-    }
-    if (reqScorer.advance(target) == NO_MORE_DOCS) {
-      reqScorer = null;
-      return doc = NO_MORE_DOCS;
-    }
-    return doc = toNonExcluded();
+    return toNonExcluded(reqApproximation.advance(target));
   }
 
+  @Override
+  public TwoPhaseDocIdSetIterator asTwoPhaseIterator() {
+    if (reqTwoPhaseIterator == null) {
+      return null;
+    }
+    return new TwoPhaseDocIdSetIterator() {
+
+      @Override
+      public DocIdSetIterator approximation() {
+        return reqApproximation;
+      }
+
+      @Override
+      public boolean matches() throws IOException {
+        final int doc = reqApproximation.docID();
+        // check if the doc is not excluded
+        int exclDoc = exclApproximation.docID();
+        if (exclDoc < doc) {
+          exclDoc = exclApproximation.advance(doc);
+        }
+        return ReqExclScorer.matches(doc, exclDoc, reqTwoPhaseIterator, exclTwoPhaseIterator);
+      }
+
+    };
+  }
 }

Modified: lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ReqOptSumScorer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ReqOptSumScorer.java?rev=1660325&r1=1660324&r2=1660325&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ReqOptSumScorer.java (original)
+++ lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/ReqOptSumScorer.java Tue Feb 17 09:03:30 2015
@@ -31,7 +31,7 @@ class ReqOptSumScorer extends Scorer {
   /** The scorers passed from the constructor.
    * These are set to null as soon as their next() or skipTo() returns false.
    */
-  protected Scorer reqScorer;
+  protected final Scorer reqScorer;
   protected Scorer optScorer;
 
   /** Construct a <code>ReqOptScorer</code>.
@@ -50,6 +50,11 @@ class ReqOptSumScorer extends Scorer {
   }
 
   @Override
+  public TwoPhaseDocIdSetIterator asTwoPhaseIterator() {
+    return reqScorer.asTwoPhaseIterator();
+  }
+
+  @Override
   public int nextDoc() throws IOException {
     return reqScorer.nextDoc();
   }

Modified: lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestApproximationSearchEquivalence.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestApproximationSearchEquivalence.java?rev=1660325&r1=1660324&r2=1660325&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestApproximationSearchEquivalence.java (original)
+++ lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestApproximationSearchEquivalence.java Tue Feb 17 09:03:30 2015
@@ -166,4 +166,116 @@ public class TestApproximationSearchEqui
 
     assertSameScores(bq2, bq4);
   }
+
+  public void testConstantScore() throws Exception {
+    Term t1 = randomTerm();
+    Term t2 = randomTerm();
+    TermQuery q1 = new TermQuery(t1);
+    TermQuery q2 = new TermQuery(t2);
+
+    BooleanQuery bq1 = new BooleanQuery();
+    bq1.add(new ConstantScoreQuery(q1), Occur.MUST);
+    bq1.add(new ConstantScoreQuery(q2), Occur.MUST);
+
+    BooleanQuery bq2 = new BooleanQuery();
+    bq2.add(new ConstantScoreQuery(new RandomApproximationQuery(q1, random())), Occur.MUST);
+    bq2.add(new ConstantScoreQuery(new RandomApproximationQuery(q2, random())), Occur.MUST);
+
+    assertSameScores(bq1, bq2);
+  }
+
+  public void testExclusion() throws Exception {
+    Term t1 = randomTerm();
+    Term t2 = randomTerm();
+    TermQuery q1 = new TermQuery(t1);
+    TermQuery q2 = new TermQuery(t2);
+
+    BooleanQuery bq1 = new BooleanQuery();
+    bq1.add(q1, Occur.MUST);
+    bq1.add(q2, Occur.MUST_NOT);
+
+    BooleanQuery bq2 = new BooleanQuery();
+    bq2.add(new RandomApproximationQuery(q1, random()), Occur.MUST);
+    bq2.add(new RandomApproximationQuery(q2, random()), Occur.MUST_NOT);
+
+    assertSameScores(bq1, bq2);
+  }
+
+  public void testNestedExclusion() throws Exception {
+    Term t1 = randomTerm();
+    Term t2 = randomTerm();
+    Term t3 = randomTerm();
+    TermQuery q1 = new TermQuery(t1);
+    TermQuery q2 = new TermQuery(t2);
+    TermQuery q3 = new TermQuery(t3);
+
+    BooleanQuery bq1 = new BooleanQuery();
+    bq1.add(q1, Occur.MUST);
+    bq1.add(q2, Occur.MUST_NOT);
+
+    BooleanQuery bq2 = new BooleanQuery();
+    bq2.add(bq1, Occur.MUST);
+    bq2.add(q3, Occur.MUST);
+
+    // Both req and excl have approximations
+    BooleanQuery bq3 = new BooleanQuery();
+    bq3.add(new RandomApproximationQuery(q1, random()), Occur.MUST);
+    bq3.add(new RandomApproximationQuery(q2, random()), Occur.MUST_NOT);
+
+    BooleanQuery bq4 = new BooleanQuery();
+    bq4.add(bq3, Occur.MUST);
+    bq4.add(q3, Occur.MUST);
+
+    assertSameScores(bq2, bq4);
+
+    // Only req has an approximation
+    bq3 = new BooleanQuery();
+    bq3.add(new RandomApproximationQuery(q1, random()), Occur.MUST);
+    bq3.add(q2, Occur.MUST_NOT);
+
+    bq4 = new BooleanQuery();
+    bq4.add(bq3, Occur.MUST);
+    bq4.add(q3, Occur.MUST);
+
+    assertSameScores(bq2, bq4);
+
+    // Only excl has an approximation
+    bq3 = new BooleanQuery();
+    bq3.add(q1, Occur.MUST);
+    bq3.add(new RandomApproximationQuery(q2, random()), Occur.MUST_NOT);
+
+    bq4 = new BooleanQuery();
+    bq4.add(bq3, Occur.MUST);
+    bq4.add(q3, Occur.MUST);
+
+    assertSameScores(bq2, bq4);
+  }
+
+  public void testReqOpt() throws Exception {
+    Term t1 = randomTerm();
+    Term t2 = randomTerm();
+    Term t3 = randomTerm();
+    TermQuery q1 = new TermQuery(t1);
+    TermQuery q2 = new TermQuery(t2);
+    TermQuery q3 = new TermQuery(t3);
+
+    BooleanQuery bq1 = new BooleanQuery();
+    bq1.add(q1, Occur.MUST);
+    bq1.add(q2, Occur.SHOULD);
+
+    BooleanQuery bq2 = new BooleanQuery();
+    bq2.add(bq1, Occur.MUST);
+    bq2.add(q3, Occur.MUST);
+    
+    BooleanQuery bq3 = new BooleanQuery();
+    bq3.add(new RandomApproximationQuery(q1, random()), Occur.MUST);
+    bq3.add(new RandomApproximationQuery(q2, random()), Occur.SHOULD);
+
+    BooleanQuery bq4 = new BooleanQuery();
+    bq4.add(bq3, Occur.MUST);
+    bq4.add(q3, Occur.MUST);
+
+    assertSameScores(bq2, bq4);
+  }
+
 }

Modified: lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java?rev=1660325&r1=1660324&r2=1660325&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java (original)
+++ lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java Tue Feb 17 09:03:30 2015
@@ -41,6 +41,7 @@ import org.apache.lucene.index.MultiRead
 import org.apache.lucene.index.RandomIndexWriter;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.BooleanClause.Occur;
+import org.apache.lucene.search.BooleanTopLevelScorers.BoostedScorer;
 import org.apache.lucene.search.similarities.DefaultSimilarity;
 import org.apache.lucene.search.spans.SpanQuery;
 import org.apache.lucene.search.spans.SpanTermQuery;
@@ -613,6 +614,7 @@ public class TestBooleanQuery extends Lu
 
     final Weight weight = searcher.createNormalizedWeight(q, random().nextBoolean());
     final Scorer scorer = weight.scorer(reader.leaves().get(0), null);
+    assertTrue(scorer instanceof ConjunctionScorer);
     assertNotNull(scorer.asTwoPhaseIterator());
 
     reader.close();
@@ -642,6 +644,97 @@ public class TestBooleanQuery extends Lu
 
     final Weight weight = searcher.createNormalizedWeight(q, random().nextBoolean());
     final Scorer scorer = weight.scorer(reader.leaves().get(0), null);
+    assertTrue(scorer instanceof DisjunctionScorer);
+    assertNotNull(scorer.asTwoPhaseIterator());
+
+    reader.close();
+    w.close();
+    dir.close();
+  }
+
+  public void testBoostedScorerPropagatesApproximations() throws IOException {
+    Directory dir = newDirectory();
+    RandomIndexWriter w = new RandomIndexWriter(random(), dir);
+    Document doc = new Document();
+    Field f = newTextField("field", "a b c", Field.Store.NO);
+    doc.add(f);
+    w.addDocument(doc);
+    w.commit();
+
+    DirectoryReader reader = w.getReader();
+    final IndexSearcher searcher = new IndexSearcher(reader);
+
+    PhraseQuery pq = new PhraseQuery();
+    pq.add(new Term("field", "a"));
+    pq.add(new Term("field", "b"));
+
+    BooleanQuery q = new BooleanQuery();
+    q.add(pq, Occur.SHOULD);
+    q.add(new TermQuery(new Term("field", "d")), Occur.SHOULD);
+
+    final Weight weight = searcher.createNormalizedWeight(q, random().nextBoolean());
+    final Scorer scorer = weight.scorer(reader.leaves().get(0), null);
+    assertTrue(scorer instanceof BoostedScorer);
+    assertNotNull(scorer.asTwoPhaseIterator());
+
+    reader.close();
+    w.close();
+    dir.close();
+  }
+
+  public void testExclusionPropagatesApproximations() throws IOException {
+    Directory dir = newDirectory();
+    RandomIndexWriter w = new RandomIndexWriter(random(), dir);
+    Document doc = new Document();
+    Field f = newTextField("field", "a b c", Field.Store.NO);
+    doc.add(f);
+    w.addDocument(doc);
+    w.commit();
+
+    DirectoryReader reader = w.getReader();
+    final IndexSearcher searcher = new IndexSearcher(reader);
+
+    PhraseQuery pq = new PhraseQuery();
+    pq.add(new Term("field", "a"));
+    pq.add(new Term("field", "b"));
+
+    BooleanQuery q = new BooleanQuery();
+    q.add(pq, Occur.SHOULD);
+    q.add(new TermQuery(new Term("field", "c")), Occur.MUST_NOT);
+
+    final Weight weight = searcher.createNormalizedWeight(q, random().nextBoolean());
+    final Scorer scorer = weight.scorer(reader.leaves().get(0), null);
+    assertTrue(scorer instanceof ReqExclScorer);
+    assertNotNull(scorer.asTwoPhaseIterator());
+
+    reader.close();
+    w.close();
+    dir.close();
+  }
+
+  public void testReqOptPropagatesApproximations() throws IOException {
+    Directory dir = newDirectory();
+    RandomIndexWriter w = new RandomIndexWriter(random(), dir);
+    Document doc = new Document();
+    Field f = newTextField("field", "a b c", Field.Store.NO);
+    doc.add(f);
+    w.addDocument(doc);
+    w.commit();
+
+    DirectoryReader reader = w.getReader();
+    final IndexSearcher searcher = new IndexSearcher(reader);
+
+    PhraseQuery pq = new PhraseQuery();
+    pq.add(new Term("field", "a"));
+    pq.add(new Term("field", "b"));
+
+    BooleanQuery q = new BooleanQuery();
+    q.add(pq, Occur.MUST);
+    q.add(new TermQuery(new Term("field", "c")), Occur.SHOULD);
+
+    final Weight weight = searcher.createNormalizedWeight(q, true);
+    final Scorer scorer = weight.scorer(reader.leaves().get(0), null);
+    assertTrue(scorer instanceof ReqOptSumScorer);
     assertNotNull(scorer.asTwoPhaseIterator());
 
     reader.close();

Modified: lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java?rev=1660325&r1=1660324&r2=1660325&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java (original)
+++ lucene/dev/branches/branch_5x/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java Tue Feb 17 09:03:30 2015
@@ -21,9 +21,11 @@ import java.io.IOException;
 
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
+import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.RandomIndexWriter;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.lucene.search.similarities.DefaultSimilarity;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.util.LuceneTestCase;
@@ -179,4 +181,30 @@ public class TestConstantScoreQuery exte
     d.close();
   }
 
+  public void testPropagatesApproximations() throws IOException {
+    Directory dir = newDirectory();
+    RandomIndexWriter w = new RandomIndexWriter(random(), dir);
+    Document doc = new Document();
+    Field f = newTextField("field", "a b", Field.Store.NO);
+    doc.add(f);
+    w.addDocument(doc);
+    w.commit();
+
+    DirectoryReader reader = w.getReader();
+    final IndexSearcher searcher = new IndexSearcher(reader);
+
+    PhraseQuery pq = new PhraseQuery();
+    pq.add(new Term("field", "a"));
+    pq.add(new Term("field", "b"));
+
+    ConstantScoreQuery q = new ConstantScoreQuery(pq);
+
+    final Weight weight = searcher.createNormalizedWeight(q, true);
+    final Scorer scorer = weight.scorer(reader.leaves().get(0), null);
+    assertNotNull(scorer.asTwoPhaseIterator());
+
+    reader.close();
+    w.close();
+    dir.close();
+  }
 }