Index: src/java/org/apache/lucene/index/AllTermDocs.java
===================================================================
--- src/java/org/apache/lucene/index/AllTermDocs.java	(revision 766912)
+++ src/java/org/apache/lucene/index/AllTermDocs.java	(working copy)
@@ -17,6 +17,9 @@
 
 package org.apache.lucene.index;
 
+import org.apache.lucene.search.AndRandomAccessDocIdSet;
+import org.apache.lucene.search.NotRandomAccessDocIdSet;
+import org.apache.lucene.search.RandomAccessDocIdSet;
 import org.apache.lucene.util.BitVector;
 import java.io.IOException;
 
@@ -24,14 +27,31 @@
   protected BitVector deletedDocs;
   protected int maxDoc;
   protected int doc = -1;
+  protected RandomAccessDocIdSet randomAccessDocIdSet;
 
   protected AllTermDocs(SegmentReader parent) {
     synchronized (parent) {
       this.deletedDocs = parent.deletedDocs;
+      if (deletedDocs != null) {
+        randomAccessDocIdSet = new NotRandomAccessDocIdSet(deletedDocs);
+      }
     }
     this.maxDoc = parent.maxDoc();
   }
-
+  
+  /**
+   * 
+   * @param randomAccessDocIdSet Doc id set to use
+   * @param andSegmentDeletes If true, we build a RandomAccessDocIdSet that also has the deletedDocs
+   */
+  void setRandomAccessDocIdSet(RandomAccessDocIdSet randomAccessDocIdSet, boolean andSegmentDeletes) {
+    if (andSegmentDeletes && deletedDocs != null) {
+      this.randomAccessDocIdSet = new AndRandomAccessDocIdSet(new RandomAccessDocIdSet[] {randomAccessDocIdSet, new NotRandomAccessDocIdSet(deletedDocs)});
+    } else {
+      this.randomAccessDocIdSet = randomAccessDocIdSet;
+    }
+  }
+  
   public void seek(Term term) throws IOException {
     if (term==null) {
       doc = -1;
@@ -60,7 +80,7 @@
     final int length = docs.length;
     int i = 0;
     while (i < length && doc < maxDoc) {
-      if (deletedDocs == null || !deletedDocs.get(doc)) {
+      if (randomAccessDocIdSet == null || randomAccessDocIdSet.get(doc)) {
         docs[i] = doc;
         freqs[i] = 1;
         ++i;
@@ -73,7 +93,7 @@
   public boolean skipTo(int target) throws IOException {
     doc = target;
     while (doc < maxDoc) {
-      if (deletedDocs == null || !deletedDocs.get(doc)) {
+      if (randomAccessDocIdSet == null || randomAccessDocIdSet.get(doc)) {
         return true;
       }
       doc++;
Index: src/java/org/apache/lucene/index/SegmentTermDocs.java
===================================================================
--- src/java/org/apache/lucene/index/SegmentTermDocs.java	(revision 766912)
+++ src/java/org/apache/lucene/index/SegmentTermDocs.java	(working copy)
@@ -18,8 +18,12 @@
  */
 
 import java.io.IOException;
+
+import org.apache.lucene.search.AndRandomAccessDocIdSet;
+import org.apache.lucene.search.NotRandomAccessDocIdSet;
+import org.apache.lucene.search.RandomAccessDocIdSet;
+import org.apache.lucene.store.IndexInput;
 import org.apache.lucene.util.BitVector;
-import org.apache.lucene.store.IndexInput;
 
 class SegmentTermDocs implements TermDocs {
   protected SegmentReader parent;
@@ -42,17 +46,34 @@
   
   protected boolean currentFieldStoresPayloads;
   protected boolean currentFieldOmitTermFreqAndPositions;
+  protected RandomAccessDocIdSet randomAccessDocIdSet;
   
   protected SegmentTermDocs(SegmentReader parent) {
     this.parent = parent;
     this.freqStream = (IndexInput) parent.freqStream.clone();
     synchronized (parent) {
       this.deletedDocs = parent.deletedDocs;
+      if (deletedDocs != null) {
+        randomAccessDocIdSet = new NotRandomAccessDocIdSet(deletedDocs);
+      }
     }
     this.skipInterval = parent.tis.getSkipInterval();
     this.maxSkipLevels = parent.tis.getMaxSkipLevels();
   }
-
+  
+  /**
+   * 
+   * @param randomAccessDocIdSet Doc id set to use
+   * @param andSegmentDeletes If true, we build a RandomAccessDocIdSet that also has the deletedDocs
+   */
+  void setRandomAccessDocIdSet(RandomAccessDocIdSet randomAccessDocIdSet, boolean andSegmentDeletes) {
+    if (andSegmentDeletes && deletedDocs != null) {
+      this.randomAccessDocIdSet = new AndRandomAccessDocIdSet(new RandomAccessDocIdSet[] {randomAccessDocIdSet, new NotRandomAccessDocIdSet(deletedDocs)});
+    } else {
+      this.randomAccessDocIdSet = randomAccessDocIdSet;
+    }
+  }
+  
   public void seek(Term term) throws IOException {
     TermInfo ti = parent.tis.get(term);
     seek(ti, term);
@@ -124,7 +145,7 @@
       
       count++;
 
-      if (deletedDocs == null || !deletedDocs.get(doc))
+      if (randomAccessDocIdSet == null || randomAccessDocIdSet.get(doc))
         break;
       skippingDoc();
     }
@@ -149,7 +170,7 @@
           freq = freqStream.readVInt();     // else read freq
         count++;
 
-        if (deletedDocs == null || !deletedDocs.get(doc)) {
+        if (randomAccessDocIdSet == null || randomAccessDocIdSet.get(doc)) {
           docs[i] = doc;
           freqs[i] = freq;
           ++i;
@@ -166,7 +187,7 @@
       doc += freqStream.readVInt();       
       count++;
 
-      if (deletedDocs == null || !deletedDocs.get(doc)) {
+      if (randomAccessDocIdSet == null || randomAccessDocIdSet.get(doc)) {
         docs[i] = doc;
         // Hardware freq to 1 when term freqs were not
         // stored in the index
Index: src/java/org/apache/lucene/index/SegmentTermDocsUtil.java
===================================================================
--- src/java/org/apache/lucene/index/SegmentTermDocsUtil.java	(revision 0)
+++ src/java/org/apache/lucene/index/SegmentTermDocsUtil.java	(revision 0)
@@ -0,0 +1,18 @@
+package org.apache.lucene.index;
+
+import org.apache.lucene.search.RandomAccessDocIdSet;
+
+public class SegmentTermDocsUtil {
+  public static boolean setRandomAccessDocIdSet(TermDocs td, RandomAccessDocIdSet randomAccessDocIdSet, boolean andSegmentDeletes) {
+    if (td instanceof SegmentTermDocs) {
+      SegmentTermDocs std = (SegmentTermDocs)td;
+      std.setRandomAccessDocIdSet(randomAccessDocIdSet, andSegmentDeletes);
+      return true;
+    } else if (td instanceof AllTermDocs) {
+      AllTermDocs atd = (AllTermDocs)td;
+      atd.setRandomAccessDocIdSet(randomAccessDocIdSet, andSegmentDeletes);
+      return true;
+    }
+    return false;
+  }
+}
Index: src/java/org/apache/lucene/search/AndRandomAccessDocIdSet.java
===================================================================
--- src/java/org/apache/lucene/search/AndRandomAccessDocIdSet.java	(revision 0)
+++ src/java/org/apache/lucene/search/AndRandomAccessDocIdSet.java	(revision 0)
@@ -0,0 +1,24 @@
+package org.apache.lucene.search;
+
+import java.io.IOException;
+
+public final class AndRandomAccessDocIdSet extends RandomAccessDocIdSet {
+  private final RandomAccessDocIdSet[] subfilters;
+  
+  public AndRandomAccessDocIdSet(RandomAccessDocIdSet[] subfilters) {
+    this.subfilters = subfilters;
+  }
+  
+  public DocIdSetIterator iterator() throws IOException {
+    return null;
+  }
+  
+  public final boolean get(int doc) throws IOException {
+    for (int x=0; x < subfilters.length; x++) {
+      if (!subfilters[x].get(doc)) {
+        return false;
+      }
+    }
+    return true;
+  }
+}
Index: src/java/org/apache/lucene/search/BooleanScorer2.java
===================================================================
--- src/java/org/apache/lucene/search/BooleanScorer2.java	(revision 766912)
+++ src/java/org/apache/lucene/search/BooleanScorer2.java	(working copy)
@@ -411,6 +411,22 @@
     return countingSumScorer.explain(doc); // misses coord factor. 
   */
   }
+  
+  public static final Scorer[] subscorerEmptyArray = new Scorer[0];
+  
+  public Scorer[] getSequentialSubScorers() {
+    List subscorers = new ArrayList(requiredScorers.size()+optionalScorers.size()+prohibitedScorers.size());
+    for (int x=0; x < requiredScorers.size(); x++) {
+      subscorers.add((Scorer)requiredScorers.get(x));
+    }
+    for (int x=0; x < optionalScorers.size(); x++) {
+      subscorers.add((Scorer)optionalScorers.get(x));
+    }
+    for (int x=0; x < prohibitedScorers.size(); x++) {
+      subscorers.add((Scorer)prohibitedScorers.get(x));
+    }
+    return (Scorer[])subscorers.toArray(subscorerEmptyArray);
+  }
 }
 
 
Index: src/java/org/apache/lucene/search/DisjunctionMaxScorer.java
===================================================================
--- src/java/org/apache/lucene/search/DisjunctionMaxScorer.java	(revision 766912)
+++ src/java/org/apache/lucene/search/DisjunctionMaxScorer.java	(working copy)
@@ -190,5 +190,8 @@
             heapAdjust(0);
         }
     }
-
+    
+    public Scorer[] getSequentialSubScorers() {
+      return (Scorer[])subScorers.toArray(BooleanScorer2.subscorerEmptyArray); 
+    }
 }
Index: src/java/org/apache/lucene/search/DisjunctionSumScorer.java
===================================================================
--- src/java/org/apache/lucene/search/DisjunctionSumScorer.java	(revision 766912)
+++ src/java/org/apache/lucene/search/DisjunctionSumScorer.java	(working copy)
@@ -275,4 +275,8 @@
     }
     return res;
   }
+  
+  public Scorer[] getSequentialSubScorers() {
+    return (Scorer[])subScorers.toArray(BooleanScorer2.subscorerEmptyArray); 
+  }
 }
Index: src/java/org/apache/lucene/search/Filter.java
===================================================================
--- src/java/org/apache/lucene/search/Filter.java	(revision 766912)
+++ src/java/org/apache/lucene/search/Filter.java	(working copy)
@@ -31,6 +31,22 @@
  *  in order to work with Lucene 3.0.
  */
 public abstract class Filter implements java.io.Serializable {
+  private boolean includesDeletes = false;
+  
+  public Filter() {}
+  
+  public Filter(boolean includesDeletes) {
+    this.includesDeletes = includesDeletes;
+  }
+  
+  public void setIncludesDeletes(boolean includesDeletes) {
+    this.includesDeletes = includesDeletes;
+  }
+
+  public boolean isIncludesDeletes() {
+    return includesDeletes;
+  }
+
   /**
    * @return A BitSet with true for documents which should be permitted in
    * search results, and false for those that should not.
Index: src/java/org/apache/lucene/search/IndexSearcher.java
===================================================================
--- src/java/org/apache/lucene/search/IndexSearcher.java	(revision 766912)
+++ src/java/org/apache/lucene/search/IndexSearcher.java	(working copy)
@@ -258,14 +258,52 @@
     }
   }
   
+  protected void gatherSubScorers(List allSubScorers, Scorer s) {
+    Scorer[] subScorers = s.getSequentialSubScorers();
+    if (subScorers == null) {
+      // Add the scorer itself, and do not recurse
+      allSubScorers.add(s);
+    } else {
+      for(int i=0;i<subScorers.length;i++) {
+        gatherSubScorers(allSubScorers, subScorers[i]);
+      }
+    }
+  }
+  
+  protected RandomDocIdSetScorer[] getRandomDocIdSetScorers(Scorer scorer) {
+    List list = new ArrayList();
+    gatherSubScorers(list, scorer);
+    List randomDocIdSetScorers = new ArrayList();
+    for (int x=0; x < list.size(); x++) {
+      Scorer s = (Scorer)list.get(x);
+      if (s instanceof RandomDocIdSetScorer) {
+        randomDocIdSetScorers.add((RandomDocIdSetScorer)s);
+      }
+    }
+    return (RandomDocIdSetScorer[])randomDocIdSetScorers.toArray(new RandomDocIdSetScorer[0]);
+  }
+  
   private void doSearch(IndexReader reader, Weight weight, Filter filter,
       final Collector collector) throws IOException {
-
+   
     Scorer scorer = weight.scorer(reader);
+    boolean skipFilter = false;
+    if (filter != null) {
+      boolean andSegmentDeletes = !filter.isIncludesDeletes();
+      DocIdSet docIdSet = filter.getDocIdSet(reader);
+      if (docIdSet instanceof RandomAccessDocIdSet) {
+        skipFilter = true;
+        RandomAccessDocIdSet ra = (RandomAccessDocIdSet)docIdSet;
+        RandomDocIdSetScorer[] subscorers = getRandomDocIdSetScorers(scorer);
+        for (int x=0; x < subscorers.length; x++) {
+          subscorers[x].setRandomAccessDocIdSet(ra, andSegmentDeletes);
+        }
+      }
+    }
     if (scorer == null)
       return;
 
-    if (filter == null) {
+    if (filter == null || skipFilter) {
       scorer.score(collector);
       return;
     }
Index: src/java/org/apache/lucene/search/MatchAllDocsQuery.java
===================================================================
--- src/java/org/apache/lucene/search/MatchAllDocsQuery.java	(revision 766912)
+++ src/java/org/apache/lucene/search/MatchAllDocsQuery.java	(working copy)
@@ -18,6 +18,7 @@
  */
 
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.SegmentTermDocsUtil;
 import org.apache.lucene.index.TermDocs;
 import org.apache.lucene.util.ToStringUtils;
 
@@ -43,10 +44,11 @@
     this.normsField = normsField;
   }
 
-  private class MatchAllScorer extends Scorer {
+  private class MatchAllScorer extends Scorer implements RandomDocIdSetScorer {
     final TermDocs termDocs;
     final float score;
     final byte[] norms;
+    private RandomAccessDocIdSet randomAccessDocIdSet;
 
     MatchAllScorer(IndexReader reader, Similarity similarity, Weight w, byte[] norms) throws IOException
     {
@@ -55,7 +57,12 @@
       score = w.getValue();
       this.norms = norms;
     }
-
+    
+    public void setRandomAccessDocIdSet(RandomAccessDocIdSet randomAccessDocIdSet, boolean andSegmentDeletes) {
+      this.randomAccessDocIdSet = randomAccessDocIdSet;
+      SegmentTermDocsUtil.setRandomAccessDocIdSet(termDocs, randomAccessDocIdSet, andSegmentDeletes);
+    }
+    
     public Explanation explain(int doc) {
       return null; // not called... see MatchAllDocsWeight.explain()
     }
Index: src/java/org/apache/lucene/search/NotRandomAccessDocIdSet.java
===================================================================
--- src/java/org/apache/lucene/search/NotRandomAccessDocIdSet.java	(revision 0)
+++ src/java/org/apache/lucene/search/NotRandomAccessDocIdSet.java	(revision 0)
@@ -0,0 +1,19 @@
+package org.apache.lucene.search;
+
+import java.io.IOException;
+
+public final class NotRandomAccessDocIdSet extends RandomAccessDocIdSet {
+  private final RandomAccessDocIdSet set;
+  
+  public NotRandomAccessDocIdSet(RandomAccessDocIdSet set) {
+    this.set = set;
+  }
+  
+  public final boolean get(int doc) throws IOException {
+    return !set.get(doc);
+  }
+  
+  public DocIdSetIterator iterator() throws IOException {
+    return null;
+  }
+}
Index: src/java/org/apache/lucene/search/RandomAccessDocIdSet.java
===================================================================
--- src/java/org/apache/lucene/search/RandomAccessDocIdSet.java	(revision 0)
+++ src/java/org/apache/lucene/search/RandomAccessDocIdSet.java	(revision 0)
@@ -0,0 +1,7 @@
+package org.apache.lucene.search;
+
+import java.io.IOException;
+
+public abstract class RandomAccessDocIdSet extends DocIdSet {
+  public abstract boolean get(int doc) throws IOException;
+}
Index: src/java/org/apache/lucene/search/RandomDocIdSetScorer.java
===================================================================
--- src/java/org/apache/lucene/search/RandomDocIdSetScorer.java	(revision 0)
+++ src/java/org/apache/lucene/search/RandomDocIdSetScorer.java	(revision 0)
@@ -0,0 +1,5 @@
+package org.apache.lucene.search;
+
+public interface RandomDocIdSetScorer {
+  public void setRandomAccessDocIdSet(RandomAccessDocIdSet randomAccessDocIdSet, boolean andSegmentDeletes);
+}
Index: src/java/org/apache/lucene/search/Scorer.java
===================================================================
--- src/java/org/apache/lucene/search/Scorer.java	(revision 766912)
+++ src/java/org/apache/lucene/search/Scorer.java	(working copy)
@@ -98,7 +98,11 @@
     }
     return true;
   }
-
+  
+  public Scorer[] getSequentialSubScorers() {
+    return null;
+  }
+  
   /** Returns the score of the current document matching the query.
    * Initially invalid, until {@link #next()} or {@link #skipTo(int)}
    * is called the first time, or when called from within
Index: src/java/org/apache/lucene/search/TermScorer.java
===================================================================
--- src/java/org/apache/lucene/search/TermScorer.java	(revision 766912)
+++ src/java/org/apache/lucene/search/TermScorer.java	(working copy)
@@ -20,10 +20,11 @@
 import java.io.IOException;
 
 import org.apache.lucene.index.TermDocs;
+import org.apache.lucene.index.SegmentTermDocsUtil;
 
 /** Expert: A <code>Scorer</code> for documents matching a <code>Term</code>.
  */
-final class TermScorer extends Scorer {
+final class TermScorer extends Scorer implements RandomDocIdSetScorer {
   
   private static final float[] SIM_NORM_DECODER = Similarity.getNormDecoder();
   
@@ -40,6 +41,7 @@
 
   private static final int SCORE_CACHE_SIZE = 32;
   private float[] scoreCache = new float[SCORE_CACHE_SIZE];
+  private RandomAccessDocIdSet randomAccessDocIdSet;
 
   /** Construct a <code>TermScorer</code>.
    * @param weight The weight of the <code>Term</code> in the query.
@@ -59,6 +61,11 @@
       scoreCache[i] = getSimilarity().tf(i) * weightValue;
   }
 
+  public void setRandomAccessDocIdSet(RandomAccessDocIdSet randomAccessDocIdSet, boolean andSegmentDeletes) {
+    this.randomAccessDocIdSet = randomAccessDocIdSet;
+    SegmentTermDocsUtil.setRandomAccessDocIdSet(termDocs, randomAccessDocIdSet, andSegmentDeletes);
+  }
+  
   /** @deprecated use {@link #score(Collector)} instead. */
   public void score(HitCollector hc) throws IOException {
     score(new HitCollectorWrapper(hc));
Index: src/java/org/apache/lucene/util/BitVector.java
===================================================================
--- src/java/org/apache/lucene/util/BitVector.java	(revision 766912)
+++ src/java/org/apache/lucene/util/BitVector.java	(working copy)
@@ -19,6 +19,8 @@
 
 import java.io.IOException;
 
+import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.search.RandomAccessDocIdSet;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.IndexInput;
 import org.apache.lucene.store.IndexOutput;
@@ -35,7 +37,7 @@
 
   @version $Id$
   */
-public final class BitVector implements Cloneable {
+public final class BitVector extends RandomAccessDocIdSet implements Cloneable {
 
   private byte[] bits;
   private int size;
@@ -52,6 +54,10 @@
     this.size = size;
   }
   
+  public DocIdSetIterator iterator() throws IOException {
+    return null;
+  }
+  
   public Object clone() {
     byte[] copyBits = new byte[bits.length];
     System.arraycopy(bits, 0, copyBits, 0, bits.length);
Index: src/java/org/apache/lucene/util/OpenBitSet.java
===================================================================
--- src/java/org/apache/lucene/util/OpenBitSet.java	(revision 766912)
+++ src/java/org/apache/lucene/util/OpenBitSet.java	(working copy)
@@ -20,8 +20,8 @@
 import java.util.Arrays;
 import java.io.Serializable;
 
-import org.apache.lucene.search.DocIdSet;
 import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.search.RandomAccessDocIdSet;
 
 /** An "open" BitSet implementation that allows direct access to the array of words
  * storing the bits.
@@ -77,7 +77,7 @@
  * @version $Id$
  */
 
-public class OpenBitSet extends DocIdSet implements Cloneable, Serializable {
+public class OpenBitSet extends RandomAccessDocIdSet implements Cloneable, Serializable {
   protected long[] bits;
   protected int wlen;   // number of words (elements) used in the array
 
Index: src/test/org/apache/lucene/index/TestIndexWriterReader.java
===================================================================
--- src/test/org/apache/lucene/index/TestIndexWriterReader.java	(revision 766912)
+++ src/test/org/apache/lucene/index/TestIndexWriterReader.java	(working copy)
@@ -496,12 +496,13 @@
     StringBuffer sb = new StringBuffer();
     Document doc = new Document();
     doc.add(new Field("id", Integer.toString(n), Store.YES, Index.NOT_ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
-    doc.add(new Field("indexname", indexName, Store.YES, Index.NOT_ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
+    doc.add(new Field("indexname", indexName, Store.YES, Index.NOT_ANALYZED, TermVector.NO));
     sb.append("a");
     sb.append(n);
     doc.add(new Field("field1", sb.toString(), Store.YES, Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
     sb.append(" b");
     sb.append(n);
+    sb.append(" dog ");
     for (int i = 1; i < numFields; i++) {
       doc.add(new Field("field" + (i + 1), sb.toString(), Store.YES,
                         Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
@@ -519,12 +520,13 @@
    * reader.termDocs(term); int doc = -1; //if (td.next()) { // doc = td.doc();
    * //} //writer.deleteDocuments(term); td.close(); return doc; }
    */
+  
   public static void createIndex(Directory dir1, String indexName,
-      boolean multiSegment) throws IOException {
+      boolean multiSegment, int num) throws IOException {
     IndexWriter w = new IndexWriter(dir1, new WhitespaceAnalyzer(),
         IndexWriter.MaxFieldLength.LIMITED);
     w.setMergePolicy(new LogDocMergePolicy());
-    for (int i = 0; i < 100; i++) {
+    for (int i = 0; i < num; i++) {
       w.addDocument(createDocument(i, indexName, 4));
       if (multiSegment && (i % 10) == 0) {
       }
@@ -534,6 +536,11 @@
     }
     w.close();
   }
+  
+  public static void createIndex(Directory dir1, String indexName,
+      boolean multiSegment) throws IOException {
+    createIndex(dir1, indexName, multiSegment);
+  }
 
   public static void createIndexNoClose(boolean multiSegment, String indexName,
       IndexWriter w) throws IOException {
Index: src/test/org/apache/lucene/search/TestRandomAccessFilter.java
===================================================================
--- src/test/org/apache/lucene/search/TestRandomAccessFilter.java	(revision 0)
+++ src/test/org/apache/lucene/search/TestRandomAccessFilter.java	(revision 0)
@@ -0,0 +1,119 @@
+package org.apache.lucene.search;
+
+import java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TestIndexWriterReader;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.MockRAMDirectory;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.OpenBitSet;
+
+public class TestRandomAccessFilter extends LuceneTestCase {
+  public void testRandomAccessFilter() throws Exception {
+    Directory dir = new MockRAMDirectory();
+    TestIndexWriterReader.createIndex(dir, "index", true, 2000);
+    IndexReader r = IndexReader.open(dir);
+    IndexSearcher searcher = new IndexSearcher(r);
+    TopDocs topDocs = searcher.search(new TermQuery(new Term("indexname", "index")), null, 10);
+    assertEquals(2000, topDocs.totalHits);
+    
+    int num = 400;
+    TestFilter filter = new TestFilter(num);
+    
+    topDocs = searcher.search(new TermQuery(new Term("indexname", "index")), filter, 10);
+    assertEquals(num, topDocs.totalHits);
+    r.close();
+    dir.close();
+  }
+  
+  public void testMatchAllDocs() throws Exception {
+    Directory dir = new MockRAMDirectory();
+    TestIndexWriterReader.createIndex(dir, "index", true, 2000);
+    IndexReader r = IndexReader.open(dir);
+    IndexSearcher searcher = new IndexSearcher(r);
+    
+    int num = 400;
+    TestFilter filter = new TestFilter(num);
+    
+    TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), filter, 10);
+    assertEquals(num, topDocs.totalHits);
+    r.close();
+    dir.close();
+  }
+  
+  public void testBooleanScorerSetting() throws Exception {
+    Directory dir = new MockRAMDirectory();
+    TestIndexWriterReader.createIndex(dir, "index", true, 2000);
+    IndexReader r = IndexReader.open(dir);
+    IndexSearcher searcher = new IndexSearcher(r);
+    
+    int c = TestIndexWriterReader.count(new Term("field2", "dog"), r);
+    assertEquals(2000, c);
+    
+    TopDocs topDocs = searcher.search(new TermQuery(new Term("field2", "dog")), null, 10);
+    assertEquals(2000, topDocs.totalHits);
+    
+    BooleanQuery bq = new BooleanQuery();
+    bq.add(new TermQuery(new Term("indexname", "index")), BooleanClause.Occur.MUST);
+    bq.add(new TermQuery(new Term("field2", "dog")), BooleanClause.Occur.SHOULD);
+    topDocs = searcher.search(bq, null, 10);
+    assertEquals(2000, topDocs.totalHits);
+    
+    int num = 400;
+    TestFilter filter = new TestFilter(num);
+    
+    topDocs = searcher.search(new TermQuery(new Term("indexname", "index")), filter, 10);
+    assertEquals(num, topDocs.totalHits);
+    r.close();
+    dir.close();
+  }
+  
+  public void testIncludesDeletes() throws Exception {
+    Directory dir = new MockRAMDirectory();
+    TestIndexWriterReader.createIndex(dir, "index", true, 2000);
+    IndexReader r = IndexReader.open(dir);
+    IndexSearcher searcher = new IndexSearcher(r);
+    for (int x=0; x < 200; x++) {
+      r.deleteDocument(x);
+    }
+    int num = 400;
+    TestFilter filter = new TestFilter(num);
+    filter.setIncludesDeletes(true);
+    TopDocs topDocs = searcher.search(new TermQuery(new Term("indexname", "index")), filter, 10);
+    assertEquals(400, topDocs.totalHits);
+    r.close();
+    dir.close();
+  }
+  
+  public void testRandomAccessFilterDeletes() throws Exception {
+    Directory dir = new MockRAMDirectory();
+    TestIndexWriterReader.createIndex(dir, "index", true, 2000);
+    IndexReader r = IndexReader.open(dir);
+    for (int x=0; x < 200; x++) {
+      r.deleteDocument(x);
+    }
+    IndexSearcher searcher = new IndexSearcher(r);
+    TopDocs topDocs = searcher.search(new TermQuery(new Term("indexname", "index")), null, 10);
+    assertEquals(1800, topDocs.totalHits);
+    r.close();
+    dir.close();
+  }
+  
+  public static class TestFilter extends Filter { 
+    int num;
+    
+    public TestFilter(int num) {
+      this.num = num;
+    }
+    
+    public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
+      OpenBitSet bitSet = new OpenBitSet(reader.maxDoc());
+      for (int x=0; x < num; x++) {
+        bitSet.set(x);
+      }
+      return bitSet;
+    }
+  }
+}
