/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using NumericField = Lucene.Net.Documents.NumericField; using IndexReader = Lucene.Net.Index.IndexReader; using TermDocs = Lucene.Net.Index.TermDocs; using NumericUtils = Lucene.Net.Util.NumericUtils; namespace Lucene.Net.Search { /// A range filter built on top of a cached single term field (in {@link FieldCache}). /// ///

FieldCacheRangeFilter builds a single cache for the field the first time it is used. /// Each subsequent FieldCacheRangeFilter on the same field then reuses this cache, /// even if the range itself changes. /// ///

This means that FieldCacheRangeFilter is much faster (sometimes more than 100x as fast) /// as building a {@link TermRangeFilter} (or {@link ConstantScoreRangeQuery} on a {@link TermRangeFilter}) /// for each query, if using a {@link #newStringRange}. However, if the range never changes it /// is slower (around 2x as slow) than building a CachingWrapperFilter on top of a single TermRangeFilter. /// /// For numeric data types, this filter may be significantly faster than {@link NumericRangeFilter}. /// Furthermore, it does not need the numeric values encoded by {@link NumericField}. But /// it has the problem that it only works with exact one value/document (see below). /// ///

As with all {@link FieldCache} based functionality, FieldCacheRangeFilter is only valid for /// fields which exact one term for each document (except for {@link #newStringRange} /// where 0 terms are also allowed). Due to a restriction of {@link FieldCache}, for numeric ranges /// all terms that do not have a numeric value, 0 is assumed. /// ///

Thus it works on dates, prices and other single value fields but will not work on /// regular text fields. It is preferable to use a NOT_ANALYZED field to ensure that /// there is only a single term. /// ///

This class does not have an constructor, use one of the static factory methods available, /// that create a correct instance for different data types supported by {@link FieldCache}. ///

[Serializable] public abstract class FieldCacheRangeFilter:Filter { [Serializable] private class AnonymousClassFieldCacheRangeFilter:FieldCacheRangeFilter { private class AnonymousClassFieldCacheDocIdSet:FieldCacheDocIdSet { private void InitBlock(Lucene.Net.Search.StringIndex fcsi, int inclusiveLowerPoint, int inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter enclosingInstance) { this.fcsi = fcsi; this.inclusiveLowerPoint = inclusiveLowerPoint; this.inclusiveUpperPoint = inclusiveUpperPoint; this.enclosingInstance = enclosingInstance; } private Lucene.Net.Search.StringIndex fcsi; private int inclusiveLowerPoint; private int inclusiveUpperPoint; private AnonymousClassFieldCacheRangeFilter enclosingInstance; public AnonymousClassFieldCacheRangeFilter Enclosing_Instance { get { return enclosingInstance; } } internal AnonymousClassFieldCacheDocIdSet(Lucene.Net.Search.StringIndex fcsi, int inclusiveLowerPoint, int inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2):base(Param1, Param2) { InitBlock(fcsi, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance); } internal override bool MatchDoc(int doc) { return fcsi.order[doc] >= inclusiveLowerPoint && fcsi.order[doc] <= inclusiveUpperPoint; } } internal AnonymousClassFieldCacheRangeFilter(System.String Param1, Lucene.Net.Search.Parser Param2, System.Object Param3, System.Object Param4, bool Param5, bool Param6):base(Param1, Param2, Param3, Param4, Param5, Param6) { } public override DocIdSet GetDocIdSet(IndexReader reader) { Lucene.Net.Search.StringIndex fcsi = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetStringIndex(reader, field); int lowerPoint = fcsi.BinarySearchLookup((System.String) lowerVal); int upperPoint = fcsi.BinarySearchLookup((System.String) upperVal); int inclusiveLowerPoint; int inclusiveUpperPoint; // Hints: // * binarySearchLookup returns 0, if value was null. // * the value is <0 if no exact hit was found, the returned value // is (-(insertion point) - 1) if (lowerPoint == 0) { System.Diagnostics.Debug.Assert(lowerVal == null); inclusiveLowerPoint = 1; } else if (includeLower && lowerPoint > 0) { inclusiveLowerPoint = lowerPoint; } else if (lowerPoint > 0) { inclusiveLowerPoint = lowerPoint + 1; } else { inclusiveLowerPoint = System.Math.Max(1, - lowerPoint - 1); } if (upperPoint == 0) { System.Diagnostics.Debug.Assert(upperVal == null); inclusiveUpperPoint = System.Int32.MaxValue; } else if (includeUpper && upperPoint > 0) { inclusiveUpperPoint = upperPoint; } else if (upperPoint > 0) { inclusiveUpperPoint = upperPoint - 1; } else { inclusiveUpperPoint = - upperPoint - 2; } if (inclusiveUpperPoint <= 0 || inclusiveLowerPoint > inclusiveUpperPoint) return DocIdSet.EMPTY_DOCIDSET; System.Diagnostics.Debug.Assert(inclusiveLowerPoint > 0 && inclusiveUpperPoint > 0); // for this DocIdSet, we never need to use TermDocs, // because deleted docs have an order of 0 (null entry in StringIndex) return new AnonymousClassFieldCacheDocIdSet(fcsi, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, false); } } [Serializable] private class AnonymousClassFieldCacheRangeFilter1:FieldCacheRangeFilter { private class AnonymousClassFieldCacheDocIdSet:FieldCacheDocIdSet { private void InitBlock(sbyte[] values, byte inclusiveLowerPoint, byte inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter1 enclosingInstance) { this.values = values; this.inclusiveLowerPoint = inclusiveLowerPoint; this.inclusiveUpperPoint = inclusiveUpperPoint; this.enclosingInstance = enclosingInstance; } private sbyte[] values; private byte inclusiveLowerPoint; private byte inclusiveUpperPoint; private AnonymousClassFieldCacheRangeFilter1 enclosingInstance; public AnonymousClassFieldCacheRangeFilter1 Enclosing_Instance { get { return enclosingInstance; } } internal AnonymousClassFieldCacheDocIdSet(sbyte[] values, byte inclusiveLowerPoint, byte inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter1 enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2):base(Param1, Param2) { InitBlock(values, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance); } internal override bool MatchDoc(int doc) { return values[doc] >= inclusiveLowerPoint && values[doc] <= inclusiveUpperPoint; } } internal AnonymousClassFieldCacheRangeFilter1(System.String Param1, Lucene.Net.Search.Parser Param2, System.Object Param3, System.Object Param4, bool Param5, bool Param6):base(Param1, Param2, Param3, Param4, Param5, Param6) { } public override DocIdSet GetDocIdSet(IndexReader reader) { byte inclusiveLowerPoint; byte inclusiveUpperPoint; if (lowerVal != null) { byte i = (byte) System.Convert.ToSByte(((System.ValueType) lowerVal)); if (!includeLower && i == (byte) System.Byte.MaxValue) return DocIdSet.EMPTY_DOCIDSET; inclusiveLowerPoint = (byte) (includeLower?i:(i + 1)); } else { inclusiveLowerPoint = (byte) System.Byte.MinValue; } if (upperVal != null) { byte i = (byte) System.Convert.ToSByte(((System.ValueType) upperVal)); if (!includeUpper && i == (byte) System.Byte.MinValue) return DocIdSet.EMPTY_DOCIDSET; inclusiveUpperPoint = (byte) (includeUpper?i:(i - 1)); } else { inclusiveUpperPoint = (byte) System.Byte.MaxValue; } if (inclusiveLowerPoint > inclusiveUpperPoint) return DocIdSet.EMPTY_DOCIDSET; sbyte[] values = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetBytes(reader, field, (Lucene.Net.Search.ByteParser) parser); // we only request the usage of termDocs, if the range contains 0 return new AnonymousClassFieldCacheDocIdSet(values, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, (inclusiveLowerPoint <= 0 && inclusiveUpperPoint >= 0)); } } [Serializable] private class AnonymousClassFieldCacheRangeFilter2:FieldCacheRangeFilter { private class AnonymousClassFieldCacheDocIdSet:FieldCacheDocIdSet { private void InitBlock(short[] values, short inclusiveLowerPoint, short inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter2 enclosingInstance) { this.values = values; this.inclusiveLowerPoint = inclusiveLowerPoint; this.inclusiveUpperPoint = inclusiveUpperPoint; this.enclosingInstance = enclosingInstance; } private short[] values; private short inclusiveLowerPoint; private short inclusiveUpperPoint; private AnonymousClassFieldCacheRangeFilter2 enclosingInstance; public AnonymousClassFieldCacheRangeFilter2 Enclosing_Instance { get { return enclosingInstance; } } internal AnonymousClassFieldCacheDocIdSet(short[] values, short inclusiveLowerPoint, short inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter2 enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2):base(Param1, Param2) { InitBlock(values, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance); } internal override bool MatchDoc(int doc) { return values[doc] >= inclusiveLowerPoint && values[doc] <= inclusiveUpperPoint; } } internal AnonymousClassFieldCacheRangeFilter2(System.String Param1, Lucene.Net.Search.Parser Param2, System.Object Param3, System.Object Param4, bool Param5, bool Param6):base(Param1, Param2, Param3, Param4, Param5, Param6) { } public override DocIdSet GetDocIdSet(IndexReader reader) { short inclusiveLowerPoint; short inclusiveUpperPoint; if (lowerVal != null) { short i = System.Convert.ToInt16(((System.ValueType) lowerVal)); if (!includeLower && i == System.Int16.MaxValue) return DocIdSet.EMPTY_DOCIDSET; inclusiveLowerPoint = (short) (includeLower?i:(i + 1)); } else { inclusiveLowerPoint = System.Int16.MinValue; } if (upperVal != null) { short i = System.Convert.ToInt16(((System.ValueType) upperVal)); if (!includeUpper && i == System.Int16.MinValue) return DocIdSet.EMPTY_DOCIDSET; inclusiveUpperPoint = (short) (includeUpper?i:(i - 1)); } else { inclusiveUpperPoint = System.Int16.MaxValue; } if (inclusiveLowerPoint > inclusiveUpperPoint) return DocIdSet.EMPTY_DOCIDSET; short[] values = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetShorts(reader, field, (Lucene.Net.Search.ShortParser) parser); // we only request the usage of termDocs, if the range contains 0 return new AnonymousClassFieldCacheDocIdSet(values, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, (inclusiveLowerPoint <= 0 && inclusiveUpperPoint >= 0)); } } [Serializable] private class AnonymousClassFieldCacheRangeFilter3:FieldCacheRangeFilter { private class AnonymousClassFieldCacheDocIdSet:FieldCacheDocIdSet { private void InitBlock(int[] values, int inclusiveLowerPoint, int inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter3 enclosingInstance) { this.values = values; this.inclusiveLowerPoint = inclusiveLowerPoint; this.inclusiveUpperPoint = inclusiveUpperPoint; this.enclosingInstance = enclosingInstance; } private int[] values; private int inclusiveLowerPoint; private int inclusiveUpperPoint; private AnonymousClassFieldCacheRangeFilter3 enclosingInstance; public AnonymousClassFieldCacheRangeFilter3 Enclosing_Instance { get { return enclosingInstance; } } internal AnonymousClassFieldCacheDocIdSet(int[] values, int inclusiveLowerPoint, int inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter3 enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2):base(Param1, Param2) { InitBlock(values, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance); } internal override bool MatchDoc(int doc) { return values[doc] >= inclusiveLowerPoint && values[doc] <= inclusiveUpperPoint; } } internal AnonymousClassFieldCacheRangeFilter3(System.String Param1, Lucene.Net.Search.Parser Param2, System.Object Param3, System.Object Param4, bool Param5, bool Param6):base(Param1, Param2, Param3, Param4, Param5, Param6) { } public override DocIdSet GetDocIdSet(IndexReader reader) { int inclusiveLowerPoint; int inclusiveUpperPoint; if (lowerVal != null) { int i = System.Convert.ToInt32(((System.ValueType) lowerVal)); if (!includeLower && i == System.Int32.MaxValue) return DocIdSet.EMPTY_DOCIDSET; inclusiveLowerPoint = includeLower?i:(i + 1); } else { inclusiveLowerPoint = System.Int32.MinValue; } if (upperVal != null) { int i = System.Convert.ToInt32(((System.ValueType) upperVal)); if (!includeUpper && i == System.Int32.MinValue) return DocIdSet.EMPTY_DOCIDSET; inclusiveUpperPoint = includeUpper?i:(i - 1); } else { inclusiveUpperPoint = System.Int32.MaxValue; } if (inclusiveLowerPoint > inclusiveUpperPoint) return DocIdSet.EMPTY_DOCIDSET; int[] values = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetInts(reader, field, (Lucene.Net.Search.IntParser) parser); // we only request the usage of termDocs, if the range contains 0 return new AnonymousClassFieldCacheDocIdSet(values, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, (inclusiveLowerPoint <= 0 && inclusiveUpperPoint >= 0)); } } [Serializable] private class AnonymousClassFieldCacheRangeFilter4:FieldCacheRangeFilter { private class AnonymousClassFieldCacheDocIdSet:FieldCacheDocIdSet { private void InitBlock(long[] values, long inclusiveLowerPoint, long inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter4 enclosingInstance) { this.values = values; this.inclusiveLowerPoint = inclusiveLowerPoint; this.inclusiveUpperPoint = inclusiveUpperPoint; this.enclosingInstance = enclosingInstance; } private long[] values; private long inclusiveLowerPoint; private long inclusiveUpperPoint; private AnonymousClassFieldCacheRangeFilter4 enclosingInstance; public AnonymousClassFieldCacheRangeFilter4 Enclosing_Instance { get { return enclosingInstance; } } internal AnonymousClassFieldCacheDocIdSet(long[] values, long inclusiveLowerPoint, long inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter4 enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2):base(Param1, Param2) { InitBlock(values, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance); } internal override bool MatchDoc(int doc) { return values[doc] >= inclusiveLowerPoint && values[doc] <= inclusiveUpperPoint; } } internal AnonymousClassFieldCacheRangeFilter4(System.String Param1, Lucene.Net.Search.Parser Param2, System.Object Param3, System.Object Param4, bool Param5, bool Param6):base(Param1, Param2, Param3, Param4, Param5, Param6) { } public override DocIdSet GetDocIdSet(IndexReader reader) { long inclusiveLowerPoint; long inclusiveUpperPoint; if (lowerVal != null) { long i = System.Convert.ToInt64(((System.ValueType) lowerVal)); if (!includeLower && i == System.Int64.MaxValue) return DocIdSet.EMPTY_DOCIDSET; inclusiveLowerPoint = includeLower?i:(i + 1L); } else { inclusiveLowerPoint = System.Int64.MinValue; } if (upperVal != null) { long i = System.Convert.ToInt64(((System.ValueType) upperVal)); if (!includeUpper && i == System.Int64.MinValue) return DocIdSet.EMPTY_DOCIDSET; inclusiveUpperPoint = includeUpper?i:(i - 1L); } else { inclusiveUpperPoint = System.Int64.MaxValue; } if (inclusiveLowerPoint > inclusiveUpperPoint) return DocIdSet.EMPTY_DOCIDSET; long[] values = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetLongs(reader, field, (Lucene.Net.Search.LongParser) parser); // we only request the usage of termDocs, if the range contains 0 return new AnonymousClassFieldCacheDocIdSet(values, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, (inclusiveLowerPoint <= 0L && inclusiveUpperPoint >= 0L)); } } [Serializable] private class AnonymousClassFieldCacheRangeFilter5:FieldCacheRangeFilter { private class AnonymousClassFieldCacheDocIdSet:FieldCacheDocIdSet { private void InitBlock(float[] values, float inclusiveLowerPoint, float inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter5 enclosingInstance) { this.values = values; this.inclusiveLowerPoint = inclusiveLowerPoint; this.inclusiveUpperPoint = inclusiveUpperPoint; this.enclosingInstance = enclosingInstance; } private float[] values; private float inclusiveLowerPoint; private float inclusiveUpperPoint; private AnonymousClassFieldCacheRangeFilter5 enclosingInstance; public AnonymousClassFieldCacheRangeFilter5 Enclosing_Instance { get { return enclosingInstance; } } internal AnonymousClassFieldCacheDocIdSet(float[] values, float inclusiveLowerPoint, float inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter5 enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2):base(Param1, Param2) { InitBlock(values, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance); } internal override bool MatchDoc(int doc) { return values[doc] >= inclusiveLowerPoint && values[doc] <= inclusiveUpperPoint; } } internal AnonymousClassFieldCacheRangeFilter5(System.String Param1, Lucene.Net.Search.Parser Param2, System.Object Param3, System.Object Param4, bool Param5, bool Param6):base(Param1, Param2, Param3, Param4, Param5, Param6) { } public override DocIdSet GetDocIdSet(IndexReader reader) { // we transform the floating point numbers to sortable integers // using NumericUtils to easier find the next bigger/lower value float inclusiveLowerPoint; float inclusiveUpperPoint; if (lowerVal != null) { float f = System.Convert.ToSingle(((System.ValueType) lowerVal)); if (!includeUpper && f > 0.0f && System.Single.IsInfinity(f)) return DocIdSet.EMPTY_DOCIDSET; int i = NumericUtils.FloatToSortableInt(f); inclusiveLowerPoint = NumericUtils.SortableIntToFloat(includeLower?i:(i + 1)); } else { inclusiveLowerPoint = System.Single.NegativeInfinity; } if (upperVal != null) { float f = System.Convert.ToSingle(((System.ValueType) upperVal)); if (!includeUpper && f < 0.0f && System.Single.IsInfinity(f)) return DocIdSet.EMPTY_DOCIDSET; int i = NumericUtils.FloatToSortableInt(f); inclusiveUpperPoint = NumericUtils.SortableIntToFloat(includeUpper?i:(i - 1)); } else { inclusiveUpperPoint = System.Single.PositiveInfinity; } if (inclusiveLowerPoint > inclusiveUpperPoint) return DocIdSet.EMPTY_DOCIDSET; float[] values = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetFloats(reader, field, (Lucene.Net.Search.FloatParser) parser); // we only request the usage of termDocs, if the range contains 0 return new AnonymousClassFieldCacheDocIdSet(values, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, (inclusiveLowerPoint <= 0.0f && inclusiveUpperPoint >= 0.0f)); } } [Serializable] private class AnonymousClassFieldCacheRangeFilter6:FieldCacheRangeFilter { private class AnonymousClassFieldCacheDocIdSet:FieldCacheDocIdSet { private void InitBlock(double[] values, double inclusiveLowerPoint, double inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter6 enclosingInstance) { this.values = values; this.inclusiveLowerPoint = inclusiveLowerPoint; this.inclusiveUpperPoint = inclusiveUpperPoint; this.enclosingInstance = enclosingInstance; } private double[] values; private double inclusiveLowerPoint; private double inclusiveUpperPoint; private AnonymousClassFieldCacheRangeFilter6 enclosingInstance; public AnonymousClassFieldCacheRangeFilter6 Enclosing_Instance { get { return enclosingInstance; } } internal AnonymousClassFieldCacheDocIdSet(double[] values, double inclusiveLowerPoint, double inclusiveUpperPoint, AnonymousClassFieldCacheRangeFilter6 enclosingInstance, Lucene.Net.Index.IndexReader Param1, bool Param2):base(Param1, Param2) { InitBlock(values, inclusiveLowerPoint, inclusiveUpperPoint, enclosingInstance); } internal override bool MatchDoc(int doc) { return values[doc] >= inclusiveLowerPoint && values[doc] <= inclusiveUpperPoint; } } internal AnonymousClassFieldCacheRangeFilter6(System.String Param1, Lucene.Net.Search.Parser Param2, System.Object Param3, System.Object Param4, bool Param5, bool Param6):base(Param1, Param2, Param3, Param4, Param5, Param6) { } public override DocIdSet GetDocIdSet(IndexReader reader) { // we transform the floating point numbers to sortable integers // using NumericUtils to easier find the next bigger/lower value double inclusiveLowerPoint; double inclusiveUpperPoint; if (lowerVal != null) { double f = System.Convert.ToDouble(((System.ValueType) lowerVal)); if (!includeUpper && f > 0.0 && System.Double.IsInfinity(f)) return DocIdSet.EMPTY_DOCIDSET; long i = NumericUtils.DoubleToSortableLong(f); inclusiveLowerPoint = NumericUtils.SortableLongToDouble(includeLower?i:(i + 1L)); } else { inclusiveLowerPoint = System.Double.NegativeInfinity; } if (upperVal != null) { double f = System.Convert.ToDouble(((System.ValueType) upperVal)); if (!includeUpper && f < 0.0 && System.Double.IsInfinity(f)) return DocIdSet.EMPTY_DOCIDSET; long i = NumericUtils.DoubleToSortableLong(f); inclusiveUpperPoint = NumericUtils.SortableLongToDouble(includeUpper?i:(i - 1L)); } else { inclusiveUpperPoint = System.Double.PositiveInfinity; } if (inclusiveLowerPoint > inclusiveUpperPoint) return DocIdSet.EMPTY_DOCIDSET; double[] values = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetDoubles(reader, field, (Lucene.Net.Search.DoubleParser) parser); // we only request the usage of termDocs, if the range contains 0 return new AnonymousClassFieldCacheDocIdSet(values, inclusiveLowerPoint, inclusiveUpperPoint, this, reader, (inclusiveLowerPoint <= 0.0 && inclusiveUpperPoint >= 0.0)); } } internal System.String field; internal Lucene.Net.Search.Parser parser; internal System.Object lowerVal; internal System.Object upperVal; internal bool includeLower; internal bool includeUpper; private FieldCacheRangeFilter(System.String field, Lucene.Net.Search.Parser parser, System.Object lowerVal, System.Object upperVal, bool includeLower, bool includeUpper) { this.field = field; this.parser = parser; this.lowerVal = lowerVal; this.upperVal = upperVal; this.includeLower = includeLower; this.includeUpper = includeUpper; } /// This method is implemented for each data type public abstract override DocIdSet GetDocIdSet(IndexReader reader); /// Creates a string range query using {@link FieldCache#getStringIndex}. This works with all /// fields containing zero or one term in the field. The range can be half-open by setting one /// of the values to null. /// public static FieldCacheRangeFilter NewStringRange(System.String field, System.String lowerVal, System.String upperVal, bool includeLower, bool includeUpper) { return new AnonymousClassFieldCacheRangeFilter(field, null, lowerVal, upperVal, includeLower, includeUpper); } /// Creates a numeric range query using {@link FieldCache#GetBytes(IndexReader,String)}. This works with all /// byte fields containing exactly one numeric term in the field. The range can be half-open by setting one /// of the values to null. /// public static FieldCacheRangeFilter NewByteRange(System.String field, System.Byte lowerVal, System.Byte upperVal, bool includeLower, bool includeUpper) { return NewByteRange(field, null, lowerVal, upperVal, includeLower, includeUpper); } /// Creates a numeric range query using {@link FieldCache#GetBytes(IndexReader,String,FieldCache.ByteParser)}. This works with all /// byte fields containing exactly one numeric term in the field. The range can be half-open by setting one /// of the values to null. /// public static FieldCacheRangeFilter NewByteRange(System.String field, Lucene.Net.Search.ByteParser parser, System.Byte lowerVal, System.Byte upperVal, bool includeLower, bool includeUpper) { return new AnonymousClassFieldCacheRangeFilter1(field, parser, lowerVal, upperVal, includeLower, includeUpper); } /// Creates a numeric range query using {@link FieldCache#GetShorts(IndexReader,String)}. This works with all /// short fields containing exactly one numeric term in the field. The range can be half-open by setting one /// of the values to null. /// public static FieldCacheRangeFilter NewShortRange(System.String field, System.ValueType lowerVal, System.ValueType upperVal, bool includeLower, bool includeUpper) { return NewShortRange(field, null, lowerVal, upperVal, includeLower, includeUpper); } /// Creates a numeric range query using {@link FieldCache#GetShorts(IndexReader,String,FieldCache.ShortParser)}. This works with all /// short fields containing exactly one numeric term in the field. The range can be half-open by setting one /// of the values to null. /// public static FieldCacheRangeFilter NewShortRange(System.String field, Lucene.Net.Search.ShortParser parser, System.ValueType lowerVal, System.ValueType upperVal, bool includeLower, bool includeUpper) { return new AnonymousClassFieldCacheRangeFilter2(field, parser, lowerVal, upperVal, includeLower, includeUpper); } /// Creates a numeric range query using {@link FieldCache#GetInts(IndexReader,String)}. This works with all /// int fields containing exactly one numeric term in the field. The range can be half-open by setting one /// of the values to null. /// public static FieldCacheRangeFilter NewIntRange(System.String field, System.ValueType lowerVal, System.ValueType upperVal, bool includeLower, bool includeUpper) { return NewIntRange(field, null, lowerVal, upperVal, includeLower, includeUpper); } /// Creates a numeric range query using {@link FieldCache#GetInts(IndexReader,String,FieldCache.IntParser)}. This works with all /// int fields containing exactly one numeric term in the field. The range can be half-open by setting one /// of the values to null. /// public static FieldCacheRangeFilter NewIntRange(System.String field, Lucene.Net.Search.IntParser parser, System.ValueType lowerVal, System.ValueType upperVal, bool includeLower, bool includeUpper) { return new AnonymousClassFieldCacheRangeFilter3(field, parser, lowerVal, upperVal, includeLower, includeUpper); } /// Creates a numeric range query using {@link FieldCache#GetLongs(IndexReader,String)}. This works with all /// long fields containing exactly one numeric term in the field. The range can be half-open by setting one /// of the values to null. /// public static FieldCacheRangeFilter NewLongRange(System.String field, System.ValueType lowerVal, System.ValueType upperVal, bool includeLower, bool includeUpper) { return NewLongRange(field, null, lowerVal, upperVal, includeLower, includeUpper); } /// Creates a numeric range query using {@link FieldCache#GetLongs(IndexReader,String,FieldCache.LongParser)}. This works with all /// long fields containing exactly one numeric term in the field. The range can be half-open by setting one /// of the values to null. /// public static FieldCacheRangeFilter NewLongRange(System.String field, Lucene.Net.Search.LongParser parser, System.ValueType lowerVal, System.ValueType upperVal, bool includeLower, bool includeUpper) { return new AnonymousClassFieldCacheRangeFilter4(field, parser, lowerVal, upperVal, includeLower, includeUpper); } /// Creates a numeric range query using {@link FieldCache#GetFloats(IndexReader,String)}. This works with all /// float fields containing exactly one numeric term in the field. The range can be half-open by setting one /// of the values to null. /// public static FieldCacheRangeFilter NewFloatRange(System.String field, System.ValueType lowerVal, System.ValueType upperVal, bool includeLower, bool includeUpper) { return NewFloatRange(field, null, lowerVal, upperVal, includeLower, includeUpper); } /// Creates a numeric range query using {@link FieldCache#GetFloats(IndexReader,String,FieldCache.FloatParser)}. This works with all /// float fields containing exactly one numeric term in the field. The range can be half-open by setting one /// of the values to null. /// public static FieldCacheRangeFilter NewFloatRange(System.String field, Lucene.Net.Search.FloatParser parser, System.ValueType lowerVal, System.ValueType upperVal, bool includeLower, bool includeUpper) { return new AnonymousClassFieldCacheRangeFilter5(field, parser, lowerVal, upperVal, includeLower, includeUpper); } /// Creates a numeric range query using {@link FieldCache#GetDoubles(IndexReader,String)}. This works with all /// double fields containing exactly one numeric term in the field. The range can be half-open by setting one /// of the values to null. /// public static FieldCacheRangeFilter NewDoubleRange(System.String field, System.ValueType lowerVal, System.ValueType upperVal, bool includeLower, bool includeUpper) { return NewDoubleRange(field, null, lowerVal, upperVal, includeLower, includeUpper); } /// Creates a numeric range query using {@link FieldCache#GetDoubles(IndexReader,String,FieldCache.DoubleParser)}. This works with all /// double fields containing exactly one numeric term in the field. The range can be half-open by setting one /// of the values to null. /// public static FieldCacheRangeFilter NewDoubleRange(System.String field, Lucene.Net.Search.DoubleParser parser, System.ValueType lowerVal, System.ValueType upperVal, bool includeLower, bool includeUpper) { return new AnonymousClassFieldCacheRangeFilter6(field, parser, lowerVal, upperVal, includeLower, includeUpper); } public override System.String ToString() { System.Text.StringBuilder sb = new System.Text.StringBuilder(field).Append(":"); return sb.Append(includeLower?'[':'{').Append((lowerVal == null)?"*":lowerVal.ToString()).Append(" TO ").Append((upperVal == null)?"*":upperVal.ToString()).Append(includeUpper?']':'}').ToString(); } public override bool Equals(System.Object o) { if (this == o) return true; if (!(o is FieldCacheRangeFilter)) return false; FieldCacheRangeFilter other = (FieldCacheRangeFilter) o; if (!this.field.Equals(other.field) || this.includeLower != other.includeLower || this.includeUpper != other.includeUpper) { return false; } if (this.lowerVal != null?!this.lowerVal.Equals(other.lowerVal):other.lowerVal != null) return false; if (this.upperVal != null?!this.upperVal.Equals(other.upperVal):other.upperVal != null) return false; if (this.parser != null?!this.parser.Equals(other.parser):other.parser != null) return false; return true; } public override int GetHashCode() { int h = field.GetHashCode(); h ^= ((lowerVal != null)?lowerVal.GetHashCode():550356204); h = (h << 1) | (SupportClass.Number.URShift(h, 31)); // rotate to distinguish lower from upper h ^= ((upperVal != null)?upperVal.GetHashCode():- 1674416163); h ^= ((parser != null)?parser.GetHashCode():- 1572457324); h ^= (includeLower?1549299360:- 365038026) ^ (includeUpper?1721088258:1948649653); return h; } internal abstract class FieldCacheDocIdSet:DocIdSet { private class AnonymousClassDocIdSetIterator:DocIdSetIterator { public AnonymousClassDocIdSetIterator(Lucene.Net.Index.TermDocs termDocs, FieldCacheDocIdSet enclosingInstance) { InitBlock(termDocs, enclosingInstance); } private void InitBlock(Lucene.Net.Index.TermDocs termDocs, FieldCacheDocIdSet enclosingInstance) { this.termDocs = termDocs; this.enclosingInstance = enclosingInstance; } private Lucene.Net.Index.TermDocs termDocs; private FieldCacheDocIdSet enclosingInstance; public FieldCacheDocIdSet Enclosing_Instance { get { return enclosingInstance; } } private int doc = - 1; /** @deprecated use {@link #NextDoc()} instead. */ [Obsolete("Lucene.Net-2.9.1. This method overrides obsolete member Lucene.Net.Search.DocIdSetIterator.Next()")] public override bool Next() { return NextDoc() != NO_MORE_DOCS; } /// use {@link #Advance(int)} instead. /// [Obsolete("use Advance(int) instead.")] public override bool SkipTo(int target) { return Advance(target) != NO_MORE_DOCS; } /// use {@link #DocID()} instead. /// [Obsolete("use DocID() instead.")] public override int Doc() { return termDocs.Doc(); } public override int DocID() { return doc; } public override int NextDoc() { do { if (!termDocs.Next()) return doc = NO_MORE_DOCS; } while (!Enclosing_Instance.MatchDoc(doc = termDocs.Doc())); return doc; } public override int Advance(int target) { if (!termDocs.SkipTo(target)) return doc = NO_MORE_DOCS; while (!Enclosing_Instance.MatchDoc(doc = termDocs.Doc())) { if (!termDocs.Next()) return doc = NO_MORE_DOCS; } return doc; } } private class AnonymousClassDocIdSetIterator1:DocIdSetIterator { public AnonymousClassDocIdSetIterator1(FieldCacheDocIdSet enclosingInstance) { InitBlock(enclosingInstance); } private void InitBlock(FieldCacheDocIdSet enclosingInstance) { this.enclosingInstance = enclosingInstance; } private FieldCacheDocIdSet enclosingInstance; public FieldCacheDocIdSet Enclosing_Instance { get { return enclosingInstance; } } private int doc = - 1; /// use {@link #NextDoc()} instead. /// [Obsolete("use NextDoc() instead.")] public override bool Next() { return NextDoc() != NO_MORE_DOCS; } /// use {@link #Advance(int)} instead. /// [Obsolete("use Advance(int) instead.")] public override bool SkipTo(int target) { return Advance(target) != NO_MORE_DOCS; } /// use {@link #DocID()} instead. /// [Obsolete("use DocID() instead. ")] public override int Doc() { return doc; } public override int DocID() { return doc; } public override int NextDoc() { try { do { doc++; } while (!Enclosing_Instance.MatchDoc(doc)); return doc; } catch (System.IndexOutOfRangeException e) { return doc = NO_MORE_DOCS; } } public override int Advance(int target) { try { doc = target; while (!Enclosing_Instance.MatchDoc(doc)) { doc++; } return doc; } catch (System.IndexOutOfRangeException e) { return doc = NO_MORE_DOCS; } } } private IndexReader reader; private bool mayUseTermDocs; internal FieldCacheDocIdSet(IndexReader reader, bool mayUseTermDocs) { this.reader = reader; this.mayUseTermDocs = mayUseTermDocs; } /// this method checks, if a doc is a hit, should throw AIOBE, when position invalid internal abstract bool MatchDoc(int doc); /// this DocIdSet is cacheable, if it works solely with FieldCache and no TermDocs public override bool IsCacheable() { return !(mayUseTermDocs && reader.HasDeletions()); } public override DocIdSetIterator Iterator() { // Synchronization needed because deleted docs BitVector // can change after call to hasDeletions until TermDocs creation. // We only use an iterator with termDocs, when this was requested (e.g. range contains 0) // and the index has deletions TermDocs termDocs; lock (reader) { termDocs = IsCacheable() ? null : reader.TermDocs(null); } if (termDocs != null) { // a DocIdSetIterator using TermDocs to iterate valid docIds return new AnonymousClassDocIdSetIterator(termDocs, this); } else { // a DocIdSetIterator generating docIds by incrementing a variable - // this one can be used if there are no deletions are on the index return new AnonymousClassDocIdSetIterator1(this); } } } } }