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
ChainedFilter.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.Search;
24 using Lucene.Net.Index;
25 using Lucene.Net.Util;
26 
27 namespace Lucene.Net.Analysis
28 {
29 
30  ///<summary>
31  ///* <p>
32  /// * Allows multiple {@link Filter}s to be chained.
33  /// * Logical operations such as <b>NOT</b> and <b>XOR</b>
34  /// * are applied between filters. One operation can be used
35  /// * for all filters, or a specific operation can be declared
36  /// * for each filter.
37  /// * </p>
38  /// * <p>
39  /// * Order in which filters are called depends on
40  /// * the position of the filter in the chain. It's probably
41  /// * more efficient to place the most restrictive filters
42  /// * /least computationally-intensive filters first.
43  /// * </p>
44  ///</summary>
45  public class ChainedFilter : Filter
46  {
47  public enum Logic
48  {
49  NONE = -1,
50  OR = 0,
51  AND = 1,
52  ANDNOT = 2,
53  XOR = 3
54  };
55 
56  ///<summary>Logical operation when none is declared. Defaults to OR</summary>
57  public const Logic DEFAULT = Logic.OR;
58 
59  /** The filter chain */
60  private Filter[] chain = null;
61 
62  private Logic[] logicArray;
63 
64  private Logic logic = Logic.NONE;
65 
66  ///<summary>Ctor</summary><param name="chain">The chain of filters</param>
67  public ChainedFilter(Filter[] chain)
68  {
69  this.chain = chain;
70  }
71 
72  ///<summary>ctor</summary>
73  ///<param name="chain">The chain of filters</param>
74  ///<param name="logicArray">Logical operations to apply between filters</param>
75  public ChainedFilter(Filter[] chain, Logic[] logicArray)
76  {
77  this.chain = chain;
78  this.logicArray = logicArray;
79  }
80 
81  ///<summary>ctor</summary>
82  ///<param name="chain">The chain of filters</param>
83  ///<param name="logic">Logical operation to apply to ALL filters</param>
84  public ChainedFilter(Filter[] chain, Logic logic)
85  {
86  this.chain = chain;
87  this.logic = logic;
88  }
89 
90  ///<see cref="Filter#getDocIdSet"/>
91  public override DocIdSet GetDocIdSet(IndexReader reader)
92  {
93  int[] index = new int[1]; // use array as reference to modifiable int;
94  index[0] = 0; // an object attribute would not be thread safe.
95  if (logic != Logic.NONE)
96  return GetDocIdSet(reader, logic, index);
97  else if (logicArray != null)
98  return GetDocIdSet(reader, logicArray, index);
99  else
100  return GetDocIdSet(reader, DEFAULT, index);
101  }
102 
103  private DocIdSetIterator GetDISI(Filter filter, IndexReader reader)
104  {
105  DocIdSet docIdSet = filter.GetDocIdSet(reader);
106  if (docIdSet == null)
107  {
109  }
110  else
111  {
112  DocIdSetIterator iter = docIdSet.Iterator();
113  if (iter == null)
114  {
116  }
117  else
118  {
119  return iter;
120  }
121  }
122  }
123 
124  private OpenBitSetDISI InitialResult(IndexReader reader, Logic logic, int[] index)
125  {
126  OpenBitSetDISI result;
127  /**
128  * First AND operation takes place against a completely false
129  * bitset and will always return zero results.
130  */
131  if (logic == Logic.AND)
132  {
133  result = new OpenBitSetDISI(GetDISI(chain[index[0]], reader), reader.MaxDoc());
134  ++index[0];
135  }
136  else if (logic == Logic.ANDNOT)
137  {
138  result = new OpenBitSetDISI(GetDISI(chain[index[0]], reader), reader.MaxDoc());
139  result.Flip(0, reader.MaxDoc()); // NOTE: may set bits for deleted docs.
140  ++index[0];
141  }
142  else
143  {
144  result = new OpenBitSetDISI(reader.MaxDoc());
145  }
146  return result;
147  }
148 
149 
150  ///<summary>
151  /// * Provide a SortedVIntList when it is definitely
152  /// * smaller than an OpenBitSet
153  /// * @deprecated Either use CachingWrapperFilter, or
154  /// * switch to a different DocIdSet implementation yourself.
155  /// * This method will be removed in Lucene 4.0
156  ///</summary>
157  protected DocIdSet FinalResult(OpenBitSetDISI result, int maxDocs)
158  {
159  return result;
160  }
161 
162 
163  /**
164  * Delegates to each filter in the chain.
165  * @param reader IndexReader
166  * @param logic Logical operation
167  * @return DocIdSet
168  */
169  private DocIdSet GetDocIdSet(IndexReader reader, Logic logic, int[] index)
170  {
171  OpenBitSetDISI result = InitialResult(reader, logic, index);
172  for (; index[0] < chain.Length; index[0]++)
173  {
174  DoChain(result, logic, chain[index[0]].GetDocIdSet(reader));
175  }
176  return FinalResult(result, reader.MaxDoc());
177  }
178 
179  /**
180  * Delegates to each filter in the chain.
181  * @param reader IndexReader
182  * @param logic Logical operation
183  * @return DocIdSet
184  */
185  private DocIdSet GetDocIdSet(IndexReader reader, Logic[] logic, int[] index)
186  {
187  if (logic.Length != chain.Length)
188  throw new ArgumentException("Invalid number of elements in logic array");
189 
190  OpenBitSetDISI result = InitialResult(reader, logic[0], index);
191  for (; index[0] < chain.Length; index[0]++)
192  {
193  DoChain(result, logic[index[0]], chain[index[0]].GetDocIdSet(reader));
194  }
195  return FinalResult(result, reader.MaxDoc());
196  }
197 
198  public override String ToString()
199  {
200  StringBuilder sb = new StringBuilder();
201  sb.Append("ChainedFilter: [");
202  for (int i = 0; i < chain.Length; i++)
203  {
204  sb.Append(chain[i]);
205  sb.Append(' ');
206  }
207  sb.Append(']');
208  return sb.ToString();
209  }
210 
211  private void DoChain(OpenBitSetDISI result, Logic logic, DocIdSet dis)
212  {
213 
214  if (dis is OpenBitSet)
215  {
216  // optimized case for OpenBitSets
217  switch (logic)
218  {
219  case Logic.OR:
220  result.Or((OpenBitSet)dis);
221  break;
222  case Logic.AND:
223  result.And((OpenBitSet)dis);
224  break;
225  case Logic.ANDNOT:
226  result.AndNot((OpenBitSet)dis);
227  break;
228  case Logic.XOR:
229  result.Xor((OpenBitSet)dis);
230  break;
231  default:
232  DoChain(result, DEFAULT, dis);
233  break;
234  }
235  }
236  else
237  {
238  DocIdSetIterator disi;
239  if (dis == null)
240  {
242  }
243  else
244  {
245  disi = dis.Iterator();
246  if (disi == null)
247  {
249  }
250  }
251 
252  switch (logic)
253  {
254  case Logic.OR:
255  result.InPlaceOr(disi);
256  break;
257  case Logic.AND:
258  result.InPlaceAnd(disi);
259  break;
260  case Logic.ANDNOT:
261  result.InPlaceNot(disi);
262  break;
263  case Logic.XOR:
264  result.InPlaceXor(disi);
265  break;
266  default:
267  DoChain(result, DEFAULT, dis);
268  break;
269  }
270  }
271  }
272 
273  }
274 
275 }