Skip to content

Commit f449a40

Browse files
lianchengyhuai
authored andcommitted
[SPARK-12094][SQL] Prettier tree string for TreeNode
When examining plans of complex queries with multiple joins, a pain point of mine is that, it's hard to immediately see the sibling node of a specific query plan node. This PR adds tree lines for the tree string of a `TreeNode`, so that the result can be visually more intuitive. Author: Cheng Lian <lian@databricks.com> Closes apache#10099 from liancheng/prettier-tree-string. (cherry picked from commit a1542ce) Signed-off-by: Yin Huai <yhuai@databricks.com>
1 parent d79dd97 commit f449a40

File tree

1 file changed

+26
-5
lines changed
  • sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/trees

1 file changed

+26
-5
lines changed

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/trees/TreeNode.scala

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ abstract class TreeNode[BaseType <: TreeNode[BaseType]] extends Product {
393393
override def toString: String = treeString
394394

395395
/** Returns a string representation of the nodes in this tree */
396-
def treeString: String = generateTreeString(0, new StringBuilder).toString
396+
def treeString: String = generateTreeString(0, Nil, new StringBuilder).toString
397397

398398
/**
399399
* Returns a string representation of the nodes in this tree, where each operator is numbered.
@@ -419,12 +419,33 @@ abstract class TreeNode[BaseType <: TreeNode[BaseType]] extends Product {
419419
}
420420
}
421421

422-
/** Appends the string represent of this node and its children to the given StringBuilder. */
423-
protected def generateTreeString(depth: Int, builder: StringBuilder): StringBuilder = {
424-
builder.append(" " * depth)
422+
/**
423+
* Appends the string represent of this node and its children to the given StringBuilder.
424+
*
425+
* The `i`-th element in `lastChildren` indicates whether the ancestor of the current node at
426+
* depth `i + 1` is the last child of its own parent node. The depth of the root node is 0, and
427+
* `lastChildren` for the root node should be empty.
428+
*/
429+
protected def generateTreeString(
430+
depth: Int, lastChildren: Seq[Boolean], builder: StringBuilder): StringBuilder = {
431+
if (depth > 0) {
432+
lastChildren.init.foreach { isLast =>
433+
val prefixFragment = if (isLast) " " else ": "
434+
builder.append(prefixFragment)
435+
}
436+
437+
val branch = if (lastChildren.last) "+- " else ":- "
438+
builder.append(branch)
439+
}
440+
425441
builder.append(simpleString)
426442
builder.append("\n")
427-
children.foreach(_.generateTreeString(depth + 1, builder))
443+
444+
if (children.nonEmpty) {
445+
children.init.foreach(_.generateTreeString(depth + 1, lastChildren :+ false, builder))
446+
children.last.generateTreeString(depth + 1, lastChildren :+ true, builder)
447+
}
448+
428449
builder
429450
}
430451

0 commit comments

Comments
 (0)