[SPARK-58544][SQL] Fix vector distance and norm functions returning wrong results from intermediate float overflow - #57746
Open
SEPURI-SAI-KRISHNA wants to merge 1 commit into
Conversation
…rong results from intermediate float overflow
uros-b
approved these changes
Aug 4, 2026
Member
|
Thank you @SEPURI-SAI-KRISHNA! Adding @MaxGekk to also PTAL |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes were proposed in this pull request?
VectorFunctionImplUtilsaccumulates dot products and sums of squares in single precision. Thoseintermediate quantities are quadratic in the input values, so they overflow to infinity (or
underflow to zero) long before the final result leaves the float range, and the function returns
NaN,Infinity,NULLor an all-zero vector for inputs whose true result is perfectlyrepresentable as a float.
This PR accumulates the intermediate dot products, sums of squares and absolute sums in
doubleand rounds only the final result back to
float.vector_normalizealso keeps the norm indoubleinstead of rounding it to a float before dividing, so a vector whose norm is outside thefloat range is still normalized correctly.
Affected functions:
vector_cosine_similarity,vector_inner_product,vector_l2_distance,vector_norm,vector_normalize.Why are the changes needed?
Cosine similarity and normalization are scale invariant, so rescaling the input must not change
the result -- but today it does:
vector_cosine_similarity(array(3.0e19F, 4.0e19F), array(3.0e19F, 4.0e19F))NaN1.0vector_cosine_similarity(array(1.0e-23F, 0.0F), array(1.0e-23F, 0.0F))NULL1.0vector_l2_distance(array(3.0e19F, 4.0e19F), array(0.0F, 0.0F))Infinity5.0E19vector_norm(array(3.0e19F, 4.0e19F), 2.0F)Infinity5.0E19vector_normalize(array(3.0e19F, 4.0e19F), 2.0F)[0.0, 0.0][0.6, 0.8]vector_normalize(array(1.0e-23F, 0.0F), 2.0F)NULL[1.0, 0.0]In every row above the correct result is an ordinary float; only the intermediate sum overflows
(
(3e19)^2 + (4e19)^2 = 2.5e39 > Float.MAX_VALUE) or underflows ((1e-23)^2 = 1e-46 < the smallest positive float). The wrong values are returned silently, so they propagate intosimilarity search results and rankings rather than failing loudly.
Double-precision accumulation is also what other vector similarity implementations do
(for example pgvector), and it removes a rounding error in the common case as well: the existing
vector_cosine_similarity(array(1.0F, 2.0F, 3.0F), array(4.0F, 5.0F, 6.0F))result changes from0.9746319to0.97463185, which is the correctly rounded float of32 / sqrt(1078)(
0.9746318461970763...).These functions were added in 4.2.0 by SPARK-54713 and SPARK-55030, so the wrong results are
present in the 4.2.0 release.
Documented behaviours are unchanged: empty vectors,
NULLinputs, vectors containingNULLelements, and genuinely zero-magnitude vectors return exactly what they returned before.
Does this PR introduce any user-facing change?
Yes. The functions listed above now return correct results instead of
NaN,Infinity,NULLor zeros when an intermediate sum overflows or underflows the float range, as shown in the table
above. This is a change relative to 4.2.0, where these functions were introduced.
vector_cosine_similarityalso changes by one ULP for ordinary inputs, because the result is nowcorrectly rounded (
0.9746319->0.97463185for the example above).How was this patch tested?
sql/core/src/test/resources/sql-tests/inputs/vector-distance.sqlandvector-norm.sqlcovering large and small magnitude vectors for all five functions; goldenfiles regenerated with
SPARK_GENERATE_GOLDEN_FILES=1.SQLQueryTestSuite(vector files),MiscFunctionsSuite,ExpressionInfoSuite(the
vector_cosine_similarityexample in@ExpressionDescriptionis updated to the correctlyrounded value).
On performance: the unrolled loops read through
ArrayData.getFloat()/isNullAt(), and thoseaccesses dominate the loop, so widening the accumulators is not measurable end to end. Timing the
vector_cosine_similarityloop over 1536-dimensionalUnsafeArrayDatainputs (200k calls, JITwarmed up) gives 5834 ns/call before and 5891 ns/call after in one run, and 5870 vs 5792 ns/call in
the next -- i.e. within run-to-run noise. The arithmetic in isolation (plain
float[], noArrayDataindirection) is ~1.3x slower, but it accounts for only ~20% of the loop cost.Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Opus 5)