You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by us...@apache.org on 2011/09/25 14:48:57 UTC

svn commit: r1175385 - in /lucene/dev/trunk: lucene/contrib/ modules/queries/src/java/org/apache/lucene/queries/ modules/queries/src/test/org/apache/lucene/queries/

Author: uschindler
Date: Sun Sep 25 12:48:56 2011
New Revision: 1175385

URL: http://svn.apache.org/viewvc?rev=1175385&view=rev
Log:
LUCENE-3458: Change BooleanFilter to have only a single clauses ArrayList (so toString() works in order). It now behaves more like BooleanQuery, implements Iterable<FilterClause>, and allows adding Filters without creating FilterClause. Also cleaned up formatting and Test.

Modified:
    lucene/dev/trunk/lucene/contrib/CHANGES.txt
    lucene/dev/trunk/modules/queries/src/java/org/apache/lucene/queries/BooleanFilter.java
    lucene/dev/trunk/modules/queries/src/java/org/apache/lucene/queries/FilterClause.java
    lucene/dev/trunk/modules/queries/src/test/org/apache/lucene/queries/BooleanFilterTest.java

Modified: lucene/dev/trunk/lucene/contrib/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/CHANGES.txt?rev=1175385&r1=1175384&r2=1175385&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/CHANGES.txt (original)
+++ lucene/dev/trunk/lucene/contrib/CHANGES.txt Sun Sep 25 12:48:56 2011
@@ -90,6 +90,11 @@ New Features
 
  * LUCENE-1889: Add MultiTermQuery support for FVH. (Mike Sokolov via Koji Sekiguchi)
 
+ * LUCENE-3458: Change BooleanFilter to have only a single clauses ArrayList
+   (so toString() works in order). It now behaves more like BooleanQuery,
+   implements Iterable<FilterClause>, and allows adding Filters without
+   creating FilterClause.  (Uwe Schindler)
+
 Bug Fixes
 
  * LUCENE-3417: DictionaryCompoundWordFilter did not properly add tokens from the

Modified: lucene/dev/trunk/modules/queries/src/java/org/apache/lucene/queries/BooleanFilter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/modules/queries/src/java/org/apache/lucene/queries/BooleanFilter.java?rev=1175385&r1=1175384&r2=1175385&view=diff
==============================================================================
--- lucene/dev/trunk/modules/queries/src/java/org/apache/lucene/queries/BooleanFilter.java (original)
+++ lucene/dev/trunk/modules/queries/src/java/org/apache/lucene/queries/BooleanFilter.java Sun Sep 25 12:48:56 2011
@@ -20,6 +20,7 @@ package org.apache.lucene.queries;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Iterator;
 
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
@@ -38,11 +39,9 @@ import org.apache.lucene.util.FixedBitSe
  * The resulting Filter is NOT'd with the NOT Filters
  * The resulting Filter is AND'd with the MUST Filters
  */
-public class BooleanFilter extends Filter {
+public class BooleanFilter extends Filter implements Iterable<FilterClause> {
 
-  List<Filter> shouldFilters = null;
-  List<Filter> notFilters = null;
-  List<Filter> mustFilters = null;
+  private final List<FilterClause> clauses = new ArrayList<FilterClause>();
 
   /**
    * Returns the a DocIdSetIterator representing the Boolean composition
@@ -52,9 +51,10 @@ public class BooleanFilter extends Filte
   public DocIdSet getDocIdSet(AtomicReaderContext context) throws IOException {
     FixedBitSet res = null;
     final IndexReader reader = context.reader;
-    if (shouldFilters != null) {
-      for (int i = 0; i < shouldFilters.size(); i++) {
-        final DocIdSetIterator disi = getDISI(shouldFilters, i, context);
+    
+    for (final FilterClause fc : clauses) {
+      if (fc.getOccur() == Occur.SHOULD) {
+        final DocIdSetIterator disi = getDISI(fc.getFilter(), context);
         if (disi == null) continue;
         if (res == null) {
           res = new FixedBitSet(reader.maxDoc());
@@ -63,22 +63,22 @@ public class BooleanFilter extends Filte
       }
     }
     
-    if (notFilters != null) {
-      for (int i = 0; i < notFilters.size(); i++) {
+    for (final FilterClause fc : clauses) {
+      if (fc.getOccur() == Occur.MUST_NOT) {
         if (res == null) {
           res = new FixedBitSet(reader.maxDoc());
           res.set(0, reader.maxDoc()); // NOTE: may set bits on deleted docs
         }
-        final DocIdSetIterator disi = getDISI(notFilters, i, context);
+        final DocIdSetIterator disi = getDISI(fc.getFilter(), context);
         if (disi != null) {
           res.andNot(disi);
         }
       }
     }
     
-    if (mustFilters != null) {
-      for (int i = 0; i < mustFilters.size(); i++) {
-        final DocIdSetIterator disi = getDISI(mustFilters, i, context);
+    for (final FilterClause fc : clauses) {
+      if (fc.getOccur() == Occur.MUST) {
+        final DocIdSetIterator disi = getDISI(fc.getFilter(), context);
         if (disi == null) {
           return DocIdSet.EMPTY_DOCIDSET; // no documents can match
         }
@@ -94,35 +94,39 @@ public class BooleanFilter extends Filte
     return res != null ? res : DocIdSet.EMPTY_DOCIDSET;
   }
 
+  private static DocIdSetIterator getDISI(Filter filter, AtomicReaderContext context)
+      throws IOException {
+    final DocIdSet set = filter.getDocIdSet(context);
+    return (set == null || set == DocIdSet.EMPTY_DOCIDSET) ? null : set.iterator();
+  }
+
   /**
   * Adds a new FilterClause to the Boolean Filter container
   * @param filterClause A FilterClause object containing a Filter and an Occur parameter
   */
   public void add(FilterClause filterClause) {
-    if (filterClause.getOccur().equals(Occur.MUST)) {
-      if (mustFilters == null) {
-        mustFilters = new ArrayList<Filter>();
-      }
-      mustFilters.add(filterClause.getFilter());
-    } else if (filterClause.getOccur().equals(Occur.SHOULD)) {
-      if (shouldFilters == null) {
-        shouldFilters = new ArrayList<Filter>();
-      }
-      shouldFilters.add(filterClause.getFilter());
-    } else if (filterClause.getOccur().equals(Occur.MUST_NOT)) {
-      if (notFilters == null) {
-        notFilters = new ArrayList<Filter>();
-      }
-      notFilters.add(filterClause.getFilter());
-    }
+    clauses.add(filterClause);
   }
-
-  private DocIdSetIterator getDISI(List<Filter> filters, int index, AtomicReaderContext context)
-      throws IOException {
-    final DocIdSet set = filters.get(index).getDocIdSet(context);
-    return (set == null) ? null : set.iterator();
+  
+  public final void add(Filter filter, Occur occur) {
+    add(new FilterClause(filter, occur));
   }
   
+  /**
+  * Returns the list of clauses
+  */
+  public List<FilterClause> clauses() {
+    return clauses;
+  }
+  
+  /** Returns an iterator on the clauses in this query. It implements the {@link Iterable} interface to
+   * make it possible to do:
+   * <pre>for (FilterClause clause : booleanFilter) {}</pre>
+   */
+  public final Iterator<FilterClause> iterator() {
+    return clauses().iterator();
+  }
+
   @Override
   public boolean equals(Object obj) {
     if (this == obj) {
@@ -133,44 +137,26 @@ public class BooleanFilter extends Filte
       return false;
     }
 
-    BooleanFilter other = (BooleanFilter)obj;
-    return equalFilters(notFilters, other.notFilters)
-        && equalFilters(mustFilters, other.mustFilters)
-        && equalFilters(shouldFilters, other.shouldFilters);
-  }
-
-  private boolean equalFilters(List<Filter> filters1, List<Filter> filters2) {
-    return (filters1 == filters2) || ((filters1 != null) && filters1.equals(filters2));
+    final BooleanFilter other = (BooleanFilter)obj;
+    return clauses.equals(other.clauses);
   }
 
   @Override
   public int hashCode() {
-    int hash = 7;
-    hash = 31 * hash + (null == mustFilters ? 0 : mustFilters.hashCode());
-    hash = 31 * hash + (null == notFilters ? 0 : notFilters.hashCode());
-    hash = 31 * hash + (null == shouldFilters ? 0 : shouldFilters.hashCode());
-    return hash;
+    return 657153718 ^ clauses.hashCode();
   }
   
-  /** Prints a user-readable version of this query. */
+  /** Prints a user-readable version of this Filter. */
   @Override
   public String toString() {
-    StringBuilder buffer = new StringBuilder();
-    buffer.append("BooleanFilter(");
-    appendFilters(shouldFilters, "", buffer);
-    appendFilters(mustFilters, "+", buffer);
-    appendFilters(notFilters, "-", buffer);
-    buffer.append(")");
-    return buffer.toString();
-  }
-  
-  private void appendFilters(List<Filter> filters, String occurString, StringBuilder buffer) {
-    if (filters != null) {
-      for (Filter filter : filters) {
+    final StringBuilder buffer = new StringBuilder("BooleanFilter(");
+    final int minLen = buffer.length();
+    for (final FilterClause c : clauses) {
+      if (buffer.length() > minLen) {
         buffer.append(' ');
-        buffer.append(occurString);
-        buffer.append(filter.toString());
       }
+      buffer.append(c);
     }
-  }    
+    return buffer.append(')').toString();
+  }
 }

Modified: lucene/dev/trunk/modules/queries/src/java/org/apache/lucene/queries/FilterClause.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/modules/queries/src/java/org/apache/lucene/queries/FilterClause.java?rev=1175385&r1=1175384&r2=1175385&view=diff
==============================================================================
--- lucene/dev/trunk/modules/queries/src/java/org/apache/lucene/queries/FilterClause.java (original)
+++ lucene/dev/trunk/modules/queries/src/java/org/apache/lucene/queries/FilterClause.java Sun Sep 25 12:48:56 2011
@@ -26,36 +26,57 @@ import org.apache.lucene.search.Filter;
  * (Follows the boolean logic in BooleanClause for composition 
  * of queries.)
  */
-public class FilterClause {
+public final class FilterClause {
 
-	private final Occur occur;
-	private final Filter filter;
+  private final Occur occur;
+  private final Filter filter;
 
-	/**
-	 * Create a new FilterClause
-	 * @param filter A Filter object containing a BitSet
-	 * @param occur A parameter implementation indicating SHOULD, MUST or MUST NOT
-	 */
-	
-	public FilterClause(Filter filter, Occur occur) {
-		this.occur = occur;
-		this.filter = filter;
-	}
-
-	/**
-	 * Returns this FilterClause's filter
-	 * @return A Filter object
-	 */
-	public Filter getFilter() {
-		return filter;
-	}
-
-	/**
-	 * Returns this FilterClause's occur parameter
-	 * @return An Occur object
-	 */
-	public Occur getOccur() {
-		return occur;
-	}
+  /**
+   * Create a new FilterClause
+   * @param filter A Filter object containing a BitSet
+   * @param occur A parameter implementation indicating SHOULD, MUST or MUST NOT
+   */
+
+  public FilterClause(Filter filter, Occur occur) {
+    this.occur = occur;
+    this.filter = filter;
+  }
+
+  /**
+   * Returns this FilterClause's filter
+   * @return A Filter object
+   */
+  public Filter getFilter() {
+    return filter;
+  }
+
+  /**
+   * Returns this FilterClause's occur parameter
+   * @return An Occur object
+   */
+  public Occur getOccur() {
+    return occur;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == this)
+      return true;
+    if (o == null || !(o instanceof FilterClause))
+      return false;
+    final FilterClause other = (FilterClause)o;
+    return this.filter.equals(other.filter)
+      && this.occur == other.occur;
+  }
+
+  @Override
+  public int hashCode() {
+    return filter.hashCode() ^ occur.hashCode();
+  }
+
+  @Override
+  public String toString() {
+    return occur.toString() + filter.toString();
+  }
 
 }

Modified: lucene/dev/trunk/modules/queries/src/test/org/apache/lucene/queries/BooleanFilterTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/modules/queries/src/test/org/apache/lucene/queries/BooleanFilterTest.java?rev=1175385&r1=1175384&r2=1175385&view=diff
==============================================================================
--- lucene/dev/trunk/modules/queries/src/test/org/apache/lucene/queries/BooleanFilterTest.java (original)
+++ lucene/dev/trunk/modules/queries/src/test/org/apache/lucene/queries/BooleanFilterTest.java Sun Sep 25 12:48:56 2011
@@ -26,7 +26,7 @@ import org.apache.lucene.index.IndexRead
 import org.apache.lucene.index.RandomIndexWriter;
 import org.apache.lucene.index.SlowMultiReaderWrapper;
 import org.apache.lucene.index.Term;
-import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.lucene.search.DocIdSetIterator;
 import org.apache.lucene.search.Filter;
 import org.apache.lucene.search.TermRangeFilter;
@@ -120,7 +120,7 @@ public class BooleanFilterTest extends L
   }
 
   private void tstFilterCard(String mes, int expected, Filter filt)
-      throws Throwable {
+      throws Exception {
     // BooleanFilter never returns null DIS or null DISI!
     DocIdSetIterator disi = filt.getDocIdSet(new AtomicReaderContext(reader)).iterator();
     int actual = 0;
@@ -131,176 +131,181 @@ public class BooleanFilterTest extends L
   }
 
 
-  public void testShould() throws Throwable {
+  public void testShould() throws Exception {
     BooleanFilter booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getTermsFilter("price", "030"), BooleanClause.Occur.SHOULD));
+    booleanFilter.add(getTermsFilter("price", "030"), Occur.SHOULD);
     tstFilterCard("Should retrieves only 1 doc", 1, booleanFilter);
     
     // same with a real DISI (no OpenBitSetIterator)
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getWrappedTermQuery("price", "030"), BooleanClause.Occur.SHOULD));
+    booleanFilter.add(getWrappedTermQuery("price", "030"), Occur.SHOULD);
     tstFilterCard("Should retrieves only 1 doc", 1, booleanFilter);
   }
 
-  public void testShoulds() throws Throwable {
+  public void testShoulds() throws Exception {
     BooleanFilter booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "010", "020"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "020", "030"), BooleanClause.Occur.SHOULD));
+    booleanFilter.add(getRangeFilter("price", "010", "020"), Occur.SHOULD);
+    booleanFilter.add(getRangeFilter("price", "020", "030"), Occur.SHOULD);
     tstFilterCard("Shoulds are Ored together", 5, booleanFilter);
   }
 
-  public void testShouldsAndMustNot() throws Throwable {
+  public void testShouldsAndMustNot() throws Exception {
     BooleanFilter booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "010", "020"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "020", "030"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getTermsFilter("inStock", "N"), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getRangeFilter("price", "010", "020"), Occur.SHOULD);
+    booleanFilter.add(getRangeFilter("price", "020", "030"), Occur.SHOULD);
+    booleanFilter.add(getTermsFilter("inStock", "N"), Occur.MUST_NOT);
     tstFilterCard("Shoulds Ored but AndNot", 4, booleanFilter);
 
-    booleanFilter.add(new FilterClause(getTermsFilter("inStock", "Maybe"), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getTermsFilter("inStock", "Maybe"), Occur.MUST_NOT);
     tstFilterCard("Shoulds Ored but AndNots", 3, booleanFilter);
     
     // same with a real DISI (no OpenBitSetIterator)
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "010", "020"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "020", "030"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getWrappedTermQuery("inStock", "N"), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getRangeFilter("price", "010", "020"), Occur.SHOULD);
+    booleanFilter.add(getRangeFilter("price", "020", "030"), Occur.SHOULD);
+    booleanFilter.add(getWrappedTermQuery("inStock", "N"), Occur.MUST_NOT);
     tstFilterCard("Shoulds Ored but AndNot", 4, booleanFilter);
 
-    booleanFilter.add(new FilterClause(getWrappedTermQuery("inStock", "Maybe"), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getWrappedTermQuery("inStock", "Maybe"), Occur.MUST_NOT);
     tstFilterCard("Shoulds Ored but AndNots", 3, booleanFilter);
   }
 
-  public void testShouldsAndMust() throws Throwable {
+  public void testShouldsAndMust() throws Exception {
     BooleanFilter booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "010", "020"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "020", "030"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getTermsFilter("accessRights", "admin"), BooleanClause.Occur.MUST));
+    booleanFilter.add(getRangeFilter("price", "010", "020"), Occur.SHOULD);
+    booleanFilter.add(getRangeFilter("price", "020", "030"), Occur.SHOULD);
+    booleanFilter.add(getTermsFilter("accessRights", "admin"), Occur.MUST);
     tstFilterCard("Shoulds Ored but MUST", 3, booleanFilter);
     
     // same with a real DISI (no OpenBitSetIterator)
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "010", "020"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "020", "030"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getWrappedTermQuery("accessRights", "admin"), BooleanClause.Occur.MUST));
+    booleanFilter.add(getRangeFilter("price", "010", "020"), Occur.SHOULD);
+    booleanFilter.add(getRangeFilter("price", "020", "030"), Occur.SHOULD);
+    booleanFilter.add(getWrappedTermQuery("accessRights", "admin"), Occur.MUST);
     tstFilterCard("Shoulds Ored but MUST", 3, booleanFilter);
   }
 
-  public void testShouldsAndMusts() throws Throwable {
+  public void testShouldsAndMusts() throws Exception {
     BooleanFilter booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "010", "020"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "020", "030"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getTermsFilter("accessRights", "admin"), BooleanClause.Occur.MUST));
-    booleanFilter.add(new FilterClause(getRangeFilter("date", "20040101", "20041231"), BooleanClause.Occur.MUST));
+    booleanFilter.add(getRangeFilter("price", "010", "020"), Occur.SHOULD);
+    booleanFilter.add(getRangeFilter("price", "020", "030"), Occur.SHOULD);
+    booleanFilter.add(getTermsFilter("accessRights", "admin"), Occur.MUST);
+    booleanFilter.add(getRangeFilter("date", "20040101", "20041231"), Occur.MUST);
     tstFilterCard("Shoulds Ored but MUSTs ANDED", 1, booleanFilter);
   }
 
-  public void testShouldsAndMustsAndMustNot() throws Throwable {
+  public void testShouldsAndMustsAndMustNot() throws Exception {
     BooleanFilter booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "030", "040"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getTermsFilter("accessRights", "admin"), BooleanClause.Occur.MUST));
-    booleanFilter.add(new FilterClause(getRangeFilter("date", "20050101", "20051231"), BooleanClause.Occur.MUST));
-    booleanFilter.add(new FilterClause(getTermsFilter("inStock", "N"), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getRangeFilter("price", "030", "040"), Occur.SHOULD);
+    booleanFilter.add(getTermsFilter("accessRights", "admin"), Occur.MUST);
+    booleanFilter.add(getRangeFilter("date", "20050101", "20051231"), Occur.MUST);
+    booleanFilter.add(getTermsFilter("inStock", "N"), Occur.MUST_NOT);
     tstFilterCard("Shoulds Ored but MUSTs ANDED and MustNot", 0, booleanFilter);
     
     // same with a real DISI (no OpenBitSetIterator)
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getRangeFilter("price", "030", "040"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getWrappedTermQuery("accessRights", "admin"), BooleanClause.Occur.MUST));
-    booleanFilter.add(new FilterClause(getRangeFilter("date", "20050101", "20051231"), BooleanClause.Occur.MUST));
-    booleanFilter.add(new FilterClause(getWrappedTermQuery("inStock", "N"), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getRangeFilter("price", "030", "040"), Occur.SHOULD);
+    booleanFilter.add(getWrappedTermQuery("accessRights", "admin"), Occur.MUST);
+    booleanFilter.add(getRangeFilter("date", "20050101", "20051231"), Occur.MUST);
+    booleanFilter.add(getWrappedTermQuery("inStock", "N"), Occur.MUST_NOT);
     tstFilterCard("Shoulds Ored but MUSTs ANDED and MustNot", 0, booleanFilter);
   }
 
-  public void testJustMust() throws Throwable {
+  public void testJustMust() throws Exception {
     BooleanFilter booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getTermsFilter("accessRights", "admin"), BooleanClause.Occur.MUST));
+    booleanFilter.add(getTermsFilter("accessRights", "admin"), Occur.MUST);
     tstFilterCard("MUST", 3, booleanFilter);
     
     // same with a real DISI (no OpenBitSetIterator)
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getWrappedTermQuery("accessRights", "admin"), BooleanClause.Occur.MUST));
+    booleanFilter.add(getWrappedTermQuery("accessRights", "admin"), Occur.MUST);
     tstFilterCard("MUST", 3, booleanFilter);
   }
 
-  public void testJustMustNot() throws Throwable {
+  public void testJustMustNot() throws Exception {
     BooleanFilter booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getTermsFilter("inStock", "N"), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getTermsFilter("inStock", "N"), Occur.MUST_NOT);
     tstFilterCard("MUST_NOT", 4, booleanFilter);
     
     // same with a real DISI (no OpenBitSetIterator)
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getWrappedTermQuery("inStock", "N"), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getWrappedTermQuery("inStock", "N"), Occur.MUST_NOT);
     tstFilterCard("MUST_NOT", 4, booleanFilter);
   }
 
-  public void testMustAndMustNot() throws Throwable {
+  public void testMustAndMustNot() throws Exception {
     BooleanFilter booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getTermsFilter("inStock", "N"), BooleanClause.Occur.MUST));
-    booleanFilter.add(new FilterClause(getTermsFilter("price", "030"), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getTermsFilter("inStock", "N"), Occur.MUST);
+    booleanFilter.add(getTermsFilter("price", "030"), Occur.MUST_NOT);
     tstFilterCard("MUST_NOT wins over MUST for same docs", 0, booleanFilter);
     
     // same with a real DISI (no OpenBitSetIterator)
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getWrappedTermQuery("inStock", "N"), BooleanClause.Occur.MUST));
-    booleanFilter.add(new FilterClause(getWrappedTermQuery("price", "030"), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getWrappedTermQuery("inStock", "N"), Occur.MUST);
+    booleanFilter.add(getWrappedTermQuery("price", "030"), Occur.MUST_NOT);
     tstFilterCard("MUST_NOT wins over MUST for same docs", 0, booleanFilter);
   }
 
-  public void testCombinedNullDocIdSets() throws Throwable {
+  public void testEmpty() throws Exception {
     BooleanFilter booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getTermsFilter("price", "030"), BooleanClause.Occur.MUST));
-    booleanFilter.add(new FilterClause(getNullDISFilter(), BooleanClause.Occur.MUST));
+    tstFilterCard("empty BooleanFilter returns no results", 0, booleanFilter);
+  }
+
+  public void testCombinedNullDocIdSets() throws Exception {
+    BooleanFilter booleanFilter = new BooleanFilter();
+    booleanFilter.add(getTermsFilter("price", "030"), Occur.MUST);
+    booleanFilter.add(getNullDISFilter(), Occur.MUST);
     tstFilterCard("A MUST filter that returns a null DIS should never return documents", 0, booleanFilter);
     
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getTermsFilter("price", "030"), BooleanClause.Occur.MUST));
-    booleanFilter.add(new FilterClause(getNullDISIFilter(), BooleanClause.Occur.MUST));
+    booleanFilter.add(getTermsFilter("price", "030"), Occur.MUST);
+    booleanFilter.add(getNullDISIFilter(), Occur.MUST);
     tstFilterCard("A MUST filter that returns a null DISI should never return documents", 0, booleanFilter);
     
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getTermsFilter("price", "030"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getNullDISFilter(), BooleanClause.Occur.SHOULD));
+    booleanFilter.add(getTermsFilter("price", "030"), Occur.SHOULD);
+    booleanFilter.add(getNullDISFilter(), Occur.SHOULD);
     tstFilterCard("A SHOULD filter that returns a null DIS should be invisible", 1, booleanFilter);
     
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getTermsFilter("price", "030"), BooleanClause.Occur.SHOULD));
-    booleanFilter.add(new FilterClause(getNullDISIFilter(), BooleanClause.Occur.SHOULD));
+    booleanFilter.add(getTermsFilter("price", "030"), Occur.SHOULD);
+    booleanFilter.add(getNullDISIFilter(), Occur.SHOULD);
     tstFilterCard("A SHOULD filter that returns a null DISI should be invisible", 1, booleanFilter);
     
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getTermsFilter("price", "030"), BooleanClause.Occur.MUST));
-    booleanFilter.add(new FilterClause(getNullDISFilter(), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getTermsFilter("price", "030"), Occur.MUST);
+    booleanFilter.add(getNullDISFilter(), Occur.MUST_NOT);
     tstFilterCard("A MUST_NOT filter that returns a null DIS should be invisible", 1, booleanFilter);
     
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getTermsFilter("price", "030"), BooleanClause.Occur.MUST));
-    booleanFilter.add(new FilterClause(getNullDISIFilter(), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getTermsFilter("price", "030"), Occur.MUST);
+    booleanFilter.add(getNullDISIFilter(), Occur.MUST_NOT);
     tstFilterCard("A MUST_NOT filter that returns a null DISI should be invisible", 1, booleanFilter);
   }
 
-  public void testJustNullDocIdSets() throws Throwable {
+  public void testJustNullDocIdSets() throws Exception {
     BooleanFilter booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getNullDISFilter(), BooleanClause.Occur.MUST));
+    booleanFilter.add(getNullDISFilter(), Occur.MUST);
     tstFilterCard("A MUST filter that returns a null DIS should never return documents", 0, booleanFilter);
     
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getNullDISIFilter(), BooleanClause.Occur.MUST));
+    booleanFilter.add(getNullDISIFilter(), Occur.MUST);
     tstFilterCard("A MUST filter that returns a null DISI should never return documents", 0, booleanFilter);
     
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getNullDISFilter(), BooleanClause.Occur.SHOULD));
+    booleanFilter.add(getNullDISFilter(), Occur.SHOULD);
     tstFilterCard("A single SHOULD filter that returns a null DIS should never return documents", 0, booleanFilter);
     
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getNullDISIFilter(), BooleanClause.Occur.SHOULD));
+    booleanFilter.add(getNullDISIFilter(), Occur.SHOULD);
     tstFilterCard("A single SHOULD filter that returns a null DISI should never return documents", 0, booleanFilter);
     
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getNullDISFilter(), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getNullDISFilter(), Occur.MUST_NOT);
     tstFilterCard("A single MUST_NOT filter that returns a null DIS should be invisible", 5, booleanFilter);
     
     booleanFilter = new BooleanFilter();
-    booleanFilter.add(new FilterClause(getNullDISIFilter(), BooleanClause.Occur.MUST_NOT));
+    booleanFilter.add(getNullDISIFilter(), Occur.MUST_NOT);
     tstFilterCard("A single MUST_NOT filter that returns a null DIS should be invisible", 5, booleanFilter);
   }
 }