Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add tree / pretty explain mode #14677

Merged
merged 23 commits into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions datafusion-examples/examples/planner_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

use datafusion::error::Result;
use datafusion::logical_expr::{LogicalPlan, PlanType};
use datafusion::physical_plan::displayable;
use datafusion::physical_plan::{displayable, DisplayFormatType};
use datafusion::physical_planner::DefaultPhysicalPlanner;
use datafusion::prelude::*;

Expand Down Expand Up @@ -78,7 +78,11 @@ async fn to_physical_plan_in_one_api_demo(
println!(
"Physical plan direct from logical plan:\n\n{}\n\n",
displayable(physical_plan.as_ref())
.to_stringified(false, PlanType::InitialPhysicalPlan)
.to_stringified(
false,
PlanType::InitialPhysicalPlan,
DisplayFormatType::Default
)
.plan
);

Expand Down Expand Up @@ -120,7 +124,11 @@ async fn to_physical_plan_step_by_step_demo(
println!(
"Final physical plan:\n\n{}\n\n",
displayable(physical_plan.as_ref())
.to_stringified(false, PlanType::InitialPhysicalPlan)
.to_stringified(
false,
PlanType::InitialPhysicalPlan,
DisplayFormatType::Default
)
.plan
);

Expand All @@ -135,7 +143,11 @@ async fn to_physical_plan_step_by_step_demo(
println!(
"Optimized physical plan:\n\n{}\n\n",
displayable(physical_plan.as_ref())
.to_stringified(false, PlanType::InitialPhysicalPlan)
.to_stringified(
false,
PlanType::InitialPhysicalPlan,
DisplayFormatType::Default
)
.plan
);

Expand Down
4 changes: 4 additions & 0 deletions datafusion/common/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,10 @@ config_namespace! {

/// When set to true, the explain statement will print schema information
pub show_schema: bool, default = false

/// Display format of explain. Default is "indent".
/// When set to "tree", it will print the plan in a tree-rendered format.
pub format: String, default = "indent".to_string()
}
}

Expand Down
4 changes: 4 additions & 0 deletions datafusion/core/src/datasource/file_format/arrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,10 @@ impl DisplayAs for ArrowFileSink {
FileGroupDisplay(&self.config.file_groups).fmt_as(t, f)?;
write!(f, ")")
}
DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}
Expand Down
1 change: 0 additions & 1 deletion datafusion/core/src/datasource/file_format/csv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
// under the License.

//! Re-exports the [`datafusion_datasource_csv::file_format`] module, and contains tests for it.
pub use datafusion_datasource_csv::file_format::*;

#[cfg(test)]
Expand Down
1 change: 0 additions & 1 deletion datafusion/core/src/datasource/file_format/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
// under the License.

//! Re-exports the [`datafusion_datasource_json::file_format`] module, and contains tests for it.

pub use datafusion_datasource_json::file_format::*;

#[cfg(test)]
Expand Down
4 changes: 4 additions & 0 deletions datafusion/core/src/datasource/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,10 @@ impl DisplayAs for MemSink {
let partition_count = self.batches.len();
write!(f, "MemoryTable (partitions={partition_count})")
}
DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}
Expand Down
29 changes: 26 additions & 3 deletions datafusion/core/src/physical_planner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

use std::borrow::Cow;
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::Arc;

use crate::datasource::file_format::file_type_to_format;
Expand Down Expand Up @@ -87,6 +88,7 @@ use datafusion_physical_optimizer::PhysicalOptimizerRule;
use datafusion_physical_plan::execution_plan::InvariantLevel;
use datafusion_physical_plan::placeholder_row::PlaceholderRowExec;
use datafusion_physical_plan::unnest::ListUnnest;
use datafusion_physical_plan::DisplayFormatType;

use crate::schema_equivalence::schema_satisfied_by;
use async_trait::async_trait;
Expand Down Expand Up @@ -1723,6 +1725,7 @@ impl DefaultPhysicalPlanner {
let mut stringified_plans = vec![];

let config = &session_state.config_options().explain;
let explain_format = DisplayFormatType::from_str(&config.format)?;

if !config.physical_plan_only {
stringified_plans.clone_from(&e.stringified_plans);
Expand All @@ -1742,7 +1745,11 @@ impl DefaultPhysicalPlanner {
displayable(input.as_ref())
.set_show_statistics(config.show_statistics)
.set_show_schema(config.show_schema)
.to_stringified(e.verbose, InitialPhysicalPlan),
.to_stringified(
e.verbose,
InitialPhysicalPlan,
explain_format,
),
);

// Show statistics + schema in verbose output even if not
Expand All @@ -1755,6 +1762,7 @@ impl DefaultPhysicalPlanner {
.to_stringified(
e.verbose,
InitialPhysicalPlanWithStats,
explain_format,
),
);
}
Expand All @@ -1765,6 +1773,7 @@ impl DefaultPhysicalPlanner {
.to_stringified(
e.verbose,
InitialPhysicalPlanWithSchema,
explain_format,
),
);
}
Expand All @@ -1780,7 +1789,11 @@ impl DefaultPhysicalPlanner {
displayable(plan)
.set_show_statistics(config.show_statistics)
.set_show_schema(config.show_schema)
.to_stringified(e.verbose, plan_type),
.to_stringified(
e.verbose,
plan_type,
explain_format,
),
);
},
);
Expand All @@ -1791,7 +1804,11 @@ impl DefaultPhysicalPlanner {
displayable(input.as_ref())
.set_show_statistics(config.show_statistics)
.set_show_schema(config.show_schema)
.to_stringified(e.verbose, FinalPhysicalPlan),
.to_stringified(
e.verbose,
FinalPhysicalPlan,
explain_format,
),
);

// Show statistics + schema in verbose output even if not
Expand All @@ -1804,6 +1821,7 @@ impl DefaultPhysicalPlanner {
.to_stringified(
e.verbose,
FinalPhysicalPlanWithStats,
explain_format,
),
);
}
Expand All @@ -1814,6 +1832,7 @@ impl DefaultPhysicalPlanner {
.to_stringified(
e.verbose,
FinalPhysicalPlanWithSchema,
explain_format,
),
);
}
Expand Down Expand Up @@ -2720,6 +2739,10 @@ mod tests {
DisplayFormatType::Default | DisplayFormatType::Verbose => {
write!(f, "NoOpExecutionPlan")
}
DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions datafusion/core/tests/custom_sources_cases/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ impl DisplayAs for CustomExecutionPlan {
DisplayFormatType::Default | DisplayFormatType::Verbose => {
write!(f, "CustomExecutionPlan: projection={:#?}", self.projection)
}

DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ impl DisplayAs for CustomPlan {
DisplayFormatType::Default | DisplayFormatType::Verbose => {
write!(f, "CustomPlan: batch_size={}", self.batches.len(),)
}
DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions datafusion/core/tests/custom_sources_cases/statistics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ impl DisplayAs for StatisticsValidation {
self.stats.num_rows,
)
}
DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}
Expand Down
12 changes: 10 additions & 2 deletions datafusion/core/tests/physical_optimizer/enforce_distribution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,18 @@ impl SortRequiredExec {
impl DisplayAs for SortRequiredExec {
fn fmt_as(
&self,
_t: DisplayFormatType,
t: DisplayFormatType,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(f, "SortRequiredExec: [{}]", self.expr)
match t {
DisplayFormatType::Default | DisplayFormatType::Verbose => {
write!(f, "SortRequiredExec: [{}]", self.expr)
}
DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}

Expand Down
9 changes: 9 additions & 0 deletions datafusion/core/tests/physical_optimizer/join_selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,10 @@ impl DisplayAs for UnboundedExec {
self.batch_produce.is_none(),
)
}
DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}
Expand Down Expand Up @@ -1019,6 +1023,11 @@ impl DisplayAs for StatisticsExec {
self.stats.num_rows,
)
}

DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}
Expand Down
12 changes: 10 additions & 2 deletions datafusion/core/tests/physical_optimizer/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,16 @@ impl RequirementsTestExec {
}

impl DisplayAs for RequirementsTestExec {
fn fmt_as(&self, _t: DisplayFormatType, f: &mut Formatter) -> std::fmt::Result {
write!(f, "RequiredInputOrderingExec")
fn fmt_as(&self, t: DisplayFormatType, f: &mut Formatter) -> std::fmt::Result {
match t {
DisplayFormatType::Default | DisplayFormatType::Verbose => {
write!(f, "RequiredInputOrderingExec")
}
DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions datafusion/core/tests/user_defined/user_defined_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,10 @@ impl DisplayAs for TopKExec {
DisplayFormatType::Default | DisplayFormatType::Verbose => {
write!(f, "TopKExec: k={}", self.k)
}
DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions datafusion/datasource-csv/src/file_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,10 @@ impl DisplayAs for CsvSink {
FileGroupDisplay(&self.config.file_groups).fmt_as(t, f)?;
write!(f, ")")
}
DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions datafusion/datasource-json/src/file_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ impl DisplayAs for JsonSink {
FileGroupDisplay(&self.config.file_groups).fmt_as(t, f)?;
write!(f, ")")
}
DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions datafusion/datasource-parquet/src/file_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,10 @@ impl DisplayAs for ParquetSink {
FileGroupDisplay(&self.config.file_groups).fmt_as(t, f)?;
write!(f, ")")
}
DisplayFormatType::TreeRender => {
// TODO: collect info
write!(f, "")
}
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion datafusion/datasource-parquet/src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,9 @@ impl FileSource for ParquetSource {

fn fmt_extra(&self, t: DisplayFormatType, f: &mut Formatter) -> std::fmt::Result {
match t {
DisplayFormatType::Default | DisplayFormatType::Verbose => {
DisplayFormatType::Default
| DisplayFormatType::Verbose
| DisplayFormatType::TreeRender => {
let predicate_string = self
.predicate()
.map(|p| format!(", predicate={p}"))
Expand Down
4 changes: 2 additions & 2 deletions datafusion/datasource/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl DisplayAs for FileGroupsDisplay<'_> {
let groups = if n_groups == 1 { "group" } else { "groups" };
write!(f, "{{{n_groups} {groups}: [")?;
match t {
DisplayFormatType::Default => {
DisplayFormatType::Default | DisplayFormatType::TreeRender => {
// To avoid showing too many partitions
let max_groups = 5;
fmt_up_to_n_elements(self.0, max_groups, f, |group, f| {
Expand Down Expand Up @@ -66,7 +66,7 @@ impl DisplayAs for FileGroupDisplay<'_> {
fn fmt_as(&self, t: DisplayFormatType, f: &mut Formatter) -> FmtResult {
write!(f, "[")?;
match t {
DisplayFormatType::Default => {
DisplayFormatType::Default | DisplayFormatType::TreeRender => {
// To avoid showing too many files
let max_files = 5;
fmt_up_to_n_elements(self.0, max_files, f, |pf, f| {
Expand Down
Loading