|
44 | 44 | import static org.elasticsearch.test.ListMatcher.matchesList; |
45 | 45 | import static org.elasticsearch.test.MapMatcher.assertMap; |
46 | 46 | import static org.elasticsearch.test.MapMatcher.matchesMap; |
47 | | -import static org.elasticsearch.xpack.esql.action.EsqlResolveFieldsResponse.RESOLVE_FIELDS_RESPONSE_CREATED_TV; |
| 47 | +import static org.elasticsearch.xpack.esql.action.EsqlResolveFieldsResponse.RESOLVE_FIELDS_RESPONSE_USED_TV; |
| 48 | +import static org.elasticsearch.xpack.esql.core.type.DataType.DataTypesTransportVersions.ESQL_AGGREGATE_METRIC_DOUBLE_CREATED_VERSION; |
| 49 | +import static org.elasticsearch.xpack.esql.core.type.DataType.DataTypesTransportVersions.ESQL_DENSE_VECTOR_CREATED_VERSION; |
| 50 | +import static org.elasticsearch.xpack.esql.core.type.DataType.DataTypesTransportVersions.INDEX_SOURCE; |
48 | 51 | import static org.hamcrest.Matchers.any; |
49 | 52 | import static org.hamcrest.Matchers.anyOf; |
50 | 53 | import static org.hamcrest.Matchers.containsString; |
|
71 | 74 | public class AllSupportedFieldsTestCase extends ESRestTestCase { |
72 | 75 | private static final Logger logger = LogManager.getLogger(FieldExtractorTestCase.class); |
73 | 76 |
|
74 | | - private static final TransportVersion INDEX_SOURCE = TransportVersion.fromName("index_source"); |
75 | | - |
76 | 77 | @Rule(order = Integer.MIN_VALUE) |
77 | 78 | public ProfileLogger profileLogger = new ProfileLogger(); |
78 | 79 |
|
@@ -329,6 +330,76 @@ public final void testFetchDenseVector() throws IOException { |
329 | 330 | assertMap(indexToRow(columns, values), expectedAllValues); |
330 | 331 | } |
331 | 332 |
|
| 333 | + /** |
| 334 | + * Tests fetching {@code aggregate_metric_double} if possible. Uses the {@code dense_vector_agg_metric_double_if_fns} |
| 335 | + * work around if required. |
| 336 | + */ |
| 337 | + public final void testFetchAggregateMetricDouble() throws IOException { |
| 338 | + Map<String, Object> response; |
| 339 | + try { |
| 340 | + String request = """ |
| 341 | + | EVAL strjunk = TO_STRING(f_aggregate_metric_double) |
| 342 | + | KEEP _index, f_aggregate_metric_double |
| 343 | + | LIMIT 1000 |
| 344 | + """; |
| 345 | + if (denseVectorAggMetricDoubleIfVersion() == false) { |
| 346 | + request = """ |
| 347 | + | EVAL junk = TO_AGGREGATE_METRIC_DOUBLE(1) // workaround to enable fetching aggregate_metric_double |
| 348 | + """ + request; |
| 349 | + } |
| 350 | + response = esql(request); |
| 351 | + if ((Boolean) response.get("is_partial")) { |
| 352 | + Map<?, ?> clusters = (Map<?, ?>) response.get("_clusters"); |
| 353 | + Map<?, ?> details = (Map<?, ?>) clusters.get("details"); |
| 354 | + |
| 355 | + boolean foundError = false; |
| 356 | + for (Map.Entry<?, ?> cluster : details.entrySet()) { |
| 357 | + String failures = cluster.getValue().toString(); |
| 358 | + if (denseVectorAggMetricDoubleIfFns()) { |
| 359 | + throw new AssertionError("should correctly fetch the aggregate_metric_double: " + failures); |
| 360 | + } |
| 361 | + foundError |= failures.contains("doesn't understand data type [AGGREGATE_METRIC_DOUBLE]"); |
| 362 | + } |
| 363 | + assertTrue("didn't find errors: " + details, foundError); |
| 364 | + return; |
| 365 | + } |
| 366 | + } catch (ResponseException e) { |
| 367 | + if (denseVectorAggMetricDoubleIfFns()) { |
| 368 | + throw new AssertionError("should correctly fetch the aggregate_metric_double", e); |
| 369 | + } |
| 370 | + assertThat( |
| 371 | + "old version should fail with this error", |
| 372 | + EntityUtils.toString(e.getResponse().getEntity()), |
| 373 | + anyOf( |
| 374 | + containsString("Unknown function [TO_AGGREGATE_METRIC_DOUBLE]"), |
| 375 | + containsString("Cannot use field [f_aggregate_metric_double] with unsupported type"), |
| 376 | + containsString("doesn't understand data type [AGGREGATE_METRIC_DOUBLE]") |
| 377 | + ) |
| 378 | + ); |
| 379 | + // Failure is expected and fine |
| 380 | + return; |
| 381 | + } |
| 382 | + List<?> columns = (List<?>) response.get("columns"); |
| 383 | + List<?> values = (List<?>) response.get("values"); |
| 384 | + |
| 385 | + MapMatcher expectedColumns = matchesMap().entry("f_aggregate_metric_double", "aggregate_metric_double").entry("_index", "keyword"); |
| 386 | + assertMap(nameToType(columns), expectedColumns); |
| 387 | + |
| 388 | + MapMatcher expectedAllValues = matchesMap(); |
| 389 | + for (Map.Entry<String, NodeInfo> e : expectedIndices().entrySet()) { |
| 390 | + String indexName = e.getKey(); |
| 391 | + NodeInfo nodeInfo = e.getValue(); |
| 392 | + MapMatcher expectedValues = matchesMap(); |
| 393 | + expectedValues = expectedValues.entry( |
| 394 | + "f_aggregate_metric_double", |
| 395 | + "{\"min\":-302.5,\"max\":702.3,\"sum\":200.0,\"value_count\":25}" |
| 396 | + ); |
| 397 | + expectedValues = expectedValues.entry("_index", indexName); |
| 398 | + expectedAllValues = expectedAllValues.entry(indexName, expectedValues); |
| 399 | + } |
| 400 | + assertMap(indexToRow(columns, values), expectedAllValues); |
| 401 | + } |
| 402 | + |
332 | 403 | private Map<String, Object> esql(String query) throws IOException { |
333 | 404 | Request request = new Request("POST", "_query"); |
334 | 405 | XContentBuilder body = JsonXContent.contentBuilder().startObject(); |
@@ -473,21 +544,15 @@ private Matcher<?> expectedValue(DataType type, NodeInfo nodeInfo) throws IOExce |
473 | 544 | case GEO_SHAPE -> equalTo("POINT (-71.34 41.12)"); |
474 | 545 | case NULL -> nullValue(); |
475 | 546 | case AGGREGATE_METRIC_DOUBLE -> { |
476 | | - /* |
477 | | - * We need both AGGREGATE_METRIC_DOUBLE_CREATED and RESOLVE_FIELDS_RESPONSE_CREATED_TV |
478 | | - * but RESOLVE_FIELDS_RESPONSE_CREATED_TV came last so it's enough to check just it. |
479 | | - */ |
480 | | - if (minVersion().supports(RESOLVE_FIELDS_RESPONSE_CREATED_TV) == false) { |
| 547 | + if (minVersion().supports(RESOLVE_FIELDS_RESPONSE_USED_TV) == false |
| 548 | + || minVersion().supports(ESQL_AGGREGATE_METRIC_DOUBLE_CREATED_VERSION) == false) { |
481 | 549 | yield nullValue(); |
482 | 550 | } |
483 | 551 | yield equalTo("{\"min\":-302.5,\"max\":702.3,\"sum\":200.0,\"value_count\":25}"); |
484 | 552 | } |
485 | 553 | case DENSE_VECTOR -> { |
486 | | - /* |
487 | | - * We need both DENSE_VECTOR_CREATED and RESOLVE_FIELDS_RESPONSE_CREATED_TV |
488 | | - * but RESOLVE_FIELDS_RESPONSE_CREATED_TV came last so it's enough to check just it. |
489 | | - */ |
490 | | - if (minVersion().supports(RESOLVE_FIELDS_RESPONSE_CREATED_TV) == false) { |
| 554 | + if (minVersion().supports(RESOLVE_FIELDS_RESPONSE_USED_TV) == false |
| 555 | + || minVersion().supports(ESQL_DENSE_VECTOR_CREATED_VERSION) == false) { |
491 | 556 | yield nullValue(); |
492 | 557 | } |
493 | 558 | yield equalTo(List.of(0.5, 10.0, 5.9999995)); |
@@ -572,15 +637,24 @@ private Matcher<String> expectedType(DataType type) throws IOException { |
572 | 637 | case BYTE, SHORT -> equalTo("integer"); |
573 | 638 | case HALF_FLOAT, SCALED_FLOAT, FLOAT -> equalTo("double"); |
574 | 639 | case NULL -> equalTo("keyword"); |
575 | | - case AGGREGATE_METRIC_DOUBLE, DENSE_VECTOR -> { |
576 | | - /* |
577 | | - * We need both <type_name>_CREATED and RESOLVE_FIELDS_RESPONSE_CREATED_TV |
578 | | - * but RESOLVE_FIELDS_RESPONSE_CREATED_TV came last so it's enough to check just it. |
579 | | - */ |
580 | | - if (minVersion().supports(RESOLVE_FIELDS_RESPONSE_CREATED_TV) == false) { |
| 640 | + case AGGREGATE_METRIC_DOUBLE -> { |
| 641 | + // RESOLVE_FIELDS_RESPONSE_USED_TV is newer and technically sufficient to check. |
| 642 | + // We also check for ESQL_AGGREGATE_METRIC_DOUBLE_CREATED_VERSION for clarity. |
| 643 | + // Future data types added here should only require the TV when they were created, |
| 644 | + // because it will be after RESOLVE_FIELDS_RESPONSE_USED_TV. |
| 645 | + if (minVersion().supports(RESOLVE_FIELDS_RESPONSE_USED_TV) == false |
| 646 | + || minVersion().supports(ESQL_AGGREGATE_METRIC_DOUBLE_CREATED_VERSION) == false) { |
| 647 | + yield equalTo("unsupported"); |
| 648 | + } |
| 649 | + yield equalTo("aggregate_metric_double"); |
| 650 | + } |
| 651 | + case DENSE_VECTOR -> { |
| 652 | + logger.error("ADFDAFAF " + minVersion()); |
| 653 | + if (minVersion().supports(RESOLVE_FIELDS_RESPONSE_USED_TV) == false |
| 654 | + || minVersion().supports(ESQL_DENSE_VECTOR_CREATED_VERSION) == false) { |
581 | 655 | yield equalTo("unsupported"); |
582 | 656 | } |
583 | | - yield equalTo(type.esType()); |
| 657 | + yield equalTo("dense_vector"); |
584 | 658 | } |
585 | 659 | default -> equalTo(type.esType()); |
586 | 660 | }; |
|
0 commit comments