zhuqi-lucas commented on code in PR #26757:
URL: https://github.com/apache/datafusion/pull/26757#discussion_r4430936718
##########
datafusion/session/src/physical_analyzer.rs:
##########
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: See the NOTICE file distributed with this work for
additional information regarding copyright ownership
+// SPDX-FileContributor: Licensed to the Apache Software Foundation (ASF)
under one or more contributor license agreements
+
+//! Physical analyzer interfaces.
+
+use std::fmt::Debug;
+use std::sync::Arc;
+
+use datafusion_common::Result;
+use datafusion_common::config::ConfigOptions;
+use datafusion_physical_plan::ExecutionPlan;
+
+use crate::physical_optimizer::PhysicalOptimizerContext;
+
+/// A `PhysicalAnalyzerRule` runs before requirements are enforced. The
+/// analyzer phase runs the rules that must see the plan while each
+/// operator's [`ExecutionPlan::required_input_distribution`] and
+/// [`ExecutionPlan::required_input_ordering`] are only declared, then
+/// `EnsureRequirements`, which repartitions and sorts the inputs to meet them.
+/// Every [`PhysicalOptimizerRule`] after it receives a plan that meets its
+/// requirements and must return one.
+///
+/// A rule belongs in the analyzer when `EnsureRequirements` reads what the
+/// rule changes (a requirement, an ordering, or statistics), as with the join
+/// mode `join_selection` picks, or when the rule needs the plan before
+/// enforcement adds repartitions and sorts, as with `WindowTopN`. A rule that
+/// reads what enforcement produced, such as `LimitPushdown`, is a
+/// [`PhysicalOptimizerRule`]. Both phases hold
+/// performance rules; what differs is the plan each one receives. A rule is
+/// one or the other: moving it to the other phase means implementing the
+/// other trait.
Review Comment:
On #25688 the plan, following @alamb's suggestion there, was to keep today's
order here and move `aggregate_statistics`, `LimitedDistinctAggregation`,
`FilterPushdown` and `WindowTopN` into the optimizer in follow-ups, with
`join_selection` after its own design (#26481). Dropping their
`PhysicalOptimizerRule` impls turns each of those moves into another API break,
the double break you want to avoid. #25688 kept both impls, the analyzer one
delegating, so a move is just a list change. Could we keep that, and word this
paragraph as transitional?
##########
datafusion/core/tests/physical_optimizer/eliminate_constant_join.rs:
##########
@@ -108,8 +108,8 @@ async fn keeps_join_with_lambda_filter() -> Result<()> {
.create_physical_plan()
.await?;
- let optimized = EliminateConstantJoin::new()
- .optimize(Arc::clone(&join), &ConfigOptions::new())?;
+ let optimized =
+ EliminateConstantJoin::new().analyze(Arc::clone(&join),
&ConfigOptions::new())?;
Review Comment:
`metadata_session(false)` below filters `EliminateConstantJoin` out of
`physical_optimizers()`, which no longer holds it, so both sessions eliminate
the join and `keeps_metadata_of_constant_input` compares the rewrite with
itself (I printed both plans: neither has the join).
`proto/tests/cases/plans/misc.rs:673` ("No optimizations") and
`ffi/integration-tests/tests/cases/query_planner.rs:250` ("observe planning
alone") also clear only the optimizer list.
##########
datafusion/physical-optimizer/src/filter_pushdown.rs:
##########
@@ -367,56 +368,75 @@ use itertools::{Itertools, izip};
/// [`FilterExec`]: datafusion_physical_plan::filter::FilterExec
/// [`ProjectionExec`]: datafusion_physical_plan::projection::ProjectionExec
/// [`AggregateExec`]: datafusion_physical_plan::aggregates::AggregateExec
-#[derive(Debug)]
-pub struct FilterPushdown {
- phase: FilterPushdownPhase,
- name: String,
-}
+#[derive(Debug, Default)]
+pub struct FilterPushdown {}
impl FilterPushdown {
- fn new_with_phase(phase: FilterPushdownPhase) -> Self {
- let name = match phase {
- FilterPushdownPhase::Pre => "FilterPushdown",
- FilterPushdownPhase::Post => "FilterPushdown(Post)",
- }
- .to_string();
- Self { phase, name }
+ /// Create a new [`FilterPushdown`] rule, which pushes static filters
+ /// ([`FilterPushdownPhase::Pre`]).
+ pub fn new() -> Self {
+ Self {}
}
+}
- /// Create a new [`FilterPushdown`] optimizer rule that runs in the
pre-optimization phase.
- /// See [`FilterPushdownPhase`] for more details.
+/// Pushes dynamic filters, such as those a TopK `SortExec` or a `HashJoinExec`
+/// creates, into the operators that can use them
+/// ([`FilterPushdownPhase::Post`]). It runs after the other optimizer rules,
so
+/// that later rewrites do not break the links between a filter's producer and
+/// its consumers. See [`FilterPushdown`] for how pushdown works.
+#[derive(Debug, Default)]
+pub struct DynamicFilterPushdown {}
+
+impl DynamicFilterPushdown {
Review Comment:
Per the API health guide, could `FilterPushdown::new_post_optimization` and
`OutputRequirements::new_remove_mode` stay as `#[deprecated]` shims returning
the new types? Both are still optimizer rules, so existing lists keep compiling.
##########
datafusion/ffi/src/session/mod.rs:
##########
@@ -153,6 +155,9 @@ pub(crate) struct FFI_SessionRef {
/// Utility to identify when FFI objects are accessed locally through
/// the foreign interface.
pub library_marker_id: extern "C" fn() -> usize,
+
+ /// The session's physical analyzer rules.
+ physical_analyzers: unsafe extern "C" fn(&Self) ->
SVec<FFI_PhysicalAnalyzerRule>,
Review Comment:
With this field the struct no longer matches DataFusion 55, but the comment
on `create_physical_plan` above still says that slot is kept for 55
compatibility.
--
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]