Index: src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractIndex.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractIndex.java (revision 538490)
+++ src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractIndex.java (working copy)
@@ -32,6 +32,8 @@
import java.io.StringReader;
import java.util.BitSet;
import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
/**
* Implements common functionality for a lucene index.
@@ -90,6 +92,9 @@
/** The shared IndexReader for all read-only IndexReaders */
private SharedIndexReader sharedReader;
+ /** Caches all read-only IndexReaders */
+ private Map readOnlyReaders = new HashMap();
+
/**
* The indexing queue.
*/
@@ -205,7 +210,12 @@
CachingIndexReader cr = new CachingIndexReader(IndexReader.open(getDirectory()), cache);
sharedReader = new SharedIndexReader(cr);
}
- return new ReadOnlyIndexReader(sharedReader, deleted);
+ ReadOnlyIndexReader cachedReadOnlyIndexReader = (ReadOnlyIndexReader) readOnlyReaders.get(deleted);
+ if (cachedReadOnlyIndexReader == null) {
+ cachedReadOnlyIndexReader = new ReadOnlyIndexReader(sharedReader, deleted);
+ readOnlyReaders.put(deleted, cachedReadOnlyIndexReader);
+ }
+ return cachedReadOnlyIndexReader;
}
/**
@@ -317,6 +327,7 @@
sharedReader.close();
sharedReader = null;
}
+ readOnlyReaders.clear();
}
/**
Index: src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java (revision 538490)
+++ src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java (working copy)
@@ -20,7 +20,6 @@
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.index.TermEnum;
-import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.SortComparator;
import java.io.IOException;
@@ -38,6 +37,22 @@
*/
class SharedFieldCache {
+ /** Expert: Stores term text values and document ordering data. */
+ public static class StringIndex {
+
+ /** All the term values, in natural order. */
+ public final String[] lookup;
+
+ /** Terms indexed by document id. */
+ public final String[] terms;
+
+ /** Creates one of these objects */
+ public StringIndex(String[] terms, String[] lookup) {
+ this.terms = terms;
+ this.lookup = lookup;
+ }
+ }
+
/**
* Reference to the single instance of SharedFieldCache.
*/
@@ -72,7 +87,7 @@
* information.
* @throws IOException if an error occurs while reading from the index.
*/
- public FieldCache.StringIndex getStringIndex(IndexReader reader,
+ public SharedFieldCache.StringIndex getStringIndex(IndexReader reader,
String field,
String prefix,
SortComparator comparator,
@@ -79,9 +94,9 @@
boolean includeLookup)
throws IOException {
field = field.intern();
- FieldCache.StringIndex ret = lookup(reader, field, prefix, comparator);
+ SharedFieldCache.StringIndex ret = lookup(reader, field, prefix, comparator);
if (ret == null) {
- final int[] retArray = new int[reader.maxDoc()];
+ final String[] retArray = new String[reader.maxDoc()];
List mterms = null;
if (includeLookup) {
mterms = new ArrayList();
@@ -95,7 +110,6 @@
if (includeLookup) {
mterms.add(null); // for documents with term number 0
}
- int t = 1; // current term number
try {
if (termEnum.term() == null) {
@@ -114,10 +128,8 @@
termDocs.seek(termEnum);
while (termDocs.next()) {
- retArray[termDocs.doc()] = t;
+ retArray[termDocs.doc()] = term.text().substring(prefix.length());
}
-
- t++;
} while (termEnum.next());
} finally {
termDocs.close();
@@ -128,7 +140,7 @@
if (includeLookup) {
lookup = (String[]) mterms.toArray(new String[mterms.size()]);
}
- FieldCache.StringIndex value = new FieldCache.StringIndex(retArray, lookup);
+ SharedFieldCache.StringIndex value = new SharedFieldCache.StringIndex(retArray, lookup);
store(reader, field, prefix, comparator, value);
return value;
}
@@ -138,7 +150,7 @@
/**
* See if a StringIndex object is in the cache.
*/
- FieldCache.StringIndex lookup(IndexReader reader, String field,
+ SharedFieldCache.StringIndex lookup(IndexReader reader, String field,
String prefix, SortComparator comparer) {
Key key = new Key(field, prefix, comparer);
synchronized (this) {
@@ -146,7 +158,7 @@
if (readerCache == null) {
return null;
}
- return (FieldCache.StringIndex) readerCache.get(key);
+ return (SharedFieldCache.StringIndex) readerCache.get(key);
}
}
@@ -154,7 +166,7 @@
* Put a StringIndex value to cache.
*/
Object store(IndexReader reader, String field, String prefix,
- SortComparator comparer, FieldCache.StringIndex value) {
+ SortComparator comparer, SharedFieldCache.StringIndex value) {
Key key = new Key(field, prefix, comparer);
synchronized (this) {
HashMap readerCache = (HashMap) cache.get(reader);
Index: src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java (revision 538490)
+++ src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java (working copy)
@@ -16,8 +16,12 @@
*/
package org.apache.jackrabbit.core.query.lucene;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.jackrabbit.core.query.lucene.SharedFieldCache.StringIndex;
import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.ScoreDocComparator;
import org.apache.lucene.search.SortComparator;
@@ -23,8 +27,6 @@
import org.apache.lucene.search.SortComparator;
import org.apache.lucene.search.SortField;
-import java.io.IOException;
-
/**
* Implements a SortComparator which knows how to sort on a lucene
* field that contains values for multiple properties.
@@ -86,40 +88,57 @@
* @param reader the index reader.
* @param propertyName the name of the property to sort.
* @return a ScoreDocComparator for the
+ * @throws IOException
* @throws IOException
*/
- public ScoreDocComparator newComparator(final IndexReader reader, String propertyName)
- throws IOException {
- // get the StringIndex for propertyName
- final FieldCache.StringIndex index
- = SharedFieldCache.INSTANCE.getStringIndex(reader, field,
- FieldNames.createNamedValue(propertyName, ""),
- SharedFieldSortComparator.this,
- createComparatorValues);
+ public ScoreDocComparator newComparator(final IndexReader reader, final String propertyName) throws IOException {
+
+ final List readers = new ArrayList();
+ getIndexReaders(readers, reader);
+ final SharedFieldCache.StringIndex[] indexes = new SharedFieldCache.StringIndex[readers.size()];
+
+ int maxDoc = 0;
+ final int[] starts = new int[readers.size() + 1];
+
+ for (int i = 0; i < readers.size(); i++) {
+ IndexReader r = (IndexReader) readers.get(i);
+ starts[i] = maxDoc;
+ maxDoc += r.maxDoc();
+ indexes[i] = SharedFieldCache.INSTANCE.getStringIndex(r, field,
+ FieldNames.createNamedValue(propertyName, ""),
+ SharedFieldSortComparator.this, createComparatorValues);
+ }
+ starts[readers.size()] = maxDoc;
+
return new ScoreDocComparator() {
+
public final int compare(final ScoreDoc i, final ScoreDoc j) {
- final int fi = index.order[i.doc];
- final int fj = index.order[j.doc];
- if (fi < fj) {
- return -1;
- } else if (fi > fj) {
- return 1;
- } else {
- return 0;
- }
- }
+ int idx1 = readerIndex(i.doc);
+ int idx2 = readerIndex(j.doc);
+
+ String iTerm = indexes[idx1].terms[i.doc - starts[idx1]];
+ String jTerm = indexes[idx2].terms[j.doc - starts[idx2]];
+ if (iTerm == jTerm) return 0;
+ if (iTerm == null) return -1;
+ if (jTerm == null) return 1;
+
+ return iTerm.compareTo(jTerm);
+ }
+
/**
- * Returns an empty if no lookup table is available otherwise
- * the index term for the score doc i.
- *
- * @param i the score doc.
- * @return the sort value if available.
- */
+ * Returns an empty if no lookup table is available otherwise the
+ * index term for the score doc i.
+ *
+ * @param i
+ * the score doc.
+ * @return the sort value if available.
+ */
public Comparable sortValue(final ScoreDoc i) {
- if (index.lookup != null) {
- return index.lookup[index.order[i.doc]];
+ if (createComparatorValues) {
+ StringIndex index = indexes[readerIndex(i.doc)];
+ return index.terms[i.doc];
} else {
// return dummy value
return "";
@@ -129,6 +148,34 @@
public int sortType() {
return SortField.CUSTOM;
}
+
+ /**
+ * Returns the reader index for document n.
+ *
+ * @param n document number.
+ * @return the reader index.
+ */
+ private int readerIndex(int n) {
+ int lo = 0;
+ int hi = readers.size() - 1;
+
+ 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 {
+ while (mid + 1 < readers.size() && starts[mid + 1] == midValue) {
+ mid++;
+ }
+ return mid;
+ }
+ }
+ return hi;
+ }
+
};
}
@@ -138,4 +185,23 @@
protected Comparable getComparable(String termtext) {
throw new UnsupportedOperationException();
}
+
+ /**
+ * Checks if reader is of type {@link MultiIndexReader} and if
+ * that's the case calls this method recursively for each reader within the
+ * multi index reader; otherwise the reader is simply added to the list.
+ *
+ * @param readers the list of index readers.
+ * @param reader the reader to check.
+ */
+ private void getIndexReaders(List readers, IndexReader reader) {
+ if (reader instanceof MultiIndexReader) {
+ IndexReader[] r = ((MultiIndexReader) reader).getIndexReaders();
+ for (int i = 0; i < r.length; i++) {
+ getIndexReaders(readers, r[i]);
+ }
+ } else {
+ readers.add(reader);
+ }
+ }
}