|
35 | 35 | import org.elasticsearch.common.Strings;
|
36 | 36 | import org.elasticsearch.common.geo.ShapeRelation;
|
37 | 37 | import org.elasticsearch.common.lucene.search.function.ScriptScoreQuery;
|
| 38 | +import org.elasticsearch.common.settings.Settings; |
38 | 39 | import org.elasticsearch.common.time.DateFormatter;
|
39 | 40 | import org.elasticsearch.index.IndexVersion;
|
40 | 41 | import org.elasticsearch.index.fielddata.DateScriptFieldData;
|
|
47 | 48 | import org.elasticsearch.script.ScriptFactory;
|
48 | 49 | import org.elasticsearch.script.ScriptType;
|
49 | 50 | import org.elasticsearch.search.MultiValueMode;
|
| 51 | +import org.elasticsearch.search.lookup.SearchLookup; |
50 | 52 | import org.elasticsearch.xcontent.XContentBuilder;
|
51 | 53 |
|
52 | 54 | import java.io.IOException;
|
|
55 | 57 | import java.time.ZonedDateTime;
|
56 | 58 | import java.time.temporal.ChronoUnit;
|
57 | 59 | import java.util.ArrayList;
|
| 60 | +import java.util.Arrays; |
58 | 61 | import java.util.List;
|
59 | 62 | import java.util.Map;
|
60 | 63 |
|
|
65 | 68 | import static org.hamcrest.Matchers.containsString;
|
66 | 69 | import static org.hamcrest.Matchers.equalTo;
|
67 | 70 | import static org.hamcrest.Matchers.instanceOf;
|
| 71 | +import static org.hamcrest.Matchers.nullValue; |
68 | 72 |
|
69 | 73 | public class DateScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTestCase {
|
70 | 74 |
|
| 75 | + private static final Long MALFORMED_DATE = null; |
| 76 | + |
71 | 77 | @Override
|
72 | 78 | protected ScriptFactory parseFromSource() {
|
73 | 79 | return DateFieldScript.PARSE_FROM_SOURCE;
|
@@ -502,6 +508,155 @@ public void testBlockLoader() throws IOException {
|
502 | 508 | }
|
503 | 509 | }
|
504 | 510 |
|
| 511 | + public void testBlockLoaderSourceOnlyRuntimeField() throws IOException { |
| 512 | + try ( |
| 513 | + Directory directory = newDirectory(); |
| 514 | + RandomIndexWriter iw = new RandomIndexWriter(random(), directory, newIndexWriterConfig().setMergePolicy(NoMergePolicy.INSTANCE)) |
| 515 | + ) { |
| 516 | + // given |
| 517 | + iw.addDocuments( |
| 518 | + List.of( |
| 519 | + List.of(new StoredField("_source", new BytesRef("{\"test\": [1595432181354]}"))), |
| 520 | + List.of(new StoredField("_source", new BytesRef("{\"test\": [\"2020-07-22T16:09:41.355Z\"]}"))), |
| 521 | + List.of(new StoredField("_source", new BytesRef("{\"test\": [null]}"))), |
| 522 | + List.of(new StoredField("_source", new BytesRef("{\"test\": []}"))), |
| 523 | + List.of(new StoredField("_source", new BytesRef("{\"test\": [\"malformed\"]}"))) |
| 524 | + ) |
| 525 | + ); |
| 526 | + DateScriptFieldType fieldType = simpleSourceOnlyMappedFieldType(); |
| 527 | + List<Long> expected = Arrays.asList( |
| 528 | + 1595432181354L, |
| 529 | + Instant.parse("2020-07-22T16:09:41.355Z").toEpochMilli(), |
| 530 | + null, |
| 531 | + null, |
| 532 | + MALFORMED_DATE |
| 533 | + ); |
| 534 | + |
| 535 | + try (DirectoryReader reader = iw.getReader()) { |
| 536 | + // when |
| 537 | + BlockLoader loader = fieldType.blockLoader(blContext(Settings.EMPTY, true)); |
| 538 | + |
| 539 | + // then |
| 540 | + |
| 541 | + // assert loader is of expected instance type |
| 542 | + assertThat(loader, instanceOf(DateScriptBlockDocValuesReader.DateScriptBlockLoader.class)); |
| 543 | + |
| 544 | + // ignored source doesn't support column at a time loading: |
| 545 | + var columnAtATimeLoader = loader.columnAtATimeReader(reader.leaves().getFirst()); |
| 546 | + assertThat(columnAtATimeLoader, instanceOf(DateScriptBlockDocValuesReader.class)); |
| 547 | + |
| 548 | + var rowStrideReader = loader.rowStrideReader(reader.leaves().getFirst()); |
| 549 | + assertThat(rowStrideReader, instanceOf(DateScriptBlockDocValuesReader.class)); |
| 550 | + |
| 551 | + // assert values |
| 552 | + assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType, 0), equalTo(expected)); |
| 553 | + assertThat(blockLoaderReadValuesFromRowStrideReader(reader, fieldType), equalTo(expected)); |
| 554 | + } |
| 555 | + } |
| 556 | + } |
| 557 | + |
| 558 | + public void testBlockLoaderSourceOnlyRuntimeFieldWithSyntheticSource() throws IOException { |
| 559 | + try ( |
| 560 | + Directory directory = newDirectory(); |
| 561 | + RandomIndexWriter iw = new RandomIndexWriter(random(), directory, newIndexWriterConfig().setMergePolicy(NoMergePolicy.INSTANCE)) |
| 562 | + ) { |
| 563 | + // given |
| 564 | + iw.addDocuments( |
| 565 | + List.of( |
| 566 | + createDocumentWithIgnoredSource("[1595432181354]"), |
| 567 | + createDocumentWithIgnoredSource("[\"2020-07-22T16:09:41.355Z\"]"), |
| 568 | + createDocumentWithIgnoredSource("[\"\"]"), |
| 569 | + createDocumentWithIgnoredSource("[\"malformed\"]") |
| 570 | + ) |
| 571 | + ); |
| 572 | + |
| 573 | + Settings settings = Settings.builder().put("index.mapping.source.mode", "synthetic").build(); |
| 574 | + DateScriptFieldType fieldType = simpleSourceOnlyMappedFieldType(); |
| 575 | + List<Long> expected = Arrays.asList( |
| 576 | + 1595432181354L, |
| 577 | + Instant.parse("2020-07-22T16:09:41.355Z").toEpochMilli(), |
| 578 | + null, |
| 579 | + MALFORMED_DATE |
| 580 | + ); |
| 581 | + |
| 582 | + try (DirectoryReader reader = iw.getReader()) { |
| 583 | + // when |
| 584 | + BlockLoader loader = fieldType.blockLoader(blContext(settings, true)); |
| 585 | + |
| 586 | + // then |
| 587 | + |
| 588 | + // assert loader is of expected instance type |
| 589 | + assertThat(loader, instanceOf(FallbackSyntheticSourceBlockLoader.class)); |
| 590 | + |
| 591 | + // ignored source doesn't support column at a time loading: |
| 592 | + var columnAtATimeLoader = loader.columnAtATimeReader(reader.leaves().getFirst()); |
| 593 | + assertThat(columnAtATimeLoader, nullValue()); |
| 594 | + |
| 595 | + var rowStrideReader = loader.rowStrideReader(reader.leaves().getFirst()); |
| 596 | + assertThat( |
| 597 | + rowStrideReader.getClass().getName(), |
| 598 | + equalTo("org.elasticsearch.index.mapper.FallbackSyntheticSourceBlockLoader$IgnoredSourceRowStrideReader") |
| 599 | + ); |
| 600 | + |
| 601 | + // assert values |
| 602 | + assertThat(blockLoaderReadValuesFromRowStrideReader(settings, reader, fieldType, true), equalTo(expected)); |
| 603 | + } |
| 604 | + } |
| 605 | + } |
| 606 | + |
| 607 | + /** |
| 608 | + * Returns a source only mapped field type. This is useful, since the available build() function doesn't override isParsedFromSource() |
| 609 | + */ |
| 610 | + private DateScriptFieldType simpleSourceOnlyMappedFieldType() { |
| 611 | + Script script = new Script(ScriptType.INLINE, "test", "", emptyMap()); |
| 612 | + DateFieldScript.Factory factory = new DateFieldScript.Factory() { |
| 613 | + @Override |
| 614 | + public DateFieldScript.LeafFactory newFactory( |
| 615 | + String fieldName, |
| 616 | + Map<String, Object> params, |
| 617 | + SearchLookup searchLookup, |
| 618 | + DateFormatter formatter, |
| 619 | + OnScriptError onScriptError |
| 620 | + ) { |
| 621 | + return ctx -> new DateFieldScript( |
| 622 | + fieldName, |
| 623 | + params, |
| 624 | + searchLookup, |
| 625 | + DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER, |
| 626 | + onScriptError, |
| 627 | + ctx |
| 628 | + ) { |
| 629 | + @Override |
| 630 | + @SuppressWarnings("unchecked") |
| 631 | + public void execute() { |
| 632 | + Map<String, Object> source = (Map<String, Object>) this.getParams().get("_source"); |
| 633 | + for (Object timestamp : (List<?>) source.get("test")) { |
| 634 | + Parse parse = new Parse(this); |
| 635 | + try { |
| 636 | + emit(parse.parse(timestamp)); |
| 637 | + } catch (Exception e) { |
| 638 | + // skip |
| 639 | + } |
| 640 | + } |
| 641 | + } |
| 642 | + }; |
| 643 | + } |
| 644 | + |
| 645 | + @Override |
| 646 | + public boolean isParsedFromSource() { |
| 647 | + return true; |
| 648 | + } |
| 649 | + }; |
| 650 | + return new DateScriptFieldType( |
| 651 | + "test", |
| 652 | + factory, |
| 653 | + DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER, |
| 654 | + script, |
| 655 | + emptyMap(), |
| 656 | + OnScriptError.FAIL |
| 657 | + ); |
| 658 | + } |
| 659 | + |
505 | 660 | @Override
|
506 | 661 | protected Query randomTermsQuery(MappedFieldType ft, SearchExecutionContext ctx) {
|
507 | 662 | return ft.termsQuery(randomList(1, 100, DateScriptFieldTypeTests::randomDate), ctx);
|
|
0 commit comments