/* 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/>.
*
* PredicateFinder.java
*
* Created on 13 January 2006, 09:58
*
*/
package no.sesat.search.query.finder;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import no.sesat.search.query.AndNotClause;
import no.sesat.search.query.BinaryClause;
import no.sesat.search.query.XorClause;
import no.sesat.commons.visitor.AbstractReflectionVisitor;
import no.sesat.search.query.Clause;
import no.sesat.search.query.NotClause;
import no.sesat.search.query.token.TokenEvaluationEngine;
import no.sesat.search.query.token.TokenPredicate;
import org.apache.commons.collections.Predicate;
import org.apache.log4j.Logger;
/**
* Responsible for Visiting the Query and finding where the predicate lies.
* This class is thread-safe.
* TODO Handle predicates under NOT and ANDNOT clauses. Currently they are ignored.
*
*
* @version $Id$
*/
public final class PredicateFinder extends AbstractReflectionVisitor {
private static final Logger LOG = Logger.getLogger(PredicateFinder.class);
private Predicate predicate;
private TokenEvaluationEngine engine;
private boolean singleMode = false;
private final Set<Clause> clauses = new HashSet<Clause>();
private Clause firstClause;
/** find the first clause containing the predicate.
** @param root
* @param predicate
* @param engine
* @return
*/
public synchronized Clause findFirstClause(
final Clause root,
final Predicate predicate,
final TokenEvaluationEngine engine) {
singleMode = true;
findImpl(root, predicate, engine);
singleMode = false;
return firstClause;
}
/** find all the clauses containing the predicate.
* returns largest multi-terms clauses and before leaf clauses.
* @param root
* @param predicate
* @param engine
* @return
**/
public synchronized Set<Clause> findClauses(
final Clause root,
final Predicate predicate,
final TokenEvaluationEngine engine) {
findImpl(root, predicate, engine);
return Collections.unmodifiableSet(new HashSet<Clause>(clauses));
}
private void findImpl(
final Clause root,
final Predicate predicate,
final TokenEvaluationEngine engine){
this.predicate = predicate;
this.engine = engine;
firstClause = null;
clauses.clear();
visit(root);
}
/** TODO comment me. *
* @param clause
*/
protected void visitImpl(final BinaryClause clause) {
if(null == firstClause){
evaluate(clause);
clause.getFirstClause().accept(this);
clause.getSecondClause().accept(this);
}
}
/** TODO comment me. *
* @param clause
*/
protected void visitImpl(final XorClause clause) {
if(null == firstClause){
clause.getFirstClause().accept(this);
clause.getSecondClause().accept(this);
}
}
/** TODO comment me. *
* @param clause
*/
protected void visitImpl(final NotClause clause) {}
/** TODO comment me. *
* @param clause
*/
protected void visitImpl(final AndNotClause clause) {}
/** TODO comment me. *
* @param clause
*/
protected void visitImpl(final Clause clause) {
if(null == firstClause){
evaluate(clause);
}
}
/** Find if this clause contains (either known, possible, or custom joined) predicates corresponding to
* PredicateScores listed in the context.
* @param the clause we are scoring.
* @param addition whether the score will be added or subtracted.
*/
private void evaluate(final Clause clause) {
final Set<TokenPredicate> knownPredicates = clause.getKnownPredicates();
final Set<TokenPredicate> possiblePredicates = clause.getPossiblePredicates();
// if this is a possiblePredicate or a all|any|none|not predicate
// find out if it is now applicable...
boolean applicable = knownPredicates.contains(predicate);
applicable |=
possiblePredicates.contains(predicate) || !(predicate instanceof TokenPredicate)
&& predicate.evaluate(engine);
if (applicable) {
if(singleMode){
firstClause = clause;
}else{
clauses.add(clause);
}
}
}
}