package org.aksw.jena_sparql_api.views.index;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import org.aksw.commons.collections.trees.Tree;
import org.aksw.jena_sparql_api.concept_cache.core.ProjectedOp;
import org.aksw.jena_sparql_api.concept_cache.core.VarInfo;
import org.aksw.jena_sparql_api.concept_cache.core.VarUsage;
import org.aksw.jena_sparql_api.concept_cache.op.OpUtils;
import org.aksw.jena_sparql_api.view_matcher.OpVarMap;
import org.aksw.jena_sparql_api.view_matcher.SparqlViewMatcherProjectionUtils;
import org.apache.jena.graph.Node;
import org.apache.jena.sparql.algebra.Op;
import org.apache.jena.sparql.core.Var;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
/**
* Wrapper for handling projections
*
* @author raven
*
* @param <K>
* @param <P>
*/
public class SparqlViewMatcherPopImpl<K, P>
implements SparqlViewMatcherPop<K>
{
protected SparqlViewMatcherOp<P> delegate;
// A map to associate projections with pattern ids
//protected Map<P, Map<K, ProjectedOp>> patternIdToKeyToPop;
protected Multimap<P, K> patternIdToKeys;
protected Map<K, P> keyToPatternId;
protected Map<K, ProjectedOp> keyToPop;
public SparqlViewMatcherPopImpl(SparqlViewMatcherOp<P> delegate) {
this(
delegate,
HashMultimap.create(),
new HashMap<>(),
new HashMap<>()
);
}
public SparqlViewMatcherPopImpl(
SparqlViewMatcherOp<P> delegate,
Multimap<P, K> patternIdToKeys,
Map<K, P> keyToPatternId,
Map<K, ProjectedOp> keyToPop) {
super();
this.delegate = delegate;
this.patternIdToKeys = patternIdToKeys;
this.keyToPatternId = keyToPatternId;
this.keyToPop = keyToPop;
}
/**
* Function that filters the entries associated with a patternId by
*
* @param projection
* @param patternId
* @param varMap
* @return
*/
public Collection<K> lookupKeys(VarInfo userVarInfo, P patternId, Map<Var, Var> varMap) {
Collection<K> keys = patternIdToKeys.get(patternId);
Collection<K> result = keys.stream().filter(key -> {
VarInfo viewVarInfo = keyToPop.get(key).getProjection();
boolean r = SparqlViewMatcherProjectionUtils.validateProjection(viewVarInfo, userVarInfo, varMap);
return r;
}).collect(Collectors.toList());
return result;
}
@Override
public void put(K key, ProjectedOp pop) {
// TODO Check if the op is isomorphic to an existing pattern - in that case we could reuse a prior pattern id
// For now we allocate a new entry
// Remove a possible prior entry
removeKey(key);
Op patternOp = pop.getResidualOp();
P patternId = delegate.allocate(patternOp);
keyToPatternId.put(key, patternId);
keyToPop.put(key, pop);
}
/**
* Map<K, Entry<Map<Op, Op>, Map<Var, Var>>
*
*
*
*
* @param pop
* @return
*/
@Override
public Map<K, OpVarMap> lookup(ProjectedOp pop) {
//VarInfo userVarInfo = pop.getProjection();
Op patternOp = pop.getResidualOp();
Tree<Op> userTree = OpUtils.createTree(patternOp);
Map<P, OpVarMap> cands = delegate.lookup(patternOp);
// TODO What is the result datastructure?
//LinkedHashMap<K, OpVarMap> result = null;
Map<K, OpVarMap> result = new HashMap<>();
for(Entry<P, OpVarMap> cand : cands.entrySet()) {
P patternId = cand.getKey();
OpVarMap opVarMap = cand.getValue();
// Determine the user node corresponding to the view's root node
Map<Op, Op> opMap = opVarMap.getOpMap();
Op viewRootOp = delegate.getOp(patternId);
Op userViewRootOp = opMap.get(viewRootOp);
// Analyze the var usage at that node
VarUsage varUsage = OpUtils.analyzeVarUsage(userTree, userViewRootOp);
// TODO Take distinct level into account
VarInfo userVarInfo = new VarInfo(VarUsage.getMandatoryVars(varUsage), 0);
for(Map<Var, Var> varMap : opVarMap.getVarMaps()) {
Collection<K> keys = lookupKeys(userVarInfo, patternId, varMap);
for(K key : keys) {
OpVarMap e = new OpVarMap(opVarMap.getOpMap(), varMap);
result.put(key, e);
}
}
}
return result;
}
@Override
public void removeKey(Object key) {
keyToPop.remove(key);
Object patternId = keyToPatternId.get(key);
delegate.removeKey(patternId);
patternIdToKeys.remove(patternId, key);
keyToPatternId.remove(key);
}
@Override
public ProjectedOp getPop(K key) {
ProjectedOp result = keyToPop.get(key);
return result;
}
public static SparqlViewMatcherPop<Node> create() {
SparqlViewMatcherOp<Integer> delegate = SparqlViewMatcherOpImpl.create();
SparqlViewMatcherPop<Node> result = new SparqlViewMatcherPopImpl<>(delegate);
return result;
}
}