/*
* Copyright (2005-2012) Schibsted ASA
* This file is part of Possom.
*
* Possom is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Possom is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Possom. If not, see <http://www.gnu.org/licenses/>.
*/
package no.sesat.search.query.analyser;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import no.sesat.commons.ioc.BaseContext;
import no.sesat.commons.ioc.ContextWrapper;
import no.sesat.search.query.Query;
import no.sesat.search.query.token.EvaluationRuntimeException;
import no.sesat.search.query.token.TokenEvaluationEngineContext;
import no.sesat.search.query.token.TokenPredicate;
import org.apache.commons.collections.Predicate;
import org.apache.log4j.Logger;
/**
* The AnalysisRule provides scoring of a query based on a set of
* {@link Predicate} instances.
*
*
* @version $Id$
*/
public final class AnalysisRule {
public interface Context extends TokenEvaluationEngineContext{
String getRuleName();
Appendable getReportBuffer();
}
private static final Logger LOG = Logger.getLogger(AnalysisRule.class);
/** Although we have access to the Predicates through the PredicateScore object it is possible to do set arithmetic
* when we can access the predicate collection wihtout looping them out first.
**/
private final Map<PredicateScore,Predicate> predicates = new HashMap<PredicateScore,Predicate>();
private Map<Predicate,String> predicateNames;
/**
* Adds a {@link Predicate} and an accompanying score. The predicate will at
* evaluation time be evaluated with a {@link TokenEvaluationEngine} as
* input.
*
* @param predicate
* a predicate to evaluate at evaluation time.
* @param score
* the score associated with the predicate.
*/
public void addPredicateScore(final Predicate predicate, final int score) {
final PredicateScore pScore = new PredicateScore(predicate, score);
predicates.put(pScore, predicate);
}
/**
* Evaluates this rule. All added predicates are evaluated using engine
* as input. The score of those predicates that are true are added to the
* final score (output of this method).
*
* @param query
* the query to apply the rule to.
* @param context
* @return the score of this rule when applied to query.
*/
public int evaluate(final Query query, final Context context) {
final boolean additivity = true; // TODO implement inside NOT ANDNOT clauses to deduct from score.
final StringBuilder internalReport = new StringBuilder();
final Scorer scorer = new Scorer(ContextWrapper.wrap(Scorer.Context.class,
new BaseContext() {
public String getNameForAnonymousPredicate(final Predicate predicate) {
return predicateNames.get(predicate);
}
public Appendable getReportBuffer(){
return internalReport;
}
},
context));
try{
// update the engine with the query's evaluation state
context.getTokenEvaluationEngine().setState(query.getEvaluationState());
for (PredicateScore predicateScore : predicates.keySet()) {
try{
assert null != predicateScore.getPredicate()
: "Disappearing predicate from score " + predicateScore;
if (predicateScore.getPredicate().evaluate(context.getTokenEvaluationEngine())) {
if (additivity) {
scorer.addScore(predicateScore);
} else {
scorer.minusScore(predicateScore);
}
}
}catch(EvaluationRuntimeException ie){
// make sure to mention in the analysis logs that the scoring is corrupt.
scorer.error(predicateScore);
}
}
context.getReportBuffer().append(
" <analysis name=\"" + context.getRuleName() + "\" score=\"" + scorer.getScore() + "\">\n"
+ internalReport.toString()
+ " </analysis>\n");
}catch(IOException ioe){
LOG.warn("Failed to append report results", ioe);
}finally{
context.getTokenEvaluationEngine().setState(null);
}
return scorer.getScore();
}
/** Names to use for predicates. **/
void setPredicateNameMap(final Map<Predicate,String> predicateNames) {
this.predicateNames = predicateNames;
}
}