Index: src/java/org/apache/lucene/search/FilteredTermEnum.java =================================================================== --- src/java/org/apache/lucene/search/FilteredTermEnum.java (revision 764815) +++ src/java/org/apache/lucene/search/FilteredTermEnum.java (working copy) @@ -26,9 +26,12 @@
Term enumerations are always ordered by Term.compareTo(). Each term in
the enumeration is greater than all that precede it. */
public abstract class FilteredTermEnum extends TermEnum {
- private Term currentTerm = null;
- private TermEnum actualEnum = null;
+ /** the current term */
+ protected Term currentTerm = null;
+ /** the delegate enum - to set this member use {@link #setEnum} */
+ protected TermEnum actualEnum = null;
+
public FilteredTermEnum() {}
/** Equality compare on the term */
@@ -40,6 +43,10 @@
/** Indicates the end of the enumeration has been reached */
protected abstract boolean endEnum();
+ /**
+ * use this method to set the actual TermEnum (e.g. in ctor),
+ * it will be automatically positioned on the first matching term.
+ */
protected void setEnum(TermEnum actualEnum) throws IOException {
this.actualEnum = actualEnum;
// Find the first term that matches
@@ -54,7 +61,8 @@
* Returns -1 if no Term matches or all terms have been enumerated.
*/
public int docFreq() {
- if (actualEnum == null) return -1;
+ if (currentTerm == null) return -1;
+ assert actualEnum != null;
return actualEnum.docFreq();
}
@@ -85,7 +93,7 @@
/** Closes the enumeration to further activity, freeing resources. */
public void close() throws IOException {
- actualEnum.close();
+ if (actualEnum != null) actualEnum.close();
currentTerm = null;
actualEnum = null;
}
Index: src/java/org/apache/lucene/search/MultiTermQuery.java
===================================================================
--- src/java/org/apache/lucene/search/MultiTermQuery.java (revision 764815)
+++ src/java/org/apache/lucene/search/MultiTermQuery.java (working copy)
@@ -45,6 +45,7 @@
public abstract class MultiTermQuery extends Query {
protected Term term;
protected boolean constantScoreRewrite = false;
+ int lastNumberOfTerms = -1;
/** Constructs a query for terms matching term. */
public MultiTermQuery(Term term) {
@@ -67,18 +68,35 @@
protected abstract FilteredTermEnum getEnum(IndexReader reader)
throws IOException;
+ /**
+ * Expert: Return the number of unique terms visited during the last execution of the query.
+ * If there are many of them, you may consider using another query type
+ * or optimize your term count in index.
+ * This method is not thread safe, be sure to only call it when no query is running!
+ * The results are only valid, if the test was done on a one-segment index (optimized),
+ * as search distributes the query to each single segment and the term count is reset
+ * for each segment and you only see a value for the last (and smallest segment).
+ * @throws IllegalStateException if query was not yet rewritten/executed.
+ */
+ public int getLastNumberOfTerms() {
+ if (lastNumberOfTerms < 0) throw new IllegalStateException();
+ return lastNumberOfTerms;
+ }
+
protected Filter getFilter() {
return new MultiTermFilter(this);
}
public Query rewrite(IndexReader reader) throws IOException {
if (!constantScoreRewrite) {
+ lastNumberOfTerms = 0;
FilteredTermEnum enumerator = getEnum(reader);
BooleanQuery query = new BooleanQuery(true);
try {
do {
Term t = enumerator.term();
if (t != null) {
+ lastNumberOfTerms++;
TermQuery tq = new TermQuery(t); // found a match
tq.setBoost(getBoost() * enumerator.difference()); // set the boost
query.add(tq, BooleanClause.Occur.SHOULD); // add to query
@@ -150,14 +168,15 @@
MultiTermQuery mtq;
abstract class TermGenerator {
- public void generate(IndexReader reader) throws IOException {
- TermEnum enumerator = mtq.getEnum(reader);
+ public void generate(IndexReader reader, TermEnum enumerator) throws IOException {
+ mtq.lastNumberOfTerms = 0;
TermDocs termDocs = reader.termDocs();
try {
do {
Term term = enumerator.term();
if (term == null)
break;
+ mtq.lastNumberOfTerms++;
termDocs.seek(term);
while (termDocs.next()) {
handleDoc(termDocs.doc());
@@ -165,7 +184,6 @@
} while (enumerator.next());
} finally {
termDocs.close();
- enumerator.close();
}
}
abstract public void handleDoc(int doc);
@@ -176,28 +194,42 @@
}
public BitSet bits(IndexReader reader) throws IOException {
- final BitSet bitSet = new BitSet(reader.maxDoc());
- new TermGenerator() {
- public void handleDoc(int doc) {
- bitSet.set(doc);
- }
- }.generate(reader);
- return bitSet;
+ final TermEnum enumerator = mtq.getEnum(reader);
+ try {
+ final BitSet bitSet = new BitSet(reader.maxDoc());
+ new TermGenerator() {
+ public void handleDoc(int doc) {
+ bitSet.set(doc);
+ }
+ }.generate(reader, enumerator);
+ return bitSet;
+ } finally {
+ enumerator.close();
+ }
}
public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
- final OpenBitSet bitSet = new OpenBitSet(reader.maxDoc());
- new TermGenerator() {
- public void handleDoc(int doc) {
- bitSet.set(doc);
+ final TermEnum enumerator = mtq.getEnum(reader);
+ try {
+ // if current term in enum is null, the enum is empty -> shortcut
+ if (enumerator.term() == null) {
+ mtq.lastNumberOfTerms = 0;
+ return DocIdSet.EMPTY_DOCIDSET;
}
- }.generate(reader);
-
- return bitSet;
+ // else fill into a OpenBitSet
+ final OpenBitSet bitSet = new OpenBitSet(reader.maxDoc());
+ new TermGenerator() {
+ public void handleDoc(int doc) {
+ bitSet.set(doc);
+ }
+ }.generate(reader, enumerator);
+ return bitSet;
+ } finally {
+ enumerator.close();
+ }
}
public boolean equals(Object o) {
-
if (this == o)
return true;
if (!(o instanceof MultiTermFilter))