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 9382add72b Improve parsing `extra_info` in tree explain (#15125)
9382add72b is described below

commit 9382add72b929c553ca4976d1423d8ebbc80889d
Author: irenjj <[email protected]>
AuthorDate: Tue Mar 11 03:11:16 2025 +0800

    Improve parsing `extra_info` in tree explain (#15125)
    
    * Improve parsing `extra_info` in tree explain
    
    * Improve documentation and CrossJoinDisplay
    
    ---------
    
    Co-authored-by: Andrew Lamb <[email protected]>
---
 datafusion/physical-plan/src/display.rs            |  24 ++--
 datafusion/physical-plan/src/joins/cross_join.rs   |   8 +-
 datafusion/physical-plan/src/render_tree.rs        |   3 +
 datafusion/physical-plan/src/sorts/partial_sort.rs |   6 +-
 datafusion/physical-plan/src/sorts/sort.rs         |   6 +-
 .../sqllogictest/test_files/explain_tree.slt       | 157 ++++++++++-----------
 6 files changed, 103 insertions(+), 101 deletions(-)

diff --git a/datafusion/physical-plan/src/display.rs 
b/datafusion/physical-plan/src/display.rs
index 98ba3e1fd9..59d5e60ca9 100644
--- a/datafusion/physical-plan/src/display.rs
+++ b/datafusion/physical-plan/src/display.rs
@@ -52,14 +52,18 @@ pub enum DisplayFormatType {
     /// 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.
+    /// In this mode, each line has one of two formats:
+    ///
+    /// 1. A string without a `=`, which is printed in its own line
+    ///
+    /// 2. A string with a `=` that is treated as 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
+    /// Parquet
     /// partition_sizes=[1]
-    /// partitions=1
     /// ```
     ///
     /// It is rendered in the center of a box in the following way:
@@ -69,7 +73,7 @@ pub enum DisplayFormatType {
     /// │       DataSourceExec      │
     /// │    --------------------   │
     /// │    partition_sizes: [1]   │
-    /// │       partitions: 1       │
+    /// │          Parquet          │
     /// └───────────────────────────┘
     ///  ```
     TreeRender,
@@ -857,22 +861,24 @@ impl TreeRenderVisitor<'_, '_> {
         let sorted_extra_info: BTreeMap<_, _> = extra_info.iter().collect();
         for (key, value) in sorted_extra_info {
             let mut str = Self::remove_padding(value);
-            if str.is_empty() {
-                continue;
-            }
             let mut is_inlined = false;
             let available_width = Self::NODE_RENDER_WIDTH - 7;
             let total_size = key.len() + str.len() + 2;
             let is_multiline = str.contains('\n');
-            if !is_multiline && total_size < available_width {
+
+            if str.is_empty() {
+                str = key.to_string();
+            } else if !is_multiline && total_size < available_width {
                 str = format!("{}: {}", key, str);
                 is_inlined = true;
             } else {
                 str = format!("{}:\n{}", key, str);
             }
+
             if is_inlined && was_inlined {
                 requires_padding = false;
             }
+
             if requires_padding {
                 result.push(String::new());
             }
diff --git a/datafusion/physical-plan/src/joins/cross_join.rs 
b/datafusion/physical-plan/src/joins/cross_join.rs
index e0998862bd..35c8961065 100644
--- a/datafusion/physical-plan/src/joins/cross_join.rs
+++ b/datafusion/physical-plan/src/joins/cross_join.rs
@@ -237,11 +237,13 @@ impl DisplayAs for CrossJoinExec {
         f: &mut std::fmt::Formatter,
     ) -> std::fmt::Result {
         match t {
-            DisplayFormatType::Default
-            | DisplayFormatType::Verbose
-            | DisplayFormatType::TreeRender => {
+            DisplayFormatType::Default | DisplayFormatType::Verbose => {
                 write!(f, "CrossJoinExec")
             }
+            DisplayFormatType::TreeRender => {
+                // no extra info to display
+                Ok(())
+            }
         }
     }
 }
diff --git a/datafusion/physical-plan/src/render_tree.rs 
b/datafusion/physical-plan/src/render_tree.rs
index 5f8da76a89..f86e4c55e7 100644
--- a/datafusion/physical-plan/src/render_tree.rs
+++ b/datafusion/physical-plan/src/render_tree.rs
@@ -198,9 +198,12 @@ fn create_tree_recursive(
     let mut extra_info = HashMap::new();
 
     // Parse the key-value pairs from the formatted string.
+    // See DisplayFormatType::TreeRender for details
     for line in display_info.lines() {
         if let Some((key, value)) = line.split_once('=') {
             extra_info.insert(key.to_string(), value.to_string());
+        } else {
+            extra_info.insert(line.to_string(), "".to_string());
         }
     }
 
diff --git a/datafusion/physical-plan/src/sorts/partial_sort.rs 
b/datafusion/physical-plan/src/sorts/partial_sort.rs
index 4cff0fedfa..5277a50b85 100644
--- a/datafusion/physical-plan/src/sorts/partial_sort.rs
+++ b/datafusion/physical-plan/src/sorts/partial_sort.rs
@@ -228,11 +228,11 @@ impl DisplayAs for PartialSortExec {
             }
             DisplayFormatType::TreeRender => match self.fetch {
                 Some(fetch) => {
-                    writeln!(f, "limit={fetch}")?;
-                    writeln!(f, "sort keys={}", self.expr)
+                    writeln!(f, "{}", self.expr)?;
+                    writeln!(f, "limit={fetch}")
                 }
                 None => {
-                    writeln!(f, "sort keys={}", self.expr)
+                    writeln!(f, "{}", self.expr)
                 }
             },
         }
diff --git a/datafusion/physical-plan/src/sorts/sort.rs 
b/datafusion/physical-plan/src/sorts/sort.rs
index 0b62925426..3d2323eb43 100644
--- a/datafusion/physical-plan/src/sorts/sort.rs
+++ b/datafusion/physical-plan/src/sorts/sort.rs
@@ -1007,11 +1007,11 @@ impl DisplayAs for SortExec {
             }
             DisplayFormatType::TreeRender => match self.fetch {
                 Some(fetch) => {
-                    writeln!(f, "limit={fetch}")?;
-                    writeln!(f, "sort keys=[{}]", self.expr)
+                    writeln!(f, "{}", self.expr)?;
+                    writeln!(f, "limit={fetch}")
                 }
                 None => {
-                    writeln!(f, "sort keys=[{}]", self.expr)
+                    writeln!(f, "{}", self.expr)
                 }
             },
         }
diff --git a/datafusion/sqllogictest/test_files/explain_tree.slt 
b/datafusion/sqllogictest/test_files/explain_tree.slt
index d81d83ea42..be926c0fc9 100644
--- a/datafusion/sqllogictest/test_files/explain_tree.slt
+++ b/datafusion/sqllogictest/test_files/explain_tree.slt
@@ -674,17 +674,16 @@ physical_plan
 23)┌─────────────┴─────────────┐
 24)│          SortExec         │
 25)│    --------------------   │
-26)│         sort keys:        │
-27)│   [v1@0 ASC NULLS LAST]   │
-28)└─────────────┬─────────────┘
-29)┌─────────────┴─────────────┐
-30)│       ProjectionExec      │
-31)│    --------------------   │
-32)│        v1: value@0        │
-33)└─────────────┬─────────────┘
-34)┌─────────────┴─────────────┐
-35)│       LazyMemoryExec      │
-36)└───────────────────────────┘
+26)│    v1@0 ASC NULLS LAST    │
+27)└─────────────┬─────────────┘
+28)┌─────────────┴─────────────┐
+29)│       ProjectionExec      │
+30)│    --------------------   │
+31)│        v1: value@0        │
+32)└─────────────┬─────────────┘
+33)┌─────────────┴─────────────┐
+34)│       LazyMemoryExec      │
+35)└───────────────────────────┘
 
 query TT
 explain select 
@@ -745,16 +744,14 @@ physical_plan
 01)┌───────────────────────────┐
 02)│          SortExec         │
 03)│    --------------------   │
-04)│         sort keys:        │
-05)│  [string_col@1 ASC NULLS  │
-06)│            LAST]          │
-07)└─────────────┬─────────────┘
-08)┌─────────────┴─────────────┐
-09)│       DataSourceExec      │
-10)│    --------------------   │
-11)│          files: 1         │
-12)│        format: csv        │
-13)└───────────────────────────┘
+04)│string_col@1 ASC NULLS LAST│
+05)└─────────────┬─────────────┘
+06)┌─────────────┴─────────────┐
+07)│       DataSourceExec      │
+08)│    --------------------   │
+09)│          files: 1         │
+10)│        format: csv        │
+11)└───────────────────────────┘
 
 # Query for sort with limit.
 query TT
@@ -769,16 +766,14 @@ physical_plan
 03)│    --------------------   │
 04)│          limit: 1         │
 05)│                           │
-06)│         sort keys:        │
-07)│  [string_col@1 ASC NULLS  │
-08)│            LAST]          │
-09)└─────────────┬─────────────┘
-10)┌─────────────┴─────────────┐
-11)│       DataSourceExec      │
-12)│    --------------------   │
-13)│          files: 1         │
-14)│        format: csv        │
-15)└───────────────────────────┘
+06)│string_col@1 ASC NULLS LAST│
+07)└─────────────┬─────────────┘
+08)┌─────────────┴─────────────┐
+09)│       DataSourceExec      │
+10)│    --------------------   │
+11)│          files: 1         │
+12)│        format: csv        │
+13)└───────────────────────────┘
 
 # Query with projection on csv
 query TT
@@ -865,33 +860,31 @@ physical_plan
 41)┌─────────────┴─────────────┐
 42)│          SortExec         │
 43)│    --------------------   │
-44)│         sort keys:        │
-45)│ [int_col@0 ASC NULLS LAST]│
-46)└─────────────┬─────────────┘
-47)┌─────────────┴─────────────┐
-48)│    BoundedWindowAggExec   │
-49)│    --------------------   │
-50)│        mode: Sorted       │
-51)│                           │
-52)│        select_list:       │
-53)│  rank() ORDER BY [table1  │
-54)│    .int_col DESC NULLS    │
-55)│    FIRST] RANGE BETWEEN   │
-56)│   UNBOUNDED PRECEDING AND │
-57)│         CURRENT ROW       │
-58)└─────────────┬─────────────┘
-59)┌─────────────┴─────────────┐
-60)│          SortExec         │
-61)│    --------------------   │
-62)│         sort keys:        │
-63)│      [int_col@0 DESC]     │
-64)└─────────────┬─────────────┘
-65)┌─────────────┴─────────────┐
-66)│       DataSourceExec      │
-67)│    --------------------   │
-68)│          files: 1         │
-69)│        format: csv        │
-70)└───────────────────────────┘
+44)│  int_col@0 ASC NULLS LAST │
+45)└─────────────┬─────────────┘
+46)┌─────────────┴─────────────┐
+47)│    BoundedWindowAggExec   │
+48)│    --------------------   │
+49)│        mode: Sorted       │
+50)│                           │
+51)│        select_list:       │
+52)│  rank() ORDER BY [table1  │
+53)│    .int_col DESC NULLS    │
+54)│    FIRST] RANGE BETWEEN   │
+55)│   UNBOUNDED PRECEDING AND │
+56)│         CURRENT ROW       │
+57)└─────────────┬─────────────┘
+58)┌─────────────┴─────────────┐
+59)│          SortExec         │
+60)│    --------------------   │
+61)│       int_col@0 DESC      │
+62)└─────────────┬─────────────┘
+63)┌─────────────┴─────────────┐
+64)│       DataSourceExec      │
+65)│    --------------------   │
+66)│          files: 1         │
+67)│        format: csv        │
+68)└───────────────────────────┘
 
 # Query with projection on parquet
 query TT
@@ -1025,17 +1018,16 @@ physical_plan
 01)┌───────────────────────────┐
 02)│      PartialSortExec      │
 03)│    --------------------   │
-04)│         sort keys:        │
-05)│  a@1 ASC NULLS LAST, b@2  │
-06)│     ASC NULLS LAST, d@4   │
-07)│       ASC NULLS LAST      │
-08)└─────────────┬─────────────┘
-09)┌─────────────┴─────────────┐
-10)│     StreamingTableExec    │
-11)│    --------------------   │
-12)│       infinite: true      │
-13)│        limit: None        │
-14)└───────────────────────────┘
+04)│  a@1 ASC NULLS LAST, b@2  │
+05)│     ASC NULLS LAST, d@4   │
+06)│       ASC NULLS LAST      │
+07)└─────────────┬─────────────┘
+08)┌─────────────┴─────────────┐
+09)│     StreamingTableExec    │
+10)│    --------------------   │
+11)│       infinite: true      │
+12)│        limit: None        │
+13)└───────────────────────────┘
 
 query TT
 EXPLAIN SELECT *
@@ -1050,19 +1042,18 @@ physical_plan
 01)┌───────────────────────────┐
 02)│      PartialSortExec      │
 03)│    --------------------   │
-04)│         limit: 50         │
-05)│                           │
-06)│         sort keys:        │
-07)│  a@1 ASC NULLS LAST, b@2  │
-08)│     ASC NULLS LAST, d@4   │
-09)│       ASC NULLS LAST      │
-10)└─────────────┬─────────────┘
-11)┌─────────────┴─────────────┐
-12)│     StreamingTableExec    │
-13)│    --------------------   │
-14)│       infinite: true      │
-15)│        limit: None        │
-16)└───────────────────────────┘
+04)│  a@1 ASC NULLS LAST, b@2  │
+05)│     ASC NULLS LAST, d@4   │
+06)│       ASC NULLS LAST      │
+07)│                           │
+08)│         limit: 50         │
+09)└─────────────┬─────────────┘
+10)┌─────────────┴─────────────┐
+11)│     StreamingTableExec    │
+12)│    --------------------   │
+13)│       infinite: true      │
+14)│        limit: None        │
+15)└───────────────────────────┘
 
 # Query with hash join.
 query TT
@@ -1270,7 +1261,7 @@ physical_plan
 06)┌─────────────┴─────────────┐┌─────────────┴─────────────┐
 07)│          SortExec         ││          SortExec         │
 08)│    --------------------   ││    --------------------   │
-09)│   sort keys: [c1@0 ASC]   ││   sort keys: [c1@0 ASC]   │
+09)│          c1@0 ASC         ││          c1@0 ASC         │
 10)└─────────────┬─────────────┘└─────────────┬─────────────┘
 11)┌─────────────┴─────────────┐┌─────────────┴─────────────┐
 12)│       DataSourceExec      ││       DataSourceExec      │


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to