sepuri sai krishna created SPARK-58544:
------------------------------------------

             Summary: Vector distance and norm functions return NaN, Infinity 
or NULL due to float overflow in intermediate sums
                 Key: SPARK-58544
                 URL: https://issues.apache.org/jira/browse/SPARK-58544
             Project: Spark
          Issue Type: Bug
          Components: SQL
    Affects Versions: 4.2.0
            Reporter: sepuri sai krishna


The vector distance and norm functions added in 4.2.0 accumulate 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 
silently returns a wrong value.

{code:sql}
SELECT vector_cosine_similarity(array(3.0e19F, 4.0e19F), array(3.0e19F, 
4.0e19F)); -- NaN, expected 1.0
SELECT vector_cosine_similarity(array(1.0e-23F, 0.0F), array(1.0e-23F, 0.0F));  
   -- NULL, expected 1.0
SELECT vector_l2_distance(array(3.0e19F, 4.0e19F), array(0.0F, 0.0F));          
   -- Infinity, expected 5.0E19
SELECT vector_norm(array(3.0e19F, 4.0e19F), 2.0F);                              
   -- Infinity, expected 5.0E19
SELECT vector_normalize(array(3.0e19F, 4.0e19F), 2.0F);                         
   -- [0.0,0.0], expected [0.6,0.8]
SELECT vector_normalize(array(1.0e-23F, 0.0F), 2.0F);                           
   -- NULL, expected [1.0,0.0]
{code}

||Query||Actual||Expected||
|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 case above the correct result is an ordinary float; only the 
intermediate sum leaves the float range: {{(3e19)^2 + (4e19)^2 = 2.5e39}} 
exceeds {{Float.MAX_VALUE}}, and {{(1e-23)^2 = 1e-46}} is below the smallest 
positive float. Cosine similarity and normalization are scale invariant by 
definition, so rescaling the input must not change the result, but today it 
does. The wrong values are returned silently rather than failing, so they 
propagate into similarity search results and rankings.

Affected functions: vector_cosine_similarity, vector_inner_product, 
vector_l2_distance, vector_norm, vector_normalize.

Root cause is in {{VectorFunctionImplUtils}}: the accumulators, and the 
per-element locals inside the 8-way unrolled blocks, are all {{float}}, so both 
the individual products and the running sums overflow. {{vector_normalize}} 
additionally rounds the norm to a float before dividing, which turns a norm 
outside the float range into infinity and yields an all-zero vector.

The fix is to accumulate in {{double}} and round only the final result back to 
{{float}}, and to keep the norm in {{double}} inside {{vector_normalize}}. This 
also makes the ordinary case correctly rounded: 
vector_cosine_similarity(array(1.0F, 2.0F, 3.0F), array(4.0F, 5.0F, 6.0F)) 
changes from 0.9746319 to 0.97463185, the correctly rounded float of 
32/sqrt(1078) = 0.9746318461970763.

Not affected, and correct as-is: 0.0 for empty vectors, NULL for NULL inputs or 
vectors containing NULL elements, and NULL for a genuinely zero-magnitude 
vector. The problem is that a vector of tiny but non-zero magnitude is 
currently treated as if it were zero.

Introduced by SPARK-54713 and SPARK-55030.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to