Skip to content

Commit 34c29fd

Browse files
committed
pulling up matchedAggregationValueMap works
1 parent f2b7399 commit 34c29fd

File tree

6 files changed

+168
-29
lines changed

6 files changed

+168
-29
lines changed

fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java

Lines changed: 132 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.apple.foundationdb.record.query.plan.cascades.PredicateMultiMap.PredicateMapping;
2626
import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression;
2727
import com.apple.foundationdb.record.query.plan.cascades.predicates.QueryPredicate;
28+
import com.apple.foundationdb.record.query.plan.cascades.values.Value;
2829
import com.apple.foundationdb.record.query.plan.cascades.values.translation.MaxMatchMap;
2930
import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp;
3031
import com.google.common.base.Equivalence;
@@ -68,11 +69,42 @@ default boolean isRegular() {
6869
Map<QueryPredicate, PredicateMapping> collectPulledUpPredicateMappings(@Nonnull RelationalExpression candidateExpression,
6970
@Nonnull Set<QueryPredicate> interestingPredicates);
7071

72+
@Nonnull
73+
Map<Value, Value> getMatchedAggregateValueMap();
74+
7175
@Nonnull
7276
default AdjustedBuilder adjustedBuilder() {
7377
return new AdjustedBuilder(this,
7478
getMatchedOrderingParts(),
75-
getMaxMatchMap());
79+
getMaxMatchMap(),
80+
getMatchedAggregateValueMap());
81+
}
82+
83+
@Nonnull
84+
default Map<Value, Value> adjustMatchedAggregateMap(@Nonnull final PartialMatch partialMatch,
85+
@Nonnull final Quantifier candidateQuantifier) {
86+
final var matchedAggregateValueMapBuilder = ImmutableMap.<Value, Value>builder();
87+
final var matchedAggregateValueMap = getMatchedAggregateValueMap();
88+
for (final var matchedAggregateValueMapEntry : matchedAggregateValueMap.entrySet()) {
89+
final var queryAggregateValue = matchedAggregateValueMapEntry.getKey();
90+
final var candidateAggregateValue = matchedAggregateValueMapEntry.getValue();
91+
final var candidateLowerExpression =
92+
Iterables.getOnlyElement(partialMatch.getCandidateRef().getMembers());
93+
final var candidateLowerResultValue = candidateLowerExpression.getResultValue();
94+
final var candidatePullUpMap =
95+
candidateLowerResultValue.pullUp(ImmutableList.of(candidateAggregateValue),
96+
AliasMap.emptyMap(),
97+
Sets.difference(candidateAggregateValue.getCorrelatedToWithoutChildren(),
98+
candidateLowerExpression.getCorrelatedTo()),
99+
candidateQuantifier.getAlias());
100+
final var pulledUpCandidateAggregateValue = candidatePullUpMap.get(candidateAggregateValue);
101+
if (pulledUpCandidateAggregateValue == null) {
102+
return ImmutableMap.of();
103+
}
104+
matchedAggregateValueMapBuilder.put(queryAggregateValue, pulledUpCandidateAggregateValue);
105+
}
106+
107+
return matchedAggregateValueMapBuilder.build();
76108
}
77109

78110
/**
@@ -113,6 +145,9 @@ class RegularMatchInfo implements MatchInfo {
113145
@Nonnull
114146
private final MaxMatchMap maxMatchMap;
115147

148+
@Nonnull
149+
private final Map<Value, Value> matchedAggregateValueMap;
150+
116151
/**
117152
* Field to hold additional query plan constraints that need to be imposed on the potentially realized match.
118153
*/
@@ -125,6 +160,7 @@ private RegularMatchInfo(@Nonnull final Map<CorrelationIdentifier, ComparisonRan
125160
@Nonnull final PredicateMultiMap predicateMap,
126161
@Nonnull final List<MatchedOrderingPart> matchedOrderingParts,
127162
@Nonnull final MaxMatchMap maxMatchMap,
163+
@Nonnull final Map<Value, Value> matchedAggregateValueMap,
128164
@Nonnull final QueryPlanConstraint additionalPlanConstraint) {
129165
this.parameterBindingMap = ImmutableMap.copyOf(parameterBindingMap);
130166
this.bindingAliasMap = bindingAliasMap;
@@ -138,6 +174,7 @@ private RegularMatchInfo(@Nonnull final Map<CorrelationIdentifier, ComparisonRan
138174
this.predicateMap = predicateMap;
139175
this.matchedOrderingParts = ImmutableList.copyOf(matchedOrderingParts);
140176
this.maxMatchMap = maxMatchMap;
177+
this.matchedAggregateValueMap = ImmutableMap.copyOf(matchedAggregateValueMap);
141178
this.additionalPlanConstraint = additionalPlanConstraint;
142179
}
143180

@@ -208,6 +245,12 @@ public MaxMatchMap getMaxMatchMap() {
208245
return maxMatchMap;
209246
}
210247

248+
@Nonnull
249+
@Override
250+
public Map<Value, Value> getMatchedAggregateValueMap() {
251+
return matchedAggregateValueMap;
252+
}
253+
211254
@Nonnull
212255
public QueryPlanConstraint getAdditionalPlanConstraint() {
213256
return additionalPlanConstraint;
@@ -247,7 +290,7 @@ public static Optional<MatchInfo> tryFromMatchMap(@Nonnull final AliasMap bindin
247290
@Nonnull final IdentityBiMap<Quantifier, PartialMatch> partialMatchMap,
248291
@Nonnull final MaxMatchMap maxMatchMap) {
249292
return tryMerge(bindingAliasMap, partialMatchMap, ImmutableMap.of(), PredicateMap.empty(),
250-
maxMatchMap, maxMatchMap.getQueryPlanConstraint());
293+
maxMatchMap, ImmutableMap.of(), maxMatchMap.getQueryPlanConstraint());
251294
}
252295

253296
@Nonnull
@@ -256,6 +299,7 @@ public static Optional<MatchInfo> tryMerge(@Nonnull final AliasMap bindingAliasM
256299
@Nonnull final Map<CorrelationIdentifier, ComparisonRange> parameterBindingMap,
257300
@Nonnull final PredicateMultiMap predicateMap,
258301
@Nonnull final MaxMatchMap maxMatchMap,
302+
@Nonnull final Map<Value, Value> additionalMatchedAggregateValueMap,
259303
@Nonnull final QueryPlanConstraint additionalPlanConstraint) {
260304
final var parameterMapsBuilder = ImmutableList.<Map<CorrelationIdentifier, ComparisonRange>>builder();
261305
final var matchInfos = PartialMatch.matchInfosFromMap(partialMatchMap);
@@ -281,13 +325,18 @@ public static Optional<MatchInfo> tryMerge(@Nonnull final AliasMap bindingAliasM
281325
final Optional<Map<CorrelationIdentifier, ComparisonRange>> mergedParameterBindingsOptional =
282326
tryMergeParameterBindings(parameterMapsBuilder.build());
283327

328+
final var matchedAggregateValueMap =
329+
pullUpAndMergeMatchedAggregateMap(bindingAliasMap, partialMatchMap,
330+
additionalMatchedAggregateValueMap);
331+
284332
return mergedParameterBindingsOptional
285333
.map(mergedParameterBindings -> new RegularMatchInfo(mergedParameterBindings,
286334
bindingAliasMap,
287335
partialMatchMap,
288336
predicateMap,
289337
orderingParts,
290338
maxMatchMap,
339+
matchedAggregateValueMap,
291340
additionalPlanConstraint));
292341
}
293342

@@ -312,6 +361,51 @@ public static Optional<Map<CorrelationIdentifier, ComparisonRange>> tryMergePara
312361

313362
return Optional.of(resultMap);
314363
}
364+
365+
@Nonnull
366+
private static Map<Value, Value> pullUpAndMergeMatchedAggregateMap(@Nonnull final AliasMap bindingAliasMap,
367+
@Nonnull final IdentityBiMap<Quantifier, PartialMatch> partialMatchMap,
368+
@Nonnull final Map<Value, Value> additionalMatchedAggregateValueMap) {
369+
final var matchedAggregateValueMapBuilder = ImmutableMap.<Value, Value>builder();
370+
matchedAggregateValueMapBuilder.putAll(additionalMatchedAggregateValueMap);
371+
for (final var partialMatchMapEntry : partialMatchMap.entrySet()) {
372+
final var quantifier = partialMatchMapEntry.getKey().get();
373+
if (quantifier instanceof Quantifier.ForEach) {
374+
final var partialMatch = partialMatchMapEntry.getValue().get();
375+
final var matchInfo = partialMatch.getMatchInfo();
376+
final var matchedAggregateValueMap = matchInfo.getMatchedAggregateValueMap();
377+
for (final var matchedAggregateValueMapEntry : matchedAggregateValueMap.entrySet()) {
378+
final var queryAggregateValue = matchedAggregateValueMapEntry.getKey();
379+
final var lowerQueryExpression = partialMatch.getQueryExpression();
380+
final var lowerResultValue = lowerQueryExpression.getResultValue();
381+
final var pullUpMap =
382+
lowerResultValue.pullUp(ImmutableList.of(queryAggregateValue), AliasMap.emptyMap(),
383+
Sets.difference(queryAggregateValue.getCorrelatedToWithoutChildren(),
384+
lowerQueryExpression.getCorrelatedTo()), quantifier.getAlias());
385+
final var pulledUpQueryAggregateValue = pullUpMap.get(queryAggregateValue);
386+
if (pulledUpQueryAggregateValue == null) {
387+
return ImmutableMap.of();
388+
}
389+
final var candidateAggregateValue = matchedAggregateValueMapEntry.getValue();
390+
final var candidateLowerExpression =
391+
Iterables.getOnlyElement(partialMatch.getCandidateRef().getMembers());
392+
final var candidateLowerResultValue = candidateLowerExpression.getResultValue();
393+
final var candidatePullUpMap =
394+
candidateLowerResultValue.pullUp(ImmutableList.of(candidateAggregateValue),
395+
AliasMap.emptyMap(),
396+
Sets.difference(candidateAggregateValue.getCorrelatedToWithoutChildren(),
397+
candidateLowerExpression.getCorrelatedTo()),
398+
Objects.requireNonNull(bindingAliasMap.getTarget(quantifier.getAlias())));
399+
final var pulledUpCandidateAggregateValue = candidatePullUpMap.get(candidateAggregateValue);
400+
if (pulledUpCandidateAggregateValue == null) {
401+
return ImmutableMap.of();
402+
}
403+
matchedAggregateValueMapBuilder.put(pulledUpQueryAggregateValue, pulledUpCandidateAggregateValue);
404+
}
405+
}
406+
}
407+
return matchedAggregateValueMapBuilder.build();
408+
}
315409
}
316410

317411
/**
@@ -346,12 +440,17 @@ class AdjustedMatchInfo implements MatchInfo {
346440
@Nonnull
347441
private final MaxMatchMap maxMatchMap;
348442

349-
public AdjustedMatchInfo(@Nonnull final MatchInfo underlying,
350-
@Nonnull final List<MatchedOrderingPart> matchedOrderingParts,
351-
@Nonnull final MaxMatchMap maxMatchMap) {
443+
@Nonnull
444+
private final Map<Value, Value> matchedAggregateValueMap;
445+
446+
private AdjustedMatchInfo(@Nonnull final MatchInfo underlying,
447+
@Nonnull final List<MatchedOrderingPart> matchedOrderingParts,
448+
@Nonnull final MaxMatchMap maxMatchMap,
449+
@Nonnull final Map<Value, Value> matchedAggregateValueMap) {
352450
this.underlying = underlying;
353451
this.matchedOrderingParts = matchedOrderingParts;
354452
this.maxMatchMap = maxMatchMap;
453+
this.matchedAggregateValueMap = ImmutableMap.copyOf(matchedAggregateValueMap);
355454
}
356455

357456
@Nonnull
@@ -371,6 +470,12 @@ public MaxMatchMap getMaxMatchMap() {
371470
return maxMatchMap;
372471
}
373472

473+
@Nonnull
474+
@Override
475+
public Map<Value, Value> getMatchedAggregateValueMap() {
476+
return matchedAggregateValueMap;
477+
}
478+
374479
@Override
375480
public boolean isAdjusted() {
376481
return true;
@@ -424,6 +529,9 @@ class AdjustedBuilder {
424529
@Nonnull
425530
private List<MatchedOrderingPart> matchedOrderingParts;
426531

532+
@Nonnull
533+
private Map<Value, Value> matchedAggregateValueMap;
534+
427535
/**
428536
* A map of maximum matches between the query result {@code Value} and the corresponding candidate's result
429537
* {@code Value}.
@@ -433,10 +541,12 @@ class AdjustedBuilder {
433541

434542
private AdjustedBuilder(@Nonnull final MatchInfo underlying,
435543
@Nonnull final List<MatchedOrderingPart> matchedOrderingParts,
436-
@Nonnull final MaxMatchMap maxMatchMap) {
544+
@Nonnull final MaxMatchMap maxMatchMap,
545+
@Nonnull final Map<Value, Value> matchedAggregateValueMap) {
437546
this.underlying = underlying;
438547
this.matchedOrderingParts = matchedOrderingParts;
439548
this.maxMatchMap = maxMatchMap;
549+
this.matchedAggregateValueMap = matchedAggregateValueMap;
440550
}
441551

442552
@Nonnull
@@ -449,22 +559,37 @@ public AdjustedBuilder setMatchedOrderingParts(@Nonnull final List<MatchedOrderi
449559
return this;
450560
}
451561

562+
@Nonnull
563+
public AdjustedBuilder setMatchedAggregateValueMap(@Nonnull final Map<Value, Value> matchedAggregateValueMap) {
564+
this.matchedAggregateValueMap = matchedAggregateValueMap;
565+
return this;
566+
}
567+
452568
@Nonnull
453569
public MaxMatchMap getMaxMatchMap() {
454570
return maxMatchMap;
455571
}
456572

573+
@Nonnull
457574
public AdjustedBuilder setMaxMatchMap(@Nonnull final MaxMatchMap maxMatchMap) {
458575
this.maxMatchMap = maxMatchMap;
459576
return this;
460577
}
461578

579+
580+
581+
@Nonnull
582+
public Map<Value, Value> getMatchedAggregateValueMap() {
583+
return matchedAggregateValueMap;
584+
}
585+
462586
@Nonnull
463587
public MatchInfo build() {
464588
return new AdjustedMatchInfo(
465589
underlying,
466590
matchedOrderingParts,
467-
maxMatchMap);
591+
maxMatchMap,
592+
matchedAggregateValueMap);
468593
}
469594
}
470595
}

fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -310,15 +310,12 @@ public Iterable<MatchInfo> subsumedBy(@Nonnull final RelationalExpression candid
310310
ValueEquivalence.fromAliasMap(bindingAliasMap)
311311
.then(ValueEquivalence.constantEquivalenceWithEvaluationContext(evaluationContext));
312312

313-
final var translatedAggregateValue =
314-
aggregateValue.translateCorrelations(translationMap, true);
315-
final var translatedAggregateValues =
316-
Values.primitiveAccessorsForType(translatedAggregateValue.getResultType(),
317-
() -> translatedAggregateValue).stream()
313+
final var aggregateValues =
314+
Values.primitiveAccessorsForType(aggregateValue.getResultType(), () -> aggregateValue).stream()
318315
.map(primitiveAggregateValue -> primitiveAggregateValue.simplify(AliasMap.emptyMap(),
319316
ImmutableSet.of()))
320317
.collect(ImmutableSet.toImmutableSet());
321-
if (translatedAggregateValues.isEmpty()) {
318+
if (aggregateValues.isEmpty()) {
322319
return ImmutableList.of();
323320
}
324321

@@ -331,13 +328,21 @@ public Iterable<MatchInfo> subsumedBy(@Nonnull final RelationalExpression candid
331328
if (otherAggregateValues.size() != 1) {
332329
return ImmutableList.of();
333330
}
334-
335-
final var subsumedAggregations = BooleanWithConstraint.alwaysTrue();
336-
// Iterables.getOnlyElement(translatedAggregateValues).semanticEquals(Iterables.getOnlyElement(otherAggregateValues),
337-
// valueEquivalence);
338-
// if (subsumedAggregations.isFalse()) {
339-
// return ImmutableList.of();
340-
// }
331+
final var otherPrimitiveAggregateValue = Iterables.getOnlyElement(otherAggregateValues);
332+
final var matchedAggregateValueMapBuilder = ImmutableMap.<Value, Value>builder();
333+
var subsumedAggregations = BooleanWithConstraint.alwaysTrue();
334+
for (final var primitiveAggregateValue : aggregateValues) {
335+
final var translatedPrimitiveAggregateValue =
336+
primitiveAggregateValue.translateCorrelations(translationMap, true);
337+
338+
final var semanticEquals =
339+
translatedPrimitiveAggregateValue.semanticEquals(otherPrimitiveAggregateValue, valueEquivalence);
340+
if (semanticEquals.isTrue()) {
341+
matchedAggregateValueMapBuilder.put(primitiveAggregateValue, otherPrimitiveAggregateValue);
342+
subsumedAggregations = semanticEquals;
343+
break;
344+
}
345+
}
341346

342347
final var subsumedGroupings =
343348
subsumedAggregations
@@ -357,7 +362,7 @@ public Iterable<MatchInfo> subsumedBy(@Nonnull final RelationalExpression candid
357362
subsumedGroupings.getConstraint().compose(maxMatchMap.getQueryPlanConstraint());
358363

359364
return RegularMatchInfo.tryMerge(bindingAliasMap, partialMatchMap, ImmutableMap.of(), PredicateMap.empty(),
360-
maxMatchMap, queryPlanConstraint)
365+
maxMatchMap, matchedAggregateValueMapBuilder.build(), queryPlanConstraint)
361366
.map(ImmutableList::of)
362367
.orElse(ImmutableList.of());
363368
}

fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/MatchableSortExpression.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,8 @@ public MatchableSortExpression translateCorrelations(@Nonnull final TranslationM
212212

213213
@Nonnull
214214
@Override
215-
public Optional<MatchInfo> adjustMatch(@Nonnull final PartialMatch partialMatch) {
215+
public Optional<MatchInfo> adjustMatch(@Nonnull final PartialMatch partialMatch,
216+
@Nonnull final Quantifier candidateQuantifier) {
216217
final var childMatchInfo = partialMatch.getMatchInfo();
217218
final var maxMatchMap = childMatchInfo.getMaxMatchMap();
218219
final var innerQuantifier = Iterables.getOnlyElement(getQuantifiers());
@@ -223,6 +224,7 @@ public Optional<MatchInfo> adjustMatch(@Nonnull final PartialMatch partialMatch)
223224
childMatchInfo.adjustedBuilder()
224225
.setMaxMatchMap(adjustedMaxMatchMap)
225226
.setMatchedOrderingParts(forPartialMatch(partialMatch))
227+
.setMatchedAggregateValueMap(childMatchInfo.adjustMatchedAggregateMap(partialMatch, candidateQuantifier))
226228
.build());
227229
}
228230

fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/RelationalExpression.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -749,12 +749,15 @@ static Optional<TranslationMap> pullUpAndComposeTranslationMapsMaybe(@Nonnull fi
749749

750750
/**
751751
* Override that is called by {@link AdjustMatchRule} to improve an already existing {@link PartialMatch}.
752-
* @param partialMatch the partial match already existing between {@code expression} and {@code this}
752+
* @param partialMatch the partial match already existing between {@code expression} and the only child of
753+
* {@code this}
754+
* @param candidateQuantifier the quantifier we adjust along
753755
* @return {@code Optional.empty()} if the match could not be adjusted, Optional.of(matchInfo) for a new adjusted
754756
* match, otherwise.
755757
*/
756758
@Nonnull
757-
default Optional<MatchInfo> adjustMatch(@Nonnull final PartialMatch partialMatch) {
759+
default Optional<MatchInfo> adjustMatch(@Nonnull final PartialMatch partialMatch,
760+
@Nonnull final Quantifier candidateQuantifier) {
758761
return Optional.empty();
759762
}
760763

0 commit comments

Comments
 (0)