Skip to content

Commit c010e4b

Browse files
committed
continue
1 parent c06f66c commit c010e4b

2 files changed

Lines changed: 105 additions & 23 deletions

File tree

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

Lines changed: 83 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ TupleExpr buildSegmentRoot(Deque<TupleExpr> orderedArgs, List<DeferredFilter> fi
5959
prefixBindingNames.addAll(optimized.getBindingNames());
6060
}
6161
List<DeferredFilter> unresolvedFilters = new ArrayList<>();
62-
for (DeferredFilter filter : LmdbJoinPlanSupport.sortDeferredFilters(pendingFilters)) {
62+
List<DeferredFilter> sortedFilters = LmdbJoinPlanSupport.sortDeferredFilters(pendingFilters);
63+
while (!sortedFilters.isEmpty()) {
64+
int filterIndex = nextDeferredFilterIndex(factors, sortedFilters, boundBeforeSegment);
65+
DeferredFilter filter = sortedFilters.remove(filterIndex);
6366
if (!groupDeferredFilterOnSmallestWindow(factors, filter, boundBeforeSegment)) {
6467
unresolvedFilters.add(filter);
6568
}
@@ -76,6 +79,45 @@ TupleExpr buildSegmentRoot(Deque<TupleExpr> orderedArgs, List<DeferredFilter> fi
7679
return root;
7780
}
7881

82+
private int nextDeferredFilterIndex(List<SegmentFactor> factors, List<DeferredFilter> sortedFilters,
83+
Set<String> boundBeforeSegment) {
84+
int bestIndex = -1;
85+
BindingAssignmentWindow bestWindow = null;
86+
for (int i = 0; i < sortedFilters.size(); i++) {
87+
DeferredFilter filter = sortedFilters.get(i);
88+
if (LmdbJoinPlanSupport.containsExists(filter.condition)) {
89+
continue;
90+
}
91+
BindingAssignmentWindow window = bindingAssignmentCoveringWindow(factors, filter, boundBeforeSegment);
92+
if (window == null) {
93+
continue;
94+
}
95+
if (bestWindow == null || compareBindingAssignmentWindow(window, filter, bestWindow,
96+
sortedFilters.get(bestIndex)) < 0) {
97+
bestIndex = i;
98+
bestWindow = window;
99+
}
100+
}
101+
return bestIndex < 0 ? 0 : bestIndex;
102+
}
103+
104+
private int compareBindingAssignmentWindow(BindingAssignmentWindow left, DeferredFilter leftFilter,
105+
BindingAssignmentWindow right, DeferredFilter rightFilter) {
106+
int endComparison = Integer.compare(left.endIndex, right.endIndex);
107+
if (endComparison != 0) {
108+
return endComparison;
109+
}
110+
int spanComparison = Integer.compare(left.endIndex - left.startIndex, right.endIndex - right.startIndex);
111+
if (spanComparison != 0) {
112+
return spanComparison;
113+
}
114+
int costComparison = Integer.compare(leftFilter.conditionCost, rightFilter.conditionCost);
115+
if (costComparison != 0) {
116+
return costComparison;
117+
}
118+
return Integer.compare(leftFilter.originalIndex, rightFilter.originalIndex);
119+
}
120+
79121
private TupleExpr applyPrefixBindingDeferredFilters(TupleExpr tupleExpr,
80122
List<DeferredFilter> deferredFilters, Set<String> prefixBindingNames,
81123
Set<StatementPattern> currentPatterns, Set<StatementPattern> remainingPatterns) {
@@ -201,10 +243,35 @@ private int[] smallestSinglePatternBindingCoveringWindow(List<SegmentFactor> fac
201243

202244
private boolean groupDeferredFilterOnBindingAssignments(List<SegmentFactor> factors,
203245
DeferredFilter deferredFilter, Set<String> boundBeforeSegment) {
246+
BindingAssignmentWindow window = bindingAssignmentCoveringWindow(factors, deferredFilter, boundBeforeSegment);
247+
if (window == null) {
248+
return false;
249+
}
250+
251+
Deque<TupleExpr> selectedRoots = new ArrayDeque<>(window.selectedIndexes.size());
252+
Set<StatementPattern> containedPatterns = LmdbJoinPlanSupport.identityPatternSet();
253+
for (Integer selectedIndex : window.selectedIndexes) {
254+
SegmentFactor factor = factors.get(selectedIndex);
255+
selectedRoots.addLast(factor.tupleExpr);
256+
containedPatterns.addAll(factor.containedPatterns);
257+
}
258+
TupleExpr filteredRoot = filterWrapper.wrap(buildJoinRoot(selectedRoots), List.of(deferredFilter),
259+
"bindingAssignments");
260+
SegmentFactor groupedFactor = new SegmentFactor(filteredRoot, containedPatterns);
261+
int insertionIndex = window.startIndex;
262+
for (int i = window.selectedIndexes.size() - 1; i >= 0; i--) {
263+
factors.remove((int) window.selectedIndexes.get(i));
264+
}
265+
factors.add(insertionIndex, groupedFactor);
266+
return true;
267+
}
268+
269+
private BindingAssignmentWindow bindingAssignmentCoveringWindow(List<SegmentFactor> factors,
270+
DeferredFilter deferredFilter, Set<String> boundBeforeSegment) {
204271
Set<String> missingVars = new HashSet<>(deferredFilter.requiredVars);
205272
missingVars.removeAll(boundBeforeSegment);
206273
if (missingVars.isEmpty()) {
207-
return false;
274+
return null;
208275
}
209276

210277
List<Integer> selectedIndexes = new ArrayList<>();
@@ -217,29 +284,10 @@ private boolean groupDeferredFilterOnBindingAssignments(List<SegmentFactor> fact
217284
selectedIndexes.add(i);
218285
missingVars.removeAll(factor.bindingNames);
219286
if (missingVars.isEmpty()) {
220-
break;
287+
return new BindingAssignmentWindow(selectedIndexes);
221288
}
222289
}
223-
if (!missingVars.isEmpty() || selectedIndexes.isEmpty()) {
224-
return false;
225-
}
226-
227-
Deque<TupleExpr> selectedRoots = new ArrayDeque<>(selectedIndexes.size());
228-
Set<StatementPattern> containedPatterns = LmdbJoinPlanSupport.identityPatternSet();
229-
for (Integer selectedIndex : selectedIndexes) {
230-
SegmentFactor factor = factors.get(selectedIndex);
231-
selectedRoots.addLast(factor.tupleExpr);
232-
containedPatterns.addAll(factor.containedPatterns);
233-
}
234-
TupleExpr filteredRoot = filterWrapper.wrap(buildJoinRoot(selectedRoots), List.of(deferredFilter),
235-
"bindingAssignments");
236-
SegmentFactor groupedFactor = new SegmentFactor(filteredRoot, containedPatterns);
237-
int insertionIndex = selectedIndexes.get(0);
238-
for (int i = selectedIndexes.size() - 1; i >= 0; i--) {
239-
factors.remove((int) selectedIndexes.get(i));
240-
}
241-
factors.add(insertionIndex, groupedFactor);
242-
return true;
290+
return null;
243291
}
244292

245293
private boolean groupDeferredFilterOnWindow(List<SegmentFactor> factors, DeferredFilter filter, int[] window) {
@@ -322,4 +370,16 @@ private TupleExpr buildJoinRoot(Deque<TupleExpr> orderedArgs) {
322370
}
323371
return root;
324372
}
373+
374+
private static final class BindingAssignmentWindow {
375+
private final List<Integer> selectedIndexes;
376+
private final int startIndex;
377+
private final int endIndex;
378+
379+
private BindingAssignmentWindow(List<Integer> selectedIndexes) {
380+
this.selectedIndexes = selectedIndexes;
381+
this.startIndex = selectedIndexes.get(0);
382+
this.endIndex = selectedIndexes.get(selectedIndexes.size() - 1);
383+
}
384+
}
325385
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,28 @@ void socialMediaCliqueValuesDirectLookupWorkRowsAreCheap(@TempDir Path dataDir)
178178
}
179179
}
180180

181+
@Test
182+
void socialMediaFiveCycleKeepsFastestKnownValuesCascade(@TempDir Path dataDir) throws Exception {
183+
Theme theme = Theme.SOCIAL_MEDIA;
184+
Path themeDir = prepareThemeStore(dataDir, theme);
185+
try {
186+
LmdbStore store = new LmdbStore(themeDir.toFile(), ConfigUtil.createConfig());
187+
SailRepository repository = new SailRepository(store);
188+
try {
189+
OptimizerSnapshot snapshot = explainOptimized(repository, theme, 10);
190+
assertContains(snapshot.renderedQuery(), "VALUES (?a ?b)");
191+
assertDoesNotContain(snapshot.renderedQuery(), "VALUES (?d ?e)",
192+
"Social media q10 should not pair d/e before the c/d inequality can prune d");
193+
assertBefore(snapshot.renderedQuery(), "FILTER (?c != ?d)", "VALUES ?e",
194+
"Social media q10 should prune d from the c binding before expanding e\n" + snapshot.plan());
195+
} finally {
196+
shutdownAndRelease(repository, store);
197+
}
198+
} finally {
199+
BenchmarkJoinEstimatorSupport.deleteStoreDirectory(themeDir);
200+
}
201+
}
202+
181203
@Test
182204
void libraryAuthorsByNameDoesNotReuseConditionedLearnedPatternStats(@TempDir Path dataDir) throws Exception {
183205
Theme theme = Theme.LIBRARY;

0 commit comments

Comments
 (0)