[Bug]: similarity() returns nan for zero-norm embeddings, corrupting top-k selection
Bug Description
similarity() in llama_index/core/base/embeddings/base.py divides by the product of vector norms in the default cosine branch:
product = np.dot(embedding1, embedding2)
norm = np.linalg.norm(embedding1) * np.linalg.norm(embedding2)
return product / normWhen either embedding is a zero vector (e.g. some providers return zero embeddings for empty text), the norm product is 0 and the function silently returns nan (with a RuntimeWarning).
The nan leaks into top-k selection: get_top_k_embeddings() pushes (similarity, id) tuples onto a heap, and comparisons against nan are always false, so the nan-scored node survives pruning and is returned in top-k results over legitimately scored nodes.
Version
llama-index-core 0.14.24 (reproduced on main @ 7169bcd)
Steps to Reproduce
from llama_index.core.base.embeddings.base import similarity
from llama_index.core.indices.query.embedding_utils import get_top_k_embeddings
similarity([0.0, 0.0], [1.0, 0.0]) # nan, expected 0.0
sims, ids = get_top_k_embeddings(
[1.0, 0.0], [[1.0, 0.0], [0.5, 0.5], [0.0, 0.0]], similarity_top_k=2
)
# sims == [1.0, nan], ids == [0, 2]
# the zero-vector node (id 2) is returned; the legitimately scored node (id 1, ~0.707) is droppedSuggested Fix
Return 0.0 when the norm product is zero:
if norm == 0:
return 0.0
return product / normThis matches the zero-vector convention used by sklearn's cosine similarity.
Source: run-llama/llama_index