blob: 78b1f9209c5877a4c80b0cf221d84eafc3a7b32b [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.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
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.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
public class TupleExecutionPlanGenerator implements IndexTupleGenerator {
@Override
public Iterator<TupleExpr> getPlans(final Iterator<TupleExpr> indexPlans) {
final Iterator<TupleExpr> iter = indexPlans;
return new Iterator<TupleExpr>() {
private TupleExpr next = null;
private boolean hasNextCalled = false;
private boolean isEmpty = false;
Iterator<TupleExpr> tuples = null;
@Override
public boolean hasNext() {
if (!hasNextCalled && !isEmpty) {
if (tuples != null && tuples.hasNext()) {
next = tuples.next();
hasNextCalled = true;
return true;
} else {
while (iter.hasNext()) {
tuples = getPlans(iter.next()).iterator();
if (tuples == null) {
throw new IllegalStateException("Plans cannot be null!");
}
next = tuples.next();
hasNextCalled = true;
return true;
}
isEmpty = true;
return false;
}
} else {
return !isEmpty;
}
}
@Override
public TupleExpr next() {
if (hasNextCalled) {
hasNextCalled = false;
return next;
} else if(isEmpty) {
throw new NoSuchElementException();
}else {
if (this.hasNext()) {
hasNextCalled = false;
return next;
} else {
throw new NoSuchElementException();
}
}
}
@Override
public void remove() {
throw new UnsupportedOperationException("Cannot delete from iterator!");
}
};
}
private List<TupleExpr> getPlans(final TupleExpr te) {
final NodeCollector nc = new NodeCollector();
te.visit(nc);
final Set<QueryModelNode> nodeSet = nc.getNodeSet();
final List<Filter> filterList = nc.getFilterSet();
final Projection projection = nc.getProjection().clone();
final List<TupleExpr> queryPlans = Lists.newArrayList();
final Collection<List<QueryModelNode>> plans = Collections2.permutations(nodeSet);
for (final List<QueryModelNode> p : plans) {
if (p.size() == 0) {
throw new IllegalArgumentException("Tuple must contain at least one node!");
} else if (p.size() == 1) {
queryPlans.add(te);
} else {
queryPlans.add(buildTuple(p, filterList, projection));
}
}
return queryPlans;
}
private TupleExpr buildTuple(final List<QueryModelNode> nodes, final List<Filter> filters, final Projection projection) {
final Projection proj = projection.clone();
Join join = null;
join = new Join((TupleExpr) nodes.get(0).clone(), (TupleExpr) nodes.get(1).clone());
for (int i = 2; i < nodes.size(); i++) {
join = new Join(join, (TupleExpr) nodes.get(i).clone());
}
if (filters.size() == 0) {
proj.setArg(join);
return proj;
} else {
TupleExpr queryPlan = join;
for (final Filter f : filters) {
final Filter filt = f.clone();
filt.setArg(queryPlan);
queryPlan = filt;
}
proj.setArg(queryPlan);
return proj;
}
}
public static class NodeCollector extends AbstractQueryModelVisitor<RuntimeException> {
private final Set<QueryModelNode> nodeSet = Sets.newHashSet();
private final List<Filter> filterSet = Lists.newArrayList();
private Projection projection;
public Projection getProjection() {
return projection;
}
public Set<QueryModelNode> getNodeSet() {
return nodeSet;
}
public List<Filter> getFilterSet() {
return filterSet;
}
@Override
public void meet(final Projection node) {
projection = node;
node.getArg().visit(this);
}
@Override
public void meetNode(final QueryModelNode node) throws RuntimeException {
if (node instanceof ExternalTupleSet || node instanceof BindingSetAssignment
|| node instanceof StatementPattern) {
nodeSet.add(node);
}
super.meetNode(node);
}
@Override
public void meet(final Filter node) {
filterSet.add(node);
node.getArg().visit(this);
}
}
}