aboutsummaryrefslogtreecommitdiff
path: root/sql/catalyst
diff options
context:
space:
mode:
authorCheng Lian <lian@databricks.com>2015-12-02 09:36:12 -0800
committerYin Huai <yhuai@databricks.com>2015-12-02 09:36:12 -0800
commita1542ce2f33ad365ff437d2d3014b9de2f6670e5 (patch)
treef8d4971f448fd987ccf88cc531c9ee9d7203a53d /sql/catalyst
parent128c29035b4e7383cc3a9a6c7a9ab6136205ac6c (diff)
downloadspark-a1542ce2f33ad365ff437d2d3014b9de2f6670e5.tar.gz
spark-a1542ce2f33ad365ff437d2d3014b9de2f6670e5.tar.bz2
spark-a1542ce2f33ad365ff437d2d3014b9de2f6670e5.zip
[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 #10099 from liancheng/prettier-tree-string.
Diffstat (limited to 'sql/catalyst')
-rw-r--r--sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/trees/TreeNode.scala31
1 files changed, 26 insertions, 5 deletions
diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/trees/TreeNode.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/trees/TreeNode.scala
index ad2bd78430..dfea583e01 100644
--- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/trees/TreeNode.scala
+++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/trees/TreeNode.scala
@@ -393,7 +393,7 @@ abstract class TreeNode[BaseType <: TreeNode[BaseType]] extends Product {
override def toString: String = treeString
/** Returns a string representation of the nodes in this tree */
- def treeString: String = generateTreeString(0, new StringBuilder).toString
+ def treeString: String = generateTreeString(0, Nil, new StringBuilder).toString
/**
* 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 {
}
}
- /** Appends the string represent of this node and its children to the given StringBuilder. */
- protected def generateTreeString(depth: Int, builder: StringBuilder): StringBuilder = {
- builder.append(" " * depth)
+ /**
+ * Appends the string represent of this node and its children to the given StringBuilder.
+ *
+ * The `i`-th element in `lastChildren` indicates whether the ancestor of the current node at
+ * depth `i + 1` is the last child of its own parent node. The depth of the root node is 0, and
+ * `lastChildren` for the root node should be empty.
+ */
+ protected def generateTreeString(
+ depth: Int, lastChildren: Seq[Boolean], builder: StringBuilder): StringBuilder = {
+ if (depth > 0) {
+ lastChildren.init.foreach { isLast =>
+ val prefixFragment = if (isLast) " " else ": "
+ builder.append(prefixFragment)
+ }
+
+ val branch = if (lastChildren.last) "+- " else ":- "
+ builder.append(branch)
+ }
+
builder.append(simpleString)
builder.append("\n")
- children.foreach(_.generateTreeString(depth + 1, builder))
+
+ if (children.nonEmpty) {
+ children.init.foreach(_.generateTreeString(depth + 1, lastChildren :+ false, builder))
+ children.last.generateTreeString(depth + 1, lastChildren :+ true, builder)
+ }
+
builder
}