/* * 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 System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using Lucene.Net.Util; namespace Lucene.Net.Index { /// /// The type of parser for the value of the term. /// public enum FieldParser { String, Numeric } /// /// Base class for the typed enumerators. /// /// /// There are five implementations of FieldEnumerator for /// strings, integers, longs, floats, and doubles. The numeric enumerators support both /// standard Field and NumericField implementations. The string and numeric enumerators /// have slightly different options, but both should be used within a using statment /// to close the underlying TermEnum/TermDocs. Refer to the unit tests for usage examples. /// /// /// The type of data being enumerated. public abstract class FieldEnumerator : IDisposable { /// /// Whether the enumerator will include TermDocs. /// protected bool includeDocs; /// /// The underlying TermEnum; /// private TermEnum termEnum; /// /// The optional TermDocs. /// private TermDocs termDocs; /// /// The specialized TermEnum enumerator. /// protected TermEnumerator tEnum; /// /// The specialized TermDoc enumerator. /// private TermDocEnumerator.TermDocUsingTermsEnumerator tdEnum; /// /// Whether or not the instance has been disposed. /// private bool disposed; /// /// Initialization method called by subclasses to simulate a shared /// base constructor as generic classes cannot have a parameterized ctor. /// /// The index reader to read from. /// The field to enumerate. protected void Init(IndexReader reader, string field) { this.Init(reader, field, true); } /// /// Initialization method called by subclasses to simulate a shared /// base constructor as generic classes cannot have a parameterized ctor. /// /// The index reader to read from. /// The field to enumerate. /// Whether this enumerator will support TermDocs. protected void Init(IndexReader reader, string fieldName, bool includeDocs) { this.termEnum = reader.Terms(new Term(fieldName)); if (includeDocs) { this.termDocs = reader.TermDocs(); this.tdEnum = new TermDocEnumerator.TermDocUsingTermsEnumerator(this.termDocs, this.termEnum); } this.tEnum = new TermEnumerator(termEnum, termDocs, fieldName, this); } /// /// Method to attempt to parse out the value from the encoded string /// and sets the value of Current. /// /// The encoded string. /// True if the value was successfully parsed, false if we reached the /// end of encoded values in the fiele and only the tries remain. protected abstract bool TryParse(string s); /// /// Access the enumerator for the terms. /// public TermEnumerator Terms { get { return this.tEnum; } } /// /// Access the enumerator for the TermDocs. /// public TermDocEnumerator.TermDocUsingTermsEnumerator Docs { get { if (this.termDocs == null) { throw new NotSupportedException("This instance does not support enumeration over the document ids."); } else { return this.tdEnum; } } } #region IDisposable Members /// /// Dispose of the instance. /// public void Dispose() { if (!this.disposed) { this.disposed = true; if (this.termEnum != null) { this.termEnum.Close(); } if (this.termDocs != null) { this.termDocs.Close(); } GC.SuppressFinalize(this); } } #endregion /// /// The enumerator over the terms in an index. /// public class TermEnumerator : IEnumerator, IEnumerable { /// /// The underlying TermEnum; /// private TermEnum termEnum; /// /// The optional TermDocs. /// private TermDocs termDocs; /// /// The current term in the enum. /// private Term currentTerm; /// /// The field name, if any for the enum. /// protected string fieldName; /// /// Whether the enumerator has moved beyond the first position. /// private bool isFirst = true; /// /// THe enclosing instance, called back to in order to parse the field. /// private FieldEnumerator enclosing; /// /// Ctor. /// /// The TermEnum to wrap. /// The TermDocs to wrap. public TermEnumerator(TermEnum termEnum, TermDocs termDocs, string field, FieldEnumerator enclosing) { this.termEnum = termEnum; this.termDocs = termDocs; this.fieldName = field; this.enclosing = enclosing; } #region IEnumerator Members /// /// The current item in the enumerator. /// public T Current { get; internal set; } #endregion #region IEnumerator Members /// /// Current item in the enumerator. /// object IEnumerator.Current { get { return (object)this.Current; } } /// /// Advance to the next item. /// /// public bool MoveNext() { if (this.isFirst) { this.isFirst = false; } else { if (!this.termEnum.Next()) { return false; } } this.currentTerm = termEnum.Term; if (this.currentTerm == null || (!this.currentTerm.Field.Equals(this.fieldName))) { return false; } if (this.enclosing.TryParse(this.currentTerm.Text)) { if (this.termDocs != null) { this.termDocs.Seek(this.termEnum); } return true; } return false; } /// /// Reset the enumerator to the beginngin. /// public void Reset() { throw new NotSupportedException("The enumerator cannot be reset"); } #endregion #region IDisposable Members public void Dispose() { // noop } #endregion #region IEnumerable Members /// /// Accessor to IEnumerator-T-."/> /// /// public IEnumerator GetEnumerator() { return this; } #endregion #region IEnumerable Members /// /// Accessor to IEnumertor. /// /// IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } #endregion } } /// /// Class to handle creating a TermDocs and allowing for seeking and enumeration. Used /// when you have a set of one or moreterms for which you want to enumerate over the /// documents that contain those terms. /// public class TermDocEnumerator : IEnumerable, IDisposable { /// /// The underlying TermDocs. /// private TermDocs termDocs; /// /// Ctor. /// /// The TermDocs to wrap. public TermDocEnumerator(TermDocs termDocs) { this.termDocs = termDocs; } /// /// Seek to a specific term. /// /// public void Seek(Term t) { this.termDocs.Seek(t); } #region IEnumerable Members public IEnumerator GetEnumerator() { return new TermDocUsingTermsEnumerator(this.termDocs); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } #endregion #region IDisposable Members /// /// Dispose of the instance, closing the termdocs. /// public void Dispose() { if (this.termDocs != null) { termDocs.Close(); } } #endregion /// /// Class to handle enumeration over the TermDocs that does NOT close them /// on a call to Dispose! /// public class TermDocUsingTermsEnumerator : IEnumerable, IEnumerator { /// /// A reference to an outside TermEnum that is used to position /// the TermDocs. It can be null. /// private TermEnum termEnum; /// /// The underlying TermDocs. /// private TermDocs termDocs; /// /// Ctor. /// /// TermDocs to wrap internal TermDocUsingTermsEnumerator(TermDocs termDocs) : this(termDocs, null) { } /// /// Ctor. /// /// Underlying TermDocs. /// Enclosing field enum. internal TermDocUsingTermsEnumerator(TermDocs td, TermEnum termEnum) { this.termDocs = td; this.termEnum = termEnum; } /// /// Seel to a term in the underlying TermDocs. /// /// The point to seek to. internal void Seek(TermEnum te) { this.termDocs.Seek(te); } #region IEnumerable Members /// /// Get the enumerator. /// /// public IEnumerator GetEnumerator() { return this; } #endregion #region IEnumerable Members /// /// Get the enumerator. /// /// IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } #endregion #region IEnumerator Members /// /// The current document id. /// public int Current { get { return this.termDocs.Doc; } } #endregion #region IDisposable Members /// /// Dispose impl. /// public void Dispose() { // noop as the closing of the underlying // TermDocs is handled by the containing class } #endregion #region IEnumerator Members /// /// The current item. /// object IEnumerator.Current { get { throw new NotImplementedException(); } } /// /// Move to the next item. /// /// True if more, false if not. public bool MoveNext() { return this.termDocs.Next(); } /// /// Not implemented. Use Seek instead. /// public void Reset() { throw new NotImplementedException(); } #endregion } } /// /// Implementation for enumerating over terms with a string value. /// public class StringFieldEnumerator : FieldEnumerator { /// /// Construct an enumerator over one field. /// /// Index reader. /// The field to read. public StringFieldEnumerator(IndexReader reader, string fieldName) { this.Init(reader, fieldName); } /// /// Construct an enumerator over one field. /// /// Index reader. /// The field to read. /// Whether the TermDocs will also be enumerated. public StringFieldEnumerator(IndexReader reader, string fieldName, bool includeDocs) { this.Init(reader, fieldName, includeDocs); } /// /// Sets the value of current. /// /// The string. /// Always true. protected override bool TryParse(string s) { this.tEnum.Current = s; return true; } } /// /// Base for enumerating over numeric fields. /// /// public abstract class NumericFieldEnum : FieldEnumerator { /// /// The parser type for the field being enumerated. /// private FieldParser parser; /// /// Initialize the instance. /// /// The reader. /// The field name. /// Whether to include a TermDoc enum. /// The parser to use on the field. protected void Init(IndexReader reader, string field, bool includeDocs, FieldParser parser) { base.Init(reader, field, includeDocs); this.parser = parser; } /// /// Overridden from base. /// /// String to parse. /// protected override bool TryParse(string s) { if (this.parser == FieldParser.Numeric) { return this.TryParseNumeric(s); } else { return this.TryParseString(s); } } /// /// Parse out a standard string and set the value of current. /// /// String to parse. /// True on success. protected abstract bool TryParseString(string s); /// /// Parse out an encoded numeric string and set the value of current. /// /// String to parse. /// True on success. protected abstract bool TryParseNumeric(string s); } /// /// Implementation for enumerating over all of the terms in an int numeric field. /// public class IntFieldEnumerator : NumericFieldEnum { /// /// Construct an enumerator over one field. /// /// Index reader. /// The field to read. public IntFieldEnumerator(IndexReader reader, string fieldName, FieldParser parser) { this.Init(reader, fieldName, true, parser); } /// /// Construct an enumerator over one field. /// /// Index reader. /// The field to read. /// Whether the TermDocs will also be enumerated. public IntFieldEnumerator(IndexReader reader, string fieldName, FieldParser parser, bool includeDocs) { this.Init(reader, fieldName, includeDocs, parser); } /// /// Parse the int from the string. /// /// String to parse. /// Always true. protected override bool TryParseString(string s) { this.tEnum.Current = Int32.Parse(s); return true; } /// /// Parse the int from an encoded string. /// /// String to parse. /// True if the parse was successful, false indicating failure /// and the end of useful terms in the numeric field. protected override bool TryParseNumeric(string s) { int shift = s[0] - NumericUtils.SHIFT_START_INT; if (shift > 0 && shift <= 31) { return false; } else { this.tEnum.Current = NumericUtils.PrefixCodedToInt(s); return true; } } } /// /// Implementation for enumerating over all of the terms in a float numeric field. /// public class FloatFieldEnumerator : NumericFieldEnum { /// /// Construct an enumerator over one field. /// /// Index reader. /// The field to read. public FloatFieldEnumerator(IndexReader reader, string fieldName, FieldParser parser) { this.Init(reader, fieldName, true, parser); } /// /// Construct an enumerator over one field. /// /// Index reader. /// The field to read. /// Whether the TermDocs will also be enumerated. public FloatFieldEnumerator(IndexReader reader, string fieldName, FieldParser parser, bool includeDocs) { this.Init(reader, fieldName, includeDocs, parser); } /// /// Parse the float from a string. /// /// The string to parse. /// Always true. protected override bool TryParseString(string s) { this.tEnum.Current = float.Parse(s); return true; } /// /// Parse the float from a numeric field. /// /// The string to parse. /// True if the string was parsed, false to signify the /// end of usable terms in a numeric field. protected override bool TryParseNumeric(string s) { int shift = s[0] - NumericUtils.SHIFT_START_INT; if (shift > 0 && shift <= 31) { return false; } else { this.tEnum.Current = NumericUtils.SortableIntToFloat(NumericUtils.PrefixCodedToInt(s)); return true; } } } /// /// Implementation for enumerating over all of the terms in a double numeric field. /// public class DoubleFieldEnumerator : NumericFieldEnum { /// /// Construct an enumerator over one field. /// /// Index reader. /// The field to read. public DoubleFieldEnumerator(IndexReader reader, string fieldName, FieldParser parser) { this.Init(reader, fieldName, true, parser); } /// /// Construct an enumerator over one field. /// /// Index reader. /// The field to read. /// Whether the TermDocs will also be enumerated. public DoubleFieldEnumerator(IndexReader reader, string fieldName, FieldParser parser, bool includeDocs) { this.Init(reader, fieldName, includeDocs, parser); } /// /// Parse the double from a string. /// /// The string to parse. /// Always true. protected override bool TryParseString(string s) { this.tEnum.Current = Double.Parse(s); return true; } /// /// Parse the double from a numeric field. /// /// The string to parse. /// True if the string was parsed, false to indicate the end /// of usable numeric terms. protected override bool TryParseNumeric(string s) { int shift = s[0] - NumericUtils.SHIFT_START_LONG; if (shift > 0 && shift <= 63) { return false; } else { this.tEnum.Current = NumericUtils.SortableLongToDouble(NumericUtils.PrefixCodedToLong(s)); return true; } } } /// /// Implementation for enumerating over all of the terms in a long numeric field. /// public class LongFieldEnumerator : NumericFieldEnum { /// /// Construct an enumerator over one field. /// /// Index reader. /// The field to read. public LongFieldEnumerator(IndexReader reader, string fieldName, FieldParser parser) { this.Init(reader, fieldName, true, parser); } /// /// Construct an enumerator over one field. /// /// Index reader. /// The field to read. /// Whether the TermDocs will also be enumerated. public LongFieldEnumerator(IndexReader reader, string fieldName, FieldParser parser, bool includeDocs) { this.Init(reader, fieldName, includeDocs, parser); } /// /// Parse the long from a string. /// /// The string to parse. /// Always true. protected override bool TryParseString(string s) { this.tEnum.Current = long.Parse(s); return true; } /// /// Parse the long from a numeric field. /// /// The string to parse. /// True if the string was parsed, false to inidicate /// the end of usable terms in a numeric field. protected override bool TryParseNumeric(string s) { int shift = s[0] - NumericUtils.SHIFT_START_LONG; if (shift > 0 && shift <= 63) { return false; } else { this.tEnum.Current = NumericUtils.PrefixCodedToLong(s); return true; } } } }