1 package org.apache.lucene.search;
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 import java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Iterator;
25 import org.apache.lucene.index.IndexReader;
26 import org.apache.lucene.search.BooleanClause.Occur;
27 import org.apache.lucene.util.FixedBitSet;
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
38 public class BooleanFilter extends Filter implements Iterable<FilterClause> {
40 private final List<FilterClause> clauses = new ArrayList<FilterClause>();
43 * Returns the a DocIdSetIterator representing the Boolean composition
44 * of the filters that have been added.
47 public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
48 FixedBitSet res = null;
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;
55 res = new FixedBitSet(reader.maxDoc());
61 for (final FilterClause fc : clauses) {
62 if (fc.getOccur() == Occur.MUST_NOT) {
64 res = new FixedBitSet(reader.maxDoc());
65 res.set(0, reader.maxDoc()); // NOTE: may set bits on deleted docs
67 final DocIdSetIterator disi = getDISI(fc.getFilter(), reader);
74 for (final FilterClause fc : clauses) {
75 if (fc.getOccur() == Occur.MUST) {
76 final DocIdSetIterator disi = getDISI(fc.getFilter(), reader);
78 return DocIdSet.EMPTY_DOCIDSET; // no documents can match
81 res = new FixedBitSet(reader.maxDoc());
89 return res != null ? res : DocIdSet.EMPTY_DOCIDSET;
92 private static DocIdSetIterator getDISI(Filter filter, IndexReader reader)
94 final DocIdSet set = filter.getDocIdSet(reader);
95 return (set == null || set == DocIdSet.EMPTY_DOCIDSET) ? null : set.iterator();
99 * Adds a new FilterClause to the Boolean Filter container
100 * @param filterClause A FilterClause object containing a Filter and an Occur parameter
102 public void add(FilterClause filterClause) {
103 clauses.add(filterClause);
106 public final void add(Filter filter, Occur occur) {
107 add(new FilterClause(filter, occur));
111 * Returns the list of clauses
113 public List<FilterClause> clauses() {
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>
121 public final Iterator<FilterClause> iterator() {
122 return clauses().iterator();
126 public boolean equals(Object obj) {
131 if ((obj == null) || (obj.getClass() != this.getClass())) {
135 final BooleanFilter other = (BooleanFilter)obj;
136 return clauses.equals(other.clauses);
140 public int hashCode() {
141 return 657153718 ^ clauses.hashCode();
144 /** Prints a user-readable version of this Filter. */
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) {
155 return buffer.append(')').toString();