You are viewing a plain text version of this content. The canonical link for it is here.
Posted to reviews@spark.apache.org by "SEPURI-SAI-KRISHNA (via GitHub)" <gi...@apache.org> on 2026/08/04 07:21:05 UTC

[PR] [SPARK-58544][SQL] Fix vector distance and norm functions returning wrong results from intermediate float overflow [spark]

SEPURI-SAI-KRISHNA opened a new pull request, #57746:
URL: https://github.com/apache/spark/pull/57746

   ### What changes were proposed in this pull request?
   
   `VectorFunctionImplUtils` accumulates dot products and sums of squares in single precision. Those
   intermediate 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`, `NULL` or an all-zero vector for inputs whose true result is perfectly
   representable as a float.
   
   This PR accumulates the intermediate dot products, sums of squares and absolute sums in `double`
   and rounds only the final result back to `float`. `vector_normalize` also keeps the norm in
   `double` instead of rounding it to a float before dividing, so a vector whose norm is outside the
   float 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:
   
   | Query | Before | After (correct) |
   | --- | --- | --- |
   | `vector_cosine_similarity(array(3.0e19F, 4.0e19F), array(3.0e19F, 4.0e19F))` | `NaN` | `1.0` |
   | `vector_cosine_similarity(array(1.0e-23F, 0.0F), array(1.0e-23F, 0.0F))` | `NULL` | `1.0` |
   | `vector_l2_distance(array(3.0e19F, 4.0e19F), array(0.0F, 0.0F))` | `Infinity` | `5.0E19` |
   | `vector_norm(array(3.0e19F, 4.0e19F), 2.0F)` | `Infinity` | `5.0E19` |
   | `vector_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 into
   similarity 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 from
   `0.9746319` to `0.97463185`, which is the correctly rounded float of `32 / 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, `NULL` inputs, vectors containing `NULL`
   elements, 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`, `NULL`
   or 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_similarity` also changes by one ULP for ordinary inputs, because the result is now
   correctly rounded (`0.9746319` -> `0.97463185` for the example above).
   
   ### How was this patch tested?
   
   - New golden test cases in `sql/core/src/test/resources/sql-tests/inputs/vector-distance.sql` and
     `vector-norm.sql` covering large and small magnitude vectors for all five functions; golden
     files regenerated with `SPARK_GENERATE_GOLDEN_FILES=1`.
   - Existing suites: `SQLQueryTestSuite` (vector files), `MiscFunctionsSuite`, `ExpressionInfoSuite`
     (the `vector_cosine_similarity` example in `@ExpressionDescription` is updated to the correctly
     rounded value).
   
   On performance: the unrolled loops read through `ArrayData.getFloat()` / `isNullAt()`, and those
   accesses dominate the loop, so widening the accumulators is not measurable end to end. Timing the
   `vector_cosine_similarity` loop over 1536-dimensional `UnsafeArrayData` inputs (200k calls, JIT
   warmed 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[]`, no
   `ArrayData` indirection) 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)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-58544][SQL] Fix vector distance and norm functions returning wrong results from intermediate float overflow [spark]

Posted by "cloud-fan (via GitHub)" <gi...@apache.org>.
cloud-fan commented on code in PR #57746:
URL: https://github.com/apache/spark/pull/57746#discussion_r3737581383


##########
sql/core/src/test/resources/sql-tests/inputs/vector-distance.sql:
##########
@@ -130,3 +130,38 @@ SELECT vector_l2_distance(
     array(1.0F, 2.0F, 3.0F, 4.0F, 5.0F, 6.0F, 7.0F, 8.0F, 9.0F, 10.0F, 11.0F, 12.0F, 13.0F, 14.0F, 15.0F, 16.0F),
     array(16.0F, 15.0F, 14.0F, 13.0F, 12.0F, 11.0F, 10.0F, 9.0F, 8.0F, 7.0F, 6.0F, 5.0F, 4.0F, 3.0F, 2.0F, 1.0F)
 );
+
+-- SPARK-58544: large magnitudes, intermediate sums of squares/products must not overflow the
+-- float range
+
+-- vector_cosine_similarity is scale invariant: identical vectors have similarity 1.0
+SELECT vector_cosine_similarity(array(3.0e19F, 4.0e19F), array(3.0e19F, 4.0e19F));
+
+-- vector_cosine_similarity: opposite vectors have similarity -1.0
+SELECT vector_cosine_similarity(array(3.0e19F, 4.0e19F), array(-3.0e19F, -4.0e19F));
+
+-- vector_inner_product: individual products overflow the float range but cancel out
+SELECT vector_inner_product(array(1.0e20F, 1.0e20F), array(1.0e20F, -1.0e20F));
+
+-- vector_l2_distance: sqrt((3e19)^2 + (4e19)^2) = 5e19
+SELECT vector_l2_distance(array(3.0e19F, 4.0e19F), array(0.0F, 0.0F));
+
+-- SPARK-58544: small magnitudes, intermediate sums of squares/products must not underflow to zero
+
+-- vector_cosine_similarity of identical tiny vectors is 1.0, not NULL
+SELECT vector_cosine_similarity(array(1.0e-23F, 0.0F), array(1.0e-23F, 0.0F));
+
+-- vector_cosine_similarity of orthogonal tiny vectors is 0.0, not NULL
+SELECT vector_cosine_similarity(array(1.0e-23F, 1.0e-23F), array(1.0e-23F, -1.0e-23F));
+
+-- SPARK-58544: elements that are already infinite still propagate to NaN or Infinity, the wider

Review Comment:
   Please replace this comma splice with a semicolon. The parallel comment in `vector-norm.sql:181` needs the same edit.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-58544][SQL] Fix vector distance and norm functions returning wrong results from intermediate float overflow [spark]

Posted by "uros-b (via GitHub)" <gi...@apache.org>.
uros-b commented on PR #57746:
URL: https://github.com/apache/spark/pull/57746#issuecomment-5179456200

   Thank you @SEPURI-SAI-KRISHNA! Adding @MaxGekk to also PTAL


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-58544][SQL] Fix vector distance and norm functions returning wrong results from intermediate float overflow [spark]

Posted by "SEPURI-SAI-KRISHNA (via GitHub)" <gi...@apache.org>.
SEPURI-SAI-KRISHNA commented on code in PR #57746:
URL: https://github.com/apache/spark/pull/57746#discussion_r3730126957


##########
sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/VectorFunctionImplUtils.java:
##########
@@ -448,6 +460,21 @@ public static Float vectorNorm(ArrayData vec, float degree, UTF8String funcName)
     }
   }
 
+  /**
+   * Computes the Lp norm of a float vector using the specified degree.
+   * Supported degrees: 1.0 (L1), 2.0 (L2), Float.POSITIVE_INFINITY (L∞).

Review Comment:
   Applied. I also changed the identical line in the `vectorNormalize` javadoc (line 480) so the two match; both were pre-existing



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-58544][SQL] Fix vector distance and norm functions returning wrong results from intermediate float overflow [spark]

Posted by "SEPURI-SAI-KRISHNA (via GitHub)" <gi...@apache.org>.
SEPURI-SAI-KRISHNA commented on code in PR #57746:
URL: https://github.com/apache/spark/pull/57746#discussion_r3730137971


##########
sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/VectorFunctionImplUtils.java:
##########
@@ -90,19 +93,22 @@ public static Float vectorCosineSimilarity(ArrayData left, ArrayData right, UTF8
       if (left.isNullAt(i) || right.isNullAt(i)) {
         return null;
       }
-      float a = left.getFloat(i);
-      float b = right.getFloat(i);
+      double a = left.getFloat(i);
+      double b = right.getFloat(i);
       dotProduct += a * b;
       norm1Sq += a * a;
       norm2Sq += b * b;
       i++;
     }
 
-    float normProduct = (float) Math.sqrt(norm1Sq * norm2Sq);
-    if (normProduct < Float.MIN_NORMAL) {
+    // `norm1Sq * norm2Sq` cannot overflow in double precision: both factors are bounded by

Review Comment:
   Good catch, the bound as written was unconditional. Reworded to scope it to finite elements and to
   say what happens otherwise:
   
   ```java
   // For vectors of finite elements, `norm1Sq * norm2Sq` cannot overflow in double precision:
   // both factors are bounded by MAX_ROUNDED_ARRAY_LENGTH * Float.MAX_VALUE^2, so their product
   // stays well below Double.MAX_VALUE. An element that is already infinite makes the product
   // infinite and the result NaN, exactly as it did before the accumulators were widened.
   ```
   
   An infinite element cannot produce a finite dot product either -- it is multiplied by either a
   non-zero element (giving +/-Infinity) or by zero (giving NaN) -- so `dotProduct / normProduct`
   is NaN in every such case, both before and after this change.
   
   I also added golden-file coverage for infinite elements so the behaviour is pinned rather than just
   asserted in a comment:
   
   | query | result |
   | --- | --- |
   | `vector_cosine_similarity(array(float('inf'), 1.0F), array(1.0F, 1.0F))` | `NaN` |
   | `vector_inner_product(array(float('inf'), 1.0F), array(1.0F, 1.0F))` | `Infinity` |
   | `vector_l2_distance(array(float('inf'), 1.0F), array(0.0F, 0.0F))` | `Infinity` |
   | `vector_norm(array(float('inf'), 1.0F), 2.0F)` | `Infinity` |
   | `vector_normalize(array(float('inf'), 1.0F), 2.0F)` | `[NaN,0.0]` |
   
   All five are unchanged from before this PR.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-58544][SQL] Fix vector distance and norm functions returning wrong results from intermediate float overflow [spark]

Posted by "cloud-fan (via GitHub)" <gi...@apache.org>.
cloud-fan commented on code in PR #57746:
URL: https://github.com/apache/spark/pull/57746#discussion_r3728227504


##########
sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/VectorFunctionImplUtils.java:
##########
@@ -448,6 +460,21 @@ public static Float vectorNorm(ArrayData vec, float degree, UTF8String funcName)
     }
   }
 
+  /**
+   * Computes the Lp norm of a float vector using the specified degree.
+   * Supported degrees: 1.0 (L1), 2.0 (L2), Float.POSITIVE_INFINITY (L∞).

Review Comment:
   Spark's repository guidance requires ASCII in code comments.
   
   ```suggestion
      * Supported degrees: 1.0 (L1), 2.0 (L2), Float.POSITIVE_INFINITY (infinity norm).
   ```



##########
sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/VectorFunctionImplUtils.java:
##########
@@ -90,19 +93,22 @@ public static Float vectorCosineSimilarity(ArrayData left, ArrayData right, UTF8
       if (left.isNullAt(i) || right.isNullAt(i)) {
         return null;
       }
-      float a = left.getFloat(i);
-      float b = right.getFloat(i);
+      double a = left.getFloat(i);
+      double b = right.getFloat(i);
       dotProduct += a * b;
       norm1Sq += a * a;
       norm2Sq += b * b;
       i++;
     }
 
-    float normProduct = (float) Math.sqrt(norm1Sq * norm2Sq);
-    if (normProduct < Float.MIN_NORMAL) {
+    // `norm1Sq * norm2Sq` cannot overflow in double precision: both factors are bounded by

Review Comment:
   Please narrow this bound to finite float elements. `ARRAY<FLOAT>` also admits infinities, which make an accumulated squared norm infinite, so the factors are not unconditionally bounded.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-58544][SQL] Fix vector distance and norm functions returning wrong results from intermediate float overflow [spark]

Posted by "cloud-fan (via GitHub)" <gi...@apache.org>.
cloud-fan commented on PR #57746:
URL: https://github.com/apache/spark/pull/57746#issuecomment-5236455174

   **Merge Summary:**
   - merged into master https://github.com/apache/spark/commit/d28c23f19f6d03e4cc472a507b0911bfd93829a9
   - merged into branch-4.x https://github.com/apache/spark/commit/3f6f2cf785ba0aa084137a300a6f4d7d76aa5a85
   - merged into branch-4.3 https://github.com/apache/spark/commit/da54921d8bb82471df4d8685c23455418a6fac00
   
   *Posted by `merge_spark_pr.py`*


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-58544][SQL] Fix vector distance and norm functions returning wrong results from intermediate float overflow [spark]

Posted by "cloud-fan (via GitHub)" <gi...@apache.org>.
cloud-fan closed pull request #57746: [SPARK-58544][SQL] Fix vector distance and norm functions returning wrong results from intermediate float overflow
URL: https://github.com/apache/spark/pull/57746


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


Re: [PR] [SPARK-58544][SQL] Fix vector distance and norm functions returning wrong results from intermediate float overflow [spark]

Posted by "SEPURI-SAI-KRISHNA (via GitHub)" <gi...@apache.org>.
SEPURI-SAI-KRISHNA commented on code in PR #57746:
URL: https://github.com/apache/spark/pull/57746#discussion_r3737641505


##########
sql/core/src/test/resources/sql-tests/inputs/vector-distance.sql:
##########
@@ -130,3 +130,38 @@ SELECT vector_l2_distance(
     array(1.0F, 2.0F, 3.0F, 4.0F, 5.0F, 6.0F, 7.0F, 8.0F, 9.0F, 10.0F, 11.0F, 12.0F, 13.0F, 14.0F, 15.0F, 16.0F),
     array(16.0F, 15.0F, 14.0F, 13.0F, 12.0F, 11.0F, 10.0F, 9.0F, 8.0F, 7.0F, 6.0F, 5.0F, 4.0F, 3.0F, 2.0F, 1.0F)
 );
+
+-- SPARK-58544: large magnitudes, intermediate sums of squares/products must not overflow the
+-- float range
+
+-- vector_cosine_similarity is scale invariant: identical vectors have similarity 1.0
+SELECT vector_cosine_similarity(array(3.0e19F, 4.0e19F), array(3.0e19F, 4.0e19F));
+
+-- vector_cosine_similarity: opposite vectors have similarity -1.0
+SELECT vector_cosine_similarity(array(3.0e19F, 4.0e19F), array(-3.0e19F, -4.0e19F));
+
+-- vector_inner_product: individual products overflow the float range but cancel out
+SELECT vector_inner_product(array(1.0e20F, 1.0e20F), array(1.0e20F, -1.0e20F));
+
+-- vector_l2_distance: sqrt((3e19)^2 + (4e19)^2) = 5e19
+SELECT vector_l2_distance(array(3.0e19F, 4.0e19F), array(0.0F, 0.0F));
+
+-- SPARK-58544: small magnitudes, intermediate sums of squares/products must not underflow to zero
+
+-- vector_cosine_similarity of identical tiny vectors is 1.0, not NULL
+SELECT vector_cosine_similarity(array(1.0e-23F, 0.0F), array(1.0e-23F, 0.0F));
+
+-- vector_cosine_similarity of orthogonal tiny vectors is 0.0, not NULL
+SELECT vector_cosine_similarity(array(1.0e-23F, 1.0e-23F), array(1.0e-23F, -1.0e-23F));
+
+-- SPARK-58544: elements that are already infinite still propagate to NaN or Infinity, the wider

Review Comment:
   Applied, Thanks for the catch.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org