package org.apache.lucene.queries.function;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.Explanation;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.QueryVisitor;
import org.apache.lucene.search.ScoreMode;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.Weight;
public class FunctionQuery extends Query {
final ValueSource func;
public FunctionQuery(ValueSource func) {
this.func=func;
}
public ValueSource getValueSource() {
return func;
}
protected class FunctionWeight extends Weight {
protected final IndexSearcher searcher;
protected final float boost;
protected final Map context;
public FunctionWeight(IndexSearcher searcher, float boost) throws IOException {
super(FunctionQuery.this);
this.searcher = searcher;
this.context = ValueSource.newContext(searcher);
func.createWeight(context, searcher);
this.boost = boost;
}
@Override
public void (Set<Term> terms) {}
@Override
public Scorer scorer(LeafReaderContext context) throws IOException {
return new AllScorer(context, this, boost);
}
@Override
public boolean isCacheable(LeafReaderContext ctx) {
return false;
}
@Override
public Explanation explain(LeafReaderContext context, int doc) throws IOException {
return ((AllScorer)scorer(context)).explain(doc);
}
}
@Override
public void visit(QueryVisitor visitor) {
visitor.visitLeaf(this);
}
protected class AllScorer extends Scorer {
final IndexReader reader;
final FunctionWeight weight;
final int maxDoc;
final float boost;
final DocIdSetIterator iterator;
final FunctionValues vals;
public AllScorer(LeafReaderContext context, FunctionWeight w, float boost) throws IOException {
super(w);
this.weight = w;
this.boost = boost;
this.reader = context.reader();
this.maxDoc = reader.maxDoc();
iterator = DocIdSetIterator.all(context.reader().maxDoc());
vals = func.getValues(weight.context, context);
}
@Override
public DocIdSetIterator iterator() {
return iterator;
}
@Override
public int docID() {
return iterator.docID();
}
@Override
public float score() throws IOException {
float val = vals.floatVal(docID());
if (val >= 0 == false) {
return 0;
} else {
return boost * val;
}
}
@Override
public float getMaxScore(int upTo) throws IOException {
return Float.POSITIVE_INFINITY;
}
public Explanation explain(int doc) throws IOException {
Explanation expl = vals.explain(doc);
if (expl.getValue().floatValue() < 0) {
expl = Explanation.match(0, "truncated score, max of:", Explanation.match(0f, "minimum score"), expl);
} else if (Float.isNaN(expl.getValue().floatValue())) {
expl = Explanation.match(0, "score, computed as (score == NaN ? 0 : score) since NaN is an illegal score from:", expl);
}
return Explanation.match(boost * expl.getValue().floatValue(), "FunctionQuery(" + func + "), product of:",
vals.explain(doc),
Explanation.match(weight.boost, "boost"));
}
}
@Override
public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException {
return new FunctionQuery.FunctionWeight(searcher, boost);
}
@Override
public String toString(String field)
{
return func.toString();
}
@Override
public boolean equals(Object other) {
return sameClassAs(other) &&
func.equals(((FunctionQuery) other).func);
}
@Override
public int hashCode() {
return classHash() ^ func.hashCode();
}
}