|
@@ -57,6 +57,7 @@ import org.elasticsearch.xpack.esql.expression.function.grouping.Bucket;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.grouping.TBucket;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToDateNanos;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToDatetime;
|
|
|
+import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToDenseVector;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToInteger;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToLong;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToString;
|
|
@@ -2349,21 +2350,40 @@ public class AnalyzerTests extends ESTestCase {
|
|
|
public void testDenseVectorImplicitCastingKnn() {
|
|
|
assumeTrue("dense_vector capability not available", EsqlCapabilities.Cap.DENSE_VECTOR_FIELD_TYPE.isEnabled());
|
|
|
assumeTrue("dense_vector capability not available", EsqlCapabilities.Cap.KNN_FUNCTION_V5.isEnabled());
|
|
|
+ assumeTrue("dense vector casting must be enabled", EsqlCapabilities.Cap.TO_DENSE_VECTOR_FUNCTION.isEnabled());
|
|
|
|
|
|
- checkDenseVectorCastingKnn("float_vector");
|
|
|
-
|
|
|
+ if (EsqlCapabilities.Cap.KNN_FUNCTION_V5.isEnabled()) {
|
|
|
+ checkDenseVectorCastingHexKnn("float_vector");
|
|
|
+ checkDenseVectorCastingKnn("float_vector");
|
|
|
+ }
|
|
|
if (EsqlCapabilities.Cap.DENSE_VECTOR_FIELD_TYPE_BYTE_ELEMENTS.isEnabled()) {
|
|
|
checkDenseVectorCastingKnn("byte_vector");
|
|
|
+ checkDenseVectorCastingHexKnn("byte_vector");
|
|
|
+ checkDenseVectorEvalCastingKnn("byte_vector");
|
|
|
}
|
|
|
-
|
|
|
if (EsqlCapabilities.Cap.DENSE_VECTOR_FIELD_TYPE_BIT_ELEMENTS.isEnabled()) {
|
|
|
checkDenseVectorCastingKnn("bit_vector");
|
|
|
+ checkDenseVectorCastingHexKnn("bit_vector");
|
|
|
+ checkDenseVectorEvalCastingKnn("bit_vector");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private static void checkDenseVectorCastingKnn(String fieldName) {
|
|
|
var plan = analyze(String.format(Locale.ROOT, """
|
|
|
- from test | where knn(%s, [0.342, 0.164, 0.234])
|
|
|
+ from test | where knn(%s, [0, 1, 2])
|
|
|
+ """, fieldName), "mapping-dense_vector.json");
|
|
|
+
|
|
|
+ var limit = as(plan, Limit.class);
|
|
|
+ var filter = as(limit.child(), Filter.class);
|
|
|
+ var knn = as(filter.condition(), Knn.class);
|
|
|
+ var conversion = as(knn.query(), ToDenseVector.class);
|
|
|
+ var literal = as(conversion.field(), Literal.class);
|
|
|
+ assertThat(literal.value(), equalTo(List.of(0, 1, 2)));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void checkDenseVectorCastingHexKnn(String fieldName) {
|
|
|
+ var plan = analyze(String.format(Locale.ROOT, """
|
|
|
+ from test | where knn(%s, "000102")
|
|
|
""", fieldName), "mapping-dense_vector.json");
|
|
|
|
|
|
var limit = as(plan, Limit.class);
|
|
@@ -2371,50 +2391,65 @@ public class AnalyzerTests extends ESTestCase {
|
|
|
var knn = as(filter.condition(), Knn.class);
|
|
|
var queryVector = as(knn.query(), Literal.class);
|
|
|
assertEquals(DataType.DENSE_VECTOR, queryVector.dataType());
|
|
|
- assertThat(queryVector.value(), equalTo(List.of(0.342f, 0.164f, 0.234f)));
|
|
|
+ assertThat(queryVector.value(), equalTo(List.of(0.0f, 1.0f, 2.0f)));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void checkDenseVectorEvalCastingKnn(String fieldName) {
|
|
|
+ var plan = analyze(String.format(Locale.ROOT, """
|
|
|
+ from test | eval query = to_dense_vector([0, 1, 2]) | where knn(%s, query)
|
|
|
+ """, fieldName), "mapping-dense_vector.json");
|
|
|
+
|
|
|
+ var limit = as(plan, Limit.class);
|
|
|
+ var filter = as(limit.child(), Filter.class);
|
|
|
+ var knn = as(filter.condition(), Knn.class);
|
|
|
+ var queryVector = as(knn.query(), ReferenceAttribute.class);
|
|
|
+ assertEquals(DataType.DENSE_VECTOR, queryVector.dataType());
|
|
|
+ assertThat(queryVector.name(), is("query"));
|
|
|
}
|
|
|
|
|
|
public void testDenseVectorImplicitCastingSimilarityFunctions() {
|
|
|
+ assumeTrue("dense vector casting must be enabled", EsqlCapabilities.Cap.TO_DENSE_VECTOR_FUNCTION.isEnabled());
|
|
|
+
|
|
|
if (EsqlCapabilities.Cap.COSINE_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
checkDenseVectorImplicitCastingSimilarityFunction(
|
|
|
"v_cosine(float_vector, [0.342, 0.164, 0.234])",
|
|
|
- List.of(0.342f, 0.164f, 0.234f)
|
|
|
+ List.of(0.342, 0.164, 0.234)
|
|
|
);
|
|
|
- checkDenseVectorImplicitCastingSimilarityFunction("v_cosine(byte_vector, [1, 2, 3])", List.of(1f, 2f, 3f));
|
|
|
+ checkDenseVectorImplicitCastingSimilarityFunction("v_cosine(byte_vector, [1, 2, 3])", List.of(1, 2, 3));
|
|
|
}
|
|
|
if (EsqlCapabilities.Cap.DOT_PRODUCT_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
checkDenseVectorImplicitCastingSimilarityFunction(
|
|
|
"v_dot_product(float_vector, [0.342, 0.164, 0.234])",
|
|
|
- List.of(0.342f, 0.164f, 0.234f)
|
|
|
+ List.of(0.342, 0.164, 0.234)
|
|
|
);
|
|
|
- checkDenseVectorImplicitCastingSimilarityFunction("v_dot_product(byte_vector, [1, 2, 3])", List.of(1f, 2f, 3f));
|
|
|
+ checkDenseVectorImplicitCastingSimilarityFunction("v_dot_product(byte_vector, [1, 2, 3])", List.of(1, 2, 3));
|
|
|
}
|
|
|
if (EsqlCapabilities.Cap.L1_NORM_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
checkDenseVectorImplicitCastingSimilarityFunction(
|
|
|
"v_l1_norm(float_vector, [0.342, 0.164, 0.234])",
|
|
|
- List.of(0.342f, 0.164f, 0.234f)
|
|
|
+ List.of(0.342, 0.164, 0.234)
|
|
|
);
|
|
|
- checkDenseVectorImplicitCastingSimilarityFunction("v_l1_norm(byte_vector, [1, 2, 3])", List.of(1f, 2f, 3f));
|
|
|
+ checkDenseVectorImplicitCastingSimilarityFunction("v_l1_norm(byte_vector, [1, 2, 3])", List.of(1, 2, 3));
|
|
|
}
|
|
|
if (EsqlCapabilities.Cap.L2_NORM_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
checkDenseVectorImplicitCastingSimilarityFunction(
|
|
|
"v_l2_norm(float_vector, [0.342, 0.164, 0.234])",
|
|
|
- List.of(0.342f, 0.164f, 0.234f)
|
|
|
+ List.of(0.342, 0.164, 0.234)
|
|
|
);
|
|
|
- checkDenseVectorImplicitCastingSimilarityFunction("v_l2_norm(float_vector, [1, 2, 3])", List.of(1f, 2f, 3f));
|
|
|
- checkDenseVectorImplicitCastingSimilarityFunction("v_l2_norm(byte_vector, [1, 2, 3])", List.of(1f, 2f, 3f));
|
|
|
+ checkDenseVectorImplicitCastingSimilarityFunction("v_l2_norm(float_vector, [1, 2, 3])", List.of(1, 2, 3));
|
|
|
+ checkDenseVectorImplicitCastingSimilarityFunction("v_l2_norm(byte_vector, [1, 2, 3])", List.of(1, 2, 3));
|
|
|
if (EsqlCapabilities.Cap.DENSE_VECTOR_FIELD_TYPE_BIT_ELEMENTS.isEnabled()) {
|
|
|
- checkDenseVectorImplicitCastingSimilarityFunction("v_l2_norm(bit_vector, [1, 2])", List.of(1f, 2f));
|
|
|
+ checkDenseVectorImplicitCastingSimilarityFunction("v_l2_norm(bit_vector, [1, 2])", List.of(1, 2));
|
|
|
}
|
|
|
}
|
|
|
if (EsqlCapabilities.Cap.HAMMING_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
checkDenseVectorImplicitCastingSimilarityFunction(
|
|
|
"v_hamming(byte_vector, [0.342, 0.164, 0.234])",
|
|
|
- List.of(0.342f, 0.164f, 0.234f)
|
|
|
+ List.of(0.342, 0.164, 0.234)
|
|
|
);
|
|
|
- checkDenseVectorImplicitCastingSimilarityFunction("v_hamming(byte_vector, [1, 2, 3])", List.of(1f, 2f, 3f));
|
|
|
+ checkDenseVectorImplicitCastingSimilarityFunction("v_hamming(byte_vector, [1, 2, 3])", List.of(1, 2, 3));
|
|
|
if (EsqlCapabilities.Cap.DENSE_VECTOR_FIELD_TYPE_BIT_ELEMENTS.isEnabled()) {
|
|
|
- checkDenseVectorImplicitCastingSimilarityFunction("v_hamming(bit_vector, [1, 2])", List.of(1f, 2f));
|
|
|
+ checkDenseVectorImplicitCastingSimilarityFunction("v_hamming(bit_vector, [1, 2])", List.of(1, 2));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -2431,35 +2466,82 @@ public class AnalyzerTests extends ESTestCase {
|
|
|
var similarity = as(alias.child(), VectorSimilarityFunction.class);
|
|
|
var left = as(similarity.left(), FieldAttribute.class);
|
|
|
assertThat(List.of("float_vector", "byte_vector", "bit_vector"), hasItem(left.name()));
|
|
|
- var right = as(similarity.right(), Literal.class);
|
|
|
- assertThat(right.dataType(), is(DENSE_VECTOR));
|
|
|
- assertThat(right.value(), equalTo(expectedElems));
|
|
|
+ var right = as(similarity.right(), ToDenseVector.class);
|
|
|
+ var literal = as(right.field(), Literal.class);
|
|
|
+ assertThat(literal.value(), equalTo(expectedElems));
|
|
|
}
|
|
|
|
|
|
- public void testNoDenseVectorFailsSimilarityFunction() {
|
|
|
+ public void testDenseVectorEvalCastingSimilarityFunctions() {
|
|
|
+ assumeTrue("dense vector casting must be enabled", EsqlCapabilities.Cap.TO_DENSE_VECTOR_FUNCTION.isEnabled());
|
|
|
+
|
|
|
if (EsqlCapabilities.Cap.COSINE_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
- checkNoDenseVectorFailsSimilarityFunction("v_cosine([0, 1, 2], 0.342)");
|
|
|
+ checkDenseVectorEvalCastingSimilarityFunction("v_cosine(float_vector, query)");
|
|
|
+ checkDenseVectorEvalCastingSimilarityFunction("v_cosine(byte_vector, query)");
|
|
|
+ }
|
|
|
+ if (EsqlCapabilities.Cap.DOT_PRODUCT_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
+ checkDenseVectorEvalCastingSimilarityFunction("v_dot_product(float_vector, query)");
|
|
|
+ checkDenseVectorEvalCastingSimilarityFunction("v_dot_product(byte_vector, query)");
|
|
|
+ }
|
|
|
+ if (EsqlCapabilities.Cap.L1_NORM_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
+ checkDenseVectorEvalCastingSimilarityFunction("v_l1_norm(float_vector, query)");
|
|
|
+ checkDenseVectorEvalCastingSimilarityFunction("v_l1_norm(byte_vector, query)");
|
|
|
+ }
|
|
|
+ if (EsqlCapabilities.Cap.L2_NORM_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
+ checkDenseVectorEvalCastingSimilarityFunction("v_l2_norm(float_vector, query)");
|
|
|
+ checkDenseVectorEvalCastingSimilarityFunction("v_l2_norm(float_vector, query)");
|
|
|
+ }
|
|
|
+ if (EsqlCapabilities.Cap.HAMMING_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
+ checkDenseVectorEvalCastingSimilarityFunction("v_hamming(byte_vector, query)");
|
|
|
+ checkDenseVectorEvalCastingSimilarityFunction("v_hamming(byte_vector, query)");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void checkDenseVectorEvalCastingSimilarityFunction(String similarityFunction) {
|
|
|
+ var plan = analyze(String.format(Locale.ROOT, """
|
|
|
+ from test | eval query = to_dense_vector([0.342, 0.164, 0.234]) | eval similarity = %s
|
|
|
+ """, similarityFunction), "mapping-dense_vector.json");
|
|
|
+
|
|
|
+ var limit = as(plan, Limit.class);
|
|
|
+ var eval = as(limit.child(), Eval.class);
|
|
|
+ var alias = as(eval.fields().get(0), Alias.class);
|
|
|
+ assertEquals("similarity", alias.name());
|
|
|
+ var similarity = as(alias.child(), VectorSimilarityFunction.class);
|
|
|
+ var left = as(similarity.left(), FieldAttribute.class);
|
|
|
+ assertThat(List.of("float_vector", "byte_vector"), hasItem(left.name()));
|
|
|
+ var right = as(similarity.right(), ReferenceAttribute.class);
|
|
|
+ assertThat(right.dataType(), is(DENSE_VECTOR));
|
|
|
+ assertThat(right.name(), is("query"));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testVectorFunctionHexImplicitCastingError() {
|
|
|
+ assumeTrue("dense vector casting must be enabled", EsqlCapabilities.Cap.TO_DENSE_VECTOR_FUNCTION.isEnabled());
|
|
|
+
|
|
|
+ if (EsqlCapabilities.Cap.KNN_FUNCTION_V5.isEnabled()) {
|
|
|
+ checkVectorFunctionHexImplicitCastingError("where knn(float_vector, \"notcorrect\")");
|
|
|
}
|
|
|
if (EsqlCapabilities.Cap.DOT_PRODUCT_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
- checkNoDenseVectorFailsSimilarityFunction("v_dot_product([0, 1, 2], 0.342)");
|
|
|
+ checkVectorFunctionHexImplicitCastingError("eval s = v_dot_product(\"notcorrect\", 0.342)");
|
|
|
}
|
|
|
if (EsqlCapabilities.Cap.L1_NORM_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
- checkNoDenseVectorFailsSimilarityFunction("v_l1_norm([0, 1, 2], 0.342)");
|
|
|
+ checkVectorFunctionHexImplicitCastingError("eval s = v_l1_norm(\"notcorrect\", 0.342)");
|
|
|
}
|
|
|
if (EsqlCapabilities.Cap.L2_NORM_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
- checkNoDenseVectorFailsSimilarityFunction("v_l2_norm([0, 1, 2], 0.342)");
|
|
|
+ checkVectorFunctionHexImplicitCastingError("eval s = v_l2_norm(\"notcorrect\", 0.342)");
|
|
|
}
|
|
|
if (EsqlCapabilities.Cap.HAMMING_VECTOR_SIMILARITY_FUNCTION.isEnabled()) {
|
|
|
- checkNoDenseVectorFailsSimilarityFunction("v_hamming([0, 1, 2], 0.342)");
|
|
|
+ checkVectorFunctionHexImplicitCastingError("eval s = v_hamming(\"notcorrect\", 0.342)");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void checkNoDenseVectorFailsSimilarityFunction(String similarityFunction) {
|
|
|
- var query = String.format(Locale.ROOT, "row a = 1 | eval similarity = %s", similarityFunction);
|
|
|
- VerificationException error = expectThrows(VerificationException.class, () -> analyze(query));
|
|
|
+ private void checkVectorFunctionHexImplicitCastingError(String clause) {
|
|
|
+ var query = "from test | " + clause;
|
|
|
+ VerificationException error = expectThrows(VerificationException.class, () -> analyze(query, "mapping-dense_vector.json"));
|
|
|
assertThat(
|
|
|
error.getMessage(),
|
|
|
- containsString("second argument of [" + similarityFunction + "] must be" + " [dense_vector], found value [0.342] type [double]")
|
|
|
+ containsString(
|
|
|
+ "Cannot convert string [notcorrect] to [DENSE_VECTOR], "
|
|
|
+ + "error [notcorrect is not a valid hex string: not a hexadecimal digit: \"n\" = 110]"
|
|
|
+ )
|
|
|
);
|
|
|
}
|
|
|
|
|
@@ -2475,20 +2557,9 @@ public class AnalyzerTests extends ESTestCase {
|
|
|
var alias = as(eval.fields().get(0), Alias.class);
|
|
|
assertEquals("scalar", alias.name());
|
|
|
var scalar = as(alias.child(), Magnitude.class);
|
|
|
- var child = as(scalar.field(), Literal.class);
|
|
|
- assertThat(child.dataType(), is(DENSE_VECTOR));
|
|
|
- assertThat(child.value(), equalTo(List.of(1.0f, 2.0f, 3.0f)));
|
|
|
- }
|
|
|
-
|
|
|
- public void testNoDenseVectorFailsForMagnitude() {
|
|
|
- assumeTrue("v_magnitude not available", EsqlCapabilities.Cap.MAGNITUDE_SCALAR_VECTOR_FUNCTION.isEnabled());
|
|
|
-
|
|
|
- var query = String.format(Locale.ROOT, "row a = 1 | eval scalar = v_magnitude(0.342)");
|
|
|
- VerificationException error = expectThrows(VerificationException.class, () -> analyze(query));
|
|
|
- assertThat(
|
|
|
- error.getMessage(),
|
|
|
- containsString("first argument of [v_magnitude(0.342)] must be [dense_vector], found value [0.342] type [double]")
|
|
|
- );
|
|
|
+ var child = as(scalar.field(), ToDenseVector.class);
|
|
|
+ var literal = as(child.field(), Literal.class);
|
|
|
+ assertThat(literal.value(), equalTo(List.of(1, 2, 3)));
|
|
|
}
|
|
|
|
|
|
public void testRateRequiresCounterTypes() {
|