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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 using NumericTokenStream = Mono.Lucene.Net.Analysis.NumericTokenStream;
21 using NumericField = Mono.Lucene.Net.Documents.NumericField;
22 using IndexReader = Mono.Lucene.Net.Index.IndexReader;
23 using Term = Mono.Lucene.Net.Index.Term;
24 using NumericUtils = Mono.Lucene.Net.Util.NumericUtils;
25 using StringHelper = Mono.Lucene.Net.Util.StringHelper;
26 using ToStringUtils = Mono.Lucene.Net.Util.ToStringUtils;
28 namespace Mono.Lucene.Net.Search
31 /// <summary> <p/>A {@link Query} that matches numeric values within a
32 /// specified range. To use this, you must first index the
33 /// numeric values using {@link NumericField} (expert: {@link
34 /// NumericTokenStream}). If your terms are instead textual,
35 /// you should use {@link TermRangeQuery}. {@link
36 /// NumericRangeFilter} is the filter equivalent of this
39 /// <p/>You create a new NumericRangeQuery with the static
40 /// factory methods, eg:
43 /// Query q = NumericRangeQuery.newFloatRange("weight",
44 /// new Float(0.3f), new Float(0.10f),
48 /// matches all documents whose float valued "weight" field
49 /// ranges from 0.3 to 0.10, inclusive.
51 /// <p/>The performance of NumericRangeQuery is much better
52 /// than the corresponding {@link TermRangeQuery} because the
53 /// number of terms that must be searched is usually far
54 /// fewer, thanks to trie indexing, described below.<p/>
56 /// <p/>You can optionally specify a <a
57 /// href="#precisionStepDesc"><code>precisionStep</code></a>
58 /// when creating this query. This is necessary if you've
59 /// changed this configuration from its default (4) during
60 /// indexing. Lower values consume more disk space but speed
61 /// up searching. Suitable values are between <b>1</b> and
62 /// <b>8</b>. A good starting point to test is <b>4</b>,
63 /// which is the default value for all <code>Numeric*</code>
64 /// classes. See <a href="#precisionStepDesc">below</a> for
67 /// <p/>This query defaults to {@linkplain
68 /// MultiTermQuery#CONSTANT_SCORE_AUTO_REWRITE_DEFAULT} for
69 /// 32 bit (int/float) ranges with precisionStep <8 and 64
70 /// bit (long/double) ranges with precisionStep <6.
71 /// Otherwise it uses {@linkplain
72 /// MultiTermQuery#CONSTANT_SCORE_FILTER_REWRITE} as the
73 /// number of terms is likely to be high. With precision
74 /// steps of <4, this query can be run with one of the
75 /// BooleanQuery rewrite methods without changing
76 /// BooleanQuery's default max clause count.
78 /// <p/><font color="red"><b>NOTE:</b> This API is experimental and
79 /// might change in incompatible ways in the next release.</font>
81 /// <br/><h3>How it works</h3>
83 /// <p/>See the publication about <a target="_blank" href="http://www.panfmp.org">panFMP</a>,
84 /// where this algorithm was described (referred to as <code>TrieRangeQuery</code>):
86 /// <blockquote><strong>Schindler, U, Diepenbroek, M</strong>, 2008.
87 /// <em>Generic XML-based Framework for Metadata Portals.</em>
88 /// Computers & Geosciences 34 (12), 1947-1955.
89 /// <a href="http://dx.doi.org/10.1016/j.cageo.2008.02.023"
90 /// target="_blank">doi:10.1016/j.cageo.2008.02.023</a></blockquote>
92 /// <p/><em>A quote from this paper:</em> Because Apache Lucene is a full-text
93 /// search engine and not a conventional database, it cannot handle numerical ranges
94 /// (e.g., field value is inside user defined bounds, even dates are numerical values).
95 /// We have developed an extension to Apache Lucene that stores
96 /// the numerical values in a special string-encoded format with variable precision
97 /// (all numerical values like doubles, longs, floats, and ints are converted to
98 /// lexicographic sortable string representations and stored with different precisions
99 /// (for a more detailed description of how the values are stored,
100 /// see {@link NumericUtils}). A range is then divided recursively into multiple intervals for searching:
101 /// The center of the range is searched only with the lowest possible precision in the <em>trie</em>,
102 /// while the boundaries are matched more exactly. This reduces the number of terms dramatically.<p/>
104 /// <p/>For the variant that stores long values in 8 different precisions (each reduced by 8 bits) that
105 /// uses a lowest precision of 1 byte, the index contains only a maximum of 256 distinct values in the
106 /// lowest precision. Overall, a range could consist of a theoretical maximum of
107 /// <code>7*255*2 + 255 = 3825</code> distinct terms (when there is a term for every distinct value of an
108 /// 8-byte-number in the index and the range covers almost all of them; a maximum of 255 distinct values is used
109 /// because it would always be possible to reduce the full 256 values to one term with degraded precision).
110 /// In practice, we have seen up to 300 terms in most cases (index with 500,000 metadata records
111 /// and a uniform value distribution).<p/>
113 /// <a name="precisionStepDesc"/><h3>Precision Step</h3>
114 /// <p/>You can choose any <code>precisionStep</code> when encoding values.
115 /// Lower step values mean more precisions and so more terms in index (and index gets larger).
116 /// On the other hand, the maximum number of terms to match reduces, which optimized query speed.
117 /// The formula to calculate the maximum term count is:
119 /// n = [ (bitsPerValue/precisionStep - 1) * (2^precisionStep - 1 ) * 2 ] + (2^precisionStep - 1 )
121 /// <p/><em>(this formula is only correct, when <code>bitsPerValue/precisionStep</code> is an integer;
122 /// in other cases, the value must be rounded up and the last summand must contain the modulo of the division as
123 /// precision step)</em>.
124 /// For longs stored using a precision step of 4, <code>n = 15*15*2 + 15 = 465</code>, and for a precision
125 /// step of 2, <code>n = 31*3*2 + 3 = 189</code>. But the faster search speed is reduced by more seeking
126 /// in the term enum of the index. Because of this, the ideal <code>precisionStep</code> value can only
127 /// be found out by testing. <b>Important:</b> You can index with a lower precision step value and test search speed
128 /// using a multiple of the original step value.<p/>
130 /// <p/>Good values for <code>precisionStep</code> are depending on usage and data type:
132 /// <li>The default for all data types is <b>4</b>, which is used, when no <code>precisionStep</code> is given.</li>
133 /// <li>Ideal value in most cases for <em>64 bit</em> data types <em>(long, double)</em> is <b>6</b> or <b>8</b>.</li>
134 /// <li>Ideal value in most cases for <em>32 bit</em> data types <em>(int, float)</em> is <b>4</b>.</li>
135 /// <li>Steps <b>>64</b> for <em>long/double</em> and <b>>32</b> for <em>int/float</em> produces one token
136 /// per value in the index and querying is as slow as a conventional {@link TermRangeQuery}. But it can be used
137 /// to produce fields, that are solely used for sorting (in this case simply use {@link Integer#MAX_VALUE} as
138 /// <code>precisionStep</code>). Using {@link NumericField NumericFields} for sorting
139 /// is ideal, because building the field cache is much faster than with text-only numbers.
140 /// Sorting is also possible with range query optimized fields using one of the above <code>precisionSteps</code>.</li>
143 /// <p/>Comparisons of the different types of RangeQueries on an index with about 500,000 docs showed
144 /// that {@link TermRangeQuery} in boolean rewrite mode (with raised {@link BooleanQuery} clause count)
145 /// took about 30-40 secs to complete, {@link TermRangeQuery} in constant score filter rewrite mode took 5 secs
146 /// and executing this class took <100ms to complete (on an Opteron64 machine, Java 1.5, 8 bit
147 /// precision step). This query type was developed for a geographic portal, where the performance for
148 /// e.g. bounding boxes or exact date/time stamps is important.<p/>
155 public sealed class NumericRangeQuery:MultiTermQuery
158 private NumericRangeQuery(System.String field, int precisionStep, int valSize, System.ValueType min, System.ValueType max, bool minInclusive, bool maxInclusive)
160 System.Diagnostics.Debug.Assert((valSize == 32 || valSize == 64));
161 if (precisionStep < 1)
162 throw new System.ArgumentException("precisionStep must be >=1");
163 this.field = StringHelper.Intern(field);
164 this.precisionStep = precisionStep;
165 this.valSize = valSize;
168 this.minInclusive = minInclusive;
169 this.maxInclusive = maxInclusive;
171 // For bigger precisionSteps this query likely
172 // hits too many terms, so set to CONSTANT_SCORE_FILTER right off
173 // (especially as the FilteredTermEnum is costly if wasted only for AUTO tests because it
174 // creates new enums from IndexReader for each sub-range)
179 SetRewriteMethod((precisionStep > 6)?CONSTANT_SCORE_FILTER_REWRITE:CONSTANT_SCORE_AUTO_REWRITE_DEFAULT);
183 SetRewriteMethod((precisionStep > 8)?CONSTANT_SCORE_FILTER_REWRITE:CONSTANT_SCORE_AUTO_REWRITE_DEFAULT);
187 // should never happen
188 throw new System.ArgumentException("valSize must be 32 or 64");
192 // shortcut if upper bound == lower bound
193 if (min != null && min.Equals(max))
195 SetRewriteMethod(CONSTANT_SCORE_BOOLEAN_QUERY_REWRITE);
199 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>long</code>
200 /// range using the given <a href="#precisionStepDesc"><code>precisionStep</code></a>.
201 /// You can have half-open ranges (which are in fact </≤ or >/≥ queries)
202 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
203 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
205 public static NumericRangeQuery NewLongRange(System.String field, int precisionStep, System.ValueType min, System.ValueType max, bool minInclusive, bool maxInclusive)
207 return new NumericRangeQuery(field, precisionStep, 64, min, max, minInclusive, maxInclusive);
210 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>long</code>
211 /// range using the default <code>precisionStep</code> {@link NumericUtils#PRECISION_STEP_DEFAULT} (4).
212 /// You can have half-open ranges (which are in fact </≤ or >/≥ queries)
213 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
214 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
216 public static NumericRangeQuery NewLongRange(System.String field, System.ValueType min, System.ValueType max, bool minInclusive, bool maxInclusive)
218 return new NumericRangeQuery(field, NumericUtils.PRECISION_STEP_DEFAULT, 64, min, max, minInclusive, maxInclusive);
221 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>int</code>
222 /// range using the given <a href="#precisionStepDesc"><code>precisionStep</code></a>.
223 /// You can have half-open ranges (which are in fact </≤ or >/≥ queries)
224 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
225 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
227 public static NumericRangeQuery NewIntRange(System.String field, int precisionStep, System.ValueType min, System.ValueType max, bool minInclusive, bool maxInclusive)
229 return new NumericRangeQuery(field, precisionStep, 32, min, max, minInclusive, maxInclusive);
232 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>int</code>
233 /// range using the default <code>precisionStep</code> {@link NumericUtils#PRECISION_STEP_DEFAULT} (4).
234 /// You can have half-open ranges (which are in fact </≤ or >/≥ queries)
235 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
236 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
238 public static NumericRangeQuery NewIntRange(System.String field, System.ValueType min, System.ValueType max, bool minInclusive, bool maxInclusive)
240 return new NumericRangeQuery(field, NumericUtils.PRECISION_STEP_DEFAULT, 32, min, max, minInclusive, maxInclusive);
243 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>double</code>
244 /// range using the given <a href="#precisionStepDesc"><code>precisionStep</code></a>.
245 /// You can have half-open ranges (which are in fact </≤ or >/≥ queries)
246 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
247 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
249 public static NumericRangeQuery NewDoubleRange(System.String field, int precisionStep, System.Double min, System.Double max, bool minInclusive, bool maxInclusive)
251 return new NumericRangeQuery(field, precisionStep, 64, min, max, minInclusive, maxInclusive);
254 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>double</code>
255 /// range using the default <code>precisionStep</code> {@link NumericUtils#PRECISION_STEP_DEFAULT} (4).
256 /// You can have half-open ranges (which are in fact </≤ or >/≥ queries)
257 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
258 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
260 public static NumericRangeQuery NewDoubleRange(System.String field, System.Double min, System.Double max, bool minInclusive, bool maxInclusive)
262 return new NumericRangeQuery(field, NumericUtils.PRECISION_STEP_DEFAULT, 64, min, max, minInclusive, maxInclusive);
265 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>float</code>
266 /// range using the given <a href="#precisionStepDesc"><code>precisionStep</code></a>.
267 /// You can have half-open ranges (which are in fact </≤ or >/≥ queries)
268 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
269 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
271 public static NumericRangeQuery NewFloatRange(System.String field, int precisionStep, System.Single min, System.Single max, bool minInclusive, bool maxInclusive)
273 return new NumericRangeQuery(field, precisionStep, 32, min, max, minInclusive, maxInclusive);
276 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>float</code>
277 /// range using the default <code>precisionStep</code> {@link NumericUtils#PRECISION_STEP_DEFAULT} (4).
278 /// You can have half-open ranges (which are in fact </≤ or >/≥ queries)
279 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
280 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
282 public static NumericRangeQuery NewFloatRange(System.String field, System.Single min, System.Single max, bool minInclusive, bool maxInclusive)
284 return new NumericRangeQuery(field, NumericUtils.PRECISION_STEP_DEFAULT, 32, min, max, minInclusive, maxInclusive);
288 public /*protected internal*/ override FilteredTermEnum GetEnum(IndexReader reader)
290 return new NumericRangeTermEnum(this, reader);
293 /// <summary>Returns the field name for this query </summary>
294 public System.String GetField()
299 /// <summary>Returns <code>true</code> if the lower endpoint is inclusive </summary>
300 public bool IncludesMin()
305 /// <summary>Returns <code>true</code> if the upper endpoint is inclusive </summary>
306 public bool IncludesMax()
311 /// <summary>Returns the lower value of this range query </summary>
312 public System.ValueType GetMin()
317 /// <summary>Returns the upper value of this range query </summary>
318 public System.ValueType GetMax()
324 public override System.String ToString(System.String field)
326 System.Text.StringBuilder sb = new System.Text.StringBuilder();
327 if (!this.field.Equals(field))
328 sb.Append(this.field).Append(':');
329 return sb.Append(minInclusive?'[':'{').Append((min == null)?"*":min.ToString()).Append(" TO ").Append((max == null)?"*":max.ToString()).Append(maxInclusive?']':'}').Append(ToStringUtils.Boost(GetBoost())).ToString();
333 public override bool Equals(System.Object o)
339 if (o is NumericRangeQuery)
341 NumericRangeQuery q = (NumericRangeQuery) o;
342 return ((System.Object) field == (System.Object) q.field && (q.min == null?min == null:q.min.Equals(min)) && (q.max == null?max == null:q.max.Equals(max)) && minInclusive == q.minInclusive && maxInclusive == q.maxInclusive && precisionStep == q.precisionStep);
348 public override int GetHashCode()
350 int hash = base.GetHashCode();
351 hash += (field.GetHashCode() ^ 0x4565fd66 + precisionStep ^ 0x64365465);
353 hash += (min.GetHashCode() ^ 0x14fa55fb);
355 hash += (max.GetHashCode() ^ 0x733fa5fe);
356 return hash + (minInclusive.GetHashCode() ^ 0x14fa55fb) + (maxInclusive.GetHashCode() ^ 0x733fa5fe);
359 // field must be interned after reading from stream
360 //private void ReadObject(java.io.ObjectInputStream in)
362 // in.defaultReadObject();
363 // field = StringHelper.intern(field);
367 [System.Runtime.Serialization.OnDeserialized]
368 internal void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
370 field = StringHelper.Intern(field);
373 // members (package private, to be also fast accessible by NumericRangeTermEnum)
374 internal System.String field;
375 internal int precisionStep;
376 internal int valSize;
377 internal System.ValueType min;
378 internal System.ValueType max;
379 internal bool minInclusive;
380 internal bool maxInclusive;
382 /// <summary> Subclass of FilteredTermEnum for enumerating all terms that match the
383 /// sub-ranges for trie range queries.
385 /// WARNING: This term enumeration is not guaranteed to be always ordered by
386 /// {@link Term#compareTo}.
387 /// The ordering depends on how {@link NumericUtils#splitLongRange} and
388 /// {@link NumericUtils#splitIntRange} generates the sub-ranges. For
389 /// {@link MultiTermQuery} ordering is not relevant.
391 private sealed class NumericRangeTermEnum:FilteredTermEnum
393 private class AnonymousClassLongRangeBuilder:NumericUtils.LongRangeBuilder
395 public AnonymousClassLongRangeBuilder(NumericRangeTermEnum enclosingInstance)
397 InitBlock(enclosingInstance);
399 private void InitBlock(NumericRangeTermEnum enclosingInstance)
401 this.enclosingInstance = enclosingInstance;
403 private NumericRangeTermEnum enclosingInstance;
404 public NumericRangeTermEnum Enclosing_Instance
408 return enclosingInstance;
413 public override void AddRange(System.String minPrefixCoded, System.String maxPrefixCoded)
415 Enclosing_Instance.rangeBounds.Add(minPrefixCoded);
416 Enclosing_Instance.rangeBounds.Add(maxPrefixCoded);
419 private class AnonymousClassIntRangeBuilder:NumericUtils.IntRangeBuilder
421 public AnonymousClassIntRangeBuilder(NumericRangeTermEnum enclosingInstance)
423 InitBlock(enclosingInstance);
425 private void InitBlock(NumericRangeTermEnum enclosingInstance)
427 this.enclosingInstance = enclosingInstance;
429 private NumericRangeTermEnum enclosingInstance;
430 public NumericRangeTermEnum Enclosing_Instance
434 return enclosingInstance;
439 public override void AddRange(System.String minPrefixCoded, System.String maxPrefixCoded)
441 Enclosing_Instance.rangeBounds.Add(minPrefixCoded);
442 Enclosing_Instance.rangeBounds.Add(maxPrefixCoded);
445 private void InitBlock(NumericRangeQuery enclosingInstance)
447 this.enclosingInstance = enclosingInstance;
449 private NumericRangeQuery enclosingInstance;
450 public NumericRangeQuery Enclosing_Instance
454 return enclosingInstance;
459 private IndexReader reader;
460 private System.Collections.ArrayList rangeBounds = new System.Collections.ArrayList();
461 private System.String currentUpperBound = null;
463 internal NumericRangeTermEnum(NumericRangeQuery enclosingInstance, IndexReader reader)
465 InitBlock(enclosingInstance);
466 this.reader = reader;
468 switch (Enclosing_Instance.valSize)
473 long minBound = System.Int64.MinValue;
474 if (Enclosing_Instance.min is System.Int64)
476 minBound = System.Convert.ToInt64(Enclosing_Instance.min);
478 else if (Enclosing_Instance.min is System.Double)
480 minBound = NumericUtils.DoubleToSortableLong(System.Convert.ToDouble(Enclosing_Instance.min));
482 if (!Enclosing_Instance.minInclusive && Enclosing_Instance.min != null)
484 if (minBound == System.Int64.MaxValue)
490 long maxBound = System.Int64.MaxValue;
491 if (Enclosing_Instance.max is System.Int64)
493 maxBound = System.Convert.ToInt64(Enclosing_Instance.max);
495 else if (Enclosing_Instance.max is System.Double)
497 maxBound = NumericUtils.DoubleToSortableLong(System.Convert.ToDouble(Enclosing_Instance.max));
499 if (!Enclosing_Instance.maxInclusive && Enclosing_Instance.max != null)
501 if (maxBound == System.Int64.MinValue)
506 NumericUtils.SplitLongRange(new AnonymousClassLongRangeBuilder(this), Enclosing_Instance.precisionStep, minBound, maxBound);
513 int minBound = System.Int32.MinValue;
514 if (Enclosing_Instance.min is System.Int32)
516 minBound = System.Convert.ToInt32(Enclosing_Instance.min);
518 else if (Enclosing_Instance.min is System.Single)
520 minBound = NumericUtils.FloatToSortableInt(System.Convert.ToSingle(Enclosing_Instance.min));
522 if (!Enclosing_Instance.minInclusive && Enclosing_Instance.min != null)
524 if (minBound == System.Int32.MaxValue)
530 int maxBound = System.Int32.MaxValue;
531 if (Enclosing_Instance.max is System.Int32)
533 maxBound = System.Convert.ToInt32(Enclosing_Instance.max);
535 else if (Enclosing_Instance.max is System.Single)
537 maxBound = NumericUtils.FloatToSortableInt(System.Convert.ToSingle(Enclosing_Instance.max));
539 if (!Enclosing_Instance.maxInclusive && Enclosing_Instance.max != null)
541 if (maxBound == System.Int32.MinValue)
546 NumericUtils.SplitIntRange(new AnonymousClassIntRangeBuilder(this), Enclosing_Instance.precisionStep, minBound, maxBound);
552 // should never happen
553 throw new System.ArgumentException("valSize must be 32 or 64");
557 // seek to first term
562 public override float Difference()
567 /// <summary>this is a dummy, it is not used by this class. </summary>
569 public override bool EndEnum()
571 System.Diagnostics.Debug.Assert(false); // should never be called
572 return (currentTerm != null);
575 /// <summary> Compares if current upper bound is reached,
576 /// this also updates the term count for statistics.
577 /// In contrast to {@link FilteredTermEnum}, a return value
578 /// of <code>false</code> ends iterating the current enum
579 /// and forwards to the next sub-range.
582 public /*protected internal*/ override bool TermCompare(Term term)
584 return ((System.Object) term.Field() == (System.Object) Enclosing_Instance.field && String.CompareOrdinal(term.Text(), currentUpperBound) <= 0);
587 /// <summary>Increments the enumeration to the next element. True if one exists. </summary>
589 public override bool Next()
591 // if a current term exists, the actual enum is initialized:
592 // try change to next term, if no such term exists, fall-through
593 if (currentTerm != null)
595 System.Diagnostics.Debug.Assert(actualEnum != null);
596 if (actualEnum.Next())
598 currentTerm = actualEnum.Term();
599 if (TermCompare(currentTerm))
603 // if all above fails, we go forward to the next enum,
604 // if one is available
606 if (rangeBounds.Count < 2)
608 // close the current enum and read next bounds
609 if (actualEnum != null)
614 System.Object tempObject;
615 tempObject = rangeBounds[0];
616 rangeBounds.RemoveAt(0);
617 System.String lowerBound = (System.String) tempObject;
618 System.Object tempObject2;
619 tempObject2 = rangeBounds[0];
620 rangeBounds.RemoveAt(0);
621 this.currentUpperBound = ((System.String) tempObject2);
622 // this call recursively uses next(), if no valid term in
624 // if this behavior is changed/modified in the superclass,
625 // this enum will not work anymore!
626 SetEnum(reader.Terms(new Term(Enclosing_Instance.field, lowerBound)));
627 return (currentTerm != null);
630 /// <summary>Closes the enumeration to further activity, freeing resources. </summary>
632 public override void Close()
635 currentUpperBound = null;