This is an automated email from the ASF dual-hosted git repository.
arnebdt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new 6981d82b49 GH-3323 COALESCE checks variable bindings
6981d82b49 is described below
commit 6981d82b49b1ad80f60ed2f13253c2343cfe3f97
Author: arne-bdt <[email protected]>
AuthorDate: Sun Jul 20 19:20:24 2025 +0200
GH-3323 COALESCE checks variable bindings
COALESCE(?X, ...) is a common usage pattern. COALESCE now checks if a
variable is bound before evaluating it. This avoids creating an exception for
each unbound variable, which previously impacted performance.
Added shadedJena550 and `org.apache.jena.sparql.expr.TestCoalesce` to
implement benchmarks and evaluate the performance impacts.
---
.../org/apache/jena/sparql/expr/E_Coalesce.java | 10 +-
jena-benchmarks/jena-benchmarks-jmh/pom.xml | 7 ++
.../org/apache/jena/sparql/expr/TestCoalesce.java | 115 +++++++++++++++++++++
.../jena-benchmarks-shadedJena510/pom.xml | 2 +-
.../pom.xml | 25 +++--
jena-benchmarks/pom.xml | 1 +
6 files changed, 147 insertions(+), 13 deletions(-)
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_Coalesce.java
b/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_Coalesce.java
index 23d47304d2..588c9f5e9a 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_Coalesce.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_Coalesce.java
@@ -37,9 +37,15 @@ public class E_Coalesce extends ExprFunctionN {
@Override
public NodeValue evalSpecial(Binding binding, FunctionEnv env) {
for ( Expr expr : super.getArgs() ) {
+ if(expr.isVariable() && (binding == null ||
!binding.contains(expr.asVar()))) {
+ // If the expression is a variable and no binding is provided,
+ // we skip it as it cannot be evaluated.
+ // COALESCE(?X, ...) is a common usage pattern and this check
+ // avoids creating an exception for each unbound variable.
+ continue;
+ }
try {
- NodeValue nv = expr.eval(binding, env);
- return nv;
+ return expr.eval(binding, env);
} catch (ExprEvalException ex) {}
}
throw new ExprEvalException("COALESCE: no value");
diff --git a/jena-benchmarks/jena-benchmarks-jmh/pom.xml
b/jena-benchmarks/jena-benchmarks-jmh/pom.xml
index ff1cc0ea7d..f41c418529 100644
--- a/jena-benchmarks/jena-benchmarks-jmh/pom.xml
+++ b/jena-benchmarks/jena-benchmarks-jmh/pom.xml
@@ -100,6 +100,13 @@
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.jena</groupId>
+ <artifactId>jena-benchmarks-shadedJena550</artifactId>
+ <version>5.6.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
diff --git
a/jena-benchmarks/jena-benchmarks-jmh/src/test/java/org/apache/jena/sparql/expr/TestCoalesce.java
b/jena-benchmarks/jena-benchmarks-jmh/src/test/java/org/apache/jena/sparql/expr/TestCoalesce.java
new file mode 100644
index 0000000000..4bf57be108
--- /dev/null
+++
b/jena-benchmarks/jena-benchmarks-jmh/src/test/java/org/apache/jena/sparql/expr/TestCoalesce.java
@@ -0,0 +1,115 @@
+/*
+ * 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.expr;
+
+
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.mem.graph.helper.JMHDefaultOptions;
+import org.apache.jena.sparql.engine.binding.Binding;
+import org.apache.jena.sparql.function.FunctionEnv;
+import org.apache.jena.sys.JenaSystem;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.runner.Runner;
+
+import java.util.Random;
+
+
+@State(Scope.Benchmark)
+public class TestCoalesce {
+
+ static {
+ JenaSystem.init();
+ org.apache.shadedJena550.sys.JenaSystem.init();
+ }
+
+ final static Random rnd = new Random();
+
+ @Benchmark
+ public Long benchmarkCoalesceJenaCurrent() {
+ var checksum = 0L;
+ // Create a Coalesce expression with some dummy expressions
+ var expressions = new ExprList();
+ expressions.add(new ExprVar("var1"));
+ expressions.add(new ExprVar("var2"));
+ expressions.add(new ExprVar("var3"));
+ expressions.add(new ExprVar("var4"));
+ expressions.add(new ExprVar("var5"));
+
+ var var3BoundLiteral = NodeFactory.createLiteralString("Value5");
+ var bindingBuilder = Binding.builder();
+ bindingBuilder.add(expressions.get(4).asVar(), var3BoundLiteral);
+ var binding = bindingBuilder.build();
+
+ FunctionEnv env = null;
+
+ // Coalesce expression
+ var coalesceExpr = new E_Coalesce(expressions);
+
+ for(var i=0; i<1000000; i++) {
+ var result = coalesceExpr.eval(binding, env);
+ if( result != null ) {
+ checksum += i;
+ }
+ }
+ return checksum;
+ }
+
+ @Benchmark
+ public Long benchmarkCoalesceJena550() {
+ var checksum = 0L;
+ // Create a Coalesce expression with some dummy expressions
+ var expressions = new org.apache.shadedJena550.sparql.expr.ExprList();
+ expressions.add(new
org.apache.shadedJena550.sparql.expr.ExprVar("var1"));
+ expressions.add(new
org.apache.shadedJena550.sparql.expr.ExprVar("var2"));
+ expressions.add(new
org.apache.shadedJena550.sparql.expr.ExprVar("var3"));
+ expressions.add(new
org.apache.shadedJena550.sparql.expr.ExprVar("var4"));
+ expressions.add(new
org.apache.shadedJena550.sparql.expr.ExprVar("var5"));
+
+ var var3BoundLiteral =
org.apache.shadedJena550.graph.NodeFactory.createLiteralString("Value5");
+ var bindingBuilder =
org.apache.shadedJena550.sparql.engine.binding.Binding.builder();
+ bindingBuilder.add(expressions.get(4).asVar(), var3BoundLiteral);
+ var binding = bindingBuilder.build();
+ org.apache.shadedJena550.sparql.function.FunctionEnv env = null;
+
+ // Coalesce expression
+ var coalesceExpr =
+ new
org.apache.shadedJena550.sparql.expr.E_Coalesce(expressions);
+
+ for(var i=0; i<1000000; i++) {
+ var result = coalesceExpr.eval(binding, env);
+ if( result != null ) {
+ checksum += i;
+ }
+ }
+ return checksum;
+ }
+
+ @Test
+ public void benchmark() throws Exception {
+ var opt = JMHDefaultOptions.getDefaults(this.getClass())
+ .build();
+ var results = new Runner(opt).run();
+ Assert.assertNotNull(results);
+ }
+}
diff --git a/jena-benchmarks/jena-benchmarks-shadedJena510/pom.xml
b/jena-benchmarks/jena-benchmarks-shadedJena510/pom.xml
index 8710e03627..c1ddc5bea2 100644
--- a/jena-benchmarks/jena-benchmarks-shadedJena510/pom.xml
+++ b/jena-benchmarks/jena-benchmarks-shadedJena510/pom.xml
@@ -45,7 +45,7 @@
<properties>
<build.time.xsd>${maven.build.timestamp}</build.time.xsd>
-
<automatic.module.name>org.apache.jena.benchmarks.shadedJena480</automatic.module.name>
+
<automatic.module.name>org.apache.jena.benchmarks.shadedJena510</automatic.module.name>
<maven.test.skip>true</maven.test.skip>
<scope>test</scope>
</properties>
diff --git a/jena-benchmarks/jena-benchmarks-shadedJena510/pom.xml
b/jena-benchmarks/jena-benchmarks-shadedJena550/pom.xml
similarity index 89%
copy from jena-benchmarks/jena-benchmarks-shadedJena510/pom.xml
copy to jena-benchmarks/jena-benchmarks-shadedJena550/pom.xml
index 8710e03627..bad8808728 100644
--- a/jena-benchmarks/jena-benchmarks-shadedJena510/pom.xml
+++ b/jena-benchmarks/jena-benchmarks-shadedJena550/pom.xml
@@ -24,9 +24,9 @@
<version>5.6.0-SNAPSHOT</version>
</parent>
- <name>Apache Jena - Benchmarks Shaded Jena 5.1.0</name>
- <artifactId>jena-benchmarks-shadedJena510</artifactId>
- <description>Shaded Apache Jena 5.1.0 for regression
benchmarks</description>
+ <name>Apache Jena - Benchmarks Shaded Jena 5.5.0</name>
+ <artifactId>jena-benchmarks-shadedJena550</artifactId>
+ <description>Shaded Apache Jena 5.5.0 for regression
benchmarks</description>
<packaging>jar</packaging>
<url>https://jena.apache.org/</url>
@@ -45,7 +45,7 @@
<properties>
<build.time.xsd>${maven.build.timestamp}</build.time.xsd>
-
<automatic.module.name>org.apache.jena.benchmarks.shadedJena480</automatic.module.name>
+
<automatic.module.name>org.apache.jena.benchmarks.shadedJena550</automatic.module.name>
<maven.test.skip>true</maven.test.skip>
<scope>test</scope>
</properties>
@@ -54,27 +54,32 @@
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>jena-base</artifactId>
- <version>5.1.0</version>
+ <version>5.5.0</version>
</dependency>
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>jena-iri</artifactId>
- <version>5.1.0</version>
+ <version>5.5.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jena</groupId>
+ <artifactId>jena-iri3986</artifactId>
+ <version>5.5.0</version>
</dependency>
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>jena-core</artifactId>
- <version>5.1.0</version>
+ <version>5.5.0</version>
</dependency>
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>jena-arq</artifactId>
- <version>5.1.0</version>
+ <version>5.5.0</version>
</dependency>
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>jena-geosparql</artifactId>
- <version>5.1.0</version>
+ <version>5.5.0</version>
</dependency>
</dependencies>
@@ -106,7 +111,7 @@
<relocations>
<relocation>
<pattern>org.apache.jena</pattern>
-
<shadedPattern>org.apache.shadedJena510</shadedPattern>
+
<shadedPattern>org.apache.shadedJena550</shadedPattern>
</relocation>
</relocations>
<filters>
diff --git a/jena-benchmarks/pom.xml b/jena-benchmarks/pom.xml
index 7a0094ded1..e44cc884ba 100644
--- a/jena-benchmarks/pom.xml
+++ b/jena-benchmarks/pom.xml
@@ -50,6 +50,7 @@
<module>jena-benchmarks-jmh</module>
<module>jena-benchmarks-shadedJena480</module>
<module>jena-benchmarks-shadedJena510</module>
+ <module>jena-benchmarks-shadedJena550</module>
</modules>
</project>