Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
BooleanFilter.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 using System.Collections.Generic;
20 using System.Linq;
21 using System.Text;
22 
23 using Lucene.Net.Index;
24 using Lucene.Net.Support;
25 using Lucene.Net.Util;
26 
27 namespace Lucene.Net.Search
28 {
29  public class BooleanFilter : Filter
30  {
31  /// <summary>
32  /// The filters that are optional clauses.
33  /// </summary>
34  private List<Filter> shouldFilters = null;
35 
36  /// <summary>
37  /// The filters that are used for exclusion.
38  /// </summary>
39  private List<Filter> notFilters = null;
40 
41  /// <summary>
42  /// The filters that must be met.
43  /// </summary>
44  private List<Filter> mustFilters = null;
45 
46  /// <summary>
47  /// Get the iterator for a specific filter.
48  /// </summary>
49  /// <param name="filters">The list of filters</param>
50  /// <param name="index">The index of the iterator to get.</param>
51  /// <param name="reader">The reader for the index.</param>
52  /// <returns></returns>
53  private DocIdSetIterator GetDISI(List<Filter> filters, int index, IndexReader reader)
54  {
55  return filters[index].GetDocIdSet(reader).Iterator();
56  }
57 
58  /// <summary>
59  /// Get the id set for the filter.
60  /// </summary>
61  /// <param name="reader">The reader.</param>
62  /// <returns>The filter set to use.</returns>
63  public override DocIdSet GetDocIdSet(IndexReader reader)
64  {
65  OpenBitSetDISI res = null;
66 
67  if (shouldFilters != null)
68  {
69  for (int i = 0; i < shouldFilters.Count; i++)
70  {
71  if (res == null)
72  {
73  res = new OpenBitSetDISI(GetDISI(shouldFilters, i, reader), reader.MaxDoc);
74  }
75  else
76  {
77  DocIdSet dis = shouldFilters[i].GetDocIdSet(reader);
78  if (dis is OpenBitSet)
79  {
80  // optimized case for OpenBitSets
81  res.Or((OpenBitSet)dis);
82  }
83  else
84  {
85  res.InPlaceOr(GetDISI(shouldFilters, i, reader));
86  }
87  }
88  }
89  }
90 
91  if (notFilters != null)
92  {
93  for (int i = 0; i < notFilters.Count; i++)
94  {
95  if (res == null)
96  {
97  res = new OpenBitSetDISI(GetDISI(notFilters, i, reader), reader.MaxDoc);
98  res.Flip(0, reader.MaxDoc); // NOTE: may set bits on deleted docs
99  }
100  else
101  {
102  DocIdSet dis = notFilters[i].GetDocIdSet(reader);
103  if (dis is OpenBitSet)
104  {
105  // optimized case for OpenBitSets
106  res.AndNot((OpenBitSet)dis);
107  }
108  else
109  {
110  res.InPlaceNot(GetDISI(notFilters, i, reader));
111  }
112  }
113  }
114  }
115 
116  if (mustFilters != null)
117  {
118  for (int i = 0; i < mustFilters.Count; i++)
119  {
120  if (res == null)
121  {
122  res = new OpenBitSetDISI(GetDISI(mustFilters, i, reader), reader.MaxDoc);
123  }
124  else
125  {
126  DocIdSet dis = mustFilters[i].GetDocIdSet(reader);
127  if (dis is OpenBitSet)
128  {
129  // optimized case for OpenBitSets
130  res.And((OpenBitSet)dis);
131  }
132  else
133  {
134  res.InPlaceAnd(GetDISI(mustFilters, i, reader));
135  }
136  }
137  }
138  }
139 
140  if (res != null)
141  return FinalResult(res, reader.MaxDoc);
142 
143  return DocIdSet.EMPTY_DOCIDSET;
144  }
145 
146  /* Provide a SortedVIntList when it is definitely smaller
147  * than an OpenBitSet.
148  * @deprecated Either use CachingWrapperFilter, or
149  * switch to a different DocIdSet implementation yourself.
150  * This method will be removed in Lucene 4.0
151  */
152  protected DocIdSet FinalResult(OpenBitSetDISI result, int maxDocs)
153  {
154  return result;
155  }
156 
157  /// <summary>
158  /// Add a filter clause.
159  /// </summary>
160  /// <param name="filterClause">The clause to add.</param>
161  public void Add(FilterClause filterClause)
162  {
163  if (filterClause.Occur == Occur.MUST)
164  {
165  if (mustFilters == null)
166  {
167  mustFilters = new EquatableList<Filter>();
168  }
169  mustFilters.Add(filterClause.Filter);
170  }
171  if (filterClause.Occur == Occur.SHOULD)
172  {
173  if (shouldFilters == null)
174  {
175  shouldFilters = new EquatableList<Filter>();
176  }
177  shouldFilters.Add(filterClause.Filter);
178  }
179  if (filterClause.Occur == Occur.MUST_NOT)
180  {
181  if (notFilters == null)
182  {
183  notFilters = new EquatableList<Filter>();
184  }
185  notFilters.Add(filterClause.Filter);
186  }
187  }
188 
189  /// <summary>
190  /// Determine equality between two lists.
191  /// </summary>
192  /// <param name="filters1"></param>
193  /// <param name="filters2"></param>
194  /// <returns></returns>
195  private bool EqualFilters(List<Filter> filters1, List<Filter> filters2)
196  {
197  return (filters1 == filters2) ||
198  ((filters1 != null) && filters1.Equals(filters2));
199  }
200 
201  /// <summary>
202  /// Equality
203  /// </summary>
204  /// <param name="obj"></param>
205  /// <returns></returns>
206  public override bool Equals(Object obj)
207  {
208  if (this == obj)
209  return true;
210 
211  if ((obj == null) || !(obj is BooleanFilter))
212  return false;
213 
214  BooleanFilter other = (BooleanFilter)obj;
215  return EqualFilters(notFilters, other.notFilters)
216  && EqualFilters(mustFilters, other.mustFilters)
217  && EqualFilters(shouldFilters, other.shouldFilters);
218  }
219 
220  /// <summary>
221  /// Hash code.
222  /// </summary>
223  /// <returns></returns>
224  public override int GetHashCode()
225  {
226  int hash = 7;
227  hash = 31 * (hash + this.ListHash(this.mustFilters));
228  hash = 31 * (hash + this.ListHash(this.notFilters));
229  hash = 31 * (hash + this.ListHash(this.shouldFilters));
230  return hash;
231  }
232 
233 
234  private int ListHash(List<Filter> filters)
235  {
236  int sum = 0;
237  if (filters != null && filters.Count > 0)
238  {
239  for (int i = 0; i < filters.Count; i++)
240  {
241  sum += filters[i].GetHashCode();
242  }
243  }
244  return sum;
245  }
246 
247  /// <summary>
248  /// String representation.
249  /// </summary>
250  /// <returns></returns>
251  public override String ToString()
252  {
253  StringBuilder buffer = new StringBuilder();
254  buffer.Append("BooleanFilter(");
255  AppendFilters(shouldFilters, "", buffer);
256  AppendFilters(mustFilters, "+", buffer);
257  AppendFilters(notFilters, "-", buffer);
258  buffer.Append(")");
259  return buffer.ToString();
260  }
261 
262  /// <summary>
263  /// Append individual filters.
264  /// </summary>
265  /// <param name="filters"></param>
266  /// <param name="occurString"></param>
267  /// <param name="buffer"></param>
268  private void AppendFilters(List<Filter> filters, String occurString, StringBuilder buffer)
269  {
270  if (filters != null)
271  {
272  for (int i = 0; i < filters.Count(); i++)
273  {
274  buffer.Append(' ');
275  buffer.Append(occurString);
276  buffer.Append(filters[i].ToString());
277  }
278  }
279  }
280  }
281 }