diff options
Diffstat (limited to 'src/core/Index/MultiReader.cs')
-rw-r--r-- | src/core/Index/MultiReader.cs | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/src/core/Index/MultiReader.cs b/src/core/Index/MultiReader.cs new file mode 100644 index 0000000..a441cb7 --- /dev/null +++ b/src/core/Index/MultiReader.cs @@ -0,0 +1,494 @@ +/* + * 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.Linq; +using Lucene.Net.Support; +using Document = Lucene.Net.Documents.Document; +using FieldSelector = Lucene.Net.Documents.FieldSelector; +using MultiTermDocs = Lucene.Net.Index.DirectoryReader.MultiTermDocs; +using MultiTermEnum = Lucene.Net.Index.DirectoryReader.MultiTermEnum; +using MultiTermPositions = Lucene.Net.Index.DirectoryReader.MultiTermPositions; +using DefaultSimilarity = Lucene.Net.Search.DefaultSimilarity; + +namespace Lucene.Net.Index +{ + + /// <summary>An IndexReader which reads multiple indexes, appending + /// their content. + /// </summary> + public class MultiReader:IndexReader, System.ICloneable + { + protected internal IndexReader[] subReaders; + private int[] starts; // 1st docno for each segment + private bool[] decrefOnClose; // remember which subreaders to decRef on close + private System.Collections.Generic.IDictionary<string, byte[]> normsCache = new HashMap<string,byte[]>(); + private int maxDoc = 0; + private int numDocs = - 1; + private bool hasDeletions = false; + + /// <summary> <p/>Construct a MultiReader aggregating the named set of (sub)readers. + /// Directory locking for delete, undeleteAll, and setNorm operations is + /// left to the subreaders. <p/> + /// <p/>Note that all subreaders are closed if this Multireader is closed.<p/> + /// </summary> + /// <param name="subReaders">set of (sub)readers + /// </param> + /// <throws> IOException </throws> + public MultiReader(params IndexReader[] subReaders) + { + Initialize(subReaders, true); + } + + /// <summary> <p/>Construct a MultiReader aggregating the named set of (sub)readers. + /// Directory locking for delete, undeleteAll, and setNorm operations is + /// left to the subreaders. <p/> + /// </summary> + /// <param name="closeSubReaders">indicates whether the subreaders should be closed + /// when this MultiReader is closed + /// </param> + /// <param name="subReaders">set of (sub)readers + /// </param> + /// <throws> IOException </throws> + public MultiReader(IndexReader[] subReaders, bool closeSubReaders) + { + Initialize(subReaders, closeSubReaders); + } + + private void Initialize(IndexReader[] subReaders, bool closeSubReaders) + { + // Deep copy + this.subReaders = subReaders.ToArray(); + starts = new int[subReaders.Length + 1]; // build starts array + decrefOnClose = new bool[subReaders.Length]; + for (int i = 0; i < subReaders.Length; i++) + { + starts[i] = maxDoc; + maxDoc += subReaders[i].MaxDoc; // compute maxDocs + + if (!closeSubReaders) + { + subReaders[i].IncRef(); + decrefOnClose[i] = true; + } + else + { + decrefOnClose[i] = false; + } + + if (subReaders[i].HasDeletions) + hasDeletions = true; + } + starts[subReaders.Length] = maxDoc; + } + + /// <summary> Tries to reopen the subreaders. + /// <br/> + /// If one or more subreaders could be re-opened (i. e. subReader.reopen() + /// returned a new instance != subReader), then a new MultiReader instance + /// is returned, otherwise this instance is returned. + /// <p/> + /// A re-opened instance might share one or more subreaders with the old + /// instance. Index modification operations result in undefined behavior + /// when performed before the old instance is closed. + /// (see <see cref="IndexReader.Reopen()" />). + /// <p/> + /// If subreaders are shared, then the reference count of those + /// readers is increased to ensure that the subreaders remain open + /// until the last referring reader is closed. + /// + /// </summary> + /// <throws> CorruptIndexException if the index is corrupt </throws> + /// <throws> IOException if there is a low-level IO error </throws> + public override IndexReader Reopen() + { + lock (this) + { + return DoReopen(false); + } + } + + /// <summary> Clones the subreaders. + /// (see <see cref="IndexReader.Clone()" />). + /// <br/> + /// <p/> + /// If subreaders are shared, then the reference count of those + /// readers is increased to ensure that the subreaders remain open + /// until the last referring reader is closed. + /// </summary> + public override System.Object Clone() + { + try + { + return DoReopen(true); + } + catch (System.Exception ex) + { + throw new System.SystemException(ex.Message, ex); + } + } + + /// <summary> If clone is true then we clone each of the subreaders</summary> + /// <param name="doClone"> + /// </param> + /// <returns> New IndexReader, or same one (this) if + /// reopen/clone is not necessary + /// </returns> + /// <throws> CorruptIndexException </throws> + /// <throws> IOException </throws> + protected internal virtual IndexReader DoReopen(bool doClone) + { + EnsureOpen(); + + bool reopened = false; + IndexReader[] newSubReaders = new IndexReader[subReaders.Length]; + + bool success = false; + try + { + for (int i = 0; i < subReaders.Length; i++) + { + if (doClone) + newSubReaders[i] = (IndexReader) subReaders[i].Clone(); + else + newSubReaders[i] = subReaders[i].Reopen(); + // if at least one of the subreaders was updated we remember that + // and return a new MultiReader + if (newSubReaders[i] != subReaders[i]) + { + reopened = true; + } + } + success = true; + } + finally + { + if (!success && reopened) + { + for (int i = 0; i < newSubReaders.Length; i++) + { + if (newSubReaders[i] != subReaders[i]) + { + try + { + newSubReaders[i].Close(); + } + catch (System.IO.IOException) + { + // keep going - we want to clean up as much as possible + } + } + } + } + } + + if (reopened) + { + bool[] newDecrefOnClose = new bool[subReaders.Length]; + for (int i = 0; i < subReaders.Length; i++) + { + if (newSubReaders[i] == subReaders[i]) + { + newSubReaders[i].IncRef(); + newDecrefOnClose[i] = true; + } + } + MultiReader mr = new MultiReader(newSubReaders); + mr.decrefOnClose = newDecrefOnClose; + return mr; + } + else + { + return this; + } + } + + public override ITermFreqVector[] GetTermFreqVectors(int n) + { + EnsureOpen(); + int i = ReaderIndex(n); // find segment num + return subReaders[i].GetTermFreqVectors(n - starts[i]); // dispatch to segment + } + + public override ITermFreqVector GetTermFreqVector(int n, System.String field) + { + EnsureOpen(); + int i = ReaderIndex(n); // find segment num + return subReaders[i].GetTermFreqVector(n - starts[i], field); + } + + + public override void GetTermFreqVector(int docNumber, System.String field, TermVectorMapper mapper) + { + EnsureOpen(); + int i = ReaderIndex(docNumber); // find segment num + subReaders[i].GetTermFreqVector(docNumber - starts[i], field, mapper); + } + + public override void GetTermFreqVector(int docNumber, TermVectorMapper mapper) + { + EnsureOpen(); + int i = ReaderIndex(docNumber); // find segment num + subReaders[i].GetTermFreqVector(docNumber - starts[i], mapper); + } + + public override bool IsOptimized() + { + return false; + } + + public override int NumDocs() + { + // Don't call ensureOpen() here (it could affect performance) + // NOTE: multiple threads may wind up init'ing + // numDocs... but that's harmless + if (numDocs == - 1) + { + // check cache + int n = 0; // cache miss--recompute + for (int i = 0; i < subReaders.Length; i++) + n += subReaders[i].NumDocs(); // sum from readers + numDocs = n; + } + return numDocs; + } + + public override int MaxDoc + { + get + { + // Don't call ensureOpen() here (it could affect performance) + return maxDoc; + } + } + + // inherit javadoc + public override Document Document(int n, FieldSelector fieldSelector) + { + EnsureOpen(); + int i = ReaderIndex(n); // find segment num + return subReaders[i].Document(n - starts[i], fieldSelector); // dispatch to segment reader + } + + public override bool IsDeleted(int n) + { + // Don't call ensureOpen() here (it could affect performance) + int i = ReaderIndex(n); // find segment num + return subReaders[i].IsDeleted(n - starts[i]); // dispatch to segment reader + } + + public override bool HasDeletions + { + get + { + // Don't call ensureOpen() here (it could affect performance) + return hasDeletions; + } + } + + protected internal override void DoDelete(int n) + { + numDocs = - 1; // invalidate cache + int i = ReaderIndex(n); // find segment num + subReaders[i].DeleteDocument(n - starts[i]); // dispatch to segment reader + hasDeletions = true; + } + + protected internal override void DoUndeleteAll() + { + for (int i = 0; i < subReaders.Length; i++) + subReaders[i].UndeleteAll(); + + hasDeletions = false; + numDocs = - 1; // invalidate cache + } + + private int ReaderIndex(int n) + { + // find reader for doc n: + return DirectoryReader.ReaderIndex(n, this.starts, this.subReaders.Length); + } + + public override bool HasNorms(System.String field) + { + EnsureOpen(); + for (int i = 0; i < subReaders.Length; i++) + { + if (subReaders[i].HasNorms(field)) + return true; + } + return false; + } + + public override byte[] Norms(System.String field) + { + lock (this) + { + EnsureOpen(); + byte[] bytes = normsCache[field]; + if (bytes != null) + return bytes; // cache hit + if (!HasNorms(field)) + return null; + + bytes = new byte[MaxDoc]; + for (int i = 0; i < subReaders.Length; i++) + subReaders[i].Norms(field, bytes, starts[i]); + normsCache[field] = bytes; // update cache + return bytes; + } + } + + public override void Norms(System.String field, byte[] result, int offset) + { + lock (this) + { + EnsureOpen(); + byte[] bytes = normsCache[field]; + for (int i = 0; i < subReaders.Length; i++) + // read from segments + subReaders[i].Norms(field, result, offset + starts[i]); + + if (bytes == null && !HasNorms(field)) + { + for (int i = offset; i < result.Length; i++) + { + result[i] = (byte) DefaultSimilarity.EncodeNorm(1.0f); + } + } + else if (bytes != null) + { + // cache hit + Array.Copy(bytes, 0, result, offset, MaxDoc); + } + else + { + for (int i = 0; i < subReaders.Length; i++) + { + // read from segments + subReaders[i].Norms(field, result, offset + starts[i]); + } + } + } + } + + protected internal override void DoSetNorm(int n, System.String field, byte value_Renamed) + { + lock (normsCache) + { + normsCache.Remove(field); // clear cache + } + int i = ReaderIndex(n); // find segment num + subReaders[i].SetNorm(n - starts[i], field, value_Renamed); // dispatch + } + + public override TermEnum Terms() + { + EnsureOpen(); + return new MultiTermEnum(this, subReaders, starts, null); + } + + public override TermEnum Terms(Term term) + { + EnsureOpen(); + return new MultiTermEnum(this, subReaders, starts, term); + } + + public override int DocFreq(Term t) + { + EnsureOpen(); + int total = 0; // sum freqs in segments + for (int i = 0; i < subReaders.Length; i++) + total += subReaders[i].DocFreq(t); + return total; + } + + public override TermDocs TermDocs() + { + EnsureOpen(); + return new MultiTermDocs(this, subReaders, starts); + } + + public override TermPositions TermPositions() + { + EnsureOpen(); + return new MultiTermPositions(this, subReaders, starts); + } + + protected internal override void DoCommit(System.Collections.Generic.IDictionary<string, string> commitUserData) + { + for (int i = 0; i < subReaders.Length; i++) + subReaders[i].Commit(commitUserData); + } + + protected internal override void DoClose() + { + lock (this) + { + for (int i = 0; i < subReaders.Length; i++) + { + if (decrefOnClose[i]) + { + subReaders[i].DecRef(); + } + else + { + subReaders[i].Close(); + } + } + } + + // NOTE: only needed in case someone had asked for + // FieldCache for top-level reader (which is generally + // not a good idea): + Lucene.Net.Search.FieldCache_Fields.DEFAULT.Purge(this); + } + + public override System.Collections.Generic.ICollection<string> GetFieldNames(IndexReader.FieldOption fieldNames) + { + EnsureOpen(); + return DirectoryReader.GetFieldNames(fieldNames, this.subReaders); + } + + /// <summary> Checks recursively if all subreaders are up to date. </summary> + public override bool IsCurrent() + { + for (int i = 0; i < subReaders.Length; i++) + { + if (!subReaders[i].IsCurrent()) + { + return false; + } + } + + // all subreaders are up to date + return true; + } + + /// <summary>Not implemented.</summary> + /// <throws> UnsupportedOperationException </throws> + public override long Version + { + get { throw new System.NotSupportedException("MultiReader does not support this method."); } + } + + public override IndexReader[] GetSequentialSubReaders() + { + return subReaders; + } + } +}
\ No newline at end of file |