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 2017/01/15 20:40:10 UTC

[2/2] jena git commit: Cleaning optimization.

Cleaning optimization.

Optimize
Clean up.

OptimizerMinimal
Applies only property function translation and scoped variable renaming.
This should result in the same answers as OptimizerStd.

QueryEngineMain.
Use minimal optimier

OptimizerStd
Rename to better naming.


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

Branch: refs/heads/optimizer_cleaning
Commit: d864d5e8b5744547bd4f7ca6c06f7e74e366a17c
Parents: 01d23da
Author: Andy Seaborne <an...@apache.org>
Authored: Sun Jan 15 17:41:48 2017 +0000
Committer: Andy Seaborne <an...@apache.org>
Committed: Sun Jan 15 17:41:48 2017 +0000

----------------------------------------------------------------------
 .../jena/sparql/algebra/optimize/Optimize.java  |  31 +-
 .../sparql/algebra/optimize/OptimizeStd.java    | 293 ------------------
 .../algebra/optimize/OptimizerMinimal.java      |  46 +++
 .../sparql/algebra/optimize/OptimizerStd.java   | 295 +++++++++++++++++++
 .../optimize/TransformPropertyFunction.java     |  20 +-
 .../sparql/engine/main/QueryEngineMain.java     |   9 +-
 .../jena/sparql/graph/NodeTransformOp.java      |   2 +-
 7 files changed, 385 insertions(+), 311 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/d864d5e8/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/Optimize.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/Optimize.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/Optimize.java
index 9899357..36120e7 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/Optimize.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/Optimize.java
@@ -29,21 +29,28 @@ import org.apache.jena.sparql.util.Context ;
  * <p>
  *  New optimization processes can be installed via a global change:
  *  <pre>
- *    Optimize.setFactory((cxt)->new MyOptimize(cxt)) ;</pre>
+ *    Optimize.setFactory((cxt)->new MyOptimizer(cxt)) ;</pre>
  *  or on a per-context basis: 
  *  <pre>
- *    Optimize.RewriterFactory f = (cxt)->new MyOptimize(cxt) ;
+ *    Optimize.RewriterFactory f = (cxt)->new MyOptimizer(cxt) ;
  *    context.set(ARQConstants.sysOptimizerFactory, f) ;<pre>
  */
 public class Optimize
 {
-    /** Factory for "Do nothing" optimizer. */ 
-    public static RewriteFactory noOptimizationFactory = (context) -> { return (op) -> op ; } ;
+    /** Factory for the "Do nothing" optimizer. */
+    // also known as :: (context) -> { return (op) -> op ; } ;
+    public static RewriteFactory noOptimizationFactory = context -> op -> op ; // Rigth associative.
     
-    /** Factory for teh standard optimization sequnece. */ 
-    public static RewriteFactory stdOptimizationFactory = (context) -> new OptimizeStd(context) ;
+    /** Factory for the "minimal" optimizer. */ 
+    public static RewriteFactory minimalOptimizationFactory = (context) -> new OptimizerMinimal(context);
+
+    /** Factory for the standard optimization sequnece. */ 
+    public static RewriteFactory stdOptimizationFactory = (context) -> new OptimizerStd(context);
     
-    // Set this to a different factory implementation to have a different general optimizer.  
+    /**
+     * Set this via {@link #setFactory} to a different factory implementation to have a
+     * different general optimizer.
+     */
     private static RewriteFactory factory = stdOptimizationFactory ;
         
     public static Op optimize(Op op, ExecutionContext execCxt) {
@@ -60,11 +67,19 @@ public class Optimize
         return opt.rewrite(op) ;
     }
 
-    /** Set the global optimizer factory to one that does nothing */
+    /** Set the global optimizer factory to one that does nothing.
+     * Applications probably wany {@link #basicOptimizer}  */
     public static void noOptimizer() {
         setFactory(noOptimizationFactory) ;
     }
 
+    /** Set the global optimizer factory to one that only does property functions and scaoped variables.
+     * @see #minimalOptimizationFactory
+     */
+    public static void basicOptimizer() {
+        setFactory(minimalOptimizationFactory) ;
+    }
+
     static private Rewrite decideOptimizer(Context context) {
         RewriteFactory f = (RewriteFactory)context.get(ARQConstants.sysOptimizerFactory) ;
         if ( f == null )

http://git-wip-us.apache.org/repos/asf/jena/blob/d864d5e8/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/OptimizeStd.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/OptimizeStd.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/OptimizeStd.java
deleted file mode 100644
index 983cc15..0000000
--- a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/OptimizeStd.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.jena.sparql.algebra.optimize;
-
-import org.apache.jena.query.ARQ ;
-import org.apache.jena.sparql.ARQConstants ;
-import org.apache.jena.sparql.SystemARQ ;
-import org.apache.jena.sparql.algebra.* ;
-import org.apache.jena.sparql.algebra.op.OpLabel ;
-import org.apache.jena.sparql.util.Context ;
-import org.apache.jena.sparql.util.Symbol ;
-import org.slf4j.Logger ;
-import org.slf4j.LoggerFactory ;
-
-/** The standard optimization sequence. */
-public class OptimizeStd implements Rewrite
-{
-    static private Logger log = LoggerFactory.getLogger(Optimize.class) ;
-    private final Context context ;
-
-    public OptimizeStd(Context context) {
-        this.context = context ;
-    }
-
-    /** Alternative name for compatibility only */
-    public static final Symbol filterPlacementOldName = SystemARQ.allocSymbol("filterPlacement") ;
-    
-    @Override
-    public Op rewrite(Op op) {
-        // Record optimizer
-        if ( context.get(ARQConstants.sysOptimizer) == null )
-            context.set(ARQConstants.sysOptimizer, this) ;
-        
-        // Old name, new name fixup.
-        if ( context.isDefined(filterPlacementOldName) ) {
-            if ( context.isUndef(ARQ.optFilterPlacement) )
-                context.set(ARQ.optFilterPlacement, context.get(filterPlacementOldName)) ;
-        }
-        
-        if ( false ) {
-            // Removal of "group of one" join (AKA SPARQL "simplification") 
-            // is done during algebra generation in AlgebraGenerator
-            op = apply("Simplify", new TransformSimplify(), op) ;
-            op = apply("Delabel", new TransformRemoveLabels(), op) ;
-        }
-
-        // ** TransformScopeRename
-        // This is a requirement for the linearization execution that the default
-        // ARQ query engine uses where possible.  
-        // This transformation must be done (e.g. by QueryEngineBase) if no other optimization is done. 
-        op = TransformScopeRename.transform(op) ;
-        
-        // Prepare expressions.
-        OpWalker.walk(op, new OpVisitorExprPrepare(context)) ;
-        
-        // Convert paths to triple patterns if possible.
-        if ( context.isTrueOrUndef(ARQ.optPathFlatten) ) {
-            op = apply("Path flattening", new TransformPathFlattern(), op) ;
-            // and merge adjacent BGPs (part 1)
-            if ( context.isTrueOrUndef(ARQ.optMergeBGPs) )
-                op = apply("Merge BGPs", new TransformMergeBGPs(), op) ;
-        }
-
-        // Having done the required transforms, specifically TransformScopeRename,
-        // do each optimization via an overrideable method. Subclassing can modify the
-        // transform performed.
-        
-        // Expression constant folding
-        if ( context.isTrueOrUndef(ARQ.optExprConstantFolding) )
-            op = transformExprConstantFolding(op) ;
-        
-        if ( context.isTrueOrUndef(ARQ.propertyFunctions) )
-            op = transformPropertyFunctions(op) ;
-
-        if ( context.isTrueOrUndef(ARQ.optFilterConjunction) )
-            op = transformFilterConjunction(op) ;
-
-        if ( context.isTrueOrUndef(ARQ.optFilterExpandOneOf) )
-            op = transformFilterExpandOneOf(op) ;
-        
-        // Eliminate/Inline assignments where possible
-        // Do this before we do some of the filter transformation work as inlining assignments 
-        // may give us more flexibility in optimizing the resulting filters
-        if ( context.isTrue(ARQ.optInlineAssignments) )
-            op = transformInlineAssignments(op) ;
-
-        // Apply some general purpose filter transformations
-        if ( context.isTrueOrUndef(ARQ.optFilterImplicitJoin) )
-            op = transformFilterImplicitJoin(op) ;
-        
-        if ( context.isTrueOrUndef(ARQ.optImplicitLeftJoin) )
-            op = transformFilterImplicitLeftJoin(op) ;
-                
-        if ( context.isTrueOrUndef(ARQ.optFilterDisjunction) )
-            op = transformFilterDisjunction(op) ;
-        
-        // Some ORDER BY-LIMIT N queries can be done more efficiently by only recording
-        // the top N items, so a full sort is not needed.
-        if ( context.isTrueOrUndef(ARQ.optTopNSorting) )
-            op = transformTopNSorting(op) ;
-        
-        // ORDER BY+DISTINCT optimizations
-        // We apply the one that changes evaluation order first since when it does apply it will give much
-        // better performance than just transforming DISTINCT to REDUCED
-        
-        if ( context.isTrueOrUndef(ARQ.optOrderByDistinctApplication) )
-            op = transformOrderByDistinctApplication(op) ;
-
-        // Transform some DISTINCT to REDUCED, slightly more liberal transform that ORDER BY+DISTINCT application
-        // Reduces memory consumption.
-        if ( context.isTrueOrUndef(ARQ.optDistinctToReduced) )
-            op = transformDistinctToReduced(op) ;
-        
-        // Find joins/leftJoin that can be done by index joins (generally preferred as fixed memory overhead).
-        if ( context.isTrueOrUndef(ARQ.optIndexJoinStrategy) )
-            op = transformJoinStrategy(op) ;
-                
-        // Place filters close to where their dependency variables are defined.
-        // This prunes the output of that step as early as possible.
-        // If done before TransformJoinStrategy, you can get two applications
-        // of a filter in a (sequence) from each half of a (join).  This is harmless,
-        // because filters are generally cheap, but it looks a bit bad.
-        if ( context.isTrueOrUndef(ARQ.optFilterPlacement) )
-            op = transformFilterPlacement(op) ;
-        
-        // Replace suitable FILTER(?x = TERM) with (assign) and write the TERM for ?x in the pattern.    
-        // Apply (possible a second time) after FILTER placement as it can create new possibilities.
-        // See JENA-616.
-       if ( context.isTrueOrUndef(ARQ.optFilterEquality) )
-           op = transformFilterEquality(op) ;
-                
-        // Replace suitable FILTER(?x != TERM) with (minus (original) (table)) where the table contains
-        // the candidate rows to be eliminated
-        // Off by default due to minimal performance difference
-        if ( context.isTrue(ARQ.optFilterInequality) )
-            op = transformFilterInequality(op) ;
-        
-        // Promote table empty as late as possible since this will only be produced by other 
-        // optimizations and never directly from algebra generation
-        if ( context.isTrueOrUndef(ARQ.optPromoteTableEmpty) )
-            op = transformPromoteTableEmpty(op) ;
-
-        // Merge adjacent BGPs
-        if ( context.isTrueOrUndef(ARQ.optMergeBGPs) )
-            op = transformMergeBGPs(op) ;
-
-        // Normally, leave to the specific engines.
-        if ( context.isTrue(ARQ.optReorderBGP) )
-            op = transformReorder(op) ;
-        
-        // Merge (extend) and (assign) stacks
-        if ( context.isTrueOrUndef(ARQ.optMergeExtends) )
-            op = transformExtendCombine(op) ;
-                
-        // Mark
-        if ( false )
-            op = OpLabel.create("Transformed", op) ;
-        return op ;
-    }
-    
-    protected Op transformExprConstantFolding(Op op) {
-        return Transformer.transform(new TransformCopy(), new ExprTransformConstantFold(), op);
-    }
-
-    protected Op transformPropertyFunctions(Op op) {
-        return apply("Property Functions", new TransformPropertyFunction(context), op) ;
-    }
-
-    protected Op transformFilterConjunction(Op op) {
-        return apply("filter conjunctions to ExprLists", new TransformFilterConjunction(), op) ;
-    }
-    protected Op transformFilterExpandOneOf(Op op) {
-        return apply("Break up IN and NOT IN", new TransformExpandOneOf(), op) ;
-    }
-
-    protected Op transformInlineAssignments(Op op) {
-        return TransformEliminateAssignments.eliminate(op, context.isTrue(ARQ.optInlineAssignmentsAggressive));
-    }
-
-    protected Op transformFilterImplicitJoin(Op op) {
-        return apply("Filter Implicit Join", new TransformFilterImplicitJoin(), op);
-    }
-
-    protected Op transformFilterImplicitLeftJoin(Op op) {
-        return apply("Implicit Left Join", new TransformImplicitLeftJoin(), op);
-    }
-
-    protected Op transformFilterDisjunction(Op op) {
-        return apply("Filter Disjunction", new TransformFilterDisjunction(), op) ;
-    }
-
-    protected Op transformTopNSorting(Op op) {
-        return apply("TopN Sorting", new TransformTopN(), op) ;
-    }
-
-    protected Op transformOrderByDistinctApplication(Op op) {
-        return apply("Apply DISTINCT prior to ORDER BY where possible", new TransformOrderByDistinctApplication(), op);
-    }
-
-    protected Op transformDistinctToReduced(Op op) {
-        return apply("Distinct replaced with reduced", new TransformDistinctToReduced(), op) ;
-    }
-
-    protected Op transformJoinStrategy(Op op) {
-        return apply("Index Join strategy", new TransformJoinStrategy(), op) ;
-    }
-
-    protected Op transformFilterPlacement(Op op) {
-        if ( context.isTrue(ARQ.optFilterPlacementConservative))
-            op = apply("Filter Placement (conservative)", new TransformFilterPlacementConservative(), op) ;
-        else { 
-            // Whether to push into BGPs 
-            boolean b = context.isTrueOrUndef(ARQ.optFilterPlacementBGP) ;
-            op = apply("Filter Placement", new TransformFilterPlacement(b), op) ;
-        }
-        return op ;
-    }
-
-    protected Op transformFilterEquality(Op op) {
-        return apply("Filter Equality", new TransformFilterEquality(), op) ;
-    }
-
-    protected Op transformFilterInequality(Op op) {
-        return apply("Filter Inequality", new TransformFilterInequality(), op);
-    }
-
-    protected Op transformPromoteTableEmpty(Op op) {
-        return apply("Table Empty Promotion", new TransformPromoteTableEmpty(), op) ;
-    }
-
-    protected Op transformMergeBGPs(Op op) {
-        return apply("Merge BGPs", new TransformMergeBGPs(), op) ;
-    }
-
-    protected Op transformReorder(Op op) {
-        return  apply("ReorderMerge BGPs", new TransformReorder(), op) ;
-    }
-
-    protected Op transformExtendCombine(Op op) {
-        return apply("Combine BIND/LET", new TransformExtendCombine(), op) ;
-    }
-
-    public static Op apply(Transform transform, Op op) {
-        Op op2 = Transformer.transformSkipService(transform, op) ;
-        if ( op2 != op )
-            return op2 ;
-        return op ;
-    }
-    
-    public static Op apply(String label, Transform transform, Op op) {
-        Op op2 = Transformer.transformSkipService(transform, op) ;
-        
-        final boolean debug = false ;
-        if ( debug ) {
-            if ( label != null && log.isInfoEnabled() )
-                log.info("Transform: " + label) ;
-            if ( op == op2 ) {
-                if ( log.isInfoEnabled() )
-                    log.info("No change (==)") ;
-                return op2 ;
-            }
-
-            if ( op.equals(op2) ) {
-                if ( log.isInfoEnabled() )
-                    log.info("No change (equals)") ;
-                return op2 ;
-            }
-            if ( log.isInfoEnabled() ) {
-                log.info("\n" + op.toString()) ;
-                log.info("\n" + op2.toString()) ;
-            }
-        }
-        if ( op2 != op )
-            return op2 ;
-        return op ;
-    }
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/d864d5e8/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/OptimizerMinimal.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/OptimizerMinimal.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/OptimizerMinimal.java
new file mode 100644
index 0000000..aec30c4
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/OptimizerMinimal.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.algebra.optimize;
+
+import org.apache.jena.sparql.algebra.Op;
+import org.apache.jena.sparql.util.Context;
+
+/** The minimal optimizer.
+ * This does property functions and nested variable renaming
+ * but no other transformations of the algebra expression.   
+ */
+public class OptimizerMinimal implements Rewrite {
+
+    private final Context context;
+
+    public OptimizerMinimal(Context context) {
+        this.context = context;
+    }
+
+    @Override
+    public Op rewrite(Op op) {
+        // Property functions - convert lists to arguments, create (propfunc)
+        op = TransformPropertyFunction.transform(op, context) ;
+        // Rename variables that are hidden by subqueries etc.
+        // so all variables can be treated globally.
+        // Must always do this for QueryEngineMain.
+        op = TransformScopeRename.transform(op) ;
+        return op;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/d864d5e8/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/OptimizerStd.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/OptimizerStd.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/OptimizerStd.java
new file mode 100644
index 0000000..264a381
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/OptimizerStd.java
@@ -0,0 +1,295 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.algebra.optimize;
+
+import org.apache.jena.query.ARQ ;
+import org.apache.jena.sparql.ARQConstants ;
+import org.apache.jena.sparql.SystemARQ ;
+import org.apache.jena.sparql.algebra.* ;
+import org.apache.jena.sparql.algebra.op.OpLabel ;
+import org.apache.jena.sparql.util.Context ;
+import org.apache.jena.sparql.util.Symbol ;
+import org.slf4j.Logger ;
+import org.slf4j.LoggerFactory ;
+
+/** The standard optimization sequence. */
+public class OptimizerStd implements Rewrite
+{
+    static private Logger log = LoggerFactory.getLogger(Optimize.class) ;
+    private final Context context ;
+
+    public OptimizerStd(Context context) {
+        this.context = context ;
+    }
+
+    /** Alternative name for compatibility only */
+    public static final Symbol filterPlacementOldName = SystemARQ.allocSymbol("filterPlacement") ;
+    
+    @Override
+    public Op rewrite(Op op) {
+        // Record optimizer
+        if ( context.get(ARQConstants.sysOptimizer) == null )
+            context.set(ARQConstants.sysOptimizer, this) ;
+        
+        // Old name, new name fixup.
+        if ( context.isDefined(filterPlacementOldName) ) {
+            if ( context.isUndef(ARQ.optFilterPlacement) )
+                context.set(ARQ.optFilterPlacement, context.get(filterPlacementOldName)) ;
+        }
+        
+        if ( false ) {
+            // Removal of "group of one" join (AKA SPARQL "simplification") 
+            // is done during algebra generation in AlgebraGenerator
+            op = apply("Simplify", new TransformSimplify(), op) ;
+            op = apply("Delabel", new TransformRemoveLabels(), op) ;
+        }
+
+        // ** TransformScopeRename
+        // This is a requirement for the linearization execution that the default
+        // ARQ query engine uses where possible.  
+        // This transformation must be done (e.g. by QueryEngineBase) if no other optimization is done. 
+        op = TransformScopeRename.transform(op) ;
+        
+        // Prepare expressions.
+        OpWalker.walk(op, new OpVisitorExprPrepare(context)) ;
+        
+        // Convert paths to triple patterns if possible.
+        if ( context.isTrueOrUndef(ARQ.optPathFlatten) ) {
+            op = apply("Path flattening", new TransformPathFlattern(), op) ;
+            // and merge adjacent BGPs (part 1)
+            if ( context.isTrueOrUndef(ARQ.optMergeBGPs) )
+                op = apply("Merge BGPs", new TransformMergeBGPs(), op) ;
+        }
+
+        // Having done the required transforms, specifically TransformScopeRename,
+        // do each optimization via an overrideable method. Subclassing can modify the
+        // transform performed.
+        
+        // Expression constant folding
+        if ( context.isTrueOrUndef(ARQ.optExprConstantFolding) )
+            op = transformExprConstantFolding(op) ;
+        
+        if ( context.isTrueOrUndef(ARQ.propertyFunctions) )
+            op = transformPropertyFunctions(op) ;
+
+        // Expand (A&&B) to two filter (A), (B) so that they can be placed independently.
+        if ( context.isTrueOrUndef(ARQ.optFilterConjunction) )
+            op = transformFilterConjunction(op) ;
+
+        // Expand IN and NOT IN which then allows other optimizations to be applied.
+        if ( context.isTrueOrUndef(ARQ.optFilterExpandOneOf) )
+            op = transformFilterExpandOneOf(op) ;
+        
+        // Eliminate/Inline assignments where possible
+        // Do this before we do some of the filter transformation work as inlining assignments 
+        // may give us more flexibility in optimizing the resulting filters
+        if ( context.isTrue(ARQ.optInlineAssignments) )
+            op = transformInlineAssignments(op) ;
+
+        // Apply some general purpose filter transformations
+        if ( context.isTrueOrUndef(ARQ.optFilterImplicitJoin) )
+            op = transformFilterImplicitJoin(op) ;
+        
+        if ( context.isTrueOrUndef(ARQ.optImplicitLeftJoin) )
+            op = transformFilterImplicitLeftJoin(op) ;
+                
+        if ( context.isTrueOrUndef(ARQ.optFilterDisjunction) )
+            op = transformFilterDisjunction(op) ;
+        
+        // Some ORDER BY-LIMIT N queries can be done more efficiently by only recording
+        // the top N items, so a full sort is not needed.
+        if ( context.isTrueOrUndef(ARQ.optTopNSorting) )
+            op = transformTopNSorting(op) ;
+        
+        // ORDER BY+DISTINCT optimizations
+        // We apply the one that changes evaluation order first since when it does apply it will give much
+        // better performance than just transforming DISTINCT to REDUCED
+        
+        if ( context.isTrueOrUndef(ARQ.optOrderByDistinctApplication) )
+            op = transformOrderByDistinctApplication(op) ;
+
+        // Transform some DISTINCT to REDUCED, slightly more liberal transform that ORDER BY+DISTINCT application
+        // Reduces memory consumption.
+        if ( context.isTrueOrUndef(ARQ.optDistinctToReduced) )
+            op = transformDistinctToReduced(op) ;
+        
+        // Find joins/leftJoin that can be done by index joins (generally preferred as fixed memory overhead).
+        if ( context.isTrueOrUndef(ARQ.optIndexJoinStrategy) )
+            op = transformJoinStrategy(op) ;
+                
+        // Place filters close to where their dependency variables are defined.
+        // This prunes the output of that step as early as possible.
+        // If done before TransformJoinStrategy, you can get two applications
+        // of a filter in a (sequence) from each half of a (join).  This is harmless,
+        // because filters are generally cheap, but it looks a bit bad.
+        if ( context.isTrueOrUndef(ARQ.optFilterPlacement) )
+            op = transformFilterPlacement(op) ;
+        
+        // Replace suitable FILTER(?x = TERM) with (assign) and write the TERM for ?x in the pattern.    
+        // Apply (possible a second time) after FILTER placement as it can create new possibilities.
+        // See JENA-616.
+       if ( context.isTrueOrUndef(ARQ.optFilterEquality) )
+           op = transformFilterEquality(op) ;
+                
+        // Replace suitable FILTER(?x != TERM) with (minus (original) (table)) where the table contains
+        // the candidate rows to be eliminated
+        // Off by default due to minimal performance difference
+        if ( context.isTrue(ARQ.optFilterInequality) )
+            op = transformFilterInequality(op) ;
+        
+        // Promote table empty as late as possible since this will only be produced by other 
+        // optimizations and never directly from algebra generation
+        if ( context.isTrueOrUndef(ARQ.optPromoteTableEmpty) )
+            op = transformPromoteTableEmpty(op) ;
+
+        // Merge adjacent BGPs
+        if ( context.isTrueOrUndef(ARQ.optMergeBGPs) )
+            op = transformMergeBGPs(op) ;
+
+        // Normally, leave to the specific engines.
+        if ( context.isTrue(ARQ.optReorderBGP) )
+            op = transformReorder(op) ;
+        
+        // Merge (extend) and (assign) stacks
+        if ( context.isTrueOrUndef(ARQ.optMergeExtends) )
+            op = transformExtendCombine(op) ;
+                
+        // Mark
+        if ( false )
+            op = OpLabel.create("Transformed", op) ;
+        return op ;
+    }
+    
+    protected Op transformExprConstantFolding(Op op) {
+        return Transformer.transform(new TransformCopy(), new ExprTransformConstantFold(), op);
+    }
+
+    protected Op transformPropertyFunctions(Op op) {
+        return apply("Property Functions", new TransformPropertyFunction(context), op) ;
+    }
+
+    protected Op transformFilterConjunction(Op op) {
+        return apply("filter conjunctions to ExprLists", new TransformFilterConjunction(), op) ;
+    }
+    protected Op transformFilterExpandOneOf(Op op) {
+        return apply("Break up IN and NOT IN", new TransformExpandOneOf(), op) ;
+    }
+
+    protected Op transformInlineAssignments(Op op) {
+        return TransformEliminateAssignments.eliminate(op, context.isTrue(ARQ.optInlineAssignmentsAggressive));
+    }
+
+    protected Op transformFilterImplicitJoin(Op op) {
+        return apply("Filter Implicit Join", new TransformFilterImplicitJoin(), op);
+    }
+
+    protected Op transformFilterImplicitLeftJoin(Op op) {
+        return apply("Implicit Left Join", new TransformImplicitLeftJoin(), op);
+    }
+
+    protected Op transformFilterDisjunction(Op op) {
+        return apply("Filter Disjunction", new TransformFilterDisjunction(), op) ;
+    }
+
+    protected Op transformTopNSorting(Op op) {
+        return apply("TopN Sorting", new TransformTopN(), op) ;
+    }
+
+    protected Op transformOrderByDistinctApplication(Op op) {
+        return apply("Apply DISTINCT prior to ORDER BY where possible", new TransformOrderByDistinctApplication(), op);
+    }
+
+    protected Op transformDistinctToReduced(Op op) {
+        return apply("Distinct replaced with reduced", new TransformDistinctToReduced(), op) ;
+    }
+
+    protected Op transformJoinStrategy(Op op) {
+        return apply("Index Join strategy", new TransformJoinStrategy(), op) ;
+    }
+
+    protected Op transformFilterPlacement(Op op) {
+        if ( context.isTrue(ARQ.optFilterPlacementConservative))
+            op = apply("Filter Placement (conservative)", new TransformFilterPlacementConservative(), op) ;
+        else { 
+            // Whether to push into BGPs 
+            boolean b = context.isTrueOrUndef(ARQ.optFilterPlacementBGP) ;
+            op = apply("Filter Placement", new TransformFilterPlacement(b), op) ;
+        }
+        return op ;
+    }
+
+    protected Op transformFilterEquality(Op op) {
+        return apply("Filter Equality", new TransformFilterEquality(), op) ;
+    }
+
+    protected Op transformFilterInequality(Op op) {
+        return apply("Filter Inequality", new TransformFilterInequality(), op);
+    }
+
+    protected Op transformPromoteTableEmpty(Op op) {
+        return apply("Table Empty Promotion", new TransformPromoteTableEmpty(), op) ;
+    }
+
+    protected Op transformMergeBGPs(Op op) {
+        return apply("Merge BGPs", new TransformMergeBGPs(), op) ;
+    }
+
+    protected Op transformReorder(Op op) {
+        return  apply("ReorderMerge BGPs", new TransformReorder(), op) ;
+    }
+
+    protected Op transformExtendCombine(Op op) {
+        return apply("Combine BIND/LET", new TransformExtendCombine(), op) ;
+    }
+
+    public static Op apply(Transform transform, Op op) {
+        Op op2 = Transformer.transformSkipService(transform, op) ;
+        if ( op2 != op )
+            return op2 ;
+        return op ;
+    }
+    
+    public static Op apply(String label, Transform transform, Op op) {
+        Op op2 = Transformer.transformSkipService(transform, op) ;
+        
+        final boolean debug = false ;
+        if ( debug ) {
+            if ( label != null && log.isInfoEnabled() )
+                log.info("Transform: " + label) ;
+            if ( op == op2 ) {
+                if ( log.isInfoEnabled() )
+                    log.info("No change (==)") ;
+                return op2 ;
+            }
+
+            if ( op.equals(op2) ) {
+                if ( log.isInfoEnabled() )
+                    log.info("No change (equals)") ;
+                return op2 ;
+            }
+            if ( log.isInfoEnabled() ) {
+                log.info("\n" + op.toString()) ;
+                log.info("\n" + op2.toString()) ;
+            }
+        }
+        if ( op2 != op )
+            return op2 ;
+        return op ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/d864d5e8/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/TransformPropertyFunction.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/TransformPropertyFunction.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/TransformPropertyFunction.java
index b138c5f..3fc313f 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/TransformPropertyFunction.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/TransformPropertyFunction.java
@@ -19,9 +19,8 @@
 package org.apache.jena.sparql.algebra.optimize;
 
 import org.apache.jena.query.ARQ ;
-import org.apache.jena.sparql.algebra.Op ;
-import org.apache.jena.sparql.algebra.PropertyFunctionGenerator ;
-import org.apache.jena.sparql.algebra.TransformCopy ;
+import org.apache.jena.sparql.ARQConstants;
+import org.apache.jena.sparql.algebra.*;
 import org.apache.jena.sparql.algebra.op.OpBGP ;
 import org.apache.jena.sparql.algebra.op.OpTriple ;
 import org.apache.jena.sparql.pfunction.PropertyFunctionRegistry ;
@@ -34,6 +33,21 @@ public class TransformPropertyFunction extends TransformCopy
     private final boolean doingMagicProperties ;
     private final PropertyFunctionRegistry registry ;
     
+    /** Apply the property function transformation. 
+     *  <p>
+     *  The {@code context} provide the place to find the property function registry.
+     *  A custom one canbe supplied using 
+     *  {@link ARQConstants#registryPropertyFunctions}
+     *  <p>
+     *  See {@link PropertyFunctionRegistry#chooseRegistry} for the full decision process.
+     *  <p>
+     *  In addition, {@link ARQ#enablePropertyFunctions} must be true (this is the default). 
+     */
+    public static Op transform(Op op, Context context) {
+        Transform t = new TransformPropertyFunction(context) ;
+        return Transformer.transform(t, op) ; 
+    }
+    
     public TransformPropertyFunction(Context context)
     {
         this.context = context ;  

http://git-wip-us.apache.org/repos/asf/jena/blob/d864d5e8/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/QueryEngineMain.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/QueryEngineMain.java b/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/QueryEngineMain.java
index 993d4d4..c9a85aa 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/QueryEngineMain.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/QueryEngineMain.java
@@ -22,7 +22,7 @@ import org.apache.jena.query.ARQ ;
 import org.apache.jena.query.Query ;
 import org.apache.jena.sparql.algebra.Algebra ;
 import org.apache.jena.sparql.algebra.Op ;
-import org.apache.jena.sparql.algebra.optimize.TransformScopeRename ;
+import org.apache.jena.sparql.algebra.optimize.Optimize;
 import org.apache.jena.sparql.core.DatasetGraph ;
 import org.apache.jena.sparql.engine.* ;
 import org.apache.jena.sparql.engine.binding.Binding ;
@@ -67,11 +67,8 @@ public class QueryEngineMain extends QueryEngineBase
         return Algebra.optimize(op, super.context) ;
     }
     
-    protected Op minimalModifyOp(Op op)
-    {
-        // Must always do this for QueryEngineMain.
-        // The optimizer does do this.
-        return TransformScopeRename.transform(op) ;
+    protected Op minimalModifyOp(Op op) {
+        return Optimize.minimalOptimizationFactory.create(context).rewrite(op);
     }
     
     // -------- Factory

http://git-wip-us.apache.org/repos/asf/jena/blob/d864d5e8/jena-arq/src/main/java/org/apache/jena/sparql/graph/NodeTransformOp.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/graph/NodeTransformOp.java b/jena-arq/src/main/java/org/apache/jena/sparql/graph/NodeTransformOp.java
index ff3a74b..09a6846 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/graph/NodeTransformOp.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/graph/NodeTransformOp.java
@@ -38,7 +38,7 @@ import org.apache.jena.sparql.path.Path ;
 
 class NodeTransformOp extends TransformCopy
 {
-    // This finds everywhere that node can lurk in an algebra expression:
+    // This finds everywhere that nodes can lurk in an algebra expression:
     //   BGPs, paths, triples, quads
     //   GRAPH, GRAPH{} (DatasetNames)
     //   Filters, including inside EXISTS and expressions in LeftJoin