blob: 96f822fe666ed8e2a2689675cc33423bab97b2e3 [file] [log] [blame]
package org.apache.rya.indexing.IndexPlanValidator;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.util.Iterator;
import java.util.Set;
import org.apache.rya.api.domain.VarNameUtils;
import org.apache.rya.indexing.external.tupleSet.ExternalTupleSet;
import org.eclipse.rdf4j.query.algebra.BindingSetAssignment;
import org.eclipse.rdf4j.query.algebra.Filter;
import org.eclipse.rdf4j.query.algebra.Join;
import org.eclipse.rdf4j.query.algebra.Projection;
import org.eclipse.rdf4j.query.algebra.QueryModelNode;
import org.eclipse.rdf4j.query.algebra.StatementPattern;
import org.eclipse.rdf4j.query.algebra.TupleExpr;
import org.eclipse.rdf4j.query.algebra.helpers.AbstractQueryModelVisitor;
import com.google.common.collect.Sets;
public class ThreshholdPlanSelector implements IndexedQueryPlanSelector {
private TupleExpr query;
private int queryNodeCount = 0;
public ThreshholdPlanSelector(TupleExpr query) {
this.query = query;
QueryNodeCount qnc = new QueryNodeCount();
query.visit(qnc);
this.queryNodeCount = qnc.getNodeCount();
if(queryNodeCount == 0) {
throw new IllegalArgumentException("TupleExpr must contain at least one node!");
}
}
@Override
public TupleExpr getThreshholdQueryPlan(Iterator<TupleExpr> tuples, double threshhold, double indexWeight,
double commonVarWeight, double extProdWeight) {
if (threshhold < 0 || threshhold > 1) {
throw new IllegalArgumentException("Threshhold must be between 0 and 1!");
}
double minCost = Double.MAX_VALUE;
TupleExpr minTup = null;
double tempCost = 0;
TupleExpr tempTup = null;
while (tuples.hasNext()) {
tempTup = tuples.next();
tempCost = getCost(tempTup, indexWeight, commonVarWeight, extProdWeight);
if (tempCost < minCost) {
minCost = tempCost;
minTup = tempTup;
}
if (minCost <= threshhold) {
return minTup;
}
}
return minTup;
}
public double getCost(TupleExpr te, double indexWeight, double commonVarWeight, double dirProdWeight) {
if (indexWeight + commonVarWeight + dirProdWeight != 1) {
throw new IllegalArgumentException("Weights must sum to 1!");
}
if(te == null) {
throw new IllegalArgumentException("TupleExpr cannot be null!");
}
QueryNodeCount qnc = new QueryNodeCount();
te.visit(qnc);
double nodeCount = qnc.getNodeCount();
double commonJoinVars = qnc.getCommonJoinVarCount();
double joinVars = qnc.getJoinVarCount();
double joinCount = qnc.getJoinCount();
double dirProdCount = qnc.getDirProdCount();
double dirProductScale;
if(queryNodeCount > nodeCount) {
dirProductScale = 1/ (queryNodeCount - nodeCount);
} else {
dirProductScale = 1/ (queryNodeCount - nodeCount + 1);
}
double joinVarRatio;
double dirProductRatio;
if(joinVars != 0) {
joinVarRatio = (joinVars - commonJoinVars) / joinVars;
} else {
joinVarRatio = 0;
}
if(joinCount != 0) {
dirProductRatio = dirProdCount / joinCount;
} else {
dirProductRatio = 0;
}
double cost = indexWeight * (nodeCount / queryNodeCount) + commonVarWeight*joinVarRatio
+ dirProdWeight *dirProductRatio*dirProductScale;
// System.out.println("Tuple is " + te + " and cost is " + cost);
// System.out.println("Node count is " + nodeCount + " and query node count is " + queryNodeCount);
// System.out.println("Common join vars are " + commonJoinVars + " and join vars " + joinVars);
// System.out.println("Join count is " + joinCount + " and direct prod count is " + dirProdCount);
return cost;
}
public static class QueryNodeCount extends AbstractQueryModelVisitor<RuntimeException> {
private int nodeCount = 0;
private int commonJoinVars = 0;
private int joinVars = 0;
private int joinCount = 0;
private int dirProdCount = 0;
public int getCommonJoinVarCount() {
return commonJoinVars;
}
public int getJoinVarCount() {
return joinVars;
}
public int getNodeCount() {
return nodeCount;
}
public int getJoinCount() {
return joinCount;
}
public int getDirProdCount() {
return dirProdCount;
}
public void meet(Projection node) {
node.getArg().visit(this);
}
public void meetNode(QueryModelNode node) {
if (node instanceof ExternalTupleSet) {
nodeCount += 1;
return;
}
super.meetNode(node);
return;
}
@Override
public void meet(StatementPattern node) {
nodeCount += 1;
return;
}
@Override
public void meet(Filter node) {
nodeCount += 1;
node.getArg().visit(this);
}
public void meet(BindingSetAssignment node) {
nodeCount += 1;
return;
}
@Override
public void meet(Join node) {
int tempCount = 0;
Set<String> lNames = node.getLeftArg().getAssuredBindingNames();
Set<String> rNames = node.getRightArg().getAssuredBindingNames();
for(String s: node.getLeftArg().getBindingNames()) {
if (VarNameUtils.isConstant(s)) {
lNames.remove(s);
}
}
for(String s: node.getRightArg().getBindingNames()) {
if (VarNameUtils.isConstant(s)) {
rNames.remove(s);
}
}
joinVars += Math.min(lNames.size(), rNames.size());
tempCount = Sets.intersection(lNames, rNames).size();
if (tempCount == 0) {
dirProdCount += 1;
} else {
commonJoinVars += tempCount;
}
joinCount += 1;
super.meet(node);
}
}
}