Index: src/java/org/apache/lucene/search/BooleanQuery.java
===================================================================
--- src/java/org/apache/lucene/search/BooleanQuery.java	(revision 573048)
+++ src/java/org/apache/lucene/search/BooleanQuery.java	(working copy)
@@ -61,7 +61,7 @@
    * so this parameter indirectly controls the maximum buffer requirements for
    * query search.
    * <p>When this parameter becomes a bottleneck for a Query one can use a
-   * Filter. For example instead of a {@link RangeQuery} one can use a
+   * MatchFilter. For example instead of a {@link RangeQuery} one can use a
    * {@link RangeFilter}.
    * <p>Normally the buffers are allocated by the JVM. When using for example
    * {@link org.apache.lucene.store.MMapDirectory} the buffering is left to
Index: src/java/org/apache/lucene/search/ConstantScoreQuery.java
===================================================================
--- src/java/org/apache/lucene/search/ConstantScoreQuery.java	(revision 573048)
+++ src/java/org/apache/lucene/search/ConstantScoreQuery.java	(working copy)
@@ -20,7 +20,6 @@
 import org.apache.lucene.index.IndexReader;
 
 import java.io.IOException;
-import java.util.BitSet;
 import java.util.Set;
 
 /**
@@ -31,14 +30,14 @@
  * @version $Id$
  */
 public class ConstantScoreQuery extends Query {
-  protected final Filter filter;
+  protected final MatchFilter filter;
 
-  public ConstantScoreQuery(Filter filter) {
+  public ConstantScoreQuery(MatchFilter filter) {
     this.filter=filter;
   }
 
   /** Returns the encapsulated filter */
-  public Filter getFilter() {
+  public MatchFilter getFilter() {
     return filter;
   }
 
@@ -85,7 +84,7 @@
     public Explanation explain(IndexReader reader, int doc) throws IOException {
 
       ConstantScorer cs = (ConstantScorer)scorer(reader);
-      boolean exists = cs.bits.get(doc);
+      boolean exists = cs.matcher.skipTo(doc) && (cs.matcher.doc() == doc);
 
       ComplexExplanation result = new ComplexExplanation();
 
@@ -107,23 +106,21 @@
   }
 
   protected class ConstantScorer extends Scorer {
-    final BitSet bits;
+    final Matcher matcher;
     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);
+      matcher = filter.getMatcher(reader);
     }
 
     public boolean next() throws IOException {
-      doc = bits.nextSetBit(doc+1);
-      return doc >= 0;
+      return matcher.next();
     }
 
     public int doc() {
-      return doc;
+      return matcher.doc();
     }
 
     public float score() throws IOException {
@@ -131,8 +128,7 @@
     }
 
     public boolean skipTo(int target) throws IOException {
-      doc = bits.nextSetBit(target);  // requires JDK 1.4
-      return doc >= 0;
+      return matcher.skipTo(target);
     }
 
     public Explanation explain(int doc) throws IOException {
Index: src/java/org/apache/lucene/search/FieldDoc.java
===================================================================
--- src/java/org/apache/lucene/search/FieldDoc.java	(revision 573048)
+++ src/java/org/apache/lucene/search/FieldDoc.java	(working copy)
@@ -47,7 +47,7 @@
 	 * Sort object.  Each Object will be either an Integer, Float or String,
 	 * depending on the type of values in the terms of the original field.
 	 * @see Sort
-	 * @see Searcher#search(Query,Filter,int,Sort)
+	 * @see Searcher#search(Query,MatchFilter,int,Sort)
 	 */
 	public Comparable[] fields;
 
Index: src/java/org/apache/lucene/search/FieldSortedHitQueue.java
===================================================================
--- src/java/org/apache/lucene/search/FieldSortedHitQueue.java	(revision 573048)
+++ src/java/org/apache/lucene/search/FieldSortedHitQueue.java	(working copy)
@@ -33,7 +33,7 @@
  * @author  Tim Jones (Nacimiento Software)
  * @since   lucene 1.4
  * @version $Id$
- * @see Searcher#search(Query,Filter,int,Sort)
+ * @see Searcher#search(Query,MatchFilter,int,Sort)
  * @see FieldCache
  */
 public class FieldSortedHitQueue
@@ -127,7 +127,7 @@
    * by a MultiSearcher with other search hits.
    * @param  doc  The FieldDoc to store sort values into.
    * @return  The same FieldDoc passed in.
-   * @see Searchable#search(Weight,Filter,int,Sort)
+   * @see Searchable#search(Weight,MatchFilter,int,Sort)
    */
   FieldDoc fillFields (final FieldDoc doc) {
     final int n = comparators.length;
Index: src/java/org/apache/lucene/search/FilteredQuery.java
===================================================================
--- src/java/org/apache/lucene/search/FilteredQuery.java	(revision 573048)
+++ 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;
 
 
@@ -43,15 +42,15 @@
 extends Query {
 
   Query query;
-  Filter filter;
+  MatchFilter filter;
 
   /**
    * 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.
+   * MatchFilter.getMatcher() 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>.
+   * @param filter MatchFilter to apply to query results, cannot be <code>null</code>.
    */
-  public FilteredQuery (Query query, Filter filter) {
+  public FilteredQuery (Query query, MatchFilter filter) {
     this.query = query;
     this.filter = filter;
   }
@@ -85,14 +84,16 @@
           inner.addDetail(new Explanation(getBoost(),"boost"));
           inner.addDetail(preBoost);
         }
-        Filter f = FilteredQuery.this.filter;
-        BitSet matches = f.bits(ir);
-        if (matches.get(i))
+        MatchFilter f = FilteredQuery.this.filter;
+        Matcher matcher = f.getMatcher(ir);
+        if (matcher.skipTo(i) && (matcher.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 Matcher matcher = filter.getMatcher(indexReader);
 
-          public boolean next() throws IOException {
-            do {
-              if (! scorer.next()) {
+        return new Scorer(similarity) {
+
+          private boolean advanceToCommon() throws IOException {
+            while (scorer.doc() != matcher.doc()) {
+              if (scorer.doc() < matcher.doc()) {
+                if (!scorer.skipTo(matcher.doc())) {
+                  return false;
+                }
+              } else if (!matcher.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 matcher.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 matcher.skipTo(i)
+                && scorer.skipTo(matcher.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 (matcher.skipTo(i) && (matcher.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;
           }
         };
@@ -167,7 +167,7 @@
     return query;
   }
 
-  public Filter getFilter() {
+  public MatchFilter getFilter() {
     return filter;
   }
 
Index: src/java/org/apache/lucene/search/Hits.java
===================================================================
--- src/java/org/apache/lucene/search/Hits.java	(revision 573048)
+++ src/java/org/apache/lucene/search/Hits.java	(working copy)
@@ -35,7 +35,7 @@
 public final class Hits {
   private Weight weight;
   private Searcher searcher;
-  private Filter filter = null;
+  private MatchFilter filter = null;
   private Sort sort = null;
 
   private int length;				  // the total number of hits
@@ -46,14 +46,14 @@
   private int numDocs = 0;      // number cached
   private int maxDocs = 200;    // max to cache
 
-  Hits(Searcher s, Query q, Filter f) throws IOException {
+  Hits(Searcher s, Query q, MatchFilter f) throws IOException {
     weight = q.weight(s);
     searcher = s;
     filter = f;
     getMoreDocs(50); // retrieve 100 initially
   }
 
-  Hits(Searcher s, Query q, Filter f, Sort o) throws IOException {
+  Hits(Searcher s, Query q, MatchFilter f, Sort o) throws IOException {
     weight = q.weight(s);
     searcher = s;
     filter = f;
Index: src/java/org/apache/lucene/search/QueryWrapperFilter.java
===================================================================
--- src/java/org/apache/lucene/search/QueryWrapperFilter.java	(revision 573048)
+++ src/java/org/apache/lucene/search/QueryWrapperFilter.java	(working copy)
@@ -31,8 +31,6 @@
  * QueryFilter that matches, e.g., only documents modified within the last
  * week.  The QueryFilter and RangeQuery would only need to be reconstructed
  * once per day.
- *
- * @version $Id:$
  */
 public class QueryWrapperFilter extends Filter {
   private Query query;
@@ -43,13 +41,12 @@
   public QueryWrapperFilter(Query query) {
     this.query = query;
   }
-
+  
   public BitSet bits(IndexReader reader) throws IOException {
     final BitSet bits = new BitSet(reader.maxDoc());
-
-    new IndexSearcher(reader).search(query, new HitCollector() {
-      public final void collect(int doc, float score) {
-        bits.set(doc);  // set bit for hit
+    new IndexSearcher(reader).match(query, new MatchCollector() {
+      public final void collect(int doc) {
+        bits.set(doc);
       }
     });
     return bits;
Index: src/java/org/apache/lucene/search/CachingWrapperFilter.java
===================================================================
--- src/java/org/apache/lucene/search/CachingWrapperFilter.java	(revision 573048)
+++ src/java/org/apache/lucene/search/CachingWrapperFilter.java	(working copy)
@@ -17,12 +17,15 @@
  * limitations under the License.
  */
 
-import org.apache.lucene.index.IndexReader;
 import java.util.BitSet;
 import java.util.WeakHashMap;
 import java.util.Map;
 import java.io.IOException;
 
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.util.DefaultMatcher;
+import org.apache.lucene.util.MatcherProvider;
+
 /**
  * Wraps another filter's result and caches it.  The purpose is to allow
  * filters to simply filter, and then wrap with this class to add caching.
@@ -44,24 +47,31 @@
   }
 
   public BitSet bits(IndexReader reader) throws IOException {
-    if (cache == null) {
-      cache = new WeakHashMap();
-    }
+    return filter.bits(reader);
+  }
+  
+  public Matcher getMatcher(IndexReader reader) throws IOException {
+    MatcherProvider cachedMP = null;
 
-    synchronized (cache) {  // check cache
-      BitSet cached = (BitSet) cache.get(reader);
-      if (cached != null) {
-        return cached;
+    synchronized (this) {
+      if (cache == null) {
+        cache = new WeakHashMap();
+      } else {
+        cachedMP = (MatcherProvider) cache.get(reader);
       }
     }
 
-    final BitSet bits = filter.bits(reader);
+    if (cachedMP != null) {
+      return cachedMP.getMatcher();
+    }
 
-    synchronized (cache) {  // update cache
-      cache.put(reader, bits);
+    cachedMP = DefaultMatcher.makeMatcherProvider(bits(reader));
+
+    synchronized (this) {  // update cache
+      cache.put(reader, cachedMP);
     }
 
-    return bits;
+    return cachedMP.getMatcher();
   }
 
   public String toString() {
Index: src/test/org/apache/lucene/search/CheckHits.java
===================================================================
--- src/test/org/apache/lucene/search/CheckHits.java	(revision 573048)
+++ src/test/org/apache/lucene/search/CheckHits.java	(working copy)
@@ -377,7 +377,7 @@
                    new ExplanationAsserter
                    (q, null, this));
     }
-    public Hits search(Query query, Filter filter) throws IOException {
+    public Hits search(Query query, MatchFilter filter) throws IOException {
       checkExplanations(query);
       return super.search(query,filter);
     }
@@ -385,13 +385,13 @@
       checkExplanations(query);
       return super.search(query,sort);
     }
-    public Hits search(Query query, Filter filter,
+    public Hits search(Query query, MatchFilter filter,
                        Sort sort) throws IOException {
       checkExplanations(query);
       return super.search(query,filter,sort);
     }
     public TopFieldDocs search(Query query,
-                               Filter filter,
+                               MatchFilter filter,
                                int n,
                                Sort sort) throws IOException {
       
@@ -402,12 +402,12 @@
       checkExplanations(query);
       super.search(query,results);
     }
-    public void search(Query query, Filter filter,
+    public void search(Query query, MatchFilter filter,
                        HitCollector results) throws IOException {
       checkExplanations(query);
       super.search(query,filter, results);
     }
-    public TopDocs search(Query query, Filter filter,
+    public TopDocs search(Query query, MatchFilter filter,
                           int n) throws IOException {
 
       checkExplanations(query);
Index: src/test/org/apache/lucene/search/TestCustomSearcherSort.java
===================================================================
--- src/test/org/apache/lucene/search/TestCustomSearcherSort.java	(revision 573048)
+++ src/test/org/apache/lucene/search/TestCustomSearcherSort.java	(working copy)
@@ -252,9 +252,9 @@
             this.switcher = switcher;
         }
         /* (non-Javadoc)
-         * @see org.apache.lucene.search.Searchable#search(org.apache.lucene.search.Query, org.apache.lucene.search.Filter, int, org.apache.lucene.search.Sort)
+         * @see org.apache.lucene.search.Searchable#search(org.apache.lucene.search.Query, org.apache.lucene.search.MatchFilter, int, org.apache.lucene.search.Sort)
          */
-        public TopFieldDocs search(Query query, Filter filter, int nDocs,
+        public TopFieldDocs search(Query query, MatchFilter filter, int nDocs,
                 Sort sort) throws IOException {
             BooleanQuery bq = new BooleanQuery();
             bq.add(query, BooleanClause.Occur.MUST);
@@ -262,9 +262,9 @@
             return super.search(bq, filter, nDocs, sort);
         }
         /* (non-Javadoc)
-         * @see org.apache.lucene.search.Searchable#search(org.apache.lucene.search.Query, org.apache.lucene.search.Filter, int)
+         * @see org.apache.lucene.search.Searchable#search(org.apache.lucene.search.Query, org.apache.lucene.search.MatchFilter, int)
          */
-        public TopDocs search(Query query, Filter filter, int nDocs)
+        public TopDocs search(Query query, MatchFilter filter, int nDocs)
         throws IOException {
             BooleanQuery bq = new BooleanQuery();
             bq.add(query, BooleanClause.Occur.MUST);
Index: src/test/org/apache/lucene/search/TestRemoteCachingWrapperFilter.java
===================================================================
--- src/test/org/apache/lucene/search/TestRemoteCachingWrapperFilter.java	(revision 573048)
+++ src/test/org/apache/lucene/search/TestRemoteCachingWrapperFilter.java	(working copy)
@@ -77,7 +77,7 @@
     Naming.rebind("//localhost/Searchable", impl);
   }
 
-  private static void search(Query query, Filter filter, int hitNumber, String typeValue) throws Exception {
+  private static void search(Query query, MatchFilter filter, int hitNumber, String typeValue) throws Exception {
     Searchable[] searchables = { getRemote() };
     Searcher searcher = new MultiSearcher(searchables);
     Hits result = searcher.search(query,filter);
Index: src/test/org/apache/lucene/search/TestCachingWrapperFilter.java
===================================================================
--- src/test/org/apache/lucene/search/TestCachingWrapperFilter.java	(revision 573048)
+++ 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.getMatcher(reader);
     assertTrue("first time", filter.wasCalled());
 
     // second time, nested filter should not be called
     filter.clear();
-    cacher.bits(reader);
+    cacher.getMatcher(reader);
     assertFalse("second time", filter.wasCalled());
 
     reader.close();
