pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / contrib / queries / src / java / org / apache / lucene / search / BooleanFilter.java
1 package org.apache.lucene.search;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Iterator;
24
25 import org.apache.lucene.index.IndexReader;
26 import org.apache.lucene.search.BooleanClause.Occur;
27 import org.apache.lucene.util.FixedBitSet;
28
29 /**
30  * A container Filter that allows Boolean composition of Filters.
31  * Filters are allocated into one of three logical constructs;
32  * SHOULD, MUST NOT, MUST
33  * The results Filter BitSet is constructed as follows:
34  * SHOULD Filters are OR'd together
35  * The resulting Filter is NOT'd with the NOT Filters
36  * The resulting Filter is AND'd with the MUST Filters
37  */
38 public class BooleanFilter extends Filter implements Iterable<FilterClause> {
39
40   private final List<FilterClause> clauses = new ArrayList<FilterClause>();
41
42   /**
43    * Returns the a DocIdSetIterator representing the Boolean composition
44    * of the filters that have been added.
45    */
46   @Override
47   public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
48     FixedBitSet res = null;
49     
50     for (final FilterClause fc : clauses) {
51       if (fc.getOccur() == Occur.SHOULD) {
52         final DocIdSetIterator disi = getDISI(fc.getFilter(), reader);
53         if (disi == null) continue;
54         if (res == null) {
55           res = new FixedBitSet(reader.maxDoc());
56         }
57         res.or(disi);
58       }
59     }
60     
61     for (final FilterClause fc : clauses) {
62       if (fc.getOccur() == Occur.MUST_NOT) {
63         if (res == null) {
64           res = new FixedBitSet(reader.maxDoc());
65           res.set(0, reader.maxDoc()); // NOTE: may set bits on deleted docs
66         }
67         final DocIdSetIterator disi = getDISI(fc.getFilter(), reader);
68         if (disi != null) {
69           res.andNot(disi);
70         }
71       }
72     }
73     
74     for (final FilterClause fc : clauses) {
75       if (fc.getOccur() == Occur.MUST) {
76         final DocIdSetIterator disi = getDISI(fc.getFilter(), reader);
77         if (disi == null) {
78           return DocIdSet.EMPTY_DOCIDSET; // no documents can match
79         }
80         if (res == null) {
81           res = new FixedBitSet(reader.maxDoc());
82           res.or(disi);
83         } else {
84           res.and(disi);
85         }
86       }
87     }
88
89     return res != null ? res : DocIdSet.EMPTY_DOCIDSET;
90   }
91
92   private static DocIdSetIterator getDISI(Filter filter, IndexReader reader)
93       throws IOException {
94     final DocIdSet set = filter.getDocIdSet(reader);
95     return (set == null || set == DocIdSet.EMPTY_DOCIDSET) ? null : set.iterator();
96   }
97
98   /**
99   * Adds a new FilterClause to the Boolean Filter container
100   * @param filterClause A FilterClause object containing a Filter and an Occur parameter
101   */
102   public void add(FilterClause filterClause) {
103     clauses.add(filterClause);
104   }
105   
106   public final void add(Filter filter, Occur occur) {
107     add(new FilterClause(filter, occur));
108   }
109   
110   /**
111   * Returns the list of clauses
112   */
113   public List<FilterClause> clauses() {
114     return clauses;
115   }
116   
117   /** Returns an iterator on the clauses in this query. It implements the {@link Iterable} interface to
118    * make it possible to do:
119    * <pre>for (FilterClause clause : booleanFilter) {}</pre>
120    */
121   public final Iterator<FilterClause> iterator() {
122     return clauses().iterator();
123   }
124
125   @Override
126   public boolean equals(Object obj) {
127     if (this == obj) {
128       return true;
129     }
130
131     if ((obj == null) || (obj.getClass() != this.getClass())) {
132       return false;
133     }
134
135     final BooleanFilter other = (BooleanFilter)obj;
136     return clauses.equals(other.clauses);
137   }
138
139   @Override
140   public int hashCode() {
141     return 657153718 ^ clauses.hashCode();
142   }
143   
144   /** Prints a user-readable version of this Filter. */
145   @Override
146   public String toString() {
147     final StringBuilder buffer = new StringBuilder("BooleanFilter(");
148     final int minLen = buffer.length();
149     for (final FilterClause c : clauses) {
150       if (buffer.length() > minLen) {
151         buffer.append(' ');
152       }
153       buffer.append(c);
154     }
155     return buffer.append(')').toString();
156   }
157 }