|
@@ -8,9 +8,11 @@
|
|
|
package org.elasticsearch.xpack.vectors.query;
|
|
|
|
|
|
import org.apache.lucene.util.BytesRef;
|
|
|
+import org.elasticsearch.Version;
|
|
|
+import org.elasticsearch.script.ScoreScript;
|
|
|
import org.elasticsearch.xpack.vectors.mapper.VectorEncoderDecoder;
|
|
|
|
|
|
-import java.util.Iterator;
|
|
|
+import java.nio.ByteBuffer;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
|
|
@@ -19,132 +21,166 @@ import static org.elasticsearch.xpack.vectors.mapper.VectorEncoderDecoder.sortSp
|
|
|
public class ScoreScriptUtils {
|
|
|
|
|
|
//**************FUNCTIONS FOR DENSE VECTORS
|
|
|
+ // Functions are implemented as classes to accept a hidden parameter scoreScript that contains some index settings.
|
|
|
+ // Also, constructors for some functions accept queryVector to calculate and cache queryVectorMagnitude only once
|
|
|
+ // per script execution for all documents.
|
|
|
|
|
|
- /**
|
|
|
- * Calculate l1 norm - Manhattan distance
|
|
|
- * between a query's dense vector and documents' dense vectors
|
|
|
- *
|
|
|
- * @param queryVector the query vector parsed as {@code List<Number>} from json
|
|
|
- * @param dvs VectorScriptDocValues representing encoded documents' vectors
|
|
|
- */
|
|
|
- public static double l1norm(List<Number> queryVector, VectorScriptDocValues.DenseVectorScriptDocValues dvs){
|
|
|
- BytesRef value = dvs.getEncodedValue();
|
|
|
- float[] docVector = VectorEncoderDecoder.decodeDenseVector(value);
|
|
|
- if (queryVector.size() != docVector.length) {
|
|
|
- throw new IllegalArgumentException("Can't calculate l1norm! The number of dimensions of the query vector [" +
|
|
|
- queryVector.size() + "] is different from the documents' vectors [" + docVector.length + "].");
|
|
|
+ public static class DenseVectorFunction {
|
|
|
+ final ScoreScript scoreScript;
|
|
|
+ final float[] queryVector;
|
|
|
+
|
|
|
+ public DenseVectorFunction(ScoreScript scoreScript, List<Number> queryVector) {
|
|
|
+ this(scoreScript, queryVector, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constructs a dense vector function.
|
|
|
+ *
|
|
|
+ * @param scoreScript The script in which this function was referenced.
|
|
|
+ * @param queryVector The query vector.
|
|
|
+ * @param normalizeQuery Whether the provided query should be normalized to unit length.
|
|
|
+ */
|
|
|
+ public DenseVectorFunction(ScoreScript scoreScript,
|
|
|
+ List<Number> queryVector,
|
|
|
+ boolean normalizeQuery) {
|
|
|
+ this.scoreScript = scoreScript;
|
|
|
+
|
|
|
+ this.queryVector = new float[queryVector.size()];
|
|
|
+ double queryMagnitude = 0.0;
|
|
|
+ for (int i = 0; i < queryVector.size(); i++) {
|
|
|
+ float value = queryVector.get(i).floatValue();
|
|
|
+ this.queryVector[i] = value;
|
|
|
+ queryMagnitude += value * value;
|
|
|
+ }
|
|
|
+ queryMagnitude = Math.sqrt(queryMagnitude);
|
|
|
+
|
|
|
+ if (normalizeQuery) {
|
|
|
+ for (int dim = 0; dim < this.queryVector.length; dim++) {
|
|
|
+ this.queryVector[dim] /= queryMagnitude;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- Iterator<Number> queryVectorIter = queryVector.iterator();
|
|
|
- double l1norm = 0;
|
|
|
- for (int dim = 0; dim < docVector.length; dim++){
|
|
|
- l1norm += Math.abs(queryVectorIter.next().floatValue() - docVector[dim]);
|
|
|
+
|
|
|
+ public void validateDocVector(BytesRef vector) {
|
|
|
+ if (vector == null) {
|
|
|
+ throw new IllegalArgumentException("A document doesn't have a value for a vector field!");
|
|
|
+ }
|
|
|
+
|
|
|
+ int vectorLength = VectorEncoderDecoder.denseVectorLength(scoreScript._getIndexVersion(), vector);
|
|
|
+ if (queryVector.length != vectorLength) {
|
|
|
+ throw new IllegalArgumentException("The query vector has a different number of dimensions [" +
|
|
|
+ queryVector.length + "] than the document vectors [" + vectorLength + "].");
|
|
|
+ }
|
|
|
}
|
|
|
- return l1norm;
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Calculate l2 norm - Euclidean distance
|
|
|
- * between a query's dense vector and documents' dense vectors
|
|
|
- *
|
|
|
- * @param queryVector the query vector parsed as {@code List<Number>} from json
|
|
|
- * @param dvs VectorScriptDocValues representing encoded documents' vectors
|
|
|
- */
|
|
|
- public static double l2norm(List<Number> queryVector, VectorScriptDocValues.DenseVectorScriptDocValues dvs){
|
|
|
- BytesRef value = dvs.getEncodedValue();
|
|
|
- float[] docVector = VectorEncoderDecoder.decodeDenseVector(value);
|
|
|
- if (queryVector.size() != docVector.length) {
|
|
|
- throw new IllegalArgumentException("Can't calculate l2norm! The number of dimensions of the query vector [" +
|
|
|
- queryVector.size() + "] is different from the documents' vectors [" + docVector.length + "].");
|
|
|
+ // Calculate l1 norm (Manhattan distance) between a query's dense vector and documents' dense vectors
|
|
|
+ public static final class L1Norm extends DenseVectorFunction {
|
|
|
+
|
|
|
+ public L1Norm(ScoreScript scoreScript, List<Number> queryVector) {
|
|
|
+ super(scoreScript, queryVector);
|
|
|
}
|
|
|
- Iterator<Number> queryVectorIter = queryVector.iterator();
|
|
|
- double l2norm = 0;
|
|
|
- for (int dim = 0; dim < docVector.length; dim++){
|
|
|
- double diff = queryVectorIter.next().floatValue() - docVector[dim];
|
|
|
- l2norm += diff * diff;
|
|
|
+
|
|
|
+ public double l1norm(VectorScriptDocValues.DenseVectorScriptDocValues dvs) {
|
|
|
+ BytesRef vector = dvs.getEncodedValue();
|
|
|
+ validateDocVector(vector);
|
|
|
+ ByteBuffer byteBuffer = ByteBuffer.wrap(vector.bytes, vector.offset, vector.length);
|
|
|
+ double l1norm = 0;
|
|
|
+
|
|
|
+ for (float queryValue : queryVector) {
|
|
|
+ l1norm += Math.abs(queryValue - byteBuffer.getFloat());
|
|
|
+ }
|
|
|
+ return l1norm;
|
|
|
}
|
|
|
- return Math.sqrt(l2norm);
|
|
|
}
|
|
|
|
|
|
+ // Calculate l2 norm (Euclidean distance) between a query's dense vector and documents' dense vectors
|
|
|
+ public static final class L2Norm extends DenseVectorFunction {
|
|
|
|
|
|
- /**
|
|
|
- * Calculate a dot product between a query's dense vector and documents' dense vectors
|
|
|
- *
|
|
|
- * @param queryVector the query vector parsed as {@code List<Number>} from json
|
|
|
- * @param dvs VectorScriptDocValues representing encoded documents' vectors
|
|
|
- */
|
|
|
- public static double dotProduct(List<Number> queryVector, VectorScriptDocValues.DenseVectorScriptDocValues dvs){
|
|
|
- BytesRef value = dvs.getEncodedValue();
|
|
|
- float[] docVector = VectorEncoderDecoder.decodeDenseVector(value);
|
|
|
- if (queryVector.size() != docVector.length) {
|
|
|
- throw new IllegalArgumentException("Can't calculate dotProduct! The number of dimensions of the query vector [" +
|
|
|
- queryVector.size() + "] is different from the documents' vectors [" + docVector.length + "].");
|
|
|
+ public L2Norm(ScoreScript scoreScript, List<Number> queryVector) {
|
|
|
+ super(scoreScript, queryVector);
|
|
|
+ }
|
|
|
+
|
|
|
+ public double l2norm(VectorScriptDocValues.DenseVectorScriptDocValues dvs) {
|
|
|
+ BytesRef vector = dvs.getEncodedValue();
|
|
|
+ validateDocVector(vector);
|
|
|
+ ByteBuffer byteBuffer = ByteBuffer.wrap(vector.bytes, vector.offset, vector.length);
|
|
|
+
|
|
|
+ double l2norm = 0;
|
|
|
+ for (float queryValue : queryVector) {
|
|
|
+ double diff = queryValue - byteBuffer.getFloat();
|
|
|
+ l2norm += diff * diff;
|
|
|
+ }
|
|
|
+ return Math.sqrt(l2norm);
|
|
|
}
|
|
|
- return intDotProduct(queryVector, docVector);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Calculate cosine similarity between a query's dense vector and documents' dense vectors
|
|
|
- *
|
|
|
- * CosineSimilarity is implemented as a class to use
|
|
|
- * painless script caching to calculate queryVectorMagnitude
|
|
|
- * only once per script execution for all documents.
|
|
|
- * A user will call `cosineSimilarity(params.queryVector, doc['my_vector'])`
|
|
|
- */
|
|
|
- public static final class CosineSimilarity {
|
|
|
- final double queryVectorMagnitude;
|
|
|
- final List<Number> queryVector;
|
|
|
+ // Calculate a dot product between a query's dense vector and documents' dense vectors
|
|
|
+ public static final class DotProduct extends DenseVectorFunction {
|
|
|
|
|
|
- // calculate queryVectorMagnitude once per query execution
|
|
|
- public CosineSimilarity(List<Number> queryVector) {
|
|
|
- this.queryVector = queryVector;
|
|
|
+ public DotProduct(ScoreScript scoreScript, List<Number> queryVector) {
|
|
|
+ super(scoreScript, queryVector);
|
|
|
+ }
|
|
|
+
|
|
|
+ public double dotProduct(VectorScriptDocValues.DenseVectorScriptDocValues dvs){
|
|
|
+ BytesRef vector = dvs.getEncodedValue();
|
|
|
+ validateDocVector(vector);
|
|
|
+ ByteBuffer byteBuffer = ByteBuffer.wrap(vector.bytes, vector.offset, vector.length);
|
|
|
|
|
|
double dotProduct = 0;
|
|
|
- for (Number value : queryVector) {
|
|
|
- float floatValue = value.floatValue();
|
|
|
- dotProduct += floatValue * floatValue;
|
|
|
+ for (float queryValue : queryVector) {
|
|
|
+ dotProduct += queryValue * byteBuffer.getFloat();
|
|
|
}
|
|
|
- this.queryVectorMagnitude = Math.sqrt(dotProduct);
|
|
|
+ return dotProduct;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- public double cosineSimilarity(VectorScriptDocValues.DenseVectorScriptDocValues dvs) {
|
|
|
- BytesRef value = dvs.getEncodedValue();
|
|
|
- float[] docVector = VectorEncoderDecoder.decodeDenseVector(value);
|
|
|
- if (queryVector.size() != docVector.length) {
|
|
|
- throw new IllegalArgumentException("Can't calculate cosineSimilarity! The number of dimensions of the query vector [" +
|
|
|
- queryVector.size() + "] is different from the documents' vectors [" + docVector.length + "].");
|
|
|
- }
|
|
|
-
|
|
|
- // calculate docVector magnitude
|
|
|
- double dotProduct = 0f;
|
|
|
- for (int dim = 0; dim < docVector.length; dim++) {
|
|
|
- dotProduct += (double) docVector[dim] * docVector[dim];
|
|
|
- }
|
|
|
- final double docVectorMagnitude = Math.sqrt(dotProduct);
|
|
|
+ // Calculate cosine similarity between a query's dense vector and documents' dense vectors
|
|
|
+ public static final class CosineSimilarity extends DenseVectorFunction {
|
|
|
|
|
|
- double docQueryDotProduct = intDotProduct(queryVector, docVector);
|
|
|
- return docQueryDotProduct / (docVectorMagnitude * queryVectorMagnitude);
|
|
|
+ public CosineSimilarity(ScoreScript scoreScript, List<Number> queryVector) {
|
|
|
+ super(scoreScript, queryVector, true);
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- private static double intDotProduct(List<Number> v1, float[] v2){
|
|
|
- double v1v2DotProduct = 0;
|
|
|
- Iterator<Number> v1Iter = v1.iterator();
|
|
|
- for (int dim = 0; dim < v2.length; dim++) {
|
|
|
- v1v2DotProduct += v1Iter.next().floatValue() * v2[dim];
|
|
|
+ public double cosineSimilarity(VectorScriptDocValues.DenseVectorScriptDocValues dvs) {
|
|
|
+ BytesRef vector = dvs.getEncodedValue();
|
|
|
+ validateDocVector(vector);
|
|
|
+
|
|
|
+ ByteBuffer byteBuffer = ByteBuffer.wrap(vector.bytes, vector.offset, vector.length);
|
|
|
+
|
|
|
+ double dotProduct = 0.0;
|
|
|
+ double vectorMagnitude = 0.0f;
|
|
|
+ if (scoreScript._getIndexVersion().onOrAfter(Version.V_7_5_0)) {
|
|
|
+ for (float queryValue : queryVector) {
|
|
|
+ dotProduct += queryValue * byteBuffer.getFloat();
|
|
|
+ }
|
|
|
+ vectorMagnitude = VectorEncoderDecoder.decodeVectorMagnitude(scoreScript._getIndexVersion(), vector);
|
|
|
+ } else {
|
|
|
+ for (float queryValue : queryVector) {
|
|
|
+ float docValue = byteBuffer.getFloat();
|
|
|
+ dotProduct += queryValue * docValue;
|
|
|
+ vectorMagnitude += docValue * docValue;
|
|
|
+ }
|
|
|
+ vectorMagnitude = (float) Math.sqrt(vectorMagnitude);
|
|
|
+ }
|
|
|
+ return dotProduct / vectorMagnitude;
|
|
|
}
|
|
|
- return v1v2DotProduct;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
//**************FUNCTIONS FOR SPARSE VECTORS
|
|
|
+ // Functions are implemented as classes to accept a hidden parameter scoreScript that contains some index settings.
|
|
|
+ // Also, constructors for some functions accept queryVector to calculate and cache queryVectorMagnitude only once
|
|
|
+ // per script execution for all documents.
|
|
|
|
|
|
- public static class VectorSparseFunctions {
|
|
|
+ public static class SparseVectorFunction {
|
|
|
+ final ScoreScript scoreScript;
|
|
|
final float[] queryValues;
|
|
|
final int[] queryDims;
|
|
|
|
|
|
// prepare queryVector once per script execution
|
|
|
// queryVector represents a map of dimensions to values
|
|
|
- public VectorSparseFunctions(Map<String, Number> queryVector) {
|
|
|
+ public SparseVectorFunction(ScoreScript scoreScript, Map<String, Number> queryVector) {
|
|
|
+ this.scoreScript = scoreScript;
|
|
|
//break vector into two arrays dims and values
|
|
|
int n = queryVector.size();
|
|
|
queryValues = new float[n];
|
|
@@ -162,26 +198,26 @@ public class ScoreScriptUtils {
|
|
|
// Sort dimensions in the ascending order and sort values in the same order as their corresponding dimensions
|
|
|
sortSparseDimsFloatValues(queryDims, queryValues, n);
|
|
|
}
|
|
|
+
|
|
|
+ public void validateDocVector(BytesRef vector) {
|
|
|
+ if (vector == null) {
|
|
|
+ throw new IllegalArgumentException("A document doesn't have a value for a vector field!");
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Calculate l1 norm - Manhattan distance
|
|
|
- * between a query's sparse vector and documents' sparse vectors
|
|
|
- *
|
|
|
- * L1NormSparse is implemented as a class to use
|
|
|
- * painless script caching to prepare queryVector
|
|
|
- * only once per script execution for all documents.
|
|
|
- * A user will call `l1normSparse(params.queryVector, doc['my_vector'])`
|
|
|
- */
|
|
|
- public static final class L1NormSparse extends VectorSparseFunctions {
|
|
|
- public L1NormSparse(Map<String, Number> queryVector) {
|
|
|
- super(queryVector);
|
|
|
+ // Calculate l1 norm (Manhattan distance) between a query's sparse vector and documents' sparse vectors
|
|
|
+ public static final class L1NormSparse extends SparseVectorFunction {
|
|
|
+ public L1NormSparse(ScoreScript scoreScript,Map<String, Number> queryVector) {
|
|
|
+ super(scoreScript, queryVector);
|
|
|
}
|
|
|
|
|
|
public double l1normSparse(VectorScriptDocValues.SparseVectorScriptDocValues dvs) {
|
|
|
- BytesRef value = dvs.getEncodedValue();
|
|
|
- int[] docDims = VectorEncoderDecoder.decodeSparseVectorDims(value);
|
|
|
- float[] docValues = VectorEncoderDecoder.decodeSparseVector(value);
|
|
|
+ BytesRef vector = dvs.getEncodedValue();
|
|
|
+ validateDocVector(vector);
|
|
|
+
|
|
|
+ int[] docDims = VectorEncoderDecoder.decodeSparseVectorDims(scoreScript._getIndexVersion(), vector);
|
|
|
+ float[] docValues = VectorEncoderDecoder.decodeSparseVector(scoreScript._getIndexVersion(), vector);
|
|
|
int queryIndex = 0;
|
|
|
int docIndex = 0;
|
|
|
double l1norm = 0;
|
|
@@ -210,24 +246,18 @@ public class ScoreScriptUtils {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Calculate l2 norm - Euclidean distance
|
|
|
- * between a query's sparse vector and documents' sparse vectors
|
|
|
- *
|
|
|
- * L2NormSparse is implemented as a class to use
|
|
|
- * painless script caching to prepare queryVector
|
|
|
- * only once per script execution for all documents.
|
|
|
- * A user will call `l2normSparse(params.queryVector, doc['my_vector'])`
|
|
|
- */
|
|
|
- public static final class L2NormSparse extends VectorSparseFunctions {
|
|
|
- public L2NormSparse(Map<String, Number> queryVector) {
|
|
|
- super(queryVector);
|
|
|
+ // Calculate l2 norm (Euclidean distance) between a query's sparse vector and documents' sparse vectors
|
|
|
+ public static final class L2NormSparse extends SparseVectorFunction {
|
|
|
+ public L2NormSparse(ScoreScript scoreScript, Map<String, Number> queryVector) {
|
|
|
+ super(scoreScript, queryVector);
|
|
|
}
|
|
|
|
|
|
public double l2normSparse(VectorScriptDocValues.SparseVectorScriptDocValues dvs) {
|
|
|
- BytesRef value = dvs.getEncodedValue();
|
|
|
- int[] docDims = VectorEncoderDecoder.decodeSparseVectorDims(value);
|
|
|
- float[] docValues = VectorEncoderDecoder.decodeSparseVector(value);
|
|
|
+ BytesRef vector = dvs.getEncodedValue();
|
|
|
+ validateDocVector(vector);
|
|
|
+
|
|
|
+ int[] docDims = VectorEncoderDecoder.decodeSparseVectorDims(scoreScript._getIndexVersion(), vector);
|
|
|
+ float[] docValues = VectorEncoderDecoder.decodeSparseVector(scoreScript._getIndexVersion(), vector);
|
|
|
int queryIndex = 0;
|
|
|
int docIndex = 0;
|
|
|
double l2norm = 0;
|
|
@@ -259,40 +289,28 @@ public class ScoreScriptUtils {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Calculate a dot product between a query's sparse vector and documents' sparse vectors
|
|
|
- *
|
|
|
- * DotProductSparse is implemented as a class to use
|
|
|
- * painless script caching to prepare queryVector
|
|
|
- * only once per script execution for all documents.
|
|
|
- * A user will call `dotProductSparse(params.queryVector, doc['my_vector'])`
|
|
|
- */
|
|
|
- public static final class DotProductSparse extends VectorSparseFunctions {
|
|
|
- public DotProductSparse(Map<String, Number> queryVector) {
|
|
|
- super(queryVector);
|
|
|
+ // Calculate a dot product between a query's sparse vector and documents' sparse vectors
|
|
|
+ public static final class DotProductSparse extends SparseVectorFunction {
|
|
|
+ public DotProductSparse(ScoreScript scoreScript, Map<String, Number> queryVector) {
|
|
|
+ super(scoreScript, queryVector);
|
|
|
}
|
|
|
|
|
|
public double dotProductSparse(VectorScriptDocValues.SparseVectorScriptDocValues dvs) {
|
|
|
- BytesRef value = dvs.getEncodedValue();
|
|
|
- int[] docDims = VectorEncoderDecoder.decodeSparseVectorDims(value);
|
|
|
- float[] docValues = VectorEncoderDecoder.decodeSparseVector(value);
|
|
|
+ BytesRef vector = dvs.getEncodedValue();
|
|
|
+ validateDocVector(vector);
|
|
|
+
|
|
|
+ int[] docDims = VectorEncoderDecoder.decodeSparseVectorDims(scoreScript._getIndexVersion(), vector);
|
|
|
+ float[] docValues = VectorEncoderDecoder.decodeSparseVector(scoreScript._getIndexVersion(), vector);
|
|
|
return intDotProductSparse(queryValues, queryDims, docValues, docDims);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Calculate cosine similarity between a query's sparse vector and documents' sparse vectors
|
|
|
- *
|
|
|
- * CosineSimilaritySparse is implemented as a class to use
|
|
|
- * painless script caching to prepare queryVector and calculate queryVectorMagnitude
|
|
|
- * only once per script execution for all documents.
|
|
|
- * A user will call `cosineSimilaritySparse(params.queryVector, doc['my_vector'])`
|
|
|
- */
|
|
|
- public static final class CosineSimilaritySparse extends VectorSparseFunctions {
|
|
|
+ // Calculate cosine similarity between a query's sparse vector and documents' sparse vectors
|
|
|
+ public static final class CosineSimilaritySparse extends SparseVectorFunction {
|
|
|
final double queryVectorMagnitude;
|
|
|
|
|
|
- public CosineSimilaritySparse(Map<String, Number> queryVector) {
|
|
|
- super(queryVector);
|
|
|
+ public CosineSimilaritySparse(ScoreScript scoreScript, Map<String, Number> queryVector) {
|
|
|
+ super(scoreScript, queryVector);
|
|
|
double dotProduct = 0;
|
|
|
for (int i = 0; i< queryDims.length; i++) {
|
|
|
dotProduct += queryValues[i] * queryValues[i];
|
|
@@ -301,18 +319,23 @@ public class ScoreScriptUtils {
|
|
|
}
|
|
|
|
|
|
public double cosineSimilaritySparse(VectorScriptDocValues.SparseVectorScriptDocValues dvs) {
|
|
|
- BytesRef value = dvs.getEncodedValue();
|
|
|
- int[] docDims = VectorEncoderDecoder.decodeSparseVectorDims(value);
|
|
|
- float[] docValues = VectorEncoderDecoder.decodeSparseVector(value);
|
|
|
+ BytesRef vector = dvs.getEncodedValue();
|
|
|
+ validateDocVector(vector);
|
|
|
|
|
|
- // calculate docVector magnitude
|
|
|
- double dotProduct = 0;
|
|
|
- for (float docValue : docValues) {
|
|
|
- dotProduct += (double) docValue * docValue;
|
|
|
- }
|
|
|
- final double docVectorMagnitude = Math.sqrt(dotProduct);
|
|
|
+ int[] docDims = VectorEncoderDecoder.decodeSparseVectorDims(scoreScript._getIndexVersion(), vector);
|
|
|
+ float[] docValues = VectorEncoderDecoder.decodeSparseVector(scoreScript._getIndexVersion(), vector);
|
|
|
|
|
|
double docQueryDotProduct = intDotProductSparse(queryValues, queryDims, docValues, docDims);
|
|
|
+ double docVectorMagnitude = 0.0f;
|
|
|
+ if (scoreScript._getIndexVersion().onOrAfter(Version.V_7_5_0)) {
|
|
|
+ docVectorMagnitude = VectorEncoderDecoder.decodeVectorMagnitude(scoreScript._getIndexVersion(), vector);
|
|
|
+ } else {
|
|
|
+ for (float docValue : docValues) {
|
|
|
+ docVectorMagnitude += docValue * docValue;
|
|
|
+ }
|
|
|
+ docVectorMagnitude = (float) Math.sqrt(docVectorMagnitude);
|
|
|
+ }
|
|
|
+
|
|
|
return docQueryDotProduct / (docVectorMagnitude * queryVectorMagnitude);
|
|
|
}
|
|
|
}
|