From d793520f2b7fefcad15968eb702e3a460cd7b6ed Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Fri, 31 Oct 2025 11:57:55 +0100 Subject: [PATCH 01/10] First steps in improving performance. --- .../reasoner/api/TripleVarBindingSet.java | 19 ++++++++++++------- .../reasoner/rulenode/BindingSetStore.java | 11 +++++++---- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java index 101c9ec23..c4734832c 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java @@ -28,13 +28,18 @@ public class TripleVarBindingSet { public TripleVarBindingSet(Set aGraphPattern) { + this(aGraphPattern, 16); + } + + public TripleVarBindingSet(Set aGraphPattern, int initialCapacity) { + this.graphPattern = aGraphPattern; - bindings = ConcurrentHashMap.newKeySet(); + bindings = ConcurrentHashMap.newKeySet(initialCapacity); } public TripleVarBindingSet(Set aGraphPattern, BindingSet aBindingSet) { - this(aGraphPattern); + this(aGraphPattern, aBindingSet.size()); for (Binding b : aBindingSet) { this.add(new TripleVarBinding(this.graphPattern, b)); @@ -187,13 +192,12 @@ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { LOG.trace("Merging {} bindings with our {} bindings.", aBindingSet.getBindings().size(), this.getBindings().size()); - TripleVarBindingSet gbs = new TripleVarBindingSet(this.graphPattern); - final int otherBindingSetSize = aBindingSet.getBindings().size(); final long totalCount = (long) otherBindingSetSize * (long) this.getBindings().size(); if (totalCount > LARGE_BS_SIZE) LOG.warn("Merging 2 large BindingSets ({} * {} = {}). This can take some time.", aBindingSet.getBindings().size(), this.getBindings().size(), totalCount); + TripleVarBindingSet gbs = new TripleVarBindingSet(this.graphPattern, (int) totalCount); if (this.bindings.isEmpty()) { gbs.addAll(aBindingSet.getBindings()); @@ -204,7 +208,8 @@ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { final int milestoneSize = PROGRESS_MILESTONE_SIZE; AtomicLong nextMilestone = new AtomicLong(milestoneSize); - this.bindings.stream().parallel().forEach(tvb1 -> { +// this.bindings.stream().forEach(tvb1 -> { + for (var tvb1 : this.bindings) { for (TripleVarBinding otherB : aBindingSet.getBindings()) { // always add a merged version of the two bindings, except when they conflict. if (!tvb1.isConflicting(otherB)) { @@ -217,11 +222,11 @@ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { LOG.trace("{}/{} BindingSet merge tasks done!", current * otherBindingSetSize, totalCount); nextMilestone.set(current + milestoneSize); } - }); + } } if (totalCount > LARGE_BS_SIZE) - LOG.debug("Merging large BindingSets done!"); + LOG.trace("Merging large BindingSets done!"); return gbs; } diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java index ceaa76b1b..640e1e163 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicLong; import java.util.Set; import java.util.stream.Collectors; @@ -108,11 +109,13 @@ private TripleVarBindingSet translateWithCombiMatches(Set aGraphP Set someCombiMatches, Map> someNeighborBS) { var combinedTVBS = new TripleVarBindingSet(aGraphPattern); - int i = 0; + AtomicLong i = new AtomicLong(0); int size = someCombiMatches.size(); + +// someCombiMatches.stream().forEach(cMatch -> { for (CombiMatch cMatch : someCombiMatches) { - i = i + 1; - LOG.trace("Creating binding set for combi match: {}/{}", i, size); + i.incrementAndGet(); + LOG.debug("Creating binding set for combi match: {}/{}", i.get(), size); // keep separate binding set per combi match var cMatchTVBS = new TripleVarBindingSet(aGraphPattern); @@ -128,7 +131,7 @@ private TripleVarBindingSet translateWithCombiMatches(Set aGraphP TripleVarBindingSet tvbs = matchToBS.get(cSingleMatch); if (tvbs != null) - cMatchTVBS.addAll(cMatchTVBS.combine(tvbs).getBindings()); + cMatchTVBS = cMatchTVBS.combine(tvbs); } } } From f7b181d618a04231a646205082324017bd2152af Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Mon, 3 Nov 2025 11:16:31 +0100 Subject: [PATCH 02/10] Try out improved conflict detection. --- .../engine/reasoner/api/TripleVarBinding.java | 23 +++++++++++++++++++ .../reasoner/api/TripleVarBindingSet.java | 11 ++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java index 0abd8e9ae..215ae5b00 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java @@ -125,6 +125,25 @@ public boolean isConflicting(TripleVarBinding tvb) { return false; } + /** + * True if two Bindings have a different value for at least one variable. Note + * that it looks not at variable instances. + */ + public boolean isConflicting2(TripleVarBinding tvb, Set overlappingVars) { + + Node l, val; + for (Var e : overlappingVars) { + l = tvb.getVarValue(e); + + val = this.getVarValue(e); + + if (!val.equals(l)) { + return true; + } + } + return false; + } + /** * We assume all occurrences of a var have the same literal, we just return the * first one found. @@ -253,4 +272,8 @@ public boolean containsTriplePattern(TriplePattern value) { return false; } + public Set getVars() { + return this.variableTripleVarMapping.keySet(); + } + } diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java index c4734832c..b6be57d79 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java @@ -189,6 +189,15 @@ public TripleVarBindingSet merge(TripleVarBindingSet aBindingSet) { */ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { + Set overlappingVars = new HashSet(); + if (this.bindings.size() > 0 && aBindingSet.getBindings().size() > 0) { + Set vars1 = this.bindings.iterator().next().getVars(); + Set vars2 = aBindingSet.getBindings().iterator().next().getVars(); + overlappingVars.addAll(vars1); + overlappingVars.retainAll(vars2); +// LOG.debug("Overlapping vars found: {} - {} = {}", vars1, vars2, overlappingVars); + } + LOG.trace("Merging {} bindings with our {} bindings.", aBindingSet.getBindings().size(), this.getBindings().size()); @@ -212,7 +221,7 @@ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { for (var tvb1 : this.bindings) { for (TripleVarBinding otherB : aBindingSet.getBindings()) { // always add a merged version of the two bindings, except when they conflict. - if (!tvb1.isConflicting(otherB)) { + if (!tvb1.isConflicting2(otherB, overlappingVars)) { gbs.add(tvb1.merge(otherB)); } } From 21b99b16b825386d433d548f89fc17e5aaab8508 Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Fri, 31 Oct 2025 11:57:55 +0100 Subject: [PATCH 03/10] First steps in improving performance. --- .../reasoner/api/TripleVarBindingSet.java | 19 ++++++++++++------- .../reasoner/rulenode/BindingSetStore.java | 11 +++++++---- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java index f671d6a43..58c3cc9a5 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java @@ -28,13 +28,18 @@ public class TripleVarBindingSet { public TripleVarBindingSet(Set aGraphPattern) { + this(aGraphPattern, 16); + } + + public TripleVarBindingSet(Set aGraphPattern, int initialCapacity) { + this.graphPattern = aGraphPattern; - bindings = ConcurrentHashMap.newKeySet(); + bindings = ConcurrentHashMap.newKeySet(initialCapacity); } public TripleVarBindingSet(Set aGraphPattern, BindingSet aBindingSet) { - this(aGraphPattern); + this(aGraphPattern, aBindingSet.size()); for (Binding b : aBindingSet) { this.add(new TripleVarBinding(this.graphPattern, b)); @@ -187,13 +192,12 @@ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { LOG.trace("Merging {} bindings with our {} bindings.", aBindingSet.getBindings().size(), this.getBindings().size()); - TripleVarBindingSet gbs = new TripleVarBindingSet(this.graphPattern); - final int otherBindingSetSize = aBindingSet.getBindings().size(); final long totalCount = (long) otherBindingSetSize * (long) this.getBindings().size(); if (totalCount > LARGE_BS_SIZE) LOG.warn("Merging 2 large BindingSets ({} * {} = {}). This can take some time.", aBindingSet.getBindings().size(), this.getBindings().size(), totalCount); + TripleVarBindingSet gbs = new TripleVarBindingSet(this.graphPattern, (int) totalCount); if (this.bindings.isEmpty()) { gbs.addAll(aBindingSet.getBindings()); @@ -204,7 +208,8 @@ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { final int milestoneSize = PROGRESS_MILESTONE_SIZE; AtomicLong nextMilestone = new AtomicLong(milestoneSize); - this.bindings.stream().parallel().forEach(tvb1 -> { +// this.bindings.stream().forEach(tvb1 -> { + for (var tvb1 : this.bindings) { for (TripleVarBinding otherB : aBindingSet.getBindings()) { // always add a merged version of the two bindings, except when they conflict. if (!tvb1.isConflicting(otherB)) { @@ -217,11 +222,11 @@ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { LOG.trace("{}/{} BindingSet merge tasks done!", current * otherBindingSetSize, totalCount); nextMilestone.set(current + milestoneSize); } - }); + } } if (totalCount > LARGE_BS_SIZE) - LOG.debug("Merging large BindingSets done!"); + LOG.trace("Merging large BindingSets done!"); return gbs; } diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java index ceaa76b1b..640e1e163 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicLong; import java.util.Set; import java.util.stream.Collectors; @@ -108,11 +109,13 @@ private TripleVarBindingSet translateWithCombiMatches(Set aGraphP Set someCombiMatches, Map> someNeighborBS) { var combinedTVBS = new TripleVarBindingSet(aGraphPattern); - int i = 0; + AtomicLong i = new AtomicLong(0); int size = someCombiMatches.size(); + +// someCombiMatches.stream().forEach(cMatch -> { for (CombiMatch cMatch : someCombiMatches) { - i = i + 1; - LOG.trace("Creating binding set for combi match: {}/{}", i, size); + i.incrementAndGet(); + LOG.debug("Creating binding set for combi match: {}/{}", i.get(), size); // keep separate binding set per combi match var cMatchTVBS = new TripleVarBindingSet(aGraphPattern); @@ -128,7 +131,7 @@ private TripleVarBindingSet translateWithCombiMatches(Set aGraphP TripleVarBindingSet tvbs = matchToBS.get(cSingleMatch); if (tvbs != null) - cMatchTVBS.addAll(cMatchTVBS.combine(tvbs).getBindings()); + cMatchTVBS = cMatchTVBS.combine(tvbs); } } } From 12a345a9913431a80c6dee62d8fd37022f922497 Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Mon, 3 Nov 2025 11:16:31 +0100 Subject: [PATCH 04/10] Try out improved conflict detection. --- .../engine/reasoner/api/TripleVarBinding.java | 23 +++++++++++++++++++ .../reasoner/api/TripleVarBindingSet.java | 11 ++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java index f6d03c9ff..3da8c3efd 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java @@ -125,6 +125,25 @@ public boolean isConflicting(TripleVarBinding tvb) { return false; } + /** + * True if two Bindings have a different value for at least one variable. Note + * that it looks not at variable instances. + */ + public boolean isConflicting2(TripleVarBinding tvb, Set overlappingVars) { + + Node l, val; + for (Var e : overlappingVars) { + l = tvb.getVarValue(e); + + val = this.getVarValue(e); + + if (!val.equals(l)) { + return true; + } + } + return false; + } + /** * We assume all occurrences of a var have the same literal, we just return the * first one found. @@ -253,4 +272,8 @@ public boolean containsTriplePattern(TriplePattern value) { return false; } + public Set getVars() { + return this.variableTripleVarMapping.keySet(); + } + } diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java index 58c3cc9a5..0695494ba 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java @@ -189,6 +189,15 @@ public TripleVarBindingSet merge(TripleVarBindingSet aBindingSet) { */ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { + Set overlappingVars = new HashSet(); + if (this.bindings.size() > 0 && aBindingSet.getBindings().size() > 0) { + Set vars1 = this.bindings.iterator().next().getVars(); + Set vars2 = aBindingSet.getBindings().iterator().next().getVars(); + overlappingVars.addAll(vars1); + overlappingVars.retainAll(vars2); +// LOG.debug("Overlapping vars found: {} - {} = {}", vars1, vars2, overlappingVars); + } + LOG.trace("Merging {} bindings with our {} bindings.", aBindingSet.getBindings().size(), this.getBindings().size()); @@ -212,7 +221,7 @@ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { for (var tvb1 : this.bindings) { for (TripleVarBinding otherB : aBindingSet.getBindings()) { // always add a merged version of the two bindings, except when they conflict. - if (!tvb1.isConflicting(otherB)) { + if (!tvb1.isConflicting2(otherB, overlappingVars)) { gbs.add(tvb1.merge(otherB)); } } From 85786dce6c8545f4fbdc48a61659944cac3116e6 Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Fri, 10 Apr 2026 10:35:39 +0200 Subject: [PATCH 05/10] Merge branch 'improve-binding-set-merge' of https://github.com/TNO/knowledge-engine.git into improve-binding-set-merge --- .../engine/reasoner/api/TripleVarBinding.java | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java index 69f89dff6..3da8c3efd 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java @@ -144,25 +144,6 @@ public boolean isConflicting2(TripleVarBinding tvb, Set overlappingVars) { return false; } - /** - * True if two Bindings have a different value for at least one variable. Note - * that it looks not at variable instances. - */ - public boolean isConflicting2(TripleVarBinding tvb, Set overlappingVars) { - - Node l, val; - for (Var e : overlappingVars) { - l = tvb.getVarValue(e); - - val = this.getVarValue(e); - - if (!val.equals(l)) { - return true; - } - } - return false; - } - /** * We assume all occurrences of a var have the same literal, we just return the * first one found. From 3b82ed3163d3767301737d031bab322e4ab9d16d Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Fri, 10 Apr 2026 11:41:38 +0200 Subject: [PATCH 06/10] Combined improvements from master and this branch. Ready to merge if all tests succeed. --- .../engine/reasoner/api/TripleVarBinding.java | 2 +- .../reasoner/api/TripleVarBindingSet.java | 24 +++++++++---------- .../reasoner/rulenode/BindingSetStore.java | 13 +++++----- .../api/TestAskAnswerLargeBindingSets.java | 2 +- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java index 3da8c3efd..68fd260be 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java @@ -137,7 +137,7 @@ public boolean isConflicting2(TripleVarBinding tvb, Set overlappingVars) { val = this.getVarValue(e); - if (!val.equals(l)) { + if (!val.sameValueAs(l)) { return true; } } diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java index 0695494ba..2576d7b63 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java @@ -189,15 +189,6 @@ public TripleVarBindingSet merge(TripleVarBindingSet aBindingSet) { */ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { - Set overlappingVars = new HashSet(); - if (this.bindings.size() > 0 && aBindingSet.getBindings().size() > 0) { - Set vars1 = this.bindings.iterator().next().getVars(); - Set vars2 = aBindingSet.getBindings().iterator().next().getVars(); - overlappingVars.addAll(vars1); - overlappingVars.retainAll(vars2); -// LOG.debug("Overlapping vars found: {} - {} = {}", vars1, vars2, overlappingVars); - } - LOG.trace("Merging {} bindings with our {} bindings.", aBindingSet.getBindings().size(), this.getBindings().size()); @@ -211,14 +202,23 @@ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { if (this.bindings.isEmpty()) { gbs.addAll(aBindingSet.getBindings()); } else { + + Set overlappingVars = new HashSet(); + if (this.bindings.size() > 0 && aBindingSet.getBindings().size() > 0) { + Set vars1 = this.bindings.iterator().next().getVars(); + Set vars2 = aBindingSet.getBindings().iterator().next().getVars(); + overlappingVars.addAll(vars1); + overlappingVars.retainAll(vars2); + LOG.trace("Overlapping vars found: {} - {} = {}", vars1, vars2, overlappingVars); + } + // Cartesian product is the base case AtomicLong progress = new AtomicLong(0); final int milestoneSize = PROGRESS_MILESTONE_SIZE; AtomicLong nextMilestone = new AtomicLong(milestoneSize); -// this.bindings.stream().forEach(tvb1 -> { - for (var tvb1 : this.bindings) { + this.bindings.stream().parallel().forEach(tvb1 -> { for (TripleVarBinding otherB : aBindingSet.getBindings()) { // always add a merged version of the two bindings, except when they conflict. if (!tvb1.isConflicting2(otherB, overlappingVars)) { @@ -231,7 +231,7 @@ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { LOG.trace("{}/{} BindingSet merge tasks done!", current * otherBindingSetSize, totalCount); nextMilestone.set(current + milestoneSize); } - } + }); } if (totalCount > LARGE_BS_SIZE) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java index 640e1e163..b03a6bf2b 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java @@ -93,7 +93,7 @@ public boolean haveAllNeighborsContributedExcept(Set nodes) { } /** - * Translates the given TripleVarBindingSets from neighbors to a single + * Combine the given TripleVarBindingSets from neighbors to a single * TripleVarBindingSet using the given combi matches. Because the combi matches * are very specific to how they should be formed, using this information should * speed up the binding set merging process considerably. @@ -105,17 +105,16 @@ public boolean haveAllNeighborsContributedExcept(Set nodes) { * @return A TripleVarBindingSet that consists of only valid (according to the * combimatches) bindings. */ - private TripleVarBindingSet translateWithCombiMatches(Set aGraphPattern, + private TripleVarBindingSet combineWithCombiMatches(Set aGraphPattern, Set someCombiMatches, Map> someNeighborBS) { var combinedTVBS = new TripleVarBindingSet(aGraphPattern); AtomicLong i = new AtomicLong(0); int size = someCombiMatches.size(); -// someCombiMatches.stream().forEach(cMatch -> { - for (CombiMatch cMatch : someCombiMatches) { + someCombiMatches.stream().forEach(cMatch -> { i.incrementAndGet(); - LOG.debug("Creating binding set for combi match: {}/{}", i.get(), size); + LOG.trace("Creating binding set for combi match: {}/{}", i.get(), size); // keep separate binding set per combi match var cMatchTVBS = new TripleVarBindingSet(aGraphPattern); @@ -139,7 +138,7 @@ private TripleVarBindingSet translateWithCombiMatches(Set aGraphP // addAll instead of merge, because different combi matches do not need to be // combined. combinedTVBS.addAll(cMatchTVBS.getBindings()); - } + }); return combinedTVBS; @@ -170,7 +169,7 @@ public TripleVarBindingSet get() { // at the consequent/antecedent neighbors depending on backward/forward // reasoning) we use the older (slower) method when there are no combi matches. if (this.combiMatches != null) - this.cache = this.translateWithCombiMatches(this.graphPattern, this.combiMatches, this.neighborBindingSet); + this.cache = this.combineWithCombiMatches(this.graphPattern, this.combiMatches, this.neighborBindingSet); else { LOG.trace("Ignoring combi matches for binding set construction."); TripleVarBindingSet combinedBS = new TripleVarBindingSet(graphPattern); diff --git a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestAskAnswerLargeBindingSets.java b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestAskAnswerLargeBindingSets.java index e6621f139..82f25b7c2 100644 --- a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestAskAnswerLargeBindingSets.java +++ b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestAskAnswerLargeBindingSets.java @@ -37,7 +37,7 @@ public class TestAskAnswerLargeBindingSets { private static BindingSet kb2BS; private static KnowledgeNetwork kn; - private static int NR_OF_BINDINGS = 1500; + private static int NR_OF_BINDINGS = 2500; private static char[] chars = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }; From 1c63b646b58dff9b081cbf1e7e58530951d0c1ea Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Fri, 10 Apr 2026 11:49:58 +0200 Subject: [PATCH 07/10] Fix null pointer errors in isConflicting2(...) --- .../java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java index 68fd260be..18c5f6f8a 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBinding.java @@ -137,7 +137,7 @@ public boolean isConflicting2(TripleVarBinding tvb, Set overlappingVars) { val = this.getVarValue(e); - if (!val.sameValueAs(l)) { + if (val != null && l != null && !val.sameValueAs(l)) { return true; } } From 33691e4992d98e1e06963d422ddd22a52fd493c1 Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Fri, 10 Apr 2026 12:20:34 +0200 Subject: [PATCH 08/10] Improve overlapping vars calculations --- .../engine/reasoner/api/TripleVarBindingSet.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java index 2576d7b63..90f4700fe 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/api/TripleVarBindingSet.java @@ -23,6 +23,7 @@ public class TripleVarBindingSet { private Set graphPattern; private Set bindings; private Set tripleVarsCache; + private Set varsCache; private static final Logger LOG = LoggerFactory.getLogger(TripleVarBindingSet.class); @@ -176,6 +177,15 @@ public TripleVarBindingSet merge(TripleVarBindingSet aBindingSet) { return gbs; } + public Set getVariables() { + if (this.varsCache == null) { + this.varsCache = new HashSet(); + for (TriplePattern tp : this.graphPattern) + this.varsCache.addAll(tp.getVariables()); + } + return this.varsCache; + } + /** * Special merge that only combines the current bindings with the given * bindings. It only adds bindings that are a combination of two input bindings @@ -205,8 +215,8 @@ public TripleVarBindingSet combine(TripleVarBindingSet aBindingSet) { Set overlappingVars = new HashSet(); if (this.bindings.size() > 0 && aBindingSet.getBindings().size() > 0) { - Set vars1 = this.bindings.iterator().next().getVars(); - Set vars2 = aBindingSet.getBindings().iterator().next().getVars(); + Set vars1 = this.getVariables(); + Set vars2 = aBindingSet.getVariables(); overlappingVars.addAll(vars1); overlappingVars.retainAll(vars2); LOG.trace("Overlapping vars found: {} - {} = {}", vars1, vars2, overlappingVars); From 7be136ed349b0550038137f242ebbcf200010e13 Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Fri, 10 Apr 2026 12:58:22 +0200 Subject: [PATCH 09/10] Reduce nr of bindings to reduce duration. --- .../smartconnector/api/TestAskAnswerLargeBindingSets.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestAskAnswerLargeBindingSets.java b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestAskAnswerLargeBindingSets.java index 82f25b7c2..06b14bb13 100644 --- a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestAskAnswerLargeBindingSets.java +++ b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestAskAnswerLargeBindingSets.java @@ -37,7 +37,7 @@ public class TestAskAnswerLargeBindingSets { private static BindingSet kb2BS; private static KnowledgeNetwork kn; - private static int NR_OF_BINDINGS = 2500; + private static int NR_OF_BINDINGS = 2000; private static char[] chars = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }; From ac7582b96fd1b77a112fab94c416865d1046d7ea Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Fri, 10 Apr 2026 13:36:09 +0200 Subject: [PATCH 10/10] Reduce nr of bindings even more. GitHub actions are slow and do not finish before 10s. --- .../smartconnector/api/TestAskAnswerLargeBindingSets.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestAskAnswerLargeBindingSets.java b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestAskAnswerLargeBindingSets.java index 06b14bb13..e6621f139 100644 --- a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestAskAnswerLargeBindingSets.java +++ b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestAskAnswerLargeBindingSets.java @@ -37,7 +37,7 @@ public class TestAskAnswerLargeBindingSets { private static BindingSet kb2BS; private static KnowledgeNetwork kn; - private static int NR_OF_BINDINGS = 2000; + private static int NR_OF_BINDINGS = 1500; private static char[] chars = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };