github-actions[bot] commented on code in PR #61345:
URL: https://github.com/apache/doris/pull/61345#discussion_r3304934599
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/Predicates.java:
##########
@@ -254,41 +265,372 @@ private static Set<Expression>
normalizeExpression(Expression expression, Cascad
return ExpressionUtils.extractConjunctionToSet(expression);
}
- /**
- * compensate residual predicates
- */
- public static Map<Expression, ExpressionInfo>
compensateResidualPredicate(StructInfo queryStructInfo,
+ /** Collect all predicate compensation candidates before residual
finalization. */
+ public static PredicateCompensation collectCompensationCandidates(
+ StructInfo queryStructInfo,
StructInfo viewStructInfo,
SlotMapping viewToQuerySlotMapping,
- ComparisonResult comparisonResult) {
- // TODO Residual predicates compensate, simplify implementation
currently.
- SplitPredicate querySplitPredicate =
queryStructInfo.getSplitPredicate();
- SplitPredicate viewSplitPredicate = viewStructInfo.getSplitPredicate();
+ ComparisonResult comparisonResult,
+ CascadesContext cascadesContext) {
+ Map<Expression, ExpressionInfo> equalCandidates =
collectEquivalenceCandidates(
+ queryStructInfo, viewStructInfo, viewToQuerySlotMapping,
comparisonResult);
+ Map<Expression, ExpressionInfo> rangeCandidates =
collectRangeCandidates(
+ queryStructInfo, viewStructInfo, viewToQuerySlotMapping,
comparisonResult, cascadesContext);
+ Map<Expression, ExpressionInfo> residualCandidates =
collectResidualCandidates(queryStructInfo);
+ if (equalCandidates == null || rangeCandidates == null ||
residualCandidates == null) {
+ return null;
+ }
+ return new PredicateCompensation(equalCandidates, rangeCandidates,
residualCandidates);
+ }
- Set<Expression> viewResidualQueryBasedSet = new HashSet<>();
- for (Expression viewExpression :
viewSplitPredicate.getResidualPredicateMap().keySet()) {
- viewResidualQueryBasedSet.add(
- ExpressionUtils.replace(viewExpression,
viewToQuerySlotMapping.toSlotReferenceMap()));
+ /** Compensate predicates in one step. */
+ public static PredicateCompensation compensatePredicates(
+ StructInfo queryStructInfo,
+ StructInfo viewStructInfo,
+ SlotMapping viewToQuerySlotMapping,
+ ComparisonResult comparisonResult,
+ CascadesContext cascadesContext) {
+ PredicateCompensation compensationCandidates =
collectCompensationCandidates(
+ queryStructInfo, viewStructInfo, viewToQuerySlotMapping,
comparisonResult, cascadesContext);
+ if (compensationCandidates == null) {
+ return null;
+ }
+ Expression combinedCompensationCandidates = buildCombinedPredicate(
+ compensationCandidates.getEquals().keySet(),
+ compensationCandidates.getRanges().keySet(),
+ compensationCandidates.getResiduals().keySet());
+
+ Set<Expression> queryBasedViewResidualPredicates =
collectNonInferredQueryBasedExpressions(
+
viewStructInfo.getSplitPredicate().getResidualPredicateMap().keySet(),
viewToQuerySlotMapping);
+ Expression combinedQueryBasedViewResidual =
buildCombinedPredicate(queryBasedViewResidualPredicates);
+ if (BooleanLiteral.TRUE.equals(combinedQueryBasedViewResidual)) {
+ // The target residual is TRUE, so implication always holds and
DNF expansion is unnecessary.
+ return rejectUnsafeResidualCompensation(compensationCandidates);
}
- viewResidualQueryBasedSet.remove(BooleanLiteral.TRUE);
- Set<Expression> queryResidualSet =
querySplitPredicate.getResidualPredicateMap().keySet();
- // remove unnecessary literal BooleanLiteral.TRUE
- queryResidualSet.remove(BooleanLiteral.TRUE);
- // query residual predicate can not contain all view residual
predicate when view have residual predicate,
- // bail out
- if (!queryResidualSet.containsAll(viewResidualQueryBasedSet)) {
+ try {
+ // The compensation must not widen the view result:
+ // compensationCandidates => combinedQueryBasedViewResidual.
+ if (!impliesByDnf(combinedCompensationCandidates,
combinedQueryBasedViewResidual)) {
+ return null;
+ }
+
+ PredicateCompensation finalCompensation = new
PredicateCompensation(
+ removePredicatesImpliedByViewResidual(
+ compensationCandidates.getEquals(),
combinedQueryBasedViewResidual),
+ removePredicatesImpliedByViewResidual(
+ compensationCandidates.getRanges(),
combinedQueryBasedViewResidual),
+ removePredicatesImpliedByViewResidual(
+ compensationCandidates.getResiduals(),
combinedQueryBasedViewResidual));
+ return rejectUnsafeResidualCompensation(finalCompensation);
+ } catch (DnfBranchOverflowException e) {
Review Comment:
This overflow fallback now rejects exact residual matches when the non-empty
view residual is a large conjunction of ORs. For example, the new
`testCompensateCandidatesByViewResidualReturnsNullWhenDnfBranchesOverflow` uses
identical query/view SQL, so the old residual compensation path would accept it
by exact set containment/removal without expanding DNF. That rewrite is always
safe because the MV already has the same residual predicate; failing only
because the proof engine expands `query == view` past `MAX_DNF_BRANCHES` is a
regression in rewrite coverage. Please add an exact/subset residual fast path
before DNF implication, or otherwise remove already-covered residual predicates
before expansion, and update the test to expect success for the
identical-residual case.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]