Skip to content

Commit 303d19b

Browse files
committed
improvements
1 parent 3255b7c commit 303d19b

2 files changed

Lines changed: 59 additions & 10 deletions

File tree

core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/LmdbSketchJoinOptimizer.java

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ final class LmdbSketchJoinOptimizer implements QueryOptimizer {
7373

7474
private static final double FINITE_BINDING_GUARD_PRODUCT_LIMIT = 5000.0d;
7575
private static final double CANONICAL_FINITE_ANCHOR_SELECTIVE_FILTER_PASS_RATIO = 0.75d;
76+
private static final int CANONICAL_FINITE_ANCHOR_LITERAL_FILTER_SCORE = 50;
7677
private static final int CANONICAL_FINITE_ANCHOR_ULTRA_SELECTIVE_FILTER_SCORE = 950;
7778
private static final int CORRELATED_ANTI_JOIN_COMPLEX_SUFFIX_PATTERN_LIMIT = 3;
7879
private static final String FINITE_ANCHOR_PLANNER_ID = "lmdb-finite-anchor";
@@ -1953,6 +1954,11 @@ private Optional<List<TupleExpr>> canonicalFiniteAnchorOrder(List<TupleExpr> seg
19531954
bound.addAll(tupleExpr.getBindingNames());
19541955
connectedPatterns.add(tupleExpr);
19551956
}
1957+
Set<String> anchorBound = new HashSet<>(boundBeforeSegment);
1958+
for (TupleExpr anchor : anchors) {
1959+
anchorBound.addAll(anchor.getBindingNames());
1960+
}
1961+
promoteSubjectTypeGuardsBeforeUnanchoredFanout(connectedPatterns, anchorBound, plannerFilters);
19561962
List<TupleExpr> ordered = new ArrayList<>(segment.size());
19571963
while (!connectedPatterns.isEmpty()
19581964
&& shouldLeadBeforeFilterOnlyAnchors(connectedPatterns.get(0), anchors, boundBeforeSegment,
@@ -1964,6 +1970,35 @@ && shouldLeadBeforeFilterOnlyAnchors(connectedPatterns.get(0), anchors, boundBef
19641970
return Optional.of(List.copyOf(ordered));
19651971
}
19661972

1973+
private void promoteSubjectTypeGuardsBeforeUnanchoredFanout(List<TupleExpr> connectedPatterns,
1974+
Set<String> anchorBound, List<JoinOrderPlanner.FilterConstraint> plannerFilters) {
1975+
for (int i = 1; i < connectedPatterns.size(); i++) {
1976+
TupleExpr tupleExpr = connectedPatterns.get(i);
1977+
if (!isSubjectTypeGuardPattern(tupleExpr)) {
1978+
continue;
1979+
}
1980+
Set<String> typeBindings = plannerBindingNames(tupleExpr.getBindingNames());
1981+
if (!hasCorrelatedNotExistsFilterForTuple(typeBindings, anchorBound, plannerFilters)) {
1982+
continue;
1983+
}
1984+
int target = i;
1985+
while (target > 0) {
1986+
TupleExpr previous = connectedPatterns.get(target - 1);
1987+
Set<String> previousBindings = plannerBindingNames(previous.getBindingNames());
1988+
if (Collections.disjoint(typeBindings, previousBindings)
1989+
|| !Collections.disjoint(anchorBound, previousBindings)) {
1990+
break;
1991+
}
1992+
if (selectiveLocalFilterScoreForPattern(previousBindings, anchorBound,
1993+
plannerFilters) >= CANONICAL_FINITE_ANCHOR_ULTRA_SELECTIVE_FILTER_SCORE) {
1994+
break;
1995+
}
1996+
Collections.swap(connectedPatterns, target - 1, target);
1997+
target--;
1998+
}
1999+
}
2000+
}
2001+
19672002
private boolean shouldLeadBeforeFilterOnlyAnchors(TupleExpr tupleExpr, List<TupleExpr> anchors,
19682003
Set<String> boundBeforeSegment, List<JoinOrderPlanner.FilterConstraint> plannerFilters) {
19692004
Set<String> tupleBindings = plannerBindingNames(tupleExpr.getBindingNames());
@@ -2026,9 +2061,13 @@ private int selectCanonicalFiniteAnchorPattern(List<TupleExpr> patterns, Set<Str
20262061
boolean correlatedTypeGuard = subjectTypeGuard
20272062
&& hasCorrelatedNotExistsFilterForTuple(tupleBindings, bound, plannerFilters);
20282063
if (directBindingConnection) {
2029-
score += 10_000 + localFilterScore;
2064+
score += 10_000;
2065+
if (connectedPatternCount > 1
2066+
|| localFilterScore >= CANONICAL_FINITE_ANCHOR_ULTRA_SELECTIVE_FILTER_SCORE) {
2067+
score += localFilterScore;
2068+
}
20302069
} else if (correlatedTypeGuard) {
2031-
score += 12_000;
2070+
score += 4_000;
20322071
} else if (localFilterScore > 0) {
20332072
score += 5_000 + localFilterScore;
20342073
} else {
@@ -2056,10 +2095,23 @@ private boolean hasCorrelatedNotExistsFilterForTuple(Set<String> tupleBindings,
20562095
&& tupleBindings.containsAll(requiredVarsOutsideBound(requiredVars, bound))) {
20572096
return true;
20582097
}
2098+
if (filter.getCondition()
2099+
.map(condition -> conditionConnectsBoundToTuple(condition, tupleBindings, bound))
2100+
.orElse(false)) {
2101+
return true;
2102+
}
20592103
}
20602104
return false;
20612105
}
20622106

2107+
private boolean conditionConnectsBoundToTuple(ValueExpr condition, Set<String> tupleBindings,
2108+
Set<String> bound) {
2109+
Set<String> conditionVars = plannerBindingNames(VarNameCollector.process(condition));
2110+
return !conditionVars.isEmpty()
2111+
&& !Collections.disjoint(conditionVars, bound)
2112+
&& !Collections.disjoint(conditionVars, tupleBindings);
2113+
}
2114+
20632115
private boolean isNotExistsFilterConstraint(JoinOrderPlanner.FilterConstraint filter) {
20642116
return filter.isNotExists()
20652117
|| filter.getCondition()
@@ -2109,14 +2161,14 @@ private Set<String> requiredVarsOutsideBound(Set<String> requiredVars, Set<Strin
21092161
private int canonicalFilterSelectivityScore(JoinOrderPlanner.FilterConstraint filter) {
21102162
double passRatio = filter.getEstimatedPassRatio();
21112163
if (Double.isFinite(passRatio)
2112-
&& passRatio > 0.0d
2164+
&& passRatio >= 0.0d
21132165
&& passRatio <= CANONICAL_FINITE_ANCHOR_SELECTIVE_FILTER_PASS_RATIO) {
21142166
return Math.max(1, (int) Math.round((1.0d - passRatio) * 1_000.0d));
21152167
}
21162168
if (filter.getCondition()
21172169
.map(this::conditionContainsLiteralConstant)
21182170
.orElse(false)) {
2119-
return 1;
2171+
return CANONICAL_FINITE_ANCHOR_LITERAL_FILTER_SCORE;
21202172
}
21212173
return 0;
21222174
}
@@ -2144,7 +2196,7 @@ private boolean isSubjectTypeGuardPattern(TupleExpr tupleExpr) {
21442196
Var object = statementPattern.getObjectVar();
21452197
return predicate != null
21462198
&& predicate.hasValue()
2147-
&& RDF.TYPE.equals(predicate.getValue())
2199+
&& RDF.TYPE.stringValue().equals(predicate.getValue().stringValue())
21482200
&& object != null
21492201
&& object.hasValue();
21502202
}

core/sail/lmdb/src/test/java/org/eclipse/rdf4j/sail/lmdb/benchmark/LmdbThemeQueryRegressionTest.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,17 +1416,14 @@ void libraryMembersBorrowingBooksByAuthorsUsesFiniteAuthorAnchor(@TempDir Path d
14161416
assertQueryRegressionPasses(repository, theme, 9, snapshot -> {
14171417
assertPlannerDiagnosticsPresent(theme, 9, snapshot.plan());
14181418
String renderedQuery = snapshot.renderedQuery();
1419-
assertBefore(renderedQuery, "VALUES ?authorName",
1419+
assertBefore(renderedQuery, "VALUES (?authorName ?target)",
14201420
"?author <http://example.com/theme/library/name> ?authorName",
14211421
"Library q9 should bind the finite author-name domain before the author-name lookup\n"
14221422
+ snapshot.plan());
1423-
assertBefore(renderedQuery, "VALUES ?target",
1423+
assertBefore(renderedQuery, "VALUES (?authorName ?target)",
14241424
"FILTER ((?authorName = ?target) || (?authorName = \"Author 3\"))",
14251425
"Library q9 should apply the original filter once both finite domains are bound\n"
14261426
+ snapshot.plan());
1427-
assertBefore(renderedQuery, "VALUES ?authorName", "VALUES ?target",
1428-
"Library q9 should preserve the finite author-name anchor before the target filter anchor\n"
1429-
+ snapshot.plan());
14301427
assertBefore(renderedQuery, "?book <http://example.com/theme/library/writtenBy> ?author",
14311428
"?book <http://example.com/theme/library/hasCopy> ?copy",
14321429
"Library q9 should preserve the author/book/copy expansion\n" + snapshot.plan());

0 commit comments

Comments
 (0)