2010YOUY01 commented on PR #25688:
URL: https://github.com/apache/datafusion/pull/25688#issuecomment-6008341569

   > As neat an idea of having multiple classes of constraints that can be 
satisfied at different points, I think it makes it harder to reason about the 
optimizer as a whole and any OptimizerRule individually -- we would need some 
way for each rule to communicate what its expected input and output boundary was
   
   If I understand the assumptions behind the optimizer implementation 
correctly, adding more explicit constraints should make both understanding and 
implementation easier.
   
   Let me first restate the assumptions. I may be missing something here since 
I have less experience working on optimizers.
   
   ```txt
   # Assumptions for the physical optimizer
   
   DataFusion provides a default ordered list of optimizer rules.
   
   // Default rules
   rules = [
     rule1,
     rule2,
     rule3,
     rule4,
     ...
   ]
   
   - The default rules are only guaranteed to be safe when run in the 
prescribed order.
   
   - To disable specific behavior, use configuration options that define 
known-safe variations. For example,
     `set datafusion.optimizer.enable_distinct_aggregation_soft_limit = false`
     disables one specific aggregation optimization without arbitrarily 
modifying the rule pipeline.
   
   - (This sounds intimidating, but seems close to the current state):
     To implement an extension rule outside core, you need to understand the 
implicit constraints established by the surrounding default optimizer rules. 
Otherwise, changes in the default rules might break the plan.
     Currently, many of these constraints are only documented locally inside 
individual rules.
   
   # Future improvement direction
   
   Make these constraints easier to understand, express, and test.
   
   # Not intended usage
   
   Arbitrarily reorder/remove default rules downstream and expect the resulting 
optimizer pipeline to remain valid.
   
   // Reordered default rules mixed with extension rules
   rules = [
     rule3,
     extension_rule1,
     rule1,
     ...
   ]
   ```
   
   ## More constraints can simplify optimizer extensions
   
   If we explicitly exclude arbitrary reordering of the default optimizer rule 
list from the supported use case, then stronger constraints can simplify the 
optimizer:
   
   - **Simpler implementation:** each optimizer rule needs to handle fewer 
possible input states if its preconditions are known.
   - **Safer composition:** a rule knows which invariants it must preserve so 
that later rules continue to work correctly.
   
   ### Walkthrough
   
   In @zhuqi-lucas's use case:
   
   ```txt
   rules = [
     rule1,
     rule2,
     EnsureRequirements,
     rule3,
     extension_rule,
     ...
   ]
   ```
   
   If we treat the analyzer/optimizer split as a general boundary, the 
preconditions and postconditions of `extension_rule` become much clearer:
   
   - **Assumption:** input plans already satisfy their distribution/ordering 
requirements (`RepartitionExec`s have been inserted and the plan is runnable).
   - **Promise:** the rule must not invalidate those requirements. It either 
preserves the existing enforcement operators or re-runs `EnsureRequirements` 
internally when necessary.
   
   The simplification provided by this boundary is that a semantically 
equivalent plan has a canonical physical shape at this point in the optimizer.
   
   ```txt
   // plan1 and plan2 are semantically equivalent, but the analyzer boundary
   // guarantees that this rule only needs to handle plan1.
   //
   // This reduces the number of physical shapes the rule needs to reason about.
   
   // plan1
   AggregateExec(mode=final)
   --RepartitionExec
   ----AggregateExec(mode=partial)
   
   // plan2
   AggregateExec(mode=final)
   --AggregateExec(mode=partial)
   ```
   
   More constraints can reduce the problem space further. For example, if this 
extension rule needs to inspect projections, its implementation becomes simpler 
if projected plans also have one canonical shape at this boundary, rather than 
allowing several equivalent representations.
   
   ## Proceeding with this PR
   
   Now @zhuqi-lucas and @alamb seem more in favor of implementing the 
analyzer/optimizer split first, and treating a more general boundary mechanism 
as a follow-up.
   
   My current preference is to implement the more general optimizer boundary 
directly, to avoid introducing multiple mechanisms for the same underlying 
problem. That said, if I have misunderstood the assumptions above, this 
proposal would definitely need to be reworked.
   
   I'd like to hear your thoughts before deciding on the next step. If you also 
think a general boundary mechanism is a plausible direction, I can put together 
a PoC this week.


-- 
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]

Reply via email to