[SPARK-58637][ML] Optimize HashingTF transform closure - #57845
[SPARK-58637][ML] Optimize HashingTF transform closure#57845zhengruifeng wants to merge 1 commit into
Conversation
|
Thank you @zhengruifeng! |
|
Nice optimization — pre-selecting the hash function and UDF avoids the per-term A few suggestions:
|
### What changes were proposed in this pull request? This PR optimizes `HashingTF.transform` by selecting the binary/counting UDF and hash function from `($(binary), hashFuncVersion)` before executing the UDF. The UDF calculates feature indexes from the captured hash function and local `numFeatures` value instead of calling the instance `indexOf` method. Binary mode uses `OpenHashMap.update`, while counting mode uses `changeValue`. Both store integer term counts and convert them to `Double` only when constructing the output sparse vector. The compatibility test for HashingTF models saved before Spark 3.0 now also verifies `transform`, including the saved binary mode and legacy hash function. ### Why are the changes needed? Calling `indexOf` from the UDF captures the `HashingTF` transformer and performs a parameter lookup and hash-version match for every term. Selecting the behavior before constructing the UDF reduces the closure to the values it needs, removes repeated branching and parameter lookups, and reduces the term-count map value size from `Double` to `Int`. ### Does this PR introduce _any_ user-facing change? No. ### How was this patch tested? `build/sbt -java-home /usr/lib/jvm/java-17-openjdk-amd64 'mllib/testOnly org.apache.spark.ml.feature.HashingTFSuite'` All 6 tests passed. The compiled UDF helper signatures were also inspected to confirm that they do not retain a `HashingTF` receiver. ### Was this patch authored or co-authored using generative AI tooling? Generated-by: Codex (GPT-5) Closes #57845 from zhengruifeng/SPARK-58637. Authored-by: Ruifeng Zheng <ruifengz@apache.org> Signed-off-by: Ruifeng Zheng <ruifengz@foxmail.com> (cherry picked from commit 8210537) Signed-off-by: Ruifeng Zheng <ruifengz@foxmail.com>
What changes were proposed in this pull request?
This PR optimizes
HashingTF.transformby selecting the binary/counting UDF and hash functionfrom
($(binary), hashFuncVersion)before executing the UDF. The UDF calculates feature indexesfrom the captured hash function and local
numFeaturesvalue instead of calling the instanceindexOfmethod.Binary mode uses
OpenHashMap.update, while counting mode useschangeValue. Both store integerterm counts and convert them to
Doubleonly when constructing the output sparse vector.The compatibility test for HashingTF models saved before Spark 3.0 now also verifies
transform,including the saved binary mode and legacy hash function.
Why are the changes needed?
Calling
indexOffrom the UDF captures theHashingTFtransformer and performs a parameter lookupand hash-version match for every term. Selecting the behavior before constructing the UDF reduces
the closure to the values it needs, removes repeated branching and parameter lookups, and reduces
the term-count map value size from
DoubletoInt.Does this PR introduce any user-facing change?
No.
How was this patch tested?
build/sbt -java-home /usr/lib/jvm/java-17-openjdk-amd64 'mllib/testOnly org.apache.spark.ml.feature.HashingTFSuite'All 6 tests passed. The compiled UDF helper signatures were also inspected to confirm that they do
not retain a
HashingTFreceiver.Was this patch authored or co-authored using generative AI tooling?
Generated-by: Codex (GPT-5)