package org.aksw.jena_sparql_api.concept_cache.op; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import com.google.common.base.Function; import com.google.common.collect.AbstractIterator; import com.google.common.collect.Sets; import org.apache.jena.sparql.algebra.Op; import org.apache.jena.sparql.algebra.OpVisitorBase; import org.apache.jena.sparql.algebra.op.OpDistinct; import org.apache.jena.sparql.algebra.op.OpExt; // So from the outside we really need candidate mappings // on the op-name level // between the cache tree and the query tree // So this really is sub graph isomorphism, // but with a little twist that different equivalences hold for different node labels // e.g. for left joins and disjunctions argument order (the order of the child vertices) matters, whereas // for e.g. join this is not relevant /* * * * * Essentially, for each node we need to create an iterator of possible child-mappings * * */ class FunctionOpChildren implements Function<Op, List<Op>> { @Override public List<Op> apply(Op op) { List<Op> result = OpUtils.getSubOps(op); return result; } public static final FunctionOpChildren fn = new FunctionOpChildren(); } class ComparatorOpName implements Comparator<Op> { @Override public int compare(Op a, Op b) { int result = a.getName().compareTo(b.getName()); return result; } public static final ComparatorOpName fn = new ComparatorOpName(); } interface ItFactory<T> { Iterator<Map<T, T>> create(T a, T b); } /** * * @author raven * * @param <T> */ class IteratorTreeMatcher<T> extends AbstractIterator<Map<T, T>> { /** * Comparator to check whether two nodes are equivalent * (Maybe jgrapht's equivalence comparator would be appropriate here?) */ public Comparator<T> comparator; /** * Factory that maps a pair of equivalent nodes * to an iterator for all possible matches among their children * * Probably the factory could have the comparator internally */ ItFactory<Map<Op, Op>> iteratorFactory; void dummy() { //OpWalker.walk(op, visitor); } @Override protected Map<T, T> computeNext() { // TODO Auto-generated method stub return null; } } /** * Iterator that requires an exact 1:1 mapping between nodes. * So it returns at most a single entry. * * @author raven * */ class IteratorMatchDirectMatch<T> extends AbstractIterator<Map<T, T>> { public List<T> needle; public List<T> haystack; public Comparator<T> comparator; @Override protected Map<T, T> computeNext() { int n = needle.size(); boolean isAllEqual = true; // The whole sequence starting at 0 must be equal for(int i = 0; i < n; ++i) { T needleItem = needle.get(i); T haystackItem = haystack.get(i); // Check if these items match boolean isEqual = comparator.compare(needleItem, haystackItem) == 0; if(!isEqual) { isAllEqual = false; break; } } Map<T, T> result; if(isAllEqual) { result = new HashMap<T, T>(); for(int i = 0; i < n; ++i) { T needleItem = needle.get(i); T haystackItem = haystack.get(i); result.put(needleItem, haystackItem); } } else { result = endOfData(); } return result; } } /** * * @author raven * */ interface CacheOpSuplier { Op getCandidates(Op prototype); } /** * Matches nodes of two OP trees * * @author raven * */ class MatcherState { private Map<Op, Op> needleToHaystack; /** * Leafs are the set of nodes of the needle that were not mapped yet */ private Set<Op> leafs = Sets.newIdentityHashSet(); } class OpMatcher { private Op currentOp; public OpMatcher(OpMatcher parent) { } public Op getCurrentOp() { return currentOp; } public OpMatcher progress(int argIndex, Op cacheOp) { return null; } } /** * Walks a query structure and at each node checks * * @author raven * */ public class OpVisitorCacheCandidateFinder extends OpVisitorBase { private Collection<Op> availableOps; public <T> Collection<OpMatcher> initiate(Class<T> clazz) { return null; } /** * Find the set of ops that */ public <T extends Op> Collection<T> find(Class<T> clazz) { Set<T> result = Sets.newIdentityHashSet(); for(Op candidate : availableOps) { boolean isClassValid = candidate.getClass().isAssignableFrom(clazz); //if(candidate.getName().equals(op.getName())) { if(isClassValid) { result.add((T)candidate); } } return result; } @Override public void visit(OpExt op) { if(op instanceof OpExtConjunctiveQuery) { this.visit((OpExtConjunctiveQuery) op); } } public void visit(OpDistinct op) { // TODO Initiation should return a set of initial mappings, // which can then be continued with further iteration of the query // the result of this visitor is then the set of OpMappings that were traversed until the end // // wh //Collection<OpDistinct> initiated = initiate(OpDistinct.class); // op.visit(this); } public void visit(OpExtConjunctiveQuery op) { //op.visit(opVisitor); } }