add --shared
[pylucene.git] / lucene-java-3.4.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
23 import org.apache.lucene.index.IndexReader;
24 import org.apache.lucene.search.BooleanClause.Occur;
25 import org.apache.lucene.util.OpenBitSet;
26 import org.apache.lucene.util.OpenBitSetDISI;
27
28 /**
29  * A container Filter that allows Boolean composition of Filters.
30  * Filters are allocated into one of three logical constructs;
31  * SHOULD, MUST NOT, MUST
32  * The results Filter BitSet is constructed as follows:
33  * SHOULD Filters are OR'd together
34  * The resulting Filter is NOT'd with the NOT Filters
35  * The resulting Filter is AND'd with the MUST Filters
36  */
37
38 public class BooleanFilter extends Filter
39 {
40   ArrayList<Filter> shouldFilters = null;
41   ArrayList<Filter> notFilters = null;
42   ArrayList<Filter> mustFilters = null;
43   
44   private DocIdSetIterator getDISI(ArrayList<Filter> filters, int index, IndexReader reader)
45   throws IOException
46   {
47     return filters.get(index).getDocIdSet(reader).iterator();
48   }
49
50   /**
51    * Returns the a DocIdSetIterator representing the Boolean composition
52    * of the filters that have been added.
53    */
54   @Override
55   public DocIdSet getDocIdSet(IndexReader reader) throws IOException
56   {
57     OpenBitSetDISI res = null;
58   
59     if (shouldFilters != null) {
60       for (int i = 0; i < shouldFilters.size(); i++) {
61         if (res == null) {
62           res = new OpenBitSetDISI(getDISI(shouldFilters, i, reader), reader.maxDoc());
63         } else { 
64           DocIdSet dis = shouldFilters.get(i).getDocIdSet(reader);
65           if(dis instanceof OpenBitSet) {
66             // optimized case for OpenBitSets
67             res.or((OpenBitSet) dis);
68           } else {
69             res.inPlaceOr(getDISI(shouldFilters, i, reader));
70           }
71         }
72       }
73     }
74     
75     if (notFilters!=null) {
76       for (int i = 0; i < notFilters.size(); i++) {
77         if (res == null) {
78           res = new OpenBitSetDISI(getDISI(notFilters, i, reader), reader.maxDoc());
79           res.flip(0, reader.maxDoc()); // NOTE: may set bits on deleted docs
80         } else {
81           DocIdSet dis = notFilters.get(i).getDocIdSet(reader);
82           if(dis instanceof OpenBitSet) {
83             // optimized case for OpenBitSets
84             res.andNot((OpenBitSet) dis);
85           } else {
86             res.inPlaceNot(getDISI(notFilters, i, reader));
87           }
88         }
89       }
90     }
91     
92     if (mustFilters!=null) {
93       for (int i = 0; i < mustFilters.size(); i++) {
94         if (res == null) {
95           res = new OpenBitSetDISI(getDISI(mustFilters, i, reader), reader.maxDoc());
96         } else {
97           DocIdSet dis = mustFilters.get(i).getDocIdSet(reader);
98           if(dis instanceof OpenBitSet) {
99             // optimized case for OpenBitSets
100             res.and((OpenBitSet) dis);
101           } else {
102             res.inPlaceAnd(getDISI(mustFilters, i, reader));
103           }
104         }
105       }
106     }
107     
108     if (res !=null)
109       return finalResult(res, reader.maxDoc());
110
111     return DocIdSet.EMPTY_DOCIDSET;
112   }
113
114   /** Provide a SortedVIntList when it is definitely smaller
115    * than an OpenBitSet.
116    * @deprecated Either use CachingWrapperFilter, or
117    * switch to a different DocIdSet implementation yourself.
118    * This method will be removed in Lucene 4.0 
119    */
120   @Deprecated
121   protected final DocIdSet finalResult(OpenBitSetDISI result, int maxDocs) {
122     return result;
123   }
124
125   /**
126   * Adds a new FilterClause to the Boolean Filter container
127   * @param filterClause A FilterClause object containing a Filter and an Occur parameter
128   */
129   
130   public void add(FilterClause filterClause)
131   {
132     if (filterClause.getOccur().equals(Occur.MUST)) {
133       if (mustFilters==null) {
134         mustFilters=new ArrayList<Filter>();
135       }
136       mustFilters.add(filterClause.getFilter());
137     }
138     if (filterClause.getOccur().equals(Occur.SHOULD)) {
139       if (shouldFilters==null) {
140         shouldFilters=new ArrayList<Filter>();
141       }
142       shouldFilters.add(filterClause.getFilter());
143     }
144     if (filterClause.getOccur().equals(Occur.MUST_NOT)) {
145       if (notFilters==null) {
146         notFilters=new ArrayList<Filter>();
147       }
148       notFilters.add(filterClause.getFilter());
149     }
150   }
151
152   private boolean equalFilters(ArrayList<Filter> filters1, ArrayList<Filter> filters2)
153   {
154      return (filters1 == filters2) ||
155               ((filters1 != null) && filters1.equals(filters2));
156   }
157   
158   @Override
159   public boolean equals(Object obj)
160   {
161     if (this == obj)
162       return true;
163
164     if ((obj == null) || (obj.getClass() != this.getClass()))
165       return false;
166
167     BooleanFilter other = (BooleanFilter)obj;
168     return equalFilters(notFilters, other.notFilters)
169         && equalFilters(mustFilters, other.mustFilters)
170         && equalFilters(shouldFilters, other.shouldFilters);
171   }
172
173   @Override
174   public int hashCode()
175   {
176     int hash=7;
177     hash = 31 * hash + (null == mustFilters ? 0 : mustFilters.hashCode());
178     hash = 31 * hash + (null == notFilters ? 0 : notFilters.hashCode());
179     hash = 31 * hash + (null == shouldFilters ? 0 : shouldFilters.hashCode());
180     return hash;
181   }
182   
183   /** Prints a user-readable version of this query. */
184   @Override
185   public String toString()
186   {
187     StringBuilder buffer = new StringBuilder();
188     buffer.append("BooleanFilter(");
189     appendFilters(shouldFilters, "", buffer);
190     appendFilters(mustFilters, "+", buffer);
191     appendFilters(notFilters, "-", buffer);
192     buffer.append(")");
193     return buffer.toString();
194   }
195   
196   private void appendFilters(ArrayList<Filter> filters, String occurString, StringBuilder buffer)
197   {
198     if (filters != null) {
199       for (int i = 0; i < filters.size(); i++) {
200         buffer.append(' ');
201         buffer.append(occurString);
202         buffer.append(filters.get(i).toString());
203       }
204     }
205   }    
206 }