You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by ur...@apache.org on 2026/08/12 09:42:52 UTC
(spark) branch branch-4.3 updated: [SPARK-58710][MLLIB] Remove unused members from the decision tree Node classes
This is an automated email from the ASF dual-hosted git repository.
uros-b pushed a commit to branch branch-4.3
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/branch-4.3 by this push:
new fdaaaae41456 [SPARK-58710][MLLIB] Remove unused members from the decision tree Node classes
fdaaaae41456 is described below
commit fdaaaae41456bebc46139f7301bf1471cbd7228d
Author: Uros Bojanic <22...@users.noreply.github.com>
AuthorDate: Wed Aug 12 09:42:24 2026 +0000
[SPARK-58710][MLLIB] Remove unused members from the decision tree Node classes
### What changes were proposed in this pull request?
Removes members with no callers from the two decision tree `Node` files.
`mllib/tree/model/Node.scala`: `deepCopy`, and the companion helpers `isLeftChild`, `maxNodesInLevel`, `startIndexInLevel`, `emptyNode`, `parentIndex`, `getNode`, `indexToLevel`.
`ml/tree/Node.scala`: the `deepCopy` declaration and its two overrides, plus `parentIndex`, `isLeftChild`, `maxNodesInLevel`, `startIndexInLevel`, `getNode`.
### Why are the changes needed?
None of these has a caller. `deepCopy` is reachable only from itself, so the declaration and both overrides are dead as a unit. The last callers of the indexing helpers disappeared when the decision tree implementation moved from `spark.mllib` to `spark.ml`.
Both files are covered because `ml/tree/Node.scala` carries the comment `// The below indexing methods were copied from spark.mllib.tree.model.Node`, so removing only the original would leave the labelled copy behind.
The live members are kept: `apply`, `leftChildIndex` and `rightChildIndex` in both objects, plus `emptyNode` and `indexToLevel` in `LearningNode`, which `RandomForest` still calls.
### Does this PR introduce _any_ user-facing change?
No. The `mllib` companion object is `private[spark]` and `deepCopy` is `private[tree]`, so nothing removed is public API. `GenerateMIMAIgnore` already excludes package-private members, so no `MimaExcludes` entry is required.
### How was this patch tested?
Pure removal of unreferenced code; no test references any removed member. Deadness was checked for each name across all file types, and dynamic reachability was ruled out explicitly: none appears as a string literal, there is no reflection or codegen in either tree package, and no MiMa filter names them. The two `Node` hierarchies are unrelated (`ml` imports the `mllib` one under an alias), so removing from one cannot affect the other.
### Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Opus 4.8)
Closes #57928 from uros-b/deadcode-mllib-node-unused.
Authored-by: Uros Bojanic <22...@users.noreply.github.com>
Signed-off-by: Uros Bojanic <22...@users.noreply.github.com>
(cherry picked from commit 0a9c89fb43e2cb3b0349698eadd6304f0a23a0d1)
Signed-off-by: Uros Bojanic <22...@users.noreply.github.com>
---
.../main/scala/org/apache/spark/ml/tree/Node.scala | 53 ----------------
.../org/apache/spark/mllib/tree/model/Node.scala | 73 ----------------------
2 files changed, 126 deletions(-)
diff --git a/mllib/src/main/scala/org/apache/spark/ml/tree/Node.scala b/mllib/src/main/scala/org/apache/spark/ml/tree/Node.scala
index b68a5e079dc4..a52b79b377fa 100644
--- a/mllib/src/main/scala/org/apache/spark/ml/tree/Node.scala
+++ b/mllib/src/main/scala/org/apache/spark/ml/tree/Node.scala
@@ -77,9 +77,6 @@ sealed abstract class Node extends Serializable {
* @return Max feature index used in a split, or -1 if there are no splits (single leaf node).
*/
private[ml] def maxSplitFeatureIndex(): Int
-
- /** Returns a deep copy of the subtree rooted at this node. */
- private[tree] def deepCopy(): Node
}
private[ml] object Node {
@@ -146,10 +143,6 @@ class LeafNode private[ml] (
}
override private[ml] def maxSplitFeatureIndex(): Int = -1
-
- override private[tree] def deepCopy(): Node = {
- new LeafNode(prediction, impurity, impurityStats)
- }
}
/**
@@ -238,11 +231,6 @@ class InternalNode private[ml] (
math.max(split.featureIndex,
math.max(leftChild.maxSplitFeatureIndex(), rightChild.maxSplitFeatureIndex()))
}
-
- override private[tree] def deepCopy(): Node = {
- new InternalNode(prediction, impurity, gain, leftChild.deepCopy(), rightChild.deepCopy(),
- split, impurityStats)
- }
}
private object InternalNode {
@@ -393,11 +381,6 @@ private[tree] object LearningNode {
*/
def rightChildIndex(nodeIndex: Int): Int = (nodeIndex << 1) + 1
- /**
- * Get the parent index of the given node, or 0 if it is the root.
- */
- def parentIndex(nodeIndex: Int): Int = nodeIndex >> 1
-
/**
* Return the level of a tree which the given node is in.
*/
@@ -407,40 +390,4 @@ private[tree] object LearningNode {
java.lang.Integer.numberOfTrailingZeros(java.lang.Integer.highestOneBit(nodeIndex))
}
- /**
- * Returns true if this is a left child.
- * Note: Returns false for the root.
- */
- def isLeftChild(nodeIndex: Int): Boolean = nodeIndex > 1 && nodeIndex % 2 == 0
-
- /**
- * Return the maximum number of nodes which can be in the given level of the tree.
- * @param level Level of tree (0 = root).
- */
- def maxNodesInLevel(level: Int): Int = 1 << level
-
- /**
- * Return the index of the first node in the given level.
- * @param level Level of tree (0 = root).
- */
- def startIndexInLevel(level: Int): Int = 1 << level
-
- /**
- * Traces down from a root node to get the node with the given node index.
- * This assumes the node exists.
- */
- def getNode(nodeIndex: Int, rootNode: LearningNode): LearningNode = {
- var tmpNode: LearningNode = rootNode
- var levelsToGo = indexToLevel(nodeIndex)
- while (levelsToGo > 0) {
- if ((nodeIndex & (1 << levelsToGo - 1)) == 0) {
- tmpNode = tmpNode.leftChild.get
- } else {
- tmpNode = tmpNode.rightChild.get
- }
- levelsToGo -= 1
- }
- tmpNode
- }
-
}
diff --git a/mllib/src/main/scala/org/apache/spark/mllib/tree/model/Node.scala b/mllib/src/main/scala/org/apache/spark/mllib/tree/model/Node.scala
index a0eec8b2afb9..6ac0bfdc7b63 100644
--- a/mllib/src/main/scala/org/apache/spark/mllib/tree/model/Node.scala
+++ b/mllib/src/main/scala/org/apache/spark/mllib/tree/model/Node.scala
@@ -80,23 +80,6 @@ class Node @Since("1.2.0") (
}
}
- /**
- * Returns a deep copy of the subtree rooted at this node.
- */
- private[tree] def deepCopy(): Node = {
- val leftNodeCopy = if (leftNode.isEmpty) {
- None
- } else {
- Some(leftNode.get.deepCopy())
- }
- val rightNodeCopy = if (rightNode.isEmpty) {
- None
- } else {
- Some(rightNode.get.deepCopy())
- }
- new Node(id, predict, impurity, isLeaf, split, leftNodeCopy, rightNodeCopy, stats)
- }
-
/**
* Get the number of nodes in tree below this node, including leaf nodes.
* E.g., if this is a leaf, returns 0. If both children are leaves, returns 2.
@@ -157,12 +140,6 @@ class Node @Since("1.2.0") (
private[spark] object Node {
- /**
- * Return a node with the given node id (but nothing else set).
- */
- def emptyNode(nodeIndex: Int): Node = new Node(nodeIndex, new Predict(Double.MinValue), -1.0,
- false, None, None, None, None)
-
/**
* Construct a node with nodeIndex, predict, impurity and isLeaf parameters.
* This is used in `DecisionTree.findBestSplits` to construct child nodes
@@ -192,54 +169,4 @@ private[spark] object Node {
*/
def rightChildIndex(nodeIndex: Int): Int = (nodeIndex << 1) + 1
- /**
- * Get the parent index of the given node, or 0 if it is the root.
- */
- def parentIndex(nodeIndex: Int): Int = nodeIndex >> 1
-
- /**
- * Return the level of a tree which the given node is in.
- */
- def indexToLevel(nodeIndex: Int): Int = if (nodeIndex == 0) {
- throw new IllegalArgumentException(s"0 is not a valid node index.")
- } else {
- java.lang.Integer.numberOfTrailingZeros(java.lang.Integer.highestOneBit(nodeIndex))
- }
-
- /**
- * Returns true if this is a left child.
- * Note: Returns false for the root.
- */
- def isLeftChild(nodeIndex: Int): Boolean = nodeIndex > 1 && nodeIndex % 2 == 0
-
- /**
- * Return the maximum number of nodes which can be in the given level of the tree.
- * @param level Level of tree (0 = root).
- */
- def maxNodesInLevel(level: Int): Int = 1 << level
-
- /**
- * Return the index of the first node in the given level.
- * @param level Level of tree (0 = root).
- */
- def startIndexInLevel(level: Int): Int = 1 << level
-
- /**
- * Traces down from a root node to get the node with the given node index.
- * This assumes the node exists.
- */
- def getNode(nodeIndex: Int, rootNode: Node): Node = {
- var tmpNode: Node = rootNode
- var levelsToGo = indexToLevel(nodeIndex)
- while (levelsToGo > 0) {
- if ((nodeIndex & (1 << levelsToGo - 1)) == 0) {
- tmpNode = tmpNode.leftNode.get
- } else {
- tmpNode = tmpNode.rightNode.get
- }
- levelsToGo -= 1
- }
- tmpNode
- }
-
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org