blob: 6f8cc7eea8a9e14a44b300646b4ce5e5f31a822a [file] [log] [blame]
using J2N.Collections.Generic.Extensions;
using System;
using System.Collections.Generic;
using JCG = J2N.Collections.Generic;
namespace Lucene.Net.Index
{
/*
* 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.
*/
/// <summary>
/// Base class for implementing <see cref="CompositeReader"/>s based on an array
/// of sub-readers. The implementing class has to add code for
/// correctly refcounting and closing the sub-readers.
///
/// <para/>User code will most likely use <see cref="MultiReader"/> to build a
/// composite reader on a set of sub-readers (like several
/// <see cref="DirectoryReader"/>s).
///
/// <para/> For efficiency, in this API documents are often referred to via
/// <i>document numbers</i>, non-negative integers which each name a unique
/// document in the index. These document numbers are ephemeral -- they may change
/// as documents are added to and deleted from an index. Clients should thus not
/// rely on a given document having the same number between sessions.
///
/// <para/><b>NOTE</b>:
/// <see cref="IndexReader"/> instances are completely thread
/// safe, meaning multiple threads can call any of its methods,
/// concurrently. If your application requires external
/// synchronization, you should <b>not</b> synchronize on the
/// <see cref="IndexReader"/> instance; use your own
/// (non-Lucene) objects instead.
/// <para/>
/// @lucene.internal
/// </summary>
/// <seealso cref="MultiReader"/>
public abstract class BaseCompositeReader<R> : CompositeReader
where R : IndexReader
{
private readonly R[] subReaders;
private readonly int[] starts; // 1st docno for each reader
private readonly int maxDoc;
private readonly int numDocs;
/// <summary>
/// List view solely for <see cref="GetSequentialSubReaders()"/>,
/// for effectiveness the array is used internally.
/// </summary>
private readonly IList<IndexReader> subReadersList; // LUCENENET: Changed from IList<R> to IList<IndexReader> to eliminate casting
/// <summary>
/// Constructs a <see cref="BaseCompositeReader{R}"/> on the given <paramref name="subReaders"/>. </summary>
/// <param name="subReaders"> the wrapped sub-readers. This array is returned by
/// <see cref="GetSequentialSubReaders()"/> and used to resolve the correct
/// subreader for docID-based methods. <b>Please note:</b> this array is <b>not</b>
/// cloned and not protected for modification, the subclass is responsible
/// to do this. </param>
protected BaseCompositeReader(R[] subReaders)
{
this.subReaders = subReaders;
// LUCENENET: To eliminate casting, we create the list explicitly
var subReadersList = new JCG.List<IndexReader>(subReaders.Length);
for (int i = 0; i < subReaders.Length; i++)
subReadersList.Add(subReaders[i]);
this.subReadersList = subReadersList.AsReadOnly();
starts = new int[subReaders.Length + 1]; // build starts array
int maxDoc = 0, numDocs = 0;
for (int i = 0; i < subReaders.Length; i++)
{
starts[i] = maxDoc;
IndexReader r = subReaders[i];
maxDoc += r.MaxDoc; // compute maxDocs
if (maxDoc < 0) // overflow
{
throw new ArgumentException("Too many documents, composite IndexReaders cannot exceed " + int.MaxValue);
}
numDocs += r.NumDocs; // compute numDocs
r.RegisterParentReader(this);
}
starts[subReaders.Length] = maxDoc;
this.maxDoc = maxDoc;
this.numDocs = numDocs;
}
public override sealed Fields GetTermVectors(int docID)
{
EnsureOpen();
int i = ReaderIndex(docID); // find subreader num
return subReaders[i].GetTermVectors(docID - starts[i]); // dispatch to subreader
}
public override sealed int NumDocs
{
get
{
// Don't call ensureOpen() here (it could affect performance)
return numDocs;
}
}
public override sealed int MaxDoc
{
get
{
// Don't call ensureOpen() here (it could affect performance)
return maxDoc;
}
}
public override sealed void Document(int docID, StoredFieldVisitor visitor)
{
EnsureOpen();
int i = ReaderIndex(docID); // find subreader num
subReaders[i].Document(docID - starts[i], visitor); // dispatch to subreader
}
public override sealed int DocFreq(Term term)
{
EnsureOpen();
int total = 0; // sum freqs in subreaders
for (int i = 0; i < subReaders.Length; i++)
{
total += subReaders[i].DocFreq(term);
}
return total;
}
public override sealed long TotalTermFreq(Term term)
{
EnsureOpen();
long total = 0; // sum freqs in subreaders
for (int i = 0; i < subReaders.Length; i++)
{
long sub = subReaders[i].TotalTermFreq(term);
if (sub == -1)
{
return -1;
}
total += sub;
}
return total;
}
public override sealed long GetSumDocFreq(string field)
{
EnsureOpen();
long total = 0; // sum doc freqs in subreaders
foreach (R reader in subReaders)
{
long sub = reader.GetSumDocFreq(field);
if (sub == -1)
{
return -1; // if any of the subs doesn't support it, return -1
}
total += sub;
}
return total;
}
public override sealed int GetDocCount(string field)
{
EnsureOpen();
int total = 0; // sum doc counts in subreaders
foreach (R reader in subReaders)
{
int sub = reader.GetDocCount(field);
if (sub == -1)
{
return -1; // if any of the subs doesn't support it, return -1
}
total += sub;
}
return total;
}
public override sealed long GetSumTotalTermFreq(string field)
{
EnsureOpen();
long total = 0; // sum doc total term freqs in subreaders
foreach (R reader in subReaders)
{
long sub = reader.GetSumTotalTermFreq(field);
if (sub == -1)
{
return -1; // if any of the subs doesn't support it, return -1
}
total += sub;
}
return total;
}
/// <summary>
/// Helper method for subclasses to get the corresponding reader for a doc ID </summary>
protected internal int ReaderIndex(int docID)
{
if (docID < 0 || docID >= maxDoc)
{
throw new System.ArgumentException("docID must be >= 0 and < maxDoc=" + maxDoc + " (got docID=" + docID + ")");
}
return ReaderUtil.SubIndex(docID, this.starts);
}
/// <summary>
/// Helper method for subclasses to get the docBase of the given sub-reader index. </summary>
protected internal int ReaderBase(int readerIndex)
{
if (readerIndex < 0 || readerIndex >= subReaders.Length)
{
throw new System.ArgumentException("readerIndex must be >= 0 and < getSequentialSubReaders().size()");
}
return this.starts[readerIndex];
}
protected internal override sealed IList<IndexReader> GetSequentialSubReaders()
{
return subReadersList;
}
}
}