You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2015/07/14 18:21:50 UTC

[2/2] jena git commit: Follow-on from JENA-989: more cases of producing a simpler query.

Follow-on from JENA-989: more cases of producing a simpler query.

Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/a31c7d27
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/a31c7d27
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/a31c7d27

Branch: refs/heads/master
Commit: a31c7d2718b85779d38c00abc74f8ab573dce41b
Parents: b43a3f2
Author: Andy Seaborne <an...@apache.org>
Authored: Tue Jul 14 17:21:37 2015 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Tue Jul 14 17:21:37 2015 +0100

----------------------------------------------------------------------
 .../apache/jena/sparql/algebra/OpAsQuery.java   | 89 ++++++++++++--------
 .../jena/sparql/algebra/TestOpAsQuery.java      | 53 ++++++++++--
 2 files changed, 104 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/a31c7d27/jena-arq/src/main/java/org/apache/jena/sparql/algebra/OpAsQuery.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/OpAsQuery.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/OpAsQuery.java
index 19e56da..a6e339c 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/OpAsQuery.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/OpAsQuery.java
@@ -450,30 +450,10 @@ public class OpAsQuery {
                 g = currentGroup() ;
             }
 
-            ElementPathBlock currentPathBlock = null ;
             for ( Op op : opSequence.getElements() ) {
                 Element e = asElement(op) ;
-                // -- Combining code.
-                if ( e instanceof ElementPathBlock ) {
-                    if ( currentPathBlock != null ) {
-                        // Use last ElementPathBlock
-                        ElementPathBlock newPathBlock = (ElementPathBlock)e ;
-                        currentPathBlock.getPattern().addAll(newPathBlock.getPattern());
-                        // Don't add to the ElementGroup.
-                        continue ;
-                    } else { 
-                        // Start an ElementPathBlock 
-                        currentPathBlock = (ElementPathBlock)e ;
-                        // fall through to add the element.
-                    }
-                } else {
-                    // Current element not a ElementPathBlock
-                    currentPathBlock = null ;
-                }
-                // -- End combining code
-                g.addElement(e) ;
+                insertIntoGroup(g, e) ;
             }
-
             
             if ( nestGroup )
                 endSubGroup() ;
@@ -558,7 +538,7 @@ public class OpAsQuery {
             ElementGroup eRightGroup = asElementGroup(opJoin.getRight()) ;
             Element eRight = eRightGroup ;
             // Very special case. If the RHS is not something that risks
-            // reparsing into a copmbined element of a group, strip the group-of-one. 
+            // reparsing into a combined element of a group, strip the group-of-one. 
             // See also ElementTransformCleanGroupsOfOne
             if ( eRightGroup.size() == 1 ) {
                 // This always was a {} around it but it's unnecessary in a group of one. 
@@ -567,8 +547,8 @@ public class OpAsQuery {
             }
 
             ElementGroup g = currentGroup() ;
-            g.addElement(eLeft) ;
-            g.addElement(eRight) ;
+            insertIntoGroup(g, eLeft) ;
+            insertIntoGroup(g, eRight) ;
             return ;
         }
 
@@ -747,18 +727,18 @@ public class OpAsQuery {
         @Override
         public void visit(OpAssign opAssign) {
             Element e = asElement(opAssign.getSubOp()) ;
-            if ( currentGroup() != e )
-                currentGroup().addElement(e) ;
+            // If (assign ... (table unit)), and first in group, don't add the empty group.
+            insertIntoGroup(currentGroup(), e) ;
             processAssigns(Arrays.asList(opAssign), (var,expr)->{
                 currentGroup().addElement(new ElementAssign(var,expr)) ;
             }) ;
         }
-
+        
         @Override
         public void visit(OpExtend opExtend) {
             Element e = asElement(opExtend.getSubOp()) ;
-            if ( currentGroup() != e )
-                currentGroup().addElement(e) ;
+            // If (extend ... (table unit)), and first in group, don't add the empty group.
+            insertIntoGroup(currentGroup(), e) ;
             processExtends(Arrays.asList(opExtend), (var,expr)->{
                 currentGroup().addElement(new ElementBind(var,expr)) ;
             }) ;
@@ -819,12 +799,55 @@ public class OpAsQuery {
             throw new ARQNotImplemented("OpTopN") ;
         }
 
+        /** Insert into a group, skip initial empty subgroups; recombining ElementPathBlock */
+        private static void insertIntoGroup(ElementGroup eg, Element e) {
+            // Skip initial empty subgroup.
+            if ( emptyGroup(e) && eg.isEmpty() )
+                return ;
+
+            // Empty group.
+            if ( eg.isEmpty() ) {
+                eg.addElement(e);
+                return ;
+            }
+            
+            Element eltTop = eg.getLast() ;
+            if ( ! ( eltTop instanceof ElementPathBlock ) ) {
+                // Not working on a ElementPathBlock - no need to group-of-one 
+                // when inserting ElementPathBlock.
+                e = unwrapGroupOfOnePathBlock(e) ;
+                eg.addElement(e);
+                return ;
+            }
+            if ( ! ( e  instanceof ElementPathBlock ) ) {
+                eg.addElement(e);
+                return ;
+            }
+            // Combine.
+            ElementPathBlock currentPathBlock = (ElementPathBlock)eltTop ;
+            ElementPathBlock newPathBlock = (ElementPathBlock)e ;
+            currentPathBlock.getPattern().addAll(newPathBlock.getPattern());
+        }
+
+        private static Element unwrapGroupOfOnePathBlock(Element e) {
+            Element e2 = getElementOfGroupOfOne(e) ;
+            if ( e2 != null )
+                return e2 ;
+            return e ;
+        }
+
+        private static Element getElementOfGroupOfOne(Element e) {
+            if ( e instanceof ElementGroup ) {
+                ElementGroup eg = (ElementGroup)e ;
+                if ( eg.size() == 1 )
+                    return eg.get(0) ;
+            }
+            return null ;
+        }
+        
         private Element lastElement() {
             ElementGroup g = currentGroup ;
-            if ( g == null || g.size() == 0 )
-                return null ;
-            int len = g.size() ;
-            return g.get(len - 1) ;
+            return g.getLast() ; 
         }
 
         private void startSubGroup() {

http://git-wip-us.apache.org/repos/asf/jena/blob/a31c7d27/jena-arq/src/test/java/org/apache/jena/sparql/algebra/TestOpAsQuery.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/algebra/TestOpAsQuery.java b/jena-arq/src/test/java/org/apache/jena/sparql/algebra/TestOpAsQuery.java
index 6e37c2d..ab8666f 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/algebra/TestOpAsQuery.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/algebra/TestOpAsQuery.java
@@ -30,6 +30,7 @@ import org.apache.jena.query.QueryFactory ;
 import org.apache.jena.query.Syntax ;
 import org.apache.jena.sparql.algebra.Algebra ;
 import org.apache.jena.sparql.algebra.Op ;
+import org.apache.jena.sparql.sse.SSE ;
 import org.junit.Assert ;
 import org.junit.Test ;
 
@@ -128,10 +129,7 @@ public class TestOpAsQuery {
     { test_roundTripQuery("SELECT ?s { ?s ?p ?o { SELECT (count(*) as ?cp) { ?s ?p ?o } }}") ; }
     
     @Test public void testSubQuery_03()
-    //{ test_roundTripQuery("SELECT ?s { { SELECT (count(*) as ?cp) { ?s ?p ?o } } ?s ?p ?o }") ; }
-    // The trailing ?s ?p ?o gets a {} round it.
-    { test_equivalentQuery("SELECT ?s { { SELECT (count(*) as ?cp) { ?s ?p ?o } } ?s ?p ?o }",
-                           "SELECT ?s { { SELECT (count(*) as ?cp) { ?s ?p ?o } } { ?s ?p ?o } }") ; }
+    { test_roundTripQuery("SELECT ?s { { SELECT (count(*) as ?cp) { ?s ?p ?o } } ?s ?p ?o }") ; }
     
     @Test public void testSubQuery_04()
     { test_roundTripQuery("SELECT * WHERE { ?s ?p ?o . BIND(?o AS ?x) }") ; }
@@ -387,10 +385,46 @@ public class TestOpAsQuery {
         test_roundTripAlegbra(query) ;
     }
     
+    @Test
+    public void testValues1() {
+        String query = "SELECT  * { VALUES ?x {1 2} ?s ?p ?x }" ;
+        test_roundTripQuery(query) ;
+    }
+    
+    @Test
+    public void testValues2() {
+        String query = "SELECT  * { ?s ?p ?x  VALUES ?x {1 2} }" ;
+        test_roundTripQuery(query) ;
+    }
+
+    // Algebra to query : optimization cases OpAsQuery can handle.
+    
+    @Test
+    public void testAlgebra01() {
+        String opStr = "(sequence (bgp (?s1 ?p1 ?o1)) (bgp (?s2 ?p2 ?o2)) )" ;
+        String query = "SELECT * { ?s1 ?p1 ?o1. ?s2 ?p2 ?o2}" ;
+        test_AlgebraToQuery(opStr, query);
+    }
+    
+    @Test
+    public void testAlgebra02() {
+        String opStr = "(sequence (bgp (?s1 ?p1 ?o1)) (path ?x (path* :p) ?z) )" ;
+        String query = "PREFIX : <http://example/> SELECT * { ?s1 ?p1 ?o1. ?x :p* ?z}" ;
+        test_AlgebraToQuery(opStr, query);
+    }
+
+    @Test
+    public void testAlgebra03() {
+        String opStr = "(sequence  (path ?x (path* :p) ?z) (bgp (?s1 ?p1 ?o1)) )" ;
+        String query = "PREFIX : <http://example/> SELECT * { ?x :p* ?z . ?s1 ?p1 ?o1. }" ;
+        test_AlgebraToQuery(opStr, query);
+    }
+    
     // There 3 classes of transformations: there are 3 main test operations.
     //   test_roundTripQuery: The same query is recovered from OpAsQuery
     //   test_roundTripAlegbra: Different queries with the same alegra forms
     //   test_equivalentQuery: Different equivalent queries - same answers, different algebra.
+    //   test_algebraToQuery: algebra to query (e.g. optimization shapes)
     // 
     // test_roundTripQuery is test_equivalentQuery with same input and expected.
     // + quad variants.
@@ -432,6 +466,15 @@ public class TestOpAsQuery {
         Op a2 = Algebra.compile(r[1]);
         Assert.assertEquals(a1, a2);
     }
+    
+    // algebra->OpAsQuery->query
+    public static void test_AlgebraToQuery(String input, String expected) {
+        Op op = SSE.parseOp(input) ;
+        Query orig = QueryFactory.create(expected, Syntax.syntaxSPARQL_11);
+        stripNamespacesAndBase(orig) ;
+        Query got = OpAsQuery.asQuery(op);
+        Assert.assertEquals(orig, got) ;
+    }
 
     // query->algebra->OpAsQuery->query
     private static Query[] roundTripQuery(String query) {
@@ -442,7 +485,7 @@ public class TestOpAsQuery {
         return r;
     }
     
- // query->algebra/quads->OpAsQuery->query
+    // query->algebra/quads->OpAsQuery->query
     private static Query[] roundTripQueryQuad(String query) {
         Query orig = QueryFactory.create(query, Syntax.syntaxSPARQL_11);
         Op toReconstruct = Algebra.compile(orig);