|
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; |
48 | 50 | import static org.hamcrest.Matchers.any; |
49 | 51 | import static org.hamcrest.Matchers.anyOf; |
50 | 52 | import static org.hamcrest.Matchers.containsString; |
@@ -329,6 +331,76 @@ public final void testFetchDenseVector() throws IOException { |
329 | 331 | assertMap(indexToRow(columns, values), expectedAllValues); |
330 | 332 | } |
331 | 333 |
|
| 334 | + /** |
| 335 | + * Tests fetching {@code aggregate_metric_double} if possible. Uses the {@code dense_vector_agg_metric_double_if_fns} |
| 336 | + * work around if required. |
| 337 | + */ |
| 338 | + public final void testFetchAggregateMetricDouble() throws IOException { |
| 339 | + Map<String, Object> response; |
| 340 | + try { |
| 341 | + String request = """ |
| 342 | + | EVAL strjunk = TO_STRING(f_aggregate_metric_double) |
| 343 | + | KEEP _index, f_aggregate_metric_double |
| 344 | + | LIMIT 1000 |
| 345 | + """; |
| 346 | + if (denseVectorAggMetricDoubleIfVersion() == false) { |
| 347 | + request = """ |
| 348 | + | EVAL junk = TO_AGGREGATE_METRIC_DOUBLE(1) // workaround to enable fetching aggregate_metric_double |
| 349 | + """ + request; |
| 350 | + } |
| 351 | + response = esql(request); |
| 352 | + if ((Boolean) response.get("is_partial")) { |
| 353 | + Map<?, ?> clusters = (Map<?, ?>) response.get("_clusters"); |
| 354 | + Map<?, ?> details = (Map<?, ?>) clusters.get("details"); |
| 355 | + |
| 356 | + boolean foundError = false; |
| 357 | + for (Map.Entry<?, ?> cluster : details.entrySet()) { |
| 358 | + String failures = cluster.getValue().toString(); |
| 359 | + if (denseVectorAggMetricDoubleIfFns()) { |
| 360 | + throw new AssertionError("should correctly fetch the aggregate_metric_double: " + failures); |
| 361 | + } |
| 362 | + foundError |= failures.contains("doesn't understand data type [AGGREGATE_METRIC_DOUBLE]"); |
| 363 | + } |
| 364 | + assertTrue("didn't find errors: " + details, foundError); |
| 365 | + return; |
| 366 | + } |
| 367 | + } catch (ResponseException e) { |
| 368 | + if (denseVectorAggMetricDoubleIfFns()) { |
| 369 | + throw new AssertionError("should correctly fetch the aggregate_metric_double", e); |
| 370 | + } |
| 371 | + assertThat( |
| 372 | + "old version should fail with this error", |
| 373 | + EntityUtils.toString(e.getResponse().getEntity()), |
| 374 | + anyOf( |
| 375 | + containsString("Unknown function [TO_AGGREGATE_METRIC_DOUBLE]"), |
| 376 | + containsString("Cannot use field [f_aggregate_metric_double] with unsupported type"), |
| 377 | + containsString("doesn't understand data type [AGGREGATE_METRIC_DOUBLE]") |
| 378 | + ) |
| 379 | + ); |
| 380 | + // Failure is expected and fine |
| 381 | + return; |
| 382 | + } |
| 383 | + List<?> columns = (List<?>) response.get("columns"); |
| 384 | + List<?> values = (List<?>) response.get("values"); |
| 385 | + |
| 386 | + MapMatcher expectedColumns = matchesMap().entry("f_aggregate_metric_double", "aggregate_metric_double").entry("_index", "keyword"); |
| 387 | + assertMap(nameToType(columns), expectedColumns); |
| 388 | + |
| 389 | + MapMatcher expectedAllValues = matchesMap(); |
| 390 | + for (Map.Entry<String, NodeInfo> e : expectedIndices().entrySet()) { |
| 391 | + String indexName = e.getKey(); |
| 392 | + NodeInfo nodeInfo = e.getValue(); |
| 393 | + MapMatcher expectedValues = matchesMap(); |
| 394 | + expectedValues = expectedValues.entry( |
| 395 | + "f_aggregate_metric_double", |
| 396 | + "{\"min\":-302.5,\"max\":702.3,\"sum\":200.0,\"value_count\":25}" |
| 397 | + ); |
| 398 | + expectedValues = expectedValues.entry("_index", indexName); |
| 399 | + expectedAllValues = expectedAllValues.entry(indexName, expectedValues); |
| 400 | + } |
| 401 | + assertMap(indexToRow(columns, values), expectedAllValues); |
| 402 | + } |
| 403 | + |
332 | 404 | private Map<String, Object> esql(String query) throws IOException { |
333 | 405 | Request request = new Request("POST", "_query"); |
334 | 406 | XContentBuilder body = JsonXContent.contentBuilder().startObject(); |
@@ -473,21 +545,15 @@ private Matcher<?> expectedValue(DataType type, NodeInfo nodeInfo) throws IOExce |
473 | 545 | case GEO_SHAPE -> equalTo("POINT (-71.34 41.12)"); |
474 | 546 | case NULL -> nullValue(); |
475 | 547 | 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) { |
| 548 | + if (minVersion().supports(RESOLVE_FIELDS_RESPONSE_USED_TV) == false |
| 549 | + || minVersion().supports(ESQL_AGGREGATE_METRIC_DOUBLE_CREATED_VERSION) == false) { |
481 | 550 | yield nullValue(); |
482 | 551 | } |
483 | 552 | yield equalTo("{\"min\":-302.5,\"max\":702.3,\"sum\":200.0,\"value_count\":25}"); |
484 | 553 | } |
485 | 554 | 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) { |
| 555 | + if (minVersion().supports(RESOLVE_FIELDS_RESPONSE_USED_TV) == false |
| 556 | + || minVersion().supports(ESQL_DENSE_VECTOR_CREATED_VERSION) == false) { |
491 | 557 | yield nullValue(); |
492 | 558 | } |
493 | 559 | yield equalTo(List.of(0.5, 10.0, 5.9999995)); |
@@ -572,15 +638,20 @@ private Matcher<String> expectedType(DataType type) throws IOException { |
572 | 638 | case BYTE, SHORT -> equalTo("integer"); |
573 | 639 | case HALF_FLOAT, SCALED_FLOAT, FLOAT -> equalTo("double"); |
574 | 640 | 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) { |
| 641 | + case AGGREGATE_METRIC_DOUBLE -> { |
| 642 | + if (minVersion().supports(RESOLVE_FIELDS_RESPONSE_USED_TV) == false |
| 643 | + || minVersion().supports(ESQL_AGGREGATE_METRIC_DOUBLE_CREATED_VERSION) == false) { |
| 644 | + yield equalTo("unsupported"); |
| 645 | + } |
| 646 | + yield equalTo("aggregate_metric_double"); |
| 647 | + } |
| 648 | + case DENSE_VECTOR -> { |
| 649 | + logger.error("ADFDAFAF " + minVersion()); |
| 650 | + if (minVersion().supports(RESOLVE_FIELDS_RESPONSE_USED_TV) == false |
| 651 | + || minVersion().supports(ESQL_DENSE_VECTOR_CREATED_VERSION) == false) { |
581 | 652 | yield equalTo("unsupported"); |
582 | 653 | } |
583 | | - yield equalTo(type.esType()); |
| 654 | + yield equalTo("dense_vector"); |
584 | 655 | } |
585 | 656 | default -> equalTo(type.esType()); |
586 | 657 | }; |
|
0 commit comments