This is an automated email from the ASF dual-hosted git repository.
alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git
The following commit(s) were added to refs/heads/main by this push:
new 3dc212c907 Implement `tree` explain for FilterExec (#15001)
3dc212c907 is described below
commit 3dc212c9078c92f57ab7f58e75e1258130c772d0
Author: Andrew Lamb <[email protected]>
AuthorDate: Wed Mar 5 08:55:06 2025 -0500
Implement `tree` explain for FilterExec (#15001)
---
datafusion/physical-plan/src/display.rs | 35 +++++++++++++++++--
datafusion/physical-plan/src/filter.rs | 3 +-
.../sqllogictest/test_files/explain_tree.slt | 39 +++++++++++++++++++---
3 files changed, 68 insertions(+), 9 deletions(-)
diff --git a/datafusion/physical-plan/src/display.rs
b/datafusion/physical-plan/src/display.rs
index 26e0a822f5..096b515407 100644
--- a/datafusion/physical-plan/src/display.rs
+++ b/datafusion/physical-plan/src/display.rs
@@ -37,10 +37,41 @@ use super::{accept, ExecutionPlan, ExecutionPlanVisitor};
#[derive(Debug, Clone, Copy)]
pub enum DisplayFormatType {
/// Default, compact format. Example: `FilterExec: c12 < 10.0`
+ ///
+ /// This format is designed to provide a detailed textual description
+ /// of all rele
Default,
- /// Verbose, showing all available details
+ /// Verbose, showing all available details.
+ ///
+ /// This form is even more detailed than [`Self::Default`]
Verbose,
- /// TreeRender, display plan like a tree.
+ /// TreeRender, displayed in the `tree` explain type.
+ ///
+ /// This format is inspired by DuckDB's explain plans. The information
+ /// presented should be "user friendly", and contain only the most relevant
+ /// information for understanding a plan. It should NOT contain the same
level
+ /// of detail information as the [`Self::Default`] format.
+ ///
+ /// In this mode, each line contains a key=value pair.
+ /// Everything before the first `=` is treated as the key, and everything
after the
+ /// first `=` is treated as the value.
+ ///
+ /// For example, if the output of `TreeRender` is this:
+ /// ```text
+ /// partition_sizes=[1]
+ /// partitions=1
+ /// ```
+ ///
+ /// It is rendered in the center of a box in the following way:
+ ///
+ /// ```text
+ /// ┌───────────────────────────┐
+ /// │ DataSourceExec │
+ /// │ -------------------- │
+ /// │ partition_sizes: [1] │
+ /// │ partitions: 1 │
+ /// └───────────────────────────┘
+ /// ```
TreeRender,
}
diff --git a/datafusion/physical-plan/src/filter.rs
b/datafusion/physical-plan/src/filter.rs
index 524da586f5..ffcda1d888 100644
--- a/datafusion/physical-plan/src/filter.rs
+++ b/datafusion/physical-plan/src/filter.rs
@@ -330,8 +330,7 @@ impl DisplayAs for FilterExec {
write!(f, "FilterExec: {}{}", self.predicate,
display_projections)
}
DisplayFormatType::TreeRender => {
- // TODO: collect info
- write!(f, "")
+ write!(f, "predicate={}", self.predicate)
}
}
}
diff --git a/datafusion/sqllogictest/test_files/explain_tree.slt
b/datafusion/sqllogictest/test_files/explain_tree.slt
index 5f07857820..18de2c6a61 100644
--- a/datafusion/sqllogictest/test_files/explain_tree.slt
+++ b/datafusion/sqllogictest/test_files/explain_tree.slt
@@ -74,13 +74,16 @@ physical_plan
03)└─────────────┬─────────────┘
04)┌─────────────┴─────────────┐
05)│ FilterExec │
-06)└─────────────┬─────────────┘
-07)┌─────────────┴─────────────┐
-08)│ RepartitionExec │
+06)│ -------------------- │
+07)│ predicate: │
+08)│ string_col@1 != foo │
09)└─────────────┬─────────────┘
10)┌─────────────┴─────────────┐
-11)│ DataSourceExec │
-12)└───────────────────────────┘
+11)│ RepartitionExec │
+12)└─────────────┬─────────────┘
+13)┌─────────────┴─────────────┐
+14)│ DataSourceExec │
+15)└───────────────────────────┘
# Aggregate
query TT
@@ -185,6 +188,32 @@ physical_plan
26)│ DataSourceExec ││ DataSourceExec │
27)└───────────────────────────┘└───────────────────────────┘
+# Long Filter (demonstrate what happens with wrapping)
+query TT
+explain SELECT int_col FROM table1
+WHERE string_col != 'foo' AND string_col != 'bar' AND string_col != 'a really
long string constant'
+;
+----
+logical_plan
+01)Projection: table1.int_col
+02)--Filter: table1.string_col != Utf8("foo") AND table1.string_col !=
Utf8("bar") AND table1.string_col != Utf8("a really long string constant")
+03)----TableScan: table1 projection=[int_col, string_col],
partial_filters=[table1.string_col != Utf8("foo"), table1.string_col !=
Utf8("bar"), table1.string_col != Utf8("a really long string constant")]
+physical_plan
+01)┌───────────────────────────┐
+02)│ CoalesceBatchesExec │
+03)└─────────────┬─────────────┘
+04)┌─────────────┴─────────────┐
+05)│ FilterExec │
+06)│ -------------------- │
+07)│ predicate: │
+08)│string_col@1 != foo AND ...│
+09)└─────────────┬─────────────┘
+10)┌─────────────┴─────────────┐
+11)│ RepartitionExec │
+12)└─────────────┬─────────────┘
+13)┌─────────────┴─────────────┐
+14)│ DataSourceExec │
+15)└───────────────────────────┘
# cleanup
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]