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
FieldCacheRangeFilter.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 Lucene.Net.Index;
20 using Lucene.Net.Support;
21 using NumericField = Lucene.Net.Documents.NumericField;
22 using IndexReader = Lucene.Net.Index.IndexReader;
23 using TermDocs = Lucene.Net.Index.TermDocs;
24 using NumericUtils = Lucene.Net.Util.NumericUtils;
25 
26 namespace Lucene.Net.Search
27 {
28 
29  /// <summary> A range filter built on top of a cached single term field (in <see cref="FieldCache" />).
30  ///
31  /// <p/><see cref="FieldCacheRangeFilter" /> builds a single cache for the field the first time it is used.
32  /// Each subsequent <see cref="FieldCacheRangeFilter" /> on the same field then reuses this cache,
33  /// even if the range itself changes.
34  ///
35  /// <p/>This means that <see cref="FieldCacheRangeFilter" /> is much faster (sometimes more than 100x as fast)
36  /// as building a <see cref="TermRangeFilter" /> if using a <see cref="NewStringRange" />. However, if the range never changes it
37  /// is slower (around 2x as slow) than building a CachingWrapperFilter on top of a single <see cref="TermRangeFilter" />.
38  ///
39  /// For numeric data types, this filter may be significantly faster than <see cref="NumericRangeFilter{T}" />.
40  /// Furthermore, it does not need the numeric values encoded by <see cref="NumericField" />. But
41  /// it has the problem that it only works with exact one value/document (see below).
42  ///
43  /// <p/>As with all <see cref="FieldCache" /> based functionality, <see cref="FieldCacheRangeFilter" /> is only valid for
44  /// fields which exact one term for each document (except for <see cref="NewStringRange" />
45  /// where 0 terms are also allowed). Due to a restriction of <see cref="FieldCache" />, for numeric ranges
46  /// all terms that do not have a numeric value, 0 is assumed.
47  ///
48  /// <p/>Thus it works on dates, prices and other single value fields but will not work on
49  /// regular text fields. It is preferable to use a <c>NOT_ANALYZED</c> field to ensure that
50  /// there is only a single term.
51  ///
52  /// <p/>This class does not have an constructor, use one of the static factory methods available,
53  /// that create a correct instance for different data types supported by <see cref="FieldCache" />.
54  /// </summary>
55 
56  public static class FieldCacheRangeFilter
57  {
58  [Serializable]
59  private class AnonymousClassFieldCacheRangeFilter : FieldCacheRangeFilter<string>
60  {
61  private class AnonymousClassFieldCacheDocIdSet : FieldCacheDocIdSet
62  {
63  private void InitBlock(Lucene.Net.Search.StringIndex fcsi, int inclusiveLowerPoint, int inclusiveUpperPoint, FieldCacheRangeFilter<string> enclosingInstance)
64  {
65  this.fcsi = fcsi;
66  this.inclusiveLowerPoint = inclusiveLowerPoint;
67  this.inclusiveUpperPoint = inclusiveUpperPoint;
68  this.enclosingInstance = enclosingInstance;
69  }
70  private Lucene.Net.Search.StringIndex fcsi;
71  private int inclusiveLowerPoint;
72  private int inclusiveUpperPoint;
73  private FieldCacheRangeFilter<string> enclosingInstance;
74  public FieldCacheRangeFilter<string> Enclosing_Instance
75  {
76  get
77  {
78  return enclosingInstance;
79  }
80 
81  }
82  internal AnonymousClassFieldCacheDocIdSet(Lucene.Net.Search.StringIndex fcsi, int inclusiveLowerPoint, int inclusiveUpperPoint, FieldCacheRangeFilter<string> enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2)
83  : base(Param1, Param2)
84  {
85  InitBlock(fcsi, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance);
86  }
87  internal override bool MatchDoc(int doc)
88  {
89  return fcsi.order[doc] >= inclusiveLowerPoint && fcsi.order[doc] <= inclusiveUpperPoint;
90  }
91  }
92  internal AnonymousClassFieldCacheRangeFilter(string field, Lucene.Net.Search.Parser parser, string lowerVal, string upperVal, bool includeLower, bool includeUpper)
93  : base(field, parser, lowerVal, upperVal, includeLower, includeUpper)
94  {
95  }
96  public override DocIdSet GetDocIdSet(IndexReader reader)
97  {
98  Lucene.Net.Search.StringIndex fcsi = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetStringIndex(reader, field);
99  int lowerPoint = fcsi.BinarySearchLookup(lowerVal);
100  int upperPoint = fcsi.BinarySearchLookup(upperVal);
101 
102  int inclusiveLowerPoint;
103  int inclusiveUpperPoint;
104 
105  // Hints:
106  // * binarySearchLookup returns 0, if value was null.
107  // * the value is <0 if no exact hit was found, the returned value
108  // is (-(insertion point) - 1)
109  if (lowerPoint == 0)
110  {
111  System.Diagnostics.Debug.Assert(lowerVal == null);
112  inclusiveLowerPoint = 1;
113  }
114  else if (includeLower && lowerPoint > 0)
115  {
116  inclusiveLowerPoint = lowerPoint;
117  }
118  else if (lowerPoint > 0)
119  {
120  inclusiveLowerPoint = lowerPoint + 1;
121  }
122  else
123  {
124  inclusiveLowerPoint = System.Math.Max(1, -lowerPoint - 1);
125  }
126 
127  if (upperPoint == 0)
128  {
129  System.Diagnostics.Debug.Assert(upperVal == null);
130  inclusiveUpperPoint = System.Int32.MaxValue;
131  }
132  else if (includeUpper && upperPoint > 0)
133  {
134  inclusiveUpperPoint = upperPoint;
135  }
136  else if (upperPoint > 0)
137  {
138  inclusiveUpperPoint = upperPoint - 1;
139  }
140  else
141  {
142  inclusiveUpperPoint = -upperPoint - 2;
143  }
144 
145  if (inclusiveUpperPoint <= 0 || inclusiveLowerPoint > inclusiveUpperPoint)
146  return DocIdSet.EMPTY_DOCIDSET;
147 
148  System.Diagnostics.Debug.Assert(inclusiveLowerPoint > 0 && inclusiveUpperPoint > 0);
149 
150  // for this DocIdSet, we never need to use TermDocs,
151  // because deleted docs have an order of 0 (null entry in StringIndex)
152  return new AnonymousClassFieldCacheDocIdSet(fcsi, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, false);
153  }
154  }
155  [Serializable]
156  private class AnonymousClassFieldCacheRangeFilter1 : FieldCacheRangeFilter<sbyte?>
157  {
158  private class AnonymousClassFieldCacheDocIdSet : FieldCacheDocIdSet
159  {
160  private void InitBlock(sbyte[] values, sbyte inclusiveLowerPoint, sbyte inclusiveUpperPoint, FieldCacheRangeFilter<sbyte?> enclosingInstance)
161  {
162  this.values = values;
163  this.inclusiveLowerPoint = inclusiveLowerPoint;
164  this.inclusiveUpperPoint = inclusiveUpperPoint;
165  this.enclosingInstance = enclosingInstance;
166  }
167  private sbyte[] values;
168  private sbyte inclusiveLowerPoint;
169  private sbyte inclusiveUpperPoint;
170  private FieldCacheRangeFilter<sbyte?> enclosingInstance;
171  public FieldCacheRangeFilter<sbyte?> Enclosing_Instance
172  {
173  get
174  {
175  return enclosingInstance;
176  }
177 
178  }
179  internal AnonymousClassFieldCacheDocIdSet(sbyte[] values, sbyte inclusiveLowerPoint, sbyte inclusiveUpperPoint, FieldCacheRangeFilter<sbyte?> enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2)
180  : base(Param1, Param2)
181  {
182  InitBlock(values, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance);
183  }
184  internal override bool MatchDoc(int doc)
185  {
186  return values[doc] >= inclusiveLowerPoint && values[doc] <= inclusiveUpperPoint;
187  }
188  }
189  internal AnonymousClassFieldCacheRangeFilter1(string field, Parser parser, sbyte? lowerVal, sbyte? upperVal, bool includeLower, bool includeUpper)
190  : base(field, parser, lowerVal, upperVal, includeLower, includeUpper)
191  {
192  }
193  public override DocIdSet GetDocIdSet(IndexReader reader)
194  {
195  sbyte inclusiveLowerPoint;
196  sbyte inclusiveUpperPoint;
197  if (lowerVal != null)
198  {
199  sbyte i = (sbyte)lowerVal;
200  if (!includeLower && i == sbyte.MaxValue)
201  return DocIdSet.EMPTY_DOCIDSET;
202  inclusiveLowerPoint = (sbyte)(includeLower ? i : (i + 1));
203  }
204  else
205  {
206  inclusiveLowerPoint = sbyte.MinValue;
207  }
208  if (upperVal != null)
209  {
210  sbyte i = (sbyte)upperVal;
211  if (!includeUpper && i == sbyte.MinValue)
212  return DocIdSet.EMPTY_DOCIDSET;
213  inclusiveUpperPoint = (sbyte)(includeUpper ? i : (i - 1));
214  }
215  else
216  {
217  inclusiveUpperPoint = sbyte.MaxValue;
218  }
219 
220  if (inclusiveLowerPoint > inclusiveUpperPoint)
221  return DocIdSet.EMPTY_DOCIDSET;
222 
223  sbyte[] values = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetBytes(reader, field, (Lucene.Net.Search.ByteParser)parser);
224  // we only request the usage of termDocs, if the range contains 0
225  return new AnonymousClassFieldCacheDocIdSet(values, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, (inclusiveLowerPoint <= 0 && inclusiveUpperPoint >= 0));
226  }
227  }
228  [Serializable]
229  private class AnonymousClassFieldCacheRangeFilter2 : FieldCacheRangeFilter<short?>
230  {
231  private class AnonymousClassFieldCacheDocIdSet : FieldCacheDocIdSet
232  {
233  private void InitBlock(short[] values, short inclusiveLowerPoint, short inclusiveUpperPoint, FieldCacheRangeFilter<short?> enclosingInstance)
234  {
235  this.values = values;
236  this.inclusiveLowerPoint = inclusiveLowerPoint;
237  this.inclusiveUpperPoint = inclusiveUpperPoint;
238  this.enclosingInstance = enclosingInstance;
239  }
240  private short[] values;
241  private short inclusiveLowerPoint;
242  private short inclusiveUpperPoint;
243  private FieldCacheRangeFilter<short?> enclosingInstance;
244  public FieldCacheRangeFilter<short?> Enclosing_Instance
245  {
246  get
247  {
248  return enclosingInstance;
249  }
250 
251  }
252  internal AnonymousClassFieldCacheDocIdSet(short[] values, short inclusiveLowerPoint, short inclusiveUpperPoint, FieldCacheRangeFilter<short?> enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2)
253  : base(Param1, Param2)
254  {
255  InitBlock(values, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance);
256  }
257  internal override bool MatchDoc(int doc)
258  {
259  return values[doc] >= inclusiveLowerPoint && values[doc] <= inclusiveUpperPoint;
260  }
261  }
262  internal AnonymousClassFieldCacheRangeFilter2(string field, Parser parser, short? lowerVal, short? upperVal, bool includeLower, bool includeUpper)
263  : base(field, parser, lowerVal, upperVal, includeLower, includeUpper)
264  {
265  }
266  public override DocIdSet GetDocIdSet(IndexReader reader)
267  {
268  short inclusiveLowerPoint;
269  short inclusiveUpperPoint;
270  if (lowerVal != null)
271  {
272  short i = (short)lowerVal;
273  if (!includeLower && i == short.MaxValue)
274  return DocIdSet.EMPTY_DOCIDSET;
275  inclusiveLowerPoint = (short)(includeLower ? i : (i + 1));
276  }
277  else
278  {
279  inclusiveLowerPoint = short.MinValue;
280  }
281  if (upperVal != null)
282  {
283  short i = (short)upperVal;
284  if (!includeUpper && i == short.MinValue)
285  return DocIdSet.EMPTY_DOCIDSET;
286  inclusiveUpperPoint = (short)(includeUpper ? i : (i - 1));
287  }
288  else
289  {
290  inclusiveUpperPoint = short.MaxValue;
291  }
292 
293  if (inclusiveLowerPoint > inclusiveUpperPoint)
294  return DocIdSet.EMPTY_DOCIDSET;
295 
296  short[] values = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetShorts(reader, field, (Lucene.Net.Search.ShortParser)parser);
297  // we only request the usage of termDocs, if the range contains 0
298  return new AnonymousClassFieldCacheDocIdSet(values, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, (inclusiveLowerPoint <= 0 && inclusiveUpperPoint >= 0));
299  }
300  }
301  [Serializable]
302  private class AnonymousClassFieldCacheRangeFilter3 : FieldCacheRangeFilter<int?>
303  {
304  private class AnonymousClassFieldCacheDocIdSet : FieldCacheDocIdSet
305  {
306  private void InitBlock(int[] values, int inclusiveLowerPoint, int inclusiveUpperPoint, FieldCacheRangeFilter<int?> enclosingInstance)
307  {
308  this.values = values;
309  this.inclusiveLowerPoint = inclusiveLowerPoint;
310  this.inclusiveUpperPoint = inclusiveUpperPoint;
311  this.enclosingInstance = enclosingInstance;
312  }
313  private int[] values;
314  private int inclusiveLowerPoint;
315  private int inclusiveUpperPoint;
316  private FieldCacheRangeFilter<int?> enclosingInstance;
317  public FieldCacheRangeFilter<int?> Enclosing_Instance
318  {
319  get
320  {
321  return enclosingInstance;
322  }
323 
324  }
325  internal AnonymousClassFieldCacheDocIdSet(int[] values, int inclusiveLowerPoint, int inclusiveUpperPoint, FieldCacheRangeFilter<int?> enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2)
326  : base(Param1, Param2)
327  {
328  InitBlock(values, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance);
329  }
330  internal override bool MatchDoc(int doc)
331  {
332  return values[doc] >= inclusiveLowerPoint && values[doc] <= inclusiveUpperPoint;
333  }
334  }
335  internal AnonymousClassFieldCacheRangeFilter3(string field, Lucene.Net.Search.Parser parser, int? lowerVal, int? upperVal, bool includeLower, bool includeUpper)
336  : base(field, parser, lowerVal, upperVal, includeLower, includeUpper)
337  {
338  }
339  public override DocIdSet GetDocIdSet(IndexReader reader)
340  {
341  int inclusiveLowerPoint;
342  int inclusiveUpperPoint;
343  if (lowerVal != null)
344  {
345  int i = (int)lowerVal;
346  if (!includeLower && i == int.MaxValue)
347  return DocIdSet.EMPTY_DOCIDSET;
348  inclusiveLowerPoint = includeLower ? i : (i + 1);
349  }
350  else
351  {
352  inclusiveLowerPoint = int.MinValue;
353  }
354  if (upperVal != null)
355  {
356  int i = (int)upperVal;
357  if (!includeUpper && i == int.MinValue)
358  return DocIdSet.EMPTY_DOCIDSET;
359  inclusiveUpperPoint = includeUpper ? i : (i - 1);
360  }
361  else
362  {
363  inclusiveUpperPoint = int.MaxValue;
364  }
365 
366  if (inclusiveLowerPoint > inclusiveUpperPoint)
367  return DocIdSet.EMPTY_DOCIDSET;
368 
369  int[] values = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetInts(reader, field, (Lucene.Net.Search.IntParser)parser);
370  // we only request the usage of termDocs, if the range contains 0
371  return new AnonymousClassFieldCacheDocIdSet(values, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, (inclusiveLowerPoint <= 0 && inclusiveUpperPoint >= 0));
372  }
373  }
374  [Serializable]
375  private class AnonymousClassFieldCacheRangeFilter4 : FieldCacheRangeFilter<long?>
376  {
377  private class AnonymousClassFieldCacheDocIdSet : FieldCacheDocIdSet
378  {
379  private void InitBlock(long[] values, long inclusiveLowerPoint, long inclusiveUpperPoint, FieldCacheRangeFilter<long?> enclosingInstance)
380  {
381  this.values = values;
382  this.inclusiveLowerPoint = inclusiveLowerPoint;
383  this.inclusiveUpperPoint = inclusiveUpperPoint;
384  this.enclosingInstance = enclosingInstance;
385  }
386  private long[] values;
387  private long inclusiveLowerPoint;
388  private long inclusiveUpperPoint;
389  private FieldCacheRangeFilter<long?> enclosingInstance;
390  public FieldCacheRangeFilter<long?> Enclosing_Instance
391  {
392  get
393  {
394  return enclosingInstance;
395  }
396 
397  }
398  internal AnonymousClassFieldCacheDocIdSet(long[] values, long inclusiveLowerPoint, long inclusiveUpperPoint, FieldCacheRangeFilter<long?> enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2)
399  : base(Param1, Param2)
400  {
401  InitBlock(values, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance);
402  }
403  internal override bool MatchDoc(int doc)
404  {
405  return values[doc] >= inclusiveLowerPoint && values[doc] <= inclusiveUpperPoint;
406  }
407  }
408  internal AnonymousClassFieldCacheRangeFilter4(string field, Lucene.Net.Search.Parser parser, long? lowerVal, long? upperVal, bool includeLower, bool includeUpper)
409  : base(field, parser, lowerVal, upperVal, includeLower, includeUpper)
410  {
411  }
412  public override DocIdSet GetDocIdSet(IndexReader reader)
413  {
414  long inclusiveLowerPoint;
415  long inclusiveUpperPoint;
416  if (lowerVal != null)
417  {
418  long i = (long)lowerVal;
419  if (!includeLower && i == long.MaxValue)
420  return DocIdSet.EMPTY_DOCIDSET;
421  inclusiveLowerPoint = includeLower ? i : (i + 1L);
422  }
423  else
424  {
425  inclusiveLowerPoint = long.MinValue;
426  }
427  if (upperVal != null)
428  {
429  long i = (long)upperVal;
430  if (!includeUpper && i == long.MinValue)
431  return DocIdSet.EMPTY_DOCIDSET;
432  inclusiveUpperPoint = includeUpper ? i : (i - 1L);
433  }
434  else
435  {
436  inclusiveUpperPoint = long.MaxValue;
437  }
438 
439  if (inclusiveLowerPoint > inclusiveUpperPoint)
440  return DocIdSet.EMPTY_DOCIDSET;
441 
442  long[] values = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetLongs(reader, field, (Lucene.Net.Search.LongParser)parser);
443  // we only request the usage of termDocs, if the range contains 0
444  return new AnonymousClassFieldCacheDocIdSet(values, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, (inclusiveLowerPoint <= 0L && inclusiveUpperPoint >= 0L));
445  }
446  }
447  [Serializable]
448  private class AnonymousClassFieldCacheRangeFilter5 : FieldCacheRangeFilter<float?>
449  {
450  private class AnonymousClassFieldCacheDocIdSet : FieldCacheDocIdSet
451  {
452  private void InitBlock(float[] values, float inclusiveLowerPoint, float inclusiveUpperPoint, FieldCacheRangeFilter<float?> enclosingInstance)
453  {
454  this.values = values;
455  this.inclusiveLowerPoint = inclusiveLowerPoint;
456  this.inclusiveUpperPoint = inclusiveUpperPoint;
457  this.enclosingInstance = enclosingInstance;
458  }
459  private float[] values;
460  private float inclusiveLowerPoint;
461  private float inclusiveUpperPoint;
462  private FieldCacheRangeFilter<float?> enclosingInstance;
463  public FieldCacheRangeFilter<float?> Enclosing_Instance
464  {
465  get
466  {
467  return enclosingInstance;
468  }
469 
470  }
471  internal AnonymousClassFieldCacheDocIdSet(float[] values, float inclusiveLowerPoint, float inclusiveUpperPoint, FieldCacheRangeFilter<float?> enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2)
472  : base(Param1, Param2)
473  {
474  InitBlock(values, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance);
475  }
476  internal override bool MatchDoc(int doc)
477  {
478  return values[doc] >= inclusiveLowerPoint && values[doc] <= inclusiveUpperPoint;
479  }
480  }
481  internal AnonymousClassFieldCacheRangeFilter5(string field, Lucene.Net.Search.Parser parser, float? lowerVal, float? upperVal, bool includeLower, bool includeUpper)
482  : base(field, parser, lowerVal, upperVal, includeLower, includeUpper)
483  {
484  }
485  public override DocIdSet GetDocIdSet(IndexReader reader)
486  {
487  // we transform the floating point numbers to sortable integers
488  // using NumericUtils to easier find the next bigger/lower value
489  float inclusiveLowerPoint;
490  float inclusiveUpperPoint;
491  if (lowerVal != null)
492  {
493  float f = (float)lowerVal;
494  if (!includeUpper && f > 0.0f && float.IsInfinity(f))
495  return DocIdSet.EMPTY_DOCIDSET;
496  int i = NumericUtils.FloatToSortableInt(f);
497  inclusiveLowerPoint = NumericUtils.SortableIntToFloat(includeLower ? i : (i + 1));
498  }
499  else
500  {
501  inclusiveLowerPoint = float.NegativeInfinity;
502  }
503  if (upperVal != null)
504  {
505  float f = (float)upperVal;
506  if (!includeUpper && f < 0.0f && float.IsInfinity(f))
507  return DocIdSet.EMPTY_DOCIDSET;
508  int i = NumericUtils.FloatToSortableInt(f);
509  inclusiveUpperPoint = NumericUtils.SortableIntToFloat(includeUpper ? i : (i - 1));
510  }
511  else
512  {
513  inclusiveUpperPoint = float.PositiveInfinity;
514  }
515 
516  if (inclusiveLowerPoint > inclusiveUpperPoint)
517  return DocIdSet.EMPTY_DOCIDSET;
518 
519  float[] values = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetFloats(reader, field, (Lucene.Net.Search.FloatParser)parser);
520  // we only request the usage of termDocs, if the range contains 0
521  return new AnonymousClassFieldCacheDocIdSet(values, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, (inclusiveLowerPoint <= 0.0f && inclusiveUpperPoint >= 0.0f));
522  }
523  }
524  [Serializable]
525  private class AnonymousClassFieldCacheRangeFilter6 : FieldCacheRangeFilter<double?>
526  {
527  private class AnonymousClassFieldCacheDocIdSet : FieldCacheDocIdSet
528  {
529  private void InitBlock(double[] values, double inclusiveLowerPoint, double inclusiveUpperPoint, FieldCacheRangeFilter<double?> enclosingInstance)
530  {
531  this.values = values;
532  this.inclusiveLowerPoint = inclusiveLowerPoint;
533  this.inclusiveUpperPoint = inclusiveUpperPoint;
534  this.enclosingInstance = enclosingInstance;
535  }
536  private double[] values;
537  private double inclusiveLowerPoint;
538  private double inclusiveUpperPoint;
539  private FieldCacheRangeFilter<double?> enclosingInstance;
540  public FieldCacheRangeFilter<double?> Enclosing_Instance
541  {
542  get
543  {
544  return enclosingInstance;
545  }
546 
547  }
548  internal AnonymousClassFieldCacheDocIdSet(double[] values, double inclusiveLowerPoint, double inclusiveUpperPoint, FieldCacheRangeFilter<double?> enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2)
549  : base(Param1, Param2)
550  {
551  InitBlock(values, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance);
552  }
553  internal override bool MatchDoc(int doc)
554  {
555  return values[doc] >= inclusiveLowerPoint && values[doc] <= inclusiveUpperPoint;
556  }
557  }
558  internal AnonymousClassFieldCacheRangeFilter6(string field, Lucene.Net.Search.Parser parser, double? lowerVal, double? upperVal, bool includeLower, bool includeUpper)
559  : base(field, parser, lowerVal, upperVal, includeLower, includeUpper)
560  {
561  }
562  public override DocIdSet GetDocIdSet(IndexReader reader)
563  {
564  // we transform the floating point numbers to sortable integers
565  // using NumericUtils to easier find the next bigger/lower value
566  double inclusiveLowerPoint;
567  double inclusiveUpperPoint;
568  if (lowerVal != null)
569  {
570  double f = (double)lowerVal;
571  if (!includeUpper && f > 0.0 && double.IsInfinity(f))
572  return DocIdSet.EMPTY_DOCIDSET;
573  long i = NumericUtils.DoubleToSortableLong(f);
574  inclusiveLowerPoint = NumericUtils.SortableLongToDouble(includeLower ? i : (i + 1L));
575  }
576  else
577  {
578  inclusiveLowerPoint = double.NegativeInfinity;
579  }
580  if (upperVal != null)
581  {
582  double f = (double)upperVal;
583  if (!includeUpper && f < 0.0 && double.IsInfinity(f))
584  return DocIdSet.EMPTY_DOCIDSET;
585  long i = NumericUtils.DoubleToSortableLong(f);
586  inclusiveUpperPoint = NumericUtils.SortableLongToDouble(includeUpper ? i : (i - 1L));
587  }
588  else
589  {
590  inclusiveUpperPoint = double.PositiveInfinity;
591  }
592 
593  if (inclusiveLowerPoint > inclusiveUpperPoint)
594  return DocIdSet.EMPTY_DOCIDSET;
595 
596  double[] values = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetDoubles(reader, field, (Lucene.Net.Search.DoubleParser)parser);
597  // we only request the usage of termDocs, if the range contains 0
598  return new AnonymousClassFieldCacheDocIdSet(values, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, (inclusiveLowerPoint <= 0.0 && inclusiveUpperPoint >= 0.0));
599  }
600  }
601 
602  /// <summary> Creates a string range filter using <see cref="FieldCache.GetStringIndex(IndexReader,string)" />. This works with all
603  /// fields containing zero or one term in the field. The range can be half-open by setting one
604  /// of the values to <c>null</c>.
605  /// </summary>
606  public static FieldCacheRangeFilter<string> NewStringRange(string field, string lowerVal, string upperVal, bool includeLower, bool includeUpper)
607  {
608  return new AnonymousClassFieldCacheRangeFilter(field, null, lowerVal, upperVal, includeLower, includeUpper);
609  }
610 
611  /// <summary> Creates a numeric range filter using <see cref="FieldCache.GetBytes(IndexReader,String)" />. This works with all
612  /// byte fields containing exactly one numeric term in the field. The range can be half-open by setting one
613  /// of the values to <c>null</c>.
614  /// </summary>
615  public static FieldCacheRangeFilter<sbyte?> NewByteRange(string field, sbyte? lowerVal, sbyte? upperVal, bool includeLower, bool includeUpper)
616  {
617  return NewByteRange(field, null, lowerVal, upperVal, includeLower, includeUpper);
618  }
619 
620  /// <summary> Creates a numeric range filter using <see cref="FieldCache.GetBytes(IndexReader,String,ByteParser)" />. This works with all
621  /// byte fields containing exactly one numeric term in the field. The range can be half-open by setting one
622  /// of the values to <c>null</c>.
623  /// </summary>
624  public static FieldCacheRangeFilter<sbyte?> NewByteRange(string field, Lucene.Net.Search.ByteParser parser, sbyte? lowerVal, sbyte? upperVal, bool includeLower, bool includeUpper)
625  {
626  return new AnonymousClassFieldCacheRangeFilter1(field, parser, lowerVal, upperVal, includeLower, includeUpper);
627  }
628 
629  /// <summary> Creates a numeric range query using <see cref="FieldCache.GetShorts(IndexReader,String)" />. This works with all
630  /// short fields containing exactly one numeric term in the field. The range can be half-open by setting one
631  /// of the values to <c>null</c>.
632  /// </summary>
633  public static FieldCacheRangeFilter<short?> NewShortRange(string field, short? lowerVal, short? upperVal, bool includeLower, bool includeUpper)
634  {
635  return NewShortRange(field, null, lowerVal, upperVal, includeLower, includeUpper);
636  }
637 
638  /// <summary> Creates a numeric range query using <see cref="FieldCache.GetShorts(IndexReader,String,ShortParser)" />. This works with all
639  /// short fields containing exactly one numeric term in the field. The range can be half-open by setting one
640  /// of the values to <c>null</c>.
641  /// </summary>
642  public static FieldCacheRangeFilter<short?> NewShortRange(string field, Lucene.Net.Search.ShortParser parser, short? lowerVal, short? upperVal, bool includeLower, bool includeUpper)
643  {
644  return new AnonymousClassFieldCacheRangeFilter2(field, parser, lowerVal, upperVal, includeLower, includeUpper);
645  }
646 
647  /// <summary> Creates a numeric range query using <see cref="FieldCache.GetInts(IndexReader,String)" />. This works with all
648  /// int fields containing exactly one numeric term in the field. The range can be half-open by setting one
649  /// of the values to <c>null</c>.
650  /// </summary>
651  public static FieldCacheRangeFilter<int?> NewIntRange(string field, int? lowerVal, int? upperVal, bool includeLower, bool includeUpper)
652  {
653  return NewIntRange(field, null, lowerVal, upperVal, includeLower, includeUpper);
654  }
655 
656  /// <summary> Creates a numeric range query using <see cref="FieldCache.GetInts(IndexReader,String,IntParser)" />. This works with all
657  /// int fields containing exactly one numeric term in the field. The range can be half-open by setting one
658  /// of the values to <c>null</c>.
659  /// </summary>
660  public static FieldCacheRangeFilter<int?> NewIntRange(string field, Lucene.Net.Search.IntParser parser, int? lowerVal, int? upperVal, bool includeLower, bool includeUpper)
661  {
662  return new AnonymousClassFieldCacheRangeFilter3(field, parser, lowerVal, upperVal, includeLower, includeUpper);
663  }
664 
665  /// <summary> Creates a numeric range query using <see cref="FieldCache.GetLongs(IndexReader,String)" />. This works with all
666  /// long fields containing exactly one numeric term in the field. The range can be half-open by setting one
667  /// of the values to <c>null</c>.
668  /// </summary>
669  public static FieldCacheRangeFilter<long?> NewLongRange(string field, long? lowerVal, long? upperVal, bool includeLower, bool includeUpper)
670  {
671  return NewLongRange(field, null, lowerVal, upperVal, includeLower, includeUpper);
672  }
673 
674  /// <summary> Creates a numeric range query using <see cref="FieldCache.GetLongs(IndexReader,String,LongParser)" />. This works with all
675  /// long fields containing exactly one numeric term in the field. The range can be half-open by setting one
676  /// of the values to <c>null</c>.
677  /// </summary>
678  public static FieldCacheRangeFilter<long?> NewLongRange(string field, Lucene.Net.Search.LongParser parser, long? lowerVal, long? upperVal, bool includeLower, bool includeUpper)
679  {
680  return new AnonymousClassFieldCacheRangeFilter4(field, parser, lowerVal, upperVal, includeLower, includeUpper);
681  }
682 
683  /// <summary> Creates a numeric range query using <see cref="FieldCache.GetFloats(IndexReader,String)" />. This works with all
684  /// float fields containing exactly one numeric term in the field. The range can be half-open by setting one
685  /// of the values to <c>null</c>.
686  /// </summary>
687  public static FieldCacheRangeFilter<float?> NewFloatRange(string field, float? lowerVal, float? upperVal, bool includeLower, bool includeUpper)
688  {
689  return NewFloatRange(field, null, lowerVal, upperVal, includeLower, includeUpper);
690  }
691 
692  /// <summary> Creates a numeric range query using <see cref="FieldCache.GetFloats(IndexReader,String,FloatParser)" />. This works with all
693  /// float fields containing exactly one numeric term in the field. The range can be half-open by setting one
694  /// of the values to <c>null</c>.
695  /// </summary>
696  public static FieldCacheRangeFilter<float?> NewFloatRange(string field, Lucene.Net.Search.FloatParser parser, float? lowerVal, float? upperVal, bool includeLower, bool includeUpper)
697  {
698  return new AnonymousClassFieldCacheRangeFilter5(field, parser, lowerVal, upperVal, includeLower, includeUpper);
699  }
700 
701  /// <summary> Creates a numeric range query using <see cref="FieldCache.GetDoubles(IndexReader,String)" />. This works with all
702  /// double fields containing exactly one numeric term in the field. The range can be half-open by setting one
703  /// of the values to <c>null</c>.
704  /// </summary>
705  public static FieldCacheRangeFilter<double?> NewDoubleRange(string field, double? lowerVal, double? upperVal, bool includeLower, bool includeUpper)
706  {
707  return NewDoubleRange(field, null, lowerVal, upperVal, includeLower, includeUpper);
708  }
709 
710  /// <summary> Creates a numeric range query using <see cref="FieldCache.GetDoubles(IndexReader,String,DoubleParser)" />. This works with all
711  /// double fields containing exactly one numeric term in the field. The range can be half-open by setting one
712  /// of the values to <c>null</c>.
713  /// </summary>
714  public static FieldCacheRangeFilter<double?> NewDoubleRange(string field, Lucene.Net.Search.DoubleParser parser, double? lowerVal, double? upperVal, bool includeLower, bool includeUpper)
715  {
716  return new AnonymousClassFieldCacheRangeFilter6(field, parser, lowerVal, upperVal, includeLower, includeUpper);
717  }
718  }
719 
720  [Serializable]
721  public abstract class FieldCacheRangeFilter<T> : Filter
722  {
723  internal System.String field;
724  internal Lucene.Net.Search.Parser parser;
725  internal T lowerVal;
726  internal T upperVal;
727  internal bool includeLower;
728  internal bool includeUpper;
729 
730  protected internal FieldCacheRangeFilter(System.String field, Lucene.Net.Search.Parser parser, T lowerVal, T upperVal, bool includeLower, bool includeUpper)
731  {
732  this.field = field;
733  this.parser = parser;
734  this.lowerVal = lowerVal;
735  this.upperVal = upperVal;
736  this.includeLower = includeLower;
737  this.includeUpper = includeUpper;
738  }
739 
740  /// <summary>This method is implemented for each data type </summary>
741  public abstract override DocIdSet GetDocIdSet(IndexReader reader);
742 
743  public override System.String ToString()
744  {
745  System.Text.StringBuilder sb = new System.Text.StringBuilder(field).Append(":");
746  return sb.Append(includeLower?'[':'{').Append((lowerVal == null)?"*":lowerVal.ToString()).Append(" TO ").Append((upperVal == null)?"*":upperVal.ToString()).Append(includeUpper?']':'}').ToString();
747  }
748 
749  public override bool Equals(System.Object o)
750  {
751  if (this == o)
752  return true;
753  if (!(o is FieldCacheRangeFilter<T>))
754  return false;
755  FieldCacheRangeFilter<T> other = (FieldCacheRangeFilter<T>) o;
756 
757  if (!this.field.Equals(other.field) || this.includeLower != other.includeLower || this.includeUpper != other.includeUpper)
758  {
759  return false;
760  }
761  if (this.lowerVal != null ?! this.lowerVal.Equals(other.lowerVal):other.lowerVal != null)
762  return false;
763  if (this.upperVal != null ?! this.upperVal.Equals(other.upperVal):other.upperVal != null)
764  return false;
765  if (this.parser != null ?! this.parser.Equals(other.parser):other.parser != null)
766  return false;
767  return true;
768  }
769 
770  public override int GetHashCode()
771  {
772  int h = field.GetHashCode();
773  h ^= ((lowerVal != null)?lowerVal.GetHashCode():550356204);
774  h = (h << 1) | (Number.URShift(h, 31)); // rotate to distinguish lower from upper
775  h ^= ((upperVal != null)?upperVal.GetHashCode():- 1674416163);
776  h ^= ((parser != null)?parser.GetHashCode():- 1572457324);
777  h ^= (includeLower?1549299360:- 365038026) ^ (includeUpper?1721088258:1948649653);
778  return h;
779  }
780 
781  /// <summary>
782  /// Returns the field name for this filter
783  /// </summary>
784  public string GetField { get { return field; } }
785 
786  /// <summary>
787  /// Returns <c>true</c> if the lower endpoint is inclusive
788  /// </summary>
789  public bool IncludesLower { get { return includeLower; } }
790 
791  /// <summary>
792  /// Returns <c>true</c> if the upper endpoint is inclusive
793  /// </summary>
794  public bool IncludesUpper { get { return includeUpper; } }
795 
796  /// <summary>
797  /// Returns the lower value of the range filter
798  /// </summary>
799  public T LowerValue { get { return lowerVal; } }
800 
801  /// <summary>
802  /// Returns the upper value of this range filter
803  /// </summary>
804  public T UpperValue { get { return upperVal; } }
805 
806  public Parser Parser { get { return parser; } }
807 
808  internal abstract class FieldCacheDocIdSet:DocIdSet
809  {
810  private class AnonymousClassDocIdSetIterator : DocIdSetIterator
811  {
812  public AnonymousClassDocIdSetIterator(Lucene.Net.Index.TermDocs termDocs, FieldCacheDocIdSet enclosingInstance)
813  {
814  InitBlock(termDocs, enclosingInstance);
815  }
816  private void InitBlock(Lucene.Net.Index.TermDocs termDocs, FieldCacheDocIdSet enclosingInstance)
817  {
818  this.termDocs = termDocs;
819  this.enclosingInstance = enclosingInstance;
820  }
821  private Lucene.Net.Index.TermDocs termDocs;
822  private FieldCacheDocIdSet enclosingInstance;
823  public FieldCacheDocIdSet Enclosing_Instance
824  {
825  get
826  {
827  return enclosingInstance;
828  }
829 
830  }
831  private int doc = - 1;
832 
833  public override int DocID()
834  {
835  return doc;
836  }
837 
838  public override int NextDoc()
839  {
840  do
841  {
842  if (!termDocs.Next())
843  return doc = NO_MORE_DOCS;
844  }
845  while (!Enclosing_Instance.MatchDoc(doc = termDocs.Doc));
846  return doc;
847  }
848 
849  public override int Advance(int target)
850  {
851  if (!termDocs.SkipTo(target))
852  return doc = NO_MORE_DOCS;
853  while (!Enclosing_Instance.MatchDoc(doc = termDocs.Doc))
854  {
855  if (!termDocs.Next())
856  return doc = NO_MORE_DOCS;
857  }
858  return doc;
859  }
860  }
861  private class AnonymousClassDocIdSetIterator1:DocIdSetIterator
862  {
863  public AnonymousClassDocIdSetIterator1(FieldCacheDocIdSet enclosingInstance)
864  {
865  InitBlock(enclosingInstance);
866  }
867  private void InitBlock(FieldCacheDocIdSet enclosingInstance)
868  {
869  this.enclosingInstance = enclosingInstance;
870  }
871  private FieldCacheDocIdSet enclosingInstance;
872  public FieldCacheDocIdSet Enclosing_Instance
873  {
874  get
875  {
876  return enclosingInstance;
877  }
878 
879  }
880  private int doc = - 1;
881 
882  public override int DocID()
883  {
884  return doc;
885  }
886 
887  public override int NextDoc()
888  {
889  try
890  {
891  do
892  {
893  doc++;
894  }
895  while (!Enclosing_Instance.MatchDoc(doc));
896  return doc;
897  }
898  catch (System.IndexOutOfRangeException)
899  {
900  return doc = NO_MORE_DOCS;
901  }
902  }
903 
904  public override int Advance(int target)
905  {
906  try
907  {
908  doc = target;
909  while (!Enclosing_Instance.MatchDoc(doc))
910  {
911  doc++;
912  }
913  return doc;
914  }
915  catch (System.IndexOutOfRangeException)
916  {
917  return doc = NO_MORE_DOCS;
918  }
919  }
920  }
921  private IndexReader reader;
922  private bool mayUseTermDocs;
923 
924  internal FieldCacheDocIdSet(IndexReader reader, bool mayUseTermDocs)
925  {
926  this.reader = reader;
927  this.mayUseTermDocs = mayUseTermDocs;
928  }
929 
930  /// <summary>this method checks, if a doc is a hit, should throw AIOBE, when position invalid </summary>
931  internal abstract bool MatchDoc(int doc);
932 
933  /// <summary>this DocIdSet is cacheable, if it works solely with FieldCache and no TermDocs </summary>
934  public override bool IsCacheable
935  {
936  get { return !(mayUseTermDocs && reader.HasDeletions); }
937  }
938 
939  public override DocIdSetIterator Iterator()
940  {
941  // Synchronization needed because deleted docs BitVector
942  // can change after call to hasDeletions until TermDocs creation.
943  // We only use an iterator with termDocs, when this was requested (e.g. range contains 0)
944  // and the index has deletions
945  TermDocs termDocs;
946  lock (reader)
947  {
948  termDocs = IsCacheable ? null : reader.TermDocs(null);
949  }
950  if (termDocs != null)
951  {
952  // a DocIdSetIterator using TermDocs to iterate valid docIds
953  return new AnonymousClassDocIdSetIterator(termDocs, this);
954  }
955  else
956  {
957  // a DocIdSetIterator generating docIds by incrementing a variable -
958  // this one can be used if there are no deletions are on the index
959  return new AnonymousClassDocIdSetIterator1(this);
960  }
961  }
962  }
963  }
964 }