You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-commits@lucene.apache.org by mi...@apache.org on 2009/07/27 11:50:02 UTC

svn commit: r798086 - in /lucene/java/trunk: ./ contrib/miscellaneous/src/java/org/apache/lucene/misc/ src/java/org/apache/lucene/analysis/ src/java/org/apache/lucene/index/ src/java/org/apache/lucene/search/ src/java/org/apache/lucene/search/function/...

Author: mikemccand
Date: Mon Jul 27 09:50:02 2009
New Revision: 798086

URL: http://svn.apache.org/viewvc?rev=798086&view=rev
Log:
LUCENE-1754: BooleanQuery detects up front if it won't match any docs and returns null from its scorer() instead of NonMatchingScorer

Modified:
    lucene/java/trunk/CHANGES.txt
    lucene/java/trunk/contrib/miscellaneous/src/java/org/apache/lucene/misc/ChainedFilter.java
    lucene/java/trunk/src/java/org/apache/lucene/analysis/Analyzer.java
    lucene/java/trunk/src/java/org/apache/lucene/index/DocumentsWriter.java
    lucene/java/trunk/src/java/org/apache/lucene/search/BooleanQuery.java
    lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer2.java
    lucene/java/trunk/src/java/org/apache/lucene/search/CachingWrapperFilter.java
    lucene/java/trunk/src/java/org/apache/lucene/search/ConstantScoreQuery.java
    lucene/java/trunk/src/java/org/apache/lucene/search/DocIdSet.java
    lucene/java/trunk/src/java/org/apache/lucene/search/Filter.java
    lucene/java/trunk/src/java/org/apache/lucene/search/FilteredQuery.java
    lucene/java/trunk/src/java/org/apache/lucene/search/IndexSearcher.java
    lucene/java/trunk/src/java/org/apache/lucene/search/MultiPhraseQuery.java
    lucene/java/trunk/src/java/org/apache/lucene/search/NonMatchingScorer.java
    lucene/java/trunk/src/java/org/apache/lucene/search/PhraseQuery.java
    lucene/java/trunk/src/java/org/apache/lucene/search/QueryWeight.java
    lucene/java/trunk/src/java/org/apache/lucene/search/function/CustomScoreQuery.java
    lucene/java/trunk/src/test/org/apache/lucene/search/QueryUtils.java
    lucene/java/trunk/src/test/org/apache/lucene/search/TestDocIdSet.java

Modified: lucene/java/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/java/trunk/CHANGES.txt?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/CHANGES.txt (original)
+++ lucene/java/trunk/CHANGES.txt Mon Jul 27 09:50:02 2009
@@ -337,6 +337,16 @@
     made public as expert, experimental APIs.  These APIs may suddenly
     change from release to release (Jason Rutherglen via Mike
     McCandless).
+    
+32. LUCENE-1754: QueryWeight.scorer() can return null if no documents
+    are going to be matched by the query. Similarly,
+    Filter.getDocIdSet() can return null if no documents are going to
+    be accepted by the Filter. Note that these 'can' return null,
+    however they don't have to and can return a Scorer/DocIdSet which
+    does not match / reject all documents.  This is already the
+    behavior of some QueryWeight/Filter implementations, and is
+    documented here just for emphasis. (Shai Erera via Mike
+    McCandless)
 
 Bug fixes
 
@@ -663,6 +673,11 @@
     Removes conversions between Set and array.
     (Simon Willnauer via Mark Miller)
 
+11. LUCENE-1754: BooleanQuery.queryWeight.scorer() will return null if
+    it won't match any documents (e.g. if there are no required and
+    optional scorers, or not enough optional scorers to satisfy
+    minShouldMatch).  (Shai Erera via Mike McCandless)
+
 Documentation
 
 Build

Modified: lucene/java/trunk/contrib/miscellaneous/src/java/org/apache/lucene/misc/ChainedFilter.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/miscellaneous/src/java/org/apache/lucene/misc/ChainedFilter.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/contrib/miscellaneous/src/java/org/apache/lucene/misc/ChainedFilter.java (original)
+++ lucene/java/trunk/contrib/miscellaneous/src/java/org/apache/lucene/misc/ChainedFilter.java Mon Jul 27 09:50:02 2009
@@ -60,6 +60,7 @@
 import java.io.IOException;
 import org.apache.lucene.search.DocIdSet;
 import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.search.EmptyDocIdSetIterator;
 import org.apache.lucene.util.OpenBitSet;
 import org.apache.lucene.util.OpenBitSetDISI;
 import org.apache.lucene.util.SortedVIntList;
@@ -146,9 +147,18 @@
     }
 
     private DocIdSetIterator getDISI(Filter filter, IndexReader reader)
-    throws IOException
-    {
-        return filter.getDocIdSet(reader).iterator();
+    throws IOException {
+        DocIdSet docIdSet = filter.getDocIdSet(reader);
+        if (docIdSet == null) {
+          return EmptyDocIdSetIterator.getInstance();
+        } else {
+          DocIdSetIterator iter = docIdSet.iterator();
+          if (iter == null) {
+            return EmptyDocIdSetIterator.getInstance();
+          } else {
+            return iter;
+          }
+        }
     }
 
     private OpenBitSetDISI initialResult(IndexReader reader, int logic, int[] index)
@@ -241,13 +251,11 @@
     }
 
     private void doChain(OpenBitSetDISI result, int logic, DocIdSet dis)
-    throws IOException
-    {
+    throws IOException {
       
       if (dis instanceof OpenBitSet) {
         // optimized case for OpenBitSets
-        switch (logic)
-        {
+        switch (logic) {
             case OR:
                 result.or((OpenBitSet) dis);
                 break;
@@ -265,9 +273,17 @@
                 break;
         }
       } else {
-        DocIdSetIterator disi = dis.iterator();      
-        switch (logic)
-        {
+        DocIdSetIterator disi;
+        if (dis == null) {
+          disi = EmptyDocIdSetIterator.getInstance();
+        } else {
+          disi = dis.iterator();
+          if (disi == null) {
+            disi = EmptyDocIdSetIterator.getInstance();            
+          }
+        }
+
+        switch (logic) {
             case OR:
                 result.inPlaceOr(disi);
                 break;

Modified: lucene/java/trunk/src/java/org/apache/lucene/analysis/Analyzer.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/analysis/Analyzer.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/analysis/Analyzer.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/analysis/Analyzer.java Mon Jul 27 09:50:02 2009
@@ -133,7 +133,7 @@
    * fields.  This method is only called if the field
    * produced at least one token for indexing.
    *
-   * @param Fieldable the field just indexed
+   * @param field the field just indexed
    * @return offset gap, added to the next token emitted from {@link #tokenStream(String,Reader)}
    */
   public int getOffsetGap(Fieldable field) {

Modified: lucene/java/trunk/src/java/org/apache/lucene/index/DocumentsWriter.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/DocumentsWriter.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/index/DocumentsWriter.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/index/DocumentsWriter.java Mon Jul 27 09:50:02 2009
@@ -1007,12 +1007,14 @@
       int limit = ((Integer) entry.getValue()).intValue();
       QueryWeight weight = query.queryWeight(searcher);
       Scorer scorer = weight.scorer(reader, true, false);
-      while(true)  {
-        int doc = scorer.nextDoc();
-        if (((long) docIDStart) + doc >= limit)
-          break;
-        reader.deleteDocument(doc);
-        any = true;
+      if (scorer != null) {
+        while(true)  {
+          int doc = scorer.nextDoc();
+          if (((long) docIDStart) + doc >= limit)
+            break;
+          reader.deleteDocument(doc);
+          any = true;
+        }
       }
     }
     searcher.close();

Modified: lucene/java/trunk/src/java/org/apache/lucene/search/BooleanQuery.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/BooleanQuery.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/BooleanQuery.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/BooleanQuery.java Mon Jul 27 09:50:02 2009
@@ -227,9 +227,12 @@
       float sum = 0.0f;
       boolean fail = false;
       int shouldMatchCount = 0;
-      for (int i = 0 ; i < weights.size(); i++) {
-        BooleanClause c = (BooleanClause)clauses.get(i);
-        QueryWeight w = (QueryWeight)weights.get(i);
+      for (Iterator wIter = weights.iterator(), cIter = clauses.iterator(); wIter.hasNext();) {
+        QueryWeight w = (QueryWeight) wIter.next();
+        BooleanClause c = (BooleanClause) cIter.next();
+        if (w.scorer(reader, true, true) == null) {
+          continue;
+        }
         Explanation e = w.explain(reader, doc);
         if (!c.isProhibited()) maxCoord++;
         if (e.isMatch()) {
@@ -244,7 +247,7 @@
             sumExpl.addDetail(r);
             fail = true;
           }
-          if (c.getOccur().equals(Occur.SHOULD))
+          if (c.getOccur() == Occur.SHOULD)
             shouldMatchCount++;
         } else if (c.isRequired()) {
           Explanation r = new Explanation(0.0f, "no match on required clause (" + c.getQuery().toString() + ")");
@@ -312,6 +315,16 @@
         return new BooleanScorer(similarity, minNrShouldMatch, optional, prohibited);
       }
       
+      if (required.size() == 0 && optional.size() == 0) {
+        // no required and optional clauses.
+        return null;
+      } else if (optional.size() < minNrShouldMatch) {
+        // either >1 req scorer, or there are 0 req scorers and at least 1
+        // optional scorer. Therefore if there are not enough optional scorers
+        // no documents will be matched by the query
+        return null;
+      }
+      
       // Return a BooleanScorer2
       return new BooleanScorer2(similarity, minNrShouldMatch, required, prohibited, optional);
     }

Modified: lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer2.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer2.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer2.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer2.java Mon Jul 27 09:50:02 2009
@@ -218,36 +218,26 @@
   }
 
   private Scorer makeCountingSumScorerNoReq() throws IOException { // No required scorers
-    if (optionalScorers.size() == 0) {
-      return new NonMatchingScorer(); // no clauses or only prohibited clauses
-    } else { // No required scorers. At least one optional scorer.
-      // minNrShouldMatch optional scorers are required, but at least 1
-      int nrOptRequired = (minNrShouldMatch < 1) ? 1 : minNrShouldMatch;
-      if (optionalScorers.size() < nrOptRequired) { 
-        return new NonMatchingScorer(); // fewer optional clauses than minimum (at least 1) that should match
-      } else { // optionalScorers.size() >= nrOptRequired, no required scorers
-        Scorer requiredCountingSumScorer =
-              (optionalScorers.size() > nrOptRequired)
-              ? countingDisjunctionSumScorer(optionalScorers, nrOptRequired)
-              : // optionalScorers.size() == nrOptRequired (all optional scorers are required), no required scorers
-              (optionalScorers.size() == 1)
-              ? new SingleMatchScorer((Scorer) optionalScorers.get(0))
-              : countingConjunctionSumScorer(optionalScorers);
-        return addProhibitedScorers(requiredCountingSumScorer);
-      }
-    }
+    // minNrShouldMatch optional scorers are required, but at least 1
+    int nrOptRequired = (minNrShouldMatch < 1) ? 1 : minNrShouldMatch;
+    Scorer requiredCountingSumScorer;
+    if (optionalScorers.size() > nrOptRequired)
+      requiredCountingSumScorer = countingDisjunctionSumScorer(optionalScorers, nrOptRequired);
+    else if (optionalScorers.size() == 1)
+      requiredCountingSumScorer = new SingleMatchScorer((Scorer) optionalScorers.get(0));
+    else
+      requiredCountingSumScorer = countingConjunctionSumScorer(optionalScorers);
+    return addProhibitedScorers(requiredCountingSumScorer);
   }
 
   private Scorer makeCountingSumScorerSomeReq() throws IOException { // At least one required scorer.
-    if (optionalScorers.size() < minNrShouldMatch) {
-      return new NonMatchingScorer(); // fewer optional clauses than minimum that should match
-    } else if (optionalScorers.size() == minNrShouldMatch) { // all optional scorers also required.
+    if (optionalScorers.size() == minNrShouldMatch) { // all optional scorers also required.
       ArrayList allReq = new ArrayList(requiredScorers);
       allReq.addAll(optionalScorers);
       return addProhibitedScorers(countingConjunctionSumScorer(allReq));
     } else { // optionalScorers.size() > minNrShouldMatch, and at least one required scorer
       Scorer requiredCountingSumScorer =
-            (requiredScorers.size() == 1)
+            requiredScorers.size() == 1
             ? new SingleMatchScorer((Scorer) requiredScorers.get(0))
             : countingConjunctionSumScorer(requiredScorers);
       if (minNrShouldMatch > 0) { // use a required disjunction scorer over the optional scorers
@@ -260,9 +250,10 @@
       } else { // minNrShouldMatch == 0
         return new ReqOptSumScorer(
                       addProhibitedScorers(requiredCountingSumScorer),
-                      ((optionalScorers.size() == 1)
+                      optionalScorers.size() == 1
                         ? new SingleMatchScorer((Scorer) optionalScorers.get(0))
-                        : countingDisjunctionSumScorer(optionalScorers, 1))); // require 1 in combined, optional scorer.
+                        // require 1 in combined, optional scorer.
+                        : countingDisjunctionSumScorer(optionalScorers, 1));
       }
     }
   }

Modified: lucene/java/trunk/src/java/org/apache/lucene/search/CachingWrapperFilter.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/CachingWrapperFilter.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/CachingWrapperFilter.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/CachingWrapperFilter.java Mon Jul 27 09:50:02 2009
@@ -100,12 +100,13 @@
 
     final DocIdSet docIdSet = docIdSetToCache(filter.getDocIdSet(reader), reader);
 
-    synchronized (cache) {  // update cache
-      cache.put(reader, docIdSet);
+    if (docIdSet != null) {
+      synchronized (cache) {  // update cache
+        cache.put(reader, docIdSet);
+      }
     }
 
     return docIdSet;
-    
   }
 
   public String toString() {

Modified: lucene/java/trunk/src/java/org/apache/lucene/search/ConstantScoreQuery.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/ConstantScoreQuery.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/ConstantScoreQuery.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/ConstantScoreQuery.java Mon Jul 27 09:50:02 2009
@@ -113,7 +113,17 @@
     public ConstantScorer(Similarity similarity, IndexReader reader, QueryWeight w) throws IOException {
       super(similarity);
       theScore = w.getValue();
-      docIdSetIterator = filter.getDocIdSet(reader).iterator();
+      DocIdSet docIdSet = filter.getDocIdSet(reader);
+      if (docIdSet == null) {
+        docIdSetIterator = EmptyDocIdSetIterator.getInstance();
+      } else {
+        DocIdSetIterator iter = docIdSet.iterator();
+        if (iter == null) {
+          docIdSetIterator = EmptyDocIdSetIterator.getInstance();
+        } else {
+          docIdSetIterator = iter;
+        }
+      }
     }
 
     /** @deprecated use {@link #nextDoc()} instead. */

Modified: lucene/java/trunk/src/java/org/apache/lucene/search/DocIdSet.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/DocIdSet.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/DocIdSet.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/DocIdSet.java Mon Jul 27 09:50:02 2009
@@ -30,6 +30,8 @@
    * implemented using a {@link SortedVIntList}). */
   public static final DocIdSet EMPTY_DOCIDSET = new SortedVIntList(new int[0]);
     
-  /** Provides a {@link DocIdSetIterator} to access the set. */
+  /** Provides a {@link DocIdSetIterator} to access the set.
+   * This may (but is not required to) return null if there
+   * are no docs that match. */
   public abstract DocIdSetIterator iterator() throws IOException;
 }

Modified: lucene/java/trunk/src/java/org/apache/lucene/search/Filter.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/Filter.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/Filter.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/Filter.java Mon Jul 27 09:50:02 2009
@@ -39,10 +39,12 @@
   public BitSet bits(IndexReader reader) throws IOException {
     throw new UnsupportedOperationException();
   }
-	
+
   /**
-   * @return a DocIdSet that provides the documents which should be
-   * permitted or prohibited in search results.
+   * @return a DocIdSet that provides the documents which should be permitted or
+   *         prohibited in search results. <b>NOTE:</b> null can be returned if
+   *         no documents will be accepted by this Filter.
+   * 
    * @see DocIdBitSet
    */
   public DocIdSet getDocIdSet(IndexReader reader) throws IOException {

Modified: lucene/java/trunk/src/java/org/apache/lucene/search/FilteredQuery.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/FilteredQuery.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/FilteredQuery.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/FilteredQuery.java Mon Jul 27 09:50:02 2009
@@ -82,7 +82,11 @@
           inner.addDetail(preBoost);
         }
         Filter f = FilteredQuery.this.filter;
-        DocIdSetIterator docIdSetIterator = f.getDocIdSet(ir).iterator();
+        DocIdSet docIdSet = f.getDocIdSet(ir);
+        DocIdSetIterator docIdSetIterator = docIdSet == null ? EmptyDocIdSetIterator.getInstance() : docIdSet.iterator();
+        if (docIdSetIterator == null) {
+          docIdSetIterator = EmptyDocIdSetIterator.getInstance();
+        }
         if (docIdSetIterator.advance(i) == i) {
           return inner;
         } else {
@@ -100,7 +104,17 @@
       public Scorer scorer(IndexReader indexReader, boolean scoreDocsInOrder, boolean topScorer)
           throws IOException {
         final Scorer scorer = weight.scorer(indexReader, scoreDocsInOrder, false);
-        final DocIdSetIterator docIdSetIterator = filter.getDocIdSet(indexReader).iterator();
+        if (scorer == null) {
+          return null;
+        }
+        DocIdSet docIdSet = filter.getDocIdSet(indexReader);
+        if (docIdSet == null) {
+          return null;
+        }
+        final DocIdSetIterator docIdSetIterator = docIdSet.iterator();
+        if (docIdSetIterator == null) {
+          return null;
+        }
 
         return new Scorer(similarity) {
 

Modified: lucene/java/trunk/src/java/org/apache/lucene/search/IndexSearcher.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/IndexSearcher.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/IndexSearcher.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/IndexSearcher.java Mon Jul 27 09:50:02 2009
@@ -267,8 +267,17 @@
     assert docID == -1 || docID == DocIdSetIterator.NO_MORE_DOCS;
 
     // CHECKME: use ConjunctionScorer here?
-    DocIdSetIterator filterIter = filter.getDocIdSet(reader).iterator();
+    DocIdSet filterDocIdSet = filter.getDocIdSet(reader);
+    if (filterDocIdSet == null) {
+      // this means the filter does not accept any documents.
+      return;
+    }
     
+    DocIdSetIterator filterIter = filterDocIdSet.iterator();
+    if (filterIter == null) {
+      // this means the filter does not accept any documents.
+      return;
+    }
     int filterDoc = filterIter.nextDoc();
     int scorerDoc = scorer.advance(filterDoc);
     

Modified: lucene/java/trunk/src/java/org/apache/lucene/search/MultiPhraseQuery.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/MultiPhraseQuery.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/MultiPhraseQuery.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/MultiPhraseQuery.java Mon Jul 27 09:50:02 2009
@@ -217,7 +217,11 @@
       fieldExpl.setDescription("fieldWeight("+getQuery()+" in "+doc+
                                "), product of:");
 
-      Explanation tfExpl = scorer(reader, true, false).explain(doc);
+      Scorer scorer = scorer(reader, true, false);
+      if (scorer == null) {
+        return new Explanation(0.0f, "no matching docs");
+      }
+      Explanation tfExpl = scorer.explain(doc);
       fieldExpl.addDetail(tfExpl);
       fieldExpl.addDetail(idfExpl);
 

Modified: lucene/java/trunk/src/java/org/apache/lucene/search/NonMatchingScorer.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/NonMatchingScorer.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/NonMatchingScorer.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/NonMatchingScorer.java Mon Jul 27 09:50:02 2009
@@ -1,50 +0,0 @@
-package org.apache.lucene.search;
-
-/**
- * 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;
-
-/** A scorer that matches no document at all. */
-class NonMatchingScorer extends Scorer {
-  public NonMatchingScorer() { super(null); } // no similarity used
-  
-  /** @deprecated use {@link #docID()} instead. */
-  public int doc() { throw new UnsupportedOperationException(); }
-  
-  public int docID() { return NO_MORE_DOCS; }
-
-  /** @deprecated use {@link #nextDoc()} instead. */
-  public boolean next() throws IOException { return false; }
-  
-  public int nextDoc() throws IOException { return NO_MORE_DOCS; }
-
-  public float score() { throw new UnsupportedOperationException(); }
-
-  /** @deprecated use {@link #advance(int)} instead. */
-  public boolean skipTo(int target) { return false; }
-  
-  public int advance(int target) { return NO_MORE_DOCS; }
-
-  public Explanation explain(int doc) {
-    Explanation e = new Explanation();
-    e.setDescription("No document matches.");
-    return e;
-  }
-}
- 
-

Modified: lucene/java/trunk/src/java/org/apache/lucene/search/PhraseQuery.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/PhraseQuery.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/PhraseQuery.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/PhraseQuery.java Mon Jul 27 09:50:02 2009
@@ -209,7 +209,11 @@
       fieldExpl.setDescription("fieldWeight("+field+":"+query+" in "+doc+
                                "), product of:");
 
-      Explanation tfExpl = scorer(reader, true, false).explain(doc);
+      Scorer scorer = scorer(reader, true, false);
+      if (scorer == null) {
+        return new Explanation(0.0f, "no matching docs");
+      }
+      Explanation tfExpl = scorer.explain(doc);
       fieldExpl.addDetail(tfExpl);
       fieldExpl.addDetail(idfExpl);
 

Modified: lucene/java/trunk/src/java/org/apache/lucene/search/QueryWeight.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/QueryWeight.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/QueryWeight.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/QueryWeight.java Mon Jul 27 09:50:02 2009
@@ -75,8 +75,11 @@
    * <p>
    * <b>NOTE:</b> even if <code>scoreDocsInOrder</code> is false, it is
    * recommended to check whether the returned <code>Scorer</code> indeed scores
-   * documents out of order (i.e., call {@link #scoresDocsOutOfOrder()}), as some
-   * <code>Scorer</code> implementations will always return documents in-order.
+   * documents out of order (i.e., call {@link #scoresDocsOutOfOrder()}), as
+   * some <code>Scorer</code> implementations will always return documents
+   * in-order.<br>
+   * <b>NOTE:</b> null can be returned if no documents will be scored by this
+   * query.
    * 
    * @param reader
    *          the {@link IndexReader} for which to return the {@link Scorer}.

Modified: lucene/java/trunk/src/java/org/apache/lucene/search/function/CustomScoreQuery.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/function/CustomScoreQuery.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/function/CustomScoreQuery.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/function/CustomScoreQuery.java Mon Jul 27 09:50:02 2009
@@ -331,6 +331,9 @@
       // false for "topScorer" because we will not invoke
       // score(Collector) on these scorers:
       Scorer subQueryScorer = subQueryWeight.scorer(reader, true, false);
+      if (subQueryScorer == null) {
+        return null;
+      }
       Scorer[] valSrcScorers = new Scorer[valSrcWeights.length];
       for(int i = 0; i < valSrcScorers.length; i++) {
          valSrcScorers[i] = valSrcWeights[i].scorer(reader, true, false);
@@ -339,7 +342,8 @@
     }
 
     public Explanation explain(IndexReader reader, int doc) throws IOException {
-      return scorer(reader, true, false).explain(doc);
+      Scorer scorer = scorer(reader, true, false);
+      return scorer == null ? new Explanation(0.0f, "no matching docs") : scorer.explain(doc);
     }
     
     public boolean scoresDocsOutOfOrder() {

Modified: lucene/java/trunk/src/test/org/apache/lucene/search/QueryUtils.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/test/org/apache/lucene/search/QueryUtils.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/test/org/apache/lucene/search/QueryUtils.java (original)
+++ lucene/java/trunk/src/test/org/apache/lucene/search/QueryUtils.java Mon Jul 27 09:50:02 2009
@@ -152,7 +152,10 @@
 
       final QueryWeight w = q.queryWeight(s);
       final Scorer scorer = w.scorer(s.getIndexReader(), true, false);
-      
+      if (scorer == null) {
+        continue;
+      }
+
       // FUTURE: ensure scorer.doc()==-1
 
       final int[] sdoc = new int[] {-1};
@@ -253,8 +256,10 @@
     });
     QueryWeight w = q.queryWeight(s);
     Scorer scorer = w.scorer(s.getIndexReader(), true, false);
-    boolean more = scorer.advance(lastDoc[0] + 1) != DocIdSetIterator.NO_MORE_DOCS;
-    if (more) 
-      Assert.assertFalse("query's last doc was "+lastDoc[0]+" but skipTo("+(lastDoc[0]+1)+") got to "+scorer.docID(),more);
+    if (scorer != null) {
+      boolean more = scorer.advance(lastDoc[0] + 1) != DocIdSetIterator.NO_MORE_DOCS;
+      if (more) 
+        Assert.assertFalse("query's last doc was "+lastDoc[0]+" but skipTo("+(lastDoc[0]+1)+") got to "+scorer.docID(),more);
+    }
   }
 }

Modified: lucene/java/trunk/src/test/org/apache/lucene/search/TestDocIdSet.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/test/org/apache/lucene/search/TestDocIdSet.java?rev=798086&r1=798085&r2=798086&view=diff
==============================================================================
--- lucene/java/trunk/src/test/org/apache/lucene/search/TestDocIdSet.java (original)
+++ lucene/java/trunk/src/test/org/apache/lucene/search/TestDocIdSet.java Mon Jul 27 09:50:02 2009
@@ -22,6 +22,18 @@
 import java.util.Arrays;
 import java.util.Iterator;
 
+import junit.framework.Assert;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.Field.Index;
+import org.apache.lucene.document.Field.Store;
+import org.apache.lucene.analysis.WhitespaceAnalyzer;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriter.MaxFieldLength;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.RAMDirectory;
 import org.apache.lucene.util.LuceneTestCase;
 import org.apache.lucene.util._TestUtil;
 
@@ -102,4 +114,30 @@
       fail();
     }
   }
+  
+  public void testNullDocIdSet() throws Exception {
+    // Tests that if a Filter produces a null DocIdSet, which is given to
+    // IndexSearcher, everything works fine. This came up in LUCENE-1754.
+    Directory dir = new RAMDirectory();
+    IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), MaxFieldLength.UNLIMITED);
+    Document doc = new Document();
+    doc.add(new Field("c", "val", Store.NO, Index.NOT_ANALYZED_NO_NORMS));
+    writer.addDocument(doc);
+    writer.close();
+    
+    // First verify the document is searchable.
+    IndexSearcher searcher = new IndexSearcher(dir, true);
+    Assert.assertEquals(1, searcher.search(new MatchAllDocsQuery(), 10).totalHits);
+    
+    // Now search w/ a Filter which returns a null DocIdSet
+    Filter f = new Filter() {
+      public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
+        return null;
+      }
+    };
+    
+    Assert.assertEquals(0, searcher.search(new MatchAllDocsQuery(), f, 10).totalHits);
+    searcher.close();
+  }
+
 }