Index: src/java/org/apache/lucene/search/CachingSpanFilter.java
===================================================================
--- src/java/org/apache/lucene/search/CachingSpanFilter.java	(revision 610038)
+++ src/java/org/apache/lucene/search/CachingSpanFilter.java	(working copy)
@@ -43,11 +43,19 @@
     this.filter = filter;
   }
 
+  /**
+   * @deprecated Use {@link #getDocIdSet(IndexReader)} instead.
+   */
   public BitSet bits(IndexReader reader) throws IOException {
     SpanFilterResult result = getCachedResult(reader);
     return result != null ? result.getBits() : null;
   }
-
+  
+  public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
+    SpanFilterResult result = getCachedResult(reader);
+    return result != null ? result.getDocIdSet() : null;
+  }
+  
   private SpanFilterResult getCachedResult(IndexReader reader) throws IOException {
     SpanFilterResult result = null;
     if (cache == null) {
Index: src/java/org/apache/lucene/search/CachingWrapperFilter.java
===================================================================
--- src/java/org/apache/lucene/search/CachingWrapperFilter.java	(revision 610038)
+++ src/java/org/apache/lucene/search/CachingWrapperFilter.java	(working copy)
@@ -43,6 +43,9 @@
     this.filter = filter;
   }
 
+  /**
+   * @deprecated Use {@link #getDocIdSet(IndexReader)} instead.
+   */
   public BitSet bits(IndexReader reader) throws IOException {
     if (cache == null) {
       cache = new WeakHashMap();
@@ -63,7 +66,29 @@
 
     return bits;
   }
+  
+  public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
+    if (cache == null) {
+      cache = new WeakHashMap();
+    }
 
+    synchronized (cache) {  // check cache
+      DocIdSet cached = (DocIdSet) cache.get(reader);
+      if (cached != null) {
+        return cached;
+      }
+    }
+
+    final DocIdSet docIdSet = filter.getDocIdSet(reader);
+
+    synchronized (cache) {  // update cache
+      cache.put(reader, docIdSet);
+    }
+
+    return docIdSet;
+    
+  }
+
   public String toString() {
     return "CachingWrapperFilter("+filter+")";
   }
Index: src/java/org/apache/lucene/search/ConstantScoreQuery.java
===================================================================
--- src/java/org/apache/lucene/search/ConstantScoreQuery.java	(revision 610038)
+++ src/java/org/apache/lucene/search/ConstantScoreQuery.java	(working copy)
@@ -85,7 +85,7 @@
     public Explanation explain(IndexReader reader, int doc) throws IOException {
 
       ConstantScorer cs = (ConstantScorer)scorer(reader);
-      boolean exists = cs.bits.get(doc);
+      boolean exists = cs.docIdSetIterator.skipTo(doc) && (cs.docIdSetIterator.doc() == doc);
 
       ComplexExplanation result = new ComplexExplanation();
 
@@ -107,23 +107,22 @@
   }
 
   protected class ConstantScorer extends Scorer {
-    final BitSet bits;
+    final DocIdSetIterator docIdSetIterator;
     final float theScore;
     int doc=-1;
 
     public ConstantScorer(Similarity similarity, IndexReader reader, Weight w) throws IOException {
       super(similarity);
       theScore = w.getValue();
-      bits = filter.bits(reader);
+      docIdSetIterator = filter.getDocIdSet(reader).iterator();
     }
 
     public boolean next() throws IOException {
-      doc = bits.nextSetBit(doc+1);
-      return doc >= 0;
+      return docIdSetIterator.next();
     }
 
     public int doc() {
-      return doc;
+      return docIdSetIterator.doc();
     }
 
     public float score() throws IOException {
@@ -131,8 +130,7 @@
     }
 
     public boolean skipTo(int target) throws IOException {
-      doc = bits.nextSetBit(target);  // requires JDK 1.4
-      return doc >= 0;
+      return docIdSetIterator.skipTo(target);
     }
 
     public Explanation explain(int doc) throws IOException {
Index: src/java/org/apache/lucene/search/DocIdSet.java
===================================================================
--- src/java/org/apache/lucene/search/DocIdSet.java	(revision 0)
+++ src/java/org/apache/lucene/search/DocIdSet.java	(revision 0)
@@ -0,0 +1,27 @@
+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.
+ */
+
+
+/**
+ * A DocIdSet contains a set of doc ids. Implementing classes must provide
+ * a {@link DocIdSetIterator} to access the set. 
+ */
+public abstract class DocIdSet {
+	public abstract DocIdSetIterator iterator();
+}
Index: src/java/org/apache/lucene/search/DocIdSetIterator.java
===================================================================
--- src/java/org/apache/lucene/search/DocIdSetIterator.java	(revision 0)
+++ src/java/org/apache/lucene/search/DocIdSetIterator.java	(revision 0)
@@ -0,0 +1,49 @@
+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;
+
+/**
+ * This abstract class defines methods to iterate over a set of
+ * non-decreasing doc ids.
+ */
+public abstract class DocIdSetIterator {
+    /** Returns the current document number.  <p> This is invalid until {@link
+    #next()} is called for the first time.*/
+    public abstract int doc();
+    
+    /** Moves to the next docId in the set. Returns true, iff
+     * there is such a docId. */
+    public abstract boolean next() throws IOException;
+    
+    /** Skips entries to the first beyond the current whose document number is
+     * greater than or equal to <i>target</i>. <p>Returns true iff there is such
+     * an entry.  <p>Behaves as if written: <pre>
+     *   boolean skipTo(int target) {
+     *     do {
+     *       if (!next())
+     *         return false;
+     *     } while (target > doc());
+     *     return true;
+     *   }
+     * </pre>
+     * Some implementations are considerably more efficient than that.
+     */
+    public abstract boolean skipTo(int target) throws IOException;
+}
Index: src/java/org/apache/lucene/search/Filter.java
===================================================================
--- src/java/org/apache/lucene/search/Filter.java	(revision 610038)
+++ src/java/org/apache/lucene/search/Filter.java	(working copy)
@@ -20,11 +20,32 @@
 import java.util.BitSet;
 import java.io.IOException;
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.util.DocIdBitSet;
 
-/** Abstract base class providing a mechanism to restrict searches to a subset
- of an index. */
+/** Abstract base class providing a mechanism to use a subset of an index
+ *  for restriction or permission of index search results.
+ *  <p>
+ *  <b>Note:</b> In Lucene 3.0 {@link #bits(IndexReader)} will be removed
+ *  and {@link #getDocIdSet(IndexReader)} will be defined as abstract.
+ *  All implementing classes must therefore implement {@link #getDocIdSet(IndexReader)}
+ *  in order to work with Lucene 3.0.
+ */
 public abstract class Filter implements java.io.Serializable {
-  /** Returns a BitSet with true for documents which should be permitted in
-    search results, and false for those that should not. */
-  public abstract BitSet bits(IndexReader reader) throws IOException;
+  /**
+   * @return A BitSet with true for documents which should be permitted in
+   * search results, and false for those that should not.
+   * @deprecated Use {@link #getDocIdSet(IndexReader)} instead.
+   */
+  public BitSet bits(IndexReader reader) throws IOException {
+    return null;
+  }
+	
+  /**
+   * @return a DocIdSet that provides the documents which should be
+   * permitted or prohibited in search results.
+   * @see DocIdBitSet
+   */
+  public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
+    return new DocIdBitSet(bits(reader));
+  }
 }
Index: src/java/org/apache/lucene/search/FilteredQuery.java
===================================================================
--- src/java/org/apache/lucene/search/FilteredQuery.java	(revision 610038)
+++ src/java/org/apache/lucene/search/FilteredQuery.java	(working copy)
@@ -21,7 +21,6 @@
 import org.apache.lucene.util.ToStringUtils;
 
 import java.io.IOException;
-import java.util.BitSet;
 import java.util.Set;
 
 
@@ -47,7 +46,7 @@
 
   /**
    * Constructs a new query which applies a filter to the results of the original query.
-   * Filter.bits() will be called every time this query is used in a search.
+   * Filter.getDocIdSet() will be called every time this query is used in a search.
    * @param query  Query to be filtered, cannot be <code>null</code>.
    * @param filter Filter to apply to query results, cannot be <code>null</code>.
    */
@@ -86,13 +85,15 @@
           inner.addDetail(preBoost);
         }
         Filter f = FilteredQuery.this.filter;
-        BitSet matches = f.bits(ir);
-        if (matches.get(i))
+        DocIdSetIterator docIdSetIterator = f.getDocIdSet(ir).iterator();
+        if (docIdSetIterator.skipTo(i) && (docIdSetIterator.doc() == i)) {
           return inner;
-        Explanation result = new Explanation
-          (0.0f, "failure to match filter: " + f.toString());
-        result.addDetail(inner);
-        return result;
+        } else {
+          Explanation result = new Explanation
+            (0.0f, "failure to match filter: " + f.toString());
+          result.addDetail(inner);
+          return result;
+        }
       }
 
       // return this query
@@ -100,50 +101,49 @@
 
       // return a filtering scorer
        public Scorer scorer (IndexReader indexReader) throws IOException {
-        final Scorer scorer = weight.scorer (indexReader);
-        final BitSet bitset = filter.bits (indexReader);
-        return new Scorer (similarity) {
+        final Scorer scorer = weight.scorer(indexReader);
+        final DocIdSetIterator docIdSetIterator = filter.getDocIdSet(indexReader).iterator();
 
-          public boolean next() throws IOException {
-            do {
-              if (! scorer.next()) {
+        return new Scorer(similarity) {
+
+          private boolean advanceToCommon() throws IOException {
+            while (scorer.doc() != docIdSetIterator.doc()) {
+              if (scorer.doc() < docIdSetIterator.doc()) {
+                if (!scorer.skipTo(docIdSetIterator.doc())) {
+                  return false;
+                }
+              } else if (!docIdSetIterator.skipTo(scorer.doc())) {
                 return false;
               }
-            } while (! bitset.get(scorer.doc()));
-            /* When skipTo() is allowed on scorer it should be used here
-             * in combination with bitset.nextSetBit(...)
-             * See the while loop in skipTo() below.
-             */
+            }
             return true;
           }
+
+          public boolean next() throws IOException {
+            return docIdSetIterator.next() && scorer.next() && advanceToCommon();
+          }
+
           public int doc() { return scorer.doc(); }
 
           public boolean skipTo(int i) throws IOException {
-            if (! scorer.skipTo(i)) {
-              return false;
-            }
-            while (! bitset.get(scorer.doc())) {
-              int nextFiltered = bitset.nextSetBit(scorer.doc() + 1);
-              if (nextFiltered == -1) {
-                return false;
-              } else if (! scorer.skipTo(nextFiltered)) {
-                return false;
-              }
-            }
-            return true;
-           }
+            return docIdSetIterator.skipTo(i)
+                && scorer.skipTo(docIdSetIterator.doc())
+                && advanceToCommon();
+          }
 
           public float score() throws IOException { return getBoost() * scorer.score(); }
 
           // add an explanation about whether the document was filtered
           public Explanation explain (int i) throws IOException {
-            Explanation exp = scorer.explain (i);
-            exp.setValue(getBoost() * exp.getValue());
+            Explanation exp = scorer.explain(i);
             
-            if (bitset.get(i))
+            if (docIdSetIterator.skipTo(i) && (docIdSetIterator.doc() == i)) {
               exp.setDescription ("allowed by filter: "+exp.getDescription());
-            else
+              exp.setValue(getBoost() * exp.getValue());
+            } else {
               exp.setDescription ("removed by filter: "+exp.getDescription());
+              exp.setValue(0.0f);
+            }
             return exp;
           }
         };
Index: src/java/org/apache/lucene/search/IndexSearcher.java
===================================================================
--- src/java/org/apache/lucene/search/IndexSearcher.java	(revision 610038)
+++ src/java/org/apache/lucene/search/IndexSearcher.java	(working copy)
@@ -128,22 +128,33 @@
   // inherit javadoc
   public void search(Weight weight, Filter filter,
                      final HitCollector results) throws IOException {
-    HitCollector collector = results;
-    if (filter != null) {
-      final BitSet bits = filter.bits(reader);
-      collector = new HitCollector() {
-          public final void collect(int doc, float score) {
-            if (bits.get(doc)) {                  // skip docs not in bits
-              results.collect(doc, score);
-            }
-          }
-        };
-    }
 
     Scorer scorer = weight.scorer(reader);
     if (scorer == null)
       return;
-    scorer.score(collector);
+
+    if (filter == null) {
+      scorer.score(results);
+      return;
+    }
+
+    DocIdSetIterator docIdSetIterator = filter.getDocIdSet(reader).iterator(); // CHECKME: use ConjunctionScorer here?
+    boolean more = docIdSetIterator.next();
+    while (more) {
+      int filterDocId = docIdSetIterator.doc();
+      if (! scorer.skipTo(filterDocId)) {
+        more = false;
+      } else {
+        int scorerDocId = scorer.doc();
+        if (scorerDocId == filterDocId) { // permitted by filter
+          results.collect(scorerDocId, scorer.score());
+          more = docIdSetIterator.skipTo(scorerDocId + 1);
+        } else {
+          more = docIdSetIterator.skipTo(scorerDocId);
+        }
+      }
+    }
+
   }
 
   public Query rewrite(Query original) throws IOException {
Index: src/java/org/apache/lucene/search/PrefixFilter.java
===================================================================
--- src/java/org/apache/lucene/search/PrefixFilter.java	(revision 610038)
+++ src/java/org/apache/lucene/search/PrefixFilter.java	(working copy)
@@ -18,6 +18,7 @@
  */
 
 import org.apache.lucene.search.Filter;
+import org.apache.lucene.util.OpenBitSet;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.TermEnum;
@@ -39,6 +40,9 @@
 
   public Term getPrefix() { return prefix; }
 
+  /**
+   * @deprecated Use {@link #getDocIdSet(IndexReader)} instead.
+   */  
   public BitSet bits(IndexReader reader) throws IOException {
     final BitSet bitSet = new BitSet(reader.maxDoc());
     new PrefixGenerator(prefix) {
@@ -48,6 +52,16 @@
     }.generate(reader);
     return bitSet;
   }
+  
+  public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
+    final OpenBitSet bitSet = new OpenBitSet(reader.maxDoc());
+    new PrefixGenerator(prefix) {
+      public void handleDoc(int doc) {
+        bitSet.set(doc);
+      }
+    }.generate(reader);
+    return bitSet;
+  }
 
   /** Prints a user-readable version of this query. */
   public String toString () {
Index: src/java/org/apache/lucene/search/QueryWrapperFilter.java
===================================================================
--- src/java/org/apache/lucene/search/QueryWrapperFilter.java	(revision 610038)
+++ src/java/org/apache/lucene/search/QueryWrapperFilter.java	(working copy)
@@ -21,6 +21,7 @@
 import java.util.BitSet;
 
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.util.OpenBitSet;
 
 /** 
  * Constrains search results to only match those which also match a provided
@@ -44,6 +45,9 @@
     this.query = query;
   }
 
+  /**
+   * @deprecated Use {@link #getDocIdSet(IndexReader)} instead.
+   */
   public BitSet bits(IndexReader reader) throws IOException {
     final BitSet bits = new BitSet(reader.maxDoc());
 
@@ -54,7 +58,18 @@
     });
     return bits;
   }
+  
+  public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
+    final OpenBitSet bits = new OpenBitSet(reader.maxDoc());
 
+    new IndexSearcher(reader).search(query, new HitCollector() {
+      public final void collect(int doc, float score) {
+        bits.set(doc);  // set bit for hit
+      }
+    });
+    return bits;
+  }
+
   public String toString() {
     return "QueryWrapperFilter(" + query + ")";
   }
Index: src/java/org/apache/lucene/search/RangeFilter.java
===================================================================
--- src/java/org/apache/lucene/search/RangeFilter.java	(revision 610038)
+++ src/java/org/apache/lucene/search/RangeFilter.java	(working copy)
@@ -21,6 +21,7 @@
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermDocs;
 import org.apache.lucene.index.TermEnum;
+import org.apache.lucene.util.OpenBitSet;
 
 import java.io.IOException;
 import java.util.BitSet;
@@ -94,6 +95,7 @@
      * Returns a BitSet with true for documents which should be
      * permitted in search results, and false for those that should
      * not.
+     * @deprecated Use {@link #getDocIdSet(IndexReader)} instead.
      */
     public BitSet bits(IndexReader reader) throws IOException {
         BitSet bits = new BitSet(reader.maxDoc());
@@ -152,6 +154,69 @@
         return bits;
     }
     
+    /**
+     * Returns a BitSet with true for documents which should be
+     * permitted in search results, and false for those that should
+     * not.
+     */
+    public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
+        OpenBitSet bits = new OpenBitSet(reader.maxDoc());
+        
+        TermEnum enumerator =
+            (null != lowerTerm
+             ? reader.terms(new Term(fieldName, lowerTerm))
+             : reader.terms(new Term(fieldName,"")));
+        
+        try {
+            
+            if (enumerator.term() == null) {
+                return bits;
+            }
+            
+            boolean checkLower = false;
+            if (!includeLower) // make adjustments to set to exclusive
+                checkLower = true;
+        
+            TermDocs termDocs = reader.termDocs();
+            try {
+                
+                do {
+                    Term term = enumerator.term();
+                    if (term != null && term.field().equals(fieldName)) {
+                        if (!checkLower || null==lowerTerm || term.text().compareTo(lowerTerm) > 0) {
+                            checkLower = false;
+                            if (upperTerm != null) {
+                                int compare = upperTerm.compareTo(term.text());
+                                /* if beyond the upper term, or is exclusive and
+                                 * this is equal to the upper term, break out */
+                                if ((compare < 0) ||
+                                    (!includeUpper && compare==0)) {
+                                    break;
+                                }
+                            }
+                            /* we have a good term, find the docs */
+                            
+                            termDocs.seek(enumerator.term());
+                            while (termDocs.next()) {
+                                bits.set(termDocs.doc());
+                            }
+                        }
+                    } else {
+                        break;
+                    }
+                }
+                while (enumerator.next());
+                
+            } finally {
+                termDocs.close();
+            }
+        } finally {
+            enumerator.close();
+        }
+
+        return bits;
+    }
+    
     public String toString() {
         StringBuffer buffer = new StringBuffer();
         buffer.append(fieldName);
Index: src/java/org/apache/lucene/search/RemoteCachingWrapperFilter.java
===================================================================
--- src/java/org/apache/lucene/search/RemoteCachingWrapperFilter.java	(revision 610038)
+++ src/java/org/apache/lucene/search/RemoteCachingWrapperFilter.java	(working copy)
@@ -50,9 +50,21 @@
    * searcher side of a remote connection.
    * @param reader the index reader for the Filter
    * @return the bitset
+   * @deprecated Use {@link #getDocIdSet(IndexReader)} instead.
    */
   public BitSet bits(IndexReader reader) throws IOException {
     Filter cachedFilter = FilterManager.getInstance().getFilter(filter);
     return cachedFilter.bits(reader);
   }
+  
+  /**
+   * Uses the {@link FilterManager} to keep the cache for a filter on the 
+   * searcher side of a remote connection.
+   * @param reader the index reader for the Filter
+   * @return the DocIdSet
+   */
+  public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
+    Filter cachedFilter = FilterManager.getInstance().getFilter(filter);
+    return cachedFilter.getDocIdSet(reader);
+  }
 }
Index: src/java/org/apache/lucene/search/Scorer.java
===================================================================
--- src/java/org/apache/lucene/search/Scorer.java	(revision 610038)
+++ src/java/org/apache/lucene/search/Scorer.java	(working copy)
@@ -33,7 +33,7 @@
  * </p>
  * @see BooleanQuery#setAllowDocsOutOfOrder
  */
-public abstract class Scorer {
+public abstract class Scorer extends DocIdSetIterator {
   private Similarity similarity;
 
   /** Constructs a Scorer.
@@ -76,65 +76,12 @@
     return true;
   }
 
-  /**
-   * Advances to the document matching this Scorer with the lowest doc Id
-   * greater than the current value of {@link #doc()} (or to the matching
-   * document with the lowest doc Id if next has never been called on
-   * this Scorer).
-   *
-   * <p>
-   * When this method is used the {@link #explain(int)} method should not
-   * be used.
-   * </p>
-   *
-   * @return true iff there is another document matching the query.
-   * @see BooleanQuery#setAllowDocsOutOfOrder
-   */
-  public abstract boolean next() throws IOException;
-
-  /** Returns the current document number matching the query.
-   * Initially invalid, until {@link #next()} is called the first time.
-   */
-  public abstract int doc();
-
   /** Returns the score of the current document matching the query.
    * Initially invalid, until {@link #next()} or {@link #skipTo(int)}
    * is called the first time.
    */
   public abstract float score() throws IOException;
 
-  /**
-   * Skips to the document matching this Scorer with the lowest doc Id
-   * greater than or equal to a given target.
-   *
-   * <p>
-   * The behavior of this method is undefined if the target specified is
-   * less than or equal to the current value of {@link #doc()}.
-   * <p>
-   * Behaves as if written:
-   * <pre>
-   *   boolean skipTo(int target) {
-   *     do {
-   *       if (!next())
-   * 	     return false;
-   *     } while (target > doc());
-   *     return true;
-   *   }
-   * </pre>
-   * Most implementations are considerably more efficient than that.
-   * </p>
-   *
-   * <p>
-   * When this method is used the {@link #explain(int)} method should not
-   * be used.
-   * </p>
-   *
-   * @param target The target document number.
-   * @return true iff there is such a match.
-   * @see BooleanQuery#setAllowDocsOutOfOrder
-   */
-  public abstract boolean skipTo(int target) throws IOException;
-
   /** Returns an explanation of the score for a document.
    * <br>When this method is used, the {@link #next()}, {@link #skipTo(int)} and
    * {@link #score(HitCollector)} methods should not be used.
Index: src/java/org/apache/lucene/search/Searchable.java
===================================================================
--- src/java/org/apache/lucene/search/Searchable.java	(revision 610038)
+++ src/java/org/apache/lucene/search/Searchable.java	(working copy)
@@ -48,7 +48,7 @@
    * non-high-scoring hits.
    *
    * @param weight to match documents
-   * @param filter if non-null, a bitset used to eliminate some documents
+   * @param filter if non-null, used to permit documents to be collected.
    * @param results to receive hits
    * @throws BooleanQuery.TooManyClauses
    */
Index: src/java/org/apache/lucene/search/Searcher.java
===================================================================
--- src/java/org/apache/lucene/search/Searcher.java	(revision 610038)
+++ src/java/org/apache/lucene/search/Searcher.java	(working copy)
@@ -109,7 +109,7 @@
    * non-high-scoring hits.
    *
    * @param query to match documents
-   * @param filter if non-null, a bitset used to eliminate some documents
+   * @param filter if non-null, used to permit documents to be collected.
    * @param results to receive hits
    * @throws BooleanQuery.TooManyClauses
    */
Index: src/java/org/apache/lucene/search/SpanFilter.java
===================================================================
--- src/java/org/apache/lucene/search/SpanFilter.java	(revision 610038)
+++ src/java/org/apache/lucene/search/SpanFilter.java	(working copy)
@@ -30,7 +30,7 @@
 public abstract class SpanFilter extends Filter{
   /** Returns a SpanFilterResult with true for documents which should be permitted in
     search results, and false for those that should not and Spans for where the true docs match.
-   * @param reader The {@link org.apache.lucene.index.IndexReader} to load position and bitset information from
+   * @param reader The {@link org.apache.lucene.index.IndexReader} to load position and DocIdSet information from
    * @return A {@link SpanFilterResult}
    * @throws java.io.IOException if there was an issue accessing the necessary information
    * */
Index: src/java/org/apache/lucene/search/SpanFilterResult.java
===================================================================
--- src/java/org/apache/lucene/search/SpanFilterResult.java	(revision 610038)
+++ src/java/org/apache/lucene/search/SpanFilterResult.java	(working copy)
@@ -28,20 +28,34 @@
  *
  **/
 public class SpanFilterResult {
+  /** @deprecated */
   private BitSet bits;
+  
+  private DocIdSet docIdSet;
   private List positions;//Spans spans;
 
   /**
    *
    * @param bits The bits for the Filter
    * @param positions A List of {@link org.apache.lucene.search.SpanFilterResult.PositionInfo} objects
+   * @deprecated Use {@link #SpanFilterResult(DocIdSet, List)} instead
    */
   public SpanFilterResult(BitSet bits, List positions) {
     this.bits = bits;
     this.positions = positions;
   }
-
+  
   /**
+  *
+  * @param docIdSet The DocIdSet for the Filter
+  * @param positions A List of {@link org.apache.lucene.search.SpanFilterResult.PositionInfo} objects
+  */
+  public SpanFilterResult(DocIdSet docIdSet, List positions) {
+    this.docIdSet = docIdSet;
+    this.positions = positions;
+  }
+  
+  /**
    * The first entry in the array corresponds to the first "on" bit.
    * Entries are increasing by document order
    * @return A List of PositionInfo objects
@@ -50,11 +64,17 @@
     return positions;
   }
 
+  /** 
+   * @deprecated Use {@link #getDocIdSet()}
+   */
   public BitSet getBits() {
     return bits;
   }
-
   
+  /** Returns the docIdSet */
+  public DocIdSet getDocIdSet() {
+    return docIdSet;
+  }
 
   public static class PositionInfo {
     private int doc;
Index: src/java/org/apache/lucene/search/SpanQueryFilter.java
===================================================================
--- src/java/org/apache/lucene/search/SpanQueryFilter.java	(revision 610038)
+++ src/java/org/apache/lucene/search/SpanQueryFilter.java	(working copy)
@@ -19,6 +19,7 @@
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.spans.SpanQuery;
 import org.apache.lucene.search.spans.Spans;
+import org.apache.lucene.util.OpenBitSet;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -54,15 +55,14 @@
     this.query = query;
   }
 
-  public BitSet bits(IndexReader reader) throws IOException {
+  public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
     SpanFilterResult result = bitSpans(reader);
-    return result.getBits();
+    return result.getDocIdSet();
   }
 
-
   public SpanFilterResult bitSpans(IndexReader reader) throws IOException {
 
-    final BitSet bits = new BitSet(reader.maxDoc());
+    final OpenBitSet bits = new OpenBitSet(reader.maxDoc());
     Spans spans = query.getSpans(reader);
     List tmp = new ArrayList(20);
     int currentDoc = -1;
Index: src/test/org/apache/lucene/search/CachingWrapperFilterHelper.java
===================================================================
--- src/test/org/apache/lucene/search/CachingWrapperFilterHelper.java	(revision 610038)
+++ src/test/org/apache/lucene/search/CachingWrapperFilterHelper.java	(working copy)
@@ -43,13 +43,13 @@
     this.shouldHaveCache = shouldHaveCache;
   }
   
-  public BitSet bits(IndexReader reader) throws IOException {
+  public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
     if (cache == null) {
       cache = new WeakHashMap();
     }
     
     synchronized (cache) {  // check cache
-      BitSet cached = (BitSet) cache.get(reader);
+      DocIdSet cached = (DocIdSet) cache.get(reader);
       if (shouldHaveCache) {
         TestCase.assertNotNull("Cache should have data ", cached);
       } else {
@@ -60,7 +60,7 @@
       }
     }
 
-    final BitSet bits = filter.bits(reader);
+    final DocIdSet bits = filter.getDocIdSet(reader);
 
     synchronized (cache) {  // update cache
       cache.put(reader, bits);
Index: src/test/org/apache/lucene/search/RemoteCachingWrapperFilterHelper.java
===================================================================
--- src/test/org/apache/lucene/search/RemoteCachingWrapperFilterHelper.java	(revision 610038)
+++ src/test/org/apache/lucene/search/RemoteCachingWrapperFilterHelper.java	(working copy)
@@ -42,7 +42,7 @@
     this.shouldHaveCache = shouldHaveCache;
   }
 
-  public BitSet bits(IndexReader reader) throws IOException {
+  public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
     Filter cachedFilter = FilterManager.getInstance().getFilter(filter);
     
     TestCase.assertNotNull("Filter should not be null", cachedFilter);
@@ -55,6 +55,6 @@
     if (filter instanceof CachingWrapperFilterHelper) {
       ((CachingWrapperFilterHelper)cachedFilter).setShouldHaveCache(shouldHaveCache);
     }
-    return cachedFilter.bits(reader);
+    return cachedFilter.getDocIdSet(reader);
   }
 }
Index: src/test/org/apache/lucene/search/TestCachingWrapperFilter.java
===================================================================
--- src/test/org/apache/lucene/search/TestCachingWrapperFilter.java	(revision 610038)
+++ src/test/org/apache/lucene/search/TestCachingWrapperFilter.java	(working copy)
@@ -36,12 +36,12 @@
     CachingWrapperFilter cacher = new CachingWrapperFilter(filter);
 
     // first time, nested filter is called
-    cacher.bits(reader);
+    cacher.getDocIdSet(reader);
     assertTrue("first time", filter.wasCalled());
 
     // second time, nested filter should not be called
     filter.clear();
-    cacher.bits(reader);
+    cacher.getDocIdSet(reader);
     assertFalse("second time", filter.wasCalled());
 
     reader.close();
Index: src/test/org/apache/lucene/search/TestRemoteCachingWrapperFilter.java
===================================================================
--- src/test/org/apache/lucene/search/TestRemoteCachingWrapperFilter.java	(revision 610038)
+++ src/test/org/apache/lucene/search/TestRemoteCachingWrapperFilter.java	(working copy)
@@ -90,7 +90,7 @@
 
 
   public void testTermRemoteFilter() throws Exception {
-    CachingWrapperFilterHelper cwfh = new CachingWrapperFilterHelper(new QueryFilter(new TermQuery(new Term("type", "a"))));
+    CachingWrapperFilterHelper cwfh = new CachingWrapperFilterHelper(new QueryWrapperFilter(new TermQuery(new Term("type", "a"))));
     
     // This is what we are fixing - if one uses a CachingWrapperFilter(Helper) it will never 
     // cache the filter on the remote site
@@ -111,16 +111,16 @@
     // assert that we get the same cached Filter, even if we create a new instance of RemoteCachingWrapperFilter(Helper)
     // this should pass because the Filter parameters are the same, and the cache uses Filter's hashCode() as cache keys,
     // and Filters' hashCode() builds on Filter parameters, not the Filter instance itself
-    rcwfh = new RemoteCachingWrapperFilterHelper(new QueryFilter(new TermQuery(new Term("type", "a"))), false);
+    rcwfh = new RemoteCachingWrapperFilterHelper(new QueryWrapperFilter(new TermQuery(new Term("type", "a"))), false);
     rcwfh.shouldHaveCache(false);
     search(new TermQuery(new Term("test", "test")), rcwfh, 0, "A");
 
-    rcwfh = new RemoteCachingWrapperFilterHelper(new QueryFilter(new TermQuery(new Term("type", "a"))), false);
+    rcwfh = new RemoteCachingWrapperFilterHelper(new QueryWrapperFilter(new TermQuery(new Term("type", "a"))), false);
     rcwfh.shouldHaveCache(true);
     search(new TermQuery(new Term("test", "test")), rcwfh, 0, "A");
 
     // assert that we get a non-cached version of the Filter because this is a new Query (type:b)
-    rcwfh = new RemoteCachingWrapperFilterHelper(new QueryFilter(new TermQuery(new Term("type", "b"))), false);
+    rcwfh = new RemoteCachingWrapperFilterHelper(new QueryWrapperFilter(new TermQuery(new Term("type", "b"))), false);
     rcwfh.shouldHaveCache(false);
     search(new TermQuery(new Term("type", "b")), rcwfh, 0, "B");
   }
Index: src/test/org/apache/lucene/search/TestSpanQueryFilter.java
===================================================================
--- src/test/org/apache/lucene/search/TestSpanQueryFilter.java	(revision 610038)
+++ src/test/org/apache/lucene/search/TestSpanQueryFilter.java	(working copy)
@@ -55,20 +55,36 @@
     SpanTermQuery query = new SpanTermQuery(new Term("field", English.intToEnglish(10).trim()));
     SpanQueryFilter filter = new SpanQueryFilter(query);
     SpanFilterResult result = filter.bitSpans(reader);
-    BitSet bits = result.getBits();
-    assertTrue("bits is null and it shouldn't be", bits != null);
-    assertTrue("tenth bit is not on", bits.get(10));
+    DocIdSet docIdSet = result.getDocIdSet();
+    assertTrue("docIdSet is null and it shouldn't be", docIdSet != null);
+    assertContainsDocId("docIdSet doesn't contain docId 10", docIdSet, 10);
     List spans = result.getPositions();
     assertTrue("spans is null and it shouldn't be", spans != null);
-    assertTrue("spans Size: " + spans.size() + " is not: " + bits.cardinality(), spans.size() == bits.cardinality());
+    int size = getDocIdSetSize(docIdSet);
+    assertTrue("spans Size: " + spans.size() + " is not: " + size, spans.size() == size);
     for (Iterator iterator = spans.iterator(); iterator.hasNext();) {
        SpanFilterResult.PositionInfo info = (SpanFilterResult.PositionInfo) iterator.next();
       assertTrue("info is null and it shouldn't be", info != null);
       //The doc should indicate the bit is on
-      assertTrue("Bit is not on and it should be", bits.get(info.getDoc()));
+      assertContainsDocId("docIdSet doesn't contain docId " + info.getDoc(), docIdSet, info.getDoc());
       //There should be two positions in each
       assertTrue("info.getPositions() Size: " + info.getPositions().size() + " is not: " + 2, info.getPositions().size() == 2);
     }
     reader.close();
   }
+  
+  int getDocIdSetSize(DocIdSet docIdSet) throws Exception {
+    int size = 0;
+    DocIdSetIterator it = docIdSet.iterator();
+    while (it.next()) {
+      size++;
+    }
+    return size;
+  }
+  
+  public void assertContainsDocId(String msg, DocIdSet docIdSet, int docId) throws Exception {
+    DocIdSetIterator it = docIdSet.iterator();
+    assertTrue(msg, it.skipTo(docId));
+    assertTrue(msg, it.doc() == docId);
+  }
 }
