Author: andy
Date: Sat Nov 16 23:36:45 2013
New Revision: 1542613
URL: http://svn.apache.org/r1542613
Log:
Recursively push filter expressions down.
Modified:
jena/Scratch/AFS/Dev/src-dev/opt/OptMain.java
jena/Scratch/AFS/Dev/src-dev/opt/TestFilterPlacement.java
jena/Scratch/AFS/Dev/src-dev/opt/TransformFilterEquality2.java
jena/Scratch/AFS/Dev/src-dev/opt/TransformFilterPlacement_Rewrite.java
Modified: jena/Scratch/AFS/Dev/src-dev/opt/OptMain.java
URL:
http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src-dev/opt/OptMain.java?rev=1542613&r1=1542612&r2=1542613&view=diff
==============================================================================
--- jena/Scratch/AFS/Dev/src-dev/opt/OptMain.java (original)
+++ jena/Scratch/AFS/Dev/src-dev/opt/OptMain.java Sat Nov 16 23:36:45 2013
@@ -33,11 +33,25 @@ import com.hp.hpl.jena.sparql.sse.SSE ;
public class OptMain {
public static void main(String... argv) throws Exception {
+ // Tests
+ // coverage,
+ // repeated application.
+ // BGPs directly.
+ // Complex/recurse tests
+
+ // Transformations are applied "bottom up"
+ // - should this be top down?
+ // - what happens if hits a filter? Currently, it stops.
+
+ // test combined with filter equality.
+
// What about covered left but partial right?
// Push left (join),)
// Push left (left join)
// Other cases
+ // Check order of all optimziations - equality last.
+
// Also TransformDistinctToReduced (JENA-585)and
TransformOrderByDistincApplication
// Combinations e.g. placement then equality
@@ -54,6 +68,12 @@ public class OptMain {
// * Join
// Need to say what was pushed.
+ // Full optimization tests
+
+ // Was Op.equals a good idea?
+ // Calculate vars for an expr once and cache : op.getVars.
+
+ // XXX Push recursively.
if ( false ) {
String input = "(filter ((= ?A 2) (= ?z 99) (= ?x 123)) (bgp (?s
?p ?x) (?s ?p ?z)) )" ;
@@ -65,21 +85,33 @@ public class OptMain {
System.exit(0) ;
}
- if (true) {
- String qs = StrUtils.strjoinNL(
- "PREFIX ex: <http://example.org/test#>",
- "SELECT * WHERE {",
- " ?var ex:p1 ?x. ",
- " OPTIONAL {",
- " ?x ex:p2 ?y.",
- " OPTIONAL {",
- " ?y ex:p3 ?z",
- " }",
- " }",
- " FILTER (?var = ex:i)",
- "}") ;
- Query query = QueryFactory.create(qs) ;
+ if ( false ) {
+ String qs1 = StrUtils.strjoinNL
+ ("PREFIX ex: <http://example.org/test#>",
+ "SELECT * WHERE {",
+ " ?var ex:p1 ?x. ",
+ " OPTIONAL {",
+ " ?x ex:p2 ?y.",
+ " OPTIONAL {",
+ " ?y ex:p3 ?z",
+ " }",
+ " }",
+ " FILTER (?var = ex:i)",
+ "}") ;
+ String qs2 = StrUtils.strjoinNL
+ ("PREFIX ex: <http://example.org/test#>",
+ "SELECT * WHERE {",
+ " ?s ?p ?o .",
+ " ?s ?q ?w ",
+ " BIND ( ?o+1 as ?z)" ,
+ " FILTER (?o != 57)",
+ " FILTER (?z != 57)",
+ "}") ;
+
+ Query query = QueryFactory.create(qs2) ;
Op op1 = Algebra.compile(query) ;
+ System.out.println("** Input") ;
+ System.out.println(op1) ;
{
System.out.println("** OLD") ;
Op op2 = Algebra.optimize(op1) ;
@@ -94,6 +126,8 @@ public class OptMain {
System.exit(0) ;
}
+ // Extend test
+
// What about covered left but partial right?
// Push left (join),)
// Push left (left join)
Modified: jena/Scratch/AFS/Dev/src-dev/opt/TestFilterPlacement.java
URL:
http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src-dev/opt/TestFilterPlacement.java?rev=1542613&r1=1542612&r2=1542613&view=diff
==============================================================================
--- jena/Scratch/AFS/Dev/src-dev/opt/TestFilterPlacement.java (original)
+++ jena/Scratch/AFS/Dev/src-dev/opt/TestFilterPlacement.java Sat Nov 16
23:36:45 2013
@@ -29,55 +29,43 @@ import com.hp.hpl.jena.sparql.algebra.Tr
import com.hp.hpl.jena.sparql.sse.SSE ;
public class TestFilterPlacement extends BaseTest { //extends
AbstractTestTransform {
- @Test
- public void place_filter_bgp_01() {
+ @Test public void place_filter_bgp_01() {
test("(filter (= ?x 1) (bgp ( ?s ?p ?x)))", "(filter (= ?x 1) (bgp (
?s ?p ?x)))") ;
}
- @Test
- public void place_filter_bgp_02() {
+ @Test public void place_filter_bgp_02() {
test("(filter (= ?x 1) (bgp (?s ?p ?x) (?s1 ?p1 ?x1) ))",
"(sequence (filter (= ?x 1) (bgp ( ?s ?p ?x))) (bgp (?s1 ?p1
?x1)))") ;
}
- @Test
- public void place_filter_bgp_03() {
+ @Test public void place_filter_bgp_03() {
test("(filter (= ?x 1) (bgp (?s ?p ?x) (?s1 ?p1 ?x) ))",
"(sequence (filter (= ?x 1) (bgp ( ?s ?p ?x))) (bgp (?s1 ?p1
?x)))") ;
}
- @Test
- public void place_filter_bgp_04() {
+ @Test public void place_filter_bgp_04() {
test("(filter (= ?XX 1) (bgp (?s ?p ?x) (?s1 ?p1 ?XX) ))", "(filter (=
?XX 1) (bgp (?s ?p ?x) (?s1 ?p1 ?XX) ))") ;
}
- @Test
- public void place_filter_no_match_01() {
+ @Test public void place_filter_no_match_01() {
// Unbound
test("(filter (= ?x ?unbound) (bgp (?s ?p ?x)))", null) ;
}
- @Test
- public void place_filter_no_match_02() {
+ @Test public void place_filter_no_match_02() {
test("(filter (= ?x ?unbound) (bgp (?s ?p ?x) (?s ?p ?x)))", null) ;
}
- @Test
- public void place_filter_no_match_03() {
+ @Test public void place_filter_no_match_03() {
test("(filter (= ?x ?unbound) (bgp (?s ?p ?x) (?s1 ?p1 ?XX)))", null) ;
}
- // Sequence
-
- @Test
- public void place_filter_sequence_01() {
+ @Test public void place_filter_sequence_01() {
test("(filter (= ?x 123) (sequence (bgp (?s ?p ?x)) (bgp (?s ?p ?z))
))",
"(sequence (filter (= ?x 123) (bgp (?s ?p ?x))) (bgp (?s ?p ?z))
)") ;
-
}
- @Test
- public void place_filter_sequence_02() {
+ @Test public void place_filter_sequence_02() {
// Given the sequence flows left into right, only need to filter in the
// LHS. The RHS can't introduce ?x because it woudl not be a legal
sequence
// if, for example, it had a BIND in it.
@@ -85,29 +73,25 @@ public class TestFilterPlacement extends
"(sequence (filter (= ?x 123) (bgp (?s ?p ?x))) (bgp (?s ?p ?x))
)") ;
}
- @Test
- public void place_filter_sequence_03() {
+ @Test public void place_filter_sequence_03() {
test("(filter (= ?z 123) (sequence (bgp (?s ?p ?x)) (bgp (?s ?p ?z))
))",
null) ;
}
// Join : one sided push.
- @Test
- public void place_filter_join_01() {
+ @Test public void place_filter_join_01() {
test("(filter (= ?x 123) (join (bgp (?s ?p ?x)) (bgp (?s ?p ?z)) ))",
"(join (filter (= ?x 123) (bgp (?s ?p ?x))) (bgp (?s ?p ?z)) )") ;
}
// Join : two side push
- @Test
- public void place_filter_join_02() {
+ @Test public void place_filter_join_02() {
test("(filter (= ?x 123) (join (bgp (?s ?p ?x)) (bgp (?s ?p ?x)) ))",
"(join (filter (= ?x 123) (bgp (?s ?p ?x))) (filter (= ?x 123)
(bgp (?s ?p ?x))) )") ;
}
- @Test
- public void place_filter_join_03() {
+ @Test public void place_filter_join_03() {
String x = StrUtils.strjoinNL
("(filter ((= 13 14) (> ?o1 12) (< ?o 56) (< (+ ?o ?o1) 999))",
" (join",
@@ -126,7 +110,7 @@ public class TestFilterPlacement extends
// " (filter (> ?o1 12)",
// " (bgp (triple ?s ?p1 ?o1))))))") ;
- // Everything psuhed down.
+ // Everything pushed down.
String y = StrUtils.strjoinNL
("(filter (< (+ ?o ?o1) 999)",
" (join",
@@ -134,33 +118,66 @@ public class TestFilterPlacement extends
" (bgp (triple ?s ?p ?o)))",
" (filter ((= 13 14) (> ?o1 12))",
" (bgp (triple ?s ?p1 ?o1)))))") ;
- test(x, y) ;
+ // Recursive push in - causes (= 13 14) to go into BGP
+ String y1 = StrUtils.strjoinNL
+ ("(filter (< (+ ?o ?o1) 999)",
+ " (join",
+ " (filter (< ?o 56)",
+ " (sequence",
+ " (filter (= 13 14)",
+ " (table unit))",
+ " (bgp (triple ?s ?p ?o))))",
+ " (filter (> ?o1 12)",
+ " (sequence",
+ " (filter (= 13 14)",
+ " (table unit))",
+ " (bgp (triple ?s ?p1 ?o1))))",
+ " ))") ;
+ test(x, y1) ;
}
- @Test
- public void place_filter_conditional_01() {
+ @Test public void place_filter_conditional_01() {
// conditional
test("(filter (= ?x 123) (conditional (bgp (?s ?p ?x)) (bgp (?s ?p
?z)) ))",
"(conditional (filter (= ?x 123) (bgp (?s ?p ?x))) (bgp (?s ?p
?z)) )") ;
}
- @Test
- public void place_filter_conditional_02() {
+ @Test public void place_filter_conditional_02() {
// conditional
test("(filter (= ?z 123) (conditional (bgp (?s ?p ?x)) (bgp (?s ?p
?z)) ))",
"(filter (= ?z 123) (conditional (bgp (?s ?p ?x)) (bgp (?s ?p
?z)) ))") ;
}
- @Test
- public void place_filter_conditional_03() {
+ @Test public void place_filter_conditional_03() {
// conditional
test("(filter (= ?x 123) (conditional (bgp (?s ?p ?x)) (bgp (?s ?p
?x)) ))",
"(conditional (filter (= ?x 123) (bgp (?s ?p ?x))) (bgp (?s ?p
?x)) )") ;
}
- // LeftJoin
+ // ** Sequence
+
+ // ** LeftJoin
+
+ // ** Extend
+
+ @Test public void place_extend_01() {
+ test("(filter (= ?x 123) (extend ((?z 123)) (bgp (?s ?p ?x)) ))",
+ "(extend ((?z 123)) (filter (= ?x 123) (bgp (?s ?p ?x)) ))") ;
+ }
+
+ @Test public void place_extend_02() { // Blocked
+ test("(filter (= ?x 123) (extend ((?x 123)) (bgp (?s ?p ?z)) ))",
+ null) ;
+ }
+
+ @Test public void place_extend_03() {
+ test("(filter (= ?x 123) (extend ((?x1 123)) (filter (< ?x 456) (bgp
(?s ?p ?x) (?s ?p ?z))) ))",
+ "(extend (?x1 123) (sequence (filter ((< ?x 456) (= ?x 123)) (bgp
(?s ?p ?x))) (bgp (?s ?p ?z))) )") ;
+ }
+ // ** Assign
+
public static void test(String input, String output) {
Transform t_placement = new TransformFilterPlacement_Rewrite() ;
Op op1 = SSE.parseOp(input) ;
Modified: jena/Scratch/AFS/Dev/src-dev/opt/TransformFilterEquality2.java
URL:
http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src-dev/opt/TransformFilterEquality2.java?rev=1542613&r1=1542612&r2=1542613&view=diff
==============================================================================
--- jena/Scratch/AFS/Dev/src-dev/opt/TransformFilterEquality2.java (original)
+++ jena/Scratch/AFS/Dev/src-dev/opt/TransformFilterEquality2.java Sat Nov 16
23:36:45 2013
@@ -41,7 +41,7 @@ import com.hp.hpl.jena.sparql.expr.* ;
public class TransformFilterEquality2 extends TransformCopy
{
// The approach taken for { OPTIONAL{} OPTIONAL{} } is more general ...
and better?
- // Still need to be careful of double-nested OPTIONALS as intermedates of
a different
+ // Still need to be careful of double-nested OPTIONALS as intermediates of
a different
// value can block overall results so don't mask immediately.
public TransformFilterEquality2()
{ }
Modified: jena/Scratch/AFS/Dev/src-dev/opt/TransformFilterPlacement_Rewrite.java
URL:
http://svn.apache.org/viewvc/jena/Scratch/AFS/Dev/src-dev/opt/TransformFilterPlacement_Rewrite.java?rev=1542613&r1=1542612&r2=1542613&view=diff
==============================================================================
--- jena/Scratch/AFS/Dev/src-dev/opt/TransformFilterPlacement_Rewrite.java
(original)
+++ jena/Scratch/AFS/Dev/src-dev/opt/TransformFilterPlacement_Rewrite.java Sat
Nov 16 23:36:45 2013
@@ -28,6 +28,7 @@ import java.util.Iterator ;
import java.util.List ;
import java.util.Set ;
+import org.apache.jena.atlas.lib.CollectionUtils ;
import org.apache.jena.atlas.lib.DS ;
import com.hp.hpl.jena.graph.Node ;
@@ -49,30 +50,28 @@ import com.hp.hpl.jena.sparql.util.VarUt
*/
public class TransformFilterPlacement_Rewrite extends TransformCopy {
- // Tests
- // coverage,
- // repeated application.
- // BGPs directly.
-
- // Transformations are applied "bottom up"
- // - should this be top down?
- // - what happens if hits a filter? Currently, it stops.
-
- // Was Op.equals a good idea?
- // Calculate vars for an expr once and cache
-
static class Placement {
final Op op ;
final ExprList unplaced ;
Placement(Op op, ExprList remaining) { this.op = op ; this.unplaced =
remaining ; }
}
+ static final ExprList emptyList = new ExprList() ;
+ static final Placement noChangePlacement = null ; //new Placement(null,
null) ;
+
private static Placement result(Op op, ExprList remaining) {
if ( op == null )
return null ;
return new Placement(op, remaining) ;
}
+ private static Placement resultNoChange(Op original) {
+ return noChangePlacement ;
+ }
+ private static boolean isNoChange(Placement placement) {
+ return placement == noChangePlacement ;
+ }
+
public static Op transform(ExprList exprs, BasicPattern bgp) {
Placement placement = placeFilterBGP(exprs, bgp) ;
Op op = ( placement == null ) ? new OpBGP(bgp) : placement.op ;
@@ -95,7 +94,6 @@ public class TransformFilterPlacement_Re
public Op transform(OpFilter opFilter, Op x) {
ExprList exprs = opFilter.getExprs() ;
Placement placement = transform(exprs, x) ;
-
if ( placement == null || placement.op == x )
// Didn't do anything.
return super.transform(opFilter, x) ;
@@ -103,11 +101,14 @@ public class TransformFilterPlacement_Re
return op ;
}
- // XXX Placement in / placement out?
-
+ // Recurse
+ private static Op transformOp(ExprList exprs, Op x) {
+ Placement placement = transform(exprs, x) ;
+ Op op = buildFilter(placement) ;
+ return op ;
+ }
+
private static Placement transform(ExprList exprs, Op input) {
- // OpAssign/OpExtend could be done if the assignment and exprs are
- // independent.
// Dispatch by visitor??
Placement placement = null ;
@@ -125,21 +126,25 @@ public class TransformFilterPlacement_Re
placement = placeFilterLeftJoin(exprs, (OpLeftJoin)input) ;
else if ( input instanceof OpFilter )
placement = placeFilter(exprs, (OpFilter)input) ;
-
-// else if ( input instanceof OpExtend ) {}
-// else if ( input instanceof OpAssign ) {}
-
+ else if ( input instanceof OpExtend )
+ placement = placeExtend(exprs, (OpExtend)input) ;
+ else if ( input instanceof OpAssign )
+ placement = placeAssign(exprs, (OpAssign)input) ;
+
return placement ;
}
+
+ private static Placement x_placeNoOp(ExprList exprs, Op op) {
+ return result(op, exprs) ;
+ }
// == The placeFilter* modify the exprs and patternVarsScope arguments
private static Placement placeFilter(ExprList exprs, OpFilter input) {
- // XXX NoOp
+ // XXX Recurse ??
return result(input, exprs) ;
}
-
private static Placement placeFilterBGP(ExprList exprs, OpBGP x) {
return placeFilterBGP(exprs, x.getPattern()) ;
}
@@ -267,7 +272,7 @@ public class TransformFilterPlacement_Re
op = insertAnyFilter(exprs, varScope, op) ;
Op seqElt = iter.next() ;
// XXX Recurse
- //seqElt = transform(exprs, varScope, seqElt) ; // varScope pass
in?
+ //seqElt = transformOp(exprs, seqElt) ;
// Merge into sequence.
varScope.addAll(OpVars.mentionedVars(seqElt)) ;
op = OpSequence.create(op, seqElt) ;
@@ -275,9 +280,6 @@ public class TransformFilterPlacement_Re
return result(op, exprs) ;
}
- // XXX Comments
-
- // XXX Push recursively.
// Whether to push a covered filter into the RHS even if pushed into the
LHS.
// If this is run after join->sequence, then this is good to do.
@@ -304,7 +306,6 @@ public class TransformFilterPlacement_Re
if ( pushed && ! pushRightAsWellAsLeft )
continue ;
// If left only, make this "else if" of left test, remove
"continue"
- // XXX Tests for this
if ( rightVars.containsAll(vars) ) {
// Push right
pushRight.add(expr) ;
@@ -319,16 +320,12 @@ public class TransformFilterPlacement_Re
return null ;
Op opLeftNew = left ;
- if ( !pushLeft.isEmpty() ) {
- // opLeftNew = transform(exprs, opLeftNew) ;
- opLeftNew = OpFilter.filter(pushLeft, opLeftNew) ;
- }
+ if ( !pushLeft.isEmpty() )
+ opLeftNew = transformOp(pushLeft, opLeftNew) ;
Op opRightNew = right ;
- if ( !pushRight.isEmpty() ) {
- // opRightNew = transform(exprs, opRightNew) ;
- opRightNew = OpFilter.filter(pushRight, opRightNew) ;
- }
+ if ( !pushRight.isEmpty() )
+ opRightNew = transformOp(pushRight, opRightNew) ;
Op op = OpJoin.create(opLeftNew, opRightNew) ;
return result(op, unpushed) ;
@@ -344,6 +341,7 @@ public class TransformFilterPlacement_Re
Placement nLeft = transform(exprs, left) ;
if ( nLeft == null )
result(null, exprs) ;
+ // XXX Recurse
Op op = new OpConditional(nLeft.op, right) ;
return result(op, nLeft.unplaced) ;
}
@@ -360,68 +358,55 @@ public class TransformFilterPlacement_Re
Op op = OpLeftJoin.create(nLeft.op, right, opLeftJoin.getExprs()) ;
return result(op, nLeft.unplaced) ;
}
-// // Any filters that depend on no variables.
-// Op opInitial = insertAnyFilter(exprs, varScope, null) ;
-//
-// if ( opInitial == opLeftJoin )
-// opInitial = null ;
-//
-// // ?? Anything magic for the filters in the LeftJoin itself?
-// ExprList leftJoinExpr = opLeftJoin.getExprs() ;
-//
-// Op left = opLeftJoin.getLeft() ;
-// Op right = opLeftJoin.getRight() ;
-// Collection<Var> leftVars = OpVars.mentionedVars(left) ;
-// Collection<Var> rightVars = OpVars.mentionedVars(right) ;
-// ExprList unpushed = new ExprList() ;
-// ExprList pushLeft = new ExprList() ;
-// ExprList pushRight = new ExprList() ; // Unused
-//
-// for (Expr expr : exprs) {
-// Set<Var> vars = expr.getVarsMentioned() ;
-// boolean pushed = false ;
-//
-// if ( leftVars.containsAll(vars)
-// // && disjoint(rightVars, vars)
-// ) {
-// // If not disjoint can push in, put also retain it.
-// // if ( rightVars.containsAny()
-// // && right does not mention.
-//
-// pushLeft.add(expr) ;
-// pushed = true ;
-// }
-// // Right?????
-//
-// if ( !pushed )
-// unpushed.add(expr) ;
-// }
-//
-// if ( pushLeft.isEmpty() && pushRight.isEmpty() )
-// return opLeftJoin ;
-//
-// Op opLeftNew = left ;
-// if ( !pushLeft.isEmpty() )
-// opLeftNew = OpFilter.filter(pushLeft, opLeftNew) ;
-//
-// Op opRightNew = right ;
-// if ( !pushRight.isEmpty() )
-// opRightNew = OpFilter.filter(pushRight, opRightNew) ;
-//
-// // HACK
-// exprs.getList().clear() ;
-// exprs.getList().addAll(unpushed.getList()) ;
-//
-// Op op = OpLeftJoin.create(opLeftNew, opRightNew, (ExprList)null) ;
-// if ( opInitial != null )
-// op = OpSequence.create(opInitial, op) ;
-// return op ;
-// }
-//
-// private static <T> boolean disjoint(Collection<T> collection,
Collection<T> possibleElts) {
-// return CollectionUtils.disjoint(collection, possibleElts) ;
-// }
+
+ private static <T> boolean disjoint(Collection<T> collection,
Collection<T> possibleElts) {
+ return CollectionUtils.disjoint(collection, possibleElts) ;
+ }
+ /** Try to optimize (filter (extend ...)) */
+ private static Placement placeExtend(ExprList exprs, OpExtend input) {
+ return processExtendAssign(exprs, input) ;
+ }
+
+ private static Placement processExtendAssign(ExprList exprs,
OpExtendAssign input) {
+ // Could break up the VarExprList
+ Collection<Var> vars1 = input.getVarExprList().getVars() ;
+ ExprList pushed = new ExprList() ;
+ ExprList unpushed = new ExprList() ;
+
+ for ( Expr expr : exprs ) {
+ Set<Var> exprVars = expr.getVarsMentioned() ;
+ if ( disjoint(vars1, exprVars) )
+ pushed.add(expr);
+ else
+ unpushed.add(expr) ;
+ }
+
+ if ( pushed.isEmpty() )
+ return resultNoChange(input) ;
+
+ // (filter ... (extend ... ))
+ // ===>
+ // (extend ... (filter ... ))
+ Op opSub = input.getSubOp() ;
+
+ // And try down the expressions
+ Placement p = transform(pushed, opSub) ;
+
+ if ( p == null ) {
+ Op op1 = OpFilter.filter(exprs, opSub) ;
+ Op op2 = input.copy(op1) ; //, input.getVarExprList()) ;
//OpExtend.extend(op1, input.getVarExprList()) ;
+ return result(op2, unpushed) ;
+ }
+ Op op1 = OpFilter.filter(p.unplaced, p.op) ;
+ Op op2 = OpExtend.extend(op1, input.getVarExprList()) ;
+ return result(op2, unpushed) ;
+ }
+
+ private static Placement placeAssign(ExprList exprs, OpAssign input) {
+ return processExtendAssign(exprs, input) ;
+
+ }
// ---- Utilities
/** For any expression now in scope, wrap the op with a filter */