You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by rv...@apache.org on 2015/07/07 11:24:24 UTC
[19/26] jena git commit: Merge branch 'master' into
eliminate-assignments-jena3
http://git-wip-us.apache.org/repos/asf/jena/blob/9d684173/jena-arq/src/main/java/org/apache/jena/query/ARQ.java
----------------------------------------------------------------------
diff --cc jena-arq/src/main/java/org/apache/jena/query/ARQ.java
index 0000000,420e3b9..5ba3074
mode 000000,100644..100644
--- a/jena-arq/src/main/java/org/apache/jena/query/ARQ.java
+++ b/jena-arq/src/main/java/org/apache/jena/query/ARQ.java
@@@ -1,0 -1,582 +1,594 @@@
+ /*
+ * 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.query;
+
+ import org.apache.jena.riot.RIOT ;
+ import org.apache.jena.sparql.ARQConstants ;
+ import org.apache.jena.sparql.SystemARQ ;
+ import org.apache.jena.sparql.algebra.optimize.TransformOrderByDistinctApplication ;
+ import org.apache.jena.sparql.engine.http.Service ;
+ import org.apache.jena.sparql.engine.main.StageBuilder ;
+ import org.apache.jena.sparql.lib.Metadata ;
+ import org.apache.jena.sparql.mgt.ARQMgt ;
+ import org.apache.jena.sparql.mgt.Explain ;
+ import org.apache.jena.sparql.mgt.SystemInfo ;
+ import org.apache.jena.sparql.mgt.Explain.InfoLevel ;
+ import org.apache.jena.sparql.util.Context ;
+ import org.apache.jena.sparql.util.MappingRegistry ;
+ import org.apache.jena.sparql.util.Symbol ;
+ import org.slf4j.Logger ;
+ import org.slf4j.LoggerFactory ;
+
+ /** ARQ - miscellaneous settings */
+
+ public class ARQ
+ {
+ /** Name of the execution logger */
+ public static final String logExecName = "com.hp.hpl.jena.arq.exec" ;
+
+ /** Name of the information logger */
+ public static final String logInfoName = "com.hp.hpl.jena.arq.info" ;
+
+ /** Name of the logger for remote HTTP requests */
+ public static final String logHttpRequestName = "com.hp.hpl.jena.arq.service" ;
+
+ private static final Logger logExec = LoggerFactory.getLogger(logExecName) ;
+ private static final Logger logInfo = LoggerFactory.getLogger(logInfoName) ;
+ private static final Logger logHttpRequest = LoggerFactory.getLogger(logHttpRequestName) ;
+
+ /** The execution logger */
+ public static Logger getExecLogger() { return logExec ; }
+
+ /** The information logger */
+ public static Logger getInfoLogger() { return logInfo ; }
+
+ /** The HTTP Request logger */
+ public static Logger getHttpRequestLogger() { return logHttpRequest ; }
+
+ /** Symbol to enable logging of execution.
+ * Must also set log4j, or other logging system,
+ * for logger "com.hp.hpl.jena.sparql.exec"
+ * e.g. log4j.properties -- log4j.logger.com.hp.hpl.jena.sparql.exec=INFO
+ * See the <a href="http://jena.apache.org/documentation/query/logging.html">ARQ Logging Documentation</a>.
+ */
+ public static final Symbol symLogExec = ARQConstants.allocSymbol("logExec") ;
+
+ /** Get the currently global execution logging setting */
+ public static Explain.InfoLevel getExecutionLogging() { return (Explain.InfoLevel)ARQ.getContext().get(ARQ.symLogExec) ; }
+
+ /** Set execution logging - logging is to logger "com.hp.hpl.jena.arq.exec" at level INFO.
+ * An appropriate logging configuration is also required.
+ */
+ public static void setExecutionLogging(Explain.InfoLevel infoLevel)
+ {
+ if ( InfoLevel.NONE.equals(infoLevel) )
+ {
+ ARQ.getContext().unset(ARQ.symLogExec) ;
+ return ;
+ }
+
+ ARQ.getContext().set(ARQ.symLogExec, infoLevel) ;
+ // if ( ! getExecLogger().isInfoEnabled() )
+ // getExecLogger().warn("Attempt to enable execution logging but the logger '"+logExecName+"' is not logging at level INFO") ;
+ }
+
+ /** IRI for ARQ */
+ public static final String arqIRI = "http://jena.hpl.hp.com/#arq" ;
+
+ /** Root of ARQ-defined parameter names */
+ public static final String arqParamNS = "http://jena.apache.org/ARQ#" ;
+
+ /** Prefix for ARQ-defined parameter names */
+ public static final String arqSymbolPrefix = "arq" ;
+
+ /** Stick exactly to the spec.
+ */
+ public static final Symbol strictSPARQL =
+ ARQConstants.allocSymbol("strictSPARQL") ;
+
+ /** Controls bNode labels as <_:...> or not -
+ * that is a pseudo URIs.
+ * This does not affect [] or _:a bNodes as variables in queries.
+ */
+
+ public static final Symbol constantBNodeLabels =
+ ARQConstants.allocSymbol("constantBNodeLabels") ;
+
+ /** Enable built-in property functions - also called "magic properties".
+ * These are properties in triple patterns that need
+ * calculation, not matching. See ARQ documentation for more details.
+ * rdfs:member and http://jena.apache.org/ARQ/list#member are provided.
+ */
+
+ public static final Symbol enablePropertyFunctions =
+ ARQConstants.allocSymbol("enablePropertyFunctions") ;
+
+ /** Enable logging of execution timing.
+ */
+
+ public static final Symbol enableExecutionTimeLogging =
+ ARQConstants.allocSymbol("enableExecutionTimeLogging") ;
+
+ /** If true, XML result sets written will contain the graph bNode label
+ * See also inputGraphBNodeLabels
+ */
+
+ public static final Symbol outputGraphBNodeLabels =
+ ARQConstants.allocSymbol("outputGraphBNodeLabels") ;
+
+ /** If true, XML result sets will use the bNode label in the result set itself.
+ * See also outputGraphBNodeLabels
+ */
+
+ public static final Symbol inputGraphBNodeLabels =
+ ARQConstants.allocSymbol("inputGraphBNodeLabels") ;
+
+ /** Turn on processing of blank node labels in queries */
+ public static void enableBlankNodeResultLabels() { enableBlankNodeResultLabels(true) ; }
+
+ /** Turn on/off processing of blank node labels in queries */
+ public static void enableBlankNodeResultLabels(boolean val)
+ {
+ Boolean b = val;
+ globalContext.set(inputGraphBNodeLabels, b) ;
+ globalContext.set(outputGraphBNodeLabels, b) ;
+ }
+
+
+ /**
+ * Set timeout. The value of this symbol gives thevalue of the timeout in milliseconds
+ * <ul>
+ * <li>A Number; the long value is used</li>
+ * <li>A string, e.g. "1000", parsed as a number</li>
+ * <li>A string, as two numbers separated by a comma, e.g. "500,10000" parsed as two numbers</li>
+ * </ul>
+ * @see QueryExecution#setTimeout(long)
+ * @see QueryExecution#setTimeout(long,long)
+ */
+ public static final Symbol queryTimeout = ARQConstants.allocSymbol("queryTimeout") ;
+
+ // This can't be a context constant because NodeValues don't look in the context.
+ // /**
+ // * Context symbol controlling Roman Numerals in Filters.
+ // */
+ // public static final Symbol enableRomanNumerals = ARQConstants.allocSymbol("romanNumerals") ;
+
+ /**
+ * Context key for StageBuilder used in BGP compilation
+ */
+ public static final Symbol stageGenerator = ARQConstants.allocSymbol("stageGenerator") ;
+
+ /**
+ * Context key to control hiding non-distinuished variables
+ */
+ public static final Symbol hideNonDistiguishedVariables = ARQConstants.allocSymbol("hideNonDistiguishedVariables") ;
+
+ /**
+ * Use the SAX parser for XML result sets. The default is to use StAX for
+ * full streaming of XML results. The SAX parser takes a copy of the result set
+ * before giving the ResultSet to the calling application.
+ */
+ public static final Symbol useSAX = ARQConstants.allocSymbol("useSAX") ;
+
+ /**
+ * Indicate whether duplicate select and groupby variables are allowed.
+ * If false, duplicates are silently supressed; it's not an error.
+ */
+ public static final boolean allowDuplicateSelectColumns = false ;
+
+ /**
+ * Determine which regular expression system to use.
+ * The value of this context entry should be a string or symbol
+ * of one of the following:
+ * javaRegex : use java.util.regex (support features outside the strict SPARQL regex language)
+ * xercesRegex : use the internal XPath regex engine (more compliant)
+ */
+
+ public static final Symbol regexImpl = ARQConstants.allocSymbol("regexImpl") ;
+
+
+ /** Symbol to name java.util.regex regular expression engine */
+ public static final Symbol javaRegex = ARQConstants.allocSymbol("javaRegex") ;
+ /** Symbol to name the Xerces-J regular expression engine */
+ public static final Symbol xercesRegex = ARQConstants.allocSymbol("xercesRegex") ;
+
+ /**
+ * Use this Symbol to allow passing additional query parameters to a
+ * SERVICE <IRI> call.
+ * Parameters need to be grouped by SERVICE <IRI>,
+ * a Map<String, Map<String,List<String>>> is assumed.
+ * The key of the first map is the SERVICE IRI, the value is a Map
+ * which maps the name of a query string parameters to its values.
+ *
+ * @see org.apache.jena.sparql.engine.http.Service
+ */
+ public static final Symbol serviceParams = ARQConstants.allocSymbol("serviceParams") ;
+
+ /**
+ * Control whether SERVICE processing is allowed.
+ * If the context of the query exexcution contains this,
+ * and it's set to "false", then SERVICE is not allowed.
+ */
+
+ public static final Symbol serviceAllowed = Service.serviceAllowed ;
+
+ /**
+ * A Long value that specifies the number of bindings (or triples for CONSTRUCT queries) to be stored in memory by sort
+ * operations or hash tables before switching to temporary disk files. The value defaults to -1, which will always
+ * keep the bindings in memory and never write to temporary files. The amount of memory used will vary based on
+ * the size of the bindings. If you are retrieving large literal strings, then you may need to lower the value.
+ * <p/>
+ * Note that for a complex query, several sort or hash operations might be running in parallel; each one will be
+ * allowed to retain as many bindings in memory as this value specifies before it starts putting data in temporary
+ * files. Also, several running sessions could be doing such operations concurrently. Therefore, the total number
+ * of bindings held in memory could be many times this value; it is necessary to keep this fact in mind when
+ * choosing the value.
+ * <p/>
+ * Operations currently affected by this symbol: <br>
+ * ORDER BY, SPARQL Update, CONSTRUCT (optionally)
+ * <p/>
+ * TODO: Give a reasonable suggested value here. 10,000?
+ * <p/>
+ * @see <a href="https://issues.apache.org/jira/browse/JENA-119">JENA-119</a>
+ */
+ // Some possible additions to the list:
+ // Sort: DISTINCT, merge joins<br>
+ // Hash table: GROUP BY, MINUS, SERVICE, VALUES, and hash joins <br>
+ public static final Symbol spillToDiskThreshold = ARQConstants.allocSymbol("spillToDiskThreshold") ;
+
+ // Optimizer controls.
+
+ /**
+ * Globally switch the default optimizer on and off :
+ * Note that storage subsystems may also be applying
+ * separately controlled optimizations.
+ */
+
+ public static void enableOptimizer(boolean state)
+ {
+ enableOptimizer(ARQ.getContext(), state) ;
+ }
+
+ /**
+ * Switch the default optimizer on and off for a specific Context.
+ * Note that storage subsystems may also be applying
+ * separately controlled optimizations.
+ */
+ public static void enableOptimizer(Context context, boolean state)
+ {
+ context.set(ARQ.optimization, state) ;
+ }
+
+ /**
+ * Context key controlling whether the main query engine applies the
+ * default optimization transformations.
+ */
+ public static final Symbol optimization = ARQConstants.allocSymbol("optimization") ;
+
+ /**
+ * Context key controlling whether the main query engine flattens simple paths
+ * (e.g. <tt>?x :p/:q ?z => ?x :p ?.0 . ?.0 ?q ?z</tt>)
+ * <p>Default is "true"
+ */
+ public static final Symbol optPathFlatten = ARQConstants.allocSymbol("optPathFlatten") ;
+
+ /**
+ * Context key controlling whether the main query engine moves filters to the "best" place.
+ * Default is "true" - filter placement is done.
+ */
+ public static final Symbol optFilterPlacement = ARQConstants.allocSymbol("optFilterPlacement") ;
+
+ /**
+ * Context key controlling whether to do filter placement within BGP and quad blocks.
+ * Modies the effect of optFilterPlacement.
+ * Default is "true" - filter placement is pushed into BGPs.
+ */
+ public static final Symbol optFilterPlacementBGP = ARQConstants.allocSymbol("optFilterPlacementBGP") ;
+
+ /**
+ * Context key controlling whether the main query engine moves filters to the "best" place using
+ * the more limited and conservative strategy which does not place as many filters
+ * Must be explicitly set "true" to operate.
+ * Filter placement, via {@link #optFilterPlacement} must also be active (which it is by default).
+ * @see #optFilterPlacement
+ */
+ public static final Symbol optFilterPlacementConservative = ARQConstants.allocSymbol("optFilterPlacementConservative") ;
+
+ /**
+ * Context key controlling whether an ORDER BY-LIMIT query is done avoiding total sort using an heap.
+ * Default is "true" - total sort if avoided by default when ORDER BY is used with LIMIT.
+ */
+ public static final Symbol optTopNSorting = ARQConstants.allocSymbol("optTopNSorting") ;
+
+ /**
+ * Context key controlling whether a DISTINCT-ORDER BY query is done by replacing the distinct with a reduced.
+ * Default is "true" - the reduced operator does not need to keep a data structure with all previously seen bindings.
+ */
+ public static final Symbol optDistinctToReduced = ARQConstants.allocSymbol("optDistinctToReduced") ;
+
+ /**
+ * Context key controlling whether a DISTINCT-ORDER BY query is done by applying the ORDER BY after the DISTINCT
+ * when default SPARQL semantics usually mean ORDER BY applies before DISTINCT. This optimization applies only
+ * in a subset of cases unlike the more general {@link #optDistinctToReduced} optimization.
+ * <p>
+ * See {@link TransformOrderByDistinctApplication} for more discussion on exactly when this may apply
+ * </p>
+ */
+ public static final Symbol optOrderByDistinctApplication = ARQConstants.allocSymbol("optOrderByDistinctApplication");
+
+ /**
+ * Context key controlling whether the standard optimizer applies
+ * optimizations to equalities in FILTERs.
+ * This optimization is conservative - it does not take place if
+ * there is a potential risk of changing query semantics.
+ */
+ public static final Symbol optFilterEquality = ARQConstants.allocSymbol("optFilterEquality") ;
+
+ /**
+ * Context key controlling whether the standard optimizer applies
+ * optimizations to inequalities in FILTERs
+ * This optimization is conservative - it does not take place if
+ * there is a potential risk of changing query semantics
+ */
+ public static final Symbol optFilterInequality = ARQConstants.allocSymbol("optFilterInequality") ;
+
+ /**
+ * Context key controlling whether the standard optimizer applies optimizations to implicit joins in FILTERs.
+ * This optimization is conservative - it does not take place if there is a potential risk of changing query semantics.
+ */
+ public static final Symbol optFilterImplicitJoin = ARQConstants.allocSymbol("optFilterImplicitJoin");
+
+ /**
+ * Context key controlling whether the standard optimizer applies optimizations to implicit left joins.
+ * This optimization is conservative - it does not take place if there is a potential risk of changing query semantics.
+ */
+ public static final Symbol optImplicitLeftJoin = ARQConstants.allocSymbol("optImplicitLeftJoin");
+
+ /**
+ * Context key for a declaration that xsd:strings and simple literals are
+ * different in the storage. They are the same value in a memory store.
+ * When in doubt, xsd:strings are assumed to be the same value as simple literals
+ */
+ public static final Symbol optTermStrings = ARQConstants.allocSymbol("optTermStrings") ;
+
+ /**
+ * Context key controlling whether the standard optimizer applies constant folding to expressions
+ */
+ public static final Symbol optExprConstantFolding = ARQConstants.allocSymbol("optExprConstantFolding");
+
+ /**
+ * Context key controlling whether the standard optimizer applies
+ * optimizations to conjunctions (&&) in filters.
+ */
+ public static final Symbol optFilterConjunction = ARQConstants.allocSymbol("optFilterConjunction") ;
+
+ /**
+ * Context key controlling whether the standard optimizer applies
+ * optimizations to IN and NOT IN.
+ */
+ public static final Symbol optFilterExpandOneOf = ARQConstants.allocSymbol("optFilterExpandOneOf") ;
+
+ /**
+ * Context key controlling whether the standard optimizer applies
+ * optimizations to disjunctions (||) in filters.
+ */
+ public static final Symbol optFilterDisjunction = ARQConstants.allocSymbol("optFilterDisjunction") ;
+
+ /**
+ * Context key controlling whether the standard optimizer applies table empty promotion
+ */
+ public static final Symbol optPromoteTableEmpty = ARQConstants.allocSymbol("optPromoteTableEmpty") ;
+
+ /**
+ * Context key controlling whether the standard optimizer applies optimizations to the evaluation
+ * of joins to favour index joins wherever possible
+ */
+ public static final Symbol optIndexJoinStrategy = ARQConstants.allocSymbol("optIndexJoinStrategy");
+
+ /**
++ * Context key controlling whether the standard optimizer applies optimizations where by some
++ * assignments may be eliminated/inlined into the operators where their values are used only once
++ */
++ public static final Symbol optInlineAssignments = ARQConstants.allocSymbol("optInlineAssignments");
++
++ /**
++ * Context key controlling whether the standard optimizer aggressively inlines assignments whose
++ * values are used only once into operators where those expressions may be evaluated multiple times e.g. order
++ */
++ public static final Symbol optInlineAssignmentsAggressive = ARQConstants.allocSymbol("optInlineAssignmentsAggressive");
++
++ /**
+ * Context key controlling whether the standard optimizater applies optimizations to joined BGPs to
+ * merge them into single BGPs.
+ * By default, this transformation is applied.
+ */
+ public static final Symbol optMergeBGPs = ARQConstants.allocSymbol("optMergeBGPs");
+
+ /**
+ * Context key controlling whether the standard optimizater applies the optimization
+ * to combine stacks of (extend) into one compound operation. Ditto (assign).
+ * By default, this transformation is applied.
+ */
+ public static final Symbol optMergeExtends = ARQConstants.allocSymbol("optMergeExtends");
+
+ /**
+ * Context key controlling whether the main query engine processes property functions.
+ *
+ */
+ public static final Symbol propertyFunctions = ARQConstants.allocSymbol("propertyFunctions") ;
+
+ /**
+ * Expression evaluation without extension types (e.g. xsd:date, language tags)
+ */
+ public static final Symbol extensionValueTypes = ARQConstants.allocSymbol("extensionValueTypesExpr") ;
+
+ /**
+ * Generate the ToList operation in the algebra (as ARQ is stream based, ToList is a non-op).
+ * Default is not to do so. Strict mode will also enable this.
+ */
+ public static final Symbol generateToList = ARQConstants.allocSymbol("generateToList") ;
+
+ /** Set strict mode, including expression evaluation */
+ public static void setStrictMode() { setStrictMode(ARQ.getContext()) ; }
+
+ /** Set strict mode for a given Context.
+ *
+ * Does not influence expression evaluation because NodeValues
+ * are controlled globally, not per context.
+ */
+ public static void setStrictMode(Context context)
+ {
+ SystemARQ.StrictDateTimeFO = true ;
+ SystemARQ.ValueExtensions = false ;
+ SystemARQ.EnableRomanNumerals = false ;
+
+ context.set(optimization, false) ;
+ context.set(hideNonDistiguishedVariables, true) ;
+ context.set(strictSPARQL, true) ;
+ context.set(enablePropertyFunctions, false) ;
+
+ context.set(extensionValueTypes, false) ;
+ context.set(constantBNodeLabels, false) ;
+ context.set(generateToList, true) ;
+ context.set(regexImpl, xercesRegex) ;
+
+ //context.set(filterPlacement, false) ;
+ }
+
+ public static boolean isStrictMode() { return ARQ.getContext().isTrue(strictSPARQL) ; }
+
+ /** Set normal mode, including expression evaluation */
+ public static void setNormalMode() {
+ SystemARQ.StrictDateTimeFO = false ;
+ SystemARQ.ValueExtensions = true ;
+ SystemARQ.EnableRomanNumerals = false ;
+ setNormalMode(ARQ.getContext()) ;
+ }
+
+ /** Explicitly set the values for normal operation.
+ * Does not influence expression evaluation.
+ */
+ public static void setNormalMode(Context context)
+ {
+ context.set(optimization, true) ;
+ context.set(hideNonDistiguishedVariables, false) ;
+ context.set(strictSPARQL, false) ;
+ context.set(enablePropertyFunctions, true) ;
+
+ context.set(extensionValueTypes, true) ;
+ context.set(constantBNodeLabels, true) ;
+ context.set(generateToList, false) ;
+ context.set(regexImpl, javaRegex) ;
+ }
+
+ // ----------------------------------
+
+ /** The root package name for ARQ */
+ public static final String PATH = "org.apache.jena.arq";
+
+ static private String metadataLocation = "org/apache/jena/arq/arq-properties.xml" ;
+
+ static private Metadata metadata = new Metadata(metadataLocation) ;
+
+ /** The product name */
+ public static final String NAME = "ARQ";
+
+ /** The full name of the current ARQ version */
+ public static final String VERSION = metadata.get(PATH+".version", "unknown") ;
+
+ /** The date and time at which this release was built */
+ public static final String BUILD_DATE = metadata.get(PATH+".build.datetime", "unset") ;
+
+ // A correct way to manage without synchonized using the double checked locking pattern.
+ // http://en.wikipedia.org/wiki/Double-checked_locking
+ // http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
+ private static volatile boolean initialized = false ;
+ private static final Object initLock = new Object() ;
+
+ private static Context globalContext = null ;
+
+ /** Ensure things have started - applications do not need call this.
+ * The method is public so any part of ARQ can call it.
+ * Note the final static initializer call
+ */
+
+ public static void init()
+ {
+ if ( initialized )
+ return ;
+ synchronized(initLock)
+ {
+ if ( initialized )
+ return ;
+ initialized = true ;
+ globalContext = defaultSettings() ;
+
+ RIOT.init() ;
+ StageBuilder.init() ;
+ ARQMgt.init() ; // After context and after PATH/NAME/VERSION/BUILD_DATE are set
+ MappingRegistry.addPrefixMapping(ARQ.arqSymbolPrefix, ARQ.arqParamNS) ;
+
+ // This is the pattern for any subsystem to register.
+ SystemInfo sysInfo = new SystemInfo(ARQ.arqIRI, ARQ.PATH, ARQ.VERSION, ARQ.BUILD_DATE) ;
+ SystemARQ.registerSubSystem(sysInfo) ;
+
+ // Register RIOT details here, not earlier, to avoid
+ // initialization loops with RIOT.init() called directly.
+ RIOT.register() ;
+ }
+ }
+
+ // Force a call
+ static { init() ; }
+
+ /* Side effects */
+ private static Context defaultSettings()
+ {
+ SystemARQ.StrictDateTimeFO = false ;
+ SystemARQ.ValueExtensions = true ;
+ SystemARQ.EnableRomanNumerals = false ;
+
+ Context context = new Context() ;
+ context.unset(optimization) ;
+ //context.set(hideNonDistiguishedVariables, true) ;
+ context.set(strictSPARQL, false) ;
+ context.set(constantBNodeLabels, true) ;
+ context.set(enablePropertyFunctions, true) ;
+ context.set(regexImpl, javaRegex) ;
+
+ return context ;
+ }
+
+ public static Context getContext()
+ {
+ //ARQ.init() ;
+ return globalContext ;
+ }
+
+ // Convenience call-throughs
+ public static void set(Symbol symbol, boolean value) { getContext().set(symbol, value) ; }
+ public static void setTrue(Symbol symbol) { getContext().setTrue(symbol) ; }
+ public static void setFalse(Symbol symbol) { getContext().setFalse(symbol) ; }
+ public static void unset(Symbol symbol) { getContext().unset(symbol) ; }
+ public static boolean isTrue(Symbol symbol) { return getContext().isTrue(symbol) ; }
+ public static boolean isFalse(Symbol symbol) { return getContext().isFalse(symbol) ; }
+ public static boolean isTrueOrUndef(Symbol symbol) { return getContext().isTrueOrUndef(symbol) ; }
+ public static boolean isFalseOrUndef(Symbol symbol) { return getContext().isFalseOrUndef(symbol) ; }
+
+ }
http://git-wip-us.apache.org/repos/asf/jena/blob/9d684173/jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/Optimize.java
----------------------------------------------------------------------
diff --cc jena-arq/src/main/java/org/apache/jena/sparql/algebra/optimize/Optimize.java
index 0000000,342b50d..034e233
mode 000000,100644..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
@@@ -1,0 -1,300 +1,304 @@@
+ /*
+ * 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.algebra.* ;
+ import org.apache.jena.sparql.algebra.op.OpLabel ;
+ import org.apache.jena.sparql.engine.ExecutionContext ;
+ import org.apache.jena.sparql.util.Context ;
+ import org.apache.jena.sparql.util.Symbol ;
+ import org.slf4j.Logger ;
+ import org.slf4j.LoggerFactory ;
+
+
+ public class Optimize implements Rewrite
+ {
+ static private Logger log = LoggerFactory.getLogger(Optimize.class) ;
+
+ // A small (one slot) registry to allow plugging in an alternative optimizer
+ public interface RewriterFactory { Rewrite create(Context context) ; }
+
+ // ----
+ public static RewriterFactory noOptimizationFactory = new RewriterFactory()
+ {
+ @Override
+ public Rewrite create(Context context)
+ {
+ return new Rewrite() {
+
+ @Override
+ public Op rewrite(Op op)
+ {
+ return op ;
+ }} ;
+ }} ;
+
+ public static RewriterFactory stdOptimizationFactory = new RewriterFactory()
+ {
+ @Override
+ public Rewrite create(Context context)
+ {
+ return new Optimize(context) ;
+ }
+ } ;
+
+ // Set this to a different factory implementation to have a different general optimizer.
+ private static RewriterFactory factory = stdOptimizationFactory ;
+
+ // ----
+
+ public static Op optimize(Op op, ExecutionContext execCxt)
+ {
+ return optimize(op, execCxt.getContext()) ;
+ }
+
+ // The execution-independent optimizations
+ public static Op optimize(Op op, Context context)
+ {
+ Rewrite opt = decideOptimizer(context) ;
+ return opt.rewrite(op) ;
+ }
+
+ /** Set the global optimizer factory to one that does nothing */
+ public static void noOptimizer()
+ {
+ setFactory(noOptimizationFactory) ;
+ }
+
+ static private Rewrite decideOptimizer(Context context)
+ {
+ RewriterFactory f = (RewriterFactory)context.get(ARQConstants.sysOptimizerFactory) ;
+ if ( f == null )
+ f = factory ;
+ if ( f == null )
+ f = stdOptimizationFactory ; // Only if default 'factory' gets lost.
+ return f.create(context) ;
+ }
+
+
+ /** Globably set the factory for making optimizers */
+ public static void setFactory(RewriterFactory aFactory)
+ { factory = aFactory ; }
+
+ /** Get the global factory for making optimizers */
+ public static RewriterFactory getFactory()
+ { return factory ; }
+
+ // ---- The object proper for the standard optimizations
+
+ private final Context context ;
+ private Optimize(ExecutionContext execCxt)
+ {
+ this(execCxt.getContext()) ;
+ }
+
+ private Optimize(Context context)
+ {
+ this.context = context ;
+ }
+
+ /** Alternative name for compatibility only */
+ public static final Symbol filterPlacementOldName = ARQConstants.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) ;
+ }
+
+ // Expression constant folding
+ if ( context.isTrueOrUndef(ARQ.optExprConstantFolding) )
+ op = Transformer.transform(new TransformCopy(), new ExprTransformConstantFold(), op);
+
+ // Need to allow subsystems to play with this list.
+
+ if ( context.isTrueOrUndef(ARQ.propertyFunctions) )
+ op = apply("Property Functions", new TransformPropertyFunction(context), op) ;
+
+ if ( context.isTrueOrUndef(ARQ.optFilterConjunction) )
+ op = apply("filter conjunctions to ExprLists", new TransformFilterConjunction(), op) ;
+
+ if ( context.isTrueOrUndef(ARQ.optFilterExpandOneOf) )
+ op = apply("Break up IN and NOT IN", new TransformExpandOneOf(), op) ;
+
+ // Apply some general purpose filter transformations
+
+ if ( context.isTrueOrUndef(ARQ.optFilterImplicitJoin) )
+ op = apply("Filter Implicit Join", new TransformFilterImplicitJoin(), op);
+
+ if ( context.isTrueOrUndef(ARQ.optImplicitLeftJoin) )
+ op = apply("Implicit Left Join", new TransformImplicitLeftJoin(), op);
+
+ if ( context.isTrueOrUndef(ARQ.optFilterDisjunction) )
+ op = apply("Filter Disjunction", new 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 = apply("TopN Sorting", new TransformTopN(), 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 = apply("Apply DISTINCT prior to ORDER BY where possible", new 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 = apply("Distinct replaced with reduced", new TransformDistinctToReduced(), op) ;
+
+ // Find joins/leftJoin that can be done by index joins (generally preferred as fixed memory overhead).
+ if ( context.isTrueOrUndef(ARQ.optIndexJoinStrategy) )
+ op = apply("Index Join strategy", new 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) ) {
+ 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) ;
+ }
+ }
+
+ // 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 = apply("Filter Equality", new 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 = apply("Filter Inequality", new TransformFilterInequality(), op);
+
++ // Eliminate/Inline assignments where possible
++ if ( context.isTrue(ARQ.optInlineAssignments) )
++ op = TransformEliminateAssignments.eliminate(op, context.isTrue(ARQ.optInlineAssignmentsAggressive));
++
+ // 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 = apply("Table Empty Promotion", new TransformPromoteTableEmpty(), op) ;
+
+ // Merge adjacent BGPs
+ if ( context.isTrueOrUndef(ARQ.optMergeBGPs) )
+ op = apply("Merge BGPs", new TransformMergeBGPs(), op) ;
+
+ // Merge (extend) and (assign) stacks
+ if ( context.isTrueOrUndef(ARQ.optMergeExtends) )
+ op = apply("Combine BIND/LET", new TransformExtendCombine(), op) ;
+
+ // Mark
+ if ( false )
+ op = OpLabel.create("Transformed", op) ;
+ return 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)
+ {
+ // Use this to apply inside NOT EXISTS and EXISTS
+ // Transform transform2 = new TransformApplyInsideExprFunctionOp(transform) ;
+ // Remember there is an outer substitue to the NOT EXISTS operation.
+
+ //Transform transform2 = new TransformApplyInsideExprFunctionOp(transform) ;
+
+ 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/9d684173/jena-arq/src/test/java/org/apache/jena/sparql/algebra/optimize/TS_Optimization.java
----------------------------------------------------------------------
diff --cc jena-arq/src/test/java/org/apache/jena/sparql/algebra/optimize/TS_Optimization.java
index 0000000,9099486..e921f47
mode 000000,100644..100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/algebra/optimize/TS_Optimization.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/algebra/optimize/TS_Optimization.java
@@@ -1,0 -1,40 +1,41 @@@
+ /*
+ * 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.junit.runner.RunWith ;
+ import org.junit.runners.Suite ;
+
+ @RunWith(Suite.class)
+ @Suite.SuiteClasses( {
+ TestReorderBGP.class
+ , TestVarRename.class
+ , TestOptDistinctReduced.class
+ , TestSemanticEquivalence.class
+ , TestTransformConstantFolding.class
+ , TestTransformFilters.class
+ , TestTransformFilterPlacement.class
+ , TestTransformMergeBGPs.class
+ , TestTransformPromoteTableEmpty.class
++ , TestTransformEliminateAssignments.class
+ , TestTransformTopN.class
+ , TestOptimizer.class
+ })
+
+ public class TS_Optimization
+ {}