blob: e0291147b4a8213c9a1f654fb4d73239a8e31cb1 [file] [log] [blame]
package org.apache.rya.indexing.external.tupleSet;
/*
* 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.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.rya.api.domain.VarNameUtils;
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryEvaluationException;
import org.eclipse.rdf4j.query.algebra.Projection;
import org.eclipse.rdf4j.query.algebra.TupleExpr;
import org.eclipse.rdf4j.query.algebra.Var;
import org.eclipse.rdf4j.query.algebra.evaluation.impl.ExternalSet;
import org.eclipse.rdf4j.query.algebra.helpers.AbstractQueryModelVisitor;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
/**
* This is an abstract class of delegating the evaluation of part
* of a SPARQL query to an external source. The {@link TupleExpr} returned by {@link ExternalTupleSet#getTupleExpr()}
* represents the SPARQL string that this node evaluates, and table returned by {@link ExternalTupleSet#getTableVarMap()}
* maps the variables of TupleExpr to the variables stored in the external store (which may be different). The map
* returned by {@link ExternalTupleSet#getSupportedVariableOrderMap()} provides a map of all the variable orders in which
* data is written to the supporting, and is useful for determining which {@link BindingSet} can be passed into
* {@link ExternalTupleSet#evaluate(BindingSet)}.
*
*/
public abstract class ExternalTupleSet extends ExternalSet {
public static final String VAR_ORDER_DELIM = ";";
/**
* @deprecated use {@link VarNameUtils#CONSTANT_PREFIX}.
*/
@Deprecated
public static final String CONST_PREFIX = VarNameUtils.CONSTANT_PREFIX;
public static final String VALUE_DELIM = "\u0000";
private Projection tupleExpr;
private Map<String, String> tableVarMap = Maps.newHashMap(); //maps vars in tupleExpr to var in stored binding sets
private Map<String, Set<String>> supportedVarOrders = Maps.newHashMap(); //indicates supported var orders
private Map<String, Value> valMap;
public ExternalTupleSet() {
}
public ExternalTupleSet(Projection tupleExpr) {
Preconditions.checkNotNull(tupleExpr);
this.tupleExpr = tupleExpr;
valMap = getValMap();
updateTableVarMap(tupleExpr, tupleExpr);
}
@Override
abstract public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(BindingSet bindings) throws QueryEvaluationException;
@Override
public Set<String> getBindingNames() {
return tupleExpr.getBindingNames();
}
@Override
public Set<String> getAssuredBindingNames() {
return tupleExpr.getAssuredBindingNames();
}
@Override
public String getSignature() {
return "(External Projection) " + Joiner.on(", ").join(tupleExpr.getProjectionElemList().getElements()).replaceAll("\\s+", " ");
}
public Projection getTupleExpr() {
return tupleExpr;
}
public void setProjectionExpr(Projection tupleExpr) {
Preconditions.checkNotNull(tupleExpr);
if(this.tupleExpr == null) {
updateTableVarMap(tupleExpr, tupleExpr);
} else {
updateTableVarMap(tupleExpr, this.tupleExpr);
}
this.tupleExpr = tupleExpr;
valMap = getValMap();
if (supportedVarOrders.size() != 0) {
updateSupportedVarOrderMap();
}
}
public void setTableVarMap(Map<String,String> vars) {
Preconditions.checkNotNull(vars);
this.tableVarMap = vars;
}
public Map<String, String> getTableVarMap() {
return this.tableVarMap;
}
public void setSupportedVariableOrderMap(Map<String, Set<String>> varOrders) {
Preconditions.checkNotNull(varOrders);
this.supportedVarOrders = varOrders;
}
public void setSupportedVariableOrderMap(List<String> varOrders) {
Preconditions.checkNotNull(varOrders);
this.supportedVarOrders = createSupportedVarOrderMap(varOrders);
}
public Map<String, Set<String>> getSupportedVariableOrderMap() {
return supportedVarOrders;
}
public Map<String, Value> getConstantValueMap() {
return valMap;
}
@Override
public ExternalSet clone() {
final ExternalTupleSet clone = (ExternalTupleSet) super.clone();
clone.setProjectionExpr(this.tupleExpr.clone());
clone.tableVarMap = Maps.newHashMap();
for(final String s: this.tableVarMap.keySet()) {
clone.tableVarMap.put(s,this.tableVarMap.get(s));
}
clone.supportedVarOrders = Maps.newHashMap();
for(final String s: this.supportedVarOrders.keySet()) {
clone.supportedVarOrders.put(s,this.supportedVarOrders.get(s));
}
return clone;
}
public Map<String, Set<String>> getSupportedVariableOrders() {
return supportedVarOrders;
}
public boolean supportsBindingSet(Set<String> bindingNames) {
final Collection<Set<String>> values = supportedVarOrders.values();
final Set<String> bNames = Sets.newHashSet();
final Set<String> bNamesWithConstants = Sets.newHashSet();
for (final String s : this.getTupleExpr().getBindingNames()) {
if (bindingNames.contains(s)) {
bNames.add(s);
bNamesWithConstants.add(s);
} else if(VarNameUtils.isConstant(s)) {
bNamesWithConstants.add(s);
}
}
return values.contains(bNames) || values.contains(bNamesWithConstants);
}
/**
* @param tupleMatch
* - project expression - call after setting {@link tupleExpr} to
* map new variables to old -- the variables in the binding list
* of the new tupleExpr (tupleMatch) must map to the
* corresponding variables in the binding list of the old
* tupleExpr
*/
private void updateTableVarMap(TupleExpr newTuple, TupleExpr oldTuple) {
final List<String> replacementVars = Lists.newArrayList(newTuple
.getBindingNames());
final List<String> tableVars = Lists.newArrayList(oldTuple
.getBindingNames());
final Map<String, String> tableMap = Maps.newHashMap();
for (int i = 0; i < tableVars.size(); i++) {
tableMap.put(replacementVars.get(i), tableVars.get(i));
}
this.setTableVarMap(tableMap);
}
/**
* call after setting {@link tableVarMap} to update map of supported
* variables in terms of variables in new tupleExpr
*/
private void updateSupportedVarOrderMap() {
Preconditions.checkArgument(supportedVarOrders.size() != 0);
final Map<String, Set<String>> newSupportedOrders = Maps.newHashMap();
final BiMap<String, String> biMap = HashBiMap.create(tableVarMap)
.inverse();
Set<String> temp = null;
final Set<String> keys = supportedVarOrders.keySet();
for (final String s : keys) {
temp = supportedVarOrders.get(s);
final Set<String> newSet = Sets.newHashSet();
for (final String t : temp) {
newSet.add(biMap.get(t));
}
final String[] tempStrings = s.split(VAR_ORDER_DELIM);
String v = "";
for (final String u : tempStrings) {
if (v.length() == 0) {
v = v + biMap.get(u);
} else {
v = v + VAR_ORDER_DELIM + biMap.get(u);
}
}
newSupportedOrders.put(v, newSet);
}
supportedVarOrders = newSupportedOrders;
}
/**
*
* @param orders
* @return - map with all possible orders in which results are written to the table
*/
private Map<String, Set<String>> createSupportedVarOrderMap(List<String> orders) {
final Map<String, Set<String>> supportedVars = Maps.newHashMap();
for (final String t : orders) {
final String[] tempOrder = t.split(VAR_ORDER_DELIM);
final Set<String> varSet = Sets.newHashSet();
String u = "";
for (final String s : tempOrder) {
if(u.length() == 0) {
u = s;
} else{
u = u+ VAR_ORDER_DELIM + s;
}
varSet.add(s);
supportedVars.put(u, new HashSet<String>(varSet));
}
}
return supportedVars;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof ExternalTupleSet)) {
return false;
} else {
final ExternalTupleSet arg = (ExternalTupleSet) other;
return this.getTupleExpr().equals(arg.getTupleExpr());
}
}
@Override
public int hashCode() {
int result = 17;
result = 31*result + tupleExpr.hashCode();
return result;
}
private Map<String, Value> getValMap() {
ValueMapVisitor valMapVis = new ValueMapVisitor();
tupleExpr.visit(valMapVis);
return valMapVis.getValMap();
}
/**
*
* Extracts the values associated with constant labels in the query Used to
* create binding sets from range scan
*/
private class ValueMapVisitor extends
AbstractQueryModelVisitor<RuntimeException> {
Map<String, Value> valMap = Maps.newHashMap();
public Map<String, Value> getValMap() {
return valMap;
}
@Override
public void meet(Var node) {
if (VarNameUtils.isConstant(node.getName())) {
valMap.put(node.getName(), node.getValue());
}
}
}
}