package org.aksw.jena_sparql_api.sparql_path2; import java.util.HashSet; import java.util.List; import java.util.Set; import org.aksw.jena_sparql_api.core.QueryExecutionFactory; import org.aksw.jena_sparql_api.jgrapht.LabeledEdge; import org.aksw.jena_sparql_api.jgrapht.LabeledEdgeImpl; import org.aksw.jena_sparql_api.utils.model.Directed; import org.apache.jena.graph.Node; import org.apache.jena.graph.NodeFactory; import org.apache.jena.query.QueryExecution; import org.apache.jena.rdf.model.Model; import org.jgrapht.DirectedGraph; import org.jgrapht.graph.DefaultDirectedGraph; import org.jgrapht.graph.DefaultEdge; import org.jgrapht.graph.DirectedGraphUnion; public class JoinSummaryUtils { public static Model createPredicateJoinSummary(QueryExecutionFactory qef) { String queryStr = "PREFIX r: <http://example.org/resource/>" + "PREFIX o: <http://example.org/ontology/>" + "CONSTRUCT {\n" + " ?s\n" + " a o:PredicateJoinSummary ;\n" + " o:sourcePredicate ?x ;\n" + " o:targetPredicate ?y ;\n" + " o:freqTotal ?ct ;\n" + " o:freqSource ?ca ;\n" + " o:freqIntermediary ?cb ;\n" + " o:freqTarget ?cc\n" + "}\n" + "{\n" + " { SELECT ?x ?y (Count(*) As ?ct) (Count(Distinct ?a) As ?ca) (Count(Distinct ?b) As ?cb) (Count(Distinct ?c) As ?cc) {\n" + " ?a ?x ?b .\n" + " ?b ?y ?c .\n" + " } GROUP BY ?x ?y }\n" + " BIND(r:training_dataset As ?d)\n" + " BIND(uri(concat(str(r:join), '-', encode_for_uri(?d), '-', md5(concat(str(?x), str(?y))))) As ?s)\n" + "}\n" ; QueryExecution qe = qef.createQueryExecution(queryStr); Model result = qe.execConstruct(); return result; } public static Model createPredicateSummary(QueryExecutionFactory qef) { String queryStr = "PREFIX r: <http://example.org/resource/>\n" + "PREFIX o: <http://example.org/ontology/>\n" + "CONSTRUCT {\n" + " ?s\n" + " a o:PredicateSummary ;\n" + " o:predicate ?x ;\n" + " o:freqTotal ?ct ;\n" + " o:freqSource ?ca ;\n" + " o:freqTarget ?cb\n" + "}\n" + "{\n" + " { SELECT ?x (Count(*) As ?ct) (Count(Distinct ?a) As ?ca) (Count(Distinct ?b) As ?cb) {\n" + " ?a ?x ?b .\n" + " } GROUP BY ?x }\n" + " BIND(r:training_dataset As ?d)\n" + " BIND(uri(concat(str(r:predicate), '-', encode_for_uri(?d), '-', encode_for_uri(?x))) As ?s)\n" + "}\n"; QueryExecution qe = qef.createQueryExecution(queryStr); Model result = qe.execConstruct(); return result; } public static List<NestedPath<Node, DefaultEdge>> findJoinSummaryPaths( Nfa<Integer, LabeledEdge<Integer, PredicateClass>> nfa, Set<Integer> states, DirectedGraph<Node, DefaultEdge> joinGraph, Node augStart, Node augEnd, Long k) { List<NestedPath<Node, DefaultEdge>> reachabilityPaths = NfaExecutionUtils.findPathsInJoinSummary( nfa, LabeledEdgeImpl::isEpsilon, states, joinGraph, augStart, 1l, (trans, node) -> { // function for dealing with a predicate without known preceeding predicate Set<Directed<Node>> r = new HashSet<>(); PredicateClass pc = trans.getLabel(); for(int i = 0; i < 2; ++i) { boolean transReverse = i == 1; ValueSet<Node> preds = pc.get(i); Set<DefaultEdge> edges = transReverse ? joinGraph.incomingEdgesOf(node) : joinGraph.outgoingEdgesOf(node) ; edges.stream() .map(edge -> transReverse ? joinGraph.getEdgeSource(edge) : joinGraph.getEdgeTarget(edge)) .filter(p -> preds.contains(p)) .map(p -> new Directed<>(p, transReverse)) .forEach(r::add); } return r; }, (trans, diPred) -> { // for the nfa transition and a set data nodes, return matching triplets per node // TODO: if the diPred is any, we assume that every predicate of the transition may match // This is ugly if the transition allows any predicate //Set<Triplet<Node, DefaultEdge>> r; Node pred = diPred == null ? null : diPred.getValue(); PredicateClass pc = trans.getLabel(); Set<Directed<Node>> r = new HashSet<>(); boolean predReverse = diPred.isReverse(); // Check the transition - if it is opposite to the current predicate, // we cannot consult the join summary - so we return a pseudo-triplet indicating that it will join with any further predicate for(int i = 0; i < 2; ++i) { boolean transReverse = i == 1; ValueSet<Node> transPolPreds = pc.get(i); // polarity set Set<Node> transPreds = transPolPreds.getValues(); // If transition and path predicate face in the same direction, we can consult the join summary // If the point in opposing directions, we return the ANY token if(predReverse == transReverse) { if(pred.equals(Node.ANY)) { if(transPolPreds.isPositive()) { transPreds.stream() .map(p -> new Directed<>(p, transReverse)) .forEach(r::add); } else { r.add(new Directed<>(Node.ANY, transReverse)); } } else { Set<DefaultEdge> edges = transReverse ? joinGraph.incomingEdgesOf(pred) : joinGraph.outgoingEdgesOf(pred) ; edges.stream() .map(edge -> transReverse ? joinGraph.getEdgeSource(edge) : joinGraph.getEdgeTarget(edge)) .filter(p -> transPolPreds.contains(p)) .map(p -> new Directed<>(p, transReverse)) .forEach(r::add); } } else { if(!transPolPreds.isEmpty()) { r.add(new Directed<>(Node.ANY, transReverse)); } } } return r; }, nestedPath -> { Node current = nestedPath.getCurrent(); boolean r = current.equals(Node.ANY) || nestedPath.getCurrent().equals(augEnd); return r; }); reachabilityPaths.forEach(o -> System.out.println("REACHPATH: " + o.asSimplePath())); return reachabilityPaths; } /** * Checks whether there exists a path connecting start and end nodes via the nfa * * @param nfa * @param augStart * @param augEnd * @param joinGraph */ public static boolean existsJoinSummaryPath( Nfa<Integer, LabeledEdge<Integer, PredicateClass>> nfa, Set<Integer> states, DirectedGraph<Node, DefaultEdge> joinGraph, Node augStart, Node augEnd) { List<NestedPath<Node, DefaultEdge>> paths = findJoinSummaryPaths( nfa, states, joinGraph, augStart, augEnd, 1l); boolean result = !paths.isEmpty(); return result; } /** * Given a predicate and a direction, * determine whether a path exists for this predicate * * @param nfa * @param state the current set of states in the nfa * @param endAugJoinGraph the end-augmented join graph * @param augEnd the end node of the end-augmented join graph * @param joinGraph */ public static boolean existsReachability( Nfa<Integer, LabeledEdge<Integer, PredicateClass>> nfa, Set<Integer> states, DirectedGraph<Node, DefaultEdge> endAugJoinGraph, // joinGraph that was augmented with targets Node augEnd, Node predicate, boolean reverse) { DirectedGraph<Node, DefaultEdge> augJoinGraph = new DefaultDirectedGraph<>(DefaultEdge.class); // TODO Dynamically allocate a start and end vertex that is not part of the rawJoinGraph Node augStart = NodeFactory.createURI("http://start.org"); //Node augEnd = NodeFactory.createURI("http://end.org"); JGraphTUtils.addSuperVertex(augJoinGraph, augStart, predicate, reverse); DirectedGraph<Node, DefaultEdge> joinGraph = new DirectedGraphUnion<Node, DefaultEdge>(augJoinGraph, endAugJoinGraph); boolean result = existsJoinSummaryPath( nfa, states, joinGraph, augStart, augEnd); return result; } }