/* * #! * Ontopia Engine * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * !# */ package net.ontopia.topicmaps.query.impl.utils; import java.util.Set; import java.util.List; import java.util.Iterator; import net.ontopia.utils.OntopiaRuntimeException; import net.ontopia.topicmaps.query.core.InvalidQueryException; import net.ontopia.topicmaps.query.parser.Variable; import net.ontopia.topicmaps.query.parser.OrClause; import net.ontopia.topicmaps.query.parser.NotClause; import net.ontopia.topicmaps.query.parser.PredicateIF; import net.ontopia.topicmaps.query.parser.AbstractClause; import net.ontopia.topicmaps.query.parser.PredicateClause; import net.ontopia.topicmaps.impl.utils.Argument; public class SimpleCostEstimator extends CostEstimator { /** * INTERNAL: Computes the cost of evaluating the given clause * in the given context of variable bindings. The cost largely * depends on the number of unbound variables in the clause. * @param context A set of bound variables. * @param clause The clause whose cost we want to compute. * @param literalvars Contains the variables representing literals. * Only an issue in rules. * @param rulename The name of the current rule (so we can delay * recursive evaluation). */ public int computeCost(Set context, AbstractClause clause, Set literalvars, String rulename) { int cost = 0; // penalties for unbound variables Iterator it = clause.getAllVariables().iterator(); while (it.hasNext()) { Object variable = it.next(); if (!context.contains(variable)) cost += 10; if (literalvars.contains(variable)) cost += 1; // this is really a literal... // penalties and bonuses for various kinds of predicates if (clause instanceof PredicateClause) { // initialize PredicateIF predicate = ((PredicateClause) clause).getPredicate(); PredicateSignature sign = null; try { sign = PredicateSignature.getSignature(predicate); } catch (InvalidQueryException e) { throw new OntopiaRuntimeException(e); } // check for specific predicates (FIXME: generalize!) String name = predicate.getName(); if (name.equals("instance-of")) cost += 1; else if (name.equals("/=")) cost -= 5; else if (name.equals("value-like")) cost -= 11; // value-like must go first else if (name.equals(rulename)) cost += 100; // recursive evaluation should happen late // check for arguments which must be bound Argument lastArgument = null; List realargs = clause.getArguments(); for (int ix = 0; ix < realargs.size(); ix++) { Argument argument = sign.getArgument(ix); Object arg = realargs.get(ix); if (arg instanceof Variable) { if (!context.contains(arg) && (argument == null ? (lastArgument == null ? false : (lastArgument.isRepeatable() && lastArgument.mustBeBound())) : // take repeatable arguments into account argument.mustBeBound())) cost += 100000; // can't run this one now } if (argument != null) lastArgument = argument; } } else if (clause instanceof NotClause) cost += 100; // not clauses must be done late else if (clause instanceof OrClause && ((OrClause) clause).getAlternatives().size() == 1) cost += 50; // optional clauses should also be done late } // penalties for starting from literals // NEW: this bit is somewhat untried // FIXME: this appears to also penalize parameters!! cost += clause.getAllLiterals().size(); // that is, 1 point per literal return cost; } }