Skip to content

Commit 5d234c3

Browse files
author
elasticsearchmachine
committed
Merge remote-tracking branch 'origin/main' into lucene_snapshot
2 parents 67e7ca1 + 1d6c6a5 commit 5d234c3

File tree

12 files changed

+1074
-22
lines changed

12 files changed

+1074
-22
lines changed

docs/reference/query-languages/esql/esql-lookup-join.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ The `LOOKUP JOIN` command adds new columns to a table, with data from {{es}} ind
4242

4343
## Example
4444

45-
`LOOKUP JOIN` has left-join behavior. If no rows match in the looked index, `LOOKUP JOIN` retains the incoming row and adds `null`s. If many rows in the lookedup index match, `LOOKUP JOIN` adds one row per match.
45+
`LOOKUP JOIN` has left-join behavior. If no rows match in the lookup index, `LOOKUP JOIN` retains the incoming row and adds `null`s. If many rows in the lookup index match, `LOOKUP JOIN` adds one row per match.
4646

4747
In this example, we have two sample tables:
4848

@@ -112,7 +112,9 @@ To use `LOOKUP JOIN`, the following requirements must be met:
112112
* Numeric types follow these compatibility rules:
113113
* `short` and `byte` are compatible with `integer` (all represented as `int`)
114114
* `float`, `half_float`, and `scaled_float` are compatible with `double` (all represented as `double`)
115-
* For text fields: You can use text fields on the left-hand side of the join only if they have a `.keyword` subfield
115+
* For text fields: You can only use text fields as the join key on the left-hand side of the join and only if they have a `.keyword` subfield
116+
117+
To obtain a join key with a compatible type, use a [conversion function](/reference/query-languages/esql/esql-functions-operators.md#esql-type-conversion-functions) if needed.
116118

117119
For a complete list of supported data types and their internal representations, see the [Supported Field Types documentation](/reference/query-languages/esql/limitations.md#_supported_types).
118120

@@ -121,7 +123,7 @@ For a complete list of supported data types and their internal representations,
121123
The following are the current limitations with `LOOKUP JOIN`
122124

123125
* Indices in [lookup](/reference/elasticsearch/index-settings/index-modules.md#index-mode-setting) mode are always single-sharded.
124-
* Cross cluster search is unsupported. Both source and lookup indices must be local.
126+
* Cross cluster search is unsupported initially. Both source and lookup indices must be local.
125127
* Currently, only matching on equality is supported.
126128
* `LOOKUP JOIN` can only use a single match field and a single index. Wildcards, aliases, datemath, and datastreams are not supported.
127129
* The name of the match field in `LOOKUP JOIN lu_idx ON match_field` must match an existing field in the query. This may require `RENAME`s or `EVAL`s to achieve.

muted-tests.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,6 @@ tests:
380380
- class: org.elasticsearch.xpack.esql.spatial.SpatialExtentAggregationNoLicenseIT
381381
method: testStExtentAggregationWithPoints
382382
issue: https://github.com/elastic/elasticsearch/issues/125735
383-
- class: org.elasticsearch.repositories.blobstore.testkit.analyze.GCSRepositoryAnalysisRestIT
384-
method: testRepositoryAnalysis
385-
issue: https://github.com/elastic/elasticsearch/issues/125668
386383
- class: org.elasticsearch.xpack.test.rest.XPackRestIT
387384
method: test {p0=transform/transforms_start_stop/Test schedule_now on an already started transform}
388385
issue: https://github.com/elastic/elasticsearch/issues/120720

plugins/discovery-ec2/src/javaRestTest/java/org/elasticsearch/discovery/ec2/DiscoveryEc2InstanceProfileIT.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,13 @@
1010
package org.elasticsearch.discovery.ec2;
1111

1212
import fixture.aws.DynamicAwsCredentials;
13+
import fixture.aws.DynamicRegionSupplier;
1314
import fixture.aws.ec2.AwsEc2HttpFixture;
1415
import fixture.aws.imds.Ec2ImdsHttpFixture;
1516
import fixture.aws.imds.Ec2ImdsServiceBuilder;
1617
import fixture.aws.imds.Ec2ImdsVersion;
1718

18-
import org.elasticsearch.common.util.LazyInitializable;
1919
import org.elasticsearch.discovery.DiscoveryModule;
20-
import org.elasticsearch.test.ESTestCase;
2120
import org.elasticsearch.test.cluster.ElasticsearchCluster;
2221
import org.junit.ClassRule;
2322
import org.junit.rules.RuleChain;
@@ -29,7 +28,7 @@
2928
public class DiscoveryEc2InstanceProfileIT extends DiscoveryEc2ClusterFormationTestCase {
3029

3130
// Lazy-initialized so we can generate it randomly, which is not possible in static context.
32-
private static final Supplier<String> regionSupplier = new LazyInitializable<>(ESTestCase::randomIdentifier)::getOrCompute;
31+
private static final Supplier<String> regionSupplier = new DynamicRegionSupplier();
3332

3433
private static final DynamicAwsCredentials dynamicCredentials = new DynamicAwsCredentials(regionSupplier, "ec2");
3534

server/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2365,27 +2365,29 @@ private static <V> V splitSelectorExpression(String expression, BiFunction<Strin
23652365
int lastDoubleColon = expression.lastIndexOf(SELECTOR_SEPARATOR);
23662366
if (lastDoubleColon >= 0) {
23672367
String suffix = expression.substring(lastDoubleColon + SELECTOR_SEPARATOR.length());
2368-
doValidateSelectorString(() -> expression, suffix);
2368+
IndexComponentSelector selector = resolveAndValidateSelectorString(() -> expression, suffix);
23692369
String expressionBase = expression.substring(0, lastDoubleColon);
23702370
ensureNoMoreSelectorSeparators(expressionBase, expression);
2371+
ensureNotMixingRemoteClusterExpressionWithSelectorSeparator(expressionBase, selector, expression);
23712372
return bindFunction.apply(expressionBase, suffix);
23722373
}
23732374
// Otherwise accept the default
23742375
return bindFunction.apply(expression, null);
23752376
}
23762377

23772378
public static void validateIndexSelectorString(String indexName, String suffix) {
2378-
doValidateSelectorString(() -> indexName + SELECTOR_SEPARATOR + suffix, suffix);
2379+
resolveAndValidateSelectorString(() -> indexName + SELECTOR_SEPARATOR + suffix, suffix);
23792380
}
23802381

2381-
private static void doValidateSelectorString(Supplier<String> expression, String suffix) {
2382+
private static IndexComponentSelector resolveAndValidateSelectorString(Supplier<String> expression, String suffix) {
23822383
IndexComponentSelector selector = IndexComponentSelector.getByKey(suffix);
23832384
if (selector == null) {
23842385
throw new InvalidIndexNameException(
23852386
expression.get(),
23862387
"invalid usage of :: separator, [" + suffix + "] is not a recognized selector"
23872388
);
23882389
}
2390+
return selector;
23892391
}
23902392

23912393
/**
@@ -2416,6 +2418,22 @@ private static void ensureNoMoreSelectorSeparators(String remainingExpression, S
24162418
);
24172419
}
24182420
}
2421+
2422+
/**
2423+
* Checks the expression for remote cluster pattern and throws an exception if it is combined with :: selectors.
2424+
* @throws InvalidIndexNameException if remote cluster pattern is detected after parsing the selector expression
2425+
*/
2426+
private static void ensureNotMixingRemoteClusterExpressionWithSelectorSeparator(
2427+
String expressionWithoutSelector,
2428+
IndexComponentSelector selector,
2429+
String originalExpression
2430+
) {
2431+
if (selector != null) {
2432+
if (RemoteClusterAware.isRemoteIndexName(expressionWithoutSelector)) {
2433+
throw new InvalidIndexNameException(originalExpression, "Selectors are not yet supported on remote cluster patterns");
2434+
}
2435+
}
2436+
}
24192437
}
24202438

24212439
/**

server/src/test/java/org/elasticsearch/cluster/metadata/SelectorResolverTests.java

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717
import org.elasticsearch.indices.SystemIndices;
1818
import org.elasticsearch.test.ESTestCase;
1919

20+
import java.util.Set;
21+
2022
import static org.elasticsearch.action.support.IndexComponentSelector.DATA;
2123
import static org.elasticsearch.action.support.IndexComponentSelector.FAILURES;
2224
import static org.elasticsearch.cluster.metadata.IndexNameExpressionResolver.Context;
2325
import static org.elasticsearch.cluster.metadata.IndexNameExpressionResolver.ResolvedExpression;
26+
import static org.hamcrest.Matchers.containsString;
2427
import static org.hamcrest.Matchers.equalTo;
2528
import static org.hamcrest.Matchers.is;
2629
import static org.hamcrest.Matchers.nullValue;
@@ -72,16 +75,49 @@ public void testResolveExpression() {
7275
// === Corner Cases
7376
// Empty index name is not necessarily disallowed, but will be filtered out in the next steps of resolution
7477
assertThat(resolve(selectorsAllowed, "::data"), equalTo(new ResolvedExpression("", DATA)));
75-
// Remote cluster syntax is respected, even if code higher up the call stack is likely to already have handled it already
76-
assertThat(resolve(selectorsAllowed, "cluster:index::data"), equalTo(new ResolvedExpression("cluster:index", DATA)));
77-
// CCS with an empty index name is not necessarily disallowed, though other code in the resolution logic will likely throw
78-
assertThat(resolve(selectorsAllowed, "cluster:::data"), equalTo(new ResolvedExpression("cluster:", DATA)));
79-
// Same for empty cluster and index names
78+
assertThat(resolve(selectorsAllowed, "::failures"), equalTo(new ResolvedExpression("", FAILURES)));
79+
// CCS with an empty index and cluster name is not necessarily disallowed, though other code in the resolution logic will likely
80+
// throw
8081
assertThat(resolve(selectorsAllowed, ":::data"), equalTo(new ResolvedExpression(":", DATA)));
82+
assertThat(resolve(selectorsAllowed, ":::failures"), equalTo(new ResolvedExpression(":", FAILURES)));
8183
// Any more prefix colon characters will trigger the multiple separators error logic
8284
expectThrows(InvalidIndexNameException.class, () -> resolve(selectorsAllowed, "::::data"));
85+
expectThrows(InvalidIndexNameException.class, () -> resolve(selectorsAllowed, "::::failures"));
86+
expectThrows(InvalidIndexNameException.class, () -> resolve(selectorsAllowed, ":::::failures"));
8387
// Suffix case is not supported because there is no component named with the empty string
8488
expectThrows(InvalidIndexNameException.class, () -> resolve(selectorsAllowed, "index::"));
89+
90+
// remote cluster syntax is not allowed with :: selectors
91+
final Set<String> remoteClusterExpressionsWithSelectors = Set.of(
92+
"cluster:index::failures",
93+
"cluster-*:index::failures",
94+
"cluster-*:index-*::failures",
95+
"cluster-*:*::failures",
96+
"*:index-*::failures",
97+
"*:*::failures",
98+
"*:-test*,*::failures",
99+
"cluster:::failures",
100+
"failures:index::failures",
101+
"data:index::failures",
102+
"failures:failures::failures",
103+
"data:data::failures",
104+
"cluster:index::data",
105+
"cluster-*:index::data",
106+
"cluster-*:index-*::data",
107+
"cluster-*:*::data",
108+
"*:index-*::data",
109+
"*:*::data",
110+
"cluster:::data",
111+
"failures:index::data",
112+
"data:index::data",
113+
"failures:failures::data",
114+
"data:data::data",
115+
"*:-test*,*::data"
116+
);
117+
for (String expression : remoteClusterExpressionsWithSelectors) {
118+
var e = expectThrows(InvalidIndexNameException.class, () -> resolve(selectorsAllowed, expression));
119+
assertThat(e.getMessage(), containsString("Selectors are not yet supported on remote cluster patterns"));
120+
}
85121
}
86122

87123
public void testResolveMatchAllToSelectors() {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package fixture.aws;
11+
12+
import org.elasticsearch.test.ESTestCase;
13+
14+
import java.util.Objects;
15+
import java.util.concurrent.atomic.AtomicReference;
16+
import java.util.function.Supplier;
17+
18+
/**
19+
* Lazy supplier for a region name. We cannot use randomness like {@link ESTestCase#randomIdentifier()} when creating the test fixtures in
20+
* the first place because this happens in static context, so instead we create one of these and defer the creation of the region name
21+
* itself until the test actually starts running.
22+
*/
23+
public class DynamicRegionSupplier implements Supplier<String> {
24+
private final AtomicReference<String> generatedRegion = new AtomicReference<>();
25+
26+
@Override
27+
public String get() {
28+
return Objects.requireNonNullElseGet(generatedRegion.get(), this::generateAndGet);
29+
}
30+
31+
private String generateAndGet() {
32+
final var newRegion = "DynamicRegionSupplier-" + ESTestCase.randomIdentifier();
33+
return Objects.requireNonNullElse(generatedRegion.compareAndExchange(null, newRegion), newRegion);
34+
}
35+
}

test/fixtures/aws-sts-fixture/src/main/java/fixture/aws/sts/AwsStsHttpHandler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.IOException;
1919
import java.net.URLDecoder;
2020
import java.nio.charset.StandardCharsets;
21+
import java.time.Clock;
2122
import java.time.ZonedDateTime;
2223
import java.time.format.DateTimeFormatter;
2324
import java.util.Arrays;
@@ -73,7 +74,7 @@ public void handle(final HttpExchange exchange) throws IOException {
7374
exchange.close();
7475
return;
7576
}
76-
final var accessKey = randomIdentifier();
77+
final var accessKey = "test_key_STS_" + randomIdentifier();
7778
final var sessionToken = randomIdentifier();
7879
newCredentialsConsumer.accept(accessKey, sessionToken);
7980
final byte[] response = String.format(
@@ -104,7 +105,7 @@ public void handle(final HttpExchange exchange) throws IOException {
104105
ROLE_NAME,
105106
sessionToken,
106107
randomSecretKey(),
107-
ZonedDateTime.now().plusDays(1L).format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ")),
108+
ZonedDateTime.now(Clock.systemUTC()).plusDays(1L).format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ")),
108109
accessKey
109110
).getBytes(StandardCharsets.UTF_8);
110111
exchange.getResponseHeaders().add("Content-Type", "text/xml; charset=UTF-8");

test/fixtures/ec2-imds-fixture/src/main/java/fixture/aws/imds/Ec2ImdsHttpHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public void handle(final HttpExchange exchange) throws IOException {
121121

122122
if ("GET".equals(requestMethod)) {
123123
if (path.equals(IMDS_SECURITY_CREDENTIALS_PATH) && dynamicProfileNames) {
124-
final var profileName = randomIdentifier();
124+
final var profileName = "imds_profile_" + randomIdentifier();
125125
validCredentialsEndpoints.add(IMDS_SECURITY_CREDENTIALS_PATH + profileName);
126126
sendStringResponse(exchange, profileName);
127127
return;
@@ -133,7 +133,7 @@ public void handle(final HttpExchange exchange) throws IOException {
133133
sendStringResponse(exchange, Strings.toString(instanceIdentityDocument));
134134
return;
135135
} else if (validCredentialsEndpoints.contains(path)) {
136-
final String accessKey = randomIdentifier();
136+
final String accessKey = "test_key_imds_" + randomIdentifier();
137137
final String sessionToken = randomIdentifier();
138138
newCredentialsConsumer.accept(accessKey, sessionToken);
139139
final byte[] response = Strings.format(

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,13 @@ public void testInvalidCharacterInIndexPattern() {
637637
expectDoubleColonErrorWithLineNumber(command, "*:*::failures", parseLineNumber + 3);
638638

639639
// Too many colons
640-
expectInvalidIndexNameErrorWithLineNumber(command, "\"index:::data\"", lineNumber, "index:", "must not contain ':'");
640+
expectInvalidIndexNameErrorWithLineNumber(
641+
command,
642+
"\"index:::data\"",
643+
lineNumber,
644+
"index:::data",
645+
"Selectors are not yet supported on remote cluster patterns"
646+
);
641647
expectInvalidIndexNameErrorWithLineNumber(
642648
command,
643649
"\"index::::data\"",

0 commit comments

Comments
 (0)