You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by be...@apache.org on 2026/06/01 17:49:48 UTC

(lucene) branch branch_10x updated: Validate zero vectors in setVectorValue() for cosine similarity fields (#16098)

This is an automated email from the ASF dual-hosted git repository.

benwtrent pushed a commit to branch branch_10x
in repository https://gitbox.apache.org/repos/asf/lucene.git


The following commit(s) were added to refs/heads/branch_10x by this push:
     new ea5d96a462f Validate zero vectors in setVectorValue() for cosine similarity fields (#16098)
ea5d96a462f is described below

commit ea5d96a462f92ffec96d0ad04460f5b55c8a5a4b
Author: Prithvi S <pr...@gmail.com>
AuthorDate: Mon Jun 1 23:10:45 2026 +0530

    Validate zero vectors in setVectorValue() for cosine similarity fields (#16098)
---
 lucene/CHANGES.txt                                 |  2 +
 .../apache/lucene/document/KnnByteVectorField.java |  4 ++
 .../lucene/document/KnnFloatVectorField.java       |  6 ++-
 .../java/org/apache/lucene/util/VectorUtil.java    |  2 +-
 .../test/org/apache/lucene/document/TestField.java | 45 ++++++++++++++++++++++
 5 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index ad2da50dd6d..50d1a3ec14a 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -251,6 +251,8 @@ Bug Fixes
 
 * GITHUB#15878: Fix LargeNumHitsTopDocsCollector not handling requested hit count correctly (Binlong Gao)
 
+* GITHUB#16098: Validate zero vectors in setVectorValue() for cosine similarity fields. (Prithvi S)
+
 * GITHUB#16046: Fix double-counting of underlying Automaton in CompiledAutomaton#ramBytesUsed. (Eugene Rizhkov)
 
 * GITHUB#15901: Fix undercounting of RAM used by vectors buffered in in-memory segments.
diff --git a/lucene/core/src/java/org/apache/lucene/document/KnnByteVectorField.java b/lucene/core/src/java/org/apache/lucene/document/KnnByteVectorField.java
index 570ef43c56f..fd69b3ba3ec 100644
--- a/lucene/core/src/java/org/apache/lucene/document/KnnByteVectorField.java
+++ b/lucene/core/src/java/org/apache/lucene/document/KnnByteVectorField.java
@@ -168,6 +168,10 @@ public class KnnByteVectorField extends Field {
       throw new IllegalArgumentException(
           "value length " + value.length + " must match field dimension " + type.vectorDimension());
     }
+    if (type.vectorSimilarityFunction() == VectorSimilarityFunction.COSINE
+        && VectorUtil.isZeroVector(value)) {
+      throw new IllegalArgumentException("zero vector not allowed with cosine similarity function");
+    }
     fieldsData = value;
   }
 }
diff --git a/lucene/core/src/java/org/apache/lucene/document/KnnFloatVectorField.java b/lucene/core/src/java/org/apache/lucene/document/KnnFloatVectorField.java
index dcdb8a1735d..259b3576226 100644
--- a/lucene/core/src/java/org/apache/lucene/document/KnnFloatVectorField.java
+++ b/lucene/core/src/java/org/apache/lucene/document/KnnFloatVectorField.java
@@ -169,6 +169,10 @@ public class KnnFloatVectorField extends Field {
       throw new IllegalArgumentException(
           "value length " + value.length + " must match field dimension " + type.vectorDimension());
     }
-    fieldsData = value;
+    if (type.vectorSimilarityFunction() == VectorSimilarityFunction.COSINE
+        && VectorUtil.isZeroVector(value)) {
+      throw new IllegalArgumentException("zero vector not allowed with cosine similarity function");
+    }
+    fieldsData = VectorUtil.checkFinite(value);
   }
 }
diff --git a/lucene/core/src/java/org/apache/lucene/util/VectorUtil.java b/lucene/core/src/java/org/apache/lucene/util/VectorUtil.java
index a526363b679..cf9eb759bc8 100644
--- a/lucene/core/src/java/org/apache/lucene/util/VectorUtil.java
+++ b/lucene/core/src/java/org/apache/lucene/util/VectorUtil.java
@@ -465,7 +465,7 @@ public final class VectorUtil {
 
   /** Returns true if all dimensions of provided vector are zero, false otherwise. */
   public static boolean isZeroVector(byte[] v) {
-    for (float value : v) {
+    for (byte value : v) {
       if (value != 0) {
         return false;
       }
diff --git a/lucene/core/src/test/org/apache/lucene/document/TestField.java b/lucene/core/src/test/org/apache/lucene/document/TestField.java
index 8eeecaf0fa6..116e880dbfd 100644
--- a/lucene/core/src/test/org/apache/lucene/document/TestField.java
+++ b/lucene/core/src/test/org/apache/lucene/document/TestField.java
@@ -765,6 +765,51 @@ public class TestField extends LuceneTestCase {
     assertTrue(zeroError.getMessage().contains("zero vector not allowed"));
   }
 
+  public void testKnnFieldSetVectorValueZeroVectors() throws Exception {
+    // Float vector field: setVectorValue with zero vector on COSINE field should fail
+    KnnFloatVectorField floatField =
+        new KnnFloatVectorField(
+            "knnFloats", new float[] {1, 2, 3, 4, 5}, VectorSimilarityFunction.COSINE);
+    IllegalArgumentException zeroError =
+        expectThrows(IllegalArgumentException.class, () -> floatField.setVectorValue(new float[5]));
+    assertTrue(zeroError.getMessage().contains("zero vector not allowed"));
+
+    // Non-zero setVectorValue should succeed
+    floatField.setVectorValue(new float[] {5, 4, 3, 2, 1});
+
+    // Byte vector field: setVectorValue with zero vector on COSINE field should fail
+    KnnByteVectorField byteField =
+        new KnnByteVectorField(
+            "knnBytes", new byte[] {1, 2, 3, 4, 5}, VectorSimilarityFunction.COSINE);
+    zeroError =
+        expectThrows(IllegalArgumentException.class, () -> byteField.setVectorValue(new byte[5]));
+    assertTrue(zeroError.getMessage().contains("zero vector not allowed"));
+
+    // Non-zero setVectorValue should succeed
+    byteField.setVectorValue(new byte[] {5, 4, 3, 2, 1});
+
+    // EUCLIDEAN fields should allow zero vectors via setVectorValue
+    KnnFloatVectorField euclideanFloatField =
+        new KnnFloatVectorField(
+            "knnFloatsEuc", new float[] {1, 2, 3, 4, 5}, VectorSimilarityFunction.EUCLIDEAN);
+    euclideanFloatField.setVectorValue(new float[5]);
+
+    KnnByteVectorField euclideanByteField =
+        new KnnByteVectorField(
+            "knnBytesEuc", new byte[] {1, 2, 3, 4, 5}, VectorSimilarityFunction.EUCLIDEAN);
+    euclideanByteField.setVectorValue(new byte[5]);
+
+    // Float vector field: setVectorValue with NaN should fail
+    KnnFloatVectorField nanField =
+        new KnnFloatVectorField(
+            "knnFloatsNaN", new float[] {1, 2, 3, 4, 5}, VectorSimilarityFunction.EUCLIDEAN);
+    IllegalArgumentException nanError =
+        expectThrows(
+            IllegalArgumentException.class,
+            () -> nanField.setVectorValue(new float[] {1, 2, Float.NaN, 4, 5}));
+    assertTrue(nanError.getMessage().contains("non-finite"));
+  }
+
   private void trySetByteValue(Field f) {
     expectThrows(
         IllegalArgumentException.class,