You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-commits@lucene.apache.org by bu...@apache.org on 2007/07/27 00:52:09 UTC
svn commit: r560024 - in /lucene/java/trunk: ./
src/java/org/apache/lucene/index/ src/test/org/apache/lucene/index/
Author: buschmi
Date: Thu Jul 26 15:52:08 2007
New Revision: 560024
URL: http://svn.apache.org/viewvc?view=rev&rev=560024
Log:
LUCENE-781: MultiReader fixed to not throw NPE if isCurrent(), isOptimized() or getVersion() is called.
Added:
lucene/java/trunk/src/java/org/apache/lucene/index/MultiSegmentReader.java
Modified:
lucene/java/trunk/CHANGES.txt
lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java
lucene/java/trunk/src/java/org/apache/lucene/index/MultiReader.java
lucene/java/trunk/src/test/org/apache/lucene/index/TestMultiReader.java
Modified: lucene/java/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/java/trunk/CHANGES.txt?view=diff&rev=560024&r1=560023&r2=560024
==============================================================================
--- lucene/java/trunk/CHANGES.txt (original)
+++ lucene/java/trunk/CHANGES.txt Thu Jul 26 15:52:08 2007
@@ -46,6 +46,14 @@
6. LUCENE-957: RAMDirectory fixed to properly handle directories
larger than Integer.MAX_VALUE. (Doron Cohen)
+
+ 7. LUCENE-781: MultiReader fixed to not throw NPE if isCurrent(),
+ isOptimized() or getVersion() is called. Separated MultiReader
+ into two classes: MultiSegmentReader extends IndexReader, is
+ package-protected and is created automatically by IndexReader.open()
+ in case the index has multiple segments. The public MultiReader
+ now extends MultiSegmentReader and is intended to be used by users
+ who want to add their own subreaders. (Daniel Naber, Michael Busch)
New features
Modified: lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java?view=diff&rev=560024&r1=560023&r2=560024
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java Thu Jul 26 15:52:08 2007
@@ -208,7 +208,7 @@
}
}
- reader = new MultiReader(directory, infos, closeDirectory, readers);
+ reader = new MultiSegmentReader(directory, infos, closeDirectory, readers);
}
reader.deletionPolicy = deletionPolicy;
return reader;
Modified: lucene/java/trunk/src/java/org/apache/lucene/index/MultiReader.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/MultiReader.java?view=diff&rev=560024&r1=560023&r2=560024
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/index/MultiReader.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/index/MultiReader.java Thu Jul 26 15:52:08 2007
@@ -31,14 +31,7 @@
*
* @version $Id$
*/
-public class MultiReader extends IndexReader {
- private IndexReader[] subReaders;
- private int[] starts; // 1st docno for each segment
- private Hashtable normsCache = new Hashtable();
- private int maxDoc = 0;
- private int numDocs = -1;
- private boolean hasDeletions = false;
-
+public class MultiReader extends MultiSegmentReader {
/**
* <p>Construct a MultiReader aggregating the named set of (sub)readers.
* Directory locking for delete, undeleteAll, and setNorm operations is
@@ -48,438 +41,28 @@
* @throws IOException
*/
public MultiReader(IndexReader[] subReaders) throws IOException {
- super(subReaders.length == 0 ? null : subReaders[0].directory());
- initialize(subReaders);
- }
-
- /** Construct reading the named set of readers. */
- MultiReader(Directory directory, SegmentInfos sis, boolean closeDirectory, IndexReader[] subReaders) {
- super(directory, sis, closeDirectory);
- initialize(subReaders);
- }
-
- private void initialize(IndexReader[] subReaders) {
- this.subReaders = subReaders;
- starts = new int[subReaders.length + 1]; // build starts array
- for (int i = 0; i < subReaders.length; i++) {
- starts[i] = maxDoc;
- maxDoc += subReaders[i].maxDoc(); // compute maxDocs
-
- if (subReaders[i].hasDeletions())
- hasDeletions = true;
- }
- starts[subReaders.length] = maxDoc;
- }
-
-
- public TermFreqVector[] getTermFreqVectors(int n) throws IOException {
- ensureOpen();
- int i = readerIndex(n); // find segment num
- return subReaders[i].getTermFreqVectors(n - starts[i]); // dispatch to segment
- }
-
- public TermFreqVector getTermFreqVector(int n, String field)
- throws IOException {
- ensureOpen();
- int i = readerIndex(n); // find segment num
- return subReaders[i].getTermFreqVector(n - starts[i], field);
- }
-
-
- public void getTermFreqVector(int docNumber, String field, TermVectorMapper mapper) throws IOException {
- ensureOpen();
- int i = readerIndex(docNumber); // find segment num
- subReaders[i].getTermFreqVector(docNumber - starts[i], field, mapper);
- }
-
- public void getTermFreqVector(int docNumber, TermVectorMapper mapper) throws IOException {
- ensureOpen();
- int i = readerIndex(docNumber); // find segment num
- subReaders[i].getTermFreqVector(docNumber - starts[i], mapper);
- }
-
- public synchronized int numDocs() {
- // Don't call ensureOpen() here (it could affect performance)
- 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 int maxDoc() {
- // Don't call ensureOpen() here (it could affect performance)
- return maxDoc;
- }
-
- // inherit javadoc
- public Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException {
- ensureOpen();
- int i = readerIndex(n); // find segment num
- return subReaders[i].document(n - starts[i], fieldSelector); // dispatch to segment reader
- }
-
- public boolean 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 boolean hasDeletions() {
- // Don't call ensureOpen() here (it could affect performance)
- return hasDeletions;
- }
-
- protected void doDelete(int n) throws CorruptIndexException, IOException {
- numDocs = -1; // invalidate cache
- int i = readerIndex(n); // find segment num
- subReaders[i].deleteDocument(n - starts[i]); // dispatch to segment reader
- hasDeletions = true;
- }
-
- protected void doUndeleteAll() throws CorruptIndexException, IOException {
- 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:
- int lo = 0; // search starts array
- int hi = subReaders.length - 1; // for first element less
-
- while (hi >= lo) {
- int mid = (lo + hi) >> 1;
- int midValue = starts[mid];
- if (n < midValue)
- hi = mid - 1;
- else if (n > midValue)
- lo = mid + 1;
- else { // found a match
- while (mid+1 < subReaders.length && starts[mid+1] == midValue) {
- mid++; // scan to last match
- }
- return mid;
- }
- }
- return hi;
- }
-
- public boolean hasNorms(String field) throws IOException {
- ensureOpen();
- for (int i = 0; i < subReaders.length; i++) {
- if (subReaders[i].hasNorms(field)) return true;
- }
- return false;
- }
-
- private byte[] ones;
- private byte[] fakeNorms() {
- if (ones==null) ones=SegmentReader.createFakeNorms(maxDoc());
- return ones;
- }
-
- public synchronized byte[] norms(String field) throws IOException {
- ensureOpen();
- byte[] bytes = (byte[])normsCache.get(field);
- if (bytes != null)
- return bytes; // cache hit
- if (!hasNorms(field))
- return fakeNorms();
-
- bytes = new byte[maxDoc()];
- for (int i = 0; i < subReaders.length; i++)
- subReaders[i].norms(field, bytes, starts[i]);
- normsCache.put(field, bytes); // update cache
- return bytes;
- }
-
- public synchronized void norms(String field, byte[] result, int offset)
- throws IOException {
- ensureOpen();
- byte[] bytes = (byte[])normsCache.get(field);
- if (bytes==null && !hasNorms(field)) bytes=fakeNorms();
- if (bytes != null) // cache hit
- System.arraycopy(bytes, 0, result, offset, maxDoc());
-
- for (int i = 0; i < subReaders.length; i++) // read from segments
- subReaders[i].norms(field, result, offset + starts[i]);
- }
-
- protected void doSetNorm(int n, String field, byte value)
- throws CorruptIndexException, IOException {
- normsCache.remove(field); // clear cache
- int i = readerIndex(n); // find segment num
- subReaders[i].setNorm(n-starts[i], field, value); // dispatch
- }
-
- public TermEnum terms() throws IOException {
- ensureOpen();
- return new MultiTermEnum(subReaders, starts, null);
- }
-
- public TermEnum terms(Term term) throws IOException {
- ensureOpen();
- return new MultiTermEnum(subReaders, starts, term);
- }
-
- public int docFreq(Term t) throws IOException {
- ensureOpen();
- int total = 0; // sum freqs in segments
- for (int i = 0; i < subReaders.length; i++)
- total += subReaders[i].docFreq(t);
- return total;
- }
-
- public TermDocs termDocs() throws IOException {
- ensureOpen();
- return new MultiTermDocs(subReaders, starts);
- }
-
- public TermPositions termPositions() throws IOException {
- ensureOpen();
- return new MultiTermPositions(subReaders, starts);
- }
-
- protected void doCommit() throws IOException {
- for (int i = 0; i < subReaders.length; i++)
- subReaders[i].commit();
- }
-
- void startCommit() {
- super.startCommit();
- for (int i = 0; i < subReaders.length; i++) {
- subReaders[i].startCommit();
- }
- }
-
- void rollbackCommit() {
- super.rollbackCommit();
- for (int i = 0; i < subReaders.length; i++) {
- subReaders[i].rollbackCommit();
- }
+ super(subReaders.length == 0 ? null : subReaders[0].directory(),
+ null, false, subReaders);
}
- protected synchronized void doClose() throws IOException {
- for (int i = 0; i < subReaders.length; i++)
- subReaders[i].close();
- }
-
- public Collection getFieldNames (IndexReader.FieldOption fieldNames) {
- // maintain a unique set of field names
- ensureOpen();
- Set fieldSet = new HashSet();
+ /**
+ * Checks recursively if all subreaders are up to date.
+ */
+ public boolean isCurrent() throws CorruptIndexException, IOException {
for (int i = 0; i < subReaders.length; i++) {
- IndexReader reader = subReaders[i];
- Collection names = reader.getFieldNames(fieldNames);
- fieldSet.addAll(names);
- }
- return fieldSet;
- }
-
-}
-
-class MultiTermEnum extends TermEnum {
- private SegmentMergeQueue queue;
-
- private Term term;
- private int docFreq;
-
- public MultiTermEnum(IndexReader[] readers, int[] starts, Term t)
- throws IOException {
- queue = new SegmentMergeQueue(readers.length);
- for (int i = 0; i < readers.length; i++) {
- IndexReader reader = readers[i];
- TermEnum termEnum;
-
- if (t != null) {
- termEnum = reader.terms(t);
- } else
- termEnum = reader.terms();
-
- SegmentMergeInfo smi = new SegmentMergeInfo(starts[i], termEnum, reader);
- if (t == null ? smi.next() : termEnum.term() != null)
- queue.put(smi); // initialize queue
- else
- smi.close();
- }
-
- if (t != null && queue.size() > 0) {
- next();
- }
- }
-
- public boolean next() throws IOException {
- SegmentMergeInfo top = (SegmentMergeInfo)queue.top();
- if (top == null) {
- term = null;
- return false;
- }
-
- term = top.term;
- docFreq = 0;
-
- while (top != null && term.compareTo(top.term) == 0) {
- queue.pop();
- docFreq += top.termEnum.docFreq(); // increment freq
- if (top.next())
- queue.put(top); // restore queue
- else
- top.close(); // done with a segment
- top = (SegmentMergeInfo)queue.top();
- }
- return true;
- }
-
- public Term term() {
- return term;
- }
-
- public int docFreq() {
- return docFreq;
- }
-
- public void close() throws IOException {
- queue.close();
- }
-}
-
-class MultiTermDocs implements TermDocs {
- protected IndexReader[] readers;
- protected int[] starts;
- protected Term term;
-
- protected int base = 0;
- protected int pointer = 0;
-
- private TermDocs[] readerTermDocs;
- protected TermDocs current; // == readerTermDocs[pointer]
-
- public MultiTermDocs(IndexReader[] r, int[] s) {
- readers = r;
- starts = s;
-
- readerTermDocs = new TermDocs[r.length];
- }
-
- public int doc() {
- return base + current.doc();
- }
- public int freq() {
- return current.freq();
- }
-
- public void seek(Term term) {
- this.term = term;
- this.base = 0;
- this.pointer = 0;
- this.current = null;
- }
-
- public void seek(TermEnum termEnum) throws IOException {
- seek(termEnum.term());
- }
-
- public boolean next() throws IOException {
- for(;;) {
- if (current!=null && current.next()) {
- return true;
- }
- else if (pointer < readers.length) {
- base = starts[pointer];
- current = termDocs(pointer++);
- } else {
+ if (!subReaders[i].isCurrent()) {
return false;
}
}
- }
-
- /** Optimized implementation. */
- public int read(final int[] docs, final int[] freqs) throws IOException {
- while (true) {
- while (current == null) {
- if (pointer < readers.length) { // try next segment
- base = starts[pointer];
- current = termDocs(pointer++);
- } else {
- return 0;
- }
- }
- int end = current.read(docs, freqs);
- if (end == 0) { // none left in segment
- current = null;
- } else { // got some
- final int b = base; // adjust doc numbers
- for (int i = 0; i < end; i++)
- docs[i] += b;
- return end;
- }
- }
- }
-
- /* A Possible future optimization could skip entire segments */
- public boolean skipTo(int target) throws IOException {
- for(;;) {
- if (current != null && current.skipTo(target-base)) {
- return true;
- } else if (pointer < readers.length) {
- base = starts[pointer];
- current = termDocs(pointer++);
- } else
- return false;
- }
- }
-
- private TermDocs termDocs(int i) throws IOException {
- if (term == null)
- return null;
- TermDocs result = readerTermDocs[i];
- if (result == null)
- result = readerTermDocs[i] = termDocs(readers[i]);
- result.seek(term);
- return result;
- }
-
- protected TermDocs termDocs(IndexReader reader)
- throws IOException {
- return reader.termDocs();
- }
-
- public void close() throws IOException {
- for (int i = 0; i < readerTermDocs.length; i++) {
- if (readerTermDocs[i] != null)
- readerTermDocs[i].close();
- }
- }
-}
-
-class MultiTermPositions extends MultiTermDocs implements TermPositions {
- public MultiTermPositions(IndexReader[] r, int[] s) {
- super(r,s);
- }
-
- protected TermDocs termDocs(IndexReader reader) throws IOException {
- return (TermDocs)reader.termPositions();
- }
-
- public int nextPosition() throws IOException {
- return ((TermPositions)current).nextPosition();
+
+ // all subreaders are up to date
+ return true;
}
- public int getPayloadLength() {
- return ((TermPositions)current).getPayloadLength();
- }
-
- public byte[] getPayload(byte[] data, int offset) throws IOException {
- return ((TermPositions)current).getPayload(data, offset);
- }
-
-
- // TODO: Remove warning after API has been finalized
- public boolean isPayloadAvailable() {
- return ((TermPositions) current).isPayloadAvailable();
+ /** Not implemented.
+ * @throws UnsupportedOperationException
+ */
+ public long getVersion() {
+ throw new UnsupportedOperationException("MultiReader does not support this method.");
}
}
Added: lucene/java/trunk/src/java/org/apache/lucene/index/MultiSegmentReader.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/MultiSegmentReader.java?view=auto&rev=560024
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/index/MultiSegmentReader.java (added)
+++ lucene/java/trunk/src/java/org/apache/lucene/index/MultiSegmentReader.java Thu Jul 26 15:52:08 2007
@@ -0,0 +1,475 @@
+package org.apache.lucene.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.
+ */
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.FieldSelector;
+import org.apache.lucene.store.Directory;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+/**
+ * An IndexReader which reads indexes with multiple segments.
+ */
+class MultiSegmentReader extends IndexReader {
+ protected IndexReader[] subReaders;
+ private int[] starts; // 1st docno for each segment
+ private Hashtable normsCache = new Hashtable();
+ private int maxDoc = 0;
+ private int numDocs = -1;
+ private boolean hasDeletions = false;
+
+ /** Construct reading the named set of readers. */
+ MultiSegmentReader(Directory directory, SegmentInfos sis, boolean closeDirectory, IndexReader[] subReaders) {
+ super(directory, sis, closeDirectory);
+ initialize(subReaders);
+ }
+
+ private void initialize(IndexReader[] subReaders) {
+ this.subReaders = subReaders;
+ starts = new int[subReaders.length + 1]; // build starts array
+ for (int i = 0; i < subReaders.length; i++) {
+ starts[i] = maxDoc;
+ maxDoc += subReaders[i].maxDoc(); // compute maxDocs
+
+ if (subReaders[i].hasDeletions())
+ hasDeletions = true;
+ }
+ starts[subReaders.length] = maxDoc;
+ }
+
+
+ public TermFreqVector[] getTermFreqVectors(int n) throws IOException {
+ ensureOpen();
+ int i = readerIndex(n); // find segment num
+ return subReaders[i].getTermFreqVectors(n - starts[i]); // dispatch to segment
+ }
+
+ public TermFreqVector getTermFreqVector(int n, String field)
+ throws IOException {
+ ensureOpen();
+ int i = readerIndex(n); // find segment num
+ return subReaders[i].getTermFreqVector(n - starts[i], field);
+ }
+
+
+ public void getTermFreqVector(int docNumber, String field, TermVectorMapper mapper) throws IOException {
+ ensureOpen();
+ int i = readerIndex(docNumber); // find segment num
+ subReaders[i].getTermFreqVector(docNumber - starts[i], field, mapper);
+ }
+
+ public void getTermFreqVector(int docNumber, TermVectorMapper mapper) throws IOException {
+ ensureOpen();
+ int i = readerIndex(docNumber); // find segment num
+ subReaders[i].getTermFreqVector(docNumber - starts[i], mapper);
+ }
+
+ public boolean isOptimized() {
+ return false;
+ }
+
+ public synchronized int numDocs() {
+ // Don't call ensureOpen() here (it could affect performance)
+ 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 int maxDoc() {
+ // Don't call ensureOpen() here (it could affect performance)
+ return maxDoc;
+ }
+
+ // inherit javadoc
+ public Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException {
+ ensureOpen();
+ int i = readerIndex(n); // find segment num
+ return subReaders[i].document(n - starts[i], fieldSelector); // dispatch to segment reader
+ }
+
+ public boolean 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 boolean hasDeletions() {
+ // Don't call ensureOpen() here (it could affect performance)
+ return hasDeletions;
+ }
+
+ protected void doDelete(int n) throws CorruptIndexException, IOException {
+ numDocs = -1; // invalidate cache
+ int i = readerIndex(n); // find segment num
+ subReaders[i].deleteDocument(n - starts[i]); // dispatch to segment reader
+ hasDeletions = true;
+ }
+
+ protected void doUndeleteAll() throws CorruptIndexException, IOException {
+ 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:
+ int lo = 0; // search starts array
+ int hi = subReaders.length - 1; // for first element less
+
+ while (hi >= lo) {
+ int mid = (lo + hi) >> 1;
+ int midValue = starts[mid];
+ if (n < midValue)
+ hi = mid - 1;
+ else if (n > midValue)
+ lo = mid + 1;
+ else { // found a match
+ while (mid+1 < subReaders.length && starts[mid+1] == midValue) {
+ mid++; // scan to last match
+ }
+ return mid;
+ }
+ }
+ return hi;
+ }
+
+ public boolean hasNorms(String field) throws IOException {
+ ensureOpen();
+ for (int i = 0; i < subReaders.length; i++) {
+ if (subReaders[i].hasNorms(field)) return true;
+ }
+ return false;
+ }
+
+ private byte[] ones;
+ private byte[] fakeNorms() {
+ if (ones==null) ones=SegmentReader.createFakeNorms(maxDoc());
+ return ones;
+ }
+
+ public synchronized byte[] norms(String field) throws IOException {
+ ensureOpen();
+ byte[] bytes = (byte[])normsCache.get(field);
+ if (bytes != null)
+ return bytes; // cache hit
+ if (!hasNorms(field))
+ return fakeNorms();
+
+ bytes = new byte[maxDoc()];
+ for (int i = 0; i < subReaders.length; i++)
+ subReaders[i].norms(field, bytes, starts[i]);
+ normsCache.put(field, bytes); // update cache
+ return bytes;
+ }
+
+ public synchronized void norms(String field, byte[] result, int offset)
+ throws IOException {
+ ensureOpen();
+ byte[] bytes = (byte[])normsCache.get(field);
+ if (bytes==null && !hasNorms(field)) bytes=fakeNorms();
+ if (bytes != null) // cache hit
+ System.arraycopy(bytes, 0, result, offset, maxDoc());
+
+ for (int i = 0; i < subReaders.length; i++) // read from segments
+ subReaders[i].norms(field, result, offset + starts[i]);
+ }
+
+ protected void doSetNorm(int n, String field, byte value)
+ throws CorruptIndexException, IOException {
+ normsCache.remove(field); // clear cache
+ int i = readerIndex(n); // find segment num
+ subReaders[i].setNorm(n-starts[i], field, value); // dispatch
+ }
+
+ public TermEnum terms() throws IOException {
+ ensureOpen();
+ return new MultiTermEnum(subReaders, starts, null);
+ }
+
+ public TermEnum terms(Term term) throws IOException {
+ ensureOpen();
+ return new MultiTermEnum(subReaders, starts, term);
+ }
+
+ public int docFreq(Term t) throws IOException {
+ ensureOpen();
+ int total = 0; // sum freqs in segments
+ for (int i = 0; i < subReaders.length; i++)
+ total += subReaders[i].docFreq(t);
+ return total;
+ }
+
+ public TermDocs termDocs() throws IOException {
+ ensureOpen();
+ return new MultiTermDocs(subReaders, starts);
+ }
+
+ public TermPositions termPositions() throws IOException {
+ ensureOpen();
+ return new MultiTermPositions(subReaders, starts);
+ }
+
+ protected void doCommit() throws IOException {
+ for (int i = 0; i < subReaders.length; i++)
+ subReaders[i].commit();
+ }
+
+ void startCommit() {
+ super.startCommit();
+ for (int i = 0; i < subReaders.length; i++) {
+ subReaders[i].startCommit();
+ }
+ }
+
+ void rollbackCommit() {
+ super.rollbackCommit();
+ for (int i = 0; i < subReaders.length; i++) {
+ subReaders[i].rollbackCommit();
+ }
+ }
+
+ protected synchronized void doClose() throws IOException {
+ for (int i = 0; i < subReaders.length; i++)
+ subReaders[i].close();
+ }
+
+ public Collection getFieldNames (IndexReader.FieldOption fieldNames) {
+ // maintain a unique set of field names
+ ensureOpen();
+ Set fieldSet = new HashSet();
+ for (int i = 0; i < subReaders.length; i++) {
+ IndexReader reader = subReaders[i];
+ Collection names = reader.getFieldNames(fieldNames);
+ fieldSet.addAll(names);
+ }
+ return fieldSet;
+ }
+
+
+ static class MultiTermEnum extends TermEnum {
+ private SegmentMergeQueue queue;
+
+ private Term term;
+ private int docFreq;
+
+ public MultiTermEnum(IndexReader[] readers, int[] starts, Term t)
+ throws IOException {
+ queue = new SegmentMergeQueue(readers.length);
+ for (int i = 0; i < readers.length; i++) {
+ IndexReader reader = readers[i];
+ TermEnum termEnum;
+
+ if (t != null) {
+ termEnum = reader.terms(t);
+ } else
+ termEnum = reader.terms();
+
+ SegmentMergeInfo smi = new SegmentMergeInfo(starts[i], termEnum, reader);
+ if (t == null ? smi.next() : termEnum.term() != null)
+ queue.put(smi); // initialize queue
+ else
+ smi.close();
+ }
+
+ if (t != null && queue.size() > 0) {
+ next();
+ }
+ }
+
+ public boolean next() throws IOException {
+ SegmentMergeInfo top = (SegmentMergeInfo)queue.top();
+ if (top == null) {
+ term = null;
+ return false;
+ }
+
+ term = top.term;
+ docFreq = 0;
+
+ while (top != null && term.compareTo(top.term) == 0) {
+ queue.pop();
+ docFreq += top.termEnum.docFreq(); // increment freq
+ if (top.next())
+ queue.put(top); // restore queue
+ else
+ top.close(); // done with a segment
+ top = (SegmentMergeInfo)queue.top();
+ }
+ return true;
+ }
+
+ public Term term() {
+ return term;
+ }
+
+ public int docFreq() {
+ return docFreq;
+ }
+
+ public void close() throws IOException {
+ queue.close();
+ }
+ }
+
+ static class MultiTermDocs implements TermDocs {
+ protected IndexReader[] readers;
+ protected int[] starts;
+ protected Term term;
+
+ protected int base = 0;
+ protected int pointer = 0;
+
+ private TermDocs[] readerTermDocs;
+ protected TermDocs current; // == readerTermDocs[pointer]
+
+ public MultiTermDocs(IndexReader[] r, int[] s) {
+ readers = r;
+ starts = s;
+
+ readerTermDocs = new TermDocs[r.length];
+ }
+
+ public int doc() {
+ return base + current.doc();
+ }
+ public int freq() {
+ return current.freq();
+ }
+
+ public void seek(Term term) {
+ this.term = term;
+ this.base = 0;
+ this.pointer = 0;
+ this.current = null;
+ }
+
+ public void seek(TermEnum termEnum) throws IOException {
+ seek(termEnum.term());
+ }
+
+ public boolean next() throws IOException {
+ for(;;) {
+ if (current!=null && current.next()) {
+ return true;
+ }
+ else if (pointer < readers.length) {
+ base = starts[pointer];
+ current = termDocs(pointer++);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /** Optimized implementation. */
+ public int read(final int[] docs, final int[] freqs) throws IOException {
+ while (true) {
+ while (current == null) {
+ if (pointer < readers.length) { // try next segment
+ base = starts[pointer];
+ current = termDocs(pointer++);
+ } else {
+ return 0;
+ }
+ }
+ int end = current.read(docs, freqs);
+ if (end == 0) { // none left in segment
+ current = null;
+ } else { // got some
+ final int b = base; // adjust doc numbers
+ for (int i = 0; i < end; i++)
+ docs[i] += b;
+ return end;
+ }
+ }
+ }
+
+ /* A Possible future optimization could skip entire segments */
+ public boolean skipTo(int target) throws IOException {
+ for(;;) {
+ if (current != null && current.skipTo(target-base)) {
+ return true;
+ } else if (pointer < readers.length) {
+ base = starts[pointer];
+ current = termDocs(pointer++);
+ } else
+ return false;
+ }
+ }
+
+ private TermDocs termDocs(int i) throws IOException {
+ if (term == null)
+ return null;
+ TermDocs result = readerTermDocs[i];
+ if (result == null)
+ result = readerTermDocs[i] = termDocs(readers[i]);
+ result.seek(term);
+ return result;
+ }
+
+ protected TermDocs termDocs(IndexReader reader)
+ throws IOException {
+ return reader.termDocs();
+ }
+
+ public void close() throws IOException {
+ for (int i = 0; i < readerTermDocs.length; i++) {
+ if (readerTermDocs[i] != null)
+ readerTermDocs[i].close();
+ }
+ }
+ }
+
+ static class MultiTermPositions extends MultiTermDocs implements TermPositions {
+ public MultiTermPositions(IndexReader[] r, int[] s) {
+ super(r,s);
+ }
+
+ protected TermDocs termDocs(IndexReader reader) throws IOException {
+ return (TermDocs)reader.termPositions();
+ }
+
+ public int nextPosition() throws IOException {
+ return ((TermPositions)current).nextPosition();
+ }
+
+ public int getPayloadLength() {
+ return ((TermPositions)current).getPayloadLength();
+ }
+
+ public byte[] getPayload(byte[] data, int offset) throws IOException {
+ return ((TermPositions)current).getPayload(data, offset);
+ }
+
+
+ // TODO: Remove warning after API has been finalized
+ public boolean isPayloadAvailable() {
+ return ((TermPositions) current).isPayloadAvailable();
+ }
+ }
+}
Modified: lucene/java/trunk/src/test/org/apache/lucene/index/TestMultiReader.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/test/org/apache/lucene/index/TestMultiReader.java?view=diff&rev=560024&r1=560023&r2=560024
==============================================================================
--- lucene/java/trunk/src/test/org/apache/lucene/index/TestMultiReader.java (original)
+++ lucene/java/trunk/src/test/org/apache/lucene/index/TestMultiReader.java Thu Jul 26 15:52:08 2007
@@ -61,7 +61,7 @@
public void testDocument() throws IOException {
sis.read(dir);
- MultiReader reader = new MultiReader(dir, sis, false, readers);
+ MultiSegmentReader reader = new MultiSegmentReader(dir, sis, false, readers);
assertTrue(reader != null);
Document newDoc1 = reader.document(0);
assertTrue(newDoc1 != null);
@@ -76,7 +76,7 @@
public void testUndeleteAll() throws IOException {
sis.read(dir);
- MultiReader reader = new MultiReader(dir, sis, false, readers);
+ MultiSegmentReader reader = new MultiSegmentReader(dir, sis, false, readers);
assertTrue(reader != null);
assertEquals( 2, reader.numDocs() );
reader.deleteDocument(0);
@@ -88,7 +88,7 @@
reader.commit();
reader.close();
sis.read(dir);
- reader = new MultiReader(dir, sis, false, readers);
+ reader = new MultiSegmentReader(dir, sis, false, readers);
assertEquals( 2, reader.numDocs() );
reader.deleteDocument(0);
@@ -96,17 +96,17 @@
reader.commit();
reader.close();
sis.read(dir);
- reader = new MultiReader(dir, sis, false, readers);
+ reader = new MultiSegmentReader(dir, sis, false, readers);
assertEquals( 1, reader.numDocs() );
}
public void testTermVectors() {
- MultiReader reader = new MultiReader(dir, sis, false, readers);
+ MultiSegmentReader reader = new MultiSegmentReader(dir, sis, false, readers);
assertTrue(reader != null);
}
- /* known to fail, see https://issues.apache.org/jira/browse/LUCENE-781
+
public void testIsCurrent() throws IOException {
RAMDirectory ramDir1=new RAMDirectory();
addDoc(ramDir1, "test foo", true);
@@ -135,6 +135,4 @@
iw.addDocument(doc);
iw.close();
}
- */
-
}