private TupleExpr join(TupleExpr node, TupleExpr toMove) { toMove.replaceWith(new SingletonSet()); if (node != null) { node = new Join(node, toMove); } else { node = toMove; } return node; }
private TupleExpr join(TupleExpr node, TupleExpr toMove) { toMove.replaceWith(new SingletonSet()); if (node != null) { node = new Join(node, toMove); } else { node = toMove; } return node; }
private static TupleExpr getJoin(TupleExpr oldJoin, TupleExpr newArg) { if (newArg instanceof FlattenedOptional) { return new LeftJoin(oldJoin, ((FlattenedOptional) newArg).getRightArg()); } else { return new Join(oldJoin, newArg); } }
private void removeMatchedPattern(final TupleExpr tupleExpr, final StatementPattern pattern, final TupleExprReplacer replacer) { final List<TupleExpr> indexTuples = replacer.createReplacement(pattern); if (indexTuples.size() > 1) { final VarExchangeVisitor vev = new VarExchangeVisitor(pattern); tupleExpr.visit(vev); Join join = new Join(indexTuples.remove(0), indexTuples.remove(0)); for (final TupleExpr geo : indexTuples) { join = new Join(join, geo); } pattern.replaceWith(join); } else if (indexTuples.size() == 1) { pattern.replaceWith(indexTuples.get(0)); pattern.setParentNode(null); } else { throw new IllegalStateException("Must have at least one replacement for matched StatementPattern."); } }
@Override public void meetNode(QueryModelNode node) { if (typeRequirement != null) { if (node instanceof TupleExpr && ((TupleExpr) node).getBindingNames().contains(varName)) { final Join withType = new Join((TupleExpr) node.clone(), typeRequirement); node.replaceWith(withType); } else { node.visitChildren(this); } } } @Override
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; } }
@Override public void meet(final Join node) throws Exception { super.meet(node); final TupleExpr leftArg = node.getLeftArg(); final TupleExpr rightArg = node.getRightArg(); /** * if join(join(1, 2), join(3,4)) * should be: * join(join(join(1,2), 3), 4) */ if (leftArg instanceof Join && rightArg instanceof Join) { final Join leftJoin = (Join) leftArg; final Join rightJoin = (Join) rightArg; final TupleExpr right_LeftArg = rightJoin.getLeftArg(); final TupleExpr right_rightArg = rightJoin.getRightArg(); final Join inner = new Join(leftJoin, right_LeftArg); final Join outer = new Join(inner, right_rightArg); node.replaceWith(outer); } } }
private void buildQuery(final TupleExpr tupleExpr, final StatementPattern matchStatement) { //If our IndexerExpr (to be) is the rhs-child of LeftJoin, we can safely make that a Join: // the IndexerExpr will (currently) not return results that can deliver unbound variables. //This optimization should probably be generalized into a LeftJoin -> Join optimizer under certain conditions. Until that // has been done, this code path at least takes care of queries generated by OpenSahara SparqTool that filter on OPTIONAL // projections. E.g. summary~'full text search' (summary is optional). See #379 if (matchStatement.getParentNode() instanceof LeftJoin) { final LeftJoin leftJoin = (LeftJoin)matchStatement.getParentNode(); if (leftJoin.getRightArg() == matchStatement && leftJoin.getCondition() == null) { matchStatement.getParentNode().replaceWith(new Join(leftJoin.getLeftArg(), leftJoin.getRightArg())); } } final FilterFunction fVisitor = new FilterFunction(matchStatement.getObjectVar().getName()); tupleExpr.visit(fVisitor); final List<IndexingExpr> results = Lists.newArrayList(); for(int i = 0; i < fVisitor.func.size(); i++){ results.add(new IndexingExpr(fVisitor.func.get(i), matchStatement, Arrays.stream(fVisitor.args.get(i)).toArray())); } removeMatchedPattern(tupleExpr, matchStatement, new IndexerExprReplacer(results)); }
@Test public void periodicNodePresentTest() throws Exception { List<ValueExpr> values = Arrays.asList(new Var("time"), new ValueConstant(VF.createLiteral(12.0)), new ValueConstant(VF.createLiteral(6.0)), new ValueConstant(VF.createIRI(PeriodicQueryUtil.temporalNameSpace + "hours"))); FunctionCall func = new FunctionCall(PeriodicQueryUtil.PeriodicQueryURI, values); Optional<PeriodicQueryNode> node1 = PeriodicQueryUtil.getPeriodicQueryNode(func, new Join()); Assert.assertEquals(true, node1.isPresent()); PeriodicQueryNode node2 = new PeriodicQueryNode(12*60*60*1000L, 6*3600*1000L, TimeUnit.MILLISECONDS, "time", new Join()); Assert.assertEquals(true, periodicNodesEqualIgnoreArg(node1.get(), node2)); }
@Test public void periodicNodeFractionalDurationTest() throws Exception { List<ValueExpr> values = Arrays.asList(new Var("time"), new ValueConstant(VF.createLiteral(1)), new ValueConstant(VF.createLiteral(.5)), new ValueConstant(VF.createIRI(PeriodicQueryUtil.temporalNameSpace + "hours"))); FunctionCall func = new FunctionCall(PeriodicQueryUtil.PeriodicQueryURI, values); Optional<PeriodicQueryNode> node1 = PeriodicQueryUtil.getPeriodicQueryNode(func, new Join()); Assert.assertEquals(true, node1.isPresent()); double window = 1*60*60*1000; double period = .5*3600*1000; PeriodicQueryNode node2 = new PeriodicQueryNode((long) window, (long) period, TimeUnit.MILLISECONDS, "time", new Join()); Assert.assertEquals(true, periodicNodesEqualIgnoreArg(node1.get(), node2)); }
@Test public void testNestedJoins() throws Exception { StatementPattern isUndergrad = new StatementPattern(new Var("x"), constant(RDF.TYPE), constant(UNDERGRAD)); StatementPattern isProfessor = new StatementPattern(new Var("y"), constant(RDF.TYPE), constant(PROFESSOR)); StatementPattern takesCourse = new StatementPattern(new Var("x"), constant(TAKES), new Var("c")); StatementPattern teachesCourse = new StatementPattern(new Var("y"), constant(TEACHES), new Var("c")); QueryRoot queryTree = new QueryRoot(new Join( isProfessor, new Join( new Join(isUndergrad, takesCourse), teachesCourse))); SparqlToPipelineTransformVisitor visitor = new SparqlToPipelineTransformVisitor(collection); queryTree.visit(visitor); Assert.assertTrue(queryTree.getArg() instanceof AggregationPipelineQueryNode); AggregationPipelineQueryNode pipelineNode = (AggregationPipelineQueryNode) queryTree.getArg(); Assert.assertEquals(Sets.newHashSet("x", "y", "c"), pipelineNode.getAssuredBindingNames()); }
@Override public void meet(final Filter node) throws Exception { super.meet(node); final ValueExpr condition = node.getCondition(); final TupleExpr arg = node.getArg(); if (!(arg instanceof Join)) { return; } final Join join = (Join) arg; final TupleExpr leftArg = join.getLeftArg(); final TupleExpr rightArg = join.getRightArg(); if (leftArg instanceof StatementPattern && rightArg instanceof StatementPattern) { final Filter left = new Filter(leftArg, condition); final Filter right = new Filter(rightArg, condition); node.replaceWith(new Join(left, right)); } } }
@Test public void testProjection() throws Exception { StatementPattern isUndergrad = new StatementPattern(new Var("x"), constant(RDF.TYPE), constant(UNDERGRAD)); StatementPattern isCourse = new StatementPattern(new Var("course"), constant(RDF.TYPE), constant(COURSE)); StatementPattern hasEdge = new StatementPattern(new Var("x"), new Var("p"), new Var("course")); ProjectionElemList projectionElements = new ProjectionElemList( new ProjectionElem("p", "relation"), new ProjectionElem("course")); QueryRoot queryTree = new QueryRoot(new Projection( new Join(new Join(isCourse, hasEdge), isUndergrad), projectionElements)); SparqlToPipelineTransformVisitor visitor = new SparqlToPipelineTransformVisitor(collection); queryTree.visit(visitor); Assert.assertTrue(queryTree.getArg() instanceof AggregationPipelineQueryNode); AggregationPipelineQueryNode pipelineNode = (AggregationPipelineQueryNode) queryTree.getArg(); Assert.assertEquals(Sets.newHashSet("relation", "course"), pipelineNode.getAssuredBindingNames()); }
@Override public void meet(Union union) { super.meet(union); TupleExpr leftArg = union.getLeftArg(); TupleExpr rightArg = union.getRightArg(); if (leftArg instanceof Join && rightArg instanceof Join) { Join leftJoinArg = (Join)leftArg; Join rightJoin = (Join)rightArg; if (leftJoinArg.getLeftArg().equals(rightJoin.getLeftArg())) { // factor out the left-most join argument Join newJoin = new Join(); union.replaceWith(newJoin); newJoin.setLeftArg(leftJoinArg.getLeftArg()); newJoin.setRightArg(union); union.setLeftArg(leftJoinArg.getRightArg()); union.setRightArg(rightJoin.getRightArg()); union.visit(this); } } } }
@Override public void meet(Union union) { super.meet(union); TupleExpr leftArg = union.getLeftArg(); TupleExpr rightArg = union.getRightArg(); if (leftArg instanceof Join && rightArg instanceof Join) { Join leftJoinArg = (Join)leftArg; Join rightJoin = (Join)rightArg; if (leftJoinArg.getLeftArg().equals(rightJoin.getLeftArg())) { // factor out the left-most join argument Join newJoin = new Join(); union.replaceWith(newJoin); newJoin.setLeftArg(leftJoinArg.getLeftArg()); newJoin.setRightArg(union); union.setLeftArg(leftJoinArg.getRightArg()); union.setRightArg(rightJoin.getRightArg()); union.visit(this); } } } }
@Test public void testComplexJoin() throws Exception { StatementPattern isUndergrad = new StatementPattern(new Var("x"), constant(RDF.TYPE), constant(UNDERGRAD)); StatementPattern isProfessor = new StatementPattern(new Var("y"), constant(RDF.TYPE), constant(PROFESSOR)); StatementPattern takesCourse = new StatementPattern(new Var("x"), constant(TAKES), new Var("c")); StatementPattern teachesCourse = new StatementPattern(new Var("y"), constant(TEACHES), new Var("c")); QueryRoot queryTree = new QueryRoot(new Join( new Join(isUndergrad, takesCourse), new Join(isProfessor, teachesCourse))); SparqlToPipelineTransformVisitor visitor = new SparqlToPipelineTransformVisitor(collection); queryTree.visit(visitor); Assert.assertTrue(queryTree.getArg() instanceof Join); Join topJoin = (Join) queryTree.getArg(); Assert.assertTrue(topJoin.getLeftArg() instanceof AggregationPipelineQueryNode); Assert.assertTrue(topJoin.getRightArg() instanceof AggregationPipelineQueryNode); AggregationPipelineQueryNode leftPipeline = (AggregationPipelineQueryNode) topJoin.getLeftArg(); AggregationPipelineQueryNode rightPipeline = (AggregationPipelineQueryNode) topJoin.getRightArg(); Assert.assertEquals(Sets.newHashSet("x", "c"), leftPipeline.getAssuredBindingNames()); Assert.assertEquals(Sets.newHashSet("y", "c"), rightPipeline.getAssuredBindingNames()); }
@Test public void periodicNodeNotPresentTest() throws Exception { List<ValueExpr> values = Arrays.asList(new Var("time"), new ValueConstant(VF.createLiteral(12.0)), new ValueConstant(VF.createLiteral(6.0)), new ValueConstant(VF.createIRI(PeriodicQueryUtil.temporalNameSpace + "hours"))); FunctionCall func = new FunctionCall("uri:func", values); Optional<PeriodicQueryNode> node1 = PeriodicQueryUtil.getPeriodicQueryNode(func, new Join()); Assert.assertEquals(false, node1.isPresent()); }
@Test public void testMultiProjection() throws Exception { StatementPattern isUndergrad = new StatementPattern(new Var("x"), constant(RDF.TYPE), constant(UNDERGRAD)); StatementPattern isCourse = new StatementPattern(new Var("course"), constant(RDF.TYPE), constant(COURSE)); StatementPattern hasEdge = new StatementPattern(new Var("x"), new Var("p"), new Var("course")); ProjectionElemList courseHasRelation = new ProjectionElemList( new ProjectionElem("p", "relation"), new ProjectionElem("course")); ProjectionElemList studentHasRelation = new ProjectionElemList( new ProjectionElem("p", "relation"), new ProjectionElem("x", "student")); QueryRoot queryTree = new QueryRoot(new MultiProjection( new Join(new Join(isCourse, hasEdge), isUndergrad), Arrays.asList(courseHasRelation, studentHasRelation))); SparqlToPipelineTransformVisitor visitor = new SparqlToPipelineTransformVisitor(collection); queryTree.visit(visitor); Assert.assertTrue(queryTree.getArg() instanceof AggregationPipelineQueryNode); AggregationPipelineQueryNode pipelineNode = (AggregationPipelineQueryNode) queryTree.getArg(); Assert.assertEquals(Sets.newHashSet("relation"), pipelineNode.getAssuredBindingNames()); Assert.assertEquals(Sets.newHashSet("relation", "course", "student"), pipelineNode.getBindingNames()); }
@Test public void testPeriodicNodePlacement() throws MalformedQueryException { String query = "prefix function: <http://org.apache.rya/function#> " //n + "prefix time: <http://www.w3.org/2006/time#> " //n + "prefix fn: <http://www.w3.org/2006/fn#> " //n + "select ?obs ?time ?lat where {" //n + "Filter(function:periodic(?time, 12.0, 6.0,time:hours)) " //n + "Filter(fn:test(?lat, 25)) " //n + "?obs <uri:hasTime> ?time. " //n + "?obs <uri:hasLattitude> ?lat }"; //n SPARQLParser parser = new SPARQLParser(); ParsedQuery pq = parser.parseQuery(query, null); TupleExpr te = pq.getTupleExpr(); te.visit(new PeriodicQueryNodeVisitor()); PeriodicNodeCollector collector = new PeriodicNodeCollector(); te.visit(collector); PeriodicQueryNode node2 = new PeriodicQueryNode(12*60*60*1000L, 6*3600*1000L, TimeUnit.MILLISECONDS, "time", new Join()); Assert.assertEquals(true, periodicNodesEqualIgnoreArg(node2, collector.getPeriodicQueryNode())); }
@Test public void testJoin() throws Exception { QueryRoot query = new QueryRoot(new Join( new StatementPattern(new Var("x"), constant(RDF.TYPE), constant(UNDERGRAD)), new StatementPattern(new Var("x"), constant(TAKES), new Var("course")))); SparqlToPipelineTransformVisitor visitor = new SparqlToPipelineTransformVisitor(collection); query.visit(visitor); Assert.assertTrue(query.getArg() instanceof AggregationPipelineQueryNode); AggregationPipelineQueryNode pipelineNode = (AggregationPipelineQueryNode) query.getArg(); Assert.assertEquals(Sets.newHashSet("x", "course"), pipelineNode.getAssuredBindingNames()); }