package org.apache.lucene.search; import java.io.IOException; import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.search.SecondOrderCollector.FinalValueType; /** * * This is a 2nd attempt on the 2nd order operators, while it works, * it will work only for searching inside the boundaries of index * segments (ie no distributed search) * */ public class SecondOrderQuery extends Query { private static final long serialVersionUID = -5670377581753190942L; Query firstOrderQuery; private SecondOrderCollector secondOrderCollector; private boolean alreadyExecuted; private boolean needsScoring; /** * Constructs a new query which applies a filter to the results of the * original query. Filter.getDocIdSet() will be called every time this query * is used in a search. * * @param query * Query to be filtered, cannot be <code>null</code>. * @param needsScoring * Whether the query should apply scoring algorithm (or is a simple * boolean, 1/0 - which runs faster; default is True) */ public SecondOrderQuery(Query query, SecondOrderCollector collector, boolean needsScoring) { this.firstOrderQuery = query; this.secondOrderCollector = collector; this.alreadyExecuted = false; if (collector == null) { throw new IllegalStateException("Collector must not be null"); } } public SecondOrderQuery(Query query, SecondOrderCollector collector) { this(query, collector, true); } /** * Returns a Weight that applies the filter to the enclosed query's Weight. * This is accomplished by overriding the Scorer returned by the Weight. * * The Weight is prepared before the search begins, but since we are inside * the second order query, we start searching, collect results and then * return the Weight object, which carries with itself the results of the * first-order query */ public Weight createWeight(final IndexSearcher searcher, boolean needsScores) throws IOException { Weight firstOrderWeight = firstOrderQuery.createWeight(searcher, needsScores); //System.out.println("preparing: " + this.secondOrderCollector); // conduct search only if initialization of necessary caches went well if (!alreadyExecuted && secondOrderCollector.searcherInitialization(searcher, firstOrderWeight)) { //System.out.println("Executing: " + firstOrderQuery.toString()); searcher.search(firstOrderQuery, (Collector) secondOrderCollector); //System.out.println(" searching: " + this.secondOrderCollector); // TODO: can we avoid being called (initialized) in a loop? // this looks like a bad design (on my side) if it happens // it happens when 2nd order operators are nested alreadyExecuted = true; } //System.out.println("done:" + this.secondOrderCollector); // no logging, we are basic lucene class return new SecondOrderWeight(firstOrderWeight, secondOrderCollector); } /** Rewrites the wrapped query. */ public Query rewrite(IndexReader reader) throws IOException { Query rewritten = firstOrderQuery.rewrite(reader); if (rewritten != firstOrderQuery) { SecondOrderQuery clone = new SecondOrderQuery(rewritten, this.secondOrderCollector); return clone; } else { return this; } } public Query getQuery() { return firstOrderQuery; } public SecondOrderCollector getcollector() { return secondOrderCollector; } /** * Recursively sets the implemantation type of the * final score (down the wrapped queries, if they * are of the SecondOrderQuery */ public void setFinalValueType(FinalValueType type) { secondOrderCollector.setFinalValueType(type); if (firstOrderQuery instanceof SecondOrderQuery) { ((SecondOrderQuery) firstOrderQuery).setFinalValueType(type); } } // inherit javadoc public void extractTerms(Set<Term> terms) { ((SecondOrderQuery) getQuery()).extractTerms(terms); } /** Prints a user-readable version of this query. */ public String toString(String s) { StringBuffer buffer = new StringBuffer(); buffer.append("SecondOrderQuery("); buffer.append(firstOrderQuery.toString(s)); buffer.append(", collector=" + (secondOrderCollector!=null ? secondOrderCollector.toString() : "null")); buffer.append(")"); return buffer.toString(); } /** Returns true iff <code>o</code> is equal to this. */ public boolean equals(Object o) { if (o instanceof SecondOrderQuery) { SecondOrderQuery fq = (SecondOrderQuery) o; return (firstOrderQuery.equals(fq.firstOrderQuery) && secondOrderCollector.equals(fq.secondOrderCollector)); } return false; } /** Returns a hash code value for this object. */ public int hashCode() { return firstOrderQuery.hashCode() ^ secondOrderCollector.hashCode(); } }