From 48021100492ab317f4f41c411c36a1d87854c38b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lorenzo=20Dematt=C3=A9?= Date: Wed, 24 Apr 2024 15:50:51 +0200 Subject: [PATCH 1/3] Mute testToQuery (#107782) (#107841) Related: #107782 --- .../query/functionscore/FunctionScoreQueryBuilderTests.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/src/test/java/org/elasticsearch/index/query/functionscore/FunctionScoreQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/functionscore/FunctionScoreQueryBuilderTests.java index 9277c2648c907..c4f2b3e8596ef 100644 --- a/server/src/test/java/org/elasticsearch/index/query/functionscore/FunctionScoreQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/functionscore/FunctionScoreQueryBuilderTests.java @@ -282,6 +282,12 @@ protected void doAssertLuceneQuery(FunctionScoreQueryBuilder queryBuilder, Query } } + @Override + @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/107782") + public void testToQuery() throws IOException { + super.testToQuery(); + } + public void testIllegalArguments() { expectThrows(IllegalArgumentException.class, () -> new FunctionScoreQueryBuilder((QueryBuilder) null)); expectThrows(IllegalArgumentException.class, () -> new FunctionScoreQueryBuilder((ScoreFunctionBuilder) null)); From 70cfe6f016a740a0b327dfbf0625b0d2353f82bf Mon Sep 17 00:00:00 2001 From: Alexander Spies Date: Wed, 24 Apr 2024 16:07:50 +0200 Subject: [PATCH 2/3] ESQL: Fix MV_DEDUPE when using data from an index (#107577) Correctly label numerical/boolean blocks loaded from indices, so that MV_DEDUPE works correctly. --- docs/changelog/107577.yaml | 6 +++ .../org/elasticsearch/TransportVersions.java | 1 + .../index/mapper/BlockLoader.java | 8 +-- .../compute/data/AbstractArrayBlock.java | 8 ++- .../org/elasticsearch/compute/data/Block.java | 3 +- .../lucene/ValuesSourceReaderOperator.java | 8 +-- .../mvdedupe/MultivalueDedupeBoolean.java | 2 +- .../ValuesSourceReaderOperatorTests.java | 49 +++++++++++------- .../elasticsearch/xpack/esql/CsvAssert.java | 4 +- .../xpack/esql/plugin/EsqlFeatures.java | 9 +++- .../AbstractMultivalueFunctionTestCase.java | 3 ++ .../rest-api-spec/test/esql/100_bug_fix.yml | 51 +++++++++++++++++++ 12 files changed, 122 insertions(+), 30 deletions(-) create mode 100644 docs/changelog/107577.yaml diff --git a/docs/changelog/107577.yaml b/docs/changelog/107577.yaml new file mode 100644 index 0000000000000..a9a3c36a0e04d --- /dev/null +++ b/docs/changelog/107577.yaml @@ -0,0 +1,6 @@ +pr: 107577 +summary: "ESQL: Fix MV_DEDUPE when using data from an index" +area: ES|QL +type: bug +issues: + - 104745 diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java index af2a261bf5008..2bdb3368e1b5c 100644 --- a/server/src/main/java/org/elasticsearch/TransportVersions.java +++ b/server/src/main/java/org/elasticsearch/TransportVersions.java @@ -182,6 +182,7 @@ static TransportVersion def(int id) { public static final TransportVersion TOP_LEVEL_KNN_SUPPORT_QUERY_NAME = def(8_641_00_0); public static final TransportVersion INDEX_SEGMENTS_VECTOR_FORMATS = def(8_642_00_0); public static final TransportVersion ADD_RESOURCE_ALREADY_UPLOADED_EXCEPTION = def(8_643_00_0); + public static final TransportVersion ESQL_MV_ORDERING_SORTED_ASCENDING = def(8_644_00_0); /* * STOP! READ THIS FIRST! No, really, diff --git a/server/src/main/java/org/elasticsearch/index/mapper/BlockLoader.java b/server/src/main/java/org/elasticsearch/index/mapper/BlockLoader.java index fbb742ea7a7e9..fefc49e470d58 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/BlockLoader.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/BlockLoader.java @@ -331,7 +331,7 @@ interface Docs { interface BlockFactory { /** * Build a builder to load booleans as loaded from doc values. Doc values - * load booleans deduplicated and in sorted order. + * load booleans in sorted order. */ BooleanBuilder booleansFromDocValues(int expectedCount); @@ -353,7 +353,7 @@ interface BlockFactory { /** * Build a builder to load doubles as loaded from doc values. - * Doc values load doubles deduplicated and in sorted order. + * Doc values load doubles in sorted order. */ DoubleBuilder doublesFromDocValues(int expectedCount); @@ -364,7 +364,7 @@ interface BlockFactory { /** * Build a builder to load ints as loaded from doc values. - * Doc values load ints deduplicated and in sorted order. + * Doc values load ints in sorted order. */ IntBuilder intsFromDocValues(int expectedCount); @@ -375,7 +375,7 @@ interface BlockFactory { /** * Build a builder to load longs as loaded from doc values. - * Doc values load longs deduplicated and in sorted order. + * Doc values load longs in sorted order. */ LongBuilder longsFromDocValues(int expectedCount); diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AbstractArrayBlock.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AbstractArrayBlock.java index f163c630e259c..74191970db896 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AbstractArrayBlock.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AbstractArrayBlock.java @@ -7,6 +7,7 @@ package org.elasticsearch.compute.data; +import org.elasticsearch.TransportVersions; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.core.Nullable; @@ -178,6 +179,11 @@ void writeSubFields(StreamOutput out) throws IOException { if (nullsMask != null) { out.writeLongArray(nullsMask.toLongArray()); } - out.writeEnum(mvOrdering); + if (out.getTransportVersion().before(TransportVersions.ESQL_MV_ORDERING_SORTED_ASCENDING) + && mvOrdering == MvOrdering.SORTED_ASCENDING) { + out.writeEnum(MvOrdering.UNORDERED); + } else { + out.writeEnum(mvOrdering); + } } } diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/Block.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/Block.java index 0e34eaa68881f..1e6422a5c31da 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/Block.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/Block.java @@ -121,7 +121,8 @@ public interface Block extends Accountable, BlockLoader.Block, NamedWriteable, R enum MvOrdering { UNORDERED(false, false), DEDUPLICATED_UNORDERD(true, false), - DEDUPLICATED_AND_SORTED_ASCENDING(true, true); + DEDUPLICATED_AND_SORTED_ASCENDING(true, true), + SORTED_ASCENDING(false, true); private final boolean deduplicated; private final boolean sortedAscending; diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperator.java index eab2a314b2074..06b1375ac057e 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperator.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperator.java @@ -580,7 +580,7 @@ private ComputeBlockLoaderFactory(BlockFactory factory, int pageSize) { @Override public BlockLoader.BooleanBuilder booleansFromDocValues(int expectedCount) { - return factory.newBooleanBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING); + return factory.newBooleanBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.SORTED_ASCENDING); } @Override @@ -600,7 +600,7 @@ public BlockLoader.BytesRefBuilder bytesRefs(int expectedCount) { @Override public BlockLoader.DoubleBuilder doublesFromDocValues(int expectedCount) { - return factory.newDoubleBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING); + return factory.newDoubleBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.SORTED_ASCENDING); } @Override @@ -610,7 +610,7 @@ public BlockLoader.DoubleBuilder doubles(int expectedCount) { @Override public BlockLoader.IntBuilder intsFromDocValues(int expectedCount) { - return factory.newIntBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING); + return factory.newIntBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.SORTED_ASCENDING); } @Override @@ -620,7 +620,7 @@ public BlockLoader.IntBuilder ints(int expectedCount) { @Override public BlockLoader.LongBuilder longsFromDocValues(int expectedCount) { - return factory.newLongBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING); + return factory.newLongBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.SORTED_ASCENDING); } @Override diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/mvdedupe/MultivalueDedupeBoolean.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/mvdedupe/MultivalueDedupeBoolean.java index b78efd5c870bc..a2f65d50a7654 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/mvdedupe/MultivalueDedupeBoolean.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/mvdedupe/MultivalueDedupeBoolean.java @@ -43,7 +43,7 @@ public MultivalueDedupeBoolean(BooleanBlock block) { * Dedupe values using an adaptive algorithm based on the size of the input list. */ public BooleanBlock dedupeToBlock(BlockFactory blockFactory) { - if (false == block.mayHaveMultivaluedFields()) { + if (block.mvDeduplicated()) { block.incRef(); return block; } diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperatorTests.java index 2402e6f656db0..c9d4c7f50d289 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperatorTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperatorTests.java @@ -403,6 +403,7 @@ public void testLoadAll() { loadSimpleAndAssert( driverContext, CannedSourceOperator.collectPages(simpleInput(driverContext.blockFactory(), between(100, 5000))), + Block.MvOrdering.SORTED_ASCENDING, Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING ); } @@ -416,6 +417,7 @@ public void testLoadAllInOnePage() { CannedSourceOperator.collectPages(simpleInput(driverContext.blockFactory(), between(100, 5000))) ) ), + Block.MvOrdering.UNORDERED, Block.MvOrdering.UNORDERED ); } @@ -426,7 +428,7 @@ public void testManySingleDocPages() { List input = CannedSourceOperator.collectPages(simpleInput(driverContext, numDocs, between(1, numDocs), 1)); Randomness.shuffle(input); List operators = new ArrayList<>(); - Checks checks = new Checks(Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING); + Checks checks = new Checks(Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING, Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING); FieldCase testCase = new FieldCase( new KeywordFieldMapper.KeywordFieldType("kwd"), ElementType.BYTES_REF, @@ -457,6 +459,7 @@ public void testEmpty() { loadSimpleAndAssert( driverContext, CannedSourceOperator.collectPages(simpleInput(driverContext.blockFactory(), 0)), + Block.MvOrdering.UNORDERED, Block.MvOrdering.UNORDERED ); } @@ -475,7 +478,7 @@ public void testLoadAllInOnePageShuffled() { shuffledBlocks[b] = source.getBlock(b).filter(shuffleArray); } source = new Page(shuffledBlocks); - loadSimpleAndAssert(driverContext, List.of(source), Block.MvOrdering.UNORDERED); + loadSimpleAndAssert(driverContext, List.of(source), Block.MvOrdering.UNORDERED, Block.MvOrdering.UNORDERED); } private static ValuesSourceReaderOperator.FieldInfo fieldInfo(MappedFieldType ft, ElementType elementType) { @@ -521,8 +524,13 @@ public FieldNamesFieldMapper.FieldNamesFieldType fieldNames() { }; } - private void loadSimpleAndAssert(DriverContext driverContext, List input, Block.MvOrdering docValuesMvOrdering) { - List cases = infoAndChecksForEachType(docValuesMvOrdering); + private void loadSimpleAndAssert( + DriverContext driverContext, + List input, + Block.MvOrdering booleanAndNumericalDocValuesMvOrdering, + Block.MvOrdering bytesRefDocValuesMvOrdering + ) { + List cases = infoAndChecksForEachType(booleanAndNumericalDocValuesMvOrdering, bytesRefDocValuesMvOrdering); List operators = new ArrayList<>(); operators.add( @@ -621,7 +629,10 @@ private void testLoadAllStatus(boolean allInOnePage) { List input = CannedSourceOperator.collectPages(simpleInput(driverContext, numDocs, commitEvery(numDocs), numDocs)); assertThat(reader.leaves(), hasSize(10)); assertThat(input, hasSize(10)); - List cases = infoAndChecksForEachType(Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING); + List cases = infoAndChecksForEachType( + Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING, + Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING + ); // Build one operator for each field, so we get a unique map to assert on List operators = cases.stream() .map( @@ -644,8 +655,11 @@ private void testLoadAllStatus(boolean allInOnePage) { } } - private List infoAndChecksForEachType(Block.MvOrdering docValuesMvOrdering) { - Checks checks = new Checks(docValuesMvOrdering); + private List infoAndChecksForEachType( + Block.MvOrdering booleanAndNumericalDocValuesMvOrdering, + Block.MvOrdering bytesRefDocValuesMvOrdering + ) { + Checks checks = new Checks(booleanAndNumericalDocValuesMvOrdering, bytesRefDocValuesMvOrdering); List r = new ArrayList<>(); r.add(new FieldCase(mapperService.fieldType(IdFieldMapper.NAME), ElementType.BYTES_REF, checks::ids, StatusChecks::id)); r.add(new FieldCase(TsidExtractingIdFieldMapper.INSTANCE.fieldType(), ElementType.BYTES_REF, checks::ids, StatusChecks::id)); @@ -801,7 +815,7 @@ private List infoAndChecksForEachType(Block.MvOrdering docValuesMvOrd return r; } - record Checks(Block.MvOrdering docValuesMvOrdering) { + record Checks(Block.MvOrdering booleanAndNumericalDocValuesMvOrdering, Block.MvOrdering bytesRefDocValuesMvOrdering) { void longs(Block block, int position, int key) { LongVector longs = ((LongBlock) block).asVector(); assertThat(longs.getLong(position), equalTo((long) key)); @@ -858,7 +872,7 @@ void constantNulls(Block block, int position, int key) { } void mvLongsFromDocValues(Block block, int position, int key) { - mvLongs(block, position, key, docValuesMvOrdering); + mvLongs(block, position, key, booleanAndNumericalDocValuesMvOrdering); } void mvLongsUnordered(Block block, int position, int key) { @@ -878,7 +892,7 @@ private void mvLongs(Block block, int position, int key, Block.MvOrdering expect } void mvIntsFromDocValues(Block block, int position, int key) { - mvInts(block, position, key, docValuesMvOrdering); + mvInts(block, position, key, booleanAndNumericalDocValuesMvOrdering); } void mvIntsUnordered(Block block, int position, int key) { @@ -905,7 +919,7 @@ void mvShorts(Block block, int position, int key) { assertThat(ints.getInt(offset + v), equalTo((int) (short) (2_000 * key + v))); } if (key % 3 > 0) { - assertThat(ints.mvOrdering(), equalTo(docValuesMvOrdering)); + assertThat(ints.mvOrdering(), equalTo(booleanAndNumericalDocValuesMvOrdering)); } } @@ -917,7 +931,7 @@ void mvBytes(Block block, int position, int key) { assertThat(ints.getInt(offset + v), equalTo((int) (byte) (3_000 * key + v))); } if (key % 3 > 0) { - assertThat(ints.mvOrdering(), equalTo(docValuesMvOrdering)); + assertThat(ints.mvOrdering(), equalTo(booleanAndNumericalDocValuesMvOrdering)); } } @@ -928,12 +942,12 @@ void mvDoubles(Block block, int position, int key) { assertThat(doubles.getDouble(offset + v), equalTo(key / 123_456d + v)); } if (key % 3 > 0) { - assertThat(doubles.mvOrdering(), equalTo(docValuesMvOrdering)); + assertThat(doubles.mvOrdering(), equalTo(booleanAndNumericalDocValuesMvOrdering)); } } void mvStringsFromDocValues(Block block, int position, int key) { - mvStrings(block, position, key, docValuesMvOrdering); + mvStrings(block, position, key, bytesRefDocValuesMvOrdering); } void mvStringsUnordered(Block block, int position, int key) { @@ -960,7 +974,7 @@ void mvBools(Block block, int position, int key) { assertThat(bools.getBoolean(offset + v), equalTo(BOOLEANS[key % 3][v])); } if (key % 3 > 0) { - assertThat(bools.mvOrdering(), equalTo(docValuesMvOrdering)); + assertThat(bools.mvOrdering(), equalTo(booleanAndNumericalDocValuesMvOrdering)); } } } @@ -1440,7 +1454,7 @@ private void testSequentialStoredFields(boolean sequential, int docCount) throws 0 ).get(driverContext); List results = drive(op, source.iterator(), driverContext); - Checks checks = new Checks(Block.MvOrdering.UNORDERED); + Checks checks = new Checks(Block.MvOrdering.UNORDERED, Block.MvOrdering.UNORDERED); IntVector keys = results.get(0).getBlock(1).asVector(); for (int p = 0; p < results.get(0).getPositionCount(); p++) { int key = keys.getInt(p); @@ -1459,7 +1473,8 @@ private void testSequentialStoredFields(boolean sequential, int docCount) throws public void testDescriptionOfMany() throws IOException { initIndex(1, 1); - List cases = infoAndChecksForEachType(randomFrom(Block.MvOrdering.values())); + Block.MvOrdering ordering = randomFrom(Block.MvOrdering.values()); + List cases = infoAndChecksForEachType(ordering, ordering); ValuesSourceReaderOperator.Factory factory = new ValuesSourceReaderOperator.Factory( cases.stream().map(c -> c.info).toList(), diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java index 112a5777073ee..dcbcaea3ce50b 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java @@ -19,6 +19,7 @@ import org.hamcrest.StringDescription; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; @@ -268,7 +269,8 @@ private static void dataFailure(List dataFailures) { if (f.actual instanceof List a) { actualList = a; } else { - actualList = List.of(f.actual); + // Do not use List::of - actual can be null. + actualList = Collections.singletonList(f.actual); } expected.describeMismatch(actualList, description); String prefix = "row " + f.row + " column " + f.column + ":"; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlFeatures.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlFeatures.java index ff157c0fe3e0b..89c7455baf885 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlFeatures.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlFeatures.java @@ -115,6 +115,12 @@ public class EsqlFeatures implements FeatureSpecification { */ public static final NodeFeature CASTING_OPERATOR = new NodeFeature("esql.casting_operator"); + /** + * Blocks can be labelled with {@link org.elasticsearch.compute.data.Block.MvOrdering#SORTED_ASCENDING} for optimizations. + * C.f. {@link org.elasticsearch.TransportVersions#ESQL_MV_ORDERING_SORTED_ASCENDING}. + */ + public static final NodeFeature MV_ORDERING_SORTED_ASCENDING = new NodeFeature("esql.mv_ordering_sorted_ascending"); + @Override public Set getFeatures() { return Set.of( @@ -132,7 +138,8 @@ public Set getFeatures() { ST_CONTAINS_WITHIN, ST_DISJOINT, STRING_LITERAL_AUTO_CASTING, - CASTING_OPERATOR + CASTING_OPERATOR, + MV_ORDERING_SORTED_ASCENDING ); } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/AbstractMultivalueFunctionTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/AbstractMultivalueFunctionTestCase.java index fbe146c66f27d..e648817723166 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/AbstractMultivalueFunctionTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/AbstractMultivalueFunctionTestCase.java @@ -617,6 +617,9 @@ private static > void putInOrder(List mvData, Block.M mvData.addAll(dedup); Collections.sort(mvData); } + case SORTED_ASCENDING -> { + Collections.sort(mvData); + } default -> throw new UnsupportedOperationException("unsupported ordering [" + ordering + "]"); } } diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/100_bug_fix.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/100_bug_fix.yml index bc1bf5987a6d8..b703335940056 100644 --- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/100_bug_fix.yml +++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/100_bug_fix.yml @@ -262,3 +262,54 @@ - match: { values.0.1: true } - match: { values.1.0: 3 } - match: { values.1.1: false } + + +--- +"mv_dedupe from index #104745": + - requires: + cluster_features: ["esql.mv_ordering_sorted_ascending"] + reason: "fixed by introducing a sorted, non-deduplicated MvOrdering" + - do: + indices.create: + index: idx_with_multivalues + body: + mappings: + properties: + boolean: + type: boolean + double: + type: double + integer : + type : integer + keyword : + type : keyword + long: + type: long + + - do: + bulk: + refresh: true + body: + - { "index": { "_index": "idx_with_multivalues" } } + - { "boolean": [true,false,false,true], "keyword": [foo,bar,bar,foo], "integer": [1,2,2,1], "long": [1,2,2,1], "double": [1.1,2.2,2.2,1.1] } + - do: + esql.query: + body: + query: 'from idx_with_multivalues | eval b = mv_dedupe(boolean), k = mv_dedupe(keyword), i = mv_dedupe(integer), l = mv_dedupe(long), d = mv_dedupe(double) | keep b, k, i, l, d | limit 1' + version: 2024.04.01 + - match: { columns.0.name: b } + - match: { columns.0.type: boolean } + - match: { columns.1.name: k } + - match: { columns.1.type: keyword } + - match: { columns.2.name: i } + - match: { columns.2.type: integer } + - match: { columns.3.name: l } + - match: { columns.3.type: long } + - match: { columns.4.name: d } + - match: { columns.4.type: double } + - length: { values: 1 } + - match: { values.0.0: [false, true] } + - match: { values.0.1: ["bar", "foo"] } + - match: { values.0.2: [1, 2] } + - match: { values.0.3: [1, 2] } + - match: { values.0.4: [1.1, 2.2] } From d34f0b1d226b737bcaa6b16b97a6d1cbbd184995 Mon Sep 17 00:00:00 2001 From: Nhat Nguyen Date: Wed, 24 Apr 2024 07:11:34 -0700 Subject: [PATCH 3/3] Duplicate logical aggregate and relation for ESQL (#107789) We'll need to make changes for Aggregate, EsRelation, and UnresolvedRelation logical plans for TSDB. I think it's better to replicate these classes for ESQL only instead of modifying the existing classes in QL. I also add these classes to the forbid APIs in ESQL to avoid future mistakes. --- x-pack/plugin/esql/build.gradle | 5 + .../xpack/esql/analysis/Analyzer.java | 4 +- .../xpack/esql/analysis/Verifier.java | 2 +- .../xpack/esql/io/stream/PlanNamedTypes.java | 4 +- .../optimizer/LocalLogicalPlanOptimizer.java | 4 +- .../esql/optimizer/LogicalPlanOptimizer.java | 4 +- .../xpack/esql/optimizer/OptimizerRules.java | 4 +- .../esql/optimizer/PhysicalPlanOptimizer.java | 2 +- .../xpack/esql/plan/logical/Aggregate.java | 81 +++++++++++ .../xpack/esql/plan/logical/EsRelation.java | 126 ++++++++++++++++++ .../esql/plan/logical/EsqlAggregate.java | 1 - .../plan/logical/EsqlUnresolvedRelation.java | 1 - .../esql/plan/logical/UnresolvedRelation.java | 109 +++++++++++++++ .../esql/plan/physical/EsSourceExec.java | 2 +- .../xpack/esql/planner/Mapper.java | 4 +- .../xpack/esql/planner/PlannerUtils.java | 4 +- .../xpack/esql/session/EsqlSession.java | 2 +- .../xpack/esql/stats/FeatureMetric.java | 4 +- .../resources/forbidden/ql-signatures.txt | 4 + .../elasticsearch/xpack/esql/CsvTests.java | 2 +- .../xpack/esql/analysis/AnalyzerTests.java | 4 +- .../esql/io/stream/PlanNamedTypesTests.java | 4 +- .../LocalLogicalPlanOptimizerTests.java | 7 +- .../optimizer/LogicalPlanOptimizerTests.java | 8 +- .../optimizer/PhysicalPlanOptimizerTests.java | 4 +- 25 files changed, 363 insertions(+), 33 deletions(-) create mode 100644 x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Aggregate.java create mode 100644 x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsRelation.java create mode 100644 x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/UnresolvedRelation.java create mode 100644 x-pack/plugin/esql/src/main/resources/forbidden/ql-signatures.txt diff --git a/x-pack/plugin/esql/build.gradle b/x-pack/plugin/esql/build.gradle index 7705e34cadaa0..c6220a8ce73e5 100644 --- a/x-pack/plugin/esql/build.gradle +++ b/x-pack/plugin/esql/build.gradle @@ -1,4 +1,5 @@ import org.elasticsearch.gradle.internal.info.BuildParams +import org.elasticsearch.gradle.internal.precommit.CheckForbiddenApisTask; apply plugin: 'elasticsearch.internal-es-plugin' apply plugin: 'elasticsearch.internal-cluster-test' @@ -292,3 +293,7 @@ tasks.named('stringTemplates').configure { it.outputFile = "org/elasticsearch/xpack/esql/enrich/EnrichResultBuilderForBoolean.java" } } + +tasks.withType(CheckForbiddenApisTask).configureEach { + signaturesFiles += files('src/main/resources/forbidden/ql-signatures.txt') +} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java index 02969ed56798f..86637e543b43c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java @@ -18,8 +18,10 @@ import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Drop; import org.elasticsearch.xpack.esql.plan.logical.Enrich; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.EsqlAggregate; import org.elasticsearch.xpack.esql.plan.logical.EsqlUnresolvedRelation; import org.elasticsearch.xpack.esql.plan.logical.Eval; @@ -56,8 +58,6 @@ import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison; import org.elasticsearch.xpack.ql.index.EsIndex; import org.elasticsearch.xpack.ql.plan.TableIdentifier; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; import org.elasticsearch.xpack.ql.plan.logical.Project; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Verifier.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Verifier.java index f55653c6800c9..2267125304da7 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Verifier.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Verifier.java @@ -12,6 +12,7 @@ import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute; import org.elasticsearch.xpack.esql.expression.function.grouping.GroupingFunction; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Neg; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Enrich; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.RegexExtract; @@ -32,7 +33,6 @@ import org.elasticsearch.xpack.ql.expression.function.aggregate.AggregateFunction; import org.elasticsearch.xpack.ql.expression.predicate.BinaryOperator; import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; import org.elasticsearch.xpack.ql.plan.logical.OrderBy; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypes.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypes.java index c5d8865f32ceb..01fbf9febe26a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypes.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypes.java @@ -137,9 +137,11 @@ import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Sub; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.In; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.NullEquals; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Dissect; import org.elasticsearch.xpack.esql.plan.logical.Dissect.Parser; import org.elasticsearch.xpack.esql.plan.logical.Enrich; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.Grok; import org.elasticsearch.xpack.esql.plan.logical.MvExpand; @@ -192,8 +194,6 @@ import org.elasticsearch.xpack.ql.expression.predicate.regex.WildcardPattern; import org.elasticsearch.xpack.ql.index.EsIndex; import org.elasticsearch.xpack.ql.options.EsSourceOptions; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Filter; import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizer.java index f8cb1d20ba9c5..a06cedf3bca7c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizer.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizer.java @@ -15,6 +15,8 @@ import org.elasticsearch.xpack.esql.expression.function.aggregate.Count; import org.elasticsearch.xpack.esql.expression.function.scalar.nulls.Coalesce; import org.elasticsearch.xpack.esql.optimizer.LogicalPlanOptimizer.PropagateEmptyRelation; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.TopN; import org.elasticsearch.xpack.esql.planner.AbstractPhysicalOperationProviders; @@ -31,8 +33,6 @@ import org.elasticsearch.xpack.ql.expression.predicate.Predicates; import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNotNull; import org.elasticsearch.xpack.ql.optimizer.OptimizerRules; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Filter; import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java index 4b2eaa91fa316..c62a6dcfb4cff 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java @@ -23,7 +23,9 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.nulls.Coalesce; import org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialRelatesFunction; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.In; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Enrich; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.MvExpand; import org.elasticsearch.xpack.esql.plan.logical.RegexExtract; @@ -56,8 +58,6 @@ import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.PruneLiteralsInOrderBy; import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.SetAsOptimized; import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.SimplifyComparisonsArithmetics; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Filter; import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/OptimizerRules.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/OptimizerRules.java index 38ac596135abb..19d9c5de8df46 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/OptimizerRules.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/OptimizerRules.java @@ -15,7 +15,9 @@ import org.elasticsearch.xpack.esql.evaluator.predicate.operator.comparison.NotEquals; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.In; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.NullEquals; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Enrich; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.MvExpand; import org.elasticsearch.xpack.esql.plan.logical.RegexExtract; @@ -50,8 +52,6 @@ import org.elasticsearch.xpack.ql.expression.predicate.logical.Or; import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison; import org.elasticsearch.xpack.ql.plan.QueryPlan; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; import org.elasticsearch.xpack.ql.type.DataTypes; import org.elasticsearch.xpack.ql.util.CollectionUtils; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizer.java index ee095a24e20fd..545b1f25db277 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizer.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizer.java @@ -8,6 +8,7 @@ package org.elasticsearch.xpack.esql.optimizer; import org.elasticsearch.xpack.esql.VerificationException; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.physical.AggregateExec; import org.elasticsearch.xpack.esql.plan.physical.EnrichExec; @@ -26,7 +27,6 @@ import org.elasticsearch.xpack.ql.expression.Expressions; import org.elasticsearch.xpack.ql.expression.Literal; import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; import org.elasticsearch.xpack.ql.plan.logical.Project; import org.elasticsearch.xpack.ql.rule.ParameterizedRuleExecutor; import org.elasticsearch.xpack.ql.rule.Rule; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Aggregate.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Aggregate.java new file mode 100644 index 0000000000000..926475fa57b7d --- /dev/null +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Aggregate.java @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.plan.logical; + +import org.elasticsearch.xpack.ql.capabilities.Resolvables; +import org.elasticsearch.xpack.ql.expression.Attribute; +import org.elasticsearch.xpack.ql.expression.Expression; +import org.elasticsearch.xpack.ql.expression.Expressions; +import org.elasticsearch.xpack.ql.expression.NamedExpression; +import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.ql.tree.NodeInfo; +import org.elasticsearch.xpack.ql.tree.Source; + +import java.util.List; +import java.util.Objects; + +public class Aggregate extends UnaryPlan { + + private final List groupings; + private final List aggregates; + + public Aggregate(Source source, LogicalPlan child, List groupings, List aggregates) { + super(source, child); + this.groupings = groupings; + this.aggregates = aggregates; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Aggregate::new, child(), groupings, aggregates); + } + + @Override + public Aggregate replaceChild(LogicalPlan newChild) { + return new Aggregate(source(), newChild, groupings, aggregates); + } + + public List groupings() { + return groupings; + } + + public List aggregates() { + return aggregates; + } + + @Override + public boolean expressionsResolved() { + return Resolvables.resolved(groupings) && Resolvables.resolved(aggregates); + } + + @Override + public List output() { + return Expressions.asAttributes(aggregates); + } + + @Override + public int hashCode() { + return Objects.hash(groupings, aggregates, child()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + Aggregate other = (Aggregate) obj; + return Objects.equals(groupings, other.groupings) + && Objects.equals(aggregates, other.aggregates) + && Objects.equals(child(), other.child()); + } +} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsRelation.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsRelation.java new file mode 100644 index 0000000000000..19c3d9cf52109 --- /dev/null +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsRelation.java @@ -0,0 +1,126 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.plan.logical; + +import org.elasticsearch.xpack.ql.expression.Attribute; +import org.elasticsearch.xpack.ql.expression.FieldAttribute; +import org.elasticsearch.xpack.ql.index.EsIndex; +import org.elasticsearch.xpack.ql.options.EsSourceOptions; +import org.elasticsearch.xpack.ql.plan.logical.LeafPlan; +import org.elasticsearch.xpack.ql.tree.NodeInfo; +import org.elasticsearch.xpack.ql.tree.NodeUtils; +import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.ql.type.EsField; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; + +public class EsRelation extends LeafPlan { + + private final EsIndex index; + private final List attrs; + private final EsSourceOptions esSourceOptions; + private final boolean frozen; + + public EsRelation(Source source, EsIndex index, boolean frozen) { + this(source, index, flatten(source, index.mapping()), EsSourceOptions.NO_OPTIONS, frozen); + } + + public EsRelation(Source source, EsIndex index, List attributes) { + this(source, index, attributes, EsSourceOptions.NO_OPTIONS, false); + } + + public EsRelation(Source source, EsIndex index, List attributes, EsSourceOptions esSourceOptions) { + this(source, index, attributes, esSourceOptions, false); + } + + public EsRelation(Source source, EsIndex index, List attributes, EsSourceOptions esSourceOptions, boolean frozen) { + super(source); + this.index = index; + this.attrs = attributes; + Objects.requireNonNull(esSourceOptions); + this.esSourceOptions = esSourceOptions; + this.frozen = frozen; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, EsRelation::new, index, attrs, esSourceOptions, frozen); + } + + private static List flatten(Source source, Map mapping) { + return flatten(source, mapping, null); + } + + private static List flatten(Source source, Map mapping, FieldAttribute parent) { + List list = new ArrayList<>(); + + for (Entry entry : mapping.entrySet()) { + String name = entry.getKey(); + EsField t = entry.getValue(); + + if (t != null) { + FieldAttribute f = new FieldAttribute(source, parent, parent != null ? parent.name() + "." + name : name, t); + list.add(f); + // object or nested + if (t.getProperties().isEmpty() == false) { + list.addAll(flatten(source, t.getProperties(), f)); + } + } + } + return list; + } + + public EsIndex index() { + return index; + } + + public EsSourceOptions esSourceOptions() { + return esSourceOptions; + } + + public boolean frozen() { + return frozen; + } + + @Override + public List output() { + return attrs; + } + + @Override + public boolean expressionsResolved() { + return true; + } + + @Override + public int hashCode() { + return Objects.hash(index, esSourceOptions, frozen); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + EsRelation other = (EsRelation) obj; + return Objects.equals(index, other.index) && Objects.equals(esSourceOptions, other.esSourceOptions) && frozen == other.frozen; + } + + @Override + public String nodeString() { + return nodeName() + "[" + index + "]" + NodeUtils.limitedToString(attrs); + } +} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlAggregate.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlAggregate.java index 847ed3c9972a8..610b9bab17141 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlAggregate.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlAggregate.java @@ -11,7 +11,6 @@ import org.elasticsearch.xpack.ql.expression.Expression; import org.elasticsearch.xpack.ql.expression.Expressions; import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; import org.elasticsearch.xpack.ql.tree.NodeInfo; import org.elasticsearch.xpack.ql.tree.Source; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlUnresolvedRelation.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlUnresolvedRelation.java index 01c29cbce123a..6eb5926f8b5c9 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlUnresolvedRelation.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlUnresolvedRelation.java @@ -10,7 +10,6 @@ import org.elasticsearch.xpack.ql.expression.Attribute; import org.elasticsearch.xpack.ql.options.EsSourceOptions; import org.elasticsearch.xpack.ql.plan.TableIdentifier; -import org.elasticsearch.xpack.ql.plan.logical.UnresolvedRelation; import org.elasticsearch.xpack.ql.tree.NodeInfo; import org.elasticsearch.xpack.ql.tree.Source; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/UnresolvedRelation.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/UnresolvedRelation.java new file mode 100644 index 0000000000000..c5db2d37c2638 --- /dev/null +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/UnresolvedRelation.java @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.plan.logical; + +import org.elasticsearch.xpack.ql.capabilities.Unresolvable; +import org.elasticsearch.xpack.ql.expression.Attribute; +import org.elasticsearch.xpack.ql.plan.TableIdentifier; +import org.elasticsearch.xpack.ql.plan.logical.LeafPlan; +import org.elasticsearch.xpack.ql.tree.NodeInfo; +import org.elasticsearch.xpack.ql.tree.Source; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import static java.util.Collections.singletonList; + +public class UnresolvedRelation extends LeafPlan implements Unresolvable { + + private final TableIdentifier table; + private final boolean frozen; + private final String alias; + private final String unresolvedMsg; + + public UnresolvedRelation(Source source, TableIdentifier table, String alias, boolean frozen) { + this(source, table, alias, frozen, null); + } + + public UnresolvedRelation(Source source, TableIdentifier table, String alias, boolean frozen, String unresolvedMessage) { + super(source); + this.table = table; + this.alias = alias; + this.frozen = frozen; + this.unresolvedMsg = unresolvedMessage == null ? "Unknown index [" + table.index() + "]" : unresolvedMessage; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, UnresolvedRelation::new, table, alias, frozen, unresolvedMsg); + } + + public TableIdentifier table() { + return table; + } + + public String alias() { + return alias; + } + + public boolean frozen() { + return frozen; + } + + @Override + public boolean resolved() { + return false; + } + + @Override + public boolean expressionsResolved() { + return false; + } + + @Override + public List output() { + return Collections.emptyList(); + } + + @Override + public String unresolvedMessage() { + return unresolvedMsg; + } + + @Override + public int hashCode() { + return Objects.hash(source(), table, alias, unresolvedMsg); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + UnresolvedRelation other = (UnresolvedRelation) obj; + return Objects.equals(table, other.table) + && Objects.equals(alias, other.alias) + && Objects.equals(frozen, other.frozen) + && Objects.equals(unresolvedMsg, other.unresolvedMsg); + } + + @Override + public List nodeProperties() { + return singletonList(table); + } + + @Override + public String toString() { + return UNRESOLVED_PREFIX + table.index(); + } +} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsSourceExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsSourceExec.java index e7772ed14df34..d44c0a24bfde3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsSourceExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsSourceExec.java @@ -8,9 +8,9 @@ package org.elasticsearch.xpack.esql.plan.physical; import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.expression.Attribute; import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.tree.NodeInfo; import org.elasticsearch.xpack.ql.tree.NodeUtils; import org.elasticsearch.xpack.ql.tree.Source; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/Mapper.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/Mapper.java index 2205947dccdeb..b63f8fbc148fd 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/Mapper.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/Mapper.java @@ -9,8 +9,10 @@ import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Dissect; import org.elasticsearch.xpack.esql.plan.logical.Enrich; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.Grok; import org.elasticsearch.xpack.esql.plan.logical.MvExpand; @@ -38,8 +40,6 @@ import org.elasticsearch.xpack.esql.plan.physical.ShowExec; import org.elasticsearch.xpack.esql.plan.physical.TopNExec; import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Filter; import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java index 206f428bdcb71..98bf932ce3af8 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java @@ -21,6 +21,8 @@ import org.elasticsearch.xpack.esql.optimizer.LocalLogicalPlanOptimizer; import org.elasticsearch.xpack.esql.optimizer.LocalPhysicalOptimizerContext; import org.elasticsearch.xpack.esql.optimizer.LocalPhysicalPlanOptimizer; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.TopN; import org.elasticsearch.xpack.esql.plan.physical.EsQueryExec; import org.elasticsearch.xpack.esql.plan.physical.EsSourceExec; @@ -41,8 +43,6 @@ import org.elasticsearch.xpack.ql.expression.FieldAttribute; import org.elasticsearch.xpack.ql.expression.predicate.Predicates; import org.elasticsearch.xpack.ql.options.EsSourceOptions; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Filter; import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java index cc0010c788a0c..055cc311fb9da 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java @@ -30,6 +30,7 @@ import org.elasticsearch.xpack.esql.optimizer.PhysicalPlanOptimizer; import org.elasticsearch.xpack.esql.parser.EsqlParser; import org.elasticsearch.xpack.esql.parser.TypedParamValue; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Enrich; import org.elasticsearch.xpack.esql.plan.logical.Keep; import org.elasticsearch.xpack.esql.plan.logical.RegexExtract; @@ -50,7 +51,6 @@ import org.elasticsearch.xpack.ql.index.IndexResolver; import org.elasticsearch.xpack.ql.index.MappingException; import org.elasticsearch.xpack.ql.plan.TableIdentifier; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; import org.elasticsearch.xpack.ql.plan.logical.Project; import org.elasticsearch.xpack.ql.type.DataTypes; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/stats/FeatureMetric.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/stats/FeatureMetric.java index dd1d9cffeeff1..025c7aba6719c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/stats/FeatureMetric.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/stats/FeatureMetric.java @@ -7,9 +7,11 @@ package org.elasticsearch.xpack.esql.stats; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Dissect; import org.elasticsearch.xpack.esql.plan.logical.Drop; import org.elasticsearch.xpack.esql.plan.logical.Enrich; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.Grok; import org.elasticsearch.xpack.esql.plan.logical.Keep; @@ -18,8 +20,6 @@ import org.elasticsearch.xpack.esql.plan.logical.Row; import org.elasticsearch.xpack.esql.plan.logical.meta.MetaFunctions; import org.elasticsearch.xpack.esql.plan.logical.show.ShowInfo; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Filter; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; import org.elasticsearch.xpack.ql.plan.logical.OrderBy; diff --git a/x-pack/plugin/esql/src/main/resources/forbidden/ql-signatures.txt b/x-pack/plugin/esql/src/main/resources/forbidden/ql-signatures.txt new file mode 100644 index 0000000000000..4096857db69d1 --- /dev/null +++ b/x-pack/plugin/esql/src/main/resources/forbidden/ql-signatures.txt @@ -0,0 +1,4 @@ +org.elasticsearch.xpack.ql.plan.logical.Aggregate @ use @org.elasticsearch.xpack.esql.plan.logical.Aggregate instead +org.elasticsearch.xpack.ql.plan.logical.EsRelation @ use @org.elasticsearch.xpack.esql.plan.logical.EsRelation instead +org.elasticsearch.xpack.ql.plan.logical.UnresolvedRelation @ use @org.elasticsearch.xpack.esql.plan.logical.UnresolvedRelation instead +org.elasticsearch.xpack.ql.analyzer.PreAnalyzer @ use org.elasticsearch.xpack.esql.analysis.PreAnalyzer diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java index 573dbd20b39c5..bfe4cbc6184ea 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java @@ -49,6 +49,7 @@ import org.elasticsearch.xpack.esql.analysis.Analyzer; import org.elasticsearch.xpack.esql.analysis.AnalyzerContext; import org.elasticsearch.xpack.esql.analysis.EnrichResolution; +import org.elasticsearch.xpack.esql.analysis.PreAnalyzer; import org.elasticsearch.xpack.esql.enrich.EnrichLookupService; import org.elasticsearch.xpack.esql.enrich.ResolvedEnrichPolicy; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; @@ -78,7 +79,6 @@ import org.elasticsearch.xpack.esql.type.EsqlDataTypes; import org.elasticsearch.xpack.ql.CsvSpecReader; import org.elasticsearch.xpack.ql.SpecReader; -import org.elasticsearch.xpack.ql.analyzer.PreAnalyzer; import org.elasticsearch.xpack.ql.expression.Expressions; import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; import org.elasticsearch.xpack.ql.index.EsIndex; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java index 7a85ca1628048..8f474e6cb6a83 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java @@ -25,7 +25,9 @@ import org.elasticsearch.xpack.esql.expression.function.aggregate.Max; import org.elasticsearch.xpack.esql.expression.function.aggregate.Min; import org.elasticsearch.xpack.esql.parser.ParsingException; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Enrich; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.EsqlUnresolvedRelation; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.Row; @@ -44,8 +46,6 @@ import org.elasticsearch.xpack.ql.index.EsIndex; import org.elasticsearch.xpack.ql.index.IndexResolution; import org.elasticsearch.xpack.ql.plan.TableIdentifier; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Filter; import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypesTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypesTests.java index 7af93adc301d2..57d86147a5bba 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypesTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypesTests.java @@ -46,8 +46,10 @@ import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Mul; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Sub; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.NullEquals; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Dissect; import org.elasticsearch.xpack.esql.plan.logical.Enrich; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.Grok; import org.elasticsearch.xpack.esql.plan.logical.MvExpand; @@ -87,8 +89,6 @@ import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison; import org.elasticsearch.xpack.ql.index.EsIndex; import org.elasticsearch.xpack.ql.options.EsSourceOptions; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Filter; import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java index a30418c69f0f3..e6d79d7169ca5 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java @@ -16,6 +16,7 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.nulls.Coalesce; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Add; import org.elasticsearch.xpack.esql.parser.EsqlParser; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation; import org.elasticsearch.xpack.esql.plan.logical.local.LocalSupplier; @@ -30,7 +31,6 @@ import org.elasticsearch.xpack.ql.index.EsIndex; import org.elasticsearch.xpack.ql.index.IndexResolution; import org.elasticsearch.xpack.ql.optimizer.OptimizerRulesTests; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Filter; import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; @@ -56,7 +56,6 @@ import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning; import static org.elasticsearch.xpack.esql.optimizer.LogicalPlanOptimizerTests.greaterThanOf; import static org.elasticsearch.xpack.ql.TestUtils.getFieldAttribute; -import static org.elasticsearch.xpack.ql.TestUtils.relation; import static org.elasticsearch.xpack.ql.tree.Source.EMPTY; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.hasSize; @@ -455,4 +454,8 @@ private LogicalPlan localPlan(String query) { protected List filteredWarnings() { return withDefaultLimitWarning(super.filteredWarnings()); } + + public static EsRelation relation() { + return new EsRelation(EMPTY, new EsIndex(randomAlphaOfLength(8), emptyMap()), randomBoolean()); + } } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java index 3c837f7e07150..a5aa897b8903f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java @@ -71,8 +71,10 @@ import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Sub; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.In; import org.elasticsearch.xpack.esql.parser.EsqlParser; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Dissect; import org.elasticsearch.xpack.esql.plan.logical.Enrich; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.Grok; import org.elasticsearch.xpack.esql.plan.logical.MvExpand; @@ -101,8 +103,6 @@ import org.elasticsearch.xpack.ql.expression.predicate.regex.WildcardPattern; import org.elasticsearch.xpack.ql.index.EsIndex; import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Filter; import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; @@ -4685,4 +4685,8 @@ public void testIsNullDisjunction() throws Exception { private Literal nullOf(DataType dataType) { return new Literal(Source.EMPTY, null, dataType); } + + public static EsRelation relation() { + return new EsRelation(EMPTY, new EsIndex(randomAlphaOfLength(8), emptyMap()), randomBoolean()); + } } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java index f71161d64e130..a413a2e2d4f8e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java @@ -48,7 +48,9 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialRelatesFunction; import org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialWithin; import org.elasticsearch.xpack.esql.parser.EsqlParser; +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Enrich; +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.TopN; import org.elasticsearch.xpack.esql.plan.logical.local.LocalSupplier; @@ -95,8 +97,6 @@ import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison; import org.elasticsearch.xpack.ql.index.EsIndex; import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Filter; import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.type.DataType;