From 3fad074417c9a6c9d8bd8c2f015575cd1b864346 Mon Sep 17 00:00:00 2001 From: Henning Andersen <33268011+henningandersen@users.noreply.github.com> Date: Tue, 28 May 2024 12:57:32 +0200 Subject: [PATCH 001/208] Enable not same executor assertion (#109088) Enable the assertion introduced in #108934 --- .../org/elasticsearch/action/support/PlainActionFuture.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/support/PlainActionFuture.java b/server/src/main/java/org/elasticsearch/action/support/PlainActionFuture.java index 938fe4c84480b..c52c9ba1264db 100644 --- a/server/src/main/java/org/elasticsearch/action/support/PlainActionFuture.java +++ b/server/src/main/java/org/elasticsearch/action/support/PlainActionFuture.java @@ -407,8 +407,7 @@ public static T get(CheckedConsumer Date: Tue, 28 May 2024 07:27:13 -0400 Subject: [PATCH 002/208] ESQL: Prepare analyzer for LOOKUP (#109045) This extracts two fairly uncontroversial changes that were in the main LOOKUP PR into a smaller change that's easier to review. --- .../elasticsearch/xpack/esql/analysis/Analyzer.java | 12 +++--------- .../xpack/esql/parser/ExpressionBuilder.java | 4 ++-- .../xpack/esql/parser/LogicalPlanBuilder.java | 2 +- .../xpack/esql/parser/ExpressionTests.java | 2 +- .../xpack/esql/parser/StatementParserTests.java | 8 ++++---- 5 files changed, 11 insertions(+), 17 deletions(-) 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 fc4673104a71a..082036e32e71f 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 @@ -118,16 +118,10 @@ public class Analyzer extends ParameterizedRuleExecutor> rules; static { - var resolution = new Batch<>( - "Resolution", - new ResolveTable(), - new ResolveEnrich(), - new ResolveFunctions(), - new ResolveRefs(), - new ImplicitCasting() - ); + var init = new Batch<>("Initialize", Limiter.ONCE, new ResolveTable(), new ResolveEnrich(), new ResolveFunctions()); + var resolution = new Batch<>("Resolution", new ResolveRefs(), new ImplicitCasting()); var finish = new Batch<>("Finish Analysis", Limiter.ONCE, new AddImplicitLimit()); - rules = List.of(resolution, finish); + rules = List.of(init, resolution, finish); } private final Verifier verifier; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java index fa4afd9e1e528..c80488cad4190 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java @@ -586,7 +586,7 @@ public Alias visitRenameClause(EsqlBaseParser.RenameClauseContext ctx) { NamedExpression newName = visitQualifiedNamePattern(ctx.newName); NamedExpression oldName = visitQualifiedNamePattern(ctx.oldName); if (newName instanceof UnresolvedNamePattern || oldName instanceof UnresolvedNamePattern) { - throw new ParsingException(src, "Using wildcards (*) in RENAME is not allowed [{}]", src.text()); + throw new ParsingException(src, "Using wildcards [*] in RENAME is not allowed [{}]", src.text()); } return new Alias(src, newName.name(), oldName); @@ -603,7 +603,7 @@ public NamedExpression visitEnrichWithClause(EsqlBaseParser.EnrichWithClauseCont private NamedExpression enrichFieldName(EsqlBaseParser.QualifiedNamePatternContext ctx) { var name = visitQualifiedNamePattern(ctx); if (name instanceof UnresolvedNamePattern up) { - throw new ParsingException(source(ctx), "Using wildcards (*) in ENRICH WITH projections is not allowed [{}]", up.pattern()); + throw new ParsingException(source(ctx), "Using wildcards [*] in ENRICH WITH projections is not allowed [{}]", up.pattern()); } return name; } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java index 32c7734193947..a7a3d0b816e79 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java @@ -378,7 +378,7 @@ public PlanFactory visitEnrichCommand(EsqlBaseParser.EnrichCommandContext ctx) { NamedExpression matchField = ctx.ON() != null ? visitQualifiedNamePattern(ctx.matchField) : new EmptyAttribute(source); if (matchField instanceof UnresolvedNamePattern up) { - throw new ParsingException(source, "Using wildcards (*) in ENRICH WITH projections is not allowed [{}]", up.pattern()); + throw new ParsingException(source, "Using wildcards [*] in ENRICH WITH projections is not allowed [{}]", up.pattern()); } List keepClauses = visitList(this, ctx.enrichWithClause(), NamedExpression.class); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/ExpressionTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/ExpressionTests.java index 1123b16ee45e8..8853f4661fe9b 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/ExpressionTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/ExpressionTests.java @@ -608,7 +608,7 @@ public void testMultipleProjectPatterns() { } public void testForbidWildcardProjectRename() { - assertParsingException(() -> renameExpression("b* AS a*"), "line 1:18: Using wildcards (*) in RENAME is not allowed [b* AS a*]"); + assertParsingException(() -> renameExpression("b* AS a*"), "line 1:18: Using wildcards [*] in RENAME is not allowed [b* AS a*]"); } public void testSimplifyInWithSingleElementList() { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java index 568694947e39a..db4d54caf9943 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java @@ -728,15 +728,15 @@ public void testEnrich() { processingCommand("enrich _" + mode.name() + ":countries ON country_code") ); - expectError("from a | enrich countries on foo* ", "Using wildcards (*) in ENRICH WITH projections is not allowed [foo*]"); - expectError("from a | enrich countries on foo with bar*", "Using wildcards (*) in ENRICH WITH projections is not allowed [bar*]"); + expectError("from a | enrich countries on foo* ", "Using wildcards [*] in ENRICH WITH projections is not allowed [foo*]"); + expectError("from a | enrich countries on foo with bar*", "Using wildcards [*] in ENRICH WITH projections is not allowed [bar*]"); expectError( "from a | enrich countries on foo with x = bar* ", - "Using wildcards (*) in ENRICH WITH projections is not allowed [bar*]" + "Using wildcards [*] in ENRICH WITH projections is not allowed [bar*]" ); expectError( "from a | enrich countries on foo with x* = bar ", - "Using wildcards (*) in ENRICH WITH projections is not allowed [x*]" + "Using wildcards [*] in ENRICH WITH projections is not allowed [x*]" ); expectError( "from a | enrich typo:countries on foo", From 8329a094ab9fbb98856e18327f435b977055a839 Mon Sep 17 00:00:00 2001 From: Simon Cooper Date: Tue, 28 May 2024 12:46:15 +0100 Subject: [PATCH 003/208] Add permission to secure access to certain config files (#107827) This adds a SecuredFileAccessPermission that Elasticsearch and plugins can use to limit access to certain files, so that only code that also has that same permission can access the specified files --- docs/changelog/107827.yaml | 5 ++ .../bootstrap/ESPolicyUnitTests.java | 87 +++++++++++++------ .../SecuredFileAccessPermission.java | 25 ++++++ .../org/elasticsearch/bootstrap/ESPolicy.java | 80 ++++++++++++++--- .../elasticsearch/bootstrap/PolicyUtil.java | 27 +++--- .../org/elasticsearch/bootstrap/Security.java | 78 +++++++++++++---- .../bootstrap/BootstrapForTesting.java | 11 +-- 7 files changed, 239 insertions(+), 74 deletions(-) create mode 100644 docs/changelog/107827.yaml create mode 100644 server/src/main/java/org/elasticsearch/SecuredFileAccessPermission.java diff --git a/docs/changelog/107827.yaml b/docs/changelog/107827.yaml new file mode 100644 index 0000000000000..7cf217567b745 --- /dev/null +++ b/docs/changelog/107827.yaml @@ -0,0 +1,5 @@ +pr: 107827 +summary: Add permission to secure access to certain config files +area: Security +type: bug +issues: [] diff --git a/qa/evil-tests/src/test/java/org/elasticsearch/bootstrap/ESPolicyUnitTests.java b/qa/evil-tests/src/test/java/org/elasticsearch/bootstrap/ESPolicyUnitTests.java index bd26146f92c0d..86a5e6734c701 100644 --- a/qa/evil-tests/src/test/java/org/elasticsearch/bootstrap/ESPolicyUnitTests.java +++ b/qa/evil-tests/src/test/java/org/elasticsearch/bootstrap/ESPolicyUnitTests.java @@ -10,6 +10,7 @@ import org.elasticsearch.core.SuppressForbidden; import org.elasticsearch.test.ESTestCase; +import org.junit.BeforeClass; import java.io.FilePermission; import java.net.SocketPermission; @@ -19,11 +20,15 @@ import java.security.Permission; import java.security.PermissionCollection; import java.security.Permissions; +import java.security.Policy; import java.security.ProtectionDomain; import java.security.cert.Certificate; -import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; + +import static java.util.Map.entry; +import static org.elasticsearch.bootstrap.ESPolicy.POLICY_RESOURCE; /** * Unit tests for ESPolicy: these cannot run with security manager, @@ -32,6 +37,13 @@ public class ESPolicyUnitTests extends ESTestCase { static final Map TEST_CODEBASES = BootstrapForTesting.getCodebases(); + static Policy DEFAULT_POLICY; + + @BeforeClass + public static void setupPolicy() { + assumeTrue("test cannot run with security manager", System.getSecurityManager() == null); + DEFAULT_POLICY = PolicyUtil.readPolicy(ESPolicy.class.getResource(POLICY_RESOURCE), TEST_CODEBASES); + } /** * Test policy with null codesource. @@ -42,12 +54,11 @@ public class ESPolicyUnitTests extends ESTestCase { */ @SuppressForbidden(reason = "to create FilePermission object") public void testNullCodeSource() throws Exception { - assumeTrue("test cannot run with security manager", System.getSecurityManager() == null); // create a policy with AllPermission Permission all = new AllPermission(); PermissionCollection allCollection = all.newPermissionCollection(); allCollection.add(all); - ESPolicy policy = new ESPolicy(TEST_CODEBASES, allCollection, Collections.emptyMap(), true, List.of(), List.of()); + ESPolicy policy = new ESPolicy(DEFAULT_POLICY, allCollection, Map.of(), true, List.of(), Map.of()); // restrict ourselves to NoPermission PermissionCollection noPermissions = new Permissions(); assertFalse(policy.implies(new ProtectionDomain(null, noPermissions), new FilePermission("foo", "read"))); @@ -58,9 +69,8 @@ public void testNullCodeSource() throws Exception { */ @SuppressForbidden(reason = "to create FilePermission object") public void testNullLocation() throws Exception { - assumeTrue("test cannot run with security manager", System.getSecurityManager() == null); PermissionCollection noPermissions = new Permissions(); - ESPolicy policy = new ESPolicy(TEST_CODEBASES, noPermissions, Collections.emptyMap(), true, List.of(), List.of()); + ESPolicy policy = new ESPolicy(DEFAULT_POLICY, noPermissions, Map.of(), true, List.of(), Map.of()); assertFalse( policy.implies( new ProtectionDomain(new CodeSource(null, (Certificate[]) null), noPermissions), @@ -70,9 +80,8 @@ public void testNullLocation() throws Exception { } public void testListen() { - assumeTrue("test cannot run with security manager", System.getSecurityManager() == null); final PermissionCollection noPermissions = new Permissions(); - final ESPolicy policy = new ESPolicy(TEST_CODEBASES, noPermissions, Collections.emptyMap(), true, List.of(), List.of()); + final ESPolicy policy = new ESPolicy(DEFAULT_POLICY, noPermissions, Map.of(), true, List.of(), Map.of()); assertFalse( policy.implies( new ProtectionDomain(ESPolicyUnitTests.class.getProtectionDomain().getCodeSource(), noPermissions), @@ -83,14 +92,13 @@ public void testListen() { @SuppressForbidden(reason = "to create FilePermission object") public void testDataPathPermissionIsChecked() { - assumeTrue("test cannot run with security manager", System.getSecurityManager() == null); final ESPolicy policy = new ESPolicy( - TEST_CODEBASES, + DEFAULT_POLICY, new Permissions(), - Collections.emptyMap(), + Map.of(), true, List.of(new FilePermission("/home/elasticsearch/data/-", "read")), - List.of() + Map.of() ); assertTrue( policy.implies( @@ -101,27 +109,52 @@ public void testDataPathPermissionIsChecked() { } @SuppressForbidden(reason = "to create FilePermission object") - public void testForbiddenFilesAreForbidden() { - assumeTrue("test cannot run with security manager", System.getSecurityManager() == null); - - FilePermission configPerm = new FilePermission("/home/elasticsearch/config/-", "read"); - PermissionCollection coll = configPerm.newPermissionCollection(); - coll.add(configPerm); + public void testSecuredAccess() { + String file1 = "/home/elasticsearch/config/pluginFile1.yml"; + URL codebase1 = randomFrom(TEST_CODEBASES.values()); + String file2 = "/home/elasticsearch/config/pluginFile2.yml"; + URL codebase2 = randomValueOtherThan(codebase1, () -> randomFrom(TEST_CODEBASES.values())); + String dir1 = "/home/elasticsearch/config/pluginDir/"; + URL codebase3 = randomValueOtherThanMany(Set.of(codebase1, codebase2)::contains, () -> randomFrom(TEST_CODEBASES.values())); + URL otherCodebase = randomValueOtherThanMany( + Set.of(codebase1, codebase2, codebase3)::contains, + () -> randomFrom(TEST_CODEBASES.values()) + ); ESPolicy policy = new ESPolicy( - TEST_CODEBASES, - coll, - Collections.emptyMap(), + DEFAULT_POLICY, + new Permissions(), + Map.of(), true, List.of(), - List.of(new FilePermission("/home/elasticsearch/config/forbidden.yml", "read")) - ); - ProtectionDomain pd = new ProtectionDomain( - new CodeSource(randomBoolean() ? null : randomFrom(TEST_CODEBASES.values()), (Certificate[]) null), - new Permissions() + Map.ofEntries(entry(file1, Set.of(codebase1)), entry(file2, Set.of(codebase1, codebase2)), entry(dir1 + "*", Set.of(codebase3))) ); - assertTrue(policy.implies(pd, new FilePermission("/home/elasticsearch/config/config.yml", "read"))); - assertFalse(policy.implies(pd, new FilePermission("/home/elasticsearch/config/forbidden.yml", "read"))); + ProtectionDomain nullDomain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), new Permissions()); + ProtectionDomain codebase1Domain = new ProtectionDomain(new CodeSource(codebase1, (Certificate[]) null), new Permissions()); + ProtectionDomain codebase2Domain = new ProtectionDomain(new CodeSource(codebase2, (Certificate[]) null), new Permissions()); + ProtectionDomain codebase3Domain = new ProtectionDomain(new CodeSource(codebase3, (Certificate[]) null), new Permissions()); + ProtectionDomain otherCodebaseDomain = new ProtectionDomain(new CodeSource(otherCodebase, (Certificate[]) null), new Permissions()); + + Set actions = Set.of("read", "write", "read,write", "delete", "read,write,execute,readlink,delete"); + + assertFalse(policy.implies(nullDomain, new FilePermission(file1, randomFrom(actions)))); + assertFalse(policy.implies(otherCodebaseDomain, new FilePermission(file1, randomFrom(actions)))); + assertTrue(policy.implies(codebase1Domain, new FilePermission(file1, randomFrom(actions)))); + assertFalse(policy.implies(codebase2Domain, new FilePermission(file1, randomFrom(actions)))); + assertFalse(policy.implies(codebase3Domain, new FilePermission(file1, randomFrom(actions)))); + + assertFalse(policy.implies(nullDomain, new FilePermission(file2, randomFrom(actions)))); + assertFalse(policy.implies(otherCodebaseDomain, new FilePermission(file2, randomFrom(actions)))); + assertTrue(policy.implies(codebase1Domain, new FilePermission(file2, randomFrom(actions)))); + assertTrue(policy.implies(codebase2Domain, new FilePermission(file2, randomFrom(actions)))); + assertFalse(policy.implies(codebase3Domain, new FilePermission(file2, randomFrom(actions)))); + + String dirFile = dir1 + "file.yml"; + assertFalse(policy.implies(nullDomain, new FilePermission(dirFile, randomFrom(actions)))); + assertFalse(policy.implies(otherCodebaseDomain, new FilePermission(dirFile, randomFrom(actions)))); + assertFalse(policy.implies(codebase1Domain, new FilePermission(dirFile, randomFrom(actions)))); + assertFalse(policy.implies(codebase2Domain, new FilePermission(dirFile, randomFrom(actions)))); + assertTrue(policy.implies(codebase3Domain, new FilePermission(dirFile, randomFrom(actions)))); } } diff --git a/server/src/main/java/org/elasticsearch/SecuredFileAccessPermission.java b/server/src/main/java/org/elasticsearch/SecuredFileAccessPermission.java new file mode 100644 index 0000000000000..3d24a9bc5ddb3 --- /dev/null +++ b/server/src/main/java/org/elasticsearch/SecuredFileAccessPermission.java @@ -0,0 +1,25 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch; + +import java.security.BasicPermission; + +/** + * A permission granted to ensure secured access to a file in the config directory. + *

+ * By granting this permission, all code that does not have the same permission on the same file + * will be denied all read/write access to that file. + * Note that you also need to wrap any access to the secured files in an {@code AccessController.doPrivileged()} block + * as Elasticsearch itself is denied access to files secured by plugins. + */ +public class SecuredFileAccessPermission extends BasicPermission { + public SecuredFileAccessPermission(String path) { + super(path, ""); + } +} diff --git a/server/src/main/java/org/elasticsearch/bootstrap/ESPolicy.java b/server/src/main/java/org/elasticsearch/bootstrap/ESPolicy.java index d349403505311..dbc94ad7812a7 100644 --- a/server/src/main/java/org/elasticsearch/bootstrap/ESPolicy.java +++ b/server/src/main/java/org/elasticsearch/bootstrap/ESPolicy.java @@ -21,10 +21,13 @@ import java.security.Permissions; import java.security.Policy; import java.security.ProtectionDomain; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Predicate; +import java.util.stream.Collectors; /** custom policy for union of static and dynamic permissions */ final class ESPolicy extends Policy { @@ -34,25 +37,28 @@ final class ESPolicy extends Policy { /** limited policy for scripts */ static final String UNTRUSTED_RESOURCE = "untrusted.policy"; + private static final String ALL_FILE_MASK = "read,readlink,write,delete,execute"; + final Policy template; final Policy untrusted; final Policy system; final PermissionCollection dynamic; final PermissionCollection dataPathPermission; - final PermissionCollection forbiddenFilePermission; - final Map plugins; + final Map plugins; + final PermissionCollection allSecuredFiles; + final Map> securedFiles; + @SuppressForbidden(reason = "Need to access and check file permissions directly") ESPolicy( - Map codebases, + Policy template, PermissionCollection dynamic, - Map plugins, + Map plugins, boolean filterBadDefaults, List dataPathPermissions, - List forbiddenFilePermissions + Map> securedFiles ) { - this.template = PolicyUtil.readPolicy(getClass().getResource(POLICY_RESOURCE), codebases); + this.template = template; this.dataPathPermission = createPermission(dataPathPermissions); - this.forbiddenFilePermission = createPermission(forbiddenFilePermissions); this.untrusted = PolicyUtil.readPolicy(getClass().getResource(UNTRUSTED_RESOURCE), Collections.emptyMap()); if (filterBadDefaults) { this.system = new SystemPolicy(Policy.getPolicy()); @@ -61,6 +67,27 @@ final class ESPolicy extends Policy { } this.dynamic = dynamic; this.plugins = plugins; + + this.securedFiles = securedFiles.entrySet() + .stream() + .collect(Collectors.toUnmodifiableMap(e -> new FilePermission(e.getKey(), ALL_FILE_MASK), e -> Set.copyOf(e.getValue()))); + this.allSecuredFiles = createPermission(this.securedFiles.keySet()); + } + + private static PermissionCollection createPermission(Collection permissions) { + PermissionCollection coll; + var it = permissions.iterator(); + if (it.hasNext() == false) { + coll = new Permissions(); + } else { + Permission p = it.next(); + coll = p.newPermissionCollection(); + coll.add(p); + it.forEachRemaining(coll::add); + } + + coll.setReadOnly(); + return coll; } private static PermissionCollection createPermission(List permissions) { @@ -87,12 +114,18 @@ public boolean implies(ProtectionDomain domain, Permission permission) { return false; } - // completely deny access to specific files that are forbidden - if (forbiddenFilePermission.implies(permission)) { - return false; + URL location = codeSource.getLocation(); + if (allSecuredFiles.implies(permission)) { + /* + * Check if location can access this secured file + * The permission this is generated from, SecuredFileAccessPermission, doesn't have a mask, + * it just grants all access (and so disallows all access from others) + * It's helpful to use the infrastructure around FilePermission here to do the directory structure check with implies + * so we use ALL_FILE_MASK mask to check if we can do something with this file, whatever the actual operation we're requesting + */ + return canAccessSecuredFile(location, new FilePermission(permission.getName(), ALL_FILE_MASK)); } - URL location = codeSource.getLocation(); if (location != null) { // run scripts with limited permissions if (BootstrapInfo.UNTRUSTED_CODEBASE.equals(location.getFile())) { @@ -100,7 +133,7 @@ public boolean implies(ProtectionDomain domain, Permission permission) { } // check for an additional plugin permission: plugin policy is // only consulted for its codesources. - Policy plugin = plugins.get(location.getFile()); + Policy plugin = plugins.get(location); if (plugin != null && plugin.implies(domain, permission)) { return true; } @@ -122,6 +155,29 @@ public boolean implies(ProtectionDomain domain, Permission permission) { return template.implies(domain, permission) || dynamic.implies(permission) || system.implies(domain, permission); } + @SuppressForbidden(reason = "We get given an URL by the security infrastructure") + private boolean canAccessSecuredFile(URL location, FilePermission permission) { + if (location == null) { + return false; + } + + // check the source + Set accessibleSources = securedFiles.get(permission); + if (accessibleSources != null) { + // simple case - single-file referenced directly + return accessibleSources.contains(location); + } else { + // there's a directory reference in there somewhere + // do a manual search :( + // there may be several permissions that potentially match, + // grant access if any of them cover this file + return securedFiles.entrySet() + .stream() + .filter(e -> e.getKey().implies(permission)) + .anyMatch(e -> e.getValue().contains(location)); + } + } + private static void hadoopHack() { for (StackTraceElement element : Thread.currentThread().getStackTrace()) { if ("org.apache.hadoop.util.Shell".equals(element.getClassName()) && "runCommand".equals(element.getMethodName())) { diff --git a/server/src/main/java/org/elasticsearch/bootstrap/PolicyUtil.java b/server/src/main/java/org/elasticsearch/bootstrap/PolicyUtil.java index 5d34a86c2e30b..3279bc5b1bfdf 100644 --- a/server/src/main/java/org/elasticsearch/bootstrap/PolicyUtil.java +++ b/server/src/main/java/org/elasticsearch/bootstrap/PolicyUtil.java @@ -8,6 +8,7 @@ package org.elasticsearch.bootstrap; +import org.elasticsearch.SecuredFileAccessPermission; import org.elasticsearch.core.IOUtils; import org.elasticsearch.core.PathUtils; import org.elasticsearch.core.SuppressForbidden; @@ -50,6 +51,7 @@ import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.management.MBeanPermission; import javax.management.MBeanServerPermission; @@ -60,6 +62,8 @@ import javax.security.auth.kerberos.DelegationPermission; import javax.security.auth.kerberos.ServicePermission; +import static java.util.Map.entry; + public class PolicyUtil { // this object is checked by reference, so the value in the list does not matter @@ -158,20 +162,15 @@ public boolean test(Permission permission) { // is used to mean names are accepted. We do not use this model for all permissions because many permission // classes have their own meaning for some form of wildcard matching of the name, which we want to delegate // to those permissions if possible. - Map> classPermissions = Map.of( - URLPermission.class, - ALLOW_ALL_NAMES, - DelegationPermission.class, - ALLOW_ALL_NAMES, - ServicePermission.class, - ALLOW_ALL_NAMES, - PrivateCredentialPermission.class, - ALLOW_ALL_NAMES, - SQLPermission.class, - List.of("callAbort", "setNetworkTimeout"), - ClassPermission.class, - ALLOW_ALL_NAMES - ).entrySet().stream().collect(Collectors.toMap(e -> e.getKey().getCanonicalName(), Map.Entry::getValue)); + Map> classPermissions = Stream.of( + entry(URLPermission.class, ALLOW_ALL_NAMES), + entry(DelegationPermission.class, ALLOW_ALL_NAMES), + entry(ServicePermission.class, ALLOW_ALL_NAMES), + entry(PrivateCredentialPermission.class, ALLOW_ALL_NAMES), + entry(SQLPermission.class, List.of("callAbort", "setNetworkTimeout")), + entry(ClassPermission.class, ALLOW_ALL_NAMES), + entry(SecuredFileAccessPermission.class, ALLOW_ALL_NAMES) + ).collect(Collectors.toMap(e -> e.getKey().getCanonicalName(), Map.Entry::getValue)); PermissionCollection pluginPermissionCollection = new Permissions(); namedPermissions.forEach(pluginPermissionCollection::add); pluginPermissionCollection.setReadOnly(); diff --git a/server/src/main/java/org/elasticsearch/bootstrap/Security.java b/server/src/main/java/org/elasticsearch/bootstrap/Security.java index 1c37b3492c4cb..e24e13dfff372 100644 --- a/server/src/main/java/org/elasticsearch/bootstrap/Security.java +++ b/server/src/main/java/org/elasticsearch/bootstrap/Security.java @@ -9,6 +9,7 @@ package org.elasticsearch.bootstrap; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.SecuredFileAccessPermission; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.PathUtils; import org.elasticsearch.core.SuppressForbidden; @@ -33,8 +34,11 @@ import java.nio.file.Files; import java.nio.file.NotDirectoryException; import java.nio.file.Path; +import java.security.Permission; import java.security.Permissions; import java.security.Policy; +import java.security.UnresolvedPermission; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -42,8 +46,10 @@ import java.util.Map; import java.util.Set; import java.util.function.Consumer; +import java.util.stream.Stream; import static java.lang.invoke.MethodType.methodType; +import static org.elasticsearch.bootstrap.ESPolicy.POLICY_RESOURCE; import static org.elasticsearch.bootstrap.FilePermissionUtils.addDirectoryPath; import static org.elasticsearch.bootstrap.FilePermissionUtils.addSingleFilePath; import static org.elasticsearch.reservedstate.service.FileSettingsService.OPERATOR_DIRECTORY; @@ -116,17 +122,18 @@ static void setSecurityManager(@SuppressWarnings("removal") SecurityManager sm) * @param filterBadDefaults true if we should filter out bad java defaults in the system policy. */ static void configure(Environment environment, boolean filterBadDefaults, Path pidFile) throws IOException { - // enable security policy: union of template and environment-based paths, and possibly plugin permissions Map codebases = PolicyUtil.getCodebaseJarMap(JarHell.parseModulesAndClassPath()); + Policy mainPolicy = PolicyUtil.readPolicy(ESPolicy.class.getResource(POLICY_RESOURCE), codebases); + Map pluginPolicies = getPluginAndModulePermissions(environment); Policy.setPolicy( new ESPolicy( - codebases, + mainPolicy, createPermissions(environment, pidFile), - getPluginAndModulePermissions(environment), + pluginPolicies, filterBadDefaults, createRecursiveDataPathPermission(environment), - createForbiddenFilePermissions(environment) + readSecuredFiles(environment, mainPolicy, codebases.values(), pluginPolicies) ) ); @@ -146,8 +153,8 @@ static void configure(Environment environment, boolean filterBadDefaults, Path p * we look for matching plugins and set URLs to fit */ @SuppressForbidden(reason = "proper use of URL") - static Map getPluginAndModulePermissions(Environment environment) throws IOException { - Map map = new HashMap<>(); + static Map getPluginAndModulePermissions(Environment environment) throws IOException { + Map map = new HashMap<>(); Consumer addPolicy = pluginPolicy -> { if (pluginPolicy == null) { return; @@ -155,7 +162,7 @@ static Map getPluginAndModulePermissions(Environment environment // consult this policy for each of the plugin's jars: for (URL jar : pluginPolicy.jars()) { - if (map.put(jar.getFile(), pluginPolicy.policy()) != null) { + if (map.put(jar, pluginPolicy.policy()) != null) { // just be paranoid ok? throw new IllegalStateException("per-plugin permissions already granted for jar file: " + jar); } @@ -189,16 +196,55 @@ private static List createRecursiveDataPathPermission(Environmen return toFilePermissions(policy); } - private static List createForbiddenFilePermissions(Environment environment) throws IOException { - Permissions policy = new Permissions(); - addSingleFilePath(policy, environment.configFile().resolve("elasticsearch.yml"), "read,readlink,write,delete,execute"); - addSingleFilePath(policy, environment.configFile().resolve("jvm.options"), "read,readlink,write,delete,execute"); - Path jvmOptionsD = environment.configFile().resolve("jvm.options.d"); - if (Files.isDirectory(jvmOptionsD)) { - // we don't want to create this if it doesn't exist - addDirectoryPath(policy, "forbidden_access", jvmOptionsD, "read,readlink,write,delete,execute", false); + private static Map> readSecuredFiles( + Environment environment, + Policy template, + Collection mainCodebases, + Map pluginPolicies + ) throws IOException { + Map> securedFiles = new HashMap<>(); + + for (URL url : mainCodebases) { + PolicyUtil.getPolicyPermissions(url, template, environment.tmpFile()) + .stream() + .flatMap(Security::extractSecuredFileName) + .map(environment.configFile()::resolve) + .forEach(f -> securedFiles.computeIfAbsent(f.toString(), k -> new HashSet<>()).add(url)); } - return toFilePermissions(policy); + + for (var pp : pluginPolicies.entrySet()) { + PolicyUtil.getPolicyPermissions(pp.getKey(), pp.getValue(), environment.tmpFile()) + .stream() + .flatMap(Security::extractSecuredFileName) + .map(environment.configFile()::resolve) + .forEach(f -> securedFiles.computeIfAbsent(f.toString(), k -> new HashSet<>()).add(pp.getKey())); + } + + // always add some config files as exclusive files that no one can access + // there's no reason for anyone to read these once the security manager is initialized + // so if something has tried to grant itself access, crash out with an error + addSpeciallySecuredFile(securedFiles, environment.configFile().resolve("elasticsearch.yml").toString()); + addSpeciallySecuredFile(securedFiles, environment.configFile().resolve("jvm.options").toString()); + addSpeciallySecuredFile(securedFiles, environment.configFile().resolve("jvm.options.d/-").toString()); + + return Collections.unmodifiableMap(securedFiles); + } + + private static void addSpeciallySecuredFile(Map> securedFiles, String path) { + Set attemptedToGrant = securedFiles.put(path, Set.of()); + if (attemptedToGrant != null) { + throw new IllegalStateException(attemptedToGrant + " tried to grant access to special config file " + path); + } + } + + private static Stream extractSecuredFileName(Permission p) { + if (p instanceof SecuredFileAccessPermission) { + return Stream.of(p.getName()); + } + if (p instanceof UnresolvedPermission up && up.getUnresolvedType().equals(SecuredFileAccessPermission.class.getCanonicalName())) { + return Stream.of(up.getUnresolvedName()); + } + return Stream.empty(); } /** Adds access to classpath jars/classes for jar hell scan, etc */ diff --git a/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java b/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java index f23048185876b..8a3f36ebb1f8a 100644 --- a/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java +++ b/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java @@ -56,6 +56,7 @@ import java.util.stream.Collectors; import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAsBoolean; +import static org.elasticsearch.bootstrap.ESPolicy.POLICY_RESOURCE; import static org.elasticsearch.bootstrap.FilePermissionUtils.addDirectoryPath; /** @@ -170,12 +171,12 @@ public class BootstrapForTesting { addDirectoryPath(fastPathPermissions, "java.io.tmpdir-fastpath", javaTmpDir, "read,readlink,write,delete", true); final Policy esPolicy = new ESPolicy( - codebases, + PolicyUtil.readPolicy(ESPolicy.class.getResource(POLICY_RESOURCE), codebases), perms, getPluginPermissions(), true, Security.toFilePermissions(fastPathPermissions), - List.of() + Map.of() ); Policy.setPolicy(new Policy() { @Override @@ -250,7 +251,7 @@ private static void addClassCodebase(Map codebases, String name, St * like core, test-framework, etc. this way tests fail if accesscontroller blocks are missing. */ @SuppressForbidden(reason = "accesses fully qualified URLs to configure security") - static Map getPluginPermissions() throws Exception { + static Map getPluginPermissions() throws Exception { List pluginPolicies = Collections.list( BootstrapForTesting.class.getClassLoader().getResources(PluginDescriptor.ES_PLUGIN_POLICY) ); @@ -302,9 +303,9 @@ static Map getPluginPermissions() throws Exception { } // consult each policy file for those codebases - Map map = new HashMap<>(); + Map map = new HashMap<>(); for (URL url : codebases) { - map.put(url.getFile(), new Policy() { + map.put(url, new Policy() { @Override public boolean implies(ProtectionDomain domain, Permission permission) { // implements union From 0e8847f7d3c71b6121680e36259c723b46d5f4ee Mon Sep 17 00:00:00 2001 From: Jedr Blaszyk Date: Tue, 28 May 2024 14:54:07 +0200 Subject: [PATCH 004/208] [Connector API] Remove deprecated feature fields (#109074) --- .../connector/ConnectorFeatures.java | 57 ++----------------- .../connector/ConnectorFeaturesTests.java | 8 +-- .../connector/ConnectorTestUtils.java | 2 - .../application/connector/ConnectorTests.java | 1 - 4 files changed, 7 insertions(+), 61 deletions(-) diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorFeatures.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorFeatures.java index bbb8805de1f0f..1b2e7209e41e5 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorFeatures.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorFeatures.java @@ -35,10 +35,6 @@ public class ConnectorFeatures implements Writeable, ToXContentObject { @Nullable private final FeatureEnabled documentLevelSecurityEnabled; @Nullable - private final Boolean filteringAdvancedConfigEnabled; - @Nullable - private final Boolean filteringRulesEnabled; - @Nullable private final FeatureEnabled incrementalSyncEnabled; @Nullable private final FeatureEnabled nativeConnectorAPIKeysEnabled; @@ -49,23 +45,17 @@ public class ConnectorFeatures implements Writeable, ToXContentObject { * Constructs a new instance of ConnectorFeatures. * * @param documentLevelSecurityEnabled A flag indicating whether document-level security is enabled. - * @param filteringAdvancedConfig A flag indicating whether advanced filtering configuration is enabled. - * @param filteringRules A flag indicating whether filtering rules are enabled. * @param incrementalSyncEnabled A flag indicating whether incremental sync is enabled. * @param nativeConnectorAPIKeysEnabled A flag indicating whether support for api keys is enabled for native connectors. * @param syncRulesFeatures An {@link SyncRulesFeatures} object indicating if basic and advanced sync rules are enabled. */ private ConnectorFeatures( FeatureEnabled documentLevelSecurityEnabled, - Boolean filteringAdvancedConfig, - Boolean filteringRules, FeatureEnabled incrementalSyncEnabled, FeatureEnabled nativeConnectorAPIKeysEnabled, SyncRulesFeatures syncRulesFeatures ) { this.documentLevelSecurityEnabled = documentLevelSecurityEnabled; - this.filteringAdvancedConfigEnabled = filteringAdvancedConfig; - this.filteringRulesEnabled = filteringRules; this.incrementalSyncEnabled = incrementalSyncEnabled; this.nativeConnectorAPIKeysEnabled = nativeConnectorAPIKeysEnabled; this.syncRulesFeatures = syncRulesFeatures; @@ -73,16 +63,12 @@ private ConnectorFeatures( public ConnectorFeatures(StreamInput in) throws IOException { this.documentLevelSecurityEnabled = in.readOptionalWriteable(FeatureEnabled::new); - this.filteringAdvancedConfigEnabled = in.readOptionalBoolean(); - this.filteringRulesEnabled = in.readOptionalBoolean(); this.incrementalSyncEnabled = in.readOptionalWriteable(FeatureEnabled::new); this.nativeConnectorAPIKeysEnabled = in.readOptionalWriteable(FeatureEnabled::new); this.syncRulesFeatures = in.readOptionalWriteable(SyncRulesFeatures::new); } private static final ParseField DOCUMENT_LEVEL_SECURITY_ENABLED_FIELD = new ParseField("document_level_security"); - private static final ParseField FILTERING_ADVANCED_CONFIG_ENABLED_FIELD = new ParseField("filtering_advanced_config"); - private static final ParseField FILTERING_RULES_ENABLED_FIELD = new ParseField("filtering_rules"); private static final ParseField INCREMENTAL_SYNC_ENABLED_FIELD = new ParseField("incremental_sync"); private static final ParseField NATIVE_CONNECTOR_API_KEYS_ENABLED_FIELD = new ParseField("native_connector_api_keys"); private static final ParseField SYNC_RULES_FIELD = new ParseField("sync_rules"); @@ -91,18 +77,14 @@ public ConnectorFeatures(StreamInput in) throws IOException { "connector_features", true, args -> new Builder().setDocumentLevelSecurityEnabled((FeatureEnabled) args[0]) - .setFilteringAdvancedConfig((Boolean) args[1]) - .setFilteringRules((Boolean) args[2]) - .setIncrementalSyncEnabled((FeatureEnabled) args[3]) - .setNativeConnectorAPIKeysEnabled((FeatureEnabled) args[4]) - .setSyncRulesFeatures((SyncRulesFeatures) args[5]) + .setIncrementalSyncEnabled((FeatureEnabled) args[1]) + .setNativeConnectorAPIKeysEnabled((FeatureEnabled) args[2]) + .setSyncRulesFeatures((SyncRulesFeatures) args[3]) .build() ); static { PARSER.declareObject(optionalConstructorArg(), (p, c) -> FeatureEnabled.fromXContent(p), DOCUMENT_LEVEL_SECURITY_ENABLED_FIELD); - PARSER.declareBoolean(optionalConstructorArg(), FILTERING_ADVANCED_CONFIG_ENABLED_FIELD); - PARSER.declareBoolean(optionalConstructorArg(), FILTERING_RULES_ENABLED_FIELD); PARSER.declareObject(optionalConstructorArg(), (p, c) -> FeatureEnabled.fromXContent(p), INCREMENTAL_SYNC_ENABLED_FIELD); PARSER.declareObject(optionalConstructorArg(), (p, c) -> FeatureEnabled.fromXContent(p), NATIVE_CONNECTOR_API_KEYS_ENABLED_FIELD); PARSER.declareObject(optionalConstructorArg(), (p, c) -> SyncRulesFeatures.fromXContent(p), SYNC_RULES_FIELD); @@ -127,12 +109,6 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws if (documentLevelSecurityEnabled != null) { builder.field(DOCUMENT_LEVEL_SECURITY_ENABLED_FIELD.getPreferredName(), documentLevelSecurityEnabled); } - if (filteringAdvancedConfigEnabled != null) { - builder.field(FILTERING_ADVANCED_CONFIG_ENABLED_FIELD.getPreferredName(), filteringAdvancedConfigEnabled); - } - if (filteringRulesEnabled != null) { - builder.field(FILTERING_RULES_ENABLED_FIELD.getPreferredName(), filteringRulesEnabled); - } if (incrementalSyncEnabled != null) { builder.field(INCREMENTAL_SYNC_ENABLED_FIELD.getPreferredName(), incrementalSyncEnabled); } @@ -150,8 +126,6 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws @Override public void writeTo(StreamOutput out) throws IOException { out.writeOptionalWriteable(documentLevelSecurityEnabled); - out.writeOptionalBoolean(filteringAdvancedConfigEnabled); - out.writeOptionalBoolean(filteringRulesEnabled); out.writeOptionalWriteable(incrementalSyncEnabled); out.writeOptionalWriteable(nativeConnectorAPIKeysEnabled); out.writeOptionalWriteable(syncRulesFeatures); @@ -163,8 +137,6 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; ConnectorFeatures features = (ConnectorFeatures) o; return Objects.equals(documentLevelSecurityEnabled, features.documentLevelSecurityEnabled) - && Objects.equals(filteringAdvancedConfigEnabled, features.filteringAdvancedConfigEnabled) - && Objects.equals(filteringRulesEnabled, features.filteringRulesEnabled) && Objects.equals(incrementalSyncEnabled, features.incrementalSyncEnabled) && Objects.equals(nativeConnectorAPIKeysEnabled, features.nativeConnectorAPIKeysEnabled) && Objects.equals(syncRulesFeatures, features.syncRulesFeatures); @@ -172,21 +144,12 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash( - documentLevelSecurityEnabled, - filteringAdvancedConfigEnabled, - filteringRulesEnabled, - incrementalSyncEnabled, - nativeConnectorAPIKeysEnabled, - syncRulesFeatures - ); + return Objects.hash(documentLevelSecurityEnabled, incrementalSyncEnabled, nativeConnectorAPIKeysEnabled, syncRulesFeatures); } public static class Builder { private FeatureEnabled documentLevelSecurityEnabled; - private Boolean filteringAdvancedConfig; - private Boolean filteringRules; private FeatureEnabled incrementalSyncEnabled; private FeatureEnabled nativeConnectorAPIKeysEnabled; private SyncRulesFeatures syncRulesFeatures; @@ -196,16 +159,6 @@ public Builder setDocumentLevelSecurityEnabled(FeatureEnabled documentLevelSecur return this; } - public Builder setFilteringAdvancedConfig(Boolean filteringAdvancedConfig) { - this.filteringAdvancedConfig = filteringAdvancedConfig; - return this; - } - - public Builder setFilteringRules(Boolean filteringRules) { - this.filteringRules = filteringRules; - return this; - } - public Builder setIncrementalSyncEnabled(FeatureEnabled incrementalSyncEnabled) { this.incrementalSyncEnabled = incrementalSyncEnabled; return this; @@ -224,8 +177,6 @@ public Builder setSyncRulesFeatures(SyncRulesFeatures syncRulesFeatures) { public ConnectorFeatures build() { return new ConnectorFeatures( documentLevelSecurityEnabled, - filteringAdvancedConfig, - filteringRules, incrementalSyncEnabled, nativeConnectorAPIKeysEnabled, syncRulesFeatures diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorFeaturesTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorFeaturesTests.java index 941d0a9ed4594..57f51a1054393 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorFeaturesTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorFeaturesTests.java @@ -52,7 +52,6 @@ public void testToXContent() throws IOException { "document_level_security": { "enabled": true }, - "filtering_advanced_config": true, "sync_rules": { "advanced": { "enabled": false @@ -70,7 +69,6 @@ public void testToXContent() throws IOException { public void testToXContentMissingDocumentLevelSecurity() throws IOException { String content = XContentHelper.stripWhitespace(""" { - "filtering_advanced_config": true, "sync_rules": { "advanced": { "enabled": false @@ -88,7 +86,9 @@ public void testToXContentMissingDocumentLevelSecurity() throws IOException { public void testToXContentMissingSyncRules() throws IOException { String content = XContentHelper.stripWhitespace(""" { - "filtering_advanced_config": true + "document_level_security": { + "enabled": true + } } """); @@ -98,7 +98,6 @@ public void testToXContentMissingSyncRules() throws IOException { public void testToXContentMissingSyncRulesAdvanced() throws IOException { String content = XContentHelper.stripWhitespace(""" { - "filtering_advanced_config": true, "sync_rules": { "basic": { "enabled": true @@ -116,7 +115,6 @@ public void testToXContent_NativeConnectorAPIKeysEnabled() throws IOException { "document_level_security": { "enabled": true }, - "filtering_advanced_config": true, "sync_rules": { "advanced": { "enabled": false diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTestUtils.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTestUtils.java index b6d45fff1e520..230de44a8f6c5 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTestUtils.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTestUtils.java @@ -156,8 +156,6 @@ public static ConnectorSyncInfo getRandomConnectorSyncInfo() { public static ConnectorFeatures getRandomConnectorFeatures() { return new ConnectorFeatures.Builder().setDocumentLevelSecurityEnabled(randomBoolean() ? randomConnectorFeatureEnabled() : null) - .setFilteringRules(randomFrom(new Boolean[] { null, randomBoolean() })) - .setFilteringAdvancedConfig(randomFrom(new Boolean[] { null, randomBoolean() })) .setIncrementalSyncEnabled(randomBoolean() ? randomConnectorFeatureEnabled() : null) .setNativeConnectorAPIKeysEnabled(randomBoolean() ? randomConnectorFeatureEnabled() : null) .setSyncRulesFeatures(randomBoolean() ? randomSyncRulesFeatures() : null) diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTests.java index 53efc2d0363c6..734c6eaf86965 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTests.java @@ -131,7 +131,6 @@ public void testToXContent() throws IOException { "document_level_security":{ "enabled":true }, - "filtering_advanced_config":true, "sync_rules":{ "advanced":{ "enabled":false From 968f07353f2ee4d2457a941dc67de0e151e37dee Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 28 May 2024 14:12:28 +0100 Subject: [PATCH 005/208] =?UTF-8?q?AwaitsFix=20for=C2=A0#109103?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/elasticsearch/cluster/coordination/NodeJoinTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/test/java/org/elasticsearch/cluster/coordination/NodeJoinTests.java b/server/src/test/java/org/elasticsearch/cluster/coordination/NodeJoinTests.java index b8dfdd8e91231..1b4ef86a85f7a 100644 --- a/server/src/test/java/org/elasticsearch/cluster/coordination/NodeJoinTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/coordination/NodeJoinTests.java @@ -678,6 +678,7 @@ public void testBecomeFollowerFailsPendingJoin() throws Exception { assertFalse(isLocalNodeElectedMaster()); } + @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/109103") public void testConcurrentJoining() { List masterNodes = IntStream.rangeClosed(1, randomIntBetween(2, 5)) .mapToObj(nodeId -> newNode(nodeId, true)) From 6d864154cab1798fb300ebdaf0b949df1d2581e5 Mon Sep 17 00:00:00 2001 From: Tim Grein Date: Tue, 28 May 2024 15:21:33 +0200 Subject: [PATCH 006/208] [Inference API] Add Google AI Studio completion docs (#109089) --- .../inference/delete-inference.asciidoc | 2 +- .../inference/get-inference.asciidoc | 2 +- .../inference/inference-apis.asciidoc | 2 +- .../inference/post-inference.asciidoc | 2 +- .../inference/put-inference.asciidoc | 52 ++++++++++++++++++- 5 files changed, 54 insertions(+), 6 deletions(-) diff --git a/docs/reference/inference/delete-inference.asciidoc b/docs/reference/inference/delete-inference.asciidoc index 4c7fb06d19ea6..89f76e6cef841 100644 --- a/docs/reference/inference/delete-inference.asciidoc +++ b/docs/reference/inference/delete-inference.asciidoc @@ -7,7 +7,7 @@ experimental[] Deletes an {infer} endpoint. IMPORTANT: The {infer} APIs enable you to use certain services, such as built-in -{ml} models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure or +{ml} models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure, Google AI Studio or Hugging Face. For built-in models and models uploaded though Eland, the {infer} APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the {infer} APIs to use these models or if you want to use diff --git a/docs/reference/inference/get-inference.asciidoc b/docs/reference/inference/get-inference.asciidoc index 71714c6254e64..339146adfece9 100644 --- a/docs/reference/inference/get-inference.asciidoc +++ b/docs/reference/inference/get-inference.asciidoc @@ -7,7 +7,7 @@ experimental[] Retrieves {infer} endpoint information. IMPORTANT: The {infer} APIs enable you to use certain services, such as built-in -{ml} models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure or +{ml} models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure, Google AI Studio or Hugging Face. For built-in models and models uploaded though Eland, the {infer} APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the {infer} APIs to use these models or if you want to use diff --git a/docs/reference/inference/inference-apis.asciidoc b/docs/reference/inference/inference-apis.asciidoc index bd9f6308bfce6..539bba3f0d61f 100644 --- a/docs/reference/inference/inference-apis.asciidoc +++ b/docs/reference/inference/inference-apis.asciidoc @@ -5,7 +5,7 @@ experimental[] IMPORTANT: The {infer} APIs enable you to use certain services, such as built-in -{ml} models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure or +{ml} models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure, Google AI Studio or Hugging Face. For built-in models and models uploaded though Eland, the {infer} APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the {infer} APIs to use these models or if you want to use diff --git a/docs/reference/inference/post-inference.asciidoc b/docs/reference/inference/post-inference.asciidoc index b262eed3501bb..2b9e990140658 100644 --- a/docs/reference/inference/post-inference.asciidoc +++ b/docs/reference/inference/post-inference.asciidoc @@ -7,7 +7,7 @@ experimental[] Performs an inference task on an input text by using an {infer} endpoint. IMPORTANT: The {infer} APIs enable you to use certain services, such as built-in -{ml} models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure or +{ml} models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure, Google AI Studio or Hugging Face. For built-in models and models uploaded though Eland, the {infer} APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the {infer} APIs to use these models or if you want to use diff --git a/docs/reference/inference/put-inference.asciidoc b/docs/reference/inference/put-inference.asciidoc index bb91e55ba99b9..cac03afd29562 100644 --- a/docs/reference/inference/put-inference.asciidoc +++ b/docs/reference/inference/put-inference.asciidoc @@ -8,7 +8,7 @@ Creates an {infer} endpoint to perform an {infer} task. IMPORTANT: The {infer} APIs enable you to use certain services, such as built-in {ml} models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure -OpenAI or Hugging Face. For built-in models and models uploaded though +OpenAI, Google AI Studio or Hugging Face. For built-in models and models uploaded though Eland, the {infer} APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the {infer} APIs to use these models or if you want to use non-NLP models, use the <>. @@ -45,6 +45,7 @@ The following services are available through the {infer} API: * Azure OpenAI * Azure AI Studio * Elasticsearch (for built-in models and models uploaded through Eland) +* Google AI Studio [discrete] @@ -84,6 +85,7 @@ OpenAI service. * `azureaistudio`: specify the `completion` or `text_embedding` task type to use the Azure AI Studio service. * `elasticsearch`: specify the `text_embedding` task type to use the E5 built-in model or text embedding models uploaded by Eland. +* `googleaistudio`: specify the `completion` task to use the Google AI Studio service. `service_settings`:: (Required, object) @@ -282,6 +284,33 @@ To modify this, set the `requests_per_minute` setting of this object in your ser ``` ===== + +.`service_settings` for the `googleiastudio` service +[%collapsible%closed] +===== +`api_key`::: +(Required, string) +A valid API key for the Google Gemini API. + +`model_id`::: +(Required, string) +The name of the model to use for the {infer} task. +You can find the supported models at https://ai.google.dev/gemini-api/docs/models/gemini[Gemini API models]. + +`rate_limit`::: +(Optional, object) +By default, the `googleaistudio` service sets the number of requests allowed per minute to `360`. +This helps to minimize the number of rate limit errors returned from Google AI Studio. +To modify this, set the `requests_per_minute` setting of this object in your service settings: ++ +-- +``` +"rate_limit": { + "requests_per_minute": <> +} +``` +-- +===== ++ .`service_settings` for the `elasticsearch` service [%collapsible%closed] ===== @@ -304,7 +333,6 @@ exceed the number of available processors per node divided by the number of allocations. Must be a power of 2. Max allowed value is 32. ===== - `task_settings`:: (Optional, object) Settings to configure the {infer} task. These settings are specific to the @@ -701,3 +729,23 @@ PUT _inference/completion/azure_ai_studio_completion // TEST[skip:TBD] The list of chat completion models that you can choose from in your deployment can be found in the https://ai.azure.com/explore/models?selectedTask=chat-completion[Azure AI Studio model explorer]. + +[discrete] +[[inference-example-googleaistudio]] +===== Google AI Studio service + +The following example shows how to create an {infer} endpoint called +`google_ai_studio_completion` to perform a `completion` task type. + +[source,console] +------------------------------------------------------------ +PUT _inference/completion/google_ai_studio_completion +{ + "service": "googleaistudio", + "service_settings": { + "api_key": ">", + "model_id": "" + } +} +------------------------------------------------------------ +// TEST[skip:TBD] From a80b7f62dbc99b3b6a5dc2b8d937ebd9fffbcdcd Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 28 May 2024 15:13:25 +0100 Subject: [PATCH 007/208] Fix trappy timeouts in `AcknowledgedRequest.Plain` (#109102) Relates #107984 --- .../api/_internal.delete_desired_nodes.json | 10 +++++++++ .../TransportDesiredNodesActionsIT.java | 10 +++++++-- .../support/master/AcknowledgedRequest.java | 4 ++-- .../cluster/RestDeleteDesiredNodesAction.java | 4 ++-- .../license/DeleteLicenseRequestBuilder.java | 22 ------------------- .../license/LicensingClient.java | 4 ---- .../license/RestDeleteLicenseAction.java | 5 +---- ...lusterStateLicenseServiceClusterTests.java | 8 ++++++- .../license/LicensesTransportTests.java | 7 ++++-- .../IndexLifecycleInitialisationTests.java | 10 +++++++-- .../xpack/ilm/action/RestGetStatusAction.java | 4 +--- .../ilm/LifecycleOperationSnapshotTests.java | 8 +++++-- .../lucene/bwc/ArchiveLicenseIntegTests.java | 10 +++++++-- .../SearchableSnapshotsLicenseIntegTests.java | 5 ++++- .../slm/action/RestGetSLMStatusAction.java | 4 +--- .../RestGetSnapshotLifecycleStatsAction.java | 5 +---- 16 files changed, 64 insertions(+), 56 deletions(-) delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/license/DeleteLicenseRequestBuilder.java diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/_internal.delete_desired_nodes.json b/rest-api-spec/src/main/resources/rest-api-spec/api/_internal.delete_desired_nodes.json index ff53ad1d9f4cd..8b4759719a41b 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/api/_internal.delete_desired_nodes.json +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/_internal.delete_desired_nodes.json @@ -18,6 +18,16 @@ ] } ] + }, + "params":{ + "master_timeout": { + "type": "time", + "description": "Timeout for connection to master node" + }, + "timeout": { + "type": "time", + "description": "Timeout for acknowledgements from all nodes" + } } } } diff --git a/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/desirednodes/TransportDesiredNodesActionsIT.java b/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/desirednodes/TransportDesiredNodesActionsIT.java index 38fe1f8f918f8..63801f8c1e511 100644 --- a/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/desirednodes/TransportDesiredNodesActionsIT.java +++ b/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/desirednodes/TransportDesiredNodesActionsIT.java @@ -249,7 +249,12 @@ public void testDeleteDesiredNodesTasksAreBatchedCorrectly() throws Exception { final List> deleteDesiredNodesFutures = new ArrayList<>(15); for (int i = 0; i < 15; i++) { - deleteDesiredNodesFutures.add(client().execute(TransportDeleteDesiredNodesAction.TYPE, new AcknowledgedRequest.Plain())); + deleteDesiredNodesFutures.add( + client().execute( + TransportDeleteDesiredNodesAction.TYPE, + new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ) + ); } for (ActionFuture future : deleteDesiredNodesFutures) { @@ -321,7 +326,8 @@ private UpdateDesiredNodesRequest randomDryRunUpdateDesiredNodesRequest(Settings } private void deleteDesiredNodes() { - client().execute(TransportDeleteDesiredNodesAction.TYPE, new AcknowledgedRequest.Plain()).actionGet(); + client().execute(TransportDeleteDesiredNodesAction.TYPE, new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)) + .actionGet(); } private DesiredNodes getLatestDesiredNodes() { diff --git a/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedRequest.java b/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedRequest.java index b6389d0b112b6..a55467fbfadf8 100644 --- a/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedRequest.java +++ b/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedRequest.java @@ -98,8 +98,8 @@ public Plain(StreamInput in) throws IOException { super(in); } - public Plain() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Plain(TimeValue masterNodeTimeout, TimeValue ackTimeout) { + super(masterNodeTimeout, ackTimeout); } } } diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestDeleteDesiredNodesAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestDeleteDesiredNodesAction.java index 18045828f4401..ed20f63ec406e 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestDeleteDesiredNodesAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestDeleteDesiredNodesAction.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.util.List; +import static org.elasticsearch.rest.RestUtils.getAckTimeout; import static org.elasticsearch.rest.RestUtils.getMasterNodeTimeout; public class RestDeleteDesiredNodesAction extends BaseRestHandler { @@ -33,8 +34,7 @@ public List routes() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - final AcknowledgedRequest.Plain deleteDesiredNodesRequest = new AcknowledgedRequest.Plain(); - deleteDesiredNodesRequest.masterNodeTimeout(getMasterNodeTimeout(request)); + final var deleteDesiredNodesRequest = new AcknowledgedRequest.Plain(getMasterNodeTimeout(request), getAckTimeout(request)); return restChannel -> client.execute( TransportDeleteDesiredNodesAction.TYPE, deleteDesiredNodesRequest, diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/DeleteLicenseRequestBuilder.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/DeleteLicenseRequestBuilder.java deleted file mode 100644 index 3b581ec123a71..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/DeleteLicenseRequestBuilder.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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.license; - -import org.elasticsearch.action.support.master.AcknowledgedRequest; -import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder; -import org.elasticsearch.action.support.master.AcknowledgedResponse; -import org.elasticsearch.client.internal.ElasticsearchClient; - -public class DeleteLicenseRequestBuilder extends AcknowledgedRequestBuilder< - AcknowledgedRequest.Plain, - AcknowledgedResponse, - DeleteLicenseRequestBuilder> { - - public DeleteLicenseRequestBuilder(ElasticsearchClient client) { - super(client, TransportDeleteLicenseAction.TYPE, new AcknowledgedRequest.Plain()); - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicensingClient.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicensingClient.java index a97643a54308b..5396d45126bb5 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicensingClient.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicensingClient.java @@ -24,10 +24,6 @@ public GetLicenseRequestBuilder prepareGetLicense() { return new GetLicenseRequestBuilder(client); } - public DeleteLicenseRequestBuilder prepareDeleteLicense() { - return new DeleteLicenseRequestBuilder(client); - } - public PostStartTrialRequestBuilder preparePostStartTrial() { return new PostStartTrialRequestBuilder(client); } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestDeleteLicenseAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestDeleteLicenseAction.java index 814911407377a..24c081c237ee0 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestDeleteLicenseAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestDeleteLicenseAction.java @@ -37,10 +37,7 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { - AcknowledgedRequest.Plain deleteLicenseRequest = new AcknowledgedRequest.Plain(); - deleteLicenseRequest.ackTimeout(getAckTimeout(request)); - deleteLicenseRequest.masterNodeTimeout(getMasterNodeTimeout(request)); - + final var deleteLicenseRequest = new AcknowledgedRequest.Plain(getMasterNodeTimeout(request), getAckTimeout(request)); return channel -> client.admin() .cluster() .execute(TransportDeleteLicenseAction.TYPE, deleteLicenseRequest, new RestToXContentListener<>(channel)); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/ClusterStateLicenseServiceClusterTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/ClusterStateLicenseServiceClusterTests.java index 5890434f88e6f..338c1ebfb4e21 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/ClusterStateLicenseServiceClusterTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/ClusterStateLicenseServiceClusterTests.java @@ -6,6 +6,7 @@ */ package org.elasticsearch.license; +import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.cluster.node.DiscoveryNodeRole; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.TimeValue; @@ -15,6 +16,7 @@ import static org.elasticsearch.test.ESIntegTestCase.Scope.TEST; import static org.elasticsearch.test.NodeRoles.addRoles; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.hamcrest.CoreMatchers.equalTo; @ClusterScope(scope = TEST, numDataNodes = 0, numClientNodes = 0, maxNumDataNodes = 0) @@ -51,7 +53,11 @@ public void testClusterRestartWithLicense() throws Exception { logger.info("--> get and check signed license"); assertThat(licensingClient.prepareGetLicense().get().license(), equalTo(license)); logger.info("--> remove licenses"); - licensingClient.prepareDeleteLicense().get(); + + assertAcked( + client().execute(TransportDeleteLicenseAction.TYPE, new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)) + .get() + ); assertOperationMode(License.OperationMode.BASIC); logger.info("--> restart all nodes"); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesTransportTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesTransportTests.java index f2293ac6bd9a1..7e9152c0cf18e 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesTransportTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesTransportTests.java @@ -7,6 +7,7 @@ package org.elasticsearch.license; import org.elasticsearch.action.ActionFuture; +import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.settings.Settings; @@ -181,8 +182,10 @@ public void testRemoveLicensesSimple() throws Exception { GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(clusterAdmin(), GetLicenseAction.INSTANCE).get(); assertThat(getLicenseResponse.license(), equalTo(goldLicense)); // delete all licenses - DeleteLicenseRequestBuilder deleteLicenseRequestBuilder = new DeleteLicenseRequestBuilder(clusterAdmin()); - AcknowledgedResponse deleteLicenseResponse = deleteLicenseRequestBuilder.get(); + AcknowledgedResponse deleteLicenseResponse = clusterAdmin().execute( + TransportDeleteLicenseAction.TYPE, + new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get(); assertThat(deleteLicenseResponse.isAcknowledged(), equalTo(true)); // get licenses (expected no licenses) getLicenseResponse = new GetLicenseRequestBuilder(clusterAdmin(), GetLicenseAction.INSTANCE).get(); diff --git a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/IndexLifecycleInitialisationTests.java b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/IndexLifecycleInitialisationTests.java index 404d9a05396e9..209330a3be2de 100644 --- a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/IndexLifecycleInitialisationTests.java +++ b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/IndexLifecycleInitialisationTests.java @@ -432,7 +432,10 @@ public void testCreatePolicyWhenStopped() throws Exception { assertAcked(client().execute(ILMActions.STOP, new StopILMRequest()).get()); assertBusy(() -> { - OperationMode mode = client().execute(GetStatusAction.INSTANCE, new AcknowledgedRequest.Plain()).get().getMode(); + OperationMode mode = client().execute( + GetStatusAction.INSTANCE, + new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get().getMode(); logger.info("--> waiting for STOPPED, currently: {}", mode); assertThat(mode, equalTo(OperationMode.STOPPED)); }); @@ -456,7 +459,10 @@ public void testCreatePolicyWhenStopped() throws Exception { is(both(greaterThanOrEqualTo(lowerBoundModifiedDate)).and(lessThanOrEqualTo(upperBoundModifiedDate))) ); // assert ILM is still stopped - GetStatusAction.Response statusResponse = client().execute(GetStatusAction.INSTANCE, new AcknowledgedRequest.Plain()).get(); + GetStatusAction.Response statusResponse = client().execute( + GetStatusAction.INSTANCE, + new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get(); assertThat(statusResponse.getMode(), equalTo(OperationMode.STOPPED)); } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestGetStatusAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestGetStatusAction.java index 5668b3241e6a2..3940b0a5e8ef8 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestGetStatusAction.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestGetStatusAction.java @@ -34,9 +34,7 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { - AcknowledgedRequest.Plain request = new AcknowledgedRequest.Plain(); - request.ackTimeout(getAckTimeout(restRequest)); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + final var request = new AcknowledgedRequest.Plain(getMasterNodeTimeout(restRequest), getAckTimeout(restRequest)); return channel -> client.execute(GetStatusAction.INSTANCE, request, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/LifecycleOperationSnapshotTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/LifecycleOperationSnapshotTests.java index fe0c905b35dad..22eef3d8940a3 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/LifecycleOperationSnapshotTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/LifecycleOperationSnapshotTests.java @@ -125,10 +125,14 @@ public void testModeSnapshotRestore() throws Exception { } private OperationMode ilmMode() throws Exception { - return client().execute(GetStatusAction.INSTANCE, new AcknowledgedRequest.Plain()).get().getMode(); + return client().execute(GetStatusAction.INSTANCE, new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)) + .get() + .getMode(); } private OperationMode slmMode() throws Exception { - return client().execute(GetSLMStatusAction.INSTANCE, new AcknowledgedRequest.Plain()).get().getOperationMode(); + return client().execute(GetSLMStatusAction.INSTANCE, new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)) + .get() + .getOperationMode(); } } diff --git a/x-pack/plugin/old-lucene-versions/src/internalClusterTest/java/org/elasticsearch/xpack/lucene/bwc/ArchiveLicenseIntegTests.java b/x-pack/plugin/old-lucene-versions/src/internalClusterTest/java/org/elasticsearch/xpack/lucene/bwc/ArchiveLicenseIntegTests.java index c7f00063161e1..0489390a21352 100644 --- a/x-pack/plugin/old-lucene-versions/src/internalClusterTest/java/org/elasticsearch/xpack/lucene/bwc/ArchiveLicenseIntegTests.java +++ b/x-pack/plugin/old-lucene-versions/src/internalClusterTest/java/org/elasticsearch/xpack/lucene/bwc/ArchiveLicenseIntegTests.java @@ -57,7 +57,10 @@ public void testFeatureUsage() throws Exception { } public void testFailRestoreOnInvalidLicense() throws Exception { - assertAcked(client().execute(TransportDeleteLicenseAction.TYPE, new AcknowledgedRequest.Plain()).get()); + assertAcked( + client().execute(TransportDeleteLicenseAction.TYPE, new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)) + .get() + ); assertAcked(client().execute(PostStartBasicAction.INSTANCE, new PostStartBasicRequest()).get()); ensureClusterSizeConsistency(); @@ -93,7 +96,10 @@ public void testShardAllocationOnInvalidLicense() throws Exception { assertThat(restoreSnapshotResponse.getRestoreInfo().failedShards(), equalTo(0)); ensureGreen(indexName); - assertAcked(client().execute(TransportDeleteLicenseAction.TYPE, new AcknowledgedRequest.Plain()).get()); + assertAcked( + client().execute(TransportDeleteLicenseAction.TYPE, new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)) + .get() + ); assertAcked(client().execute(PostStartBasicAction.INSTANCE, new PostStartBasicRequest()).get()); ensureClusterSizeConsistency(); diff --git a/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsLicenseIntegTests.java b/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsLicenseIntegTests.java index d5fcf0853cdae..3a218e4ca5e97 100644 --- a/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsLicenseIntegTests.java +++ b/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsLicenseIntegTests.java @@ -78,7 +78,10 @@ public void createAndMountSearchableSnapshot() throws Exception { assertThat(restoreSnapshotResponse.getRestoreInfo().failedShards(), equalTo(0)); ensureGreen(indexName); - assertAcked(client().execute(TransportDeleteLicenseAction.TYPE, new AcknowledgedRequest.Plain()).get()); + assertAcked( + client().execute(TransportDeleteLicenseAction.TYPE, new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)) + .get() + ); assertAcked(client().execute(PostStartBasicAction.INSTANCE, new PostStartBasicRequest()).get()); ensureClusterSizeConsistency(); diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestGetSLMStatusAction.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestGetSLMStatusAction.java index 51b8b5d934b86..7065af27a6f3a 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestGetSLMStatusAction.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestGetSLMStatusAction.java @@ -37,9 +37,7 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { - AcknowledgedRequest.Plain request = new AcknowledgedRequest.Plain(); - request.ackTimeout(getAckTimeout(restRequest)); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + final var request = new AcknowledgedRequest.Plain(getMasterNodeTimeout(restRequest), getAckTimeout(restRequest)); return channel -> client.execute(GetSLMStatusAction.INSTANCE, request, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestGetSnapshotLifecycleStatsAction.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestGetSnapshotLifecycleStatsAction.java index c403c50715e73..a1a3f8fc7bc6b 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestGetSnapshotLifecycleStatsAction.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestGetSnapshotLifecycleStatsAction.java @@ -37,10 +37,7 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - AcknowledgedRequest.Plain req = new AcknowledgedRequest.Plain(); - req.ackTimeout(getAckTimeout(request)); - req.masterNodeTimeout(getMasterNodeTimeout(request)); - + final var req = new AcknowledgedRequest.Plain(getMasterNodeTimeout(request), getAckTimeout(request)); return channel -> client.execute(GetSnapshotLifecycleStatsAction.INSTANCE, req, new RestToXContentListener<>(channel)); } } From 92dc76ee22637747ec8577a89f57f11bc302b9ec Mon Sep 17 00:00:00 2001 From: eyalkoren <41850454+eyalkoren@users.noreply.github.com> Date: Tue, 28 May 2024 17:24:09 +0300 Subject: [PATCH 008/208] Raw mapping merge fix for properties field (#108867) --- docs/changelog/108867.yaml | 6 ++ .../common/xcontent/XContentHelper.java | 2 +- .../index/mapper/MapperService.java | 7 +- .../index/mapper/MapperServiceTests.java | 99 ++++++++++++++++++- 4 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 docs/changelog/108867.yaml diff --git a/docs/changelog/108867.yaml b/docs/changelog/108867.yaml new file mode 100644 index 0000000000000..545349dd84aeb --- /dev/null +++ b/docs/changelog/108867.yaml @@ -0,0 +1,6 @@ +pr: 108867 +summary: Fix for raw mapping merge of fields named "properties" +area: Mapping +type: bug +issues: + - 108866 diff --git a/server/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java b/server/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java index 2227c54871352..28df2fad32cbb 100644 --- a/server/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java +++ b/server/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java @@ -415,7 +415,7 @@ public static void mergeDefaults(Map content, Map {})); + mapperService.merge("_doc", List.of(mapping1, mapping2), MergeReason.INDEX_TEMPLATE); + assertEquals(""" + { + "_doc" : { + "properties" : { + "properties" : { + "properties" : { + "child1" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword" + } + } + }, + "child2" : { + "type" : "integer" + }, + "child3" : { + "properties" : { + "grandchild" : { + "type" : "long" + } + } + } + } + } + } + } + }""", Strings.toString(mapperService.documentMapper().mapping(), true, true)); + + Mapper propertiesMapper = mapperService.documentMapper().mapping().getRoot().getMapper("properties"); + assertThat(propertiesMapper, instanceOf(ObjectMapper.class)); + Mapper childMapper = ((ObjectMapper) propertiesMapper).getMapper("child1"); + assertThat(childMapper, instanceOf(FieldMapper.class)); + assertEquals("text", childMapper.typeName()); + assertEquals(2, childMapper.getTotalFieldsCount()); + childMapper = ((ObjectMapper) propertiesMapper).getMapper("child2"); + assertThat(childMapper, instanceOf(FieldMapper.class)); + assertEquals("integer", childMapper.typeName()); + assertEquals(1, childMapper.getTotalFieldsCount()); + childMapper = ((ObjectMapper) propertiesMapper).getMapper("child3"); + assertThat(childMapper, instanceOf(ObjectMapper.class)); + Mapper grandchildMapper = ((ObjectMapper) childMapper).getMapper("grandchild"); + assertEquals("long", grandchildMapper.typeName()); + } + public void testMergeUntilLimit() throws IOException { CompressedXContent mapping1 = new CompressedXContent(""" { From 0b7114f61cc1d93652de5f11c32062f7efba8d47 Mon Sep 17 00:00:00 2001 From: Henning Andersen <33268011+henningandersen@users.noreply.github.com> Date: Tue, 28 May 2024 17:22:39 +0200 Subject: [PATCH 009/208] NodeJoinTests fix for future complete assertion (#109107) NodeJoinTests.testConcurrentJoining use their own threads, but the thread name parsing done for validating that wait and complete of future is on different executors would pick up more or less random fields. Now disregard these test threads for that assertion. Closes #109103 --- .../elasticsearch/common/util/concurrent/EsExecutors.java | 5 ++++- .../elasticsearch/cluster/coordination/NodeJoinTests.java | 5 ++--- .../common/util/concurrent/EsExecutorsTests.java | 4 ++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/common/util/concurrent/EsExecutors.java b/server/src/main/java/org/elasticsearch/common/util/concurrent/EsExecutors.java index 9bf381e6f4719..04a71b2421ddc 100644 --- a/server/src/main/java/org/elasticsearch/common/util/concurrent/EsExecutors.java +++ b/server/src/main/java/org/elasticsearch/common/util/concurrent/EsExecutors.java @@ -270,7 +270,10 @@ public static String executorName(String threadName) { // subtract 2 to avoid the `]` of the thread number part. int executorNameEnd = threadName.lastIndexOf(']', threadName.length() - 2); int executorNameStart = threadName.lastIndexOf('[', executorNameEnd); - if (executorNameStart == -1 || executorNameEnd - executorNameStart <= 1) { + if (executorNameStart == -1 + || executorNameEnd - executorNameStart <= 1 + || threadName.startsWith("TEST-") + || threadName.startsWith("LuceneTestCase")) { return null; } return threadName.substring(executorNameStart + 1, executorNameEnd); diff --git a/server/src/test/java/org/elasticsearch/cluster/coordination/NodeJoinTests.java b/server/src/test/java/org/elasticsearch/cluster/coordination/NodeJoinTests.java index 1b4ef86a85f7a..8a0f06d38fc43 100644 --- a/server/src/test/java/org/elasticsearch/cluster/coordination/NodeJoinTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/coordination/NodeJoinTests.java @@ -678,7 +678,6 @@ public void testBecomeFollowerFailsPendingJoin() throws Exception { assertFalse(isLocalNodeElectedMaster()); } - @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/109103") public void testConcurrentJoining() { List masterNodes = IntStream.rangeClosed(1, randomIntBetween(2, 5)) .mapToObj(nodeId -> newNode(nodeId, true)) @@ -775,14 +774,14 @@ public void testConcurrentJoining() { final List joinThreads = Stream.concat(correctJoinRequests.stream().map(joinRequest -> new Thread(() -> { safeAwait(barrier); joinNode(joinRequest); - }, "process " + joinRequest)), possiblyFailingJoinRequests.stream().map(joinRequest -> new Thread(() -> { + }, "TEST-process " + joinRequest)), possiblyFailingJoinRequests.stream().map(joinRequest -> new Thread(() -> { safeAwait(barrier); try { joinNode(joinRequest); } catch (CoordinationStateRejectedException e) { // ignore - these requests are expected to fail } - }, "process " + joinRequest))).toList(); + }, "TEST-process " + joinRequest))).toList(); assertionThread.start(); joinThreads.forEach(Thread::start); diff --git a/server/src/test/java/org/elasticsearch/common/util/concurrent/EsExecutorsTests.java b/server/src/test/java/org/elasticsearch/common/util/concurrent/EsExecutorsTests.java index df7b02c2309a3..e267b6c3b737d 100644 --- a/server/src/test/java/org/elasticsearch/common/util/concurrent/EsExecutorsTests.java +++ b/server/src/test/java/org/elasticsearch/common/util/concurrent/EsExecutorsTests.java @@ -37,6 +37,7 @@ import static org.hamcrest.Matchers.hasToString; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.lessThan; +import static org.hamcrest.Matchers.nullValue; /** * Tests for EsExecutors and its components like EsAbortPolicy. @@ -646,6 +647,9 @@ public void testParseExecutorName() throws InterruptedException { final var thread = threadFactory.newThread(() -> {}); try { assertThat(EsExecutors.executorName(thread.getName()), equalTo(executorName)); + assertThat(EsExecutors.executorName(thread), equalTo(executorName)); + assertThat(EsExecutors.executorName("TEST-" + thread.getName()), is(nullValue())); + assertThat(EsExecutors.executorName("LuceneTestCase" + thread.getName()), is(nullValue())); } finally { thread.join(); } From efd450ee19d18e26d4059671c6fbc8de356bf6a7 Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 28 May 2024 16:43:54 +0100 Subject: [PATCH 010/208] Clarify that red/yellow health must be addressed (#109090) We don't expect a cluster to run with `yellow` health for an extended period of time, but it's not clear from these docs that it's important to bring the cluster back to `green` health ASAP. This commit clarifies these docs. --- .../red-yellow-cluster-status.asciidoc | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/reference/troubleshooting/common-issues/red-yellow-cluster-status.asciidoc b/docs/reference/troubleshooting/common-issues/red-yellow-cluster-status.asciidoc index 4b49e191f4e16..cae4eb99dd54a 100644 --- a/docs/reference/troubleshooting/common-issues/red-yellow-cluster-status.asciidoc +++ b/docs/reference/troubleshooting/common-issues/red-yellow-cluster-status.asciidoc @@ -1,9 +1,24 @@ [[red-yellow-cluster-status]] -=== Red or yellow cluster status - -A red or yellow cluster status indicates one or more shards are missing or -unallocated. These unassigned shards increase your risk of data loss and can -degrade cluster performance. +=== Red or yellow cluster health status + +A red or yellow cluster health status indicates one or more shards are not assigned to +a node. + +* **Red health status**: The cluster has some unassigned primary shards, which +means that some operations such as searches and indexing may fail. +* **Yellow health status**: The cluster has no unassigned primary shards but some +unassigned replica shards. This increases your risk of data loss and can degrade +cluster performance. + +When your cluster has a red or yellow health status, it will continue to process +searches and indexing where possible, but may delay certain management and +cleanup activities until the cluster returns to green health status. For instance, +some <> actions require the index on which they +operate to have a green health status. + +In many cases, your cluster will recover to green health status automatically. +If the cluster doesn't automatically recover, then you must <> +the remaining problems so management and cleanup activities can proceed. [discrete] [[diagnose-cluster-status]] From 398c22c06c08686a7c1619ff7a353f73d036e9e9 Mon Sep 17 00:00:00 2001 From: Max Hniebergall <137079448+maxhniebergall@users.noreply.github.com> Date: Tue, 28 May 2024 11:59:19 -0400 Subject: [PATCH 011/208] Revert "[ML] Refactor the Embedding classes (#107516)" (#109114) * Revert "[ML] Refactor the Embedding classes (#107516)" This reverts commit 843579652c4f1b1842ef44ffbb496995f00b5b71. --- .../core/inference/results/ByteEmbedding.java | 98 ---------- .../ChunkedSparseEmbeddingResults.java | 18 +- .../ChunkedTextEmbeddingByteResults.java | 80 +++++++- .../ChunkedTextEmbeddingFloatResults.java | 76 +++++++- .../results/ChunkedTextEmbeddingResults.java | 2 +- .../core/inference/results/Embedding.java | 72 ------- .../inference/results/EmbeddingChunk.java | 79 -------- .../core/inference/results/EmbeddingInt.java | 12 ++ .../inference/results/EmbeddingResults.java | 39 ---- .../inference/results/FloatEmbedding.java | 98 ---------- .../inference/results/SparseEmbedding.java | 170 ----------------- .../results/SparseEmbeddingResults.java | 68 ++++++- .../core/inference/results/TextEmbedding.java | 2 +- .../results/TextEmbeddingByteResults.java | 104 +++++++++-- .../results/TextEmbeddingResults.java | 101 ++++++++-- .../inference/results/TextEmbeddingUtils.java | 2 +- .../MlInferenceNamedXContentProvider.java | 4 - .../results/TextEmbeddingByteResults.java | 100 ---------- .../TextEmbeddingByteResultsTests.java | 61 ------ .../TestDenseInferenceServiceExtension.java | 5 +- .../TestSparseInferenceServiceExtension.java | 9 +- .../common/EmbeddingRequestChunker.java | 141 ++------------ .../CohereEmbeddingsResponseEntity.java | 13 +- .../HuggingFaceElserResponseEntity.java | 14 +- .../HuggingFaceEmbeddingsResponseEntity.java | 10 +- .../OpenAiEmbeddingsResponseEntity.java | 7 +- .../common/EmbeddingRequestChunkerTests.java | 175 +++--------------- ...AiStudioEmbeddingsResponseEntityTests.java | 3 +- .../CohereEmbeddingsResponseEntityTests.java | 38 +++- ...gingFaceEmbeddingsResponseEntityTests.java | 33 +++- .../OpenAiEmbeddingsResponseEntityTests.java | 23 ++- .../rest/RestInferenceActionTests.java | 5 +- .../ChunkedSparseEmbeddingResultsTests.java | 5 +- .../ChunkedTextEmbeddingByteResultsTests.java | 21 ++- ...ChunkedTextEmbeddingFloatResultsTests.java | 8 +- .../ChunkedTextEmbeddingResultsTests.java | 5 +- .../results/SparseEmbeddingResultsTests.java | 46 ++--- .../TextEmbeddingByteResultsTests.java | 32 ++-- .../results/TextEmbeddingResultsTests.java | 32 ++-- .../inference/services/ServiceUtilsTests.java | 4 +- .../services/cohere/CohereServiceTests.java | 6 +- .../services/openai/OpenAiServiceTests.java | 6 +- 42 files changed, 614 insertions(+), 1213 deletions(-) delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ByteEmbedding.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/Embedding.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingChunk.java create mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingInt.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingResults.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/FloatEmbedding.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/SparseEmbedding.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/inference/results/TextEmbeddingByteResults.java delete mode 100644 x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/inference/results/TextEmbeddingByteResultsTests.java diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ByteEmbedding.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ByteEmbedding.java deleted file mode 100644 index 9fb017b75abb5..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ByteEmbedding.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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.core.inference.results; - -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.xcontent.XContentBuilder; - -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -public class ByteEmbedding extends Embedding { - - public static ByteEmbedding of(List embedding) { - byte[] embeddingBytes = new byte[embedding.size()]; - for (int i = 0; i < embedding.size(); i++) { - embeddingBytes[i] = embedding.get(i); - } - return new ByteEmbedding(embeddingBytes); - } - - /** - * Wrapper so around a primitive byte array so that it can be - * treated as a generic - */ - public static class ByteArrayWrapper implements EmbeddingValues { - - final byte[] bytes; - - public ByteArrayWrapper(byte[] bytes) { - this.bytes = bytes; - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return valuesToXContent(EMBEDDING, builder, params); - } - - @Override - public int size() { - return bytes.length; - } - - @Override - public XContentBuilder valuesToXContent(String fieldName, XContentBuilder builder, Params params) throws IOException { - builder.startArray(fieldName); - for (var value : bytes) { - builder.value(value); - } - builder.endArray(); - return builder; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ByteArrayWrapper that = (ByteArrayWrapper) o; - return Arrays.equals(bytes, that.bytes); - } - - @Override - public int hashCode() { - return Arrays.hashCode(bytes); - } - } - - public ByteEmbedding(StreamInput in) throws IOException { - this(in.readByteArray()); - } - - public ByteEmbedding(byte[] embedding) { - super(new ByteArrayWrapper(embedding)); - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeByteArray(embedding.bytes); - } - - public byte[] bytes() { - return embedding.bytes; - } - - public float[] toFloatArray() { - float[] floatArray = new float[embedding.bytes.length]; - for (int i = 0; i < embedding.bytes.length; i++) { - floatArray[i] = ((Byte) embedding.bytes[i]).floatValue(); - } - return floatArray; - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedSparseEmbeddingResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedSparseEmbeddingResults.java index 5b57a8da9d37c..c91d0dc6fd538 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedSparseEmbeddingResults.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedSparseEmbeddingResults.java @@ -49,7 +49,7 @@ public static List of(List inputs, Spars return results; } - public static ChunkedSparseEmbeddingResults of(String input, SparseEmbedding embedding) { + public static ChunkedSparseEmbeddingResults of(String input, SparseEmbeddingResults.Embedding embedding) { var weightedTokens = embedding.tokens() .stream() .map(weightedToken -> new WeightedToken(weightedToken.token(), weightedToken.weight())) @@ -58,22 +58,6 @@ public static ChunkedSparseEmbeddingResults of(String input, SparseEmbedding emb return new ChunkedSparseEmbeddingResults(List.of(new ChunkedTextExpansionResults.ChunkedResult(input, weightedTokens))); } - public static ChunkedSparseEmbeddingResults of(List> embeddingChunks) { - var ch = embeddingChunks.stream() - .map( - chunk -> new ChunkedTextExpansionResults.ChunkedResult( - chunk.matchedText(), - chunk.embedding().embedding.tokens() - .stream() - .map(weightedToken -> new WeightedToken(weightedToken.token(), weightedToken.weight())) - .toList() - ) - ) - .toList(); - - return new ChunkedSparseEmbeddingResults(ch); - } - private final List chunkedResults; public ChunkedSparseEmbeddingResults(List chunks) { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedTextEmbeddingByteResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedTextEmbeddingByteResults.java index b88b502a76195..86ea70ddd62dd 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedTextEmbeddingByteResults.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedTextEmbeddingByteResults.java @@ -7,22 +7,26 @@ package org.elasticsearch.xpack.core.inference.results; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.inference.ChunkedInferenceServiceResults; import org.elasticsearch.inference.InferenceResults; +import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xpack.core.ml.inference.results.ChunkedNlpInferenceResults; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; import static org.elasticsearch.xpack.core.inference.results.TextEmbeddingUtils.validateInputSizeAgainstEmbeddings; -public record ChunkedTextEmbeddingByteResults(List> chunks, boolean isTruncated) - implements - ChunkedInferenceServiceResults { +public record ChunkedTextEmbeddingByteResults(List chunks, boolean isTruncated) implements ChunkedInferenceServiceResults { public static final String NAME = "chunked_text_embedding_service_byte_results"; public static final String FIELD_NAME = "text_embedding_byte_chunk"; @@ -37,22 +41,23 @@ public static List of(List inputs, TextE var results = new ArrayList(inputs.size()); for (int i = 0; i < inputs.size(); i++) { - results.add(of(inputs.get(i), textEmbeddings.embeddings().get(i).getEmbedding().bytes)); + results.add(of(inputs.get(i), textEmbeddings.embeddings().get(i).values())); } return results; } public static ChunkedTextEmbeddingByteResults of(String input, byte[] byteEmbeddings) { - return new ChunkedTextEmbeddingByteResults(List.of(new EmbeddingChunk<>(input, new ByteEmbedding(byteEmbeddings))), false); + return new ChunkedTextEmbeddingByteResults(List.of(new EmbeddingChunk(input, byteEmbeddings)), false); } public ChunkedTextEmbeddingByteResults(StreamInput in) throws IOException { - this(in.readCollectionAsList(in1 -> new EmbeddingChunk<>(in1.readString(), new ByteEmbedding(in1))), in.readBoolean()); + this(in.readCollectionAsList(EmbeddingChunk::new), in.readBoolean()); } @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + // TODO add isTruncated flag builder.startArray(FIELD_NAME); for (var embedding : chunks) { embedding.toXContent(builder, params); @@ -87,7 +92,68 @@ public String getWriteableName() { return NAME; } - public List> getChunks() { + public List getChunks() { return chunks; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ChunkedTextEmbeddingByteResults that = (ChunkedTextEmbeddingByteResults) o; + return isTruncated == that.isTruncated && Objects.equals(chunks, that.chunks); + } + + @Override + public int hashCode() { + return Objects.hash(chunks, isTruncated); + } + + public record EmbeddingChunk(String matchedText, byte[] embedding) implements Writeable, ToXContentObject { + + public EmbeddingChunk(StreamInput in) throws IOException { + this(in.readString(), in.readByteArray()); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(matchedText); + out.writeByteArray(embedding); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(ChunkedNlpInferenceResults.TEXT, matchedText); + + builder.startArray(ChunkedNlpInferenceResults.INFERENCE); + for (byte value : embedding) { + builder.value(value); + } + builder.endArray(); + + builder.endObject(); + return builder; + } + + @Override + public String toString() { + return Strings.toString(this); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EmbeddingChunk that = (EmbeddingChunk) o; + return Objects.equals(matchedText, that.matchedText) && Arrays.equals(embedding, that.embedding); + } + + @Override + public int hashCode() { + int result = Objects.hash(matchedText); + result = 31 * result + Arrays.hashCode(embedding); + return result; + } + } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedTextEmbeddingFloatResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedTextEmbeddingFloatResults.java index 65370277aba34..4fcd5a53fc287 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedTextEmbeddingFloatResults.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedTextEmbeddingFloatResults.java @@ -7,30 +7,35 @@ package org.elasticsearch.xpack.core.inference.results; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.inference.ChunkedInferenceServiceResults; import org.elasticsearch.inference.InferenceResults; import org.elasticsearch.xcontent.ToXContent; +import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xpack.core.ml.inference.results.ChunkedNlpInferenceResults; import java.io.IOException; +import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; -public record ChunkedTextEmbeddingFloatResults(List> chunks) - implements - ChunkedInferenceServiceResults { +public record ChunkedTextEmbeddingFloatResults(List chunks) implements ChunkedInferenceServiceResults { public static final String NAME = "chunked_text_embedding_service_float_results"; public static final String FIELD_NAME = "text_embedding_float_chunk"; public ChunkedTextEmbeddingFloatResults(StreamInput in) throws IOException { - this(in.readCollectionAsList(in1 -> new EmbeddingChunk<>(in1.readString(), new FloatEmbedding(in1)))); + this(in.readCollectionAsList(EmbeddingChunk::new)); } @Override public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { + // TODO add isTruncated flag builder.startArray(FIELD_NAME); for (var embedding : chunks) { embedding.toXContent(builder, params); @@ -64,8 +69,69 @@ public String getWriteableName() { return NAME; } - public List> getChunks() { + public List getChunks() { return chunks; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ChunkedTextEmbeddingFloatResults that = (ChunkedTextEmbeddingFloatResults) o; + return Objects.equals(chunks, that.chunks); + } + + @Override + public int hashCode() { + return Objects.hash(chunks); + } + + public record EmbeddingChunk(String matchedText, float[] embedding) implements Writeable, ToXContentObject { + + public EmbeddingChunk(StreamInput in) throws IOException { + this(in.readString(), in.readFloatArray()); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(matchedText); + out.writeFloatArray(embedding); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(ChunkedNlpInferenceResults.TEXT, matchedText); + + builder.startArray(ChunkedNlpInferenceResults.INFERENCE); + for (float value : embedding) { + builder.value(value); + } + builder.endArray(); + + builder.endObject(); + return builder; + } + + @Override + public String toString() { + return Strings.toString(this); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EmbeddingChunk that = (EmbeddingChunk) o; + return Objects.equals(matchedText, that.matchedText) && Arrays.equals(embedding, that.embedding); + } + + @Override + public int hashCode() { + int result = Objects.hash(matchedText); + result = 31 * result + Arrays.hashCode(embedding); + return result; + } + } + } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedTextEmbeddingResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedTextEmbeddingResults.java index 5553230cb7e9f..f09eafc1591dd 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedTextEmbeddingResults.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedTextEmbeddingResults.java @@ -44,7 +44,7 @@ public static List of(List inputs, TextE var results = new ArrayList(inputs.size()); for (int i = 0; i < inputs.size(); i++) { - results.add(ChunkedTextEmbeddingResults.of(inputs.get(i), textEmbeddings.embeddings().get(i).getEmbedding().floats)); + results.add(ChunkedTextEmbeddingResults.of(inputs.get(i), textEmbeddings.embeddings().get(i).values())); } return results; diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/Embedding.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/Embedding.java deleted file mode 100644 index 75eeb6ff01f73..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/Embedding.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.core.inference.results; - -import org.elasticsearch.common.Strings; -import org.elasticsearch.common.io.stream.Writeable; -import org.elasticsearch.xcontent.ToXContentFragment; -import org.elasticsearch.xcontent.ToXContentObject; -import org.elasticsearch.xcontent.XContentBuilder; - -import java.io.IOException; -import java.util.Map; -import java.util.Objects; - -public abstract class Embedding implements Writeable, ToXContentObject { - public static final String EMBEDDING = "embedding"; - - public interface EmbeddingValues extends ToXContentFragment { - int size(); - - XContentBuilder valuesToXContent(String fieldName, XContentBuilder builder, Params params) throws IOException; - } - - protected final T embedding; - - protected Embedding(T embedding) { - this.embedding = embedding; - } - - public T getEmbedding() { - return embedding; - } - - public Map asMap() { - return Map.of(EMBEDDING, embedding); - } - - public int getSize() { - return embedding.size(); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - embedding.valuesToXContent(EMBEDDING, builder, params); - builder.endObject(); - return builder; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Embedding embedding1 = (Embedding) o; - return Objects.equals(embedding, embedding1.embedding); - } - - @Override - public int hashCode() { - return Objects.hash(embedding); - } - - @Override - public String toString() { - return Strings.toString(this); - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingChunk.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingChunk.java deleted file mode 100644 index 9f0f3bc7fe952..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingChunk.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.core.inference.results; - -import org.elasticsearch.common.Strings; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.common.io.stream.Writeable; -import org.elasticsearch.xcontent.ToXContentObject; -import org.elasticsearch.xcontent.XContentBuilder; -import org.elasticsearch.xpack.core.ml.inference.results.ChunkedNlpInferenceResults; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -public class EmbeddingChunk implements Writeable, ToXContentObject { - - private final String matchedText; - private final Embedding embedding; - - public EmbeddingChunk(String matchedText, Embedding embedding) { - this.matchedText = matchedText; - this.embedding = embedding; - } - - public String matchedText() { - return matchedText; - } - - public Embedding embedding() { - return embedding; - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeString(matchedText); - embedding.writeTo(out); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.field(ChunkedNlpInferenceResults.TEXT, matchedText); - embedding.embedding.valuesToXContent(ChunkedNlpInferenceResults.INFERENCE, builder, params); - builder.endObject(); - return builder; - } - - public Map asMap() { - var map = new HashMap(); - map.put(ChunkedNlpInferenceResults.TEXT, matchedText); - map.put(ChunkedNlpInferenceResults.INFERENCE, embedding.getEmbedding()); - return map; - } - - @Override - public String toString() { - return Strings.toString(this); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - EmbeddingChunk that = (EmbeddingChunk) o; - return Objects.equals(matchedText, that.matchedText) && Objects.equals(embedding, that.embedding); - } - - @Override - public int hashCode() { - return Objects.hash(matchedText, embedding); - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingInt.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingInt.java new file mode 100644 index 0000000000000..05fc8a3cef1b6 --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingInt.java @@ -0,0 +1,12 @@ +/* + * 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.core.inference.results; + +public interface EmbeddingInt { + int getSize(); +} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingResults.java deleted file mode 100644 index 851a320c262a5..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingResults.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.core.inference.results; - -import org.elasticsearch.inference.InferenceServiceResults; - -import java.util.List; - -public interface EmbeddingResults { - List> embeddings(); - - EmbeddingType embeddingType(); - - enum EmbeddingType { - SPARSE { - public Class matchedClass() { - return SparseEmbeddingResults.class; - }; - }, - FLOAT { - public Class matchedClass() { - return TextEmbeddingResults.class; - }; - }, - - BYTE { - public Class matchedClass() { - return TextEmbeddingByteResults.class; - }; - }; - - public abstract Class matchedClass(); - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/FloatEmbedding.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/FloatEmbedding.java deleted file mode 100644 index 18bdff1a6f47d..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/FloatEmbedding.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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.core.inference.results; - -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.xcontent.XContentBuilder; - -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -public class FloatEmbedding extends Embedding { - - public static FloatEmbedding of(List embedding) { - float[] embeddingFloats = new float[embedding.size()]; - for (int i = 0; i < embedding.size(); i++) { - embeddingFloats[i] = embedding.get(i); - } - return new FloatEmbedding(embeddingFloats); - } - - public static class FloatArrayWrapper implements EmbeddingValues { - - final float[] floats; - - public FloatArrayWrapper(float[] floats) { - this.floats = floats; - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return valuesToXContent(EMBEDDING, builder, params); - } - - @Override - public int size() { - return floats.length; - } - - @Override - public XContentBuilder valuesToXContent(String fieldName, XContentBuilder builder, Params params) throws IOException { - builder.startArray(fieldName); - for (var value : floats) { - builder.value(value); - } - builder.endArray(); - return builder; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - FloatArrayWrapper that = (FloatArrayWrapper) o; - return Arrays.equals(floats, that.floats); - } - - @Override - public int hashCode() { - return Arrays.hashCode(floats); - } - } - - public FloatEmbedding(StreamInput in) throws IOException { - this(in.readFloatArray()); - } - - public FloatEmbedding(float[] embedding) { - super(new FloatArrayWrapper(embedding)); - } - - public float[] asFloatArray() { - return embedding.floats; - } - - public double[] asDoubleArray() { - var result = new double[embedding.floats.length]; - for (int i = 0; i < embedding.floats.length; i++) { - result[i] = embedding.floats[i]; - } - return result; - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeFloatArray(embedding.floats); - } - - public static FloatEmbedding of(org.elasticsearch.xpack.core.ml.inference.results.TextEmbeddingResults embeddingResult) { - return new FloatEmbedding(embeddingResult.getInferenceAsFloat()); - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/SparseEmbedding.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/SparseEmbedding.java deleted file mode 100644 index 18b93dd1fef8d..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/SparseEmbedding.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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.core.inference.results; - -import org.elasticsearch.common.Strings; -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.common.io.stream.Writeable; -import org.elasticsearch.xcontent.ToXContentFragment; -import org.elasticsearch.xcontent.XContentBuilder; - -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -public class SparseEmbedding extends Embedding { - - public static final String IS_TRUNCATED = "is_truncated"; - - public static SparseEmbedding fromMlResults( - List weightedTokens, - boolean isTruncated - ) { - return new SparseEmbedding( - new WeightedTokens(weightedTokens.stream().map(token -> new WeightedToken(token.token(), token.weight())).toList()), - isTruncated - ); - } - - private final boolean isTruncated; - - public SparseEmbedding(StreamInput in) throws IOException { - this(new WeightedTokens(in.readCollectionAsImmutableList(SparseEmbedding.WeightedToken::new)), in.readBoolean()); - } - - public SparseEmbedding(WeightedTokens embedding, boolean isTruncated) { - super(embedding); - this.isTruncated = isTruncated; - } - - public SparseEmbedding(List tokens, boolean isTruncated) { - super(new WeightedTokens(tokens)); - this.isTruncated = isTruncated; - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeCollection(embedding.tokens); - out.writeBoolean(isTruncated); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.field(IS_TRUNCATED, isTruncated); - embedding.toXContent(builder, params); - builder.endObject(); - return builder; - } - - public boolean isTruncated() { - return isTruncated; - } - - public Map asMap() { - var embeddingMap = new LinkedHashMap( - embedding.tokens.stream().collect(Collectors.toMap(WeightedToken::token, WeightedToken::weight)) - ); - - return new LinkedHashMap<>(Map.of(IS_TRUNCATED, isTruncated, EMBEDDING, embeddingMap)); - } - - public List tokens() { - return embedding.tokens; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (super.equals(o) == false) return false; - SparseEmbedding that = (SparseEmbedding) o; - return isTruncated == that.isTruncated; - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), isTruncated); - } - - public static class WeightedTokens implements Embedding.EmbeddingValues { - private final List tokens; - - public WeightedTokens(List tokens) { - this.tokens = tokens; - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return valuesToXContent(EMBEDDING, builder, params); - } - - @Override - public int size() { - return tokens.size(); - } - - @Override - public XContentBuilder valuesToXContent(String fieldName, XContentBuilder builder, Params params) throws IOException { - builder.startObject(fieldName); - for (var weightedToken : tokens) { - weightedToken.toXContent(builder, params); - } - builder.endObject(); - return builder; - } - - public List tokens() { - return tokens; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - WeightedTokens that = (WeightedTokens) o; - return Objects.equals(tokens, that.tokens); - } - - @Override - public int hashCode() { - return Objects.hash(tokens); - } - } - - public record WeightedToken(String token, float weight) implements Writeable, ToXContentFragment { - public WeightedToken(StreamInput in) throws IOException { - this(in.readString(), in.readFloat()); - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeString(token); - out.writeFloat(weight); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.field(token, weight); - return builder; - } - - public Map asMap() { - return Map.of(token, weight); - } - - @Override - public String toString() { - return Strings.toString(this); - } - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/SparseEmbeddingResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/SparseEmbeddingResults.java index f108f9e86416c..1db6dcc802d00 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/SparseEmbeddingResults.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/SparseEmbeddingResults.java @@ -8,12 +8,15 @@ package org.elasticsearch.xpack.core.inference.results; import org.elasticsearch.ElasticsearchStatusException; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.inference.InferenceResults; import org.elasticsearch.inference.InferenceServiceResults; import org.elasticsearch.inference.TaskType; import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xpack.core.ml.inference.results.TextExpansionResults; import org.elasticsearch.xpack.core.ml.search.WeightedToken; @@ -23,24 +26,25 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import static org.elasticsearch.xpack.core.ml.inference.trainedmodel.InferenceConfig.DEFAULT_RESULTS_FIELD; -public record SparseEmbeddingResults(List embeddings) implements InferenceServiceResults, EmbeddingResults { +public record SparseEmbeddingResults(List embeddings) implements InferenceServiceResults { public static final String NAME = "sparse_embedding_results"; public static final String SPARSE_EMBEDDING = TaskType.SPARSE_EMBEDDING.toString(); public SparseEmbeddingResults(StreamInput in) throws IOException { - this(in.readCollectionAsList(SparseEmbedding::new)); + this(in.readCollectionAsList(Embedding::new)); } public static SparseEmbeddingResults of(List results) { - List embeddings = new ArrayList<>(results.size()); + List embeddings = new ArrayList<>(results.size()); for (InferenceResults result : results) { if (result instanceof TextExpansionResults expansionResults) { - embeddings.add(SparseEmbedding.fromMlResults(expansionResults.getWeightedTokens(), expansionResults.isTruncated())); + embeddings.add(Embedding.create(expansionResults.getWeightedTokens(), expansionResults.isTruncated())); } else if (result instanceof org.elasticsearch.xpack.core.ml.inference.results.ErrorInferenceResults errorResult) { if (errorResult.getException() instanceof ElasticsearchStatusException statusException) { throw statusException; @@ -67,7 +71,7 @@ public static SparseEmbeddingResults of(List results public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startArray(SPARSE_EMBEDDING); - for (var embedding : embeddings) { + for (Embedding embedding : embeddings) { embedding.toXContent(builder, params); } @@ -108,14 +112,60 @@ public List transformToLegacyFormat() { .stream() .map(weightedToken -> new WeightedToken(weightedToken.token(), weightedToken.weight())) .toList(), - embedding.isTruncated() + embedding.isTruncated ) ) .toList(); } - @Override - public EmbeddingType embeddingType() { - return EmbeddingType.SPARSE; + public record Embedding(List tokens, boolean isTruncated) implements Writeable, ToXContentObject { + + public static final String EMBEDDING = "embedding"; + public static final String IS_TRUNCATED = "is_truncated"; + + public Embedding(StreamInput in) throws IOException { + this(in.readCollectionAsList(WeightedToken::new), in.readBoolean()); + } + + public static Embedding create(List weightedTokens, boolean isTruncated) { + return new Embedding( + weightedTokens.stream().map(token -> new WeightedToken(token.token(), token.weight())).toList(), + isTruncated + ); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeCollection(tokens); + out.writeBoolean(isTruncated); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(IS_TRUNCATED, isTruncated); + builder.startObject(EMBEDDING); + + for (var weightedToken : tokens) { + weightedToken.toXContent(builder, params); + } + + builder.endObject(); + builder.endObject(); + return builder; + } + + public Map asMap() { + var embeddingMap = new LinkedHashMap( + tokens.stream().collect(Collectors.toMap(WeightedToken::token, WeightedToken::weight)) + ); + + return new LinkedHashMap<>(Map.of(IS_TRUNCATED, isTruncated, EMBEDDING, embeddingMap)); + } + + @Override + public String toString() { + return Strings.toString(this); + } } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbedding.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbedding.java index ef406f5c956ad..a185c2938223e 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbedding.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbedding.java @@ -7,7 +7,7 @@ package org.elasticsearch.xpack.core.inference.results; -public interface TextEmbedding extends EmbeddingResults { +public interface TextEmbedding { /** * Returns the first text embedding entry in the result list's array size. diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingByteResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingByteResults.java index 743795d0530f5..04986b2d957d7 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingByteResults.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingByteResults.java @@ -9,14 +9,18 @@ package org.elasticsearch.xpack.core.inference.results; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.inference.InferenceResults; import org.elasticsearch.inference.InferenceServiceResults; +import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -39,27 +43,12 @@ * ] * } */ -public class TextEmbeddingByteResults implements InferenceServiceResults, TextEmbedding { +public record TextEmbeddingByteResults(List embeddings) implements InferenceServiceResults, TextEmbedding { public static final String NAME = "text_embedding_service_byte_results"; public static final String TEXT_EMBEDDING_BYTES = "text_embedding_bytes"; - private final List embeddings; - - public TextEmbeddingByteResults(List embeddings) { - this.embeddings = embeddings; - } - public TextEmbeddingByteResults(StreamInput in) throws IOException { - this(in.readCollectionAsList(ByteEmbedding::new)); - } - - public List embeddings() { - return embeddings; - } - - @Override - public EmbeddingType embeddingType() { - return EmbeddingType.BYTE; + this(in.readCollectionAsList(Embedding::new)); } @Override @@ -70,7 +59,7 @@ public int getFirstEmbeddingSize() { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startArray(TEXT_EMBEDDING_BYTES); - for (var embedding : embeddings) { + for (Embedding embedding : embeddings) { embedding.toXContent(builder, params); } builder.endArray(); @@ -91,9 +80,9 @@ public String getWriteableName() { public List transformToCoordinationFormat() { return embeddings.stream() .map( - embedding -> new org.elasticsearch.xpack.core.ml.inference.results.TextEmbeddingByteResults( + embedding -> new org.elasticsearch.xpack.core.ml.inference.results.TextEmbeddingResults( TEXT_EMBEDDING_BYTES, - embedding.bytes(), + embedding.toDoubleArray(), false ) ) @@ -125,7 +114,82 @@ public boolean equals(Object o) { return Objects.equals(embeddings, that.embeddings); } + @Override public int hashCode() { return Objects.hash(embeddings); } + + public record Embedding(byte[] values) implements Writeable, ToXContentObject, EmbeddingInt { + public static final String EMBEDDING = "embedding"; + + public Embedding(StreamInput in) throws IOException { + this(in.readByteArray()); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeByteArray(values); + } + + public static Embedding of(List embeddingValuesList) { + byte[] embeddingValues = new byte[embeddingValuesList.size()]; + for (int i = 0; i < embeddingValuesList.size(); i++) { + embeddingValues[i] = embeddingValuesList.get(i); + } + return new Embedding(embeddingValues); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + + builder.startArray(EMBEDDING); + for (byte value : values) { + builder.value(value); + } + builder.endArray(); + + builder.endObject(); + return builder; + } + + @Override + public String toString() { + return Strings.toString(this); + } + + private float[] toFloatArray() { + float[] floatArray = new float[values.length]; + for (int i = 0; i < values.length; i++) { + floatArray[i] = ((Byte) values[i]).floatValue(); + } + return floatArray; + } + + private double[] toDoubleArray() { + double[] doubleArray = new double[values.length]; + for (int i = 0; i < values.length; i++) { + doubleArray[i] = ((Byte) values[i]).floatValue(); + } + return doubleArray; + } + + @Override + public int getSize() { + return values().length; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Embedding embedding = (Embedding) o; + return Arrays.equals(values, embedding.values); + } + + @Override + public int hashCode() { + return Arrays.hashCode(values); + } + } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingResults.java index 7652551d9ca1d..152e10e82d5ba 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingResults.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingResults.java @@ -10,19 +10,24 @@ package org.elasticsearch.xpack.core.inference.results; import org.elasticsearch.ElasticsearchStatusException; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.inference.InferenceResults; import org.elasticsearch.inference.InferenceServiceResults; import org.elasticsearch.inference.TaskType; import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; /** @@ -42,12 +47,12 @@ * ] * } */ -public record TextEmbeddingResults(List embeddings) implements InferenceServiceResults, TextEmbedding, EmbeddingResults { +public record TextEmbeddingResults(List embeddings) implements InferenceServiceResults, TextEmbedding { public static final String NAME = "text_embedding_service_results"; public static final String TEXT_EMBEDDING = TaskType.TEXT_EMBEDDING.toString(); public TextEmbeddingResults(StreamInput in) throws IOException { - this(in.readCollectionAsList(FloatEmbedding::new)); + this(in.readCollectionAsList(Embedding::new)); } @SuppressWarnings("deprecation") @@ -55,16 +60,16 @@ public TextEmbeddingResults(StreamInput in) throws IOException { this( legacyTextEmbeddingResults.embeddings() .stream() - .map(embedding -> new FloatEmbedding(embedding.values())) + .map(embedding -> new Embedding(embedding.values())) .collect(Collectors.toList()) ); } public static TextEmbeddingResults of(List results) { - List embeddings = new ArrayList<>(results.size()); + List embeddings = new ArrayList<>(results.size()); for (InferenceResults result : results) { if (result instanceof org.elasticsearch.xpack.core.ml.inference.results.TextEmbeddingResults embeddingResult) { - embeddings.add(FloatEmbedding.of(embeddingResult)); + embeddings.add(Embedding.of(embeddingResult)); } else if (result instanceof org.elasticsearch.xpack.core.ml.inference.results.ErrorInferenceResults errorResult) { if (errorResult.getException() instanceof ElasticsearchStatusException statusException) { throw statusException; @@ -92,7 +97,7 @@ public int getFirstEmbeddingSize() { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startArray(TEXT_EMBEDDING); - for (Embedding embedding : embeddings) { + for (Embedding embedding : embeddings) { embedding.toXContent(builder, params); } builder.endArray(); @@ -126,7 +131,7 @@ public List transformToCoordinationFormat() { @SuppressWarnings("deprecation") public List transformToLegacyFormat() { var legacyEmbedding = new LegacyTextEmbeddingResults( - embeddings.stream().map(embedding -> new LegacyTextEmbeddingResults.Embedding(embedding.asFloatArray())).toList() + embeddings.stream().map(embedding -> new LegacyTextEmbeddingResults.Embedding(embedding.values)).toList() ); return List.of(legacyEmbedding); @@ -140,12 +145,86 @@ public Map asMap() { } @Override - public List embeddings() { - return embeddings; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TextEmbeddingResults that = (TextEmbeddingResults) o; + return Objects.equals(embeddings, that.embeddings); } @Override - public EmbeddingType embeddingType() { - return EmbeddingType.FLOAT; + public int hashCode() { + return Objects.hash(embeddings); + } + + public record Embedding(float[] values) implements Writeable, ToXContentObject, EmbeddingInt { + public static final String EMBEDDING = "embedding"; + + public Embedding(StreamInput in) throws IOException { + this(in.readFloatArray()); + } + + public static Embedding of(org.elasticsearch.xpack.core.ml.inference.results.TextEmbeddingResults embeddingResult) { + float[] embeddingAsArray = embeddingResult.getInferenceAsFloat(); + return new Embedding(embeddingAsArray); + } + + public static Embedding of(List embeddingValuesList) { + float[] embeddingValues = new float[embeddingValuesList.size()]; + for (int i = 0; i < embeddingValuesList.size(); i++) { + embeddingValues[i] = embeddingValuesList.get(i); + } + return new Embedding(embeddingValues); + } + + @Override + public int getSize() { + return values.length; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeFloatArray(values); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + + builder.startArray(EMBEDDING); + for (float value : values) { + builder.value(value); + } + builder.endArray(); + + builder.endObject(); + return builder; + } + + @Override + public String toString() { + return Strings.toString(this); + } + + private double[] asDoubleArray() { + double[] doubles = new double[values.length]; + for (int i = 0; i < values.length; i++) { + doubles[i] = values[i]; + } + return doubles; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Embedding embedding = (Embedding) o; + return Arrays.equals(values, embedding.values); + } + + @Override + public int hashCode() { + return Arrays.hashCode(values); + } } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingUtils.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingUtils.java index d45a0d9731fc9..4c68d02264457 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingUtils.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingUtils.java @@ -19,7 +19,7 @@ public class TextEmbeddingUtils { * @return the size of the text embedding * @throws IllegalStateException if the list of embeddings is empty */ - public static int getFirstEmbeddingSize(List> embeddings) throws IllegalStateException { + public static int getFirstEmbeddingSize(List embeddings) throws IllegalStateException { if (embeddings.isEmpty()) { throw new IllegalStateException("Embeddings list is empty"); } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/inference/MlInferenceNamedXContentProvider.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/inference/MlInferenceNamedXContentProvider.java index f7fe2d0f6491a..a3fb956c3252d 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/inference/MlInferenceNamedXContentProvider.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/inference/MlInferenceNamedXContentProvider.java @@ -30,7 +30,6 @@ import org.elasticsearch.xpack.core.ml.inference.results.PyTorchPassThroughResults; import org.elasticsearch.xpack.core.ml.inference.results.QuestionAnsweringInferenceResults; import org.elasticsearch.xpack.core.ml.inference.results.RegressionInferenceResults; -import org.elasticsearch.xpack.core.ml.inference.results.TextEmbeddingByteResults; import org.elasticsearch.xpack.core.ml.inference.results.TextEmbeddingResults; import org.elasticsearch.xpack.core.ml.inference.results.TextExpansionResults; import org.elasticsearch.xpack.core.ml.inference.results.TextSimilarityInferenceResults; @@ -654,9 +653,6 @@ public List getNamedWriteables() { ); namedWriteables.add(new NamedWriteableRegistry.Entry(InferenceResults.class, TextExpansionResults.NAME, TextExpansionResults::new)); namedWriteables.add(new NamedWriteableRegistry.Entry(InferenceResults.class, TextEmbeddingResults.NAME, TextEmbeddingResults::new)); - namedWriteables.add( - new NamedWriteableRegistry.Entry(InferenceResults.class, TextEmbeddingByteResults.NAME, TextEmbeddingByteResults::new) - ); namedWriteables.add( new NamedWriteableRegistry.Entry( InferenceResults.class, diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/inference/results/TextEmbeddingByteResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/inference/results/TextEmbeddingByteResults.java deleted file mode 100644 index 4871ba208aa6a..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/inference/results/TextEmbeddingByteResults.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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.core.ml.inference.results; - -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.xcontent.XContentBuilder; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Map; -import java.util.Objects; - -public class TextEmbeddingByteResults extends NlpInferenceResults { - - public static final String NAME = "text_embedding_byte_result"; - - private final String resultsField; - private final byte[] inference; - - public TextEmbeddingByteResults(String resultsField, byte[] inference, boolean isTruncated) { - super(isTruncated); - this.inference = inference; - this.resultsField = resultsField; - } - - public TextEmbeddingByteResults(StreamInput in) throws IOException { - super(in); - inference = in.readByteArray(); - resultsField = in.readString(); - } - - public String getResultsField() { - return resultsField; - } - - public byte[] getInference() { - return inference; - } - - public float[] getInferenceAsFloat() { - float[] floatArray = new float[inference.length]; - for (int i = 0; i < inference.length; i++) { - floatArray[i] = inference[i]; - } - return floatArray; - } - - @Override - void doXContentBody(XContentBuilder builder, Params params) throws IOException { - builder.field(resultsField, inference); - } - - @Override - public String getWriteableName() { - return NAME; - } - - @Override - void doWriteTo(StreamOutput out) throws IOException { - out.writeByteArray(inference); - out.writeString(resultsField); - } - - @Override - void addMapFields(Map map) { - map.put(resultsField, inference); - } - - @Override - public Map asMap(String outputField) { - var map = super.asMap(outputField); - map.put(outputField, inference); - return map; - } - - @Override - public Object predictedValue() { - throw new UnsupportedOperationException("[" + NAME + "] does not support a single predicted value"); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (super.equals(o) == false) return false; - TextEmbeddingByteResults that = (TextEmbeddingByteResults) o; - return Objects.equals(resultsField, that.resultsField) && Arrays.equals(inference, that.inference); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), resultsField, Arrays.hashCode(inference)); - } -} diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/inference/results/TextEmbeddingByteResultsTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/inference/results/TextEmbeddingByteResultsTests.java deleted file mode 100644 index 7ea6e531fcbd2..0000000000000 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/inference/results/TextEmbeddingByteResultsTests.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.core.ml.inference.results; - -import org.elasticsearch.common.io.stream.Writeable; -import org.elasticsearch.ingest.IngestDocument; - -import java.util.Map; - -import static org.elasticsearch.xpack.core.ml.inference.trainedmodel.InferenceConfig.DEFAULT_RESULTS_FIELD; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; - -public class TextEmbeddingByteResultsTests extends InferenceResultsTestCase { - - public static TextEmbeddingByteResults createRandomResults() { - int columns = randomIntBetween(1, 10); - var arr = new byte[columns]; - for (int i = 0; i < columns; i++) { - arr[i] = randomByte(); - } - - return new TextEmbeddingByteResults(DEFAULT_RESULTS_FIELD, arr, randomBoolean()); - } - - @Override - protected Writeable.Reader instanceReader() { - return TextEmbeddingByteResults::new; - } - - @Override - protected TextEmbeddingByteResults createTestInstance() { - return createRandomResults(); - } - - @Override - protected TextEmbeddingByteResults mutateInstance(TextEmbeddingByteResults instance) { - return null;// TODO implement https://github.com/elastic/elasticsearch/issues/25929 - } - - public void testAsMap() { - TextEmbeddingByteResults testInstance = createTestInstance(); - Map asMap = testInstance.asMap(); - int size = testInstance.isTruncated ? 2 : 1; - assertThat(asMap.keySet(), hasSize(size)); - assertArrayEquals(testInstance.getInference(), (byte[]) asMap.get(DEFAULT_RESULTS_FIELD)); - if (testInstance.isTruncated) { - assertThat(asMap.get("is_truncated"), is(true)); - } - } - - @Override - void assertFieldValues(TextEmbeddingByteResults createdInstance, IngestDocument document, String parentField, String resultsField) { - assertArrayEquals(document.getFieldValue(parentField + resultsField, byte[].class), createdInstance.getInference()); - } -} diff --git a/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestDenseInferenceServiceExtension.java b/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestDenseInferenceServiceExtension.java index 9093598a8f6ff..bb18b71eb3fea 100644 --- a/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestDenseInferenceServiceExtension.java +++ b/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestDenseInferenceServiceExtension.java @@ -29,7 +29,6 @@ import org.elasticsearch.rest.RestStatus; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; import org.elasticsearch.xpack.core.ml.inference.results.ChunkedTextEmbeddingResults; @@ -138,14 +137,14 @@ public void chunkedInfer( } private TextEmbeddingResults makeResults(List input, int dimensions) { - List embeddings = new ArrayList<>(); + List embeddings = new ArrayList<>(); for (int i = 0; i < input.size(); i++) { double[] doubleEmbeddings = generateEmbedding(input.get(i), dimensions); List floatEmbeddings = new ArrayList<>(dimensions); for (int j = 0; j < dimensions; j++) { floatEmbeddings.add((float) doubleEmbeddings[j]); } - embeddings.add(FloatEmbedding.of(floatEmbeddings)); + embeddings.add(TextEmbeddingResults.Embedding.of(floatEmbeddings)); } return new TextEmbeddingResults(embeddings); } diff --git a/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestSparseInferenceServiceExtension.java b/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestSparseInferenceServiceExtension.java index c39999377ae54..05e85334cff5a 100644 --- a/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestSparseInferenceServiceExtension.java +++ b/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestSparseInferenceServiceExtension.java @@ -29,7 +29,6 @@ import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xpack.core.inference.results.ChunkedSparseEmbeddingResults; -import org.elasticsearch.xpack.core.inference.results.SparseEmbedding; import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; import org.elasticsearch.xpack.core.ml.inference.results.ChunkedTextExpansionResults; import org.elasticsearch.xpack.core.ml.search.WeightedToken; @@ -128,13 +127,13 @@ public void chunkedInfer( } private SparseEmbeddingResults makeResults(List input) { - var embeddings = new ArrayList(); + var embeddings = new ArrayList(); for (int i = 0; i < input.size(); i++) { - var tokens = new ArrayList(); + var tokens = new ArrayList(); for (int j = 0; j < 5; j++) { - tokens.add(new SparseEmbedding.WeightedToken("feature_" + j, generateEmbedding(input.get(i), j))); + tokens.add(new WeightedToken("feature_" + j, generateEmbedding(input.get(i), j))); } - embeddings.add(new SparseEmbedding(tokens, false)); + embeddings.add(new SparseEmbeddingResults.Embedding(tokens, false)); } return new SparseEmbeddingResults(embeddings); } diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/common/EmbeddingRequestChunker.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/common/EmbeddingRequestChunker.java index 6866b04f2347e..77d03ac660952 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/common/EmbeddingRequestChunker.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/common/EmbeddingRequestChunker.java @@ -7,29 +7,19 @@ package org.elasticsearch.xpack.inference.common; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.elasticsearch.ElasticsearchStatusException; import org.elasticsearch.action.ActionListener; import org.elasticsearch.common.util.concurrent.AtomicArray; import org.elasticsearch.inference.ChunkedInferenceServiceResults; import org.elasticsearch.inference.InferenceServiceResults; import org.elasticsearch.rest.RestStatus; -import org.elasticsearch.xpack.core.inference.results.ByteEmbedding; -import org.elasticsearch.xpack.core.inference.results.ChunkedSparseEmbeddingResults; -import org.elasticsearch.xpack.core.inference.results.ChunkedTextEmbeddingByteResults; import org.elasticsearch.xpack.core.inference.results.ChunkedTextEmbeddingFloatResults; -import org.elasticsearch.xpack.core.inference.results.Embedding; -import org.elasticsearch.xpack.core.inference.results.EmbeddingChunk; -import org.elasticsearch.xpack.core.inference.results.EmbeddingResults; import org.elasticsearch.xpack.core.inference.results.ErrorChunkedInferenceResults; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; -import org.elasticsearch.xpack.core.inference.results.SparseEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; /** @@ -45,8 +35,6 @@ */ public class EmbeddingRequestChunker { - private static final Logger logger = LogManager.getLogger(EmbeddingRequestChunker.class); - public static final int DEFAULT_WORDS_PER_CHUNK = 250; public static final int DEFAULT_CHUNK_OVERLAP = 100; @@ -57,12 +45,10 @@ public class EmbeddingRequestChunker { private final int chunkOverlap; private List> chunkedInputs; - private List>>> results; + private List>> results; private AtomicArray errors; private ActionListener> finalListener; - private AtomicReference firstResultType = new AtomicReference<>(); - public EmbeddingRequestChunker(List inputs, int maxNumberOfInputsPerBatch) { this.maxNumberOfInputsPerBatch = maxNumberOfInputsPerBatch; this.wordsPerChunk = DEFAULT_WORDS_PER_CHUNK; @@ -174,14 +160,14 @@ private class DebatchingListener implements ActionListener chunks, - AtomicArray>> embeddings - ) { - return switch (embeddingType) { - case FLOAT -> mergeFloatResults(chunks, embeddings); - case BYTE -> mergeByteResults(chunks, embeddings); - case SPARSE -> mergeSparseResults(chunks, embeddings); - }; - } - - private ChunkedTextEmbeddingFloatResults mergeFloatResults( + private ChunkedTextEmbeddingFloatResults merge( List chunks, - AtomicArray>> debatchedResults + AtomicArray> debatchedResults ) { - var all = new ArrayList(); + var all = new ArrayList(); for (int i = 0; i < debatchedResults.length(); i++) { var subBatch = debatchedResults.get(i); - for (var result : subBatch) { - if (result instanceof FloatEmbedding fe) { - all.add(fe); - } else { - var message = "Unexpected embedding result type [" - + result.getClass().getSimpleName() - + "], expected a float embedding"; - logger.error(message); - throw new IllegalStateException(message); - } - } + all.addAll(subBatch); } assert chunks.size() == all.size(); - var embeddingChunks = new ArrayList>(); + var embeddingChunks = new ArrayList(); for (int i = 0; i < chunks.size(); i++) { - embeddingChunks.add(new EmbeddingChunk<>(chunks.get(i), all.get(i))); + embeddingChunks.add(new ChunkedTextEmbeddingFloatResults.EmbeddingChunk(chunks.get(i), all.get(i).values())); } return new ChunkedTextEmbeddingFloatResults(embeddingChunks); } - - private ChunkedTextEmbeddingByteResults mergeByteResults( - List chunks, - AtomicArray>> debatchedResults - ) { - var all = new ArrayList(); - for (int i = 0; i < debatchedResults.length(); i++) { - var subBatch = debatchedResults.get(i); - for (var result : subBatch) { - if (result instanceof ByteEmbedding be) { - all.add(be); - } else { - var message = "Unexpected embedding result type [" - + result.getClass().getSimpleName() - + "], expected a byte embedding"; - logger.error(message); - throw new IllegalStateException(message); - } - } - } - - assert chunks.size() == all.size(); - - var embeddingChunks = new ArrayList>(); - for (int i = 0; i < chunks.size(); i++) { - embeddingChunks.add(new EmbeddingChunk<>(chunks.get(i), all.get(i))); - } - - return new ChunkedTextEmbeddingByteResults(embeddingChunks, false); - } - - private ChunkedSparseEmbeddingResults mergeSparseResults( - List chunks, - AtomicArray>> debatchedResults - ) { - var all = new ArrayList(); - for (int i = 0; i < debatchedResults.length(); i++) { - var subBatch = debatchedResults.get(i); - for (var result : subBatch) { - if (result instanceof SparseEmbedding se) { - all.add(se); - } else { - var message = "Unexpected embedding result type [" - + result.getClass().getSimpleName() - + "], expected a byte embedding"; - logger.error(message); - throw new IllegalStateException(message); - } - } - } - - assert chunks.size() == all.size(); - - var embeddingChunks = new ArrayList>(); - for (int i = 0; i < chunks.size(); i++) { - embeddingChunks.add(new EmbeddingChunk<>(chunks.get(i), all.get(i))); - } - - return ChunkedSparseEmbeddingResults.of(embeddingChunks); - } } public record BatchRequest(List subBatches) { diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntity.java index 7353f9cf1f94e..f787c6337d646 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntity.java @@ -18,8 +18,6 @@ import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.ByteEmbedding; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; @@ -190,10 +188,11 @@ private static InferenceServiceResults parseByteEmbeddingsArray(XContentParser p return new TextEmbeddingByteResults(embeddingList); } - private static ByteEmbedding parseByteArrayEntry(XContentParser parser) throws IOException { + private static TextEmbeddingByteResults.Embedding parseByteArrayEntry(XContentParser parser) throws IOException { XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.currentToken(), parser); List embeddingValuesList = XContentParserUtils.parseList(parser, CohereEmbeddingsResponseEntity::parseEmbeddingInt8Entry); - return ByteEmbedding.of(embeddingValuesList); + + return TextEmbeddingByteResults.Embedding.of(embeddingValuesList); } private static Byte parseEmbeddingInt8Entry(XContentParser parser) throws IOException { @@ -217,10 +216,10 @@ private static InferenceServiceResults parseFloatEmbeddingsArray(XContentParser return new TextEmbeddingResults(embeddingList); } - private static FloatEmbedding parseFloatArrayEntry(XContentParser parser) throws IOException { + private static TextEmbeddingResults.Embedding parseFloatArrayEntry(XContentParser parser) throws IOException { XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.currentToken(), parser); - List embeddingValues = XContentParserUtils.parseList(parser, CohereEmbeddingsResponseEntity::parseEmbeddingFloatEntry); - return FloatEmbedding.of(embeddingValues); + List embeddingValuesList = XContentParserUtils.parseList(parser, CohereEmbeddingsResponseEntity::parseEmbeddingFloatEntry); + return TextEmbeddingResults.Embedding.of(embeddingValuesList); } private static Float parseEmbeddingFloatEntry(XContentParser parser) throws IOException { diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceElserResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceElserResponseEntity.java index a18ac3e8e466b..270a981a6998d 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceElserResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceElserResponseEntity.java @@ -13,8 +13,8 @@ import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.SparseEmbedding; import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; +import org.elasticsearch.xpack.core.ml.search.WeightedToken; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -65,7 +65,7 @@ public static SparseEmbeddingResults fromResponse(Request request, HttpResult re moveToFirstToken(jsonParser); var truncationResults = request.getTruncationInfo(); - List parsedEmbeddings = XContentParserUtils.parseList( + List parsedEmbeddings = XContentParserUtils.parseList( jsonParser, (parser, index) -> HuggingFaceElserResponseEntity.parseExpansionResult(truncationResults, parser, index) ); @@ -78,24 +78,26 @@ public static SparseEmbeddingResults fromResponse(Request request, HttpResult re } } - private static SparseEmbedding parseExpansionResult(boolean[] truncationResults, XContentParser parser, int index) throws IOException { + private static SparseEmbeddingResults.Embedding parseExpansionResult(boolean[] truncationResults, XContentParser parser, int index) + throws IOException { XContentParser.Token token = parser.currentToken(); XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser); - List weightedTokens = new ArrayList<>(); + List weightedTokens = new ArrayList<>(); token = parser.nextToken(); while (token != null && token != XContentParser.Token.END_OBJECT) { XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); var floatToken = parser.nextToken(); XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, floatToken, parser); - weightedTokens.add(new SparseEmbedding.WeightedToken(parser.currentName(), parser.floatValue())); + weightedTokens.add(new WeightedToken(parser.currentName(), parser.floatValue())); + token = parser.nextToken(); } // prevent an out of bounds if for some reason the truncation list is smaller than the results var isTruncated = truncationResults != null && index < truncationResults.length && truncationResults[index]; - return new SparseEmbedding(weightedTokens, isTruncated); + return new SparseEmbeddingResults.Embedding(weightedTokens, isTruncated); } private HuggingFaceElserResponseEntity() {} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntity.java index 53a2c3e9c7f00..a3e06b3c2075a 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntity.java @@ -15,7 +15,6 @@ import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -93,7 +92,7 @@ public static TextEmbeddingResults fromResponse(Request request, HttpResult resp * sentence-transformers/all-MiniLM-L12-v2 */ private static TextEmbeddingResults parseArrayFormat(XContentParser parser) throws IOException { - List embeddingList = XContentParserUtils.parseList( + List embeddingList = XContentParserUtils.parseList( parser, HuggingFaceEmbeddingsResponseEntity::parseEmbeddingEntry ); @@ -140,7 +139,7 @@ private static TextEmbeddingResults parseArrayFormat(XContentParser parser) thro private static TextEmbeddingResults parseObjectFormat(XContentParser parser) throws IOException { positionParserAtTokenAfterField(parser, "embeddings", FAILED_TO_FIND_FIELD_TEMPLATE); - List embeddingList = XContentParserUtils.parseList( + List embeddingList = XContentParserUtils.parseList( parser, HuggingFaceEmbeddingsResponseEntity::parseEmbeddingEntry ); @@ -148,10 +147,11 @@ private static TextEmbeddingResults parseObjectFormat(XContentParser parser) thr return new TextEmbeddingResults(embeddingList); } - private static FloatEmbedding parseEmbeddingEntry(XContentParser parser) throws IOException { + private static TextEmbeddingResults.Embedding parseEmbeddingEntry(XContentParser parser) throws IOException { XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.currentToken(), parser); + List embeddingValuesList = XContentParserUtils.parseList(parser, HuggingFaceEmbeddingsResponseEntity::parseEmbeddingList); - return FloatEmbedding.of(embeddingValuesList); + return TextEmbeddingResults.Embedding.of(embeddingValuesList); } private static float parseEmbeddingList(XContentParser parser) throws IOException { diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntity.java index 18d4e78cf0bfe..39b97014c3619 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntity.java @@ -15,7 +15,6 @@ import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -84,7 +83,7 @@ public static TextEmbeddingResults fromResponse(Request request, HttpResult resp positionParserAtTokenAfterField(jsonParser, "data", FAILED_TO_FIND_FIELD_TEMPLATE); - List embeddingList = XContentParserUtils.parseList( + List embeddingList = XContentParserUtils.parseList( jsonParser, OpenAiEmbeddingsResponseEntity::parseEmbeddingObject ); @@ -93,7 +92,7 @@ public static TextEmbeddingResults fromResponse(Request request, HttpResult resp } } - private static FloatEmbedding parseEmbeddingObject(XContentParser parser) throws IOException { + private static TextEmbeddingResults.Embedding parseEmbeddingObject(XContentParser parser) throws IOException { XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser); positionParserAtTokenAfterField(parser, "embedding", FAILED_TO_FIND_FIELD_TEMPLATE); @@ -102,7 +101,7 @@ private static FloatEmbedding parseEmbeddingObject(XContentParser parser) throws // parse and discard the rest of the object consumeUntilObjectEnd(parser); - return FloatEmbedding.of(embeddingValuesList); + return TextEmbeddingResults.Embedding.of(embeddingValuesList); } private static float parseEmbeddingList(XContentParser parser) throws IOException { diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/common/EmbeddingRequestChunkerTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/common/EmbeddingRequestChunkerTests.java index 2dd9a3fde30d1..164f975cc464f 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/common/EmbeddingRequestChunkerTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/common/EmbeddingRequestChunkerTests.java @@ -10,15 +10,8 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.inference.ChunkedInferenceServiceResults; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.ByteEmbedding; -import org.elasticsearch.xpack.core.inference.results.ChunkedSparseEmbeddingResults; -import org.elasticsearch.xpack.core.inference.results.ChunkedTextEmbeddingByteResults; import org.elasticsearch.xpack.core.inference.results.ChunkedTextEmbeddingFloatResults; import org.elasticsearch.xpack.core.inference.results.ErrorChunkedInferenceResults; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; -import org.elasticsearch.xpack.core.inference.results.SparseEmbedding; -import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; -import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; import java.util.ArrayList; @@ -26,7 +19,6 @@ import java.util.concurrent.atomic.AtomicReference; import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.startsWith; @@ -165,7 +157,7 @@ public void testLongInputChunkedOverMultipleBatches() { } } - public void testMergingListenerFloatEmbedding() { + public void testMergingListener() { int batchSize = 5; int chunkSize = 20; int overlap = 0; @@ -177,7 +169,7 @@ public void testMergingListenerFloatEmbedding() { for (int i = 0; i < numberOfWordsInPassage; i++) { passageBuilder.append("passage_input").append(i).append(" "); // chunk on whitespace } - List inputs = List.of("1st small", passageBuilder.toString()); + List inputs = List.of("1st small", passageBuilder.toString(), "2nd small", "3rd small"); var finalListener = testListener(); var batches = new EmbeddingRequestChunker(inputs, batchSize, chunkSize, overlap).batchRequestsWithListeners(finalListener); @@ -185,22 +177,22 @@ public void testMergingListenerFloatEmbedding() { // 4 inputs in 2 batches { - var embeddings = new ArrayList(); + var embeddings = new ArrayList(); for (int i = 0; i < batchSize; i++) { - embeddings.add(FloatEmbedding.of(List.of(randomFloat()))); + embeddings.add(new TextEmbeddingResults.Embedding(new float[] { randomFloat() })); } batches.get(0).listener().onResponse(new TextEmbeddingResults(embeddings)); } { - var embeddings = new ArrayList(); - for (int i = 0; i < 2; i++) { // 2 requests in the 2nd batch - embeddings.add(FloatEmbedding.of(List.of(randomFloat()))); + var embeddings = new ArrayList(); + for (int i = 0; i < 4; i++) { // 4 requests in the 2nd batch + embeddings.add(new TextEmbeddingResults.Embedding(new float[] { randomFloat() })); } batches.get(1).listener().onResponse(new TextEmbeddingResults(embeddings)); } assertNotNull(finalListener.results); - assertThat(finalListener.results, hasSize(2)); + assertThat(finalListener.results, hasSize(4)); { var chunkedResult = finalListener.results.get(0); assertThat(chunkedResult, instanceOf(ChunkedTextEmbeddingFloatResults.class)); @@ -221,147 +213,22 @@ public void testMergingListenerFloatEmbedding() { assertThat(chunkedFloatResult.chunks().get(4).matchedText(), startsWith(" passage_input80 ")); assertThat(chunkedFloatResult.chunks().get(5).matchedText(), startsWith(" passage_input100 ")); } - } - - public void testMergingListenerSparseEmbedding() { - int batchSize = 5; - int chunkSize = 20; - int overlap = 0; - // passage will be chunked into batchSize + 1 parts - // and spread over 2 batch requests - int numberOfWordsInPassage = (chunkSize * batchSize) + 5; - - var passageBuilder = new StringBuilder(); - for (int i = 0; i < numberOfWordsInPassage; i++) { - passageBuilder.append("passage_input").append(i).append(" "); // chunk on whitespace - } - List inputs = List.of("1st small", passageBuilder.toString()); - - var finalListener = testListener(); - var batches = new EmbeddingRequestChunker(inputs, batchSize, chunkSize, overlap).batchRequestsWithListeners(finalListener); - assertThat(batches, hasSize(2)); - - // 4 inputs in 2 batches { - var embeddings = new ArrayList(); - for (int i = 0; i < batchSize; i++) { - embeddings.add(new SparseEmbedding(List.of(new SparseEmbedding.WeightedToken("a", 1.0f)), false)); - } - batches.get(0).listener().onResponse(new SparseEmbeddingResults(embeddings)); - } - { - var embeddings = new ArrayList(); - for (int i = 0; i < 2; i++) { // 2 requests in the 2nd batch - embeddings.add(new SparseEmbedding(List.of(new SparseEmbedding.WeightedToken("b", 1.0f)), false)); - } - batches.get(1).listener().onResponse(new SparseEmbeddingResults(embeddings)); - } - - assertNotNull(finalListener.results); - assertThat(finalListener.results, hasSize(2)); - { - var chunkedResult = finalListener.results.get(0); - assertThat(chunkedResult, instanceOf(ChunkedSparseEmbeddingResults.class)); - var chunkedSparseResult = (ChunkedSparseEmbeddingResults) chunkedResult; - assertThat(chunkedSparseResult.getChunkedResults(), hasSize(1)); - assertEquals("1st small", chunkedSparseResult.getChunkedResults().get(0).matchedText()); - } - { - // this is the large input split in multiple chunks - var chunkedResult = finalListener.results.get(1); - assertThat(chunkedResult, instanceOf(ChunkedSparseEmbeddingResults.class)); - var chunkedSparseResult = (ChunkedSparseEmbeddingResults) chunkedResult; - assertThat(chunkedSparseResult.getChunkedResults(), hasSize(6)); - assertThat(chunkedSparseResult.getChunkedResults().get(0).matchedText(), startsWith("passage_input0 ")); - assertThat(chunkedSparseResult.getChunkedResults().get(1).matchedText(), startsWith(" passage_input20 ")); - assertThat(chunkedSparseResult.getChunkedResults().get(2).matchedText(), startsWith(" passage_input40 ")); - assertThat(chunkedSparseResult.getChunkedResults().get(3).matchedText(), startsWith(" passage_input60 ")); - assertThat(chunkedSparseResult.getChunkedResults().get(4).matchedText(), startsWith(" passage_input80 ")); - assertThat(chunkedSparseResult.getChunkedResults().get(5).matchedText(), startsWith(" passage_input100 ")); - } - } - - public void testMergingListenerByteEmbedding() { - int batchSize = 5; - int chunkSize = 20; - int overlap = 0; - // passage will be chunked into batchSize + 1 parts - // and spread over 2 batch requests - int numberOfWordsInPassage = (chunkSize * batchSize) + 5; - - var passageBuilder = new StringBuilder(); - for (int i = 0; i < numberOfWordsInPassage; i++) { - passageBuilder.append("passage_input").append(i).append(" "); // chunk on whitespace - } - List inputs = List.of("1st small", passageBuilder.toString()); - - var finalListener = testListener(); - var batches = new EmbeddingRequestChunker(inputs, batchSize, chunkSize, overlap).batchRequestsWithListeners(finalListener); - assertThat(batches, hasSize(2)); - - // 2 inputs in 2 batches - { - var embeddings = new ArrayList(); - for (int i = 0; i < batchSize; i++) { - embeddings.add(ByteEmbedding.of(List.of(randomByte()))); - } - batches.get(0).listener().onResponse(new TextEmbeddingByteResults(embeddings)); - } - { - var embeddings = new ArrayList(); - for (int i = 0; i < 2; i++) { // 2 requests in the 2nd batch - embeddings.add(ByteEmbedding.of(List.of(randomByte()))); - } - batches.get(1).listener().onResponse(new TextEmbeddingByteResults(embeddings)); - } - - assertNotNull(finalListener.results); - assertThat(finalListener.results, hasSize(2)); - { - var chunkedResult = finalListener.results.get(0); - assertThat(chunkedResult, instanceOf(ChunkedTextEmbeddingByteResults.class)); - var chunkedByteResult = (ChunkedTextEmbeddingByteResults) chunkedResult; - assertThat(chunkedByteResult.chunks(), hasSize(1)); - assertEquals("1st small", chunkedByteResult.chunks().get(0).matchedText()); + var chunkedResult = finalListener.results.get(2); + assertThat(chunkedResult, instanceOf(ChunkedTextEmbeddingFloatResults.class)); + var chunkedFloatResult = (ChunkedTextEmbeddingFloatResults) chunkedResult; + assertThat(chunkedFloatResult.chunks(), hasSize(1)); + assertEquals("2nd small", chunkedFloatResult.chunks().get(0).matchedText()); } { - // this is the large input split in multiple chunks - var chunkedResult = finalListener.results.get(1); - assertThat(chunkedResult, instanceOf(ChunkedTextEmbeddingByteResults.class)); - var chunkedByteResult = (ChunkedTextEmbeddingByteResults) chunkedResult; - assertThat(chunkedByteResult.chunks(), hasSize(6)); - assertThat(chunkedByteResult.chunks().get(0).matchedText(), startsWith("passage_input0 ")); - assertThat(chunkedByteResult.chunks().get(1).matchedText(), startsWith(" passage_input20 ")); - assertThat(chunkedByteResult.chunks().get(2).matchedText(), startsWith(" passage_input40 ")); - assertThat(chunkedByteResult.chunks().get(3).matchedText(), startsWith(" passage_input60 ")); - assertThat(chunkedByteResult.chunks().get(4).matchedText(), startsWith(" passage_input80 ")); - assertThat(chunkedByteResult.chunks().get(5).matchedText(), startsWith(" passage_input100 ")); + var chunkedResult = finalListener.results.get(3); + assertThat(chunkedResult, instanceOf(ChunkedTextEmbeddingFloatResults.class)); + var chunkedFloatResult = (ChunkedTextEmbeddingFloatResults) chunkedResult; + assertThat(chunkedFloatResult.chunks(), hasSize(1)); + assertEquals("3rd small", chunkedFloatResult.chunks().get(0).matchedText()); } } - public void testDifferentResponseTypes() { - List inputs = List.of("one", "two"); - var result = new AtomicReference>(); - - var listener = ActionListener.>wrap(result::set, e -> fail(e.getMessage())); - - var batches = new EmbeddingRequestChunker(inputs, 1, 100, 0).batchRequestsWithListeners(listener); - assertThat(batches, hasSize(2)); - - batches.get(0).listener().onResponse(new TextEmbeddingByteResults(List.of(ByteEmbedding.of(List.of(randomByte()))))); - batches.get(1).listener().onResponse(new TextEmbeddingResults(List.of(FloatEmbedding.of(List.of(randomFloat()))))); - - assertThat(result.get().get(0), instanceOf(ChunkedTextEmbeddingByteResults.class)); - assertThat(result.get().get(1), instanceOf(ErrorChunkedInferenceResults.class)); - assertThat( - ((ErrorChunkedInferenceResults) result.get().get(1)).getException().getMessage(), - containsString( - "The embedding response types are different. [TextEmbeddingResults] does not match the first response type " - + "[TextEmbeddingByteResults]" - ) - ); - } - public void testListenerErrorsWithWrongNumberOfResponses() { List inputs = List.of("1st small", "2nd small", "3rd small"); @@ -384,9 +251,9 @@ public void onFailure(Exception e) { var batches = new EmbeddingRequestChunker(inputs, 10, 100, 0).batchRequestsWithListeners(listener); assertThat(batches, hasSize(1)); - var embeddings = new ArrayList(); - embeddings.add(FloatEmbedding.of(List.of(randomFloat()))); - embeddings.add(FloatEmbedding.of(List.of(randomFloat()))); + var embeddings = new ArrayList(); + embeddings.add(new TextEmbeddingResults.Embedding(new float[] { randomFloat() })); + embeddings.add(new TextEmbeddingResults.Embedding(new float[] { randomFloat() })); batches.get(0).listener().onResponse(new TextEmbeddingResults(embeddings)); assertEquals("Error the number of embedding responses [2] does not equal the number of requests [3]", failureMessage.get()); } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/azureaistudio/AzureAiStudioEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/azureaistudio/AzureAiStudioEmbeddingsResponseEntityTests.java index e744b579924c8..41768a6814f36 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/azureaistudio/AzureAiStudioEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/azureaistudio/AzureAiStudioEmbeddingsResponseEntityTests.java @@ -9,7 +9,6 @@ import org.apache.http.HttpResponse; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -56,6 +55,6 @@ public void testFromResponse_CreatesResultsForASingleItem() throws IOException { new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat(parsedResults.embeddings(), is(List.of(FloatEmbedding.of(List.of(0.014539449F, -0.015288644F))))); + assertThat(parsedResults.embeddings(), is(List.of(TextEmbeddingResults.Embedding.of(List.of(0.014539449F, -0.015288644F))))); } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntityTests.java index d0f6f45974d1e..d809635aa4f38 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntityTests.java @@ -10,8 +10,6 @@ import org.apache.http.HttpResponse; import org.elasticsearch.inference.InferenceServiceResults; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.ByteEmbedding; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; @@ -60,7 +58,7 @@ public void testFromResponse_CreatesResultsForASingleItem() throws IOException { MatcherAssert.assertThat(parsedResults, instanceOf(TextEmbeddingResults.class)); MatcherAssert.assertThat( ((TextEmbeddingResults) parsedResults).embeddings(), - is(List.of(FloatEmbedding.of(List.of(-0.0018434525F, 0.01777649F)))) + is(List.of(new TextEmbeddingResults.Embedding(new float[] { -0.0018434525F, 0.01777649F }))) ); } @@ -96,7 +94,10 @@ public void testFromResponse_CreatesResultsForASingleItem_ObjectFormat() throws new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - MatcherAssert.assertThat(parsedResults.embeddings(), is(List.of(FloatEmbedding.of(List.of(-0.0018434525F, 0.01777649F))))); + MatcherAssert.assertThat( + parsedResults.embeddings(), + is(List.of(new TextEmbeddingResults.Embedding(new float[] { -0.0018434525F, 0.01777649F }))) + ); } public void testFromResponse_UsesTheFirstValidEmbeddingsEntry() throws IOException { @@ -137,7 +138,10 @@ public void testFromResponse_UsesTheFirstValidEmbeddingsEntry() throws IOExcepti new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - MatcherAssert.assertThat(parsedResults.embeddings(), is(List.of(FloatEmbedding.of(List.of(-0.0018434525F, 0.01777649F))))); + MatcherAssert.assertThat( + parsedResults.embeddings(), + is(List.of(new TextEmbeddingResults.Embedding(new float[] { -0.0018434525F, 0.01777649F }))) + ); } public void testFromResponse_UsesTheFirstValidEmbeddingsEntryInt8_WithInvalidFirst() throws IOException { @@ -178,7 +182,10 @@ public void testFromResponse_UsesTheFirstValidEmbeddingsEntryInt8_WithInvalidFir new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - MatcherAssert.assertThat(parsedResults.embeddings(), is(List.of(ByteEmbedding.of(List.of((byte) -1, (byte) 0))))); + MatcherAssert.assertThat( + parsedResults.embeddings(), + is(List.of(new TextEmbeddingByteResults.Embedding(new byte[] { (byte) -1, (byte) 0 }))) + ); } public void testFromResponse_ParsesBytes() throws IOException { @@ -213,7 +220,10 @@ public void testFromResponse_ParsesBytes() throws IOException { new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - MatcherAssert.assertThat(parsedResults.embeddings(), is(List.of(ByteEmbedding.of(List.of((byte) -1, (byte) 0))))); + MatcherAssert.assertThat( + parsedResults.embeddings(), + is(List.of(new TextEmbeddingByteResults.Embedding(new byte[] { (byte) -1, (byte) 0 }))) + ); } public void testFromResponse_CreatesResultsForMultipleItems() throws IOException { @@ -252,7 +262,12 @@ public void testFromResponse_CreatesResultsForMultipleItems() throws IOException MatcherAssert.assertThat( parsedResults.embeddings(), - is(List.of(FloatEmbedding.of(List.of(-0.0018434525F, 0.01777649F)), FloatEmbedding.of(List.of(-0.123F, 0.123F)))) + is( + List.of( + new TextEmbeddingResults.Embedding(new float[] { -0.0018434525F, 0.01777649F }), + new TextEmbeddingResults.Embedding(new float[] { -0.123F, 0.123F }) + ) + ) ); } @@ -294,7 +309,12 @@ public void testFromResponse_CreatesResultsForMultipleItems_ObjectFormat() throw MatcherAssert.assertThat( parsedResults.embeddings(), - is(List.of(FloatEmbedding.of(List.of(-0.0018434525F, 0.01777649F)), FloatEmbedding.of(List.of(-0.123F, 0.123F)))) + is( + List.of( + new TextEmbeddingResults.Embedding(new float[] { -0.0018434525F, 0.01777649F }), + new TextEmbeddingResults.Embedding(new float[] { -0.123F, 0.123F }) + ) + ) ); } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntityTests.java index b69bb37d35c53..238dab5929139 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntityTests.java @@ -10,7 +10,6 @@ import org.apache.http.HttpResponse; import org.elasticsearch.common.ParsingException; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -38,7 +37,10 @@ public void testFromResponse_CreatesResultsForASingleItem_ArrayFormat() throws I new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat(parsedResults.embeddings(), is(List.of(FloatEmbedding.of(List.of(0.014539449F, -0.015288644F))))); + assertThat( + parsedResults.embeddings(), + is(List.of(new TextEmbeddingResults.Embedding(new float[] { 0.014539449F, -0.015288644F }))) + ); } public void testFromResponse_CreatesResultsForASingleItem_ObjectFormat() throws IOException { @@ -58,7 +60,10 @@ public void testFromResponse_CreatesResultsForASingleItem_ObjectFormat() throws new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat(parsedResults.embeddings(), is(List.of(FloatEmbedding.of(List.of(0.014539449F, -0.015288644F))))); + assertThat( + parsedResults.embeddings(), + is(List.of(new TextEmbeddingResults.Embedding(new float[] { 0.014539449F, -0.015288644F }))) + ); } public void testFromResponse_CreatesResultsForMultipleItems_ArrayFormat() throws IOException { @@ -82,7 +87,12 @@ public void testFromResponse_CreatesResultsForMultipleItems_ArrayFormat() throws assertThat( parsedResults.embeddings(), - is(List.of(FloatEmbedding.of(List.of(0.014539449F, -0.015288644F)), FloatEmbedding.of(List.of(0.0123F, -0.0123F)))) + is( + List.of( + new TextEmbeddingResults.Embedding(new float[] { 0.014539449F, -0.015288644F }), + new TextEmbeddingResults.Embedding(new float[] { 0.0123F, -0.0123F }) + ) + ) ); } @@ -109,7 +119,12 @@ public void testFromResponse_CreatesResultsForMultipleItems_ObjectFormat() throw assertThat( parsedResults.embeddings(), - is(List.of(FloatEmbedding.of(List.of(0.014539449F, -0.015288644F)), FloatEmbedding.of(List.of(0.0123F, -0.0123F)))) + is( + List.of( + new TextEmbeddingResults.Embedding(new float[] { 0.014539449F, -0.015288644F }), + new TextEmbeddingResults.Embedding(new float[] { 0.0123F, -0.0123F }) + ) + ) ); } @@ -245,7 +260,7 @@ public void testFromResponse_SucceedsWhenEmbeddingValueIsInt_ArrayFormat() throw new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat(parsedResults.embeddings(), is(List.of(FloatEmbedding.of(List.of(1.0F))))); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingResults.Embedding(new float[] { 1.0F })))); } public void testFromResponse_SucceedsWhenEmbeddingValueIsInt_ObjectFormat() throws IOException { @@ -264,7 +279,7 @@ public void testFromResponse_SucceedsWhenEmbeddingValueIsInt_ObjectFormat() thro new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat(parsedResults.embeddings(), is(List.of(FloatEmbedding.of(List.of(1.0F))))); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingResults.Embedding(new float[] { 1.0F })))); } public void testFromResponse_SucceedsWhenEmbeddingValueIsLong_ArrayFormat() throws IOException { @@ -281,7 +296,7 @@ public void testFromResponse_SucceedsWhenEmbeddingValueIsLong_ArrayFormat() thro new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat(parsedResults.embeddings(), is(List.of(FloatEmbedding.of(List.of(4.0294965E10F))))); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingResults.Embedding(new float[] { 4.0294965E10F })))); } public void testFromResponse_SucceedsWhenEmbeddingValueIsLong_ObjectFormat() throws IOException { @@ -300,7 +315,7 @@ public void testFromResponse_SucceedsWhenEmbeddingValueIsLong_ObjectFormat() thr new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat(parsedResults.embeddings(), is(List.of(FloatEmbedding.of(List.of(4.0294965E10F))))); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingResults.Embedding(new float[] { 4.0294965E10F })))); } public void testFromResponse_FailsWhenEmbeddingValueIsAnObject_ObjectFormat() { diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntityTests.java index 7299f7ab6ef7b..6c38092f509a7 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntityTests.java @@ -10,7 +10,6 @@ import org.apache.http.HttpResponse; import org.elasticsearch.common.ParsingException; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -50,7 +49,10 @@ public void testFromResponse_CreatesResultsForASingleItem() throws IOException { new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat(parsedResults.embeddings(), is(List.of(FloatEmbedding.of(List.of(0.014539449F, -0.015288644F))))); + assertThat( + parsedResults.embeddings(), + is(List.of(new TextEmbeddingResults.Embedding(new float[] { 0.014539449F, -0.015288644F }))) + ); } public void testFromResponse_CreatesResultsForMultipleItems() throws IOException { @@ -90,7 +92,12 @@ public void testFromResponse_CreatesResultsForMultipleItems() throws IOException assertThat( parsedResults.embeddings(), - is(List.of(FloatEmbedding.of(List.of(0.014539449F, -0.015288644F)), FloatEmbedding.of(List.of(0.0123F, -0.0123F)))) + is( + List.of( + new TextEmbeddingResults.Embedding(new float[] { 0.014539449F, -0.015288644F }), + new TextEmbeddingResults.Embedding(new float[] { 0.0123F, -0.0123F }) + ) + ) ); } @@ -257,7 +264,7 @@ public void testFromResponse_SucceedsWhenEmbeddingValueIsInt() throws IOExceptio new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat(parsedResults.embeddings(), is(List.of(FloatEmbedding.of(List.of(1.0F))))); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingResults.Embedding(new float[] { 1.0F })))); } public void testFromResponse_SucceedsWhenEmbeddingValueIsLong() throws IOException { @@ -286,7 +293,7 @@ public void testFromResponse_SucceedsWhenEmbeddingValueIsLong() throws IOExcepti new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat(parsedResults.embeddings(), is(List.of(FloatEmbedding.of(List.of(4.0294965E10F))))); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingResults.Embedding(new float[] { 4.0294965E10F })))); } public void testFromResponse_FailsWhenEmbeddingValueIsAnObject() { @@ -375,9 +382,9 @@ public void testFieldsInDifferentOrderServer() throws IOException { parsedResults.embeddings(), is( List.of( - FloatEmbedding.of(List.of(-0.9F, 0.5F, 0.3F)), - FloatEmbedding.of(List.of(0.1F, 0.5F)), - FloatEmbedding.of(List.of(0.5F, 0.5F)) + new TextEmbeddingResults.Embedding(new float[] { -0.9F, 0.5F, 0.3F }), + new TextEmbeddingResults.Embedding(new float[] { 0.1F, 0.5F }), + new TextEmbeddingResults.Embedding(new float[] { 0.5F, 0.5F }) ) ) ); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/RestInferenceActionTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/RestInferenceActionTests.java index eb9cf8324683f..8365ebdfad786 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/RestInferenceActionTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/RestInferenceActionTests.java @@ -15,7 +15,6 @@ import org.elasticsearch.test.rest.RestActionTestCase; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ByteEmbedding; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; import org.junit.Before; @@ -76,6 +75,8 @@ public void testUses3SecondTimeoutFromParams() { } private static InferenceAction.Response createResponse() { - return new InferenceAction.Response(new TextEmbeddingByteResults(List.of(ByteEmbedding.of(List.of((byte) -1))))); + return new InferenceAction.Response( + new TextEmbeddingByteResults(List.of(new TextEmbeddingByteResults.Embedding(new byte[] { (byte) -1 }))) + ); } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedSparseEmbeddingResultsTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedSparseEmbeddingResultsTests.java index 392a49be7cd42..073a662c1e8f2 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedSparseEmbeddingResultsTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedSparseEmbeddingResultsTests.java @@ -11,7 +11,6 @@ import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.test.AbstractWireSerializingTestCase; import org.elasticsearch.xpack.core.inference.results.ChunkedSparseEmbeddingResults; -import org.elasticsearch.xpack.core.inference.results.SparseEmbedding; import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; import org.elasticsearch.xpack.core.ml.inference.results.ChunkedNlpInferenceResults; import org.elasticsearch.xpack.core.ml.inference.results.ChunkedTextExpansionResults; @@ -74,7 +73,7 @@ public void testToXContent_CreatesTheRightJsonForASingleChunk() { public void testToXContent_CreatesTheRightJsonForASingleChunk_FromSparseEmbeddingResults() { var entity = ChunkedSparseEmbeddingResults.of( List.of("text"), - new SparseEmbeddingResults(List.of(new SparseEmbedding(List.of(new SparseEmbedding.WeightedToken("token", 0.1f)), false))) + new SparseEmbeddingResults(List.of(new SparseEmbeddingResults.Embedding(List.of(new WeightedToken("token", 0.1f)), false))) ); assertThat(entity.size(), is(1)); @@ -110,7 +109,7 @@ public void testToXContent_ThrowsWhenInputSizeIsDifferentThanEmbeddings() { IllegalArgumentException.class, () -> ChunkedSparseEmbeddingResults.of( List.of("text", "text2"), - new SparseEmbeddingResults(List.of(new SparseEmbedding(List.of(new SparseEmbedding.WeightedToken("token", 0.1f)), false))) + new SparseEmbeddingResults(List.of(new SparseEmbeddingResults.Embedding(List.of(new WeightedToken("token", 0.1f)), false))) ) ); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedTextEmbeddingByteResultsTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedTextEmbeddingByteResultsTests.java index cc1b000644dad..6d6fbe956280a 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedTextEmbeddingByteResultsTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedTextEmbeddingByteResultsTests.java @@ -10,9 +10,7 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.test.AbstractWireSerializingTestCase; -import org.elasticsearch.xpack.core.inference.results.ByteEmbedding; import org.elasticsearch.xpack.core.inference.results.ChunkedTextEmbeddingByteResults; -import org.elasticsearch.xpack.core.inference.results.EmbeddingChunk; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; import java.io.IOException; @@ -26,7 +24,7 @@ public class ChunkedTextEmbeddingByteResultsTests extends AbstractWireSerializin public static ChunkedTextEmbeddingByteResults createRandomResults() { int numChunks = randomIntBetween(1, 5); - var chunks = new ArrayList>(numChunks); + var chunks = new ArrayList(numChunks); for (int i = 0; i < numChunks; i++) { chunks.add(createRandomChunk()); @@ -35,25 +33,28 @@ public static ChunkedTextEmbeddingByteResults createRandomResults() { return new ChunkedTextEmbeddingByteResults(chunks, randomBoolean()); } - private static EmbeddingChunk createRandomChunk() { + private static ChunkedTextEmbeddingByteResults.EmbeddingChunk createRandomChunk() { int columns = randomIntBetween(1, 10); byte[] bytes = new byte[columns]; for (int i = 0; i < columns; i++) { bytes[i] = randomByte(); } - return new EmbeddingChunk<>(randomAlphaOfLength(6), new ByteEmbedding(bytes)); + return new ChunkedTextEmbeddingByteResults.EmbeddingChunk(randomAlphaOfLength(6), bytes); } public void testToXContent_CreatesTheRightJsonForASingleChunk() { - var entity = new ChunkedTextEmbeddingByteResults(List.of(new EmbeddingChunk<>("text", ByteEmbedding.of(List.of((byte) 1)))), false); + var entity = new ChunkedTextEmbeddingByteResults( + List.of(new ChunkedTextEmbeddingByteResults.EmbeddingChunk("text", new byte[] { (byte) 1 })), + false + ); assertThat( entity.asMap(), is( Map.of( ChunkedTextEmbeddingByteResults.FIELD_NAME, - List.of(new EmbeddingChunk<>("text", new ByteEmbedding(new byte[] { (byte) 1 }))) + List.of(new ChunkedTextEmbeddingByteResults.EmbeddingChunk("text", new byte[] { (byte) 1 })) ) ) ); @@ -74,7 +75,7 @@ public void testToXContent_CreatesTheRightJsonForASingleChunk() { public void testToXContent_CreatesTheRightJsonForASingleChunk_ForTextEmbeddingByteResults() { var entity = ChunkedTextEmbeddingByteResults.of( List.of("text"), - new TextEmbeddingByteResults(List.of(ByteEmbedding.of(List.of((byte) 1)))) + new TextEmbeddingByteResults(List.of(new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 1 }))) ); assertThat(entity.size(), is(1)); @@ -86,7 +87,7 @@ public void testToXContent_CreatesTheRightJsonForASingleChunk_ForTextEmbeddingBy is( Map.of( ChunkedTextEmbeddingByteResults.FIELD_NAME, - List.of(new EmbeddingChunk<>("text", new ByteEmbedding(new byte[] { (byte) 1 }))) + List.of(new ChunkedTextEmbeddingByteResults.EmbeddingChunk("text", new byte[] { (byte) 1 })) ) ) ); @@ -109,7 +110,7 @@ public void testToXContent_ThrowsWhenInputSizeIsDifferentThanEmbeddings() { IllegalArgumentException.class, () -> ChunkedTextEmbeddingByteResults.of( List.of("text", "text2"), - new TextEmbeddingByteResults(List.of(ByteEmbedding.of(List.of((byte) 1)))) + new TextEmbeddingByteResults(List.of(new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 1 }))) ) ); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedTextEmbeddingFloatResultsTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedTextEmbeddingFloatResultsTests.java index 461bf793996af..beb75fbfa36a6 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedTextEmbeddingFloatResultsTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedTextEmbeddingFloatResultsTests.java @@ -10,8 +10,6 @@ import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.test.AbstractWireSerializingTestCase; import org.elasticsearch.xpack.core.inference.results.ChunkedTextEmbeddingFloatResults; -import org.elasticsearch.xpack.core.inference.results.EmbeddingChunk; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; import java.io.IOException; import java.util.ArrayList; @@ -20,7 +18,7 @@ public class ChunkedTextEmbeddingFloatResultsTests extends AbstractWireSerializi public static ChunkedTextEmbeddingFloatResults createRandomResults() { int numChunks = randomIntBetween(1, 5); - var chunks = new ArrayList>(numChunks); + var chunks = new ArrayList(numChunks); for (int i = 0; i < numChunks; i++) { chunks.add(createRandomChunk()); @@ -29,14 +27,14 @@ public static ChunkedTextEmbeddingFloatResults createRandomResults() { return new ChunkedTextEmbeddingFloatResults(chunks); } - private static EmbeddingChunk createRandomChunk() { + private static ChunkedTextEmbeddingFloatResults.EmbeddingChunk createRandomChunk() { int columns = randomIntBetween(1, 10); float[] floats = new float[columns]; for (int i = 0; i < columns; i++) { floats[i] = randomFloat(); } - return new EmbeddingChunk<>(randomAlphaOfLength(6), new FloatEmbedding(floats)); + return new ChunkedTextEmbeddingFloatResults.EmbeddingChunk(randomAlphaOfLength(6), floats); } @Override diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedTextEmbeddingResultsTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedTextEmbeddingResultsTests.java index 935180cce5d95..1fc0282b5d96d 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedTextEmbeddingResultsTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/ChunkedTextEmbeddingResultsTests.java @@ -11,7 +11,6 @@ import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.test.AbstractWireSerializingTestCase; import org.elasticsearch.xpack.core.inference.results.ChunkedTextEmbeddingResults; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; import org.elasticsearch.xpack.core.ml.inference.results.ChunkedNlpInferenceResults; @@ -98,7 +97,7 @@ public void testToXContent_CreatesTheRightJsonForASingleChunk() { public void testToXContent_CreatesTheRightJsonForASingleChunk_FromTextEmbeddingResults() { var entity = ChunkedTextEmbeddingResults.of( List.of("text"), - new TextEmbeddingResults(List.of(FloatEmbedding.of(List.of(0.1f, 0.2f)))) + new TextEmbeddingResults(List.of(new TextEmbeddingResults.Embedding(new float[] { 0.1f, 0.2f }))) ); assertThat(entity.size(), is(1)); @@ -141,7 +140,7 @@ public void testToXContent_ThrowsWhenInputSizeIsDifferentThanEmbeddings() { IllegalArgumentException.class, () -> ChunkedTextEmbeddingResults.of( List.of("text", "text2"), - new TextEmbeddingResults(List.of(FloatEmbedding.of(List.of(0.1f, 0.2f)))) + new TextEmbeddingResults(List.of(new TextEmbeddingResults.Embedding(new float[] { 0.1f, 0.2f }))) ) ); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/SparseEmbeddingResultsTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/SparseEmbeddingResultsTests.java index acc0ef6eed269..dcdbc13f097b6 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/SparseEmbeddingResultsTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/SparseEmbeddingResultsTests.java @@ -10,7 +10,6 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.test.AbstractWireSerializingTestCase; -import org.elasticsearch.xpack.core.inference.results.SparseEmbedding; import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; import org.elasticsearch.xpack.core.ml.inference.results.TextExpansionResults; import org.elasticsearch.xpack.core.ml.search.WeightedToken; @@ -32,7 +31,7 @@ public static SparseEmbeddingResults createRandomResults() { } public static SparseEmbeddingResults createRandomResults(int numEmbeddings, int numTokens) { - List embeddings = new ArrayList<>(numEmbeddings); + List embeddings = new ArrayList<>(numEmbeddings); for (int i = 0; i < numEmbeddings; i++) { embeddings.add(createRandomEmbedding(numTokens)); @@ -42,7 +41,7 @@ public static SparseEmbeddingResults createRandomResults(int numEmbeddings, int } public static SparseEmbeddingResults createRandomResults(List input) { - List embeddings = new ArrayList<>(input.size()); + List embeddings = new ArrayList<>(input.size()); for (String s : input) { int numTokens = Strings.tokenizeToStringArray(s, " ").length; @@ -52,13 +51,13 @@ public static SparseEmbeddingResults createRandomResults(List input) { return new SparseEmbeddingResults(embeddings); } - private static SparseEmbedding createRandomEmbedding(int numTokens) { - List tokenList = new ArrayList<>(numTokens); + private static SparseEmbeddingResults.Embedding createRandomEmbedding(int numTokens) { + List tokenList = new ArrayList<>(numTokens); for (int i = 0; i < numTokens; i++) { - tokenList.add(new SparseEmbedding.WeightedToken(Integer.toString(i), (float) randomDoubleBetween(0.0, 5.0, false))); + tokenList.add(new WeightedToken(Integer.toString(i), (float) randomDoubleBetween(0.0, 5.0, false))); } - return new SparseEmbedding(tokenList, randomBoolean()); + return new SparseEmbeddingResults.Embedding(tokenList, randomBoolean()); } @Override @@ -79,14 +78,14 @@ protected SparseEmbeddingResults mutateInstance(SparseEmbeddingResults instance) int end = randomInt(instance.embeddings().size() - 1); return new SparseEmbeddingResults(instance.embeddings().subList(0, end)); } else { - List embeddings = new ArrayList<>(instance.embeddings()); + List embeddings = new ArrayList<>(instance.embeddings()); embeddings.add(createRandomEmbedding(randomIntBetween(0, 20))); return new SparseEmbeddingResults(embeddings); } } public void testToXContent_CreatesTheRightFormatForASingleEmbedding() throws IOException { - var entity = createSparseResult(List.of(createEmbedding(List.of(new SparseEmbedding.WeightedToken("token", 0.1F)), false))); + var entity = createSparseResult(List.of(createEmbedding(List.of(new WeightedToken("token", 0.1F)), false))); assertThat(entity.asMap(), is(buildExpectationSparseEmbeddings(List.of(new EmbeddingExpectation(Map.of("token", 0.1F), false))))); String xContentResult = Strings.toString(entity, true, true); assertThat(xContentResult, is(""" @@ -105,14 +104,8 @@ public void testToXContent_CreatesTheRightFormatForASingleEmbedding() throws IOE public void testToXContent_CreatesTheRightFormatForMultipleEmbeddings() throws IOException { var entity = createSparseResult( List.of( - new SparseEmbedding( - List.of(new SparseEmbedding.WeightedToken("token", 0.1F), new SparseEmbedding.WeightedToken("token2", 0.2F)), - false - ), - new SparseEmbedding( - List.of(new SparseEmbedding.WeightedToken("token3", 0.3F), new SparseEmbedding.WeightedToken("token4", 0.4F)), - false - ) + new SparseEmbeddingResults.Embedding(List.of(new WeightedToken("token", 0.1F), new WeightedToken("token2", 0.2F)), false), + new SparseEmbeddingResults.Embedding(List.of(new WeightedToken("token3", 0.3F), new WeightedToken("token4", 0.4F)), false) ) ); assertThat( @@ -152,8 +145,8 @@ public void testToXContent_CreatesTheRightFormatForMultipleEmbeddings() throws I public void testTransformToCoordinationFormat() { var results = createSparseResult( List.of( - createEmbedding(List.of(new SparseEmbedding.WeightedToken("token", 0.1F)), false), - createEmbedding(List.of(new SparseEmbedding.WeightedToken("token2", 0.2F)), true) + createEmbedding(List.of(new WeightedToken("token", 0.1F)), false), + createEmbedding(List.of(new WeightedToken("token2", 0.2F)), true) ) ).transformToCoordinationFormat(); @@ -174,16 +167,23 @@ public static Map buildExpectationSparseEmbeddings(List Map.of(SparseEmbedding.EMBEDDING, embedding.tokens, SparseEmbedding.IS_TRUNCATED, embedding.isTruncated)) + .map( + embedding -> Map.of( + SparseEmbeddingResults.Embedding.EMBEDDING, + embedding.tokens, + SparseEmbeddingResults.Embedding.IS_TRUNCATED, + embedding.isTruncated + ) + ) .toList() ); } - public static SparseEmbeddingResults createSparseResult(List embeddings) { + public static SparseEmbeddingResults createSparseResult(List embeddings) { return new SparseEmbeddingResults(embeddings); } - public static SparseEmbedding createEmbedding(List tokensList, boolean isTruncated) { - return new SparseEmbedding(tokensList, isTruncated); + public static SparseEmbeddingResults.Embedding createEmbedding(List tokensList, boolean isTruncated) { + return new SparseEmbeddingResults.Embedding(tokensList, isTruncated); } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingByteResultsTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingByteResultsTests.java index a07f75ec2c536..a15d6323d1315 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingByteResultsTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingByteResultsTests.java @@ -10,7 +10,6 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.test.AbstractWireSerializingTestCase; -import org.elasticsearch.xpack.core.inference.results.ByteEmbedding; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; import java.io.IOException; @@ -23,7 +22,7 @@ public class TextEmbeddingByteResultsTests extends AbstractWireSerializingTestCase { public static TextEmbeddingByteResults createRandomResults() { int embeddings = randomIntBetween(1, 10); - List embeddingResults = new ArrayList<>(embeddings); + List embeddingResults = new ArrayList<>(embeddings); for (int i = 0; i < embeddings; i++) { embeddingResults.add(createRandomEmbedding()); @@ -32,7 +31,7 @@ public static TextEmbeddingByteResults createRandomResults() { return new TextEmbeddingByteResults(embeddingResults); } - private static ByteEmbedding createRandomEmbedding() { + private static TextEmbeddingByteResults.Embedding createRandomEmbedding() { int columns = randomIntBetween(1, 10); byte[] bytes = new byte[columns]; @@ -40,11 +39,11 @@ private static ByteEmbedding createRandomEmbedding() { bytes[i] = randomByte(); } - return new ByteEmbedding(bytes); + return new TextEmbeddingByteResults.Embedding(bytes); } public void testToXContent_CreatesTheRightFormatForASingleEmbedding() throws IOException { - var entity = new TextEmbeddingByteResults(List.of(ByteEmbedding.of(List.of((byte) 23)))); + var entity = new TextEmbeddingByteResults(List.of(new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 23 }))); String xContentResult = Strings.toString(entity, true, true); assertThat(xContentResult, is(""" @@ -61,8 +60,10 @@ public void testToXContent_CreatesTheRightFormatForASingleEmbedding() throws IOE public void testToXContent_CreatesTheRightFormatForMultipleEmbeddings() throws IOException { var entity = new TextEmbeddingByteResults( - List.of(ByteEmbedding.of(List.of((byte) 23)), ByteEmbedding.of(List.of((byte) 24))) - + List.of( + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 23 }), + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 24 }) + ) ); String xContentResult = Strings.toString(entity, true, true); @@ -85,21 +86,24 @@ public void testToXContent_CreatesTheRightFormatForMultipleEmbeddings() throws I public void testTransformToCoordinationFormat() { var results = new TextEmbeddingByteResults( - List.of(ByteEmbedding.of(List.of((byte) 23, (byte) 24)), ByteEmbedding.of(List.of((byte) 25, (byte) 26))) + List.of( + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 23, (byte) 24 }), + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 25, (byte) 26 }) + ) ).transformToCoordinationFormat(); assertThat( results, is( List.of( - new org.elasticsearch.xpack.core.ml.inference.results.TextEmbeddingByteResults( + new org.elasticsearch.xpack.core.ml.inference.results.TextEmbeddingResults( TextEmbeddingByteResults.TEXT_EMBEDDING_BYTES, - new byte[] { 23, 24 }, + new double[] { 23F, 24F }, false ), - new org.elasticsearch.xpack.core.ml.inference.results.TextEmbeddingByteResults( + new org.elasticsearch.xpack.core.ml.inference.results.TextEmbeddingResults( TextEmbeddingByteResults.TEXT_EMBEDDING_BYTES, - new byte[] { 25, 26 }, + new double[] { 25F, 26F }, false ) ) @@ -125,7 +129,7 @@ protected TextEmbeddingByteResults mutateInstance(TextEmbeddingByteResults insta int end = randomInt(instance.embeddings().size() - 1); return new TextEmbeddingByteResults(instance.embeddings().subList(0, end)); } else { - List embeddings = new ArrayList<>(instance.embeddings()); + List embeddings = new ArrayList<>(instance.embeddings()); embeddings.add(createRandomEmbedding()); return new TextEmbeddingByteResults(embeddings); } @@ -134,7 +138,7 @@ protected TextEmbeddingByteResults mutateInstance(TextEmbeddingByteResults insta public static Map buildExpectationByte(List> embeddings) { return Map.of( TextEmbeddingByteResults.TEXT_EMBEDDING_BYTES, - embeddings.stream().map(embedding -> Map.of(ByteEmbedding.EMBEDDING, embedding)).toList() + embeddings.stream().map(embedding -> Map.of(TextEmbeddingByteResults.Embedding.EMBEDDING, embedding)).toList() ); } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingResultsTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingResultsTests.java index bac25c9181dee..716568fdb5645 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingResultsTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingResultsTests.java @@ -10,8 +10,6 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.test.AbstractWireSerializingTestCase; -import org.elasticsearch.xpack.core.inference.results.ByteEmbedding; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; @@ -25,7 +23,7 @@ public class TextEmbeddingResultsTests extends AbstractWireSerializingTestCase { public static TextEmbeddingResults createRandomResults() { int embeddings = randomIntBetween(1, 10); - List embeddingResults = new ArrayList<>(embeddings); + List embeddingResults = new ArrayList<>(embeddings); for (int i = 0; i < embeddings; i++) { embeddingResults.add(createRandomEmbedding()); @@ -34,18 +32,18 @@ public static TextEmbeddingResults createRandomResults() { return new TextEmbeddingResults(embeddingResults); } - private static FloatEmbedding createRandomEmbedding() { + private static TextEmbeddingResults.Embedding createRandomEmbedding() { int columns = randomIntBetween(1, 10); float[] floats = new float[columns]; for (int i = 0; i < columns; i++) { floats[i] = randomFloat(); } - return new FloatEmbedding(floats); + return new TextEmbeddingResults.Embedding(floats); } public void testToXContent_CreatesTheRightFormatForASingleEmbedding() throws IOException { - var entity = new TextEmbeddingResults(List.of(FloatEmbedding.of(List.of(0.1F)))); + var entity = new TextEmbeddingResults(List.of(new TextEmbeddingResults.Embedding(new float[] { 0.1F }))); String xContentResult = Strings.toString(entity, true, true); assertThat(xContentResult, is(""" @@ -61,7 +59,10 @@ public void testToXContent_CreatesTheRightFormatForASingleEmbedding() throws IOE } public void testToXContent_CreatesTheRightFormatForMultipleEmbeddings() throws IOException { - var entity = new TextEmbeddingResults(List.of(FloatEmbedding.of(List.of(0.1F)), FloatEmbedding.of(List.of(0.2F)))); + var entity = new TextEmbeddingResults( + List.of(new TextEmbeddingResults.Embedding(new float[] { 0.1F }), new TextEmbeddingResults.Embedding(new float[] { 0.2F })) + + ); String xContentResult = Strings.toString(entity, true, true); assertThat(xContentResult, is(""" @@ -82,8 +83,12 @@ public void testToXContent_CreatesTheRightFormatForMultipleEmbeddings() throws I } public void testTransformToCoordinationFormat() { - var results = new TextEmbeddingResults(List.of(FloatEmbedding.of(List.of(0.1F, 0.2F)), FloatEmbedding.of(List.of(0.3F, 0.4F)))) - .transformToCoordinationFormat(); + var results = new TextEmbeddingResults( + List.of( + new TextEmbeddingResults.Embedding(new float[] { 0.1F, 0.2F }), + new TextEmbeddingResults.Embedding(new float[] { 0.3F, 0.4F }) + ) + ).transformToCoordinationFormat(); assertThat( results, @@ -122,18 +127,21 @@ protected TextEmbeddingResults mutateInstance(TextEmbeddingResults instance) thr int end = randomInt(instance.embeddings().size() - 1); return new TextEmbeddingResults(instance.embeddings().subList(0, end)); } else { - List embeddings = new ArrayList<>(instance.embeddings()); + List embeddings = new ArrayList<>(instance.embeddings()); embeddings.add(createRandomEmbedding()); return new TextEmbeddingResults(embeddings); } } public static Map buildExpectationFloat(List embeddings) { - return Map.of(TextEmbeddingResults.TEXT_EMBEDDING, embeddings.stream().map(FloatEmbedding::new).toList()); + return Map.of(TextEmbeddingResults.TEXT_EMBEDDING, embeddings.stream().map(TextEmbeddingResults.Embedding::new).toList()); } public static Map buildExpectationByte(List embeddings) { - return Map.of(TextEmbeddingByteResults.TEXT_EMBEDDING_BYTES, embeddings.stream().map(ByteEmbedding::new).toList()); + return Map.of( + TextEmbeddingByteResults.TEXT_EMBEDDING_BYTES, + embeddings.stream().map(TextEmbeddingByteResults.Embedding::new).toList() + ); } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/ServiceUtilsTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/ServiceUtilsTests.java index edd9637d92dd8..44e3f34ffcc15 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/ServiceUtilsTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/ServiceUtilsTests.java @@ -777,7 +777,7 @@ public void testGetEmbeddingSize_ReturnsSize_ForTextEmbeddingResults() { var size = listener.actionGet(TIMEOUT); - assertThat(size, is(textEmbedding.embeddings().get(0).getEmbedding().size())); + assertThat(size, is(textEmbedding.embeddings().get(0).getSize())); } public void testGetEmbeddingSize_ReturnsSize_ForTextEmbeddingByteResults() { @@ -801,7 +801,7 @@ public void testGetEmbeddingSize_ReturnsSize_ForTextEmbeddingByteResults() { var size = listener.actionGet(TIMEOUT); - assertThat(size, is(textEmbedding.embeddings().get(0).getEmbedding().size())); + assertThat(size, is(textEmbedding.embeddings().get(0).getSize())); } private static Map modifiableMap(Map aMap) { diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/CohereServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/CohereServiceTests.java index 66097e62c3ed8..f06fee4b0b9c4 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/CohereServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/CohereServiceTests.java @@ -33,7 +33,6 @@ import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; import org.elasticsearch.xpack.core.inference.results.ChunkedTextEmbeddingFloatResults; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSender; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSenderTests; @@ -52,6 +51,7 @@ import org.junit.Before; import java.io.IOException; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -1226,14 +1226,14 @@ public void testChunkedInfer_BatchesCalls() throws IOException { var floatResult = (ChunkedTextEmbeddingFloatResults) results.get(0); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("foo", floatResult.chunks().get(0).matchedText()); - assertEquals(FloatEmbedding.of(List.of(0.123f, -0.123f)), floatResult.chunks().get(0).embedding()); + assertTrue(Arrays.equals(new float[] { 0.123f, -0.123f }, floatResult.chunks().get(0).embedding())); } { assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedTextEmbeddingFloatResults.class)); var floatResult = (ChunkedTextEmbeddingFloatResults) results.get(1); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("bar", floatResult.chunks().get(0).matchedText()); - assertEquals(FloatEmbedding.of(List.of(0.223f, -0.223f)), floatResult.chunks().get(0).embedding()); + assertTrue(Arrays.equals(new float[] { 0.223f, -0.223f }, floatResult.chunks().get(0).embedding())); } MatcherAssert.assertThat(webServer.requests(), hasSize(1)); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/openai/OpenAiServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/openai/OpenAiServiceTests.java index 124b90e10dc88..cbac29c452772 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/openai/OpenAiServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/openai/OpenAiServiceTests.java @@ -32,7 +32,6 @@ import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; import org.elasticsearch.xpack.core.inference.results.ChunkedTextEmbeddingFloatResults; -import org.elasticsearch.xpack.core.inference.results.FloatEmbedding; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSender; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSenderTests; @@ -49,6 +48,7 @@ import org.junit.Before; import java.io.IOException; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -1267,14 +1267,14 @@ public void testChunkedInfer_Batches() throws IOException { var floatResult = (ChunkedTextEmbeddingFloatResults) results.get(0); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("foo", floatResult.chunks().get(0).matchedText()); - assertEquals(FloatEmbedding.of(List.of(0.123f, -0.123f)), floatResult.chunks().get(0).embedding()); + assertTrue(Arrays.equals(new float[] { 0.123f, -0.123f }, floatResult.chunks().get(0).embedding())); } { assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedTextEmbeddingFloatResults.class)); var floatResult = (ChunkedTextEmbeddingFloatResults) results.get(1); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("bar", floatResult.chunks().get(0).matchedText()); - assertEquals(FloatEmbedding.of(List.of(0.223f, -0.223f)), floatResult.chunks().get(0).embedding()); + assertTrue(Arrays.equals(new float[] { 0.223f, -0.223f }, floatResult.chunks().get(0).embedding())); } assertThat(webServer.requests(), hasSize(1)); From a73f52500b7c63277907f801740c48034fcbf397 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Tue, 28 May 2024 12:38:36 -0400 Subject: [PATCH 012/208] ESQL: Remove `nested` shims (#109105) This removes the shim layers for `nested` that we inherited from QL. ESQL doesn't support nested yet and when it does support nested its not going to use the same tricks that QL uses. --- .../esql/core/expression/FieldAttribute.java | 20 ------------------- .../core/planner/ExpressionTranslator.java | 10 ---------- .../core/planner/ExpressionTranslators.java | 5 ++--- .../esql/core/planner/TranslatorHandler.java | 2 +- .../planner/EsqlExpressionTranslators.java | 8 ++++---- .../esql/planner/EsqlTranslatorHandler.java | 3 +-- 6 files changed, 8 insertions(+), 40 deletions(-) diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/FieldAttribute.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/FieldAttribute.java index fc63ab5d8e7f2..9ee9732b542a0 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/FieldAttribute.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/FieldAttribute.java @@ -10,7 +10,6 @@ import org.elasticsearch.xpack.esql.core.tree.NodeInfo; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; -import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.core.type.EsField; import org.elasticsearch.xpack.esql.core.util.StringUtils; @@ -27,7 +26,6 @@ public class FieldAttribute extends TypedAttribute { private final FieldAttribute parent; - private final FieldAttribute nestedParent; private final String path; private final EsField field; @@ -67,16 +65,6 @@ public FieldAttribute( this.path = parent != null ? parent.name() : StringUtils.EMPTY; this.parent = parent; this.field = field; - - // figure out the last nested parent - FieldAttribute nestedPar = null; - if (parent != null) { - nestedPar = parent.nestedParent; - if (parent.dataType() == DataTypes.NESTED) { - nestedPar = parent; - } - } - this.nestedParent = nestedPar; } @Override @@ -97,14 +85,6 @@ public String qualifiedPath() { return qualifier() != null ? qualifier() + (Strings.hasText(path) ? "." + path : StringUtils.EMPTY) : path; } - public boolean isNested() { - return nestedParent != null; - } - - public FieldAttribute nestedParent() { - return nestedParent; - } - public EsField.Exact getExactInfo() { return field.getExactInfo(); } diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslator.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslator.java index 2efbd7fbc077d..db148e2d63fa1 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslator.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslator.java @@ -11,7 +11,6 @@ import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute; import org.elasticsearch.xpack.esql.core.expression.TypedAttribute; -import org.elasticsearch.xpack.esql.core.querydsl.query.NestedQuery; import org.elasticsearch.xpack.esql.core.querydsl.query.Query; import org.elasticsearch.xpack.esql.core.util.Check; import org.elasticsearch.xpack.esql.core.util.ReflectionUtils; @@ -27,15 +26,6 @@ public Query translate(Expression exp, TranslatorHandler handler) { protected abstract Query asQuery(E e, TranslatorHandler handler); - public static Query wrapIfNested(Query query, Expression exp) { - if (query != null && exp instanceof FieldAttribute fa) { - if (fa.isNested()) { - return new NestedQuery(fa.source(), fa.nestedParent().name(), query); - } - } - return query; - } - public static FieldAttribute checkIsFieldAttribute(Expression e) { Check.isTrue(e instanceof FieldAttribute, "Expected a FieldAttribute but received [{}]", e); return (FieldAttribute) e; diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslators.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslators.java index 39674a8a5a8b0..cf19b8722b258 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslators.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslators.java @@ -105,7 +105,7 @@ public static Query doTranslate(RegexMatch e, TranslatorHandler handler) { throw new QlIllegalArgumentException("Cannot translate query for " + e); } - return wrapIfNested(q, field); + return q; } private static Query translateField(RegexMatch e, String targetFieldName) { @@ -182,10 +182,9 @@ protected Query asQuery(Not not, TranslatorHandler handler) { } public static Query doTranslate(Not not, TranslatorHandler handler) { - Expression e = not.field(); Query wrappedQuery = handler.asQuery(not.field()); Query q = wrappedQuery.negate(not.source()); - return wrapIfNested(q, e); + return q; } } diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/TranslatorHandler.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/TranslatorHandler.java index 12c68ca425816..1ccbb04f7a69c 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/TranslatorHandler.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/TranslatorHandler.java @@ -27,7 +27,7 @@ public interface TranslatorHandler { default Query wrapFunctionQuery(ScalarFunction sf, Expression field, Supplier querySupplier) { if (field instanceof FieldAttribute) { - return ExpressionTranslator.wrapIfNested(querySupplier.get(), field); + return querySupplier.get(); } throw new QlIllegalArgumentException("Cannot translate expression:[" + sf.sourceText() + "]"); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java index 70aa39a6319db..d78d2d7f79d80 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java @@ -385,17 +385,17 @@ public static void checkSpatialRelatesFunction(Expression constantExpression, Sh * improvement overall. * TODO: Remove this method and call the parent method once the SingleValueQuery improvements have been made */ - public static Query wrapFunctionQuery(Expression field, Supplier querySupplier) { - return ExpressionTranslator.wrapIfNested(querySupplier.get(), field); + public static Query wrapFunctionQuery(Supplier querySupplier) { + return querySupplier.get(); } public static Query doTranslate(SpatialRelatesFunction bc, TranslatorHandler handler) { if (bc.left().foldable()) { checkSpatialRelatesFunction(bc.left(), bc.queryRelation()); - return wrapFunctionQuery(bc.right(), () -> translate(bc, handler, bc.right(), bc.left())); + return wrapFunctionQuery(() -> translate(bc, handler, bc.right(), bc.left())); } else { checkSpatialRelatesFunction(bc.right(), bc.queryRelation()); - return wrapFunctionQuery(bc.left(), () -> translate(bc, handler, bc.left(), bc.right())); + return wrapFunctionQuery(() -> translate(bc, handler, bc.left(), bc.right())); } } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlTranslatorHandler.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlTranslatorHandler.java index 3c4ae41117273..c07be82ed2a16 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlTranslatorHandler.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlTranslatorHandler.java @@ -15,7 +15,6 @@ import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNotNull; import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNull; -import org.elasticsearch.xpack.esql.core.planner.ExpressionTranslator; import org.elasticsearch.xpack.esql.core.planner.TranslatorHandler; import org.elasticsearch.xpack.esql.core.querydsl.query.Query; import org.elasticsearch.xpack.esql.core.type.DataType; @@ -50,7 +49,7 @@ public Query wrapFunctionQuery(ScalarFunction sf, Expression field, Supplier Date: Tue, 28 May 2024 13:32:30 -0400 Subject: [PATCH 013/208] ESQL: Add parsing for a LOOKUP command (#109040) This command will serve as a sort of "inline" enrich. This commit itself is mostly antlr generated code and paranoid tests that the new `LOOKUP` keyword doesn't clash with any variables named `lookup`. I've also marked our ANTLR generated files as `linguist-generated` which causes them to be hidden by default in github's UI. You can still click a button to see them if you like. See https://docs.github.com/en/repositories/working-with-files/managing-files/customizing-how-changed-files-appear-on-github --- .gitattributes | 5 + .../src/main/resources/lookup.csv-spec | 52 + .../esql/src/main/antlr/EsqlBaseLexer.g4 | 45 + .../esql/src/main/antlr/EsqlBaseLexer.tokens | 326 ++-- .../esql/src/main/antlr/EsqlBaseParser.g4 | 13 +- .../esql/src/main/antlr/EsqlBaseParser.tokens | 326 ++-- .../xpack/esql/action/EsqlCapabilities.java | 15 +- .../xpack/esql/parser/EsqlBaseLexer.interp | 34 +- .../xpack/esql/parser/EsqlBaseLexer.java | 1730 +++++++++-------- .../xpack/esql/parser/EsqlBaseParser.interp | 18 +- .../xpack/esql/parser/EsqlBaseParser.java | 1680 ++++++++-------- .../parser/EsqlBaseParserBaseListener.java | 24 + .../parser/EsqlBaseParserBaseVisitor.java | 14 + .../esql/parser/EsqlBaseParserListener.java | 20 + .../esql/parser/EsqlBaseParserVisitor.java | 12 + .../xpack/esql/parser/ExpressionBuilder.java | 44 +- .../xpack/esql/parser/LogicalPlanBuilder.java | 45 +- .../xpack/esql/analysis/AnalyzerTests.java | 9 + .../rest-api-spec/test/esql/150_lookup.yml | 42 + 19 files changed, 2494 insertions(+), 1960 deletions(-) create mode 100644 x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup.csv-spec create mode 100644 x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/150_lookup.yml diff --git a/.gitattributes b/.gitattributes index dfb3948ec7295..ebe1a34db3479 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,3 +3,8 @@ CHANGELOG.asciidoc merge=union # These files contain expected text output, and should not be changed on # Windows build-tools-internal/src/test/resources/org/elasticsearch/gradle/internal/release/*.asciidoc text eol=lf + +x-pack/plugin/esql/src/main/antlr/*.tokens linguist-generated=true +x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/*.interp linguist-generated=true +x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer*.java linguist-generated=true +x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser*.java linguist-generated=true diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup.csv-spec new file mode 100644 index 0000000000000..f6dc28fa5db12 --- /dev/null +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup.csv-spec @@ -0,0 +1,52 @@ + + + +// +// Make sure that the new LOOKUP syntax doesn't clash with any existing things +// named "lookup" +// +rowNamedLookup +ROW lookup = "a" +; + +lookup:keyword + a +; + +rowNamedLOOKUP +ROW LOOKUP = "a" +; + +LOOKUP:keyword + a +; + +evalNamedLookup +ROW a = "a" | EVAL lookup = CONCAT(a, "1") +; + +a:keyword | lookup:keyword + a | a1 +; + +dissectNamedLookup +row a = "foo bar" | dissect a "foo %{lookup}"; + +a:keyword | lookup:keyword + foo bar | bar +; + +renameIntoLookup +row a = "foo bar" | RENAME a AS lookup; + +lookup:keyword + foo bar +; + +sortOnLookup +ROW lookup = "a" | SORT lookup +; + +lookup:keyword + a +; diff --git a/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.g4 b/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.g4 index 3c4cf1a3383bd..fb424b16ac403 100644 --- a/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.g4 +++ b/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.g4 @@ -10,6 +10,7 @@ GROK : 'grok' -> pushMode(EXPRESSION_MODE); INLINESTATS : 'inlinestats' -> pushMode(EXPRESSION_MODE); KEEP : 'keep' -> pushMode(PROJECT_MODE); LIMIT : 'limit' -> pushMode(EXPRESSION_MODE); +LOOKUP : 'lookup' -> pushMode(LOOKUP_MODE); META : 'meta' -> pushMode(META_MODE); METRICS : 'metrics' -> pushMode(METRICS_MODE); MV_EXPAND : 'mv_expand' -> pushMode(MVEXPAND_MODE); @@ -344,6 +345,50 @@ ENRICH_FIELD_WS : WS -> channel(HIDDEN) ; +// LOOKUP ON key +mode LOOKUP_MODE; +LOOKUP_PIPE : PIPE -> type(PIPE), popMode; +LOOKUP_COMMA : COMMA -> type(COMMA); +LOOKUP_DOT: DOT -> type(DOT); +LOOKUP_ON : ON -> type(ON), pushMode(LOOKUP_FIELD_MODE); + +LOOKUP_INDEX_UNQUOTED_IDENTIFIER + : INDEX_UNQUOTED_IDENTIFIER -> type(INDEX_UNQUOTED_IDENTIFIER) + ; + +LOOKUP_LINE_COMMENT + : LINE_COMMENT -> channel(HIDDEN) + ; + +LOOKUP_MULTILINE_COMMENT + : MULTILINE_COMMENT -> channel(HIDDEN) + ; + +LOOKUP_WS + : WS -> channel(HIDDEN) + ; + +mode LOOKUP_FIELD_MODE; +LOOKUP_FIELD_PIPE : PIPE -> type(PIPE), popMode, popMode; +LOOKUP_FIELD_COMMA : COMMA -> type(COMMA); +LOOKUP_FIELD_DOT: DOT -> type(DOT); + +LOOKUP_FIELD_ID_PATTERN + : ID_PATTERN -> type(ID_PATTERN) + ; + +LOOKUP_FIELD_LINE_COMMENT + : LINE_COMMENT -> channel(HIDDEN) + ; + +LOOKUP_FIELD_MULTILINE_COMMENT + : MULTILINE_COMMENT -> channel(HIDDEN) + ; + +LOOKUP_FIELD_WS + : WS -> channel(HIDDEN) + ; + mode MVEXPAND_MODE; MVEXPAND_PIPE : PIPE -> type(PIPE), popMode; MVEXPAND_DOT: DOT -> type(DOT); diff --git a/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.tokens b/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.tokens index 0e2d796eda847..30ce0d5eea55b 100644 --- a/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.tokens +++ b/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.tokens @@ -8,112 +8,119 @@ GROK=7 INLINESTATS=8 KEEP=9 LIMIT=10 -META=11 -METRICS=12 -MV_EXPAND=13 -RENAME=14 -ROW=15 -SHOW=16 -SORT=17 -STATS=18 -WHERE=19 -UNKNOWN_CMD=20 -LINE_COMMENT=21 -MULTILINE_COMMENT=22 -WS=23 -INDEX_UNQUOTED_IDENTIFIER=24 -EXPLAIN_WS=25 -EXPLAIN_LINE_COMMENT=26 -EXPLAIN_MULTILINE_COMMENT=27 -PIPE=28 -QUOTED_STRING=29 -INTEGER_LITERAL=30 -DECIMAL_LITERAL=31 -BY=32 -AND=33 -ASC=34 -ASSIGN=35 -CAST_OP=36 -COMMA=37 -DESC=38 -DOT=39 -FALSE=40 -FIRST=41 -LAST=42 -LP=43 -IN=44 -IS=45 -LIKE=46 -NOT=47 -NULL=48 -NULLS=49 -OR=50 -PARAM=51 -RLIKE=52 -RP=53 -TRUE=54 -EQ=55 -CIEQ=56 -NEQ=57 -LT=58 -LTE=59 -GT=60 -GTE=61 -PLUS=62 -MINUS=63 -ASTERISK=64 -SLASH=65 -PERCENT=66 -OPENING_BRACKET=67 -CLOSING_BRACKET=68 -UNQUOTED_IDENTIFIER=69 -QUOTED_IDENTIFIER=70 -EXPR_LINE_COMMENT=71 -EXPR_MULTILINE_COMMENT=72 -EXPR_WS=73 -METADATA=74 -FROM_LINE_COMMENT=75 -FROM_MULTILINE_COMMENT=76 -FROM_WS=77 -ID_PATTERN=78 -PROJECT_LINE_COMMENT=79 -PROJECT_MULTILINE_COMMENT=80 -PROJECT_WS=81 -AS=82 -RENAME_LINE_COMMENT=83 -RENAME_MULTILINE_COMMENT=84 -RENAME_WS=85 -ON=86 -WITH=87 -ENRICH_POLICY_NAME=88 -ENRICH_LINE_COMMENT=89 -ENRICH_MULTILINE_COMMENT=90 -ENRICH_WS=91 -ENRICH_FIELD_LINE_COMMENT=92 -ENRICH_FIELD_MULTILINE_COMMENT=93 -ENRICH_FIELD_WS=94 -MVEXPAND_LINE_COMMENT=95 -MVEXPAND_MULTILINE_COMMENT=96 -MVEXPAND_WS=97 -INFO=98 -SHOW_LINE_COMMENT=99 -SHOW_MULTILINE_COMMENT=100 -SHOW_WS=101 -FUNCTIONS=102 -META_LINE_COMMENT=103 -META_MULTILINE_COMMENT=104 -META_WS=105 -COLON=106 -SETTING=107 -SETTING_LINE_COMMENT=108 -SETTTING_MULTILINE_COMMENT=109 -SETTING_WS=110 -METRICS_LINE_COMMENT=111 -METRICS_MULTILINE_COMMENT=112 -METRICS_WS=113 -CLOSING_METRICS_LINE_COMMENT=114 -CLOSING_METRICS_MULTILINE_COMMENT=115 -CLOSING_METRICS_WS=116 +LOOKUP=11 +META=12 +METRICS=13 +MV_EXPAND=14 +RENAME=15 +ROW=16 +SHOW=17 +SORT=18 +STATS=19 +WHERE=20 +UNKNOWN_CMD=21 +LINE_COMMENT=22 +MULTILINE_COMMENT=23 +WS=24 +INDEX_UNQUOTED_IDENTIFIER=25 +EXPLAIN_WS=26 +EXPLAIN_LINE_COMMENT=27 +EXPLAIN_MULTILINE_COMMENT=28 +PIPE=29 +QUOTED_STRING=30 +INTEGER_LITERAL=31 +DECIMAL_LITERAL=32 +BY=33 +AND=34 +ASC=35 +ASSIGN=36 +CAST_OP=37 +COMMA=38 +DESC=39 +DOT=40 +FALSE=41 +FIRST=42 +LAST=43 +LP=44 +IN=45 +IS=46 +LIKE=47 +NOT=48 +NULL=49 +NULLS=50 +OR=51 +PARAM=52 +RLIKE=53 +RP=54 +TRUE=55 +EQ=56 +CIEQ=57 +NEQ=58 +LT=59 +LTE=60 +GT=61 +GTE=62 +PLUS=63 +MINUS=64 +ASTERISK=65 +SLASH=66 +PERCENT=67 +OPENING_BRACKET=68 +CLOSING_BRACKET=69 +UNQUOTED_IDENTIFIER=70 +QUOTED_IDENTIFIER=71 +EXPR_LINE_COMMENT=72 +EXPR_MULTILINE_COMMENT=73 +EXPR_WS=74 +METADATA=75 +FROM_LINE_COMMENT=76 +FROM_MULTILINE_COMMENT=77 +FROM_WS=78 +ID_PATTERN=79 +PROJECT_LINE_COMMENT=80 +PROJECT_MULTILINE_COMMENT=81 +PROJECT_WS=82 +AS=83 +RENAME_LINE_COMMENT=84 +RENAME_MULTILINE_COMMENT=85 +RENAME_WS=86 +ON=87 +WITH=88 +ENRICH_POLICY_NAME=89 +ENRICH_LINE_COMMENT=90 +ENRICH_MULTILINE_COMMENT=91 +ENRICH_WS=92 +ENRICH_FIELD_LINE_COMMENT=93 +ENRICH_FIELD_MULTILINE_COMMENT=94 +ENRICH_FIELD_WS=95 +LOOKUP_LINE_COMMENT=96 +LOOKUP_MULTILINE_COMMENT=97 +LOOKUP_WS=98 +LOOKUP_FIELD_LINE_COMMENT=99 +LOOKUP_FIELD_MULTILINE_COMMENT=100 +LOOKUP_FIELD_WS=101 +MVEXPAND_LINE_COMMENT=102 +MVEXPAND_MULTILINE_COMMENT=103 +MVEXPAND_WS=104 +INFO=105 +SHOW_LINE_COMMENT=106 +SHOW_MULTILINE_COMMENT=107 +SHOW_WS=108 +FUNCTIONS=109 +META_LINE_COMMENT=110 +META_MULTILINE_COMMENT=111 +META_WS=112 +COLON=113 +SETTING=114 +SETTING_LINE_COMMENT=115 +SETTTING_MULTILINE_COMMENT=116 +SETTING_WS=117 +METRICS_LINE_COMMENT=118 +METRICS_MULTILINE_COMMENT=119 +METRICS_WS=120 +CLOSING_METRICS_LINE_COMMENT=121 +CLOSING_METRICS_MULTILINE_COMMENT=122 +CLOSING_METRICS_WS=123 'dissect'=1 'drop'=2 'enrich'=3 @@ -124,56 +131,57 @@ CLOSING_METRICS_WS=116 'inlinestats'=8 'keep'=9 'limit'=10 -'meta'=11 -'metrics'=12 -'mv_expand'=13 -'rename'=14 -'row'=15 -'show'=16 -'sort'=17 -'stats'=18 -'where'=19 -'|'=28 -'by'=32 -'and'=33 -'asc'=34 -'='=35 -'::'=36 -','=37 -'desc'=38 -'.'=39 -'false'=40 -'first'=41 -'last'=42 -'('=43 -'in'=44 -'is'=45 -'like'=46 -'not'=47 -'null'=48 -'nulls'=49 -'or'=50 -'?'=51 -'rlike'=52 -')'=53 -'true'=54 -'=='=55 -'=~'=56 -'!='=57 -'<'=58 -'<='=59 -'>'=60 -'>='=61 -'+'=62 -'-'=63 -'*'=64 -'/'=65 -'%'=66 -']'=68 -'metadata'=74 -'as'=82 -'on'=86 -'with'=87 -'info'=98 -'functions'=102 -':'=106 +'lookup'=11 +'meta'=12 +'metrics'=13 +'mv_expand'=14 +'rename'=15 +'row'=16 +'show'=17 +'sort'=18 +'stats'=19 +'where'=20 +'|'=29 +'by'=33 +'and'=34 +'asc'=35 +'='=36 +'::'=37 +','=38 +'desc'=39 +'.'=40 +'false'=41 +'first'=42 +'last'=43 +'('=44 +'in'=45 +'is'=46 +'like'=47 +'not'=48 +'null'=49 +'nulls'=50 +'or'=51 +'?'=52 +'rlike'=53 +')'=54 +'true'=55 +'=='=56 +'=~'=57 +'!='=58 +'<'=59 +'<='=60 +'>'=61 +'>='=62 +'+'=63 +'-'=64 +'*'=65 +'/'=66 +'%'=67 +']'=69 +'metadata'=75 +'as'=83 +'on'=87 +'with'=88 +'info'=105 +'functions'=109 +':'=113 diff --git a/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4 b/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4 index 7064856567d3e..29892d464c0e5 100644 --- a/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4 +++ b/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4 @@ -32,6 +32,7 @@ processingCommand : evalCommand | inlinestatsCommand | limitCommand + | lookupCommand | keepCommand | sortCommand | statsCommand @@ -150,6 +151,10 @@ qualifiedNamePattern : identifierPattern (DOT identifierPattern)* ; +qualifiedNamePatterns + : qualifiedNamePattern (COMMA qualifiedNamePattern)* + ; + identifier : UNQUOTED_IDENTIFIER | QUOTED_IDENTIFIER @@ -185,11 +190,11 @@ orderExpression ; keepCommand - : KEEP qualifiedNamePattern (COMMA qualifiedNamePattern)* + : KEEP qualifiedNamePatterns ; dropCommand - : DROP qualifiedNamePattern (COMMA qualifiedNamePattern)* + : DROP qualifiedNamePatterns ; renameCommand @@ -268,3 +273,7 @@ enrichCommand enrichWithClause : (newName=qualifiedNamePattern ASSIGN)? enrichField=qualifiedNamePattern ; + +lookupCommand + : LOOKUP tableName=INDEX_UNQUOTED_IDENTIFIER ON matchFields=qualifiedNamePatterns + ; diff --git a/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.tokens b/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.tokens index 0e2d796eda847..30ce0d5eea55b 100644 --- a/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.tokens +++ b/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.tokens @@ -8,112 +8,119 @@ GROK=7 INLINESTATS=8 KEEP=9 LIMIT=10 -META=11 -METRICS=12 -MV_EXPAND=13 -RENAME=14 -ROW=15 -SHOW=16 -SORT=17 -STATS=18 -WHERE=19 -UNKNOWN_CMD=20 -LINE_COMMENT=21 -MULTILINE_COMMENT=22 -WS=23 -INDEX_UNQUOTED_IDENTIFIER=24 -EXPLAIN_WS=25 -EXPLAIN_LINE_COMMENT=26 -EXPLAIN_MULTILINE_COMMENT=27 -PIPE=28 -QUOTED_STRING=29 -INTEGER_LITERAL=30 -DECIMAL_LITERAL=31 -BY=32 -AND=33 -ASC=34 -ASSIGN=35 -CAST_OP=36 -COMMA=37 -DESC=38 -DOT=39 -FALSE=40 -FIRST=41 -LAST=42 -LP=43 -IN=44 -IS=45 -LIKE=46 -NOT=47 -NULL=48 -NULLS=49 -OR=50 -PARAM=51 -RLIKE=52 -RP=53 -TRUE=54 -EQ=55 -CIEQ=56 -NEQ=57 -LT=58 -LTE=59 -GT=60 -GTE=61 -PLUS=62 -MINUS=63 -ASTERISK=64 -SLASH=65 -PERCENT=66 -OPENING_BRACKET=67 -CLOSING_BRACKET=68 -UNQUOTED_IDENTIFIER=69 -QUOTED_IDENTIFIER=70 -EXPR_LINE_COMMENT=71 -EXPR_MULTILINE_COMMENT=72 -EXPR_WS=73 -METADATA=74 -FROM_LINE_COMMENT=75 -FROM_MULTILINE_COMMENT=76 -FROM_WS=77 -ID_PATTERN=78 -PROJECT_LINE_COMMENT=79 -PROJECT_MULTILINE_COMMENT=80 -PROJECT_WS=81 -AS=82 -RENAME_LINE_COMMENT=83 -RENAME_MULTILINE_COMMENT=84 -RENAME_WS=85 -ON=86 -WITH=87 -ENRICH_POLICY_NAME=88 -ENRICH_LINE_COMMENT=89 -ENRICH_MULTILINE_COMMENT=90 -ENRICH_WS=91 -ENRICH_FIELD_LINE_COMMENT=92 -ENRICH_FIELD_MULTILINE_COMMENT=93 -ENRICH_FIELD_WS=94 -MVEXPAND_LINE_COMMENT=95 -MVEXPAND_MULTILINE_COMMENT=96 -MVEXPAND_WS=97 -INFO=98 -SHOW_LINE_COMMENT=99 -SHOW_MULTILINE_COMMENT=100 -SHOW_WS=101 -FUNCTIONS=102 -META_LINE_COMMENT=103 -META_MULTILINE_COMMENT=104 -META_WS=105 -COLON=106 -SETTING=107 -SETTING_LINE_COMMENT=108 -SETTTING_MULTILINE_COMMENT=109 -SETTING_WS=110 -METRICS_LINE_COMMENT=111 -METRICS_MULTILINE_COMMENT=112 -METRICS_WS=113 -CLOSING_METRICS_LINE_COMMENT=114 -CLOSING_METRICS_MULTILINE_COMMENT=115 -CLOSING_METRICS_WS=116 +LOOKUP=11 +META=12 +METRICS=13 +MV_EXPAND=14 +RENAME=15 +ROW=16 +SHOW=17 +SORT=18 +STATS=19 +WHERE=20 +UNKNOWN_CMD=21 +LINE_COMMENT=22 +MULTILINE_COMMENT=23 +WS=24 +INDEX_UNQUOTED_IDENTIFIER=25 +EXPLAIN_WS=26 +EXPLAIN_LINE_COMMENT=27 +EXPLAIN_MULTILINE_COMMENT=28 +PIPE=29 +QUOTED_STRING=30 +INTEGER_LITERAL=31 +DECIMAL_LITERAL=32 +BY=33 +AND=34 +ASC=35 +ASSIGN=36 +CAST_OP=37 +COMMA=38 +DESC=39 +DOT=40 +FALSE=41 +FIRST=42 +LAST=43 +LP=44 +IN=45 +IS=46 +LIKE=47 +NOT=48 +NULL=49 +NULLS=50 +OR=51 +PARAM=52 +RLIKE=53 +RP=54 +TRUE=55 +EQ=56 +CIEQ=57 +NEQ=58 +LT=59 +LTE=60 +GT=61 +GTE=62 +PLUS=63 +MINUS=64 +ASTERISK=65 +SLASH=66 +PERCENT=67 +OPENING_BRACKET=68 +CLOSING_BRACKET=69 +UNQUOTED_IDENTIFIER=70 +QUOTED_IDENTIFIER=71 +EXPR_LINE_COMMENT=72 +EXPR_MULTILINE_COMMENT=73 +EXPR_WS=74 +METADATA=75 +FROM_LINE_COMMENT=76 +FROM_MULTILINE_COMMENT=77 +FROM_WS=78 +ID_PATTERN=79 +PROJECT_LINE_COMMENT=80 +PROJECT_MULTILINE_COMMENT=81 +PROJECT_WS=82 +AS=83 +RENAME_LINE_COMMENT=84 +RENAME_MULTILINE_COMMENT=85 +RENAME_WS=86 +ON=87 +WITH=88 +ENRICH_POLICY_NAME=89 +ENRICH_LINE_COMMENT=90 +ENRICH_MULTILINE_COMMENT=91 +ENRICH_WS=92 +ENRICH_FIELD_LINE_COMMENT=93 +ENRICH_FIELD_MULTILINE_COMMENT=94 +ENRICH_FIELD_WS=95 +LOOKUP_LINE_COMMENT=96 +LOOKUP_MULTILINE_COMMENT=97 +LOOKUP_WS=98 +LOOKUP_FIELD_LINE_COMMENT=99 +LOOKUP_FIELD_MULTILINE_COMMENT=100 +LOOKUP_FIELD_WS=101 +MVEXPAND_LINE_COMMENT=102 +MVEXPAND_MULTILINE_COMMENT=103 +MVEXPAND_WS=104 +INFO=105 +SHOW_LINE_COMMENT=106 +SHOW_MULTILINE_COMMENT=107 +SHOW_WS=108 +FUNCTIONS=109 +META_LINE_COMMENT=110 +META_MULTILINE_COMMENT=111 +META_WS=112 +COLON=113 +SETTING=114 +SETTING_LINE_COMMENT=115 +SETTTING_MULTILINE_COMMENT=116 +SETTING_WS=117 +METRICS_LINE_COMMENT=118 +METRICS_MULTILINE_COMMENT=119 +METRICS_WS=120 +CLOSING_METRICS_LINE_COMMENT=121 +CLOSING_METRICS_MULTILINE_COMMENT=122 +CLOSING_METRICS_WS=123 'dissect'=1 'drop'=2 'enrich'=3 @@ -124,56 +131,57 @@ CLOSING_METRICS_WS=116 'inlinestats'=8 'keep'=9 'limit'=10 -'meta'=11 -'metrics'=12 -'mv_expand'=13 -'rename'=14 -'row'=15 -'show'=16 -'sort'=17 -'stats'=18 -'where'=19 -'|'=28 -'by'=32 -'and'=33 -'asc'=34 -'='=35 -'::'=36 -','=37 -'desc'=38 -'.'=39 -'false'=40 -'first'=41 -'last'=42 -'('=43 -'in'=44 -'is'=45 -'like'=46 -'not'=47 -'null'=48 -'nulls'=49 -'or'=50 -'?'=51 -'rlike'=52 -')'=53 -'true'=54 -'=='=55 -'=~'=56 -'!='=57 -'<'=58 -'<='=59 -'>'=60 -'>='=61 -'+'=62 -'-'=63 -'*'=64 -'/'=65 -'%'=66 -']'=68 -'metadata'=74 -'as'=82 -'on'=86 -'with'=87 -'info'=98 -'functions'=102 -':'=106 +'lookup'=11 +'meta'=12 +'metrics'=13 +'mv_expand'=14 +'rename'=15 +'row'=16 +'show'=17 +'sort'=18 +'stats'=19 +'where'=20 +'|'=29 +'by'=33 +'and'=34 +'asc'=35 +'='=36 +'::'=37 +','=38 +'desc'=39 +'.'=40 +'false'=41 +'first'=42 +'last'=43 +'('=44 +'in'=45 +'is'=46 +'like'=47 +'not'=48 +'null'=49 +'nulls'=50 +'or'=51 +'?'=52 +'rlike'=53 +')'=54 +'true'=55 +'=='=56 +'=~'=57 +'!='=58 +'<'=59 +'<='=60 +'>'=61 +'>='=62 +'+'=63 +'-'=64 +'*'=65 +'/'=66 +'%'=67 +']'=69 +'metadata'=75 +'as'=83 +'on'=87 +'with'=88 +'info'=105 +'functions'=109 +':'=113 diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java index a6f7cc2317e11..ca90b9e1e3f2e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.esql.action; +import org.elasticsearch.Build; import org.elasticsearch.features.NodeFeature; import org.elasticsearch.rest.action.admin.cluster.RestNodesCapabilitiesAction; import org.elasticsearch.xpack.esql.plugin.EsqlFeatures; @@ -36,10 +37,22 @@ public class EsqlCapabilities { */ private static final String METADATA_IGNORED_FIELD = "metadata_field_ignored"; + /** + * Support for requesting the "LOOKUP" command. + */ + private static final String LOOKUP = "lookup"; + public static final Set CAPABILITIES = capabilities(); private static Set capabilities() { - List caps = new ArrayList<>(List.of(FN_CBRT, ST_CENTROID_AGG_OPTIMIZED, METADATA_IGNORED_FIELD)); + List caps = new ArrayList<>(); + caps.add(FN_CBRT); + caps.add(ST_CENTROID_AGG_OPTIMIZED); + caps.add(METADATA_IGNORED_FIELD); + + if (Build.current().isSnapshot()) { + caps.add(LOOKUP); + } /* * Add all of our cluster features without the leading "esql." diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp index 38693348204af..6f9e20e95430b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp @@ -10,6 +10,7 @@ null 'inlinestats' 'keep' 'limit' +'lookup' 'meta' 'metrics' 'mv_expand' @@ -97,6 +98,12 @@ null null null null +null +null +null +null +null +null 'info' null null @@ -129,6 +136,7 @@ GROK INLINESTATS KEEP LIMIT +LOOKUP META METRICS MV_EXPAND @@ -213,6 +221,12 @@ ENRICH_WS ENRICH_FIELD_LINE_COMMENT ENRICH_FIELD_MULTILINE_COMMENT ENRICH_FIELD_WS +LOOKUP_LINE_COMMENT +LOOKUP_MULTILINE_COMMENT +LOOKUP_WS +LOOKUP_FIELD_LINE_COMMENT +LOOKUP_FIELD_MULTILINE_COMMENT +LOOKUP_FIELD_WS MVEXPAND_LINE_COMMENT MVEXPAND_MULTILINE_COMMENT MVEXPAND_WS @@ -247,6 +261,7 @@ GROK INLINESTATS KEEP LIMIT +LOOKUP META METRICS MV_EXPAND @@ -374,6 +389,21 @@ ENRICH_FIELD_QUOTED_IDENTIFIER ENRICH_FIELD_LINE_COMMENT ENRICH_FIELD_MULTILINE_COMMENT ENRICH_FIELD_WS +LOOKUP_PIPE +LOOKUP_COMMA +LOOKUP_DOT +LOOKUP_ON +LOOKUP_INDEX_UNQUOTED_IDENTIFIER +LOOKUP_LINE_COMMENT +LOOKUP_MULTILINE_COMMENT +LOOKUP_WS +LOOKUP_FIELD_PIPE +LOOKUP_FIELD_COMMA +LOOKUP_FIELD_DOT +LOOKUP_FIELD_ID_PATTERN +LOOKUP_FIELD_LINE_COMMENT +LOOKUP_FIELD_MULTILINE_COMMENT +LOOKUP_FIELD_WS MVEXPAND_PIPE MVEXPAND_DOT MVEXPAND_QUOTED_IDENTIFIER @@ -424,6 +454,8 @@ PROJECT_MODE RENAME_MODE ENRICH_MODE ENRICH_FIELD_MODE +LOOKUP_MODE +LOOKUP_FIELD_MODE MVEXPAND_MODE SHOW_MODE META_MODE @@ -432,4 +464,4 @@ METRICS_MODE CLOSING_METRICS_MODE atn: -[4, 0, 116, 1297, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139, 2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144, 7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148, 2, 149, 7, 149, 2, 150, 7, 150, 2, 151, 7, 151, 2, 152, 7, 152, 2, 153, 7, 153, 2, 154, 7, 154, 2, 155, 7, 155, 2, 156, 7, 156, 2, 157, 7, 157, 2, 158, 7, 158, 2, 159, 7, 159, 2, 160, 7, 160, 2, 161, 7, 161, 2, 162, 7, 162, 2, 163, 7, 163, 2, 164, 7, 164, 2, 165, 7, 165, 2, 166, 7, 166, 2, 167, 7, 167, 2, 168, 7, 168, 2, 169, 7, 169, 2, 170, 7, 170, 2, 171, 7, 171, 2, 172, 7, 172, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 4, 19, 522, 8, 19, 11, 19, 12, 19, 523, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 5, 20, 532, 8, 20, 10, 20, 12, 20, 535, 9, 20, 1, 20, 3, 20, 538, 8, 20, 1, 20, 3, 20, 541, 8, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 5, 21, 550, 8, 21, 10, 21, 12, 21, 553, 9, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 4, 22, 561, 8, 22, 11, 22, 12, 22, 562, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 3, 23, 570, 8, 23, 1, 24, 4, 24, 573, 8, 24, 11, 24, 12, 24, 574, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35, 3, 35, 614, 8, 35, 1, 35, 4, 35, 617, 8, 35, 11, 35, 12, 35, 618, 1, 36, 1, 36, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 3, 38, 628, 8, 38, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 3, 40, 635, 8, 40, 1, 41, 1, 41, 1, 41, 5, 41, 640, 8, 41, 10, 41, 12, 41, 643, 9, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 5, 41, 651, 8, 41, 10, 41, 12, 41, 654, 9, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 3, 41, 661, 8, 41, 1, 41, 3, 41, 664, 8, 41, 3, 41, 666, 8, 41, 1, 42, 4, 42, 669, 8, 42, 11, 42, 12, 42, 670, 1, 43, 4, 43, 674, 8, 43, 11, 43, 12, 43, 675, 1, 43, 1, 43, 5, 43, 680, 8, 43, 10, 43, 12, 43, 683, 9, 43, 1, 43, 1, 43, 4, 43, 687, 8, 43, 11, 43, 12, 43, 688, 1, 43, 4, 43, 692, 8, 43, 11, 43, 12, 43, 693, 1, 43, 1, 43, 5, 43, 698, 8, 43, 10, 43, 12, 43, 701, 9, 43, 3, 43, 703, 8, 43, 1, 43, 1, 43, 1, 43, 1, 43, 4, 43, 709, 8, 43, 11, 43, 12, 43, 710, 1, 43, 1, 43, 3, 43, 715, 8, 43, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 75, 1, 75, 1, 76, 1, 76, 1, 77, 1, 77, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 5, 81, 846, 8, 81, 10, 81, 12, 81, 849, 9, 81, 1, 81, 1, 81, 3, 81, 853, 8, 81, 1, 81, 4, 81, 856, 8, 81, 11, 81, 12, 81, 857, 3, 81, 860, 8, 81, 1, 82, 1, 82, 4, 82, 864, 8, 82, 11, 82, 12, 82, 865, 1, 82, 1, 82, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 1, 88, 1, 88, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 96, 1, 96, 1, 97, 1, 97, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 101, 3, 101, 951, 8, 101, 1, 102, 1, 102, 3, 102, 955, 8, 102, 1, 102, 5, 102, 958, 8, 102, 10, 102, 12, 102, 961, 9, 102, 1, 102, 1, 102, 3, 102, 965, 8, 102, 1, 102, 4, 102, 968, 8, 102, 11, 102, 12, 102, 969, 3, 102, 972, 8, 102, 1, 103, 1, 103, 4, 103, 976, 8, 103, 11, 103, 12, 103, 977, 1, 104, 1, 104, 1, 104, 1, 104, 1, 105, 1, 105, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 108, 1, 108, 1, 108, 1, 108, 1, 109, 1, 109, 1, 109, 1, 109, 1, 110, 1, 110, 1, 110, 1, 110, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1, 115, 1, 115, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 120, 1, 120, 1, 121, 4, 121, 1053, 8, 121, 11, 121, 12, 121, 1054, 1, 121, 1, 121, 3, 121, 1059, 8, 121, 1, 121, 4, 121, 1062, 8, 121, 11, 121, 12, 121, 1063, 1, 122, 1, 122, 1, 122, 1, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1, 127, 1, 127, 1, 128, 1, 128, 1, 128, 1, 128, 1, 129, 1, 129, 1, 129, 1, 129, 1, 130, 1, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 131, 1, 131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 133, 1, 133, 1, 133, 1, 133, 1, 134, 1, 134, 1, 134, 1, 134, 1, 135, 1, 135, 1, 135, 1, 135, 1, 136, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 1, 143, 1, 143, 1, 143, 1, 143, 1, 144, 1, 144, 1, 144, 1, 144, 1, 144, 1, 145, 1, 145, 1, 145, 1, 145, 1, 145, 1, 146, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 148, 1, 148, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1, 151, 1, 151, 1, 152, 1, 152, 1, 152, 1, 152, 1, 153, 1, 153, 1, 153, 1, 153, 1, 154, 1, 154, 1, 154, 1, 154, 1, 154, 1, 155, 1, 155, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 4, 156, 1218, 8, 156, 11, 156, 12, 156, 1219, 1, 157, 1, 157, 1, 157, 1, 157, 1, 158, 1, 158, 1, 158, 1, 158, 1, 159, 1, 159, 1, 159, 1, 159, 1, 160, 1, 160, 1, 160, 1, 160, 1, 160, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 163, 1, 163, 1, 163, 1, 163, 1, 164, 1, 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1, 168, 1, 168, 1, 168, 1, 169, 1, 169, 1, 169, 1, 169, 1, 169, 1, 169, 1, 170, 1, 170, 1, 170, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 171, 1, 171, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 172, 2, 551, 652, 0, 173, 14, 1, 16, 2, 18, 3, 20, 4, 22, 5, 24, 6, 26, 7, 28, 8, 30, 9, 32, 10, 34, 11, 36, 12, 38, 13, 40, 14, 42, 15, 44, 16, 46, 17, 48, 18, 50, 19, 52, 20, 54, 21, 56, 22, 58, 23, 60, 0, 62, 24, 64, 0, 66, 0, 68, 25, 70, 26, 72, 27, 74, 28, 76, 0, 78, 0, 80, 0, 82, 0, 84, 0, 86, 0, 88, 0, 90, 0, 92, 0, 94, 0, 96, 29, 98, 30, 100, 31, 102, 32, 104, 33, 106, 34, 108, 35, 110, 36, 112, 37, 114, 38, 116, 39, 118, 40, 120, 41, 122, 42, 124, 43, 126, 44, 128, 45, 130, 46, 132, 47, 134, 48, 136, 49, 138, 50, 140, 51, 142, 52, 144, 53, 146, 54, 148, 55, 150, 56, 152, 57, 154, 58, 156, 59, 158, 60, 160, 61, 162, 62, 164, 63, 166, 64, 168, 65, 170, 66, 172, 67, 174, 68, 176, 69, 178, 0, 180, 70, 182, 71, 184, 72, 186, 73, 188, 0, 190, 0, 192, 0, 194, 0, 196, 0, 198, 0, 200, 74, 202, 0, 204, 75, 206, 76, 208, 77, 210, 0, 212, 0, 214, 0, 216, 0, 218, 0, 220, 78, 222, 79, 224, 80, 226, 81, 228, 0, 230, 0, 232, 0, 234, 0, 236, 82, 238, 0, 240, 83, 242, 84, 244, 85, 246, 0, 248, 0, 250, 86, 252, 87, 254, 0, 256, 88, 258, 0, 260, 0, 262, 89, 264, 90, 266, 91, 268, 0, 270, 0, 272, 0, 274, 0, 276, 0, 278, 0, 280, 0, 282, 92, 284, 93, 286, 94, 288, 0, 290, 0, 292, 0, 294, 0, 296, 95, 298, 96, 300, 97, 302, 0, 304, 98, 306, 99, 308, 100, 310, 101, 312, 0, 314, 102, 316, 103, 318, 104, 320, 105, 322, 0, 324, 106, 326, 107, 328, 108, 330, 109, 332, 110, 334, 0, 336, 0, 338, 111, 340, 112, 342, 113, 344, 0, 346, 114, 348, 115, 350, 116, 352, 0, 354, 0, 356, 0, 358, 0, 14, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 6, 0, 9, 10, 13, 13, 32, 32, 47, 47, 91, 91, 93, 93, 2, 0, 10, 10, 13, 13, 3, 0, 9, 10, 13, 13, 32, 32, 10, 0, 9, 10, 13, 13, 32, 32, 44, 44, 47, 47, 61, 61, 91, 91, 93, 93, 96, 96, 124, 124, 2, 0, 42, 42, 47, 47, 1, 0, 48, 57, 2, 0, 65, 90, 97, 122, 5, 0, 34, 34, 92, 92, 110, 110, 114, 114, 116, 116, 4, 0, 10, 10, 13, 13, 34, 34, 92, 92, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 1, 0, 96, 96, 11, 0, 9, 10, 13, 13, 32, 32, 34, 35, 44, 44, 47, 47, 58, 58, 60, 60, 62, 63, 92, 92, 124, 124, 1322, 0, 14, 1, 0, 0, 0, 0, 16, 1, 0, 0, 0, 0, 18, 1, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 24, 1, 0, 0, 0, 0, 26, 1, 0, 0, 0, 0, 28, 1, 0, 0, 0, 0, 30, 1, 0, 0, 0, 0, 32, 1, 0, 0, 0, 0, 34, 1, 0, 0, 0, 0, 36, 1, 0, 0, 0, 0, 38, 1, 0, 0, 0, 0, 40, 1, 0, 0, 0, 0, 42, 1, 0, 0, 0, 0, 44, 1, 0, 0, 0, 0, 46, 1, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 50, 1, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 54, 1, 0, 0, 0, 0, 56, 1, 0, 0, 0, 0, 58, 1, 0, 0, 0, 0, 62, 1, 0, 0, 0, 1, 64, 1, 0, 0, 0, 1, 66, 1, 0, 0, 0, 1, 68, 1, 0, 0, 0, 1, 70, 1, 0, 0, 0, 1, 72, 1, 0, 0, 0, 2, 74, 1, 0, 0, 0, 2, 96, 1, 0, 0, 0, 2, 98, 1, 0, 0, 0, 2, 100, 1, 0, 0, 0, 2, 102, 1, 0, 0, 0, 2, 104, 1, 0, 0, 0, 2, 106, 1, 0, 0, 0, 2, 108, 1, 0, 0, 0, 2, 110, 1, 0, 0, 0, 2, 112, 1, 0, 0, 0, 2, 114, 1, 0, 0, 0, 2, 116, 1, 0, 0, 0, 2, 118, 1, 0, 0, 0, 2, 120, 1, 0, 0, 0, 2, 122, 1, 0, 0, 0, 2, 124, 1, 0, 0, 0, 2, 126, 1, 0, 0, 0, 2, 128, 1, 0, 0, 0, 2, 130, 1, 0, 0, 0, 2, 132, 1, 0, 0, 0, 2, 134, 1, 0, 0, 0, 2, 136, 1, 0, 0, 0, 2, 138, 1, 0, 0, 0, 2, 140, 1, 0, 0, 0, 2, 142, 1, 0, 0, 0, 2, 144, 1, 0, 0, 0, 2, 146, 1, 0, 0, 0, 2, 148, 1, 0, 0, 0, 2, 150, 1, 0, 0, 0, 2, 152, 1, 0, 0, 0, 2, 154, 1, 0, 0, 0, 2, 156, 1, 0, 0, 0, 2, 158, 1, 0, 0, 0, 2, 160, 1, 0, 0, 0, 2, 162, 1, 0, 0, 0, 2, 164, 1, 0, 0, 0, 2, 166, 1, 0, 0, 0, 2, 168, 1, 0, 0, 0, 2, 170, 1, 0, 0, 0, 2, 172, 1, 0, 0, 0, 2, 174, 1, 0, 0, 0, 2, 176, 1, 0, 0, 0, 2, 180, 1, 0, 0, 0, 2, 182, 1, 0, 0, 0, 2, 184, 1, 0, 0, 0, 2, 186, 1, 0, 0, 0, 3, 188, 1, 0, 0, 0, 3, 190, 1, 0, 0, 0, 3, 192, 1, 0, 0, 0, 3, 194, 1, 0, 0, 0, 3, 196, 1, 0, 0, 0, 3, 198, 1, 0, 0, 0, 3, 200, 1, 0, 0, 0, 3, 202, 1, 0, 0, 0, 3, 204, 1, 0, 0, 0, 3, 206, 1, 0, 0, 0, 3, 208, 1, 0, 0, 0, 4, 210, 1, 0, 0, 0, 4, 212, 1, 0, 0, 0, 4, 214, 1, 0, 0, 0, 4, 220, 1, 0, 0, 0, 4, 222, 1, 0, 0, 0, 4, 224, 1, 0, 0, 0, 4, 226, 1, 0, 0, 0, 5, 228, 1, 0, 0, 0, 5, 230, 1, 0, 0, 0, 5, 232, 1, 0, 0, 0, 5, 234, 1, 0, 0, 0, 5, 236, 1, 0, 0, 0, 5, 238, 1, 0, 0, 0, 5, 240, 1, 0, 0, 0, 5, 242, 1, 0, 0, 0, 5, 244, 1, 0, 0, 0, 6, 246, 1, 0, 0, 0, 6, 248, 1, 0, 0, 0, 6, 250, 1, 0, 0, 0, 6, 252, 1, 0, 0, 0, 6, 256, 1, 0, 0, 0, 6, 258, 1, 0, 0, 0, 6, 260, 1, 0, 0, 0, 6, 262, 1, 0, 0, 0, 6, 264, 1, 0, 0, 0, 6, 266, 1, 0, 0, 0, 7, 268, 1, 0, 0, 0, 7, 270, 1, 0, 0, 0, 7, 272, 1, 0, 0, 0, 7, 274, 1, 0, 0, 0, 7, 276, 1, 0, 0, 0, 7, 278, 1, 0, 0, 0, 7, 280, 1, 0, 0, 0, 7, 282, 1, 0, 0, 0, 7, 284, 1, 0, 0, 0, 7, 286, 1, 0, 0, 0, 8, 288, 1, 0, 0, 0, 8, 290, 1, 0, 0, 0, 8, 292, 1, 0, 0, 0, 8, 294, 1, 0, 0, 0, 8, 296, 1, 0, 0, 0, 8, 298, 1, 0, 0, 0, 8, 300, 1, 0, 0, 0, 9, 302, 1, 0, 0, 0, 9, 304, 1, 0, 0, 0, 9, 306, 1, 0, 0, 0, 9, 308, 1, 0, 0, 0, 9, 310, 1, 0, 0, 0, 10, 312, 1, 0, 0, 0, 10, 314, 1, 0, 0, 0, 10, 316, 1, 0, 0, 0, 10, 318, 1, 0, 0, 0, 10, 320, 1, 0, 0, 0, 11, 322, 1, 0, 0, 0, 11, 324, 1, 0, 0, 0, 11, 326, 1, 0, 0, 0, 11, 328, 1, 0, 0, 0, 11, 330, 1, 0, 0, 0, 11, 332, 1, 0, 0, 0, 12, 334, 1, 0, 0, 0, 12, 336, 1, 0, 0, 0, 12, 338, 1, 0, 0, 0, 12, 340, 1, 0, 0, 0, 12, 342, 1, 0, 0, 0, 13, 344, 1, 0, 0, 0, 13, 346, 1, 0, 0, 0, 13, 348, 1, 0, 0, 0, 13, 350, 1, 0, 0, 0, 13, 352, 1, 0, 0, 0, 13, 354, 1, 0, 0, 0, 13, 356, 1, 0, 0, 0, 13, 358, 1, 0, 0, 0, 14, 360, 1, 0, 0, 0, 16, 370, 1, 0, 0, 0, 18, 377, 1, 0, 0, 0, 20, 386, 1, 0, 0, 0, 22, 393, 1, 0, 0, 0, 24, 403, 1, 0, 0, 0, 26, 410, 1, 0, 0, 0, 28, 417, 1, 0, 0, 0, 30, 431, 1, 0, 0, 0, 32, 438, 1, 0, 0, 0, 34, 446, 1, 0, 0, 0, 36, 453, 1, 0, 0, 0, 38, 463, 1, 0, 0, 0, 40, 475, 1, 0, 0, 0, 42, 484, 1, 0, 0, 0, 44, 490, 1, 0, 0, 0, 46, 497, 1, 0, 0, 0, 48, 504, 1, 0, 0, 0, 50, 512, 1, 0, 0, 0, 52, 521, 1, 0, 0, 0, 54, 527, 1, 0, 0, 0, 56, 544, 1, 0, 0, 0, 58, 560, 1, 0, 0, 0, 60, 569, 1, 0, 0, 0, 62, 572, 1, 0, 0, 0, 64, 576, 1, 0, 0, 0, 66, 581, 1, 0, 0, 0, 68, 586, 1, 0, 0, 0, 70, 590, 1, 0, 0, 0, 72, 594, 1, 0, 0, 0, 74, 598, 1, 0, 0, 0, 76, 602, 1, 0, 0, 0, 78, 604, 1, 0, 0, 0, 80, 606, 1, 0, 0, 0, 82, 609, 1, 0, 0, 0, 84, 611, 1, 0, 0, 0, 86, 620, 1, 0, 0, 0, 88, 622, 1, 0, 0, 0, 90, 627, 1, 0, 0, 0, 92, 629, 1, 0, 0, 0, 94, 634, 1, 0, 0, 0, 96, 665, 1, 0, 0, 0, 98, 668, 1, 0, 0, 0, 100, 714, 1, 0, 0, 0, 102, 716, 1, 0, 0, 0, 104, 719, 1, 0, 0, 0, 106, 723, 1, 0, 0, 0, 108, 727, 1, 0, 0, 0, 110, 729, 1, 0, 0, 0, 112, 732, 1, 0, 0, 0, 114, 734, 1, 0, 0, 0, 116, 739, 1, 0, 0, 0, 118, 741, 1, 0, 0, 0, 120, 747, 1, 0, 0, 0, 122, 753, 1, 0, 0, 0, 124, 758, 1, 0, 0, 0, 126, 760, 1, 0, 0, 0, 128, 763, 1, 0, 0, 0, 130, 766, 1, 0, 0, 0, 132, 771, 1, 0, 0, 0, 134, 775, 1, 0, 0, 0, 136, 780, 1, 0, 0, 0, 138, 786, 1, 0, 0, 0, 140, 789, 1, 0, 0, 0, 142, 791, 1, 0, 0, 0, 144, 797, 1, 0, 0, 0, 146, 799, 1, 0, 0, 0, 148, 804, 1, 0, 0, 0, 150, 807, 1, 0, 0, 0, 152, 810, 1, 0, 0, 0, 154, 813, 1, 0, 0, 0, 156, 815, 1, 0, 0, 0, 158, 818, 1, 0, 0, 0, 160, 820, 1, 0, 0, 0, 162, 823, 1, 0, 0, 0, 164, 825, 1, 0, 0, 0, 166, 827, 1, 0, 0, 0, 168, 829, 1, 0, 0, 0, 170, 831, 1, 0, 0, 0, 172, 833, 1, 0, 0, 0, 174, 838, 1, 0, 0, 0, 176, 859, 1, 0, 0, 0, 178, 861, 1, 0, 0, 0, 180, 869, 1, 0, 0, 0, 182, 871, 1, 0, 0, 0, 184, 875, 1, 0, 0, 0, 186, 879, 1, 0, 0, 0, 188, 883, 1, 0, 0, 0, 190, 888, 1, 0, 0, 0, 192, 892, 1, 0, 0, 0, 194, 896, 1, 0, 0, 0, 196, 900, 1, 0, 0, 0, 198, 904, 1, 0, 0, 0, 200, 908, 1, 0, 0, 0, 202, 917, 1, 0, 0, 0, 204, 921, 1, 0, 0, 0, 206, 925, 1, 0, 0, 0, 208, 929, 1, 0, 0, 0, 210, 933, 1, 0, 0, 0, 212, 938, 1, 0, 0, 0, 214, 942, 1, 0, 0, 0, 216, 950, 1, 0, 0, 0, 218, 971, 1, 0, 0, 0, 220, 975, 1, 0, 0, 0, 222, 979, 1, 0, 0, 0, 224, 983, 1, 0, 0, 0, 226, 987, 1, 0, 0, 0, 228, 991, 1, 0, 0, 0, 230, 996, 1, 0, 0, 0, 232, 1000, 1, 0, 0, 0, 234, 1004, 1, 0, 0, 0, 236, 1008, 1, 0, 0, 0, 238, 1011, 1, 0, 0, 0, 240, 1015, 1, 0, 0, 0, 242, 1019, 1, 0, 0, 0, 244, 1023, 1, 0, 0, 0, 246, 1027, 1, 0, 0, 0, 248, 1032, 1, 0, 0, 0, 250, 1037, 1, 0, 0, 0, 252, 1042, 1, 0, 0, 0, 254, 1049, 1, 0, 0, 0, 256, 1058, 1, 0, 0, 0, 258, 1065, 1, 0, 0, 0, 260, 1069, 1, 0, 0, 0, 262, 1073, 1, 0, 0, 0, 264, 1077, 1, 0, 0, 0, 266, 1081, 1, 0, 0, 0, 268, 1085, 1, 0, 0, 0, 270, 1091, 1, 0, 0, 0, 272, 1095, 1, 0, 0, 0, 274, 1099, 1, 0, 0, 0, 276, 1103, 1, 0, 0, 0, 278, 1107, 1, 0, 0, 0, 280, 1111, 1, 0, 0, 0, 282, 1115, 1, 0, 0, 0, 284, 1119, 1, 0, 0, 0, 286, 1123, 1, 0, 0, 0, 288, 1127, 1, 0, 0, 0, 290, 1132, 1, 0, 0, 0, 292, 1136, 1, 0, 0, 0, 294, 1140, 1, 0, 0, 0, 296, 1144, 1, 0, 0, 0, 298, 1148, 1, 0, 0, 0, 300, 1152, 1, 0, 0, 0, 302, 1156, 1, 0, 0, 0, 304, 1161, 1, 0, 0, 0, 306, 1166, 1, 0, 0, 0, 308, 1170, 1, 0, 0, 0, 310, 1174, 1, 0, 0, 0, 312, 1178, 1, 0, 0, 0, 314, 1183, 1, 0, 0, 0, 316, 1193, 1, 0, 0, 0, 318, 1197, 1, 0, 0, 0, 320, 1201, 1, 0, 0, 0, 322, 1205, 1, 0, 0, 0, 324, 1210, 1, 0, 0, 0, 326, 1217, 1, 0, 0, 0, 328, 1221, 1, 0, 0, 0, 330, 1225, 1, 0, 0, 0, 332, 1229, 1, 0, 0, 0, 334, 1233, 1, 0, 0, 0, 336, 1238, 1, 0, 0, 0, 338, 1244, 1, 0, 0, 0, 340, 1248, 1, 0, 0, 0, 342, 1252, 1, 0, 0, 0, 344, 1256, 1, 0, 0, 0, 346, 1262, 1, 0, 0, 0, 348, 1266, 1, 0, 0, 0, 350, 1270, 1, 0, 0, 0, 352, 1274, 1, 0, 0, 0, 354, 1280, 1, 0, 0, 0, 356, 1286, 1, 0, 0, 0, 358, 1292, 1, 0, 0, 0, 360, 361, 5, 100, 0, 0, 361, 362, 5, 105, 0, 0, 362, 363, 5, 115, 0, 0, 363, 364, 5, 115, 0, 0, 364, 365, 5, 101, 0, 0, 365, 366, 5, 99, 0, 0, 366, 367, 5, 116, 0, 0, 367, 368, 1, 0, 0, 0, 368, 369, 6, 0, 0, 0, 369, 15, 1, 0, 0, 0, 370, 371, 5, 100, 0, 0, 371, 372, 5, 114, 0, 0, 372, 373, 5, 111, 0, 0, 373, 374, 5, 112, 0, 0, 374, 375, 1, 0, 0, 0, 375, 376, 6, 1, 1, 0, 376, 17, 1, 0, 0, 0, 377, 378, 5, 101, 0, 0, 378, 379, 5, 110, 0, 0, 379, 380, 5, 114, 0, 0, 380, 381, 5, 105, 0, 0, 381, 382, 5, 99, 0, 0, 382, 383, 5, 104, 0, 0, 383, 384, 1, 0, 0, 0, 384, 385, 6, 2, 2, 0, 385, 19, 1, 0, 0, 0, 386, 387, 5, 101, 0, 0, 387, 388, 5, 118, 0, 0, 388, 389, 5, 97, 0, 0, 389, 390, 5, 108, 0, 0, 390, 391, 1, 0, 0, 0, 391, 392, 6, 3, 0, 0, 392, 21, 1, 0, 0, 0, 393, 394, 5, 101, 0, 0, 394, 395, 5, 120, 0, 0, 395, 396, 5, 112, 0, 0, 396, 397, 5, 108, 0, 0, 397, 398, 5, 97, 0, 0, 398, 399, 5, 105, 0, 0, 399, 400, 5, 110, 0, 0, 400, 401, 1, 0, 0, 0, 401, 402, 6, 4, 3, 0, 402, 23, 1, 0, 0, 0, 403, 404, 5, 102, 0, 0, 404, 405, 5, 114, 0, 0, 405, 406, 5, 111, 0, 0, 406, 407, 5, 109, 0, 0, 407, 408, 1, 0, 0, 0, 408, 409, 6, 5, 4, 0, 409, 25, 1, 0, 0, 0, 410, 411, 5, 103, 0, 0, 411, 412, 5, 114, 0, 0, 412, 413, 5, 111, 0, 0, 413, 414, 5, 107, 0, 0, 414, 415, 1, 0, 0, 0, 415, 416, 6, 6, 0, 0, 416, 27, 1, 0, 0, 0, 417, 418, 5, 105, 0, 0, 418, 419, 5, 110, 0, 0, 419, 420, 5, 108, 0, 0, 420, 421, 5, 105, 0, 0, 421, 422, 5, 110, 0, 0, 422, 423, 5, 101, 0, 0, 423, 424, 5, 115, 0, 0, 424, 425, 5, 116, 0, 0, 425, 426, 5, 97, 0, 0, 426, 427, 5, 116, 0, 0, 427, 428, 5, 115, 0, 0, 428, 429, 1, 0, 0, 0, 429, 430, 6, 7, 0, 0, 430, 29, 1, 0, 0, 0, 431, 432, 5, 107, 0, 0, 432, 433, 5, 101, 0, 0, 433, 434, 5, 101, 0, 0, 434, 435, 5, 112, 0, 0, 435, 436, 1, 0, 0, 0, 436, 437, 6, 8, 1, 0, 437, 31, 1, 0, 0, 0, 438, 439, 5, 108, 0, 0, 439, 440, 5, 105, 0, 0, 440, 441, 5, 109, 0, 0, 441, 442, 5, 105, 0, 0, 442, 443, 5, 116, 0, 0, 443, 444, 1, 0, 0, 0, 444, 445, 6, 9, 0, 0, 445, 33, 1, 0, 0, 0, 446, 447, 5, 109, 0, 0, 447, 448, 5, 101, 0, 0, 448, 449, 5, 116, 0, 0, 449, 450, 5, 97, 0, 0, 450, 451, 1, 0, 0, 0, 451, 452, 6, 10, 5, 0, 452, 35, 1, 0, 0, 0, 453, 454, 5, 109, 0, 0, 454, 455, 5, 101, 0, 0, 455, 456, 5, 116, 0, 0, 456, 457, 5, 114, 0, 0, 457, 458, 5, 105, 0, 0, 458, 459, 5, 99, 0, 0, 459, 460, 5, 115, 0, 0, 460, 461, 1, 0, 0, 0, 461, 462, 6, 11, 6, 0, 462, 37, 1, 0, 0, 0, 463, 464, 5, 109, 0, 0, 464, 465, 5, 118, 0, 0, 465, 466, 5, 95, 0, 0, 466, 467, 5, 101, 0, 0, 467, 468, 5, 120, 0, 0, 468, 469, 5, 112, 0, 0, 469, 470, 5, 97, 0, 0, 470, 471, 5, 110, 0, 0, 471, 472, 5, 100, 0, 0, 472, 473, 1, 0, 0, 0, 473, 474, 6, 12, 7, 0, 474, 39, 1, 0, 0, 0, 475, 476, 5, 114, 0, 0, 476, 477, 5, 101, 0, 0, 477, 478, 5, 110, 0, 0, 478, 479, 5, 97, 0, 0, 479, 480, 5, 109, 0, 0, 480, 481, 5, 101, 0, 0, 481, 482, 1, 0, 0, 0, 482, 483, 6, 13, 8, 0, 483, 41, 1, 0, 0, 0, 484, 485, 5, 114, 0, 0, 485, 486, 5, 111, 0, 0, 486, 487, 5, 119, 0, 0, 487, 488, 1, 0, 0, 0, 488, 489, 6, 14, 0, 0, 489, 43, 1, 0, 0, 0, 490, 491, 5, 115, 0, 0, 491, 492, 5, 104, 0, 0, 492, 493, 5, 111, 0, 0, 493, 494, 5, 119, 0, 0, 494, 495, 1, 0, 0, 0, 495, 496, 6, 15, 9, 0, 496, 45, 1, 0, 0, 0, 497, 498, 5, 115, 0, 0, 498, 499, 5, 111, 0, 0, 499, 500, 5, 114, 0, 0, 500, 501, 5, 116, 0, 0, 501, 502, 1, 0, 0, 0, 502, 503, 6, 16, 0, 0, 503, 47, 1, 0, 0, 0, 504, 505, 5, 115, 0, 0, 505, 506, 5, 116, 0, 0, 506, 507, 5, 97, 0, 0, 507, 508, 5, 116, 0, 0, 508, 509, 5, 115, 0, 0, 509, 510, 1, 0, 0, 0, 510, 511, 6, 17, 0, 0, 511, 49, 1, 0, 0, 0, 512, 513, 5, 119, 0, 0, 513, 514, 5, 104, 0, 0, 514, 515, 5, 101, 0, 0, 515, 516, 5, 114, 0, 0, 516, 517, 5, 101, 0, 0, 517, 518, 1, 0, 0, 0, 518, 519, 6, 18, 0, 0, 519, 51, 1, 0, 0, 0, 520, 522, 8, 0, 0, 0, 521, 520, 1, 0, 0, 0, 522, 523, 1, 0, 0, 0, 523, 521, 1, 0, 0, 0, 523, 524, 1, 0, 0, 0, 524, 525, 1, 0, 0, 0, 525, 526, 6, 19, 0, 0, 526, 53, 1, 0, 0, 0, 527, 528, 5, 47, 0, 0, 528, 529, 5, 47, 0, 0, 529, 533, 1, 0, 0, 0, 530, 532, 8, 1, 0, 0, 531, 530, 1, 0, 0, 0, 532, 535, 1, 0, 0, 0, 533, 531, 1, 0, 0, 0, 533, 534, 1, 0, 0, 0, 534, 537, 1, 0, 0, 0, 535, 533, 1, 0, 0, 0, 536, 538, 5, 13, 0, 0, 537, 536, 1, 0, 0, 0, 537, 538, 1, 0, 0, 0, 538, 540, 1, 0, 0, 0, 539, 541, 5, 10, 0, 0, 540, 539, 1, 0, 0, 0, 540, 541, 1, 0, 0, 0, 541, 542, 1, 0, 0, 0, 542, 543, 6, 20, 10, 0, 543, 55, 1, 0, 0, 0, 544, 545, 5, 47, 0, 0, 545, 546, 5, 42, 0, 0, 546, 551, 1, 0, 0, 0, 547, 550, 3, 56, 21, 0, 548, 550, 9, 0, 0, 0, 549, 547, 1, 0, 0, 0, 549, 548, 1, 0, 0, 0, 550, 553, 1, 0, 0, 0, 551, 552, 1, 0, 0, 0, 551, 549, 1, 0, 0, 0, 552, 554, 1, 0, 0, 0, 553, 551, 1, 0, 0, 0, 554, 555, 5, 42, 0, 0, 555, 556, 5, 47, 0, 0, 556, 557, 1, 0, 0, 0, 557, 558, 6, 21, 10, 0, 558, 57, 1, 0, 0, 0, 559, 561, 7, 2, 0, 0, 560, 559, 1, 0, 0, 0, 561, 562, 1, 0, 0, 0, 562, 560, 1, 0, 0, 0, 562, 563, 1, 0, 0, 0, 563, 564, 1, 0, 0, 0, 564, 565, 6, 22, 10, 0, 565, 59, 1, 0, 0, 0, 566, 570, 8, 3, 0, 0, 567, 568, 5, 47, 0, 0, 568, 570, 8, 4, 0, 0, 569, 566, 1, 0, 0, 0, 569, 567, 1, 0, 0, 0, 570, 61, 1, 0, 0, 0, 571, 573, 3, 60, 23, 0, 572, 571, 1, 0, 0, 0, 573, 574, 1, 0, 0, 0, 574, 572, 1, 0, 0, 0, 574, 575, 1, 0, 0, 0, 575, 63, 1, 0, 0, 0, 576, 577, 3, 172, 79, 0, 577, 578, 1, 0, 0, 0, 578, 579, 6, 25, 11, 0, 579, 580, 6, 25, 12, 0, 580, 65, 1, 0, 0, 0, 581, 582, 3, 74, 30, 0, 582, 583, 1, 0, 0, 0, 583, 584, 6, 26, 13, 0, 584, 585, 6, 26, 14, 0, 585, 67, 1, 0, 0, 0, 586, 587, 3, 58, 22, 0, 587, 588, 1, 0, 0, 0, 588, 589, 6, 27, 10, 0, 589, 69, 1, 0, 0, 0, 590, 591, 3, 54, 20, 0, 591, 592, 1, 0, 0, 0, 592, 593, 6, 28, 10, 0, 593, 71, 1, 0, 0, 0, 594, 595, 3, 56, 21, 0, 595, 596, 1, 0, 0, 0, 596, 597, 6, 29, 10, 0, 597, 73, 1, 0, 0, 0, 598, 599, 5, 124, 0, 0, 599, 600, 1, 0, 0, 0, 600, 601, 6, 30, 14, 0, 601, 75, 1, 0, 0, 0, 602, 603, 7, 5, 0, 0, 603, 77, 1, 0, 0, 0, 604, 605, 7, 6, 0, 0, 605, 79, 1, 0, 0, 0, 606, 607, 5, 92, 0, 0, 607, 608, 7, 7, 0, 0, 608, 81, 1, 0, 0, 0, 609, 610, 8, 8, 0, 0, 610, 83, 1, 0, 0, 0, 611, 613, 7, 9, 0, 0, 612, 614, 7, 10, 0, 0, 613, 612, 1, 0, 0, 0, 613, 614, 1, 0, 0, 0, 614, 616, 1, 0, 0, 0, 615, 617, 3, 76, 31, 0, 616, 615, 1, 0, 0, 0, 617, 618, 1, 0, 0, 0, 618, 616, 1, 0, 0, 0, 618, 619, 1, 0, 0, 0, 619, 85, 1, 0, 0, 0, 620, 621, 5, 64, 0, 0, 621, 87, 1, 0, 0, 0, 622, 623, 5, 96, 0, 0, 623, 89, 1, 0, 0, 0, 624, 628, 8, 11, 0, 0, 625, 626, 5, 96, 0, 0, 626, 628, 5, 96, 0, 0, 627, 624, 1, 0, 0, 0, 627, 625, 1, 0, 0, 0, 628, 91, 1, 0, 0, 0, 629, 630, 5, 95, 0, 0, 630, 93, 1, 0, 0, 0, 631, 635, 3, 78, 32, 0, 632, 635, 3, 76, 31, 0, 633, 635, 3, 92, 39, 0, 634, 631, 1, 0, 0, 0, 634, 632, 1, 0, 0, 0, 634, 633, 1, 0, 0, 0, 635, 95, 1, 0, 0, 0, 636, 641, 5, 34, 0, 0, 637, 640, 3, 80, 33, 0, 638, 640, 3, 82, 34, 0, 639, 637, 1, 0, 0, 0, 639, 638, 1, 0, 0, 0, 640, 643, 1, 0, 0, 0, 641, 639, 1, 0, 0, 0, 641, 642, 1, 0, 0, 0, 642, 644, 1, 0, 0, 0, 643, 641, 1, 0, 0, 0, 644, 666, 5, 34, 0, 0, 645, 646, 5, 34, 0, 0, 646, 647, 5, 34, 0, 0, 647, 648, 5, 34, 0, 0, 648, 652, 1, 0, 0, 0, 649, 651, 8, 1, 0, 0, 650, 649, 1, 0, 0, 0, 651, 654, 1, 0, 0, 0, 652, 653, 1, 0, 0, 0, 652, 650, 1, 0, 0, 0, 653, 655, 1, 0, 0, 0, 654, 652, 1, 0, 0, 0, 655, 656, 5, 34, 0, 0, 656, 657, 5, 34, 0, 0, 657, 658, 5, 34, 0, 0, 658, 660, 1, 0, 0, 0, 659, 661, 5, 34, 0, 0, 660, 659, 1, 0, 0, 0, 660, 661, 1, 0, 0, 0, 661, 663, 1, 0, 0, 0, 662, 664, 5, 34, 0, 0, 663, 662, 1, 0, 0, 0, 663, 664, 1, 0, 0, 0, 664, 666, 1, 0, 0, 0, 665, 636, 1, 0, 0, 0, 665, 645, 1, 0, 0, 0, 666, 97, 1, 0, 0, 0, 667, 669, 3, 76, 31, 0, 668, 667, 1, 0, 0, 0, 669, 670, 1, 0, 0, 0, 670, 668, 1, 0, 0, 0, 670, 671, 1, 0, 0, 0, 671, 99, 1, 0, 0, 0, 672, 674, 3, 76, 31, 0, 673, 672, 1, 0, 0, 0, 674, 675, 1, 0, 0, 0, 675, 673, 1, 0, 0, 0, 675, 676, 1, 0, 0, 0, 676, 677, 1, 0, 0, 0, 677, 681, 3, 116, 51, 0, 678, 680, 3, 76, 31, 0, 679, 678, 1, 0, 0, 0, 680, 683, 1, 0, 0, 0, 681, 679, 1, 0, 0, 0, 681, 682, 1, 0, 0, 0, 682, 715, 1, 0, 0, 0, 683, 681, 1, 0, 0, 0, 684, 686, 3, 116, 51, 0, 685, 687, 3, 76, 31, 0, 686, 685, 1, 0, 0, 0, 687, 688, 1, 0, 0, 0, 688, 686, 1, 0, 0, 0, 688, 689, 1, 0, 0, 0, 689, 715, 1, 0, 0, 0, 690, 692, 3, 76, 31, 0, 691, 690, 1, 0, 0, 0, 692, 693, 1, 0, 0, 0, 693, 691, 1, 0, 0, 0, 693, 694, 1, 0, 0, 0, 694, 702, 1, 0, 0, 0, 695, 699, 3, 116, 51, 0, 696, 698, 3, 76, 31, 0, 697, 696, 1, 0, 0, 0, 698, 701, 1, 0, 0, 0, 699, 697, 1, 0, 0, 0, 699, 700, 1, 0, 0, 0, 700, 703, 1, 0, 0, 0, 701, 699, 1, 0, 0, 0, 702, 695, 1, 0, 0, 0, 702, 703, 1, 0, 0, 0, 703, 704, 1, 0, 0, 0, 704, 705, 3, 84, 35, 0, 705, 715, 1, 0, 0, 0, 706, 708, 3, 116, 51, 0, 707, 709, 3, 76, 31, 0, 708, 707, 1, 0, 0, 0, 709, 710, 1, 0, 0, 0, 710, 708, 1, 0, 0, 0, 710, 711, 1, 0, 0, 0, 711, 712, 1, 0, 0, 0, 712, 713, 3, 84, 35, 0, 713, 715, 1, 0, 0, 0, 714, 673, 1, 0, 0, 0, 714, 684, 1, 0, 0, 0, 714, 691, 1, 0, 0, 0, 714, 706, 1, 0, 0, 0, 715, 101, 1, 0, 0, 0, 716, 717, 5, 98, 0, 0, 717, 718, 5, 121, 0, 0, 718, 103, 1, 0, 0, 0, 719, 720, 5, 97, 0, 0, 720, 721, 5, 110, 0, 0, 721, 722, 5, 100, 0, 0, 722, 105, 1, 0, 0, 0, 723, 724, 5, 97, 0, 0, 724, 725, 5, 115, 0, 0, 725, 726, 5, 99, 0, 0, 726, 107, 1, 0, 0, 0, 727, 728, 5, 61, 0, 0, 728, 109, 1, 0, 0, 0, 729, 730, 5, 58, 0, 0, 730, 731, 5, 58, 0, 0, 731, 111, 1, 0, 0, 0, 732, 733, 5, 44, 0, 0, 733, 113, 1, 0, 0, 0, 734, 735, 5, 100, 0, 0, 735, 736, 5, 101, 0, 0, 736, 737, 5, 115, 0, 0, 737, 738, 5, 99, 0, 0, 738, 115, 1, 0, 0, 0, 739, 740, 5, 46, 0, 0, 740, 117, 1, 0, 0, 0, 741, 742, 5, 102, 0, 0, 742, 743, 5, 97, 0, 0, 743, 744, 5, 108, 0, 0, 744, 745, 5, 115, 0, 0, 745, 746, 5, 101, 0, 0, 746, 119, 1, 0, 0, 0, 747, 748, 5, 102, 0, 0, 748, 749, 5, 105, 0, 0, 749, 750, 5, 114, 0, 0, 750, 751, 5, 115, 0, 0, 751, 752, 5, 116, 0, 0, 752, 121, 1, 0, 0, 0, 753, 754, 5, 108, 0, 0, 754, 755, 5, 97, 0, 0, 755, 756, 5, 115, 0, 0, 756, 757, 5, 116, 0, 0, 757, 123, 1, 0, 0, 0, 758, 759, 5, 40, 0, 0, 759, 125, 1, 0, 0, 0, 760, 761, 5, 105, 0, 0, 761, 762, 5, 110, 0, 0, 762, 127, 1, 0, 0, 0, 763, 764, 5, 105, 0, 0, 764, 765, 5, 115, 0, 0, 765, 129, 1, 0, 0, 0, 766, 767, 5, 108, 0, 0, 767, 768, 5, 105, 0, 0, 768, 769, 5, 107, 0, 0, 769, 770, 5, 101, 0, 0, 770, 131, 1, 0, 0, 0, 771, 772, 5, 110, 0, 0, 772, 773, 5, 111, 0, 0, 773, 774, 5, 116, 0, 0, 774, 133, 1, 0, 0, 0, 775, 776, 5, 110, 0, 0, 776, 777, 5, 117, 0, 0, 777, 778, 5, 108, 0, 0, 778, 779, 5, 108, 0, 0, 779, 135, 1, 0, 0, 0, 780, 781, 5, 110, 0, 0, 781, 782, 5, 117, 0, 0, 782, 783, 5, 108, 0, 0, 783, 784, 5, 108, 0, 0, 784, 785, 5, 115, 0, 0, 785, 137, 1, 0, 0, 0, 786, 787, 5, 111, 0, 0, 787, 788, 5, 114, 0, 0, 788, 139, 1, 0, 0, 0, 789, 790, 5, 63, 0, 0, 790, 141, 1, 0, 0, 0, 791, 792, 5, 114, 0, 0, 792, 793, 5, 108, 0, 0, 793, 794, 5, 105, 0, 0, 794, 795, 5, 107, 0, 0, 795, 796, 5, 101, 0, 0, 796, 143, 1, 0, 0, 0, 797, 798, 5, 41, 0, 0, 798, 145, 1, 0, 0, 0, 799, 800, 5, 116, 0, 0, 800, 801, 5, 114, 0, 0, 801, 802, 5, 117, 0, 0, 802, 803, 5, 101, 0, 0, 803, 147, 1, 0, 0, 0, 804, 805, 5, 61, 0, 0, 805, 806, 5, 61, 0, 0, 806, 149, 1, 0, 0, 0, 807, 808, 5, 61, 0, 0, 808, 809, 5, 126, 0, 0, 809, 151, 1, 0, 0, 0, 810, 811, 5, 33, 0, 0, 811, 812, 5, 61, 0, 0, 812, 153, 1, 0, 0, 0, 813, 814, 5, 60, 0, 0, 814, 155, 1, 0, 0, 0, 815, 816, 5, 60, 0, 0, 816, 817, 5, 61, 0, 0, 817, 157, 1, 0, 0, 0, 818, 819, 5, 62, 0, 0, 819, 159, 1, 0, 0, 0, 820, 821, 5, 62, 0, 0, 821, 822, 5, 61, 0, 0, 822, 161, 1, 0, 0, 0, 823, 824, 5, 43, 0, 0, 824, 163, 1, 0, 0, 0, 825, 826, 5, 45, 0, 0, 826, 165, 1, 0, 0, 0, 827, 828, 5, 42, 0, 0, 828, 167, 1, 0, 0, 0, 829, 830, 5, 47, 0, 0, 830, 169, 1, 0, 0, 0, 831, 832, 5, 37, 0, 0, 832, 171, 1, 0, 0, 0, 833, 834, 5, 91, 0, 0, 834, 835, 1, 0, 0, 0, 835, 836, 6, 79, 0, 0, 836, 837, 6, 79, 0, 0, 837, 173, 1, 0, 0, 0, 838, 839, 5, 93, 0, 0, 839, 840, 1, 0, 0, 0, 840, 841, 6, 80, 14, 0, 841, 842, 6, 80, 14, 0, 842, 175, 1, 0, 0, 0, 843, 847, 3, 78, 32, 0, 844, 846, 3, 94, 40, 0, 845, 844, 1, 0, 0, 0, 846, 849, 1, 0, 0, 0, 847, 845, 1, 0, 0, 0, 847, 848, 1, 0, 0, 0, 848, 860, 1, 0, 0, 0, 849, 847, 1, 0, 0, 0, 850, 853, 3, 92, 39, 0, 851, 853, 3, 86, 36, 0, 852, 850, 1, 0, 0, 0, 852, 851, 1, 0, 0, 0, 853, 855, 1, 0, 0, 0, 854, 856, 3, 94, 40, 0, 855, 854, 1, 0, 0, 0, 856, 857, 1, 0, 0, 0, 857, 855, 1, 0, 0, 0, 857, 858, 1, 0, 0, 0, 858, 860, 1, 0, 0, 0, 859, 843, 1, 0, 0, 0, 859, 852, 1, 0, 0, 0, 860, 177, 1, 0, 0, 0, 861, 863, 3, 88, 37, 0, 862, 864, 3, 90, 38, 0, 863, 862, 1, 0, 0, 0, 864, 865, 1, 0, 0, 0, 865, 863, 1, 0, 0, 0, 865, 866, 1, 0, 0, 0, 866, 867, 1, 0, 0, 0, 867, 868, 3, 88, 37, 0, 868, 179, 1, 0, 0, 0, 869, 870, 3, 178, 82, 0, 870, 181, 1, 0, 0, 0, 871, 872, 3, 54, 20, 0, 872, 873, 1, 0, 0, 0, 873, 874, 6, 84, 10, 0, 874, 183, 1, 0, 0, 0, 875, 876, 3, 56, 21, 0, 876, 877, 1, 0, 0, 0, 877, 878, 6, 85, 10, 0, 878, 185, 1, 0, 0, 0, 879, 880, 3, 58, 22, 0, 880, 881, 1, 0, 0, 0, 881, 882, 6, 86, 10, 0, 882, 187, 1, 0, 0, 0, 883, 884, 3, 74, 30, 0, 884, 885, 1, 0, 0, 0, 885, 886, 6, 87, 13, 0, 886, 887, 6, 87, 14, 0, 887, 189, 1, 0, 0, 0, 888, 889, 3, 172, 79, 0, 889, 890, 1, 0, 0, 0, 890, 891, 6, 88, 11, 0, 891, 191, 1, 0, 0, 0, 892, 893, 3, 174, 80, 0, 893, 894, 1, 0, 0, 0, 894, 895, 6, 89, 15, 0, 895, 193, 1, 0, 0, 0, 896, 897, 3, 112, 49, 0, 897, 898, 1, 0, 0, 0, 898, 899, 6, 90, 16, 0, 899, 195, 1, 0, 0, 0, 900, 901, 3, 108, 47, 0, 901, 902, 1, 0, 0, 0, 902, 903, 6, 91, 17, 0, 903, 197, 1, 0, 0, 0, 904, 905, 3, 96, 41, 0, 905, 906, 1, 0, 0, 0, 906, 907, 6, 92, 18, 0, 907, 199, 1, 0, 0, 0, 908, 909, 5, 109, 0, 0, 909, 910, 5, 101, 0, 0, 910, 911, 5, 116, 0, 0, 911, 912, 5, 97, 0, 0, 912, 913, 5, 100, 0, 0, 913, 914, 5, 97, 0, 0, 914, 915, 5, 116, 0, 0, 915, 916, 5, 97, 0, 0, 916, 201, 1, 0, 0, 0, 917, 918, 3, 62, 24, 0, 918, 919, 1, 0, 0, 0, 919, 920, 6, 94, 19, 0, 920, 203, 1, 0, 0, 0, 921, 922, 3, 54, 20, 0, 922, 923, 1, 0, 0, 0, 923, 924, 6, 95, 10, 0, 924, 205, 1, 0, 0, 0, 925, 926, 3, 56, 21, 0, 926, 927, 1, 0, 0, 0, 927, 928, 6, 96, 10, 0, 928, 207, 1, 0, 0, 0, 929, 930, 3, 58, 22, 0, 930, 931, 1, 0, 0, 0, 931, 932, 6, 97, 10, 0, 932, 209, 1, 0, 0, 0, 933, 934, 3, 74, 30, 0, 934, 935, 1, 0, 0, 0, 935, 936, 6, 98, 13, 0, 936, 937, 6, 98, 14, 0, 937, 211, 1, 0, 0, 0, 938, 939, 3, 116, 51, 0, 939, 940, 1, 0, 0, 0, 940, 941, 6, 99, 20, 0, 941, 213, 1, 0, 0, 0, 942, 943, 3, 112, 49, 0, 943, 944, 1, 0, 0, 0, 944, 945, 6, 100, 16, 0, 945, 215, 1, 0, 0, 0, 946, 951, 3, 78, 32, 0, 947, 951, 3, 76, 31, 0, 948, 951, 3, 92, 39, 0, 949, 951, 3, 166, 76, 0, 950, 946, 1, 0, 0, 0, 950, 947, 1, 0, 0, 0, 950, 948, 1, 0, 0, 0, 950, 949, 1, 0, 0, 0, 951, 217, 1, 0, 0, 0, 952, 955, 3, 78, 32, 0, 953, 955, 3, 166, 76, 0, 954, 952, 1, 0, 0, 0, 954, 953, 1, 0, 0, 0, 955, 959, 1, 0, 0, 0, 956, 958, 3, 216, 101, 0, 957, 956, 1, 0, 0, 0, 958, 961, 1, 0, 0, 0, 959, 957, 1, 0, 0, 0, 959, 960, 1, 0, 0, 0, 960, 972, 1, 0, 0, 0, 961, 959, 1, 0, 0, 0, 962, 965, 3, 92, 39, 0, 963, 965, 3, 86, 36, 0, 964, 962, 1, 0, 0, 0, 964, 963, 1, 0, 0, 0, 965, 967, 1, 0, 0, 0, 966, 968, 3, 216, 101, 0, 967, 966, 1, 0, 0, 0, 968, 969, 1, 0, 0, 0, 969, 967, 1, 0, 0, 0, 969, 970, 1, 0, 0, 0, 970, 972, 1, 0, 0, 0, 971, 954, 1, 0, 0, 0, 971, 964, 1, 0, 0, 0, 972, 219, 1, 0, 0, 0, 973, 976, 3, 218, 102, 0, 974, 976, 3, 178, 82, 0, 975, 973, 1, 0, 0, 0, 975, 974, 1, 0, 0, 0, 976, 977, 1, 0, 0, 0, 977, 975, 1, 0, 0, 0, 977, 978, 1, 0, 0, 0, 978, 221, 1, 0, 0, 0, 979, 980, 3, 54, 20, 0, 980, 981, 1, 0, 0, 0, 981, 982, 6, 104, 10, 0, 982, 223, 1, 0, 0, 0, 983, 984, 3, 56, 21, 0, 984, 985, 1, 0, 0, 0, 985, 986, 6, 105, 10, 0, 986, 225, 1, 0, 0, 0, 987, 988, 3, 58, 22, 0, 988, 989, 1, 0, 0, 0, 989, 990, 6, 106, 10, 0, 990, 227, 1, 0, 0, 0, 991, 992, 3, 74, 30, 0, 992, 993, 1, 0, 0, 0, 993, 994, 6, 107, 13, 0, 994, 995, 6, 107, 14, 0, 995, 229, 1, 0, 0, 0, 996, 997, 3, 108, 47, 0, 997, 998, 1, 0, 0, 0, 998, 999, 6, 108, 17, 0, 999, 231, 1, 0, 0, 0, 1000, 1001, 3, 112, 49, 0, 1001, 1002, 1, 0, 0, 0, 1002, 1003, 6, 109, 16, 0, 1003, 233, 1, 0, 0, 0, 1004, 1005, 3, 116, 51, 0, 1005, 1006, 1, 0, 0, 0, 1006, 1007, 6, 110, 20, 0, 1007, 235, 1, 0, 0, 0, 1008, 1009, 5, 97, 0, 0, 1009, 1010, 5, 115, 0, 0, 1010, 237, 1, 0, 0, 0, 1011, 1012, 3, 220, 103, 0, 1012, 1013, 1, 0, 0, 0, 1013, 1014, 6, 112, 21, 0, 1014, 239, 1, 0, 0, 0, 1015, 1016, 3, 54, 20, 0, 1016, 1017, 1, 0, 0, 0, 1017, 1018, 6, 113, 10, 0, 1018, 241, 1, 0, 0, 0, 1019, 1020, 3, 56, 21, 0, 1020, 1021, 1, 0, 0, 0, 1021, 1022, 6, 114, 10, 0, 1022, 243, 1, 0, 0, 0, 1023, 1024, 3, 58, 22, 0, 1024, 1025, 1, 0, 0, 0, 1025, 1026, 6, 115, 10, 0, 1026, 245, 1, 0, 0, 0, 1027, 1028, 3, 74, 30, 0, 1028, 1029, 1, 0, 0, 0, 1029, 1030, 6, 116, 13, 0, 1030, 1031, 6, 116, 14, 0, 1031, 247, 1, 0, 0, 0, 1032, 1033, 3, 172, 79, 0, 1033, 1034, 1, 0, 0, 0, 1034, 1035, 6, 117, 11, 0, 1035, 1036, 6, 117, 22, 0, 1036, 249, 1, 0, 0, 0, 1037, 1038, 5, 111, 0, 0, 1038, 1039, 5, 110, 0, 0, 1039, 1040, 1, 0, 0, 0, 1040, 1041, 6, 118, 23, 0, 1041, 251, 1, 0, 0, 0, 1042, 1043, 5, 119, 0, 0, 1043, 1044, 5, 105, 0, 0, 1044, 1045, 5, 116, 0, 0, 1045, 1046, 5, 104, 0, 0, 1046, 1047, 1, 0, 0, 0, 1047, 1048, 6, 119, 23, 0, 1048, 253, 1, 0, 0, 0, 1049, 1050, 8, 12, 0, 0, 1050, 255, 1, 0, 0, 0, 1051, 1053, 3, 254, 120, 0, 1052, 1051, 1, 0, 0, 0, 1053, 1054, 1, 0, 0, 0, 1054, 1052, 1, 0, 0, 0, 1054, 1055, 1, 0, 0, 0, 1055, 1056, 1, 0, 0, 0, 1056, 1057, 3, 324, 155, 0, 1057, 1059, 1, 0, 0, 0, 1058, 1052, 1, 0, 0, 0, 1058, 1059, 1, 0, 0, 0, 1059, 1061, 1, 0, 0, 0, 1060, 1062, 3, 254, 120, 0, 1061, 1060, 1, 0, 0, 0, 1062, 1063, 1, 0, 0, 0, 1063, 1061, 1, 0, 0, 0, 1063, 1064, 1, 0, 0, 0, 1064, 257, 1, 0, 0, 0, 1065, 1066, 3, 180, 83, 0, 1066, 1067, 1, 0, 0, 0, 1067, 1068, 6, 122, 24, 0, 1068, 259, 1, 0, 0, 0, 1069, 1070, 3, 256, 121, 0, 1070, 1071, 1, 0, 0, 0, 1071, 1072, 6, 123, 25, 0, 1072, 261, 1, 0, 0, 0, 1073, 1074, 3, 54, 20, 0, 1074, 1075, 1, 0, 0, 0, 1075, 1076, 6, 124, 10, 0, 1076, 263, 1, 0, 0, 0, 1077, 1078, 3, 56, 21, 0, 1078, 1079, 1, 0, 0, 0, 1079, 1080, 6, 125, 10, 0, 1080, 265, 1, 0, 0, 0, 1081, 1082, 3, 58, 22, 0, 1082, 1083, 1, 0, 0, 0, 1083, 1084, 6, 126, 10, 0, 1084, 267, 1, 0, 0, 0, 1085, 1086, 3, 74, 30, 0, 1086, 1087, 1, 0, 0, 0, 1087, 1088, 6, 127, 13, 0, 1088, 1089, 6, 127, 14, 0, 1089, 1090, 6, 127, 14, 0, 1090, 269, 1, 0, 0, 0, 1091, 1092, 3, 108, 47, 0, 1092, 1093, 1, 0, 0, 0, 1093, 1094, 6, 128, 17, 0, 1094, 271, 1, 0, 0, 0, 1095, 1096, 3, 112, 49, 0, 1096, 1097, 1, 0, 0, 0, 1097, 1098, 6, 129, 16, 0, 1098, 273, 1, 0, 0, 0, 1099, 1100, 3, 116, 51, 0, 1100, 1101, 1, 0, 0, 0, 1101, 1102, 6, 130, 20, 0, 1102, 275, 1, 0, 0, 0, 1103, 1104, 3, 252, 119, 0, 1104, 1105, 1, 0, 0, 0, 1105, 1106, 6, 131, 26, 0, 1106, 277, 1, 0, 0, 0, 1107, 1108, 3, 220, 103, 0, 1108, 1109, 1, 0, 0, 0, 1109, 1110, 6, 132, 21, 0, 1110, 279, 1, 0, 0, 0, 1111, 1112, 3, 180, 83, 0, 1112, 1113, 1, 0, 0, 0, 1113, 1114, 6, 133, 24, 0, 1114, 281, 1, 0, 0, 0, 1115, 1116, 3, 54, 20, 0, 1116, 1117, 1, 0, 0, 0, 1117, 1118, 6, 134, 10, 0, 1118, 283, 1, 0, 0, 0, 1119, 1120, 3, 56, 21, 0, 1120, 1121, 1, 0, 0, 0, 1121, 1122, 6, 135, 10, 0, 1122, 285, 1, 0, 0, 0, 1123, 1124, 3, 58, 22, 0, 1124, 1125, 1, 0, 0, 0, 1125, 1126, 6, 136, 10, 0, 1126, 287, 1, 0, 0, 0, 1127, 1128, 3, 74, 30, 0, 1128, 1129, 1, 0, 0, 0, 1129, 1130, 6, 137, 13, 0, 1130, 1131, 6, 137, 14, 0, 1131, 289, 1, 0, 0, 0, 1132, 1133, 3, 116, 51, 0, 1133, 1134, 1, 0, 0, 0, 1134, 1135, 6, 138, 20, 0, 1135, 291, 1, 0, 0, 0, 1136, 1137, 3, 180, 83, 0, 1137, 1138, 1, 0, 0, 0, 1138, 1139, 6, 139, 24, 0, 1139, 293, 1, 0, 0, 0, 1140, 1141, 3, 176, 81, 0, 1141, 1142, 1, 0, 0, 0, 1142, 1143, 6, 140, 27, 0, 1143, 295, 1, 0, 0, 0, 1144, 1145, 3, 54, 20, 0, 1145, 1146, 1, 0, 0, 0, 1146, 1147, 6, 141, 10, 0, 1147, 297, 1, 0, 0, 0, 1148, 1149, 3, 56, 21, 0, 1149, 1150, 1, 0, 0, 0, 1150, 1151, 6, 142, 10, 0, 1151, 299, 1, 0, 0, 0, 1152, 1153, 3, 58, 22, 0, 1153, 1154, 1, 0, 0, 0, 1154, 1155, 6, 143, 10, 0, 1155, 301, 1, 0, 0, 0, 1156, 1157, 3, 74, 30, 0, 1157, 1158, 1, 0, 0, 0, 1158, 1159, 6, 144, 13, 0, 1159, 1160, 6, 144, 14, 0, 1160, 303, 1, 0, 0, 0, 1161, 1162, 5, 105, 0, 0, 1162, 1163, 5, 110, 0, 0, 1163, 1164, 5, 102, 0, 0, 1164, 1165, 5, 111, 0, 0, 1165, 305, 1, 0, 0, 0, 1166, 1167, 3, 54, 20, 0, 1167, 1168, 1, 0, 0, 0, 1168, 1169, 6, 146, 10, 0, 1169, 307, 1, 0, 0, 0, 1170, 1171, 3, 56, 21, 0, 1171, 1172, 1, 0, 0, 0, 1172, 1173, 6, 147, 10, 0, 1173, 309, 1, 0, 0, 0, 1174, 1175, 3, 58, 22, 0, 1175, 1176, 1, 0, 0, 0, 1176, 1177, 6, 148, 10, 0, 1177, 311, 1, 0, 0, 0, 1178, 1179, 3, 74, 30, 0, 1179, 1180, 1, 0, 0, 0, 1180, 1181, 6, 149, 13, 0, 1181, 1182, 6, 149, 14, 0, 1182, 313, 1, 0, 0, 0, 1183, 1184, 5, 102, 0, 0, 1184, 1185, 5, 117, 0, 0, 1185, 1186, 5, 110, 0, 0, 1186, 1187, 5, 99, 0, 0, 1187, 1188, 5, 116, 0, 0, 1188, 1189, 5, 105, 0, 0, 1189, 1190, 5, 111, 0, 0, 1190, 1191, 5, 110, 0, 0, 1191, 1192, 5, 115, 0, 0, 1192, 315, 1, 0, 0, 0, 1193, 1194, 3, 54, 20, 0, 1194, 1195, 1, 0, 0, 0, 1195, 1196, 6, 151, 10, 0, 1196, 317, 1, 0, 0, 0, 1197, 1198, 3, 56, 21, 0, 1198, 1199, 1, 0, 0, 0, 1199, 1200, 6, 152, 10, 0, 1200, 319, 1, 0, 0, 0, 1201, 1202, 3, 58, 22, 0, 1202, 1203, 1, 0, 0, 0, 1203, 1204, 6, 153, 10, 0, 1204, 321, 1, 0, 0, 0, 1205, 1206, 3, 174, 80, 0, 1206, 1207, 1, 0, 0, 0, 1207, 1208, 6, 154, 15, 0, 1208, 1209, 6, 154, 14, 0, 1209, 323, 1, 0, 0, 0, 1210, 1211, 5, 58, 0, 0, 1211, 325, 1, 0, 0, 0, 1212, 1218, 3, 86, 36, 0, 1213, 1218, 3, 76, 31, 0, 1214, 1218, 3, 116, 51, 0, 1215, 1218, 3, 78, 32, 0, 1216, 1218, 3, 92, 39, 0, 1217, 1212, 1, 0, 0, 0, 1217, 1213, 1, 0, 0, 0, 1217, 1214, 1, 0, 0, 0, 1217, 1215, 1, 0, 0, 0, 1217, 1216, 1, 0, 0, 0, 1218, 1219, 1, 0, 0, 0, 1219, 1217, 1, 0, 0, 0, 1219, 1220, 1, 0, 0, 0, 1220, 327, 1, 0, 0, 0, 1221, 1222, 3, 54, 20, 0, 1222, 1223, 1, 0, 0, 0, 1223, 1224, 6, 157, 10, 0, 1224, 329, 1, 0, 0, 0, 1225, 1226, 3, 56, 21, 0, 1226, 1227, 1, 0, 0, 0, 1227, 1228, 6, 158, 10, 0, 1228, 331, 1, 0, 0, 0, 1229, 1230, 3, 58, 22, 0, 1230, 1231, 1, 0, 0, 0, 1231, 1232, 6, 159, 10, 0, 1232, 333, 1, 0, 0, 0, 1233, 1234, 3, 74, 30, 0, 1234, 1235, 1, 0, 0, 0, 1235, 1236, 6, 160, 13, 0, 1236, 1237, 6, 160, 14, 0, 1237, 335, 1, 0, 0, 0, 1238, 1239, 3, 62, 24, 0, 1239, 1240, 1, 0, 0, 0, 1240, 1241, 6, 161, 19, 0, 1241, 1242, 6, 161, 14, 0, 1242, 1243, 6, 161, 28, 0, 1243, 337, 1, 0, 0, 0, 1244, 1245, 3, 54, 20, 0, 1245, 1246, 1, 0, 0, 0, 1246, 1247, 6, 162, 10, 0, 1247, 339, 1, 0, 0, 0, 1248, 1249, 3, 56, 21, 0, 1249, 1250, 1, 0, 0, 0, 1250, 1251, 6, 163, 10, 0, 1251, 341, 1, 0, 0, 0, 1252, 1253, 3, 58, 22, 0, 1253, 1254, 1, 0, 0, 0, 1254, 1255, 6, 164, 10, 0, 1255, 343, 1, 0, 0, 0, 1256, 1257, 3, 112, 49, 0, 1257, 1258, 1, 0, 0, 0, 1258, 1259, 6, 165, 16, 0, 1259, 1260, 6, 165, 14, 0, 1260, 1261, 6, 165, 6, 0, 1261, 345, 1, 0, 0, 0, 1262, 1263, 3, 54, 20, 0, 1263, 1264, 1, 0, 0, 0, 1264, 1265, 6, 166, 10, 0, 1265, 347, 1, 0, 0, 0, 1266, 1267, 3, 56, 21, 0, 1267, 1268, 1, 0, 0, 0, 1268, 1269, 6, 167, 10, 0, 1269, 349, 1, 0, 0, 0, 1270, 1271, 3, 58, 22, 0, 1271, 1272, 1, 0, 0, 0, 1272, 1273, 6, 168, 10, 0, 1273, 351, 1, 0, 0, 0, 1274, 1275, 3, 180, 83, 0, 1275, 1276, 1, 0, 0, 0, 1276, 1277, 6, 169, 14, 0, 1277, 1278, 6, 169, 0, 0, 1278, 1279, 6, 169, 24, 0, 1279, 353, 1, 0, 0, 0, 1280, 1281, 3, 176, 81, 0, 1281, 1282, 1, 0, 0, 0, 1282, 1283, 6, 170, 14, 0, 1283, 1284, 6, 170, 0, 0, 1284, 1285, 6, 170, 27, 0, 1285, 355, 1, 0, 0, 0, 1286, 1287, 3, 102, 44, 0, 1287, 1288, 1, 0, 0, 0, 1288, 1289, 6, 171, 14, 0, 1289, 1290, 6, 171, 0, 0, 1290, 1291, 6, 171, 29, 0, 1291, 357, 1, 0, 0, 0, 1292, 1293, 3, 74, 30, 0, 1293, 1294, 1, 0, 0, 0, 1294, 1295, 6, 172, 13, 0, 1295, 1296, 6, 172, 14, 0, 1296, 359, 1, 0, 0, 0, 60, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 523, 533, 537, 540, 549, 551, 562, 569, 574, 613, 618, 627, 634, 639, 641, 652, 660, 663, 665, 670, 675, 681, 688, 693, 699, 702, 710, 714, 847, 852, 857, 859, 865, 950, 954, 959, 964, 969, 971, 975, 977, 1054, 1058, 1063, 1217, 1219, 30, 5, 2, 0, 5, 4, 0, 5, 6, 0, 5, 1, 0, 5, 3, 0, 5, 10, 0, 5, 12, 0, 5, 8, 0, 5, 5, 0, 5, 9, 0, 0, 1, 0, 7, 67, 0, 5, 0, 0, 7, 28, 0, 4, 0, 0, 7, 68, 0, 7, 37, 0, 7, 35, 0, 7, 29, 0, 7, 24, 0, 7, 39, 0, 7, 78, 0, 5, 11, 0, 5, 7, 0, 7, 70, 0, 7, 88, 0, 7, 87, 0, 7, 69, 0, 5, 13, 0, 7, 32, 0] \ No newline at end of file +[4, 0, 123, 1404, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139, 2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144, 7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148, 2, 149, 7, 149, 2, 150, 7, 150, 2, 151, 7, 151, 2, 152, 7, 152, 2, 153, 7, 153, 2, 154, 7, 154, 2, 155, 7, 155, 2, 156, 7, 156, 2, 157, 7, 157, 2, 158, 7, 158, 2, 159, 7, 159, 2, 160, 7, 160, 2, 161, 7, 161, 2, 162, 7, 162, 2, 163, 7, 163, 2, 164, 7, 164, 2, 165, 7, 165, 2, 166, 7, 166, 2, 167, 7, 167, 2, 168, 7, 168, 2, 169, 7, 169, 2, 170, 7, 170, 2, 171, 7, 171, 2, 172, 7, 172, 2, 173, 7, 173, 2, 174, 7, 174, 2, 175, 7, 175, 2, 176, 7, 176, 2, 177, 7, 177, 2, 178, 7, 178, 2, 179, 7, 179, 2, 180, 7, 180, 2, 181, 7, 181, 2, 182, 7, 182, 2, 183, 7, 183, 2, 184, 7, 184, 2, 185, 7, 185, 2, 186, 7, 186, 2, 187, 7, 187, 2, 188, 7, 188, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 4, 20, 565, 8, 20, 11, 20, 12, 20, 566, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 5, 21, 575, 8, 21, 10, 21, 12, 21, 578, 9, 21, 1, 21, 3, 21, 581, 8, 21, 1, 21, 3, 21, 584, 8, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 5, 22, 593, 8, 22, 10, 22, 12, 22, 596, 9, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 4, 23, 604, 8, 23, 11, 23, 12, 23, 605, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 3, 24, 613, 8, 24, 1, 25, 4, 25, 616, 8, 25, 11, 25, 12, 25, 617, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 36, 1, 36, 3, 36, 657, 8, 36, 1, 36, 4, 36, 660, 8, 36, 11, 36, 12, 36, 661, 1, 37, 1, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 3, 39, 671, 8, 39, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 3, 41, 678, 8, 41, 1, 42, 1, 42, 1, 42, 5, 42, 683, 8, 42, 10, 42, 12, 42, 686, 9, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 5, 42, 694, 8, 42, 10, 42, 12, 42, 697, 9, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 704, 8, 42, 1, 42, 3, 42, 707, 8, 42, 3, 42, 709, 8, 42, 1, 43, 4, 43, 712, 8, 43, 11, 43, 12, 43, 713, 1, 44, 4, 44, 717, 8, 44, 11, 44, 12, 44, 718, 1, 44, 1, 44, 5, 44, 723, 8, 44, 10, 44, 12, 44, 726, 9, 44, 1, 44, 1, 44, 4, 44, 730, 8, 44, 11, 44, 12, 44, 731, 1, 44, 4, 44, 735, 8, 44, 11, 44, 12, 44, 736, 1, 44, 1, 44, 5, 44, 741, 8, 44, 10, 44, 12, 44, 744, 9, 44, 3, 44, 746, 8, 44, 1, 44, 1, 44, 1, 44, 1, 44, 4, 44, 752, 8, 44, 11, 44, 12, 44, 753, 1, 44, 1, 44, 3, 44, 758, 8, 44, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 76, 1, 76, 1, 77, 1, 77, 1, 78, 1, 78, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 5, 82, 889, 8, 82, 10, 82, 12, 82, 892, 9, 82, 1, 82, 1, 82, 3, 82, 896, 8, 82, 1, 82, 4, 82, 899, 8, 82, 11, 82, 12, 82, 900, 3, 82, 903, 8, 82, 1, 83, 1, 83, 4, 83, 907, 8, 83, 11, 83, 12, 83, 908, 1, 83, 1, 83, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 96, 1, 96, 1, 97, 1, 97, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 102, 1, 102, 3, 102, 994, 8, 102, 1, 103, 1, 103, 3, 103, 998, 8, 103, 1, 103, 5, 103, 1001, 8, 103, 10, 103, 12, 103, 1004, 9, 103, 1, 103, 1, 103, 3, 103, 1008, 8, 103, 1, 103, 4, 103, 1011, 8, 103, 11, 103, 12, 103, 1012, 3, 103, 1015, 8, 103, 1, 104, 1, 104, 4, 104, 1019, 8, 104, 11, 104, 12, 104, 1020, 1, 105, 1, 105, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 1, 107, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 109, 1, 109, 1, 109, 1, 109, 1, 110, 1, 110, 1, 110, 1, 110, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1, 115, 1, 115, 1, 116, 1, 116, 1, 116, 1, 116, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 122, 4, 122, 1096, 8, 122, 11, 122, 12, 122, 1097, 1, 122, 1, 122, 3, 122, 1102, 8, 122, 1, 122, 4, 122, 1105, 8, 122, 11, 122, 12, 122, 1106, 1, 123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 129, 1, 129, 1, 129, 1, 129, 1, 130, 1, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 131, 1, 131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 133, 1, 133, 1, 133, 1, 133, 1, 134, 1, 134, 1, 134, 1, 134, 1, 135, 1, 135, 1, 135, 1, 135, 1, 136, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 137, 1, 137, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 1, 143, 1, 143, 1, 143, 1, 143, 1, 144, 1, 144, 1, 144, 1, 144, 1, 145, 1, 145, 1, 145, 1, 145, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 148, 1, 148, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1, 151, 1, 151, 1, 152, 1, 152, 1, 152, 1, 152, 1, 153, 1, 153, 1, 153, 1, 153, 1, 153, 1, 154, 1, 154, 1, 154, 1, 154, 1, 155, 1, 155, 1, 155, 1, 155, 1, 156, 1, 156, 1, 156, 1, 156, 1, 157, 1, 157, 1, 157, 1, 157, 1, 158, 1, 158, 1, 158, 1, 158, 1, 159, 1, 159, 1, 159, 1, 159, 1, 160, 1, 160, 1, 160, 1, 160, 1, 160, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 163, 1, 163, 1, 163, 1, 163, 1, 164, 1, 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1, 168, 1, 168, 1, 168, 1, 169, 1, 169, 1, 169, 1, 169, 1, 170, 1, 170, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 172, 4, 172, 1325, 8, 172, 11, 172, 12, 172, 1326, 1, 173, 1, 173, 1, 173, 1, 173, 1, 174, 1, 174, 1, 174, 1, 174, 1, 175, 1, 175, 1, 175, 1, 175, 1, 176, 1, 176, 1, 176, 1, 176, 1, 176, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 1, 178, 1, 178, 1, 178, 1, 178, 1, 179, 1, 179, 1, 179, 1, 179, 1, 180, 1, 180, 1, 180, 1, 180, 1, 181, 1, 181, 1, 181, 1, 181, 1, 181, 1, 181, 1, 182, 1, 182, 1, 182, 1, 182, 1, 183, 1, 183, 1, 183, 1, 183, 1, 184, 1, 184, 1, 184, 1, 184, 1, 185, 1, 185, 1, 185, 1, 185, 1, 185, 1, 185, 1, 186, 1, 186, 1, 186, 1, 186, 1, 186, 1, 186, 1, 187, 1, 187, 1, 187, 1, 187, 1, 187, 1, 187, 1, 188, 1, 188, 1, 188, 1, 188, 1, 188, 2, 594, 695, 0, 189, 16, 1, 18, 2, 20, 3, 22, 4, 24, 5, 26, 6, 28, 7, 30, 8, 32, 9, 34, 10, 36, 11, 38, 12, 40, 13, 42, 14, 44, 15, 46, 16, 48, 17, 50, 18, 52, 19, 54, 20, 56, 21, 58, 22, 60, 23, 62, 24, 64, 0, 66, 25, 68, 0, 70, 0, 72, 26, 74, 27, 76, 28, 78, 29, 80, 0, 82, 0, 84, 0, 86, 0, 88, 0, 90, 0, 92, 0, 94, 0, 96, 0, 98, 0, 100, 30, 102, 31, 104, 32, 106, 33, 108, 34, 110, 35, 112, 36, 114, 37, 116, 38, 118, 39, 120, 40, 122, 41, 124, 42, 126, 43, 128, 44, 130, 45, 132, 46, 134, 47, 136, 48, 138, 49, 140, 50, 142, 51, 144, 52, 146, 53, 148, 54, 150, 55, 152, 56, 154, 57, 156, 58, 158, 59, 160, 60, 162, 61, 164, 62, 166, 63, 168, 64, 170, 65, 172, 66, 174, 67, 176, 68, 178, 69, 180, 70, 182, 0, 184, 71, 186, 72, 188, 73, 190, 74, 192, 0, 194, 0, 196, 0, 198, 0, 200, 0, 202, 0, 204, 75, 206, 0, 208, 76, 210, 77, 212, 78, 214, 0, 216, 0, 218, 0, 220, 0, 222, 0, 224, 79, 226, 80, 228, 81, 230, 82, 232, 0, 234, 0, 236, 0, 238, 0, 240, 83, 242, 0, 244, 84, 246, 85, 248, 86, 250, 0, 252, 0, 254, 87, 256, 88, 258, 0, 260, 89, 262, 0, 264, 0, 266, 90, 268, 91, 270, 92, 272, 0, 274, 0, 276, 0, 278, 0, 280, 0, 282, 0, 284, 0, 286, 93, 288, 94, 290, 95, 292, 0, 294, 0, 296, 0, 298, 0, 300, 0, 302, 96, 304, 97, 306, 98, 308, 0, 310, 0, 312, 0, 314, 0, 316, 99, 318, 100, 320, 101, 322, 0, 324, 0, 326, 0, 328, 0, 330, 102, 332, 103, 334, 104, 336, 0, 338, 105, 340, 106, 342, 107, 344, 108, 346, 0, 348, 109, 350, 110, 352, 111, 354, 112, 356, 0, 358, 113, 360, 114, 362, 115, 364, 116, 366, 117, 368, 0, 370, 0, 372, 118, 374, 119, 376, 120, 378, 0, 380, 121, 382, 122, 384, 123, 386, 0, 388, 0, 390, 0, 392, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 13, 6, 0, 9, 10, 13, 13, 32, 32, 47, 47, 91, 91, 93, 93, 2, 0, 10, 10, 13, 13, 3, 0, 9, 10, 13, 13, 32, 32, 10, 0, 9, 10, 13, 13, 32, 32, 44, 44, 47, 47, 61, 61, 91, 91, 93, 93, 96, 96, 124, 124, 2, 0, 42, 42, 47, 47, 1, 0, 48, 57, 2, 0, 65, 90, 97, 122, 5, 0, 34, 34, 92, 92, 110, 110, 114, 114, 116, 116, 4, 0, 10, 10, 13, 13, 34, 34, 92, 92, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 1, 0, 96, 96, 11, 0, 9, 10, 13, 13, 32, 32, 34, 35, 44, 44, 47, 47, 58, 58, 60, 60, 62, 63, 92, 92, 124, 124, 1427, 0, 16, 1, 0, 0, 0, 0, 18, 1, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 24, 1, 0, 0, 0, 0, 26, 1, 0, 0, 0, 0, 28, 1, 0, 0, 0, 0, 30, 1, 0, 0, 0, 0, 32, 1, 0, 0, 0, 0, 34, 1, 0, 0, 0, 0, 36, 1, 0, 0, 0, 0, 38, 1, 0, 0, 0, 0, 40, 1, 0, 0, 0, 0, 42, 1, 0, 0, 0, 0, 44, 1, 0, 0, 0, 0, 46, 1, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 50, 1, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 54, 1, 0, 0, 0, 0, 56, 1, 0, 0, 0, 0, 58, 1, 0, 0, 0, 0, 60, 1, 0, 0, 0, 0, 62, 1, 0, 0, 0, 0, 66, 1, 0, 0, 0, 1, 68, 1, 0, 0, 0, 1, 70, 1, 0, 0, 0, 1, 72, 1, 0, 0, 0, 1, 74, 1, 0, 0, 0, 1, 76, 1, 0, 0, 0, 2, 78, 1, 0, 0, 0, 2, 100, 1, 0, 0, 0, 2, 102, 1, 0, 0, 0, 2, 104, 1, 0, 0, 0, 2, 106, 1, 0, 0, 0, 2, 108, 1, 0, 0, 0, 2, 110, 1, 0, 0, 0, 2, 112, 1, 0, 0, 0, 2, 114, 1, 0, 0, 0, 2, 116, 1, 0, 0, 0, 2, 118, 1, 0, 0, 0, 2, 120, 1, 0, 0, 0, 2, 122, 1, 0, 0, 0, 2, 124, 1, 0, 0, 0, 2, 126, 1, 0, 0, 0, 2, 128, 1, 0, 0, 0, 2, 130, 1, 0, 0, 0, 2, 132, 1, 0, 0, 0, 2, 134, 1, 0, 0, 0, 2, 136, 1, 0, 0, 0, 2, 138, 1, 0, 0, 0, 2, 140, 1, 0, 0, 0, 2, 142, 1, 0, 0, 0, 2, 144, 1, 0, 0, 0, 2, 146, 1, 0, 0, 0, 2, 148, 1, 0, 0, 0, 2, 150, 1, 0, 0, 0, 2, 152, 1, 0, 0, 0, 2, 154, 1, 0, 0, 0, 2, 156, 1, 0, 0, 0, 2, 158, 1, 0, 0, 0, 2, 160, 1, 0, 0, 0, 2, 162, 1, 0, 0, 0, 2, 164, 1, 0, 0, 0, 2, 166, 1, 0, 0, 0, 2, 168, 1, 0, 0, 0, 2, 170, 1, 0, 0, 0, 2, 172, 1, 0, 0, 0, 2, 174, 1, 0, 0, 0, 2, 176, 1, 0, 0, 0, 2, 178, 1, 0, 0, 0, 2, 180, 1, 0, 0, 0, 2, 184, 1, 0, 0, 0, 2, 186, 1, 0, 0, 0, 2, 188, 1, 0, 0, 0, 2, 190, 1, 0, 0, 0, 3, 192, 1, 0, 0, 0, 3, 194, 1, 0, 0, 0, 3, 196, 1, 0, 0, 0, 3, 198, 1, 0, 0, 0, 3, 200, 1, 0, 0, 0, 3, 202, 1, 0, 0, 0, 3, 204, 1, 0, 0, 0, 3, 206, 1, 0, 0, 0, 3, 208, 1, 0, 0, 0, 3, 210, 1, 0, 0, 0, 3, 212, 1, 0, 0, 0, 4, 214, 1, 0, 0, 0, 4, 216, 1, 0, 0, 0, 4, 218, 1, 0, 0, 0, 4, 224, 1, 0, 0, 0, 4, 226, 1, 0, 0, 0, 4, 228, 1, 0, 0, 0, 4, 230, 1, 0, 0, 0, 5, 232, 1, 0, 0, 0, 5, 234, 1, 0, 0, 0, 5, 236, 1, 0, 0, 0, 5, 238, 1, 0, 0, 0, 5, 240, 1, 0, 0, 0, 5, 242, 1, 0, 0, 0, 5, 244, 1, 0, 0, 0, 5, 246, 1, 0, 0, 0, 5, 248, 1, 0, 0, 0, 6, 250, 1, 0, 0, 0, 6, 252, 1, 0, 0, 0, 6, 254, 1, 0, 0, 0, 6, 256, 1, 0, 0, 0, 6, 260, 1, 0, 0, 0, 6, 262, 1, 0, 0, 0, 6, 264, 1, 0, 0, 0, 6, 266, 1, 0, 0, 0, 6, 268, 1, 0, 0, 0, 6, 270, 1, 0, 0, 0, 7, 272, 1, 0, 0, 0, 7, 274, 1, 0, 0, 0, 7, 276, 1, 0, 0, 0, 7, 278, 1, 0, 0, 0, 7, 280, 1, 0, 0, 0, 7, 282, 1, 0, 0, 0, 7, 284, 1, 0, 0, 0, 7, 286, 1, 0, 0, 0, 7, 288, 1, 0, 0, 0, 7, 290, 1, 0, 0, 0, 8, 292, 1, 0, 0, 0, 8, 294, 1, 0, 0, 0, 8, 296, 1, 0, 0, 0, 8, 298, 1, 0, 0, 0, 8, 300, 1, 0, 0, 0, 8, 302, 1, 0, 0, 0, 8, 304, 1, 0, 0, 0, 8, 306, 1, 0, 0, 0, 9, 308, 1, 0, 0, 0, 9, 310, 1, 0, 0, 0, 9, 312, 1, 0, 0, 0, 9, 314, 1, 0, 0, 0, 9, 316, 1, 0, 0, 0, 9, 318, 1, 0, 0, 0, 9, 320, 1, 0, 0, 0, 10, 322, 1, 0, 0, 0, 10, 324, 1, 0, 0, 0, 10, 326, 1, 0, 0, 0, 10, 328, 1, 0, 0, 0, 10, 330, 1, 0, 0, 0, 10, 332, 1, 0, 0, 0, 10, 334, 1, 0, 0, 0, 11, 336, 1, 0, 0, 0, 11, 338, 1, 0, 0, 0, 11, 340, 1, 0, 0, 0, 11, 342, 1, 0, 0, 0, 11, 344, 1, 0, 0, 0, 12, 346, 1, 0, 0, 0, 12, 348, 1, 0, 0, 0, 12, 350, 1, 0, 0, 0, 12, 352, 1, 0, 0, 0, 12, 354, 1, 0, 0, 0, 13, 356, 1, 0, 0, 0, 13, 358, 1, 0, 0, 0, 13, 360, 1, 0, 0, 0, 13, 362, 1, 0, 0, 0, 13, 364, 1, 0, 0, 0, 13, 366, 1, 0, 0, 0, 14, 368, 1, 0, 0, 0, 14, 370, 1, 0, 0, 0, 14, 372, 1, 0, 0, 0, 14, 374, 1, 0, 0, 0, 14, 376, 1, 0, 0, 0, 15, 378, 1, 0, 0, 0, 15, 380, 1, 0, 0, 0, 15, 382, 1, 0, 0, 0, 15, 384, 1, 0, 0, 0, 15, 386, 1, 0, 0, 0, 15, 388, 1, 0, 0, 0, 15, 390, 1, 0, 0, 0, 15, 392, 1, 0, 0, 0, 16, 394, 1, 0, 0, 0, 18, 404, 1, 0, 0, 0, 20, 411, 1, 0, 0, 0, 22, 420, 1, 0, 0, 0, 24, 427, 1, 0, 0, 0, 26, 437, 1, 0, 0, 0, 28, 444, 1, 0, 0, 0, 30, 451, 1, 0, 0, 0, 32, 465, 1, 0, 0, 0, 34, 472, 1, 0, 0, 0, 36, 480, 1, 0, 0, 0, 38, 489, 1, 0, 0, 0, 40, 496, 1, 0, 0, 0, 42, 506, 1, 0, 0, 0, 44, 518, 1, 0, 0, 0, 46, 527, 1, 0, 0, 0, 48, 533, 1, 0, 0, 0, 50, 540, 1, 0, 0, 0, 52, 547, 1, 0, 0, 0, 54, 555, 1, 0, 0, 0, 56, 564, 1, 0, 0, 0, 58, 570, 1, 0, 0, 0, 60, 587, 1, 0, 0, 0, 62, 603, 1, 0, 0, 0, 64, 612, 1, 0, 0, 0, 66, 615, 1, 0, 0, 0, 68, 619, 1, 0, 0, 0, 70, 624, 1, 0, 0, 0, 72, 629, 1, 0, 0, 0, 74, 633, 1, 0, 0, 0, 76, 637, 1, 0, 0, 0, 78, 641, 1, 0, 0, 0, 80, 645, 1, 0, 0, 0, 82, 647, 1, 0, 0, 0, 84, 649, 1, 0, 0, 0, 86, 652, 1, 0, 0, 0, 88, 654, 1, 0, 0, 0, 90, 663, 1, 0, 0, 0, 92, 665, 1, 0, 0, 0, 94, 670, 1, 0, 0, 0, 96, 672, 1, 0, 0, 0, 98, 677, 1, 0, 0, 0, 100, 708, 1, 0, 0, 0, 102, 711, 1, 0, 0, 0, 104, 757, 1, 0, 0, 0, 106, 759, 1, 0, 0, 0, 108, 762, 1, 0, 0, 0, 110, 766, 1, 0, 0, 0, 112, 770, 1, 0, 0, 0, 114, 772, 1, 0, 0, 0, 116, 775, 1, 0, 0, 0, 118, 777, 1, 0, 0, 0, 120, 782, 1, 0, 0, 0, 122, 784, 1, 0, 0, 0, 124, 790, 1, 0, 0, 0, 126, 796, 1, 0, 0, 0, 128, 801, 1, 0, 0, 0, 130, 803, 1, 0, 0, 0, 132, 806, 1, 0, 0, 0, 134, 809, 1, 0, 0, 0, 136, 814, 1, 0, 0, 0, 138, 818, 1, 0, 0, 0, 140, 823, 1, 0, 0, 0, 142, 829, 1, 0, 0, 0, 144, 832, 1, 0, 0, 0, 146, 834, 1, 0, 0, 0, 148, 840, 1, 0, 0, 0, 150, 842, 1, 0, 0, 0, 152, 847, 1, 0, 0, 0, 154, 850, 1, 0, 0, 0, 156, 853, 1, 0, 0, 0, 158, 856, 1, 0, 0, 0, 160, 858, 1, 0, 0, 0, 162, 861, 1, 0, 0, 0, 164, 863, 1, 0, 0, 0, 166, 866, 1, 0, 0, 0, 168, 868, 1, 0, 0, 0, 170, 870, 1, 0, 0, 0, 172, 872, 1, 0, 0, 0, 174, 874, 1, 0, 0, 0, 176, 876, 1, 0, 0, 0, 178, 881, 1, 0, 0, 0, 180, 902, 1, 0, 0, 0, 182, 904, 1, 0, 0, 0, 184, 912, 1, 0, 0, 0, 186, 914, 1, 0, 0, 0, 188, 918, 1, 0, 0, 0, 190, 922, 1, 0, 0, 0, 192, 926, 1, 0, 0, 0, 194, 931, 1, 0, 0, 0, 196, 935, 1, 0, 0, 0, 198, 939, 1, 0, 0, 0, 200, 943, 1, 0, 0, 0, 202, 947, 1, 0, 0, 0, 204, 951, 1, 0, 0, 0, 206, 960, 1, 0, 0, 0, 208, 964, 1, 0, 0, 0, 210, 968, 1, 0, 0, 0, 212, 972, 1, 0, 0, 0, 214, 976, 1, 0, 0, 0, 216, 981, 1, 0, 0, 0, 218, 985, 1, 0, 0, 0, 220, 993, 1, 0, 0, 0, 222, 1014, 1, 0, 0, 0, 224, 1018, 1, 0, 0, 0, 226, 1022, 1, 0, 0, 0, 228, 1026, 1, 0, 0, 0, 230, 1030, 1, 0, 0, 0, 232, 1034, 1, 0, 0, 0, 234, 1039, 1, 0, 0, 0, 236, 1043, 1, 0, 0, 0, 238, 1047, 1, 0, 0, 0, 240, 1051, 1, 0, 0, 0, 242, 1054, 1, 0, 0, 0, 244, 1058, 1, 0, 0, 0, 246, 1062, 1, 0, 0, 0, 248, 1066, 1, 0, 0, 0, 250, 1070, 1, 0, 0, 0, 252, 1075, 1, 0, 0, 0, 254, 1080, 1, 0, 0, 0, 256, 1085, 1, 0, 0, 0, 258, 1092, 1, 0, 0, 0, 260, 1101, 1, 0, 0, 0, 262, 1108, 1, 0, 0, 0, 264, 1112, 1, 0, 0, 0, 266, 1116, 1, 0, 0, 0, 268, 1120, 1, 0, 0, 0, 270, 1124, 1, 0, 0, 0, 272, 1128, 1, 0, 0, 0, 274, 1134, 1, 0, 0, 0, 276, 1138, 1, 0, 0, 0, 278, 1142, 1, 0, 0, 0, 280, 1146, 1, 0, 0, 0, 282, 1150, 1, 0, 0, 0, 284, 1154, 1, 0, 0, 0, 286, 1158, 1, 0, 0, 0, 288, 1162, 1, 0, 0, 0, 290, 1166, 1, 0, 0, 0, 292, 1170, 1, 0, 0, 0, 294, 1175, 1, 0, 0, 0, 296, 1179, 1, 0, 0, 0, 298, 1183, 1, 0, 0, 0, 300, 1188, 1, 0, 0, 0, 302, 1192, 1, 0, 0, 0, 304, 1196, 1, 0, 0, 0, 306, 1200, 1, 0, 0, 0, 308, 1204, 1, 0, 0, 0, 310, 1210, 1, 0, 0, 0, 312, 1214, 1, 0, 0, 0, 314, 1218, 1, 0, 0, 0, 316, 1222, 1, 0, 0, 0, 318, 1226, 1, 0, 0, 0, 320, 1230, 1, 0, 0, 0, 322, 1234, 1, 0, 0, 0, 324, 1239, 1, 0, 0, 0, 326, 1243, 1, 0, 0, 0, 328, 1247, 1, 0, 0, 0, 330, 1251, 1, 0, 0, 0, 332, 1255, 1, 0, 0, 0, 334, 1259, 1, 0, 0, 0, 336, 1263, 1, 0, 0, 0, 338, 1268, 1, 0, 0, 0, 340, 1273, 1, 0, 0, 0, 342, 1277, 1, 0, 0, 0, 344, 1281, 1, 0, 0, 0, 346, 1285, 1, 0, 0, 0, 348, 1290, 1, 0, 0, 0, 350, 1300, 1, 0, 0, 0, 352, 1304, 1, 0, 0, 0, 354, 1308, 1, 0, 0, 0, 356, 1312, 1, 0, 0, 0, 358, 1317, 1, 0, 0, 0, 360, 1324, 1, 0, 0, 0, 362, 1328, 1, 0, 0, 0, 364, 1332, 1, 0, 0, 0, 366, 1336, 1, 0, 0, 0, 368, 1340, 1, 0, 0, 0, 370, 1345, 1, 0, 0, 0, 372, 1351, 1, 0, 0, 0, 374, 1355, 1, 0, 0, 0, 376, 1359, 1, 0, 0, 0, 378, 1363, 1, 0, 0, 0, 380, 1369, 1, 0, 0, 0, 382, 1373, 1, 0, 0, 0, 384, 1377, 1, 0, 0, 0, 386, 1381, 1, 0, 0, 0, 388, 1387, 1, 0, 0, 0, 390, 1393, 1, 0, 0, 0, 392, 1399, 1, 0, 0, 0, 394, 395, 5, 100, 0, 0, 395, 396, 5, 105, 0, 0, 396, 397, 5, 115, 0, 0, 397, 398, 5, 115, 0, 0, 398, 399, 5, 101, 0, 0, 399, 400, 5, 99, 0, 0, 400, 401, 5, 116, 0, 0, 401, 402, 1, 0, 0, 0, 402, 403, 6, 0, 0, 0, 403, 17, 1, 0, 0, 0, 404, 405, 5, 100, 0, 0, 405, 406, 5, 114, 0, 0, 406, 407, 5, 111, 0, 0, 407, 408, 5, 112, 0, 0, 408, 409, 1, 0, 0, 0, 409, 410, 6, 1, 1, 0, 410, 19, 1, 0, 0, 0, 411, 412, 5, 101, 0, 0, 412, 413, 5, 110, 0, 0, 413, 414, 5, 114, 0, 0, 414, 415, 5, 105, 0, 0, 415, 416, 5, 99, 0, 0, 416, 417, 5, 104, 0, 0, 417, 418, 1, 0, 0, 0, 418, 419, 6, 2, 2, 0, 419, 21, 1, 0, 0, 0, 420, 421, 5, 101, 0, 0, 421, 422, 5, 118, 0, 0, 422, 423, 5, 97, 0, 0, 423, 424, 5, 108, 0, 0, 424, 425, 1, 0, 0, 0, 425, 426, 6, 3, 0, 0, 426, 23, 1, 0, 0, 0, 427, 428, 5, 101, 0, 0, 428, 429, 5, 120, 0, 0, 429, 430, 5, 112, 0, 0, 430, 431, 5, 108, 0, 0, 431, 432, 5, 97, 0, 0, 432, 433, 5, 105, 0, 0, 433, 434, 5, 110, 0, 0, 434, 435, 1, 0, 0, 0, 435, 436, 6, 4, 3, 0, 436, 25, 1, 0, 0, 0, 437, 438, 5, 102, 0, 0, 438, 439, 5, 114, 0, 0, 439, 440, 5, 111, 0, 0, 440, 441, 5, 109, 0, 0, 441, 442, 1, 0, 0, 0, 442, 443, 6, 5, 4, 0, 443, 27, 1, 0, 0, 0, 444, 445, 5, 103, 0, 0, 445, 446, 5, 114, 0, 0, 446, 447, 5, 111, 0, 0, 447, 448, 5, 107, 0, 0, 448, 449, 1, 0, 0, 0, 449, 450, 6, 6, 0, 0, 450, 29, 1, 0, 0, 0, 451, 452, 5, 105, 0, 0, 452, 453, 5, 110, 0, 0, 453, 454, 5, 108, 0, 0, 454, 455, 5, 105, 0, 0, 455, 456, 5, 110, 0, 0, 456, 457, 5, 101, 0, 0, 457, 458, 5, 115, 0, 0, 458, 459, 5, 116, 0, 0, 459, 460, 5, 97, 0, 0, 460, 461, 5, 116, 0, 0, 461, 462, 5, 115, 0, 0, 462, 463, 1, 0, 0, 0, 463, 464, 6, 7, 0, 0, 464, 31, 1, 0, 0, 0, 465, 466, 5, 107, 0, 0, 466, 467, 5, 101, 0, 0, 467, 468, 5, 101, 0, 0, 468, 469, 5, 112, 0, 0, 469, 470, 1, 0, 0, 0, 470, 471, 6, 8, 1, 0, 471, 33, 1, 0, 0, 0, 472, 473, 5, 108, 0, 0, 473, 474, 5, 105, 0, 0, 474, 475, 5, 109, 0, 0, 475, 476, 5, 105, 0, 0, 476, 477, 5, 116, 0, 0, 477, 478, 1, 0, 0, 0, 478, 479, 6, 9, 0, 0, 479, 35, 1, 0, 0, 0, 480, 481, 5, 108, 0, 0, 481, 482, 5, 111, 0, 0, 482, 483, 5, 111, 0, 0, 483, 484, 5, 107, 0, 0, 484, 485, 5, 117, 0, 0, 485, 486, 5, 112, 0, 0, 486, 487, 1, 0, 0, 0, 487, 488, 6, 10, 5, 0, 488, 37, 1, 0, 0, 0, 489, 490, 5, 109, 0, 0, 490, 491, 5, 101, 0, 0, 491, 492, 5, 116, 0, 0, 492, 493, 5, 97, 0, 0, 493, 494, 1, 0, 0, 0, 494, 495, 6, 11, 6, 0, 495, 39, 1, 0, 0, 0, 496, 497, 5, 109, 0, 0, 497, 498, 5, 101, 0, 0, 498, 499, 5, 116, 0, 0, 499, 500, 5, 114, 0, 0, 500, 501, 5, 105, 0, 0, 501, 502, 5, 99, 0, 0, 502, 503, 5, 115, 0, 0, 503, 504, 1, 0, 0, 0, 504, 505, 6, 12, 7, 0, 505, 41, 1, 0, 0, 0, 506, 507, 5, 109, 0, 0, 507, 508, 5, 118, 0, 0, 508, 509, 5, 95, 0, 0, 509, 510, 5, 101, 0, 0, 510, 511, 5, 120, 0, 0, 511, 512, 5, 112, 0, 0, 512, 513, 5, 97, 0, 0, 513, 514, 5, 110, 0, 0, 514, 515, 5, 100, 0, 0, 515, 516, 1, 0, 0, 0, 516, 517, 6, 13, 8, 0, 517, 43, 1, 0, 0, 0, 518, 519, 5, 114, 0, 0, 519, 520, 5, 101, 0, 0, 520, 521, 5, 110, 0, 0, 521, 522, 5, 97, 0, 0, 522, 523, 5, 109, 0, 0, 523, 524, 5, 101, 0, 0, 524, 525, 1, 0, 0, 0, 525, 526, 6, 14, 9, 0, 526, 45, 1, 0, 0, 0, 527, 528, 5, 114, 0, 0, 528, 529, 5, 111, 0, 0, 529, 530, 5, 119, 0, 0, 530, 531, 1, 0, 0, 0, 531, 532, 6, 15, 0, 0, 532, 47, 1, 0, 0, 0, 533, 534, 5, 115, 0, 0, 534, 535, 5, 104, 0, 0, 535, 536, 5, 111, 0, 0, 536, 537, 5, 119, 0, 0, 537, 538, 1, 0, 0, 0, 538, 539, 6, 16, 10, 0, 539, 49, 1, 0, 0, 0, 540, 541, 5, 115, 0, 0, 541, 542, 5, 111, 0, 0, 542, 543, 5, 114, 0, 0, 543, 544, 5, 116, 0, 0, 544, 545, 1, 0, 0, 0, 545, 546, 6, 17, 0, 0, 546, 51, 1, 0, 0, 0, 547, 548, 5, 115, 0, 0, 548, 549, 5, 116, 0, 0, 549, 550, 5, 97, 0, 0, 550, 551, 5, 116, 0, 0, 551, 552, 5, 115, 0, 0, 552, 553, 1, 0, 0, 0, 553, 554, 6, 18, 0, 0, 554, 53, 1, 0, 0, 0, 555, 556, 5, 119, 0, 0, 556, 557, 5, 104, 0, 0, 557, 558, 5, 101, 0, 0, 558, 559, 5, 114, 0, 0, 559, 560, 5, 101, 0, 0, 560, 561, 1, 0, 0, 0, 561, 562, 6, 19, 0, 0, 562, 55, 1, 0, 0, 0, 563, 565, 8, 0, 0, 0, 564, 563, 1, 0, 0, 0, 565, 566, 1, 0, 0, 0, 566, 564, 1, 0, 0, 0, 566, 567, 1, 0, 0, 0, 567, 568, 1, 0, 0, 0, 568, 569, 6, 20, 0, 0, 569, 57, 1, 0, 0, 0, 570, 571, 5, 47, 0, 0, 571, 572, 5, 47, 0, 0, 572, 576, 1, 0, 0, 0, 573, 575, 8, 1, 0, 0, 574, 573, 1, 0, 0, 0, 575, 578, 1, 0, 0, 0, 576, 574, 1, 0, 0, 0, 576, 577, 1, 0, 0, 0, 577, 580, 1, 0, 0, 0, 578, 576, 1, 0, 0, 0, 579, 581, 5, 13, 0, 0, 580, 579, 1, 0, 0, 0, 580, 581, 1, 0, 0, 0, 581, 583, 1, 0, 0, 0, 582, 584, 5, 10, 0, 0, 583, 582, 1, 0, 0, 0, 583, 584, 1, 0, 0, 0, 584, 585, 1, 0, 0, 0, 585, 586, 6, 21, 11, 0, 586, 59, 1, 0, 0, 0, 587, 588, 5, 47, 0, 0, 588, 589, 5, 42, 0, 0, 589, 594, 1, 0, 0, 0, 590, 593, 3, 60, 22, 0, 591, 593, 9, 0, 0, 0, 592, 590, 1, 0, 0, 0, 592, 591, 1, 0, 0, 0, 593, 596, 1, 0, 0, 0, 594, 595, 1, 0, 0, 0, 594, 592, 1, 0, 0, 0, 595, 597, 1, 0, 0, 0, 596, 594, 1, 0, 0, 0, 597, 598, 5, 42, 0, 0, 598, 599, 5, 47, 0, 0, 599, 600, 1, 0, 0, 0, 600, 601, 6, 22, 11, 0, 601, 61, 1, 0, 0, 0, 602, 604, 7, 2, 0, 0, 603, 602, 1, 0, 0, 0, 604, 605, 1, 0, 0, 0, 605, 603, 1, 0, 0, 0, 605, 606, 1, 0, 0, 0, 606, 607, 1, 0, 0, 0, 607, 608, 6, 23, 11, 0, 608, 63, 1, 0, 0, 0, 609, 613, 8, 3, 0, 0, 610, 611, 5, 47, 0, 0, 611, 613, 8, 4, 0, 0, 612, 609, 1, 0, 0, 0, 612, 610, 1, 0, 0, 0, 613, 65, 1, 0, 0, 0, 614, 616, 3, 64, 24, 0, 615, 614, 1, 0, 0, 0, 616, 617, 1, 0, 0, 0, 617, 615, 1, 0, 0, 0, 617, 618, 1, 0, 0, 0, 618, 67, 1, 0, 0, 0, 619, 620, 3, 176, 80, 0, 620, 621, 1, 0, 0, 0, 621, 622, 6, 26, 12, 0, 622, 623, 6, 26, 13, 0, 623, 69, 1, 0, 0, 0, 624, 625, 3, 78, 31, 0, 625, 626, 1, 0, 0, 0, 626, 627, 6, 27, 14, 0, 627, 628, 6, 27, 15, 0, 628, 71, 1, 0, 0, 0, 629, 630, 3, 62, 23, 0, 630, 631, 1, 0, 0, 0, 631, 632, 6, 28, 11, 0, 632, 73, 1, 0, 0, 0, 633, 634, 3, 58, 21, 0, 634, 635, 1, 0, 0, 0, 635, 636, 6, 29, 11, 0, 636, 75, 1, 0, 0, 0, 637, 638, 3, 60, 22, 0, 638, 639, 1, 0, 0, 0, 639, 640, 6, 30, 11, 0, 640, 77, 1, 0, 0, 0, 641, 642, 5, 124, 0, 0, 642, 643, 1, 0, 0, 0, 643, 644, 6, 31, 15, 0, 644, 79, 1, 0, 0, 0, 645, 646, 7, 5, 0, 0, 646, 81, 1, 0, 0, 0, 647, 648, 7, 6, 0, 0, 648, 83, 1, 0, 0, 0, 649, 650, 5, 92, 0, 0, 650, 651, 7, 7, 0, 0, 651, 85, 1, 0, 0, 0, 652, 653, 8, 8, 0, 0, 653, 87, 1, 0, 0, 0, 654, 656, 7, 9, 0, 0, 655, 657, 7, 10, 0, 0, 656, 655, 1, 0, 0, 0, 656, 657, 1, 0, 0, 0, 657, 659, 1, 0, 0, 0, 658, 660, 3, 80, 32, 0, 659, 658, 1, 0, 0, 0, 660, 661, 1, 0, 0, 0, 661, 659, 1, 0, 0, 0, 661, 662, 1, 0, 0, 0, 662, 89, 1, 0, 0, 0, 663, 664, 5, 64, 0, 0, 664, 91, 1, 0, 0, 0, 665, 666, 5, 96, 0, 0, 666, 93, 1, 0, 0, 0, 667, 671, 8, 11, 0, 0, 668, 669, 5, 96, 0, 0, 669, 671, 5, 96, 0, 0, 670, 667, 1, 0, 0, 0, 670, 668, 1, 0, 0, 0, 671, 95, 1, 0, 0, 0, 672, 673, 5, 95, 0, 0, 673, 97, 1, 0, 0, 0, 674, 678, 3, 82, 33, 0, 675, 678, 3, 80, 32, 0, 676, 678, 3, 96, 40, 0, 677, 674, 1, 0, 0, 0, 677, 675, 1, 0, 0, 0, 677, 676, 1, 0, 0, 0, 678, 99, 1, 0, 0, 0, 679, 684, 5, 34, 0, 0, 680, 683, 3, 84, 34, 0, 681, 683, 3, 86, 35, 0, 682, 680, 1, 0, 0, 0, 682, 681, 1, 0, 0, 0, 683, 686, 1, 0, 0, 0, 684, 682, 1, 0, 0, 0, 684, 685, 1, 0, 0, 0, 685, 687, 1, 0, 0, 0, 686, 684, 1, 0, 0, 0, 687, 709, 5, 34, 0, 0, 688, 689, 5, 34, 0, 0, 689, 690, 5, 34, 0, 0, 690, 691, 5, 34, 0, 0, 691, 695, 1, 0, 0, 0, 692, 694, 8, 1, 0, 0, 693, 692, 1, 0, 0, 0, 694, 697, 1, 0, 0, 0, 695, 696, 1, 0, 0, 0, 695, 693, 1, 0, 0, 0, 696, 698, 1, 0, 0, 0, 697, 695, 1, 0, 0, 0, 698, 699, 5, 34, 0, 0, 699, 700, 5, 34, 0, 0, 700, 701, 5, 34, 0, 0, 701, 703, 1, 0, 0, 0, 702, 704, 5, 34, 0, 0, 703, 702, 1, 0, 0, 0, 703, 704, 1, 0, 0, 0, 704, 706, 1, 0, 0, 0, 705, 707, 5, 34, 0, 0, 706, 705, 1, 0, 0, 0, 706, 707, 1, 0, 0, 0, 707, 709, 1, 0, 0, 0, 708, 679, 1, 0, 0, 0, 708, 688, 1, 0, 0, 0, 709, 101, 1, 0, 0, 0, 710, 712, 3, 80, 32, 0, 711, 710, 1, 0, 0, 0, 712, 713, 1, 0, 0, 0, 713, 711, 1, 0, 0, 0, 713, 714, 1, 0, 0, 0, 714, 103, 1, 0, 0, 0, 715, 717, 3, 80, 32, 0, 716, 715, 1, 0, 0, 0, 717, 718, 1, 0, 0, 0, 718, 716, 1, 0, 0, 0, 718, 719, 1, 0, 0, 0, 719, 720, 1, 0, 0, 0, 720, 724, 3, 120, 52, 0, 721, 723, 3, 80, 32, 0, 722, 721, 1, 0, 0, 0, 723, 726, 1, 0, 0, 0, 724, 722, 1, 0, 0, 0, 724, 725, 1, 0, 0, 0, 725, 758, 1, 0, 0, 0, 726, 724, 1, 0, 0, 0, 727, 729, 3, 120, 52, 0, 728, 730, 3, 80, 32, 0, 729, 728, 1, 0, 0, 0, 730, 731, 1, 0, 0, 0, 731, 729, 1, 0, 0, 0, 731, 732, 1, 0, 0, 0, 732, 758, 1, 0, 0, 0, 733, 735, 3, 80, 32, 0, 734, 733, 1, 0, 0, 0, 735, 736, 1, 0, 0, 0, 736, 734, 1, 0, 0, 0, 736, 737, 1, 0, 0, 0, 737, 745, 1, 0, 0, 0, 738, 742, 3, 120, 52, 0, 739, 741, 3, 80, 32, 0, 740, 739, 1, 0, 0, 0, 741, 744, 1, 0, 0, 0, 742, 740, 1, 0, 0, 0, 742, 743, 1, 0, 0, 0, 743, 746, 1, 0, 0, 0, 744, 742, 1, 0, 0, 0, 745, 738, 1, 0, 0, 0, 745, 746, 1, 0, 0, 0, 746, 747, 1, 0, 0, 0, 747, 748, 3, 88, 36, 0, 748, 758, 1, 0, 0, 0, 749, 751, 3, 120, 52, 0, 750, 752, 3, 80, 32, 0, 751, 750, 1, 0, 0, 0, 752, 753, 1, 0, 0, 0, 753, 751, 1, 0, 0, 0, 753, 754, 1, 0, 0, 0, 754, 755, 1, 0, 0, 0, 755, 756, 3, 88, 36, 0, 756, 758, 1, 0, 0, 0, 757, 716, 1, 0, 0, 0, 757, 727, 1, 0, 0, 0, 757, 734, 1, 0, 0, 0, 757, 749, 1, 0, 0, 0, 758, 105, 1, 0, 0, 0, 759, 760, 5, 98, 0, 0, 760, 761, 5, 121, 0, 0, 761, 107, 1, 0, 0, 0, 762, 763, 5, 97, 0, 0, 763, 764, 5, 110, 0, 0, 764, 765, 5, 100, 0, 0, 765, 109, 1, 0, 0, 0, 766, 767, 5, 97, 0, 0, 767, 768, 5, 115, 0, 0, 768, 769, 5, 99, 0, 0, 769, 111, 1, 0, 0, 0, 770, 771, 5, 61, 0, 0, 771, 113, 1, 0, 0, 0, 772, 773, 5, 58, 0, 0, 773, 774, 5, 58, 0, 0, 774, 115, 1, 0, 0, 0, 775, 776, 5, 44, 0, 0, 776, 117, 1, 0, 0, 0, 777, 778, 5, 100, 0, 0, 778, 779, 5, 101, 0, 0, 779, 780, 5, 115, 0, 0, 780, 781, 5, 99, 0, 0, 781, 119, 1, 0, 0, 0, 782, 783, 5, 46, 0, 0, 783, 121, 1, 0, 0, 0, 784, 785, 5, 102, 0, 0, 785, 786, 5, 97, 0, 0, 786, 787, 5, 108, 0, 0, 787, 788, 5, 115, 0, 0, 788, 789, 5, 101, 0, 0, 789, 123, 1, 0, 0, 0, 790, 791, 5, 102, 0, 0, 791, 792, 5, 105, 0, 0, 792, 793, 5, 114, 0, 0, 793, 794, 5, 115, 0, 0, 794, 795, 5, 116, 0, 0, 795, 125, 1, 0, 0, 0, 796, 797, 5, 108, 0, 0, 797, 798, 5, 97, 0, 0, 798, 799, 5, 115, 0, 0, 799, 800, 5, 116, 0, 0, 800, 127, 1, 0, 0, 0, 801, 802, 5, 40, 0, 0, 802, 129, 1, 0, 0, 0, 803, 804, 5, 105, 0, 0, 804, 805, 5, 110, 0, 0, 805, 131, 1, 0, 0, 0, 806, 807, 5, 105, 0, 0, 807, 808, 5, 115, 0, 0, 808, 133, 1, 0, 0, 0, 809, 810, 5, 108, 0, 0, 810, 811, 5, 105, 0, 0, 811, 812, 5, 107, 0, 0, 812, 813, 5, 101, 0, 0, 813, 135, 1, 0, 0, 0, 814, 815, 5, 110, 0, 0, 815, 816, 5, 111, 0, 0, 816, 817, 5, 116, 0, 0, 817, 137, 1, 0, 0, 0, 818, 819, 5, 110, 0, 0, 819, 820, 5, 117, 0, 0, 820, 821, 5, 108, 0, 0, 821, 822, 5, 108, 0, 0, 822, 139, 1, 0, 0, 0, 823, 824, 5, 110, 0, 0, 824, 825, 5, 117, 0, 0, 825, 826, 5, 108, 0, 0, 826, 827, 5, 108, 0, 0, 827, 828, 5, 115, 0, 0, 828, 141, 1, 0, 0, 0, 829, 830, 5, 111, 0, 0, 830, 831, 5, 114, 0, 0, 831, 143, 1, 0, 0, 0, 832, 833, 5, 63, 0, 0, 833, 145, 1, 0, 0, 0, 834, 835, 5, 114, 0, 0, 835, 836, 5, 108, 0, 0, 836, 837, 5, 105, 0, 0, 837, 838, 5, 107, 0, 0, 838, 839, 5, 101, 0, 0, 839, 147, 1, 0, 0, 0, 840, 841, 5, 41, 0, 0, 841, 149, 1, 0, 0, 0, 842, 843, 5, 116, 0, 0, 843, 844, 5, 114, 0, 0, 844, 845, 5, 117, 0, 0, 845, 846, 5, 101, 0, 0, 846, 151, 1, 0, 0, 0, 847, 848, 5, 61, 0, 0, 848, 849, 5, 61, 0, 0, 849, 153, 1, 0, 0, 0, 850, 851, 5, 61, 0, 0, 851, 852, 5, 126, 0, 0, 852, 155, 1, 0, 0, 0, 853, 854, 5, 33, 0, 0, 854, 855, 5, 61, 0, 0, 855, 157, 1, 0, 0, 0, 856, 857, 5, 60, 0, 0, 857, 159, 1, 0, 0, 0, 858, 859, 5, 60, 0, 0, 859, 860, 5, 61, 0, 0, 860, 161, 1, 0, 0, 0, 861, 862, 5, 62, 0, 0, 862, 163, 1, 0, 0, 0, 863, 864, 5, 62, 0, 0, 864, 865, 5, 61, 0, 0, 865, 165, 1, 0, 0, 0, 866, 867, 5, 43, 0, 0, 867, 167, 1, 0, 0, 0, 868, 869, 5, 45, 0, 0, 869, 169, 1, 0, 0, 0, 870, 871, 5, 42, 0, 0, 871, 171, 1, 0, 0, 0, 872, 873, 5, 47, 0, 0, 873, 173, 1, 0, 0, 0, 874, 875, 5, 37, 0, 0, 875, 175, 1, 0, 0, 0, 876, 877, 5, 91, 0, 0, 877, 878, 1, 0, 0, 0, 878, 879, 6, 80, 0, 0, 879, 880, 6, 80, 0, 0, 880, 177, 1, 0, 0, 0, 881, 882, 5, 93, 0, 0, 882, 883, 1, 0, 0, 0, 883, 884, 6, 81, 15, 0, 884, 885, 6, 81, 15, 0, 885, 179, 1, 0, 0, 0, 886, 890, 3, 82, 33, 0, 887, 889, 3, 98, 41, 0, 888, 887, 1, 0, 0, 0, 889, 892, 1, 0, 0, 0, 890, 888, 1, 0, 0, 0, 890, 891, 1, 0, 0, 0, 891, 903, 1, 0, 0, 0, 892, 890, 1, 0, 0, 0, 893, 896, 3, 96, 40, 0, 894, 896, 3, 90, 37, 0, 895, 893, 1, 0, 0, 0, 895, 894, 1, 0, 0, 0, 896, 898, 1, 0, 0, 0, 897, 899, 3, 98, 41, 0, 898, 897, 1, 0, 0, 0, 899, 900, 1, 0, 0, 0, 900, 898, 1, 0, 0, 0, 900, 901, 1, 0, 0, 0, 901, 903, 1, 0, 0, 0, 902, 886, 1, 0, 0, 0, 902, 895, 1, 0, 0, 0, 903, 181, 1, 0, 0, 0, 904, 906, 3, 92, 38, 0, 905, 907, 3, 94, 39, 0, 906, 905, 1, 0, 0, 0, 907, 908, 1, 0, 0, 0, 908, 906, 1, 0, 0, 0, 908, 909, 1, 0, 0, 0, 909, 910, 1, 0, 0, 0, 910, 911, 3, 92, 38, 0, 911, 183, 1, 0, 0, 0, 912, 913, 3, 182, 83, 0, 913, 185, 1, 0, 0, 0, 914, 915, 3, 58, 21, 0, 915, 916, 1, 0, 0, 0, 916, 917, 6, 85, 11, 0, 917, 187, 1, 0, 0, 0, 918, 919, 3, 60, 22, 0, 919, 920, 1, 0, 0, 0, 920, 921, 6, 86, 11, 0, 921, 189, 1, 0, 0, 0, 922, 923, 3, 62, 23, 0, 923, 924, 1, 0, 0, 0, 924, 925, 6, 87, 11, 0, 925, 191, 1, 0, 0, 0, 926, 927, 3, 78, 31, 0, 927, 928, 1, 0, 0, 0, 928, 929, 6, 88, 14, 0, 929, 930, 6, 88, 15, 0, 930, 193, 1, 0, 0, 0, 931, 932, 3, 176, 80, 0, 932, 933, 1, 0, 0, 0, 933, 934, 6, 89, 12, 0, 934, 195, 1, 0, 0, 0, 935, 936, 3, 178, 81, 0, 936, 937, 1, 0, 0, 0, 937, 938, 6, 90, 16, 0, 938, 197, 1, 0, 0, 0, 939, 940, 3, 116, 50, 0, 940, 941, 1, 0, 0, 0, 941, 942, 6, 91, 17, 0, 942, 199, 1, 0, 0, 0, 943, 944, 3, 112, 48, 0, 944, 945, 1, 0, 0, 0, 945, 946, 6, 92, 18, 0, 946, 201, 1, 0, 0, 0, 947, 948, 3, 100, 42, 0, 948, 949, 1, 0, 0, 0, 949, 950, 6, 93, 19, 0, 950, 203, 1, 0, 0, 0, 951, 952, 5, 109, 0, 0, 952, 953, 5, 101, 0, 0, 953, 954, 5, 116, 0, 0, 954, 955, 5, 97, 0, 0, 955, 956, 5, 100, 0, 0, 956, 957, 5, 97, 0, 0, 957, 958, 5, 116, 0, 0, 958, 959, 5, 97, 0, 0, 959, 205, 1, 0, 0, 0, 960, 961, 3, 66, 25, 0, 961, 962, 1, 0, 0, 0, 962, 963, 6, 95, 20, 0, 963, 207, 1, 0, 0, 0, 964, 965, 3, 58, 21, 0, 965, 966, 1, 0, 0, 0, 966, 967, 6, 96, 11, 0, 967, 209, 1, 0, 0, 0, 968, 969, 3, 60, 22, 0, 969, 970, 1, 0, 0, 0, 970, 971, 6, 97, 11, 0, 971, 211, 1, 0, 0, 0, 972, 973, 3, 62, 23, 0, 973, 974, 1, 0, 0, 0, 974, 975, 6, 98, 11, 0, 975, 213, 1, 0, 0, 0, 976, 977, 3, 78, 31, 0, 977, 978, 1, 0, 0, 0, 978, 979, 6, 99, 14, 0, 979, 980, 6, 99, 15, 0, 980, 215, 1, 0, 0, 0, 981, 982, 3, 120, 52, 0, 982, 983, 1, 0, 0, 0, 983, 984, 6, 100, 21, 0, 984, 217, 1, 0, 0, 0, 985, 986, 3, 116, 50, 0, 986, 987, 1, 0, 0, 0, 987, 988, 6, 101, 17, 0, 988, 219, 1, 0, 0, 0, 989, 994, 3, 82, 33, 0, 990, 994, 3, 80, 32, 0, 991, 994, 3, 96, 40, 0, 992, 994, 3, 170, 77, 0, 993, 989, 1, 0, 0, 0, 993, 990, 1, 0, 0, 0, 993, 991, 1, 0, 0, 0, 993, 992, 1, 0, 0, 0, 994, 221, 1, 0, 0, 0, 995, 998, 3, 82, 33, 0, 996, 998, 3, 170, 77, 0, 997, 995, 1, 0, 0, 0, 997, 996, 1, 0, 0, 0, 998, 1002, 1, 0, 0, 0, 999, 1001, 3, 220, 102, 0, 1000, 999, 1, 0, 0, 0, 1001, 1004, 1, 0, 0, 0, 1002, 1000, 1, 0, 0, 0, 1002, 1003, 1, 0, 0, 0, 1003, 1015, 1, 0, 0, 0, 1004, 1002, 1, 0, 0, 0, 1005, 1008, 3, 96, 40, 0, 1006, 1008, 3, 90, 37, 0, 1007, 1005, 1, 0, 0, 0, 1007, 1006, 1, 0, 0, 0, 1008, 1010, 1, 0, 0, 0, 1009, 1011, 3, 220, 102, 0, 1010, 1009, 1, 0, 0, 0, 1011, 1012, 1, 0, 0, 0, 1012, 1010, 1, 0, 0, 0, 1012, 1013, 1, 0, 0, 0, 1013, 1015, 1, 0, 0, 0, 1014, 997, 1, 0, 0, 0, 1014, 1007, 1, 0, 0, 0, 1015, 223, 1, 0, 0, 0, 1016, 1019, 3, 222, 103, 0, 1017, 1019, 3, 182, 83, 0, 1018, 1016, 1, 0, 0, 0, 1018, 1017, 1, 0, 0, 0, 1019, 1020, 1, 0, 0, 0, 1020, 1018, 1, 0, 0, 0, 1020, 1021, 1, 0, 0, 0, 1021, 225, 1, 0, 0, 0, 1022, 1023, 3, 58, 21, 0, 1023, 1024, 1, 0, 0, 0, 1024, 1025, 6, 105, 11, 0, 1025, 227, 1, 0, 0, 0, 1026, 1027, 3, 60, 22, 0, 1027, 1028, 1, 0, 0, 0, 1028, 1029, 6, 106, 11, 0, 1029, 229, 1, 0, 0, 0, 1030, 1031, 3, 62, 23, 0, 1031, 1032, 1, 0, 0, 0, 1032, 1033, 6, 107, 11, 0, 1033, 231, 1, 0, 0, 0, 1034, 1035, 3, 78, 31, 0, 1035, 1036, 1, 0, 0, 0, 1036, 1037, 6, 108, 14, 0, 1037, 1038, 6, 108, 15, 0, 1038, 233, 1, 0, 0, 0, 1039, 1040, 3, 112, 48, 0, 1040, 1041, 1, 0, 0, 0, 1041, 1042, 6, 109, 18, 0, 1042, 235, 1, 0, 0, 0, 1043, 1044, 3, 116, 50, 0, 1044, 1045, 1, 0, 0, 0, 1045, 1046, 6, 110, 17, 0, 1046, 237, 1, 0, 0, 0, 1047, 1048, 3, 120, 52, 0, 1048, 1049, 1, 0, 0, 0, 1049, 1050, 6, 111, 21, 0, 1050, 239, 1, 0, 0, 0, 1051, 1052, 5, 97, 0, 0, 1052, 1053, 5, 115, 0, 0, 1053, 241, 1, 0, 0, 0, 1054, 1055, 3, 224, 104, 0, 1055, 1056, 1, 0, 0, 0, 1056, 1057, 6, 113, 22, 0, 1057, 243, 1, 0, 0, 0, 1058, 1059, 3, 58, 21, 0, 1059, 1060, 1, 0, 0, 0, 1060, 1061, 6, 114, 11, 0, 1061, 245, 1, 0, 0, 0, 1062, 1063, 3, 60, 22, 0, 1063, 1064, 1, 0, 0, 0, 1064, 1065, 6, 115, 11, 0, 1065, 247, 1, 0, 0, 0, 1066, 1067, 3, 62, 23, 0, 1067, 1068, 1, 0, 0, 0, 1068, 1069, 6, 116, 11, 0, 1069, 249, 1, 0, 0, 0, 1070, 1071, 3, 78, 31, 0, 1071, 1072, 1, 0, 0, 0, 1072, 1073, 6, 117, 14, 0, 1073, 1074, 6, 117, 15, 0, 1074, 251, 1, 0, 0, 0, 1075, 1076, 3, 176, 80, 0, 1076, 1077, 1, 0, 0, 0, 1077, 1078, 6, 118, 12, 0, 1078, 1079, 6, 118, 23, 0, 1079, 253, 1, 0, 0, 0, 1080, 1081, 5, 111, 0, 0, 1081, 1082, 5, 110, 0, 0, 1082, 1083, 1, 0, 0, 0, 1083, 1084, 6, 119, 24, 0, 1084, 255, 1, 0, 0, 0, 1085, 1086, 5, 119, 0, 0, 1086, 1087, 5, 105, 0, 0, 1087, 1088, 5, 116, 0, 0, 1088, 1089, 5, 104, 0, 0, 1089, 1090, 1, 0, 0, 0, 1090, 1091, 6, 120, 24, 0, 1091, 257, 1, 0, 0, 0, 1092, 1093, 8, 12, 0, 0, 1093, 259, 1, 0, 0, 0, 1094, 1096, 3, 258, 121, 0, 1095, 1094, 1, 0, 0, 0, 1096, 1097, 1, 0, 0, 0, 1097, 1095, 1, 0, 0, 0, 1097, 1098, 1, 0, 0, 0, 1098, 1099, 1, 0, 0, 0, 1099, 1100, 3, 358, 171, 0, 1100, 1102, 1, 0, 0, 0, 1101, 1095, 1, 0, 0, 0, 1101, 1102, 1, 0, 0, 0, 1102, 1104, 1, 0, 0, 0, 1103, 1105, 3, 258, 121, 0, 1104, 1103, 1, 0, 0, 0, 1105, 1106, 1, 0, 0, 0, 1106, 1104, 1, 0, 0, 0, 1106, 1107, 1, 0, 0, 0, 1107, 261, 1, 0, 0, 0, 1108, 1109, 3, 184, 84, 0, 1109, 1110, 1, 0, 0, 0, 1110, 1111, 6, 123, 25, 0, 1111, 263, 1, 0, 0, 0, 1112, 1113, 3, 260, 122, 0, 1113, 1114, 1, 0, 0, 0, 1114, 1115, 6, 124, 26, 0, 1115, 265, 1, 0, 0, 0, 1116, 1117, 3, 58, 21, 0, 1117, 1118, 1, 0, 0, 0, 1118, 1119, 6, 125, 11, 0, 1119, 267, 1, 0, 0, 0, 1120, 1121, 3, 60, 22, 0, 1121, 1122, 1, 0, 0, 0, 1122, 1123, 6, 126, 11, 0, 1123, 269, 1, 0, 0, 0, 1124, 1125, 3, 62, 23, 0, 1125, 1126, 1, 0, 0, 0, 1126, 1127, 6, 127, 11, 0, 1127, 271, 1, 0, 0, 0, 1128, 1129, 3, 78, 31, 0, 1129, 1130, 1, 0, 0, 0, 1130, 1131, 6, 128, 14, 0, 1131, 1132, 6, 128, 15, 0, 1132, 1133, 6, 128, 15, 0, 1133, 273, 1, 0, 0, 0, 1134, 1135, 3, 112, 48, 0, 1135, 1136, 1, 0, 0, 0, 1136, 1137, 6, 129, 18, 0, 1137, 275, 1, 0, 0, 0, 1138, 1139, 3, 116, 50, 0, 1139, 1140, 1, 0, 0, 0, 1140, 1141, 6, 130, 17, 0, 1141, 277, 1, 0, 0, 0, 1142, 1143, 3, 120, 52, 0, 1143, 1144, 1, 0, 0, 0, 1144, 1145, 6, 131, 21, 0, 1145, 279, 1, 0, 0, 0, 1146, 1147, 3, 256, 120, 0, 1147, 1148, 1, 0, 0, 0, 1148, 1149, 6, 132, 27, 0, 1149, 281, 1, 0, 0, 0, 1150, 1151, 3, 224, 104, 0, 1151, 1152, 1, 0, 0, 0, 1152, 1153, 6, 133, 22, 0, 1153, 283, 1, 0, 0, 0, 1154, 1155, 3, 184, 84, 0, 1155, 1156, 1, 0, 0, 0, 1156, 1157, 6, 134, 25, 0, 1157, 285, 1, 0, 0, 0, 1158, 1159, 3, 58, 21, 0, 1159, 1160, 1, 0, 0, 0, 1160, 1161, 6, 135, 11, 0, 1161, 287, 1, 0, 0, 0, 1162, 1163, 3, 60, 22, 0, 1163, 1164, 1, 0, 0, 0, 1164, 1165, 6, 136, 11, 0, 1165, 289, 1, 0, 0, 0, 1166, 1167, 3, 62, 23, 0, 1167, 1168, 1, 0, 0, 0, 1168, 1169, 6, 137, 11, 0, 1169, 291, 1, 0, 0, 0, 1170, 1171, 3, 78, 31, 0, 1171, 1172, 1, 0, 0, 0, 1172, 1173, 6, 138, 14, 0, 1173, 1174, 6, 138, 15, 0, 1174, 293, 1, 0, 0, 0, 1175, 1176, 3, 116, 50, 0, 1176, 1177, 1, 0, 0, 0, 1177, 1178, 6, 139, 17, 0, 1178, 295, 1, 0, 0, 0, 1179, 1180, 3, 120, 52, 0, 1180, 1181, 1, 0, 0, 0, 1181, 1182, 6, 140, 21, 0, 1182, 297, 1, 0, 0, 0, 1183, 1184, 3, 254, 119, 0, 1184, 1185, 1, 0, 0, 0, 1185, 1186, 6, 141, 28, 0, 1186, 1187, 6, 141, 29, 0, 1187, 299, 1, 0, 0, 0, 1188, 1189, 3, 66, 25, 0, 1189, 1190, 1, 0, 0, 0, 1190, 1191, 6, 142, 20, 0, 1191, 301, 1, 0, 0, 0, 1192, 1193, 3, 58, 21, 0, 1193, 1194, 1, 0, 0, 0, 1194, 1195, 6, 143, 11, 0, 1195, 303, 1, 0, 0, 0, 1196, 1197, 3, 60, 22, 0, 1197, 1198, 1, 0, 0, 0, 1198, 1199, 6, 144, 11, 0, 1199, 305, 1, 0, 0, 0, 1200, 1201, 3, 62, 23, 0, 1201, 1202, 1, 0, 0, 0, 1202, 1203, 6, 145, 11, 0, 1203, 307, 1, 0, 0, 0, 1204, 1205, 3, 78, 31, 0, 1205, 1206, 1, 0, 0, 0, 1206, 1207, 6, 146, 14, 0, 1207, 1208, 6, 146, 15, 0, 1208, 1209, 6, 146, 15, 0, 1209, 309, 1, 0, 0, 0, 1210, 1211, 3, 116, 50, 0, 1211, 1212, 1, 0, 0, 0, 1212, 1213, 6, 147, 17, 0, 1213, 311, 1, 0, 0, 0, 1214, 1215, 3, 120, 52, 0, 1215, 1216, 1, 0, 0, 0, 1216, 1217, 6, 148, 21, 0, 1217, 313, 1, 0, 0, 0, 1218, 1219, 3, 224, 104, 0, 1219, 1220, 1, 0, 0, 0, 1220, 1221, 6, 149, 22, 0, 1221, 315, 1, 0, 0, 0, 1222, 1223, 3, 58, 21, 0, 1223, 1224, 1, 0, 0, 0, 1224, 1225, 6, 150, 11, 0, 1225, 317, 1, 0, 0, 0, 1226, 1227, 3, 60, 22, 0, 1227, 1228, 1, 0, 0, 0, 1228, 1229, 6, 151, 11, 0, 1229, 319, 1, 0, 0, 0, 1230, 1231, 3, 62, 23, 0, 1231, 1232, 1, 0, 0, 0, 1232, 1233, 6, 152, 11, 0, 1233, 321, 1, 0, 0, 0, 1234, 1235, 3, 78, 31, 0, 1235, 1236, 1, 0, 0, 0, 1236, 1237, 6, 153, 14, 0, 1237, 1238, 6, 153, 15, 0, 1238, 323, 1, 0, 0, 0, 1239, 1240, 3, 120, 52, 0, 1240, 1241, 1, 0, 0, 0, 1241, 1242, 6, 154, 21, 0, 1242, 325, 1, 0, 0, 0, 1243, 1244, 3, 184, 84, 0, 1244, 1245, 1, 0, 0, 0, 1245, 1246, 6, 155, 25, 0, 1246, 327, 1, 0, 0, 0, 1247, 1248, 3, 180, 82, 0, 1248, 1249, 1, 0, 0, 0, 1249, 1250, 6, 156, 30, 0, 1250, 329, 1, 0, 0, 0, 1251, 1252, 3, 58, 21, 0, 1252, 1253, 1, 0, 0, 0, 1253, 1254, 6, 157, 11, 0, 1254, 331, 1, 0, 0, 0, 1255, 1256, 3, 60, 22, 0, 1256, 1257, 1, 0, 0, 0, 1257, 1258, 6, 158, 11, 0, 1258, 333, 1, 0, 0, 0, 1259, 1260, 3, 62, 23, 0, 1260, 1261, 1, 0, 0, 0, 1261, 1262, 6, 159, 11, 0, 1262, 335, 1, 0, 0, 0, 1263, 1264, 3, 78, 31, 0, 1264, 1265, 1, 0, 0, 0, 1265, 1266, 6, 160, 14, 0, 1266, 1267, 6, 160, 15, 0, 1267, 337, 1, 0, 0, 0, 1268, 1269, 5, 105, 0, 0, 1269, 1270, 5, 110, 0, 0, 1270, 1271, 5, 102, 0, 0, 1271, 1272, 5, 111, 0, 0, 1272, 339, 1, 0, 0, 0, 1273, 1274, 3, 58, 21, 0, 1274, 1275, 1, 0, 0, 0, 1275, 1276, 6, 162, 11, 0, 1276, 341, 1, 0, 0, 0, 1277, 1278, 3, 60, 22, 0, 1278, 1279, 1, 0, 0, 0, 1279, 1280, 6, 163, 11, 0, 1280, 343, 1, 0, 0, 0, 1281, 1282, 3, 62, 23, 0, 1282, 1283, 1, 0, 0, 0, 1283, 1284, 6, 164, 11, 0, 1284, 345, 1, 0, 0, 0, 1285, 1286, 3, 78, 31, 0, 1286, 1287, 1, 0, 0, 0, 1287, 1288, 6, 165, 14, 0, 1288, 1289, 6, 165, 15, 0, 1289, 347, 1, 0, 0, 0, 1290, 1291, 5, 102, 0, 0, 1291, 1292, 5, 117, 0, 0, 1292, 1293, 5, 110, 0, 0, 1293, 1294, 5, 99, 0, 0, 1294, 1295, 5, 116, 0, 0, 1295, 1296, 5, 105, 0, 0, 1296, 1297, 5, 111, 0, 0, 1297, 1298, 5, 110, 0, 0, 1298, 1299, 5, 115, 0, 0, 1299, 349, 1, 0, 0, 0, 1300, 1301, 3, 58, 21, 0, 1301, 1302, 1, 0, 0, 0, 1302, 1303, 6, 167, 11, 0, 1303, 351, 1, 0, 0, 0, 1304, 1305, 3, 60, 22, 0, 1305, 1306, 1, 0, 0, 0, 1306, 1307, 6, 168, 11, 0, 1307, 353, 1, 0, 0, 0, 1308, 1309, 3, 62, 23, 0, 1309, 1310, 1, 0, 0, 0, 1310, 1311, 6, 169, 11, 0, 1311, 355, 1, 0, 0, 0, 1312, 1313, 3, 178, 81, 0, 1313, 1314, 1, 0, 0, 0, 1314, 1315, 6, 170, 16, 0, 1315, 1316, 6, 170, 15, 0, 1316, 357, 1, 0, 0, 0, 1317, 1318, 5, 58, 0, 0, 1318, 359, 1, 0, 0, 0, 1319, 1325, 3, 90, 37, 0, 1320, 1325, 3, 80, 32, 0, 1321, 1325, 3, 120, 52, 0, 1322, 1325, 3, 82, 33, 0, 1323, 1325, 3, 96, 40, 0, 1324, 1319, 1, 0, 0, 0, 1324, 1320, 1, 0, 0, 0, 1324, 1321, 1, 0, 0, 0, 1324, 1322, 1, 0, 0, 0, 1324, 1323, 1, 0, 0, 0, 1325, 1326, 1, 0, 0, 0, 1326, 1324, 1, 0, 0, 0, 1326, 1327, 1, 0, 0, 0, 1327, 361, 1, 0, 0, 0, 1328, 1329, 3, 58, 21, 0, 1329, 1330, 1, 0, 0, 0, 1330, 1331, 6, 173, 11, 0, 1331, 363, 1, 0, 0, 0, 1332, 1333, 3, 60, 22, 0, 1333, 1334, 1, 0, 0, 0, 1334, 1335, 6, 174, 11, 0, 1335, 365, 1, 0, 0, 0, 1336, 1337, 3, 62, 23, 0, 1337, 1338, 1, 0, 0, 0, 1338, 1339, 6, 175, 11, 0, 1339, 367, 1, 0, 0, 0, 1340, 1341, 3, 78, 31, 0, 1341, 1342, 1, 0, 0, 0, 1342, 1343, 6, 176, 14, 0, 1343, 1344, 6, 176, 15, 0, 1344, 369, 1, 0, 0, 0, 1345, 1346, 3, 66, 25, 0, 1346, 1347, 1, 0, 0, 0, 1347, 1348, 6, 177, 20, 0, 1348, 1349, 6, 177, 15, 0, 1349, 1350, 6, 177, 31, 0, 1350, 371, 1, 0, 0, 0, 1351, 1352, 3, 58, 21, 0, 1352, 1353, 1, 0, 0, 0, 1353, 1354, 6, 178, 11, 0, 1354, 373, 1, 0, 0, 0, 1355, 1356, 3, 60, 22, 0, 1356, 1357, 1, 0, 0, 0, 1357, 1358, 6, 179, 11, 0, 1358, 375, 1, 0, 0, 0, 1359, 1360, 3, 62, 23, 0, 1360, 1361, 1, 0, 0, 0, 1361, 1362, 6, 180, 11, 0, 1362, 377, 1, 0, 0, 0, 1363, 1364, 3, 116, 50, 0, 1364, 1365, 1, 0, 0, 0, 1365, 1366, 6, 181, 17, 0, 1366, 1367, 6, 181, 15, 0, 1367, 1368, 6, 181, 7, 0, 1368, 379, 1, 0, 0, 0, 1369, 1370, 3, 58, 21, 0, 1370, 1371, 1, 0, 0, 0, 1371, 1372, 6, 182, 11, 0, 1372, 381, 1, 0, 0, 0, 1373, 1374, 3, 60, 22, 0, 1374, 1375, 1, 0, 0, 0, 1375, 1376, 6, 183, 11, 0, 1376, 383, 1, 0, 0, 0, 1377, 1378, 3, 62, 23, 0, 1378, 1379, 1, 0, 0, 0, 1379, 1380, 6, 184, 11, 0, 1380, 385, 1, 0, 0, 0, 1381, 1382, 3, 184, 84, 0, 1382, 1383, 1, 0, 0, 0, 1383, 1384, 6, 185, 15, 0, 1384, 1385, 6, 185, 0, 0, 1385, 1386, 6, 185, 25, 0, 1386, 387, 1, 0, 0, 0, 1387, 1388, 3, 180, 82, 0, 1388, 1389, 1, 0, 0, 0, 1389, 1390, 6, 186, 15, 0, 1390, 1391, 6, 186, 0, 0, 1391, 1392, 6, 186, 30, 0, 1392, 389, 1, 0, 0, 0, 1393, 1394, 3, 106, 45, 0, 1394, 1395, 1, 0, 0, 0, 1395, 1396, 6, 187, 15, 0, 1396, 1397, 6, 187, 0, 0, 1397, 1398, 6, 187, 32, 0, 1398, 391, 1, 0, 0, 0, 1399, 1400, 3, 78, 31, 0, 1400, 1401, 1, 0, 0, 0, 1401, 1402, 6, 188, 14, 0, 1402, 1403, 6, 188, 15, 0, 1403, 393, 1, 0, 0, 0, 62, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 566, 576, 580, 583, 592, 594, 605, 612, 617, 656, 661, 670, 677, 682, 684, 695, 703, 706, 708, 713, 718, 724, 731, 736, 742, 745, 753, 757, 890, 895, 900, 902, 908, 993, 997, 1002, 1007, 1012, 1014, 1018, 1020, 1097, 1101, 1106, 1324, 1326, 33, 5, 2, 0, 5, 4, 0, 5, 6, 0, 5, 1, 0, 5, 3, 0, 5, 8, 0, 5, 12, 0, 5, 14, 0, 5, 10, 0, 5, 5, 0, 5, 11, 0, 0, 1, 0, 7, 68, 0, 5, 0, 0, 7, 29, 0, 4, 0, 0, 7, 69, 0, 7, 38, 0, 7, 36, 0, 7, 30, 0, 7, 25, 0, 7, 40, 0, 7, 79, 0, 5, 13, 0, 5, 7, 0, 7, 71, 0, 7, 89, 0, 7, 88, 0, 7, 87, 0, 5, 9, 0, 7, 70, 0, 5, 15, 0, 7, 33, 0] \ No newline at end of file diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.java index 3f769b2614479..f9ca7ff95c847 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.java @@ -18,48 +18,52 @@ public class EsqlBaseLexer extends Lexer { new PredictionContextCache(); public static final int DISSECT=1, DROP=2, ENRICH=3, EVAL=4, EXPLAIN=5, FROM=6, GROK=7, INLINESTATS=8, - KEEP=9, LIMIT=10, META=11, METRICS=12, MV_EXPAND=13, RENAME=14, ROW=15, - SHOW=16, SORT=17, STATS=18, WHERE=19, UNKNOWN_CMD=20, LINE_COMMENT=21, - MULTILINE_COMMENT=22, WS=23, INDEX_UNQUOTED_IDENTIFIER=24, EXPLAIN_WS=25, - EXPLAIN_LINE_COMMENT=26, EXPLAIN_MULTILINE_COMMENT=27, PIPE=28, QUOTED_STRING=29, - INTEGER_LITERAL=30, DECIMAL_LITERAL=31, BY=32, AND=33, ASC=34, ASSIGN=35, - CAST_OP=36, COMMA=37, DESC=38, DOT=39, FALSE=40, FIRST=41, LAST=42, LP=43, - IN=44, IS=45, LIKE=46, NOT=47, NULL=48, NULLS=49, OR=50, PARAM=51, RLIKE=52, - RP=53, TRUE=54, EQ=55, CIEQ=56, NEQ=57, LT=58, LTE=59, GT=60, GTE=61, - PLUS=62, MINUS=63, ASTERISK=64, SLASH=65, PERCENT=66, OPENING_BRACKET=67, - CLOSING_BRACKET=68, UNQUOTED_IDENTIFIER=69, QUOTED_IDENTIFIER=70, EXPR_LINE_COMMENT=71, - EXPR_MULTILINE_COMMENT=72, EXPR_WS=73, METADATA=74, FROM_LINE_COMMENT=75, - FROM_MULTILINE_COMMENT=76, FROM_WS=77, ID_PATTERN=78, PROJECT_LINE_COMMENT=79, - PROJECT_MULTILINE_COMMENT=80, PROJECT_WS=81, AS=82, RENAME_LINE_COMMENT=83, - RENAME_MULTILINE_COMMENT=84, RENAME_WS=85, ON=86, WITH=87, ENRICH_POLICY_NAME=88, - ENRICH_LINE_COMMENT=89, ENRICH_MULTILINE_COMMENT=90, ENRICH_WS=91, ENRICH_FIELD_LINE_COMMENT=92, - ENRICH_FIELD_MULTILINE_COMMENT=93, ENRICH_FIELD_WS=94, MVEXPAND_LINE_COMMENT=95, - MVEXPAND_MULTILINE_COMMENT=96, MVEXPAND_WS=97, INFO=98, SHOW_LINE_COMMENT=99, - SHOW_MULTILINE_COMMENT=100, SHOW_WS=101, FUNCTIONS=102, META_LINE_COMMENT=103, - META_MULTILINE_COMMENT=104, META_WS=105, COLON=106, SETTING=107, SETTING_LINE_COMMENT=108, - SETTTING_MULTILINE_COMMENT=109, SETTING_WS=110, METRICS_LINE_COMMENT=111, - METRICS_MULTILINE_COMMENT=112, METRICS_WS=113, CLOSING_METRICS_LINE_COMMENT=114, - CLOSING_METRICS_MULTILINE_COMMENT=115, CLOSING_METRICS_WS=116; + KEEP=9, LIMIT=10, LOOKUP=11, META=12, METRICS=13, MV_EXPAND=14, RENAME=15, + ROW=16, SHOW=17, SORT=18, STATS=19, WHERE=20, UNKNOWN_CMD=21, LINE_COMMENT=22, + MULTILINE_COMMENT=23, WS=24, INDEX_UNQUOTED_IDENTIFIER=25, EXPLAIN_WS=26, + EXPLAIN_LINE_COMMENT=27, EXPLAIN_MULTILINE_COMMENT=28, PIPE=29, QUOTED_STRING=30, + INTEGER_LITERAL=31, DECIMAL_LITERAL=32, BY=33, AND=34, ASC=35, ASSIGN=36, + CAST_OP=37, COMMA=38, DESC=39, DOT=40, FALSE=41, FIRST=42, LAST=43, LP=44, + IN=45, IS=46, LIKE=47, NOT=48, NULL=49, NULLS=50, OR=51, PARAM=52, RLIKE=53, + RP=54, TRUE=55, EQ=56, CIEQ=57, NEQ=58, LT=59, LTE=60, GT=61, GTE=62, + PLUS=63, MINUS=64, ASTERISK=65, SLASH=66, PERCENT=67, OPENING_BRACKET=68, + CLOSING_BRACKET=69, UNQUOTED_IDENTIFIER=70, QUOTED_IDENTIFIER=71, EXPR_LINE_COMMENT=72, + EXPR_MULTILINE_COMMENT=73, EXPR_WS=74, METADATA=75, FROM_LINE_COMMENT=76, + FROM_MULTILINE_COMMENT=77, FROM_WS=78, ID_PATTERN=79, PROJECT_LINE_COMMENT=80, + PROJECT_MULTILINE_COMMENT=81, PROJECT_WS=82, AS=83, RENAME_LINE_COMMENT=84, + RENAME_MULTILINE_COMMENT=85, RENAME_WS=86, ON=87, WITH=88, ENRICH_POLICY_NAME=89, + ENRICH_LINE_COMMENT=90, ENRICH_MULTILINE_COMMENT=91, ENRICH_WS=92, ENRICH_FIELD_LINE_COMMENT=93, + ENRICH_FIELD_MULTILINE_COMMENT=94, ENRICH_FIELD_WS=95, LOOKUP_LINE_COMMENT=96, + LOOKUP_MULTILINE_COMMENT=97, LOOKUP_WS=98, LOOKUP_FIELD_LINE_COMMENT=99, + LOOKUP_FIELD_MULTILINE_COMMENT=100, LOOKUP_FIELD_WS=101, MVEXPAND_LINE_COMMENT=102, + MVEXPAND_MULTILINE_COMMENT=103, MVEXPAND_WS=104, INFO=105, SHOW_LINE_COMMENT=106, + SHOW_MULTILINE_COMMENT=107, SHOW_WS=108, FUNCTIONS=109, META_LINE_COMMENT=110, + META_MULTILINE_COMMENT=111, META_WS=112, COLON=113, SETTING=114, SETTING_LINE_COMMENT=115, + SETTTING_MULTILINE_COMMENT=116, SETTING_WS=117, METRICS_LINE_COMMENT=118, + METRICS_MULTILINE_COMMENT=119, METRICS_WS=120, CLOSING_METRICS_LINE_COMMENT=121, + CLOSING_METRICS_MULTILINE_COMMENT=122, CLOSING_METRICS_WS=123; public static final int EXPLAIN_MODE=1, EXPRESSION_MODE=2, FROM_MODE=3, PROJECT_MODE=4, RENAME_MODE=5, - ENRICH_MODE=6, ENRICH_FIELD_MODE=7, MVEXPAND_MODE=8, SHOW_MODE=9, META_MODE=10, - SETTING_MODE=11, METRICS_MODE=12, CLOSING_METRICS_MODE=13; + ENRICH_MODE=6, ENRICH_FIELD_MODE=7, LOOKUP_MODE=8, LOOKUP_FIELD_MODE=9, + MVEXPAND_MODE=10, SHOW_MODE=11, META_MODE=12, SETTING_MODE=13, METRICS_MODE=14, + CLOSING_METRICS_MODE=15; public static String[] channelNames = { "DEFAULT_TOKEN_CHANNEL", "HIDDEN" }; public static String[] modeNames = { "DEFAULT_MODE", "EXPLAIN_MODE", "EXPRESSION_MODE", "FROM_MODE", "PROJECT_MODE", - "RENAME_MODE", "ENRICH_MODE", "ENRICH_FIELD_MODE", "MVEXPAND_MODE", "SHOW_MODE", - "META_MODE", "SETTING_MODE", "METRICS_MODE", "CLOSING_METRICS_MODE" + "RENAME_MODE", "ENRICH_MODE", "ENRICH_FIELD_MODE", "LOOKUP_MODE", "LOOKUP_FIELD_MODE", + "MVEXPAND_MODE", "SHOW_MODE", "META_MODE", "SETTING_MODE", "METRICS_MODE", + "CLOSING_METRICS_MODE" }; private static String[] makeRuleNames() { return new String[] { "DISSECT", "DROP", "ENRICH", "EVAL", "EXPLAIN", "FROM", "GROK", "INLINESTATS", - "KEEP", "LIMIT", "META", "METRICS", "MV_EXPAND", "RENAME", "ROW", "SHOW", - "SORT", "STATS", "WHERE", "UNKNOWN_CMD", "LINE_COMMENT", "MULTILINE_COMMENT", - "WS", "INDEX_UNQUOTED_IDENTIFIER_PART", "INDEX_UNQUOTED_IDENTIFIER", + "KEEP", "LIMIT", "LOOKUP", "META", "METRICS", "MV_EXPAND", "RENAME", + "ROW", "SHOW", "SORT", "STATS", "WHERE", "UNKNOWN_CMD", "LINE_COMMENT", + "MULTILINE_COMMENT", "WS", "INDEX_UNQUOTED_IDENTIFIER_PART", "INDEX_UNQUOTED_IDENTIFIER", "EXPLAIN_OPENING_BRACKET", "EXPLAIN_PIPE", "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", "EXPLAIN_MULTILINE_COMMENT", "PIPE", "DIGIT", "LETTER", "ESCAPE_SEQUENCE", "UNESCAPED_CHARS", "EXPONENT", "ASPERAND", "BACKQUOTE", "BACKQUOTE_BLOCK", @@ -82,7 +86,11 @@ private static String[] makeRuleNames() { "ENRICH_MULTILINE_COMMENT", "ENRICH_WS", "ENRICH_FIELD_PIPE", "ENRICH_FIELD_ASSIGN", "ENRICH_FIELD_COMMA", "ENRICH_FIELD_DOT", "ENRICH_FIELD_WITH", "ENRICH_FIELD_ID_PATTERN", "ENRICH_FIELD_QUOTED_IDENTIFIER", "ENRICH_FIELD_LINE_COMMENT", "ENRICH_FIELD_MULTILINE_COMMENT", - "ENRICH_FIELD_WS", "MVEXPAND_PIPE", "MVEXPAND_DOT", "MVEXPAND_QUOTED_IDENTIFIER", + "ENRICH_FIELD_WS", "LOOKUP_PIPE", "LOOKUP_COMMA", "LOOKUP_DOT", "LOOKUP_ON", + "LOOKUP_INDEX_UNQUOTED_IDENTIFIER", "LOOKUP_LINE_COMMENT", "LOOKUP_MULTILINE_COMMENT", + "LOOKUP_WS", "LOOKUP_FIELD_PIPE", "LOOKUP_FIELD_COMMA", "LOOKUP_FIELD_DOT", + "LOOKUP_FIELD_ID_PATTERN", "LOOKUP_FIELD_LINE_COMMENT", "LOOKUP_FIELD_MULTILINE_COMMENT", + "LOOKUP_FIELD_WS", "MVEXPAND_PIPE", "MVEXPAND_DOT", "MVEXPAND_QUOTED_IDENTIFIER", "MVEXPAND_UNQUOTED_IDENTIFIER", "MVEXPAND_LINE_COMMENT", "MVEXPAND_MULTILINE_COMMENT", "MVEXPAND_WS", "SHOW_PIPE", "INFO", "SHOW_LINE_COMMENT", "SHOW_MULTILINE_COMMENT", "SHOW_WS", "META_PIPE", "FUNCTIONS", "META_LINE_COMMENT", "META_MULTILINE_COMMENT", @@ -99,25 +107,26 @@ private static String[] makeRuleNames() { private static String[] makeLiteralNames() { return new String[] { null, "'dissect'", "'drop'", "'enrich'", "'eval'", "'explain'", "'from'", - "'grok'", "'inlinestats'", "'keep'", "'limit'", "'meta'", "'metrics'", - "'mv_expand'", "'rename'", "'row'", "'show'", "'sort'", "'stats'", "'where'", - null, null, null, null, null, null, null, null, "'|'", null, null, null, - "'by'", "'and'", "'asc'", "'='", "'::'", "','", "'desc'", "'.'", "'false'", - "'first'", "'last'", "'('", "'in'", "'is'", "'like'", "'not'", "'null'", - "'nulls'", "'or'", "'?'", "'rlike'", "')'", "'true'", "'=='", "'=~'", - "'!='", "'<'", "'<='", "'>'", "'>='", "'+'", "'-'", "'*'", "'/'", "'%'", - null, "']'", null, null, null, null, null, "'metadata'", null, null, - null, null, null, null, null, "'as'", null, null, null, "'on'", "'with'", - null, null, null, null, null, null, null, null, null, null, "'info'", - null, null, null, "'functions'", null, null, null, "':'" + "'grok'", "'inlinestats'", "'keep'", "'limit'", "'lookup'", "'meta'", + "'metrics'", "'mv_expand'", "'rename'", "'row'", "'show'", "'sort'", + "'stats'", "'where'", null, null, null, null, null, null, null, null, + "'|'", null, null, null, "'by'", "'and'", "'asc'", "'='", "'::'", "','", + "'desc'", "'.'", "'false'", "'first'", "'last'", "'('", "'in'", "'is'", + "'like'", "'not'", "'null'", "'nulls'", "'or'", "'?'", "'rlike'", "')'", + "'true'", "'=='", "'=~'", "'!='", "'<'", "'<='", "'>'", "'>='", "'+'", + "'-'", "'*'", "'/'", "'%'", null, "']'", null, null, null, null, null, + "'metadata'", null, null, null, null, null, null, null, "'as'", null, + null, null, "'on'", "'with'", null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, "'info'", null, + null, null, "'functions'", null, null, null, "':'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static String[] makeSymbolicNames() { return new String[] { null, "DISSECT", "DROP", "ENRICH", "EVAL", "EXPLAIN", "FROM", "GROK", - "INLINESTATS", "KEEP", "LIMIT", "META", "METRICS", "MV_EXPAND", "RENAME", - "ROW", "SHOW", "SORT", "STATS", "WHERE", "UNKNOWN_CMD", "LINE_COMMENT", + "INLINESTATS", "KEEP", "LIMIT", "LOOKUP", "META", "METRICS", "MV_EXPAND", + "RENAME", "ROW", "SHOW", "SORT", "STATS", "WHERE", "UNKNOWN_CMD", "LINE_COMMENT", "MULTILINE_COMMENT", "WS", "INDEX_UNQUOTED_IDENTIFIER", "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", "EXPLAIN_MULTILINE_COMMENT", "PIPE", "QUOTED_STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "AND", "ASC", "ASSIGN", "CAST_OP", @@ -131,7 +140,9 @@ private static String[] makeSymbolicNames() { "AS", "RENAME_LINE_COMMENT", "RENAME_MULTILINE_COMMENT", "RENAME_WS", "ON", "WITH", "ENRICH_POLICY_NAME", "ENRICH_LINE_COMMENT", "ENRICH_MULTILINE_COMMENT", "ENRICH_WS", "ENRICH_FIELD_LINE_COMMENT", "ENRICH_FIELD_MULTILINE_COMMENT", - "ENRICH_FIELD_WS", "MVEXPAND_LINE_COMMENT", "MVEXPAND_MULTILINE_COMMENT", + "ENRICH_FIELD_WS", "LOOKUP_LINE_COMMENT", "LOOKUP_MULTILINE_COMMENT", + "LOOKUP_WS", "LOOKUP_FIELD_LINE_COMMENT", "LOOKUP_FIELD_MULTILINE_COMMENT", + "LOOKUP_FIELD_WS", "MVEXPAND_LINE_COMMENT", "MVEXPAND_MULTILINE_COMMENT", "MVEXPAND_WS", "INFO", "SHOW_LINE_COMMENT", "SHOW_MULTILINE_COMMENT", "SHOW_WS", "FUNCTIONS", "META_LINE_COMMENT", "META_MULTILINE_COMMENT", "META_WS", "COLON", "SETTING", "SETTING_LINE_COMMENT", "SETTTING_MULTILINE_COMMENT", @@ -200,223 +211,243 @@ public EsqlBaseLexer(CharStream input) { public ATN getATN() { return _ATN; } public static final String _serializedATN = - "\u0004\u0000t\u0511\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ + "\u0004\u0000{\u057c\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ + "\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ "\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ "\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ - "\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0002\u0000\u0007"+ - "\u0000\u0002\u0001\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007"+ - "\u0003\u0002\u0004\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007"+ - "\u0006\u0002\u0007\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n"+ - "\u0007\n\u0002\u000b\u0007\u000b\u0002\f\u0007\f\u0002\r\u0007\r\u0002"+ - "\u000e\u0007\u000e\u0002\u000f\u0007\u000f\u0002\u0010\u0007\u0010\u0002"+ - "\u0011\u0007\u0011\u0002\u0012\u0007\u0012\u0002\u0013\u0007\u0013\u0002"+ - "\u0014\u0007\u0014\u0002\u0015\u0007\u0015\u0002\u0016\u0007\u0016\u0002"+ - "\u0017\u0007\u0017\u0002\u0018\u0007\u0018\u0002\u0019\u0007\u0019\u0002"+ - "\u001a\u0007\u001a\u0002\u001b\u0007\u001b\u0002\u001c\u0007\u001c\u0002"+ - "\u001d\u0007\u001d\u0002\u001e\u0007\u001e\u0002\u001f\u0007\u001f\u0002"+ - " \u0007 \u0002!\u0007!\u0002\"\u0007\"\u0002#\u0007#\u0002$\u0007$\u0002"+ - "%\u0007%\u0002&\u0007&\u0002\'\u0007\'\u0002(\u0007(\u0002)\u0007)\u0002"+ - "*\u0007*\u0002+\u0007+\u0002,\u0007,\u0002-\u0007-\u0002.\u0007.\u0002"+ - "/\u0007/\u00020\u00070\u00021\u00071\u00022\u00072\u00023\u00073\u0002"+ - "4\u00074\u00025\u00075\u00026\u00076\u00027\u00077\u00028\u00078\u0002"+ - "9\u00079\u0002:\u0007:\u0002;\u0007;\u0002<\u0007<\u0002=\u0007=\u0002"+ - ">\u0007>\u0002?\u0007?\u0002@\u0007@\u0002A\u0007A\u0002B\u0007B\u0002"+ - "C\u0007C\u0002D\u0007D\u0002E\u0007E\u0002F\u0007F\u0002G\u0007G\u0002"+ - "H\u0007H\u0002I\u0007I\u0002J\u0007J\u0002K\u0007K\u0002L\u0007L\u0002"+ - "M\u0007M\u0002N\u0007N\u0002O\u0007O\u0002P\u0007P\u0002Q\u0007Q\u0002"+ - "R\u0007R\u0002S\u0007S\u0002T\u0007T\u0002U\u0007U\u0002V\u0007V\u0002"+ - "W\u0007W\u0002X\u0007X\u0002Y\u0007Y\u0002Z\u0007Z\u0002[\u0007[\u0002"+ - "\\\u0007\\\u0002]\u0007]\u0002^\u0007^\u0002_\u0007_\u0002`\u0007`\u0002"+ - "a\u0007a\u0002b\u0007b\u0002c\u0007c\u0002d\u0007d\u0002e\u0007e\u0002"+ - "f\u0007f\u0002g\u0007g\u0002h\u0007h\u0002i\u0007i\u0002j\u0007j\u0002"+ - "k\u0007k\u0002l\u0007l\u0002m\u0007m\u0002n\u0007n\u0002o\u0007o\u0002"+ - "p\u0007p\u0002q\u0007q\u0002r\u0007r\u0002s\u0007s\u0002t\u0007t\u0002"+ - "u\u0007u\u0002v\u0007v\u0002w\u0007w\u0002x\u0007x\u0002y\u0007y\u0002"+ - "z\u0007z\u0002{\u0007{\u0002|\u0007|\u0002}\u0007}\u0002~\u0007~\u0002"+ - "\u007f\u0007\u007f\u0002\u0080\u0007\u0080\u0002\u0081\u0007\u0081\u0002"+ - "\u0082\u0007\u0082\u0002\u0083\u0007\u0083\u0002\u0084\u0007\u0084\u0002"+ - "\u0085\u0007\u0085\u0002\u0086\u0007\u0086\u0002\u0087\u0007\u0087\u0002"+ - "\u0088\u0007\u0088\u0002\u0089\u0007\u0089\u0002\u008a\u0007\u008a\u0002"+ - "\u008b\u0007\u008b\u0002\u008c\u0007\u008c\u0002\u008d\u0007\u008d\u0002"+ - "\u008e\u0007\u008e\u0002\u008f\u0007\u008f\u0002\u0090\u0007\u0090\u0002"+ - "\u0091\u0007\u0091\u0002\u0092\u0007\u0092\u0002\u0093\u0007\u0093\u0002"+ - "\u0094\u0007\u0094\u0002\u0095\u0007\u0095\u0002\u0096\u0007\u0096\u0002"+ - "\u0097\u0007\u0097\u0002\u0098\u0007\u0098\u0002\u0099\u0007\u0099\u0002"+ - "\u009a\u0007\u009a\u0002\u009b\u0007\u009b\u0002\u009c\u0007\u009c\u0002"+ - "\u009d\u0007\u009d\u0002\u009e\u0007\u009e\u0002\u009f\u0007\u009f\u0002"+ - "\u00a0\u0007\u00a0\u0002\u00a1\u0007\u00a1\u0002\u00a2\u0007\u00a2\u0002"+ - "\u00a3\u0007\u00a3\u0002\u00a4\u0007\u00a4\u0002\u00a5\u0007\u00a5\u0002"+ - "\u00a6\u0007\u00a6\u0002\u00a7\u0007\u00a7\u0002\u00a8\u0007\u00a8\u0002"+ - "\u00a9\u0007\u00a9\u0002\u00aa\u0007\u00aa\u0002\u00ab\u0007\u00ab\u0002"+ - "\u00ac\u0007\u00ac\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001"+ - "\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001"+ - "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ - "\u0001\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001"+ - "\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001"+ - "\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0004\u0001"+ - "\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001"+ - "\u0004\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0005\u0001"+ - "\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0006\u0001\u0006\u0001"+ - "\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0007\u0001"+ - "\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001"+ - "\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001"+ - "\u0007\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\t"+ - "\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\n\u0001"+ - "\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\u000b\u0001\u000b\u0001"+ - "\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001"+ - "\u000b\u0001\u000b\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001"+ - "\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\r\u0001\r\u0001\r\u0001"+ - "\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\u000e\u0001\u000e\u0001"+ - "\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f\u0001"+ - "\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u0010\u0001"+ - "\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+ - "\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001"+ - "\u0011\u0001\u0011\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001"+ - "\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0013\u0004\u0013\u020a"+ - "\b\u0013\u000b\u0013\f\u0013\u020b\u0001\u0013\u0001\u0013\u0001\u0014"+ - "\u0001\u0014\u0001\u0014\u0001\u0014\u0005\u0014\u0214\b\u0014\n\u0014"+ - "\f\u0014\u0217\t\u0014\u0001\u0014\u0003\u0014\u021a\b\u0014\u0001\u0014"+ - "\u0003\u0014\u021d\b\u0014\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015"+ - "\u0001\u0015\u0001\u0015\u0001\u0015\u0005\u0015\u0226\b\u0015\n\u0015"+ - "\f\u0015\u0229\t\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015"+ - "\u0001\u0015\u0001\u0016\u0004\u0016\u0231\b\u0016\u000b\u0016\f\u0016"+ - "\u0232\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017\u0001\u0017\u0003"+ - "\u0017\u023a\b\u0017\u0001\u0018\u0004\u0018\u023d\b\u0018\u000b\u0018"+ - "\f\u0018\u023e\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019"+ - "\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001b"+ - "\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001\u001c"+ - "\u0001\u001c\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001e"+ - "\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001f\u0001\u001f\u0001 \u0001"+ - " \u0001!\u0001!\u0001!\u0001\"\u0001\"\u0001#\u0001#\u0003#\u0266\b#\u0001"+ - "#\u0004#\u0269\b#\u000b#\f#\u026a\u0001$\u0001$\u0001%\u0001%\u0001&\u0001"+ - "&\u0001&\u0003&\u0274\b&\u0001\'\u0001\'\u0001(\u0001(\u0001(\u0003(\u027b"+ - "\b(\u0001)\u0001)\u0001)\u0005)\u0280\b)\n)\f)\u0283\t)\u0001)\u0001)"+ - "\u0001)\u0001)\u0001)\u0001)\u0005)\u028b\b)\n)\f)\u028e\t)\u0001)\u0001"+ - ")\u0001)\u0001)\u0001)\u0003)\u0295\b)\u0001)\u0003)\u0298\b)\u0003)\u029a"+ - "\b)\u0001*\u0004*\u029d\b*\u000b*\f*\u029e\u0001+\u0004+\u02a2\b+\u000b"+ - "+\f+\u02a3\u0001+\u0001+\u0005+\u02a8\b+\n+\f+\u02ab\t+\u0001+\u0001+"+ - "\u0004+\u02af\b+\u000b+\f+\u02b0\u0001+\u0004+\u02b4\b+\u000b+\f+\u02b5"+ - "\u0001+\u0001+\u0005+\u02ba\b+\n+\f+\u02bd\t+\u0003+\u02bf\b+\u0001+\u0001"+ - "+\u0001+\u0001+\u0004+\u02c5\b+\u000b+\f+\u02c6\u0001+\u0001+\u0003+\u02cb"+ - "\b+\u0001,\u0001,\u0001,\u0001-\u0001-\u0001-\u0001-\u0001.\u0001.\u0001"+ - ".\u0001.\u0001/\u0001/\u00010\u00010\u00010\u00011\u00011\u00012\u0001"+ - "2\u00012\u00012\u00012\u00013\u00013\u00014\u00014\u00014\u00014\u0001"+ - "4\u00014\u00015\u00015\u00015\u00015\u00015\u00015\u00016\u00016\u0001"+ - "6\u00016\u00016\u00017\u00017\u00018\u00018\u00018\u00019\u00019\u0001"+ - "9\u0001:\u0001:\u0001:\u0001:\u0001:\u0001;\u0001;\u0001;\u0001;\u0001"+ - "<\u0001<\u0001<\u0001<\u0001<\u0001=\u0001=\u0001=\u0001=\u0001=\u0001"+ - "=\u0001>\u0001>\u0001>\u0001?\u0001?\u0001@\u0001@\u0001@\u0001@\u0001"+ - "@\u0001@\u0001A\u0001A\u0001B\u0001B\u0001B\u0001B\u0001B\u0001C\u0001"+ - "C\u0001C\u0001D\u0001D\u0001D\u0001E\u0001E\u0001E\u0001F\u0001F\u0001"+ - "G\u0001G\u0001G\u0001H\u0001H\u0001I\u0001I\u0001I\u0001J\u0001J\u0001"+ - "K\u0001K\u0001L\u0001L\u0001M\u0001M\u0001N\u0001N\u0001O\u0001O\u0001"+ - "O\u0001O\u0001O\u0001P\u0001P\u0001P\u0001P\u0001P\u0001Q\u0001Q\u0005"+ - "Q\u034e\bQ\nQ\fQ\u0351\tQ\u0001Q\u0001Q\u0003Q\u0355\bQ\u0001Q\u0004Q"+ - "\u0358\bQ\u000bQ\fQ\u0359\u0003Q\u035c\bQ\u0001R\u0001R\u0004R\u0360\b"+ - "R\u000bR\fR\u0361\u0001R\u0001R\u0001S\u0001S\u0001T\u0001T\u0001T\u0001"+ - "T\u0001U\u0001U\u0001U\u0001U\u0001V\u0001V\u0001V\u0001V\u0001W\u0001"+ - "W\u0001W\u0001W\u0001W\u0001X\u0001X\u0001X\u0001X\u0001Y\u0001Y\u0001"+ - "Y\u0001Y\u0001Z\u0001Z\u0001Z\u0001Z\u0001[\u0001[\u0001[\u0001[\u0001"+ - "\\\u0001\\\u0001\\\u0001\\\u0001]\u0001]\u0001]\u0001]\u0001]\u0001]\u0001"+ - "]\u0001]\u0001]\u0001^\u0001^\u0001^\u0001^\u0001_\u0001_\u0001_\u0001"+ - "_\u0001`\u0001`\u0001`\u0001`\u0001a\u0001a\u0001a\u0001a\u0001b\u0001"+ - "b\u0001b\u0001b\u0001b\u0001c\u0001c\u0001c\u0001c\u0001d\u0001d\u0001"+ - "d\u0001d\u0001e\u0001e\u0001e\u0001e\u0003e\u03b7\be\u0001f\u0001f\u0003"+ - "f\u03bb\bf\u0001f\u0005f\u03be\bf\nf\ff\u03c1\tf\u0001f\u0001f\u0003f"+ - "\u03c5\bf\u0001f\u0004f\u03c8\bf\u000bf\ff\u03c9\u0003f\u03cc\bf\u0001"+ - "g\u0001g\u0004g\u03d0\bg\u000bg\fg\u03d1\u0001h\u0001h\u0001h\u0001h\u0001"+ - "i\u0001i\u0001i\u0001i\u0001j\u0001j\u0001j\u0001j\u0001k\u0001k\u0001"+ - "k\u0001k\u0001k\u0001l\u0001l\u0001l\u0001l\u0001m\u0001m\u0001m\u0001"+ - "m\u0001n\u0001n\u0001n\u0001n\u0001o\u0001o\u0001o\u0001p\u0001p\u0001"+ + "\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ + "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ + "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ + "\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b\u0007\u000b\u0002"+ + "\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e\u0002\u000f\u0007\u000f"+ + "\u0002\u0010\u0007\u0010\u0002\u0011\u0007\u0011\u0002\u0012\u0007\u0012"+ + "\u0002\u0013\u0007\u0013\u0002\u0014\u0007\u0014\u0002\u0015\u0007\u0015"+ + "\u0002\u0016\u0007\u0016\u0002\u0017\u0007\u0017\u0002\u0018\u0007\u0018"+ + "\u0002\u0019\u0007\u0019\u0002\u001a\u0007\u001a\u0002\u001b\u0007\u001b"+ + "\u0002\u001c\u0007\u001c\u0002\u001d\u0007\u001d\u0002\u001e\u0007\u001e"+ + "\u0002\u001f\u0007\u001f\u0002 \u0007 \u0002!\u0007!\u0002\"\u0007\"\u0002"+ + "#\u0007#\u0002$\u0007$\u0002%\u0007%\u0002&\u0007&\u0002\'\u0007\'\u0002"+ + "(\u0007(\u0002)\u0007)\u0002*\u0007*\u0002+\u0007+\u0002,\u0007,\u0002"+ + "-\u0007-\u0002.\u0007.\u0002/\u0007/\u00020\u00070\u00021\u00071\u0002"+ + "2\u00072\u00023\u00073\u00024\u00074\u00025\u00075\u00026\u00076\u0002"+ + "7\u00077\u00028\u00078\u00029\u00079\u0002:\u0007:\u0002;\u0007;\u0002"+ + "<\u0007<\u0002=\u0007=\u0002>\u0007>\u0002?\u0007?\u0002@\u0007@\u0002"+ + "A\u0007A\u0002B\u0007B\u0002C\u0007C\u0002D\u0007D\u0002E\u0007E\u0002"+ + "F\u0007F\u0002G\u0007G\u0002H\u0007H\u0002I\u0007I\u0002J\u0007J\u0002"+ + "K\u0007K\u0002L\u0007L\u0002M\u0007M\u0002N\u0007N\u0002O\u0007O\u0002"+ + "P\u0007P\u0002Q\u0007Q\u0002R\u0007R\u0002S\u0007S\u0002T\u0007T\u0002"+ + "U\u0007U\u0002V\u0007V\u0002W\u0007W\u0002X\u0007X\u0002Y\u0007Y\u0002"+ + "Z\u0007Z\u0002[\u0007[\u0002\\\u0007\\\u0002]\u0007]\u0002^\u0007^\u0002"+ + "_\u0007_\u0002`\u0007`\u0002a\u0007a\u0002b\u0007b\u0002c\u0007c\u0002"+ + "d\u0007d\u0002e\u0007e\u0002f\u0007f\u0002g\u0007g\u0002h\u0007h\u0002"+ + "i\u0007i\u0002j\u0007j\u0002k\u0007k\u0002l\u0007l\u0002m\u0007m\u0002"+ + "n\u0007n\u0002o\u0007o\u0002p\u0007p\u0002q\u0007q\u0002r\u0007r\u0002"+ + "s\u0007s\u0002t\u0007t\u0002u\u0007u\u0002v\u0007v\u0002w\u0007w\u0002"+ + "x\u0007x\u0002y\u0007y\u0002z\u0007z\u0002{\u0007{\u0002|\u0007|\u0002"+ + "}\u0007}\u0002~\u0007~\u0002\u007f\u0007\u007f\u0002\u0080\u0007\u0080"+ + "\u0002\u0081\u0007\u0081\u0002\u0082\u0007\u0082\u0002\u0083\u0007\u0083"+ + "\u0002\u0084\u0007\u0084\u0002\u0085\u0007\u0085\u0002\u0086\u0007\u0086"+ + "\u0002\u0087\u0007\u0087\u0002\u0088\u0007\u0088\u0002\u0089\u0007\u0089"+ + "\u0002\u008a\u0007\u008a\u0002\u008b\u0007\u008b\u0002\u008c\u0007\u008c"+ + "\u0002\u008d\u0007\u008d\u0002\u008e\u0007\u008e\u0002\u008f\u0007\u008f"+ + "\u0002\u0090\u0007\u0090\u0002\u0091\u0007\u0091\u0002\u0092\u0007\u0092"+ + "\u0002\u0093\u0007\u0093\u0002\u0094\u0007\u0094\u0002\u0095\u0007\u0095"+ + "\u0002\u0096\u0007\u0096\u0002\u0097\u0007\u0097\u0002\u0098\u0007\u0098"+ + "\u0002\u0099\u0007\u0099\u0002\u009a\u0007\u009a\u0002\u009b\u0007\u009b"+ + "\u0002\u009c\u0007\u009c\u0002\u009d\u0007\u009d\u0002\u009e\u0007\u009e"+ + "\u0002\u009f\u0007\u009f\u0002\u00a0\u0007\u00a0\u0002\u00a1\u0007\u00a1"+ + "\u0002\u00a2\u0007\u00a2\u0002\u00a3\u0007\u00a3\u0002\u00a4\u0007\u00a4"+ + "\u0002\u00a5\u0007\u00a5\u0002\u00a6\u0007\u00a6\u0002\u00a7\u0007\u00a7"+ + "\u0002\u00a8\u0007\u00a8\u0002\u00a9\u0007\u00a9\u0002\u00aa\u0007\u00aa"+ + "\u0002\u00ab\u0007\u00ab\u0002\u00ac\u0007\u00ac\u0002\u00ad\u0007\u00ad"+ + "\u0002\u00ae\u0007\u00ae\u0002\u00af\u0007\u00af\u0002\u00b0\u0007\u00b0"+ + "\u0002\u00b1\u0007\u00b1\u0002\u00b2\u0007\u00b2\u0002\u00b3\u0007\u00b3"+ + "\u0002\u00b4\u0007\u00b4\u0002\u00b5\u0007\u00b5\u0002\u00b6\u0007\u00b6"+ + "\u0002\u00b7\u0007\u00b7\u0002\u00b8\u0007\u00b8\u0002\u00b9\u0007\u00b9"+ + "\u0002\u00ba\u0007\u00ba\u0002\u00bb\u0007\u00bb\u0002\u00bc\u0007\u00bc"+ + "\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000"+ + "\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001"+ + "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002"+ + "\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002"+ + "\u0001\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+ + "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004\u0001\u0004"+ + "\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004"+ + "\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+ + "\u0001\u0005\u0001\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006"+ + "\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0007\u0001\u0007\u0001\u0007"+ + "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007"+ + "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\b\u0001"+ + "\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\t\u0001\t\u0001\t\u0001"+ + "\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001"+ + "\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\u000b\u0001\u000b\u0001\u000b"+ + "\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001"+ + "\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\r\u0001"+ + "\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001"+ + "\r\u0001\r\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e"+ + "\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f"+ + "\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u0010\u0001\u0010"+ + "\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0011"+ + "\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011"+ + "\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012"+ + "\u0001\u0012\u0001\u0012\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013"+ + "\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0014\u0004\u0014"+ + "\u0235\b\u0014\u000b\u0014\f\u0014\u0236\u0001\u0014\u0001\u0014\u0001"+ + "\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0005\u0015\u023f\b\u0015\n"+ + "\u0015\f\u0015\u0242\t\u0015\u0001\u0015\u0003\u0015\u0245\b\u0015\u0001"+ + "\u0015\u0003\u0015\u0248\b\u0015\u0001\u0015\u0001\u0015\u0001\u0016\u0001"+ + "\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0005\u0016\u0251\b\u0016\n"+ + "\u0016\f\u0016\u0254\t\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001"+ + "\u0016\u0001\u0016\u0001\u0017\u0004\u0017\u025c\b\u0017\u000b\u0017\f"+ + "\u0017\u025d\u0001\u0017\u0001\u0017\u0001\u0018\u0001\u0018\u0001\u0018"+ + "\u0003\u0018\u0265\b\u0018\u0001\u0019\u0004\u0019\u0268\b\u0019\u000b"+ + "\u0019\f\u0019\u0269\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001"+ + "\u001a\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001"+ + "\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001d\u0001\u001d\u0001"+ + "\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001"+ + "\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001 \u0001 \u0001!\u0001"+ + "!\u0001\"\u0001\"\u0001\"\u0001#\u0001#\u0001$\u0001$\u0003$\u0291\b$"+ + "\u0001$\u0004$\u0294\b$\u000b$\f$\u0295\u0001%\u0001%\u0001&\u0001&\u0001"+ + "\'\u0001\'\u0001\'\u0003\'\u029f\b\'\u0001(\u0001(\u0001)\u0001)\u0001"+ + ")\u0003)\u02a6\b)\u0001*\u0001*\u0001*\u0005*\u02ab\b*\n*\f*\u02ae\t*"+ + "\u0001*\u0001*\u0001*\u0001*\u0001*\u0001*\u0005*\u02b6\b*\n*\f*\u02b9"+ + "\t*\u0001*\u0001*\u0001*\u0001*\u0001*\u0003*\u02c0\b*\u0001*\u0003*\u02c3"+ + "\b*\u0003*\u02c5\b*\u0001+\u0004+\u02c8\b+\u000b+\f+\u02c9\u0001,\u0004"+ + ",\u02cd\b,\u000b,\f,\u02ce\u0001,\u0001,\u0005,\u02d3\b,\n,\f,\u02d6\t"+ + ",\u0001,\u0001,\u0004,\u02da\b,\u000b,\f,\u02db\u0001,\u0004,\u02df\b"+ + ",\u000b,\f,\u02e0\u0001,\u0001,\u0005,\u02e5\b,\n,\f,\u02e8\t,\u0003,"+ + "\u02ea\b,\u0001,\u0001,\u0001,\u0001,\u0004,\u02f0\b,\u000b,\f,\u02f1"+ + "\u0001,\u0001,\u0003,\u02f6\b,\u0001-\u0001-\u0001-\u0001.\u0001.\u0001"+ + ".\u0001.\u0001/\u0001/\u0001/\u0001/\u00010\u00010\u00011\u00011\u0001"+ + "1\u00012\u00012\u00013\u00013\u00013\u00013\u00013\u00014\u00014\u0001"+ + "5\u00015\u00015\u00015\u00015\u00015\u00016\u00016\u00016\u00016\u0001"+ + "6\u00016\u00017\u00017\u00017\u00017\u00017\u00018\u00018\u00019\u0001"+ + "9\u00019\u0001:\u0001:\u0001:\u0001;\u0001;\u0001;\u0001;\u0001;\u0001"+ + "<\u0001<\u0001<\u0001<\u0001=\u0001=\u0001=\u0001=\u0001=\u0001>\u0001"+ + ">\u0001>\u0001>\u0001>\u0001>\u0001?\u0001?\u0001?\u0001@\u0001@\u0001"+ + "A\u0001A\u0001A\u0001A\u0001A\u0001A\u0001B\u0001B\u0001C\u0001C\u0001"+ + "C\u0001C\u0001C\u0001D\u0001D\u0001D\u0001E\u0001E\u0001E\u0001F\u0001"+ + "F\u0001F\u0001G\u0001G\u0001H\u0001H\u0001H\u0001I\u0001I\u0001J\u0001"+ + "J\u0001J\u0001K\u0001K\u0001L\u0001L\u0001M\u0001M\u0001N\u0001N\u0001"+ + "O\u0001O\u0001P\u0001P\u0001P\u0001P\u0001P\u0001Q\u0001Q\u0001Q\u0001"+ + "Q\u0001Q\u0001R\u0001R\u0005R\u0379\bR\nR\fR\u037c\tR\u0001R\u0001R\u0003"+ + "R\u0380\bR\u0001R\u0004R\u0383\bR\u000bR\fR\u0384\u0003R\u0387\bR\u0001"+ + "S\u0001S\u0004S\u038b\bS\u000bS\fS\u038c\u0001S\u0001S\u0001T\u0001T\u0001"+ + "U\u0001U\u0001U\u0001U\u0001V\u0001V\u0001V\u0001V\u0001W\u0001W\u0001"+ + "W\u0001W\u0001X\u0001X\u0001X\u0001X\u0001X\u0001Y\u0001Y\u0001Y\u0001"+ + "Y\u0001Z\u0001Z\u0001Z\u0001Z\u0001[\u0001[\u0001[\u0001[\u0001\\\u0001"+ + "\\\u0001\\\u0001\\\u0001]\u0001]\u0001]\u0001]\u0001^\u0001^\u0001^\u0001"+ + "^\u0001^\u0001^\u0001^\u0001^\u0001^\u0001_\u0001_\u0001_\u0001_\u0001"+ + "`\u0001`\u0001`\u0001`\u0001a\u0001a\u0001a\u0001a\u0001b\u0001b\u0001"+ + "b\u0001b\u0001c\u0001c\u0001c\u0001c\u0001c\u0001d\u0001d\u0001d\u0001"+ + "d\u0001e\u0001e\u0001e\u0001e\u0001f\u0001f\u0001f\u0001f\u0003f\u03e2"+ + "\bf\u0001g\u0001g\u0003g\u03e6\bg\u0001g\u0005g\u03e9\bg\ng\fg\u03ec\t"+ + "g\u0001g\u0001g\u0003g\u03f0\bg\u0001g\u0004g\u03f3\bg\u000bg\fg\u03f4"+ + "\u0003g\u03f7\bg\u0001h\u0001h\u0004h\u03fb\bh\u000bh\fh\u03fc\u0001i"+ + "\u0001i\u0001i\u0001i\u0001j\u0001j\u0001j\u0001j\u0001k\u0001k\u0001"+ + "k\u0001k\u0001l\u0001l\u0001l\u0001l\u0001l\u0001m\u0001m\u0001m\u0001"+ + "m\u0001n\u0001n\u0001n\u0001n\u0001o\u0001o\u0001o\u0001o\u0001p\u0001"+ "p\u0001p\u0001q\u0001q\u0001q\u0001q\u0001r\u0001r\u0001r\u0001r\u0001"+ - "s\u0001s\u0001s\u0001s\u0001t\u0001t\u0001t\u0001t\u0001t\u0001u\u0001"+ - "u\u0001u\u0001u\u0001u\u0001v\u0001v\u0001v\u0001v\u0001v\u0001w\u0001"+ - "w\u0001w\u0001w\u0001w\u0001w\u0001w\u0001x\u0001x\u0001y\u0004y\u041d"+ - "\by\u000by\fy\u041e\u0001y\u0001y\u0003y\u0423\by\u0001y\u0004y\u0426"+ - "\by\u000by\fy\u0427\u0001z\u0001z\u0001z\u0001z\u0001{\u0001{\u0001{\u0001"+ + "s\u0001s\u0001s\u0001s\u0001t\u0001t\u0001t\u0001t\u0001u\u0001u\u0001"+ + "u\u0001u\u0001u\u0001v\u0001v\u0001v\u0001v\u0001v\u0001w\u0001w\u0001"+ + "w\u0001w\u0001w\u0001x\u0001x\u0001x\u0001x\u0001x\u0001x\u0001x\u0001"+ + "y\u0001y\u0001z\u0004z\u0448\bz\u000bz\fz\u0449\u0001z\u0001z\u0003z\u044e"+ + "\bz\u0001z\u0004z\u0451\bz\u000bz\fz\u0452\u0001{\u0001{\u0001{\u0001"+ "{\u0001|\u0001|\u0001|\u0001|\u0001}\u0001}\u0001}\u0001}\u0001~\u0001"+ "~\u0001~\u0001~\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+ - "\u007f\u0001\u007f\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+ + "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+ "\u0081\u0001\u0081\u0001\u0081\u0001\u0081\u0001\u0082\u0001\u0082\u0001"+ "\u0082\u0001\u0082\u0001\u0083\u0001\u0083\u0001\u0083\u0001\u0083\u0001"+ "\u0084\u0001\u0084\u0001\u0084\u0001\u0084\u0001\u0085\u0001\u0085\u0001"+ "\u0085\u0001\u0085\u0001\u0086\u0001\u0086\u0001\u0086\u0001\u0086\u0001"+ "\u0087\u0001\u0087\u0001\u0087\u0001\u0087\u0001\u0088\u0001\u0088\u0001"+ "\u0088\u0001\u0088\u0001\u0089\u0001\u0089\u0001\u0089\u0001\u0089\u0001"+ - "\u0089\u0001\u008a\u0001\u008a\u0001\u008a\u0001\u008a\u0001\u008b\u0001"+ + "\u008a\u0001\u008a\u0001\u008a\u0001\u008a\u0001\u008a\u0001\u008b\u0001"+ "\u008b\u0001\u008b\u0001\u008b\u0001\u008c\u0001\u008c\u0001\u008c\u0001"+ - "\u008c\u0001\u008d\u0001\u008d\u0001\u008d\u0001\u008d\u0001\u008e\u0001"+ - "\u008e\u0001\u008e\u0001\u008e\u0001\u008f\u0001\u008f\u0001\u008f\u0001"+ - "\u008f\u0001\u0090\u0001\u0090\u0001\u0090\u0001\u0090\u0001\u0090\u0001"+ - "\u0091\u0001\u0091\u0001\u0091\u0001\u0091\u0001\u0091\u0001\u0092\u0001"+ - "\u0092\u0001\u0092\u0001\u0092\u0001\u0093\u0001\u0093\u0001\u0093\u0001"+ - "\u0093\u0001\u0094\u0001\u0094\u0001\u0094\u0001\u0094\u0001\u0095\u0001"+ + "\u008c\u0001\u008d\u0001\u008d\u0001\u008d\u0001\u008d\u0001\u008d\u0001"+ + "\u008e\u0001\u008e\u0001\u008e\u0001\u008e\u0001\u008f\u0001\u008f\u0001"+ + "\u008f\u0001\u008f\u0001\u0090\u0001\u0090\u0001\u0090\u0001\u0090\u0001"+ + "\u0091\u0001\u0091\u0001\u0091\u0001\u0091\u0001\u0092\u0001\u0092\u0001"+ + "\u0092\u0001\u0092\u0001\u0092\u0001\u0092\u0001\u0093\u0001\u0093\u0001"+ + "\u0093\u0001\u0093\u0001\u0094\u0001\u0094\u0001\u0094\u0001\u0094\u0001"+ "\u0095\u0001\u0095\u0001\u0095\u0001\u0095\u0001\u0096\u0001\u0096\u0001"+ - "\u0096\u0001\u0096\u0001\u0096\u0001\u0096\u0001\u0096\u0001\u0096\u0001"+ "\u0096\u0001\u0096\u0001\u0097\u0001\u0097\u0001\u0097\u0001\u0097\u0001"+ "\u0098\u0001\u0098\u0001\u0098\u0001\u0098\u0001\u0099\u0001\u0099\u0001"+ - "\u0099\u0001\u0099\u0001\u009a\u0001\u009a\u0001\u009a\u0001\u009a\u0001"+ - "\u009a\u0001\u009b\u0001\u009b\u0001\u009c\u0001\u009c\u0001\u009c\u0001"+ - "\u009c\u0001\u009c\u0004\u009c\u04c2\b\u009c\u000b\u009c\f\u009c\u04c3"+ - "\u0001\u009d\u0001\u009d\u0001\u009d\u0001\u009d\u0001\u009e\u0001\u009e"+ - "\u0001\u009e\u0001\u009e\u0001\u009f\u0001\u009f\u0001\u009f\u0001\u009f"+ - "\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a1"+ - "\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a2"+ - "\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a3\u0001\u00a3\u0001\u00a3"+ - "\u0001\u00a3\u0001\u00a4\u0001\u00a4\u0001\u00a4\u0001\u00a4\u0001\u00a5"+ - "\u0001\u00a5\u0001\u00a5\u0001\u00a5\u0001\u00a5\u0001\u00a5\u0001\u00a6"+ - "\u0001\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a7\u0001\u00a7\u0001\u00a7"+ - "\u0001\u00a7\u0001\u00a8\u0001\u00a8\u0001\u00a8\u0001\u00a8\u0001\u00a9"+ - "\u0001\u00a9\u0001\u00a9\u0001\u00a9\u0001\u00a9\u0001\u00a9\u0001\u00aa"+ - "\u0001\u00aa\u0001\u00aa\u0001\u00aa\u0001\u00aa\u0001\u00aa\u0001\u00ab"+ - "\u0001\u00ab\u0001\u00ab\u0001\u00ab\u0001\u00ab\u0001\u00ab\u0001\u00ac"+ - "\u0001\u00ac\u0001\u00ac\u0001\u00ac\u0001\u00ac\u0002\u0227\u028c\u0000"+ - "\u00ad\u000e\u0001\u0010\u0002\u0012\u0003\u0014\u0004\u0016\u0005\u0018"+ - "\u0006\u001a\u0007\u001c\b\u001e\t \n\"\u000b$\f&\r(\u000e*\u000f,\u0010"+ - ".\u00110\u00122\u00134\u00146\u00158\u0016:\u0017<\u0000>\u0018@\u0000"+ - "B\u0000D\u0019F\u001aH\u001bJ\u001cL\u0000N\u0000P\u0000R\u0000T\u0000"+ - "V\u0000X\u0000Z\u0000\\\u0000^\u0000`\u001db\u001ed\u001ff h!j\"l#n$p"+ - "%r&t\'v(x)z*|+~,\u0080-\u0082.\u0084/\u00860\u00881\u008a2\u008c3\u008e"+ - "4\u00905\u00926\u00947\u00968\u00989\u009a:\u009c;\u009e<\u00a0=\u00a2"+ - ">\u00a4?\u00a6@\u00a8A\u00aaB\u00acC\u00aeD\u00b0E\u00b2\u0000\u00b4F"+ - "\u00b6G\u00b8H\u00baI\u00bc\u0000\u00be\u0000\u00c0\u0000\u00c2\u0000"+ - "\u00c4\u0000\u00c6\u0000\u00c8J\u00ca\u0000\u00ccK\u00ceL\u00d0M\u00d2"+ - "\u0000\u00d4\u0000\u00d6\u0000\u00d8\u0000\u00da\u0000\u00dcN\u00deO\u00e0"+ - "P\u00e2Q\u00e4\u0000\u00e6\u0000\u00e8\u0000\u00ea\u0000\u00ecR\u00ee"+ - "\u0000\u00f0S\u00f2T\u00f4U\u00f6\u0000\u00f8\u0000\u00faV\u00fcW\u00fe"+ - "\u0000\u0100X\u0102\u0000\u0104\u0000\u0106Y\u0108Z\u010a[\u010c\u0000"+ - "\u010e\u0000\u0110\u0000\u0112\u0000\u0114\u0000\u0116\u0000\u0118\u0000"+ - "\u011a\\\u011c]\u011e^\u0120\u0000\u0122\u0000\u0124\u0000\u0126\u0000"+ - "\u0128_\u012a`\u012ca\u012e\u0000\u0130b\u0132c\u0134d\u0136e\u0138\u0000"+ - "\u013af\u013cg\u013eh\u0140i\u0142\u0000\u0144j\u0146k\u0148l\u014am\u014c"+ - "n\u014e\u0000\u0150\u0000\u0152o\u0154p\u0156q\u0158\u0000\u015ar\u015c"+ - "s\u015et\u0160\u0000\u0162\u0000\u0164\u0000\u0166\u0000\u000e\u0000\u0001"+ - "\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\r\u0006\u0000\t\n"+ - "\r\r //[[]]\u0002\u0000\n\n\r\r\u0003\u0000\t\n\r\r \n\u0000\t\n\r\r"+ - " ,,//==[[]]``||\u0002\u0000**//\u0001\u000009\u0002\u0000AZaz\u0005\u0000"+ - "\"\"\\\\nnrrtt\u0004\u0000\n\n\r\r\"\"\\\\\u0002\u0000EEee\u0002\u0000"+ - "++--\u0001\u0000``\u000b\u0000\t\n\r\r \"#,,//::<<>?\\\\||\u052a\u0000"+ - "\u000e\u0001\u0000\u0000\u0000\u0000\u0010\u0001\u0000\u0000\u0000\u0000"+ - "\u0012\u0001\u0000\u0000\u0000\u0000\u0014\u0001\u0000\u0000\u0000\u0000"+ - "\u0016\u0001\u0000\u0000\u0000\u0000\u0018\u0001\u0000\u0000\u0000\u0000"+ - "\u001a\u0001\u0000\u0000\u0000\u0000\u001c\u0001\u0000\u0000\u0000\u0000"+ - "\u001e\u0001\u0000\u0000\u0000\u0000 \u0001\u0000\u0000\u0000\u0000\""+ - "\u0001\u0000\u0000\u0000\u0000$\u0001\u0000\u0000\u0000\u0000&\u0001\u0000"+ - "\u0000\u0000\u0000(\u0001\u0000\u0000\u0000\u0000*\u0001\u0000\u0000\u0000"+ - "\u0000,\u0001\u0000\u0000\u0000\u0000.\u0001\u0000\u0000\u0000\u00000"+ - "\u0001\u0000\u0000\u0000\u00002\u0001\u0000\u0000\u0000\u00004\u0001\u0000"+ - "\u0000\u0000\u00006\u0001\u0000\u0000\u0000\u00008\u0001\u0000\u0000\u0000"+ - "\u0000:\u0001\u0000\u0000\u0000\u0000>\u0001\u0000\u0000\u0000\u0001@"+ - "\u0001\u0000\u0000\u0000\u0001B\u0001\u0000\u0000\u0000\u0001D\u0001\u0000"+ - "\u0000\u0000\u0001F\u0001\u0000\u0000\u0000\u0001H\u0001\u0000\u0000\u0000"+ - "\u0002J\u0001\u0000\u0000\u0000\u0002`\u0001\u0000\u0000\u0000\u0002b"+ - "\u0001\u0000\u0000\u0000\u0002d\u0001\u0000\u0000\u0000\u0002f\u0001\u0000"+ - "\u0000\u0000\u0002h\u0001\u0000\u0000\u0000\u0002j\u0001\u0000\u0000\u0000"+ - "\u0002l\u0001\u0000\u0000\u0000\u0002n\u0001\u0000\u0000\u0000\u0002p"+ - "\u0001\u0000\u0000\u0000\u0002r\u0001\u0000\u0000\u0000\u0002t\u0001\u0000"+ - "\u0000\u0000\u0002v\u0001\u0000\u0000\u0000\u0002x\u0001\u0000\u0000\u0000"+ - "\u0002z\u0001\u0000\u0000\u0000\u0002|\u0001\u0000\u0000\u0000\u0002~"+ - "\u0001\u0000\u0000\u0000\u0002\u0080\u0001\u0000\u0000\u0000\u0002\u0082"+ + "\u0099\u0001\u0099\u0001\u0099\u0001\u009a\u0001\u009a\u0001\u009a\u0001"+ + "\u009a\u0001\u009b\u0001\u009b\u0001\u009b\u0001\u009b\u0001\u009c\u0001"+ + "\u009c\u0001\u009c\u0001\u009c\u0001\u009d\u0001\u009d\u0001\u009d\u0001"+ + "\u009d\u0001\u009e\u0001\u009e\u0001\u009e\u0001\u009e\u0001\u009f\u0001"+ + "\u009f\u0001\u009f\u0001\u009f\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001"+ + "\u00a0\u0001\u00a0\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001"+ + "\u00a1\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a3\u0001"+ + "\u00a3\u0001\u00a3\u0001\u00a3\u0001\u00a4\u0001\u00a4\u0001\u00a4\u0001"+ + "\u00a4\u0001\u00a5\u0001\u00a5\u0001\u00a5\u0001\u00a5\u0001\u00a5\u0001"+ + "\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a6\u0001"+ + "\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a7\u0001\u00a7\u0001"+ + "\u00a7\u0001\u00a7\u0001\u00a8\u0001\u00a8\u0001\u00a8\u0001\u00a8\u0001"+ + "\u00a9\u0001\u00a9\u0001\u00a9\u0001\u00a9\u0001\u00aa\u0001\u00aa\u0001"+ + "\u00aa\u0001\u00aa\u0001\u00aa\u0001\u00ab\u0001\u00ab\u0001\u00ac\u0001"+ + "\u00ac\u0001\u00ac\u0001\u00ac\u0001\u00ac\u0004\u00ac\u052d\b\u00ac\u000b"+ + "\u00ac\f\u00ac\u052e\u0001\u00ad\u0001\u00ad\u0001\u00ad\u0001\u00ad\u0001"+ + "\u00ae\u0001\u00ae\u0001\u00ae\u0001\u00ae\u0001\u00af\u0001\u00af\u0001"+ + "\u00af\u0001\u00af\u0001\u00b0\u0001\u00b0\u0001\u00b0\u0001\u00b0\u0001"+ + "\u00b0\u0001\u00b1\u0001\u00b1\u0001\u00b1\u0001\u00b1\u0001\u00b1\u0001"+ + "\u00b1\u0001\u00b2\u0001\u00b2\u0001\u00b2\u0001\u00b2\u0001\u00b3\u0001"+ + "\u00b3\u0001\u00b3\u0001\u00b3\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001"+ + "\u00b4\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001"+ + "\u00b5\u0001\u00b6\u0001\u00b6\u0001\u00b6\u0001\u00b6\u0001\u00b7\u0001"+ + "\u00b7\u0001\u00b7\u0001\u00b7\u0001\u00b8\u0001\u00b8\u0001\u00b8\u0001"+ + "\u00b8\u0001\u00b9\u0001\u00b9\u0001\u00b9\u0001\u00b9\u0001\u00b9\u0001"+ + "\u00b9\u0001\u00ba\u0001\u00ba\u0001\u00ba\u0001\u00ba\u0001\u00ba\u0001"+ + "\u00ba\u0001\u00bb\u0001\u00bb\u0001\u00bb\u0001\u00bb\u0001\u00bb\u0001"+ + "\u00bb\u0001\u00bc\u0001\u00bc\u0001\u00bc\u0001\u00bc\u0001\u00bc\u0002"+ + "\u0252\u02b7\u0000\u00bd\u0010\u0001\u0012\u0002\u0014\u0003\u0016\u0004"+ + "\u0018\u0005\u001a\u0006\u001c\u0007\u001e\b \t\"\n$\u000b&\f(\r*\u000e"+ + ",\u000f.\u00100\u00112\u00124\u00136\u00148\u0015:\u0016<\u0017>\u0018"+ + "@\u0000B\u0019D\u0000F\u0000H\u001aJ\u001bL\u001cN\u001dP\u0000R\u0000"+ + "T\u0000V\u0000X\u0000Z\u0000\\\u0000^\u0000`\u0000b\u0000d\u001ef\u001f"+ + "h j!l\"n#p$r%t&v\'x(z)|*~+\u0080,\u0082-\u0084.\u0086/\u00880\u008a1\u008c"+ + "2\u008e3\u00904\u00925\u00946\u00967\u00988\u009a9\u009c:\u009e;\u00a0"+ + "<\u00a2=\u00a4>\u00a6?\u00a8@\u00aaA\u00acB\u00aeC\u00b0D\u00b2E\u00b4"+ + "F\u00b6\u0000\u00b8G\u00baH\u00bcI\u00beJ\u00c0\u0000\u00c2\u0000\u00c4"+ + "\u0000\u00c6\u0000\u00c8\u0000\u00ca\u0000\u00ccK\u00ce\u0000\u00d0L\u00d2"+ + "M\u00d4N\u00d6\u0000\u00d8\u0000\u00da\u0000\u00dc\u0000\u00de\u0000\u00e0"+ + "O\u00e2P\u00e4Q\u00e6R\u00e8\u0000\u00ea\u0000\u00ec\u0000\u00ee\u0000"+ + "\u00f0S\u00f2\u0000\u00f4T\u00f6U\u00f8V\u00fa\u0000\u00fc\u0000\u00fe"+ + "W\u0100X\u0102\u0000\u0104Y\u0106\u0000\u0108\u0000\u010aZ\u010c[\u010e"+ + "\\\u0110\u0000\u0112\u0000\u0114\u0000\u0116\u0000\u0118\u0000\u011a\u0000"+ + "\u011c\u0000\u011e]\u0120^\u0122_\u0124\u0000\u0126\u0000\u0128\u0000"+ + "\u012a\u0000\u012c\u0000\u012e`\u0130a\u0132b\u0134\u0000\u0136\u0000"+ + "\u0138\u0000\u013a\u0000\u013cc\u013ed\u0140e\u0142\u0000\u0144\u0000"+ + "\u0146\u0000\u0148\u0000\u014af\u014cg\u014eh\u0150\u0000\u0152i\u0154"+ + "j\u0156k\u0158l\u015a\u0000\u015cm\u015en\u0160o\u0162p\u0164\u0000\u0166"+ + "q\u0168r\u016as\u016ct\u016eu\u0170\u0000\u0172\u0000\u0174v\u0176w\u0178"+ + "x\u017a\u0000\u017cy\u017ez\u0180{\u0182\u0000\u0184\u0000\u0186\u0000"+ + "\u0188\u0000\u0010\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t"+ + "\n\u000b\f\r\u000e\u000f\r\u0006\u0000\t\n\r\r //[[]]\u0002\u0000\n\n"+ + "\r\r\u0003\u0000\t\n\r\r \n\u0000\t\n\r\r ,,//==[[]]``||\u0002\u0000"+ + "**//\u0001\u000009\u0002\u0000AZaz\u0005\u0000\"\"\\\\nnrrtt\u0004\u0000"+ + "\n\n\r\r\"\"\\\\\u0002\u0000EEee\u0002\u0000++--\u0001\u0000``\u000b\u0000"+ + "\t\n\r\r \"#,,//::<<>?\\\\||\u0593\u0000\u0010\u0001\u0000\u0000\u0000"+ + "\u0000\u0012\u0001\u0000\u0000\u0000\u0000\u0014\u0001\u0000\u0000\u0000"+ + "\u0000\u0016\u0001\u0000\u0000\u0000\u0000\u0018\u0001\u0000\u0000\u0000"+ + "\u0000\u001a\u0001\u0000\u0000\u0000\u0000\u001c\u0001\u0000\u0000\u0000"+ + "\u0000\u001e\u0001\u0000\u0000\u0000\u0000 \u0001\u0000\u0000\u0000\u0000"+ + "\"\u0001\u0000\u0000\u0000\u0000$\u0001\u0000\u0000\u0000\u0000&\u0001"+ + "\u0000\u0000\u0000\u0000(\u0001\u0000\u0000\u0000\u0000*\u0001\u0000\u0000"+ + "\u0000\u0000,\u0001\u0000\u0000\u0000\u0000.\u0001\u0000\u0000\u0000\u0000"+ + "0\u0001\u0000\u0000\u0000\u00002\u0001\u0000\u0000\u0000\u00004\u0001"+ + "\u0000\u0000\u0000\u00006\u0001\u0000\u0000\u0000\u00008\u0001\u0000\u0000"+ + "\u0000\u0000:\u0001\u0000\u0000\u0000\u0000<\u0001\u0000\u0000\u0000\u0000"+ + ">\u0001\u0000\u0000\u0000\u0000B\u0001\u0000\u0000\u0000\u0001D\u0001"+ + "\u0000\u0000\u0000\u0001F\u0001\u0000\u0000\u0000\u0001H\u0001\u0000\u0000"+ + "\u0000\u0001J\u0001\u0000\u0000\u0000\u0001L\u0001\u0000\u0000\u0000\u0002"+ + "N\u0001\u0000\u0000\u0000\u0002d\u0001\u0000\u0000\u0000\u0002f\u0001"+ + "\u0000\u0000\u0000\u0002h\u0001\u0000\u0000\u0000\u0002j\u0001\u0000\u0000"+ + "\u0000\u0002l\u0001\u0000\u0000\u0000\u0002n\u0001\u0000\u0000\u0000\u0002"+ + "p\u0001\u0000\u0000\u0000\u0002r\u0001\u0000\u0000\u0000\u0002t\u0001"+ + "\u0000\u0000\u0000\u0002v\u0001\u0000\u0000\u0000\u0002x\u0001\u0000\u0000"+ + "\u0000\u0002z\u0001\u0000\u0000\u0000\u0002|\u0001\u0000\u0000\u0000\u0002"+ + "~\u0001\u0000\u0000\u0000\u0002\u0080\u0001\u0000\u0000\u0000\u0002\u0082"+ "\u0001\u0000\u0000\u0000\u0002\u0084\u0001\u0000\u0000\u0000\u0002\u0086"+ "\u0001\u0000\u0000\u0000\u0002\u0088\u0001\u0000\u0000\u0000\u0002\u008a"+ "\u0001\u0000\u0000\u0000\u0002\u008c\u0001\u0000\u0000\u0000\u0002\u008e"+ @@ -428,598 +459,651 @@ public EsqlBaseLexer(CharStream input) { "\u0001\u0000\u0000\u0000\u0002\u00a4\u0001\u0000\u0000\u0000\u0002\u00a6"+ "\u0001\u0000\u0000\u0000\u0002\u00a8\u0001\u0000\u0000\u0000\u0002\u00aa"+ "\u0001\u0000\u0000\u0000\u0002\u00ac\u0001\u0000\u0000\u0000\u0002\u00ae"+ - "\u0001\u0000\u0000\u0000\u0002\u00b0\u0001\u0000\u0000\u0000\u0002\u00b4"+ - "\u0001\u0000\u0000\u0000\u0002\u00b6\u0001\u0000\u0000\u0000\u0002\u00b8"+ - "\u0001\u0000\u0000\u0000\u0002\u00ba\u0001\u0000\u0000\u0000\u0003\u00bc"+ - "\u0001\u0000\u0000\u0000\u0003\u00be\u0001\u0000\u0000\u0000\u0003\u00c0"+ + "\u0001\u0000\u0000\u0000\u0002\u00b0\u0001\u0000\u0000\u0000\u0002\u00b2"+ + "\u0001\u0000\u0000\u0000\u0002\u00b4\u0001\u0000\u0000\u0000\u0002\u00b8"+ + "\u0001\u0000\u0000\u0000\u0002\u00ba\u0001\u0000\u0000\u0000\u0002\u00bc"+ + "\u0001\u0000\u0000\u0000\u0002\u00be\u0001\u0000\u0000\u0000\u0003\u00c0"+ "\u0001\u0000\u0000\u0000\u0003\u00c2\u0001\u0000\u0000\u0000\u0003\u00c4"+ "\u0001\u0000\u0000\u0000\u0003\u00c6\u0001\u0000\u0000\u0000\u0003\u00c8"+ "\u0001\u0000\u0000\u0000\u0003\u00ca\u0001\u0000\u0000\u0000\u0003\u00cc"+ "\u0001\u0000\u0000\u0000\u0003\u00ce\u0001\u0000\u0000\u0000\u0003\u00d0"+ - "\u0001\u0000\u0000\u0000\u0004\u00d2\u0001\u0000\u0000\u0000\u0004\u00d4"+ - "\u0001\u0000\u0000\u0000\u0004\u00d6\u0001\u0000\u0000\u0000\u0004\u00dc"+ - "\u0001\u0000\u0000\u0000\u0004\u00de\u0001\u0000\u0000\u0000\u0004\u00e0"+ - "\u0001\u0000\u0000\u0000\u0004\u00e2\u0001\u0000\u0000\u0000\u0005\u00e4"+ - "\u0001\u0000\u0000\u0000\u0005\u00e6\u0001\u0000\u0000\u0000\u0005\u00e8"+ + "\u0001\u0000\u0000\u0000\u0003\u00d2\u0001\u0000\u0000\u0000\u0003\u00d4"+ + "\u0001\u0000\u0000\u0000\u0004\u00d6\u0001\u0000\u0000\u0000\u0004\u00d8"+ + "\u0001\u0000\u0000\u0000\u0004\u00da\u0001\u0000\u0000\u0000\u0004\u00e0"+ + "\u0001\u0000\u0000\u0000\u0004\u00e2\u0001\u0000\u0000\u0000\u0004\u00e4"+ + "\u0001\u0000\u0000\u0000\u0004\u00e6\u0001\u0000\u0000\u0000\u0005\u00e8"+ "\u0001\u0000\u0000\u0000\u0005\u00ea\u0001\u0000\u0000\u0000\u0005\u00ec"+ "\u0001\u0000\u0000\u0000\u0005\u00ee\u0001\u0000\u0000\u0000\u0005\u00f0"+ "\u0001\u0000\u0000\u0000\u0005\u00f2\u0001\u0000\u0000\u0000\u0005\u00f4"+ - "\u0001\u0000\u0000\u0000\u0006\u00f6\u0001\u0000\u0000\u0000\u0006\u00f8"+ + "\u0001\u0000\u0000\u0000\u0005\u00f6\u0001\u0000\u0000\u0000\u0005\u00f8"+ "\u0001\u0000\u0000\u0000\u0006\u00fa\u0001\u0000\u0000\u0000\u0006\u00fc"+ - "\u0001\u0000\u0000\u0000\u0006\u0100\u0001\u0000\u0000\u0000\u0006\u0102"+ + "\u0001\u0000\u0000\u0000\u0006\u00fe\u0001\u0000\u0000\u0000\u0006\u0100"+ "\u0001\u0000\u0000\u0000\u0006\u0104\u0001\u0000\u0000\u0000\u0006\u0106"+ "\u0001\u0000\u0000\u0000\u0006\u0108\u0001\u0000\u0000\u0000\u0006\u010a"+ - "\u0001\u0000\u0000\u0000\u0007\u010c\u0001\u0000\u0000\u0000\u0007\u010e"+ + "\u0001\u0000\u0000\u0000\u0006\u010c\u0001\u0000\u0000\u0000\u0006\u010e"+ "\u0001\u0000\u0000\u0000\u0007\u0110\u0001\u0000\u0000\u0000\u0007\u0112"+ "\u0001\u0000\u0000\u0000\u0007\u0114\u0001\u0000\u0000\u0000\u0007\u0116"+ "\u0001\u0000\u0000\u0000\u0007\u0118\u0001\u0000\u0000\u0000\u0007\u011a"+ "\u0001\u0000\u0000\u0000\u0007\u011c\u0001\u0000\u0000\u0000\u0007\u011e"+ - "\u0001\u0000\u0000\u0000\b\u0120\u0001\u0000\u0000\u0000\b\u0122\u0001"+ - "\u0000\u0000\u0000\b\u0124\u0001\u0000\u0000\u0000\b\u0126\u0001\u0000"+ - "\u0000\u0000\b\u0128\u0001\u0000\u0000\u0000\b\u012a\u0001\u0000\u0000"+ - "\u0000\b\u012c\u0001\u0000\u0000\u0000\t\u012e\u0001\u0000\u0000\u0000"+ - "\t\u0130\u0001\u0000\u0000\u0000\t\u0132\u0001\u0000\u0000\u0000\t\u0134"+ - "\u0001\u0000\u0000\u0000\t\u0136\u0001\u0000\u0000\u0000\n\u0138\u0001"+ - "\u0000\u0000\u0000\n\u013a\u0001\u0000\u0000\u0000\n\u013c\u0001\u0000"+ - "\u0000\u0000\n\u013e\u0001\u0000\u0000\u0000\n\u0140\u0001\u0000\u0000"+ - "\u0000\u000b\u0142\u0001\u0000\u0000\u0000\u000b\u0144\u0001\u0000\u0000"+ - "\u0000\u000b\u0146\u0001\u0000\u0000\u0000\u000b\u0148\u0001\u0000\u0000"+ - "\u0000\u000b\u014a\u0001\u0000\u0000\u0000\u000b\u014c\u0001\u0000\u0000"+ - "\u0000\f\u014e\u0001\u0000\u0000\u0000\f\u0150\u0001\u0000\u0000\u0000"+ - "\f\u0152\u0001\u0000\u0000\u0000\f\u0154\u0001\u0000\u0000\u0000\f\u0156"+ - "\u0001\u0000\u0000\u0000\r\u0158\u0001\u0000\u0000\u0000\r\u015a\u0001"+ - "\u0000\u0000\u0000\r\u015c\u0001\u0000\u0000\u0000\r\u015e\u0001\u0000"+ - "\u0000\u0000\r\u0160\u0001\u0000\u0000\u0000\r\u0162\u0001\u0000\u0000"+ + "\u0001\u0000\u0000\u0000\u0007\u0120\u0001\u0000\u0000\u0000\u0007\u0122"+ + "\u0001\u0000\u0000\u0000\b\u0124\u0001\u0000\u0000\u0000\b\u0126\u0001"+ + "\u0000\u0000\u0000\b\u0128\u0001\u0000\u0000\u0000\b\u012a\u0001\u0000"+ + "\u0000\u0000\b\u012c\u0001\u0000\u0000\u0000\b\u012e\u0001\u0000\u0000"+ + "\u0000\b\u0130\u0001\u0000\u0000\u0000\b\u0132\u0001\u0000\u0000\u0000"+ + "\t\u0134\u0001\u0000\u0000\u0000\t\u0136\u0001\u0000\u0000\u0000\t\u0138"+ + "\u0001\u0000\u0000\u0000\t\u013a\u0001\u0000\u0000\u0000\t\u013c\u0001"+ + "\u0000\u0000\u0000\t\u013e\u0001\u0000\u0000\u0000\t\u0140\u0001\u0000"+ + "\u0000\u0000\n\u0142\u0001\u0000\u0000\u0000\n\u0144\u0001\u0000\u0000"+ + "\u0000\n\u0146\u0001\u0000\u0000\u0000\n\u0148\u0001\u0000\u0000\u0000"+ + "\n\u014a\u0001\u0000\u0000\u0000\n\u014c\u0001\u0000\u0000\u0000\n\u014e"+ + "\u0001\u0000\u0000\u0000\u000b\u0150\u0001\u0000\u0000\u0000\u000b\u0152"+ + "\u0001\u0000\u0000\u0000\u000b\u0154\u0001\u0000\u0000\u0000\u000b\u0156"+ + "\u0001\u0000\u0000\u0000\u000b\u0158\u0001\u0000\u0000\u0000\f\u015a\u0001"+ + "\u0000\u0000\u0000\f\u015c\u0001\u0000\u0000\u0000\f\u015e\u0001\u0000"+ + "\u0000\u0000\f\u0160\u0001\u0000\u0000\u0000\f\u0162\u0001\u0000\u0000"+ "\u0000\r\u0164\u0001\u0000\u0000\u0000\r\u0166\u0001\u0000\u0000\u0000"+ - "\u000e\u0168\u0001\u0000\u0000\u0000\u0010\u0172\u0001\u0000\u0000\u0000"+ - "\u0012\u0179\u0001\u0000\u0000\u0000\u0014\u0182\u0001\u0000\u0000\u0000"+ - "\u0016\u0189\u0001\u0000\u0000\u0000\u0018\u0193\u0001\u0000\u0000\u0000"+ - "\u001a\u019a\u0001\u0000\u0000\u0000\u001c\u01a1\u0001\u0000\u0000\u0000"+ - "\u001e\u01af\u0001\u0000\u0000\u0000 \u01b6\u0001\u0000\u0000\u0000\""+ - "\u01be\u0001\u0000\u0000\u0000$\u01c5\u0001\u0000\u0000\u0000&\u01cf\u0001"+ - "\u0000\u0000\u0000(\u01db\u0001\u0000\u0000\u0000*\u01e4\u0001\u0000\u0000"+ - "\u0000,\u01ea\u0001\u0000\u0000\u0000.\u01f1\u0001\u0000\u0000\u00000"+ - "\u01f8\u0001\u0000\u0000\u00002\u0200\u0001\u0000\u0000\u00004\u0209\u0001"+ - "\u0000\u0000\u00006\u020f\u0001\u0000\u0000\u00008\u0220\u0001\u0000\u0000"+ - "\u0000:\u0230\u0001\u0000\u0000\u0000<\u0239\u0001\u0000\u0000\u0000>"+ - "\u023c\u0001\u0000\u0000\u0000@\u0240\u0001\u0000\u0000\u0000B\u0245\u0001"+ - "\u0000\u0000\u0000D\u024a\u0001\u0000\u0000\u0000F\u024e\u0001\u0000\u0000"+ - "\u0000H\u0252\u0001\u0000\u0000\u0000J\u0256\u0001\u0000\u0000\u0000L"+ - "\u025a\u0001\u0000\u0000\u0000N\u025c\u0001\u0000\u0000\u0000P\u025e\u0001"+ - "\u0000\u0000\u0000R\u0261\u0001\u0000\u0000\u0000T\u0263\u0001\u0000\u0000"+ - "\u0000V\u026c\u0001\u0000\u0000\u0000X\u026e\u0001\u0000\u0000\u0000Z"+ - "\u0273\u0001\u0000\u0000\u0000\\\u0275\u0001\u0000\u0000\u0000^\u027a"+ - "\u0001\u0000\u0000\u0000`\u0299\u0001\u0000\u0000\u0000b\u029c\u0001\u0000"+ - "\u0000\u0000d\u02ca\u0001\u0000\u0000\u0000f\u02cc\u0001\u0000\u0000\u0000"+ - "h\u02cf\u0001\u0000\u0000\u0000j\u02d3\u0001\u0000\u0000\u0000l\u02d7"+ - "\u0001\u0000\u0000\u0000n\u02d9\u0001\u0000\u0000\u0000p\u02dc\u0001\u0000"+ - "\u0000\u0000r\u02de\u0001\u0000\u0000\u0000t\u02e3\u0001\u0000\u0000\u0000"+ - "v\u02e5\u0001\u0000\u0000\u0000x\u02eb\u0001\u0000\u0000\u0000z\u02f1"+ - "\u0001\u0000\u0000\u0000|\u02f6\u0001\u0000\u0000\u0000~\u02f8\u0001\u0000"+ - "\u0000\u0000\u0080\u02fb\u0001\u0000\u0000\u0000\u0082\u02fe\u0001\u0000"+ - "\u0000\u0000\u0084\u0303\u0001\u0000\u0000\u0000\u0086\u0307\u0001\u0000"+ - "\u0000\u0000\u0088\u030c\u0001\u0000\u0000\u0000\u008a\u0312\u0001\u0000"+ - "\u0000\u0000\u008c\u0315\u0001\u0000\u0000\u0000\u008e\u0317\u0001\u0000"+ - "\u0000\u0000\u0090\u031d\u0001\u0000\u0000\u0000\u0092\u031f\u0001\u0000"+ - "\u0000\u0000\u0094\u0324\u0001\u0000\u0000\u0000\u0096\u0327\u0001\u0000"+ - "\u0000\u0000\u0098\u032a\u0001\u0000\u0000\u0000\u009a\u032d\u0001\u0000"+ - "\u0000\u0000\u009c\u032f\u0001\u0000\u0000\u0000\u009e\u0332\u0001\u0000"+ - "\u0000\u0000\u00a0\u0334\u0001\u0000\u0000\u0000\u00a2\u0337\u0001\u0000"+ - "\u0000\u0000\u00a4\u0339\u0001\u0000\u0000\u0000\u00a6\u033b\u0001\u0000"+ - "\u0000\u0000\u00a8\u033d\u0001\u0000\u0000\u0000\u00aa\u033f\u0001\u0000"+ - "\u0000\u0000\u00ac\u0341\u0001\u0000\u0000\u0000\u00ae\u0346\u0001\u0000"+ - "\u0000\u0000\u00b0\u035b\u0001\u0000\u0000\u0000\u00b2\u035d\u0001\u0000"+ - "\u0000\u0000\u00b4\u0365\u0001\u0000\u0000\u0000\u00b6\u0367\u0001\u0000"+ - "\u0000\u0000\u00b8\u036b\u0001\u0000\u0000\u0000\u00ba\u036f\u0001\u0000"+ - "\u0000\u0000\u00bc\u0373\u0001\u0000\u0000\u0000\u00be\u0378\u0001\u0000"+ - "\u0000\u0000\u00c0\u037c\u0001\u0000\u0000\u0000\u00c2\u0380\u0001\u0000"+ - "\u0000\u0000\u00c4\u0384\u0001\u0000\u0000\u0000\u00c6\u0388\u0001\u0000"+ - "\u0000\u0000\u00c8\u038c\u0001\u0000\u0000\u0000\u00ca\u0395\u0001\u0000"+ - "\u0000\u0000\u00cc\u0399\u0001\u0000\u0000\u0000\u00ce\u039d\u0001\u0000"+ - "\u0000\u0000\u00d0\u03a1\u0001\u0000\u0000\u0000\u00d2\u03a5\u0001\u0000"+ - "\u0000\u0000\u00d4\u03aa\u0001\u0000\u0000\u0000\u00d6\u03ae\u0001\u0000"+ - "\u0000\u0000\u00d8\u03b6\u0001\u0000\u0000\u0000\u00da\u03cb\u0001\u0000"+ - "\u0000\u0000\u00dc\u03cf\u0001\u0000\u0000\u0000\u00de\u03d3\u0001\u0000"+ - "\u0000\u0000\u00e0\u03d7\u0001\u0000\u0000\u0000\u00e2\u03db\u0001\u0000"+ - "\u0000\u0000\u00e4\u03df\u0001\u0000\u0000\u0000\u00e6\u03e4\u0001\u0000"+ - "\u0000\u0000\u00e8\u03e8\u0001\u0000\u0000\u0000\u00ea\u03ec\u0001\u0000"+ - "\u0000\u0000\u00ec\u03f0\u0001\u0000\u0000\u0000\u00ee\u03f3\u0001\u0000"+ - "\u0000\u0000\u00f0\u03f7\u0001\u0000\u0000\u0000\u00f2\u03fb\u0001\u0000"+ - "\u0000\u0000\u00f4\u03ff\u0001\u0000\u0000\u0000\u00f6\u0403\u0001\u0000"+ - "\u0000\u0000\u00f8\u0408\u0001\u0000\u0000\u0000\u00fa\u040d\u0001\u0000"+ - "\u0000\u0000\u00fc\u0412\u0001\u0000\u0000\u0000\u00fe\u0419\u0001\u0000"+ - "\u0000\u0000\u0100\u0422\u0001\u0000\u0000\u0000\u0102\u0429\u0001\u0000"+ - "\u0000\u0000\u0104\u042d\u0001\u0000\u0000\u0000\u0106\u0431\u0001\u0000"+ - "\u0000\u0000\u0108\u0435\u0001\u0000\u0000\u0000\u010a\u0439\u0001\u0000"+ - "\u0000\u0000\u010c\u043d\u0001\u0000\u0000\u0000\u010e\u0443\u0001\u0000"+ - "\u0000\u0000\u0110\u0447\u0001\u0000\u0000\u0000\u0112\u044b\u0001\u0000"+ - "\u0000\u0000\u0114\u044f\u0001\u0000\u0000\u0000\u0116\u0453\u0001\u0000"+ - "\u0000\u0000\u0118\u0457\u0001\u0000\u0000\u0000\u011a\u045b\u0001\u0000"+ - "\u0000\u0000\u011c\u045f\u0001\u0000\u0000\u0000\u011e\u0463\u0001\u0000"+ - "\u0000\u0000\u0120\u0467\u0001\u0000\u0000\u0000\u0122\u046c\u0001\u0000"+ - "\u0000\u0000\u0124\u0470\u0001\u0000\u0000\u0000\u0126\u0474\u0001\u0000"+ - "\u0000\u0000\u0128\u0478\u0001\u0000\u0000\u0000\u012a\u047c\u0001\u0000"+ - "\u0000\u0000\u012c\u0480\u0001\u0000\u0000\u0000\u012e\u0484\u0001\u0000"+ - "\u0000\u0000\u0130\u0489\u0001\u0000\u0000\u0000\u0132\u048e\u0001\u0000"+ - "\u0000\u0000\u0134\u0492\u0001\u0000\u0000\u0000\u0136\u0496\u0001\u0000"+ - "\u0000\u0000\u0138\u049a\u0001\u0000\u0000\u0000\u013a\u049f\u0001\u0000"+ - "\u0000\u0000\u013c\u04a9\u0001\u0000\u0000\u0000\u013e\u04ad\u0001\u0000"+ - "\u0000\u0000\u0140\u04b1\u0001\u0000\u0000\u0000\u0142\u04b5\u0001\u0000"+ - "\u0000\u0000\u0144\u04ba\u0001\u0000\u0000\u0000\u0146\u04c1\u0001\u0000"+ - "\u0000\u0000\u0148\u04c5\u0001\u0000\u0000\u0000\u014a\u04c9\u0001\u0000"+ - "\u0000\u0000\u014c\u04cd\u0001\u0000\u0000\u0000\u014e\u04d1\u0001\u0000"+ - "\u0000\u0000\u0150\u04d6\u0001\u0000\u0000\u0000\u0152\u04dc\u0001\u0000"+ - "\u0000\u0000\u0154\u04e0\u0001\u0000\u0000\u0000\u0156\u04e4\u0001\u0000"+ - "\u0000\u0000\u0158\u04e8\u0001\u0000\u0000\u0000\u015a\u04ee\u0001\u0000"+ - "\u0000\u0000\u015c\u04f2\u0001\u0000\u0000\u0000\u015e\u04f6\u0001\u0000"+ - "\u0000\u0000\u0160\u04fa\u0001\u0000\u0000\u0000\u0162\u0500\u0001\u0000"+ - "\u0000\u0000\u0164\u0506\u0001\u0000\u0000\u0000\u0166\u050c\u0001\u0000"+ - "\u0000\u0000\u0168\u0169\u0005d\u0000\u0000\u0169\u016a\u0005i\u0000\u0000"+ - "\u016a\u016b\u0005s\u0000\u0000\u016b\u016c\u0005s\u0000\u0000\u016c\u016d"+ - "\u0005e\u0000\u0000\u016d\u016e\u0005c\u0000\u0000\u016e\u016f\u0005t"+ - "\u0000\u0000\u016f\u0170\u0001\u0000\u0000\u0000\u0170\u0171\u0006\u0000"+ - "\u0000\u0000\u0171\u000f\u0001\u0000\u0000\u0000\u0172\u0173\u0005d\u0000"+ - "\u0000\u0173\u0174\u0005r\u0000\u0000\u0174\u0175\u0005o\u0000\u0000\u0175"+ - "\u0176\u0005p\u0000\u0000\u0176\u0177\u0001\u0000\u0000\u0000\u0177\u0178"+ - "\u0006\u0001\u0001\u0000\u0178\u0011\u0001\u0000\u0000\u0000\u0179\u017a"+ - "\u0005e\u0000\u0000\u017a\u017b\u0005n\u0000\u0000\u017b\u017c\u0005r"+ - "\u0000\u0000\u017c\u017d\u0005i\u0000\u0000\u017d\u017e\u0005c\u0000\u0000"+ - "\u017e\u017f\u0005h\u0000\u0000\u017f\u0180\u0001\u0000\u0000\u0000\u0180"+ - "\u0181\u0006\u0002\u0002\u0000\u0181\u0013\u0001\u0000\u0000\u0000\u0182"+ - "\u0183\u0005e\u0000\u0000\u0183\u0184\u0005v\u0000\u0000\u0184\u0185\u0005"+ - "a\u0000\u0000\u0185\u0186\u0005l\u0000\u0000\u0186\u0187\u0001\u0000\u0000"+ - "\u0000\u0187\u0188\u0006\u0003\u0000\u0000\u0188\u0015\u0001\u0000\u0000"+ - "\u0000\u0189\u018a\u0005e\u0000\u0000\u018a\u018b\u0005x\u0000\u0000\u018b"+ - "\u018c\u0005p\u0000\u0000\u018c\u018d\u0005l\u0000\u0000\u018d\u018e\u0005"+ - "a\u0000\u0000\u018e\u018f\u0005i\u0000\u0000\u018f\u0190\u0005n\u0000"+ - "\u0000\u0190\u0191\u0001\u0000\u0000\u0000\u0191\u0192\u0006\u0004\u0003"+ - "\u0000\u0192\u0017\u0001\u0000\u0000\u0000\u0193\u0194\u0005f\u0000\u0000"+ - "\u0194\u0195\u0005r\u0000\u0000\u0195\u0196\u0005o\u0000\u0000\u0196\u0197"+ - "\u0005m\u0000\u0000\u0197\u0198\u0001\u0000\u0000\u0000\u0198\u0199\u0006"+ - "\u0005\u0004\u0000\u0199\u0019\u0001\u0000\u0000\u0000\u019a\u019b\u0005"+ - "g\u0000\u0000\u019b\u019c\u0005r\u0000\u0000\u019c\u019d\u0005o\u0000"+ - "\u0000\u019d\u019e\u0005k\u0000\u0000\u019e\u019f\u0001\u0000\u0000\u0000"+ - "\u019f\u01a0\u0006\u0006\u0000\u0000\u01a0\u001b\u0001\u0000\u0000\u0000"+ - "\u01a1\u01a2\u0005i\u0000\u0000\u01a2\u01a3\u0005n\u0000\u0000\u01a3\u01a4"+ - "\u0005l\u0000\u0000\u01a4\u01a5\u0005i\u0000\u0000\u01a5\u01a6\u0005n"+ - "\u0000\u0000\u01a6\u01a7\u0005e\u0000\u0000\u01a7\u01a8\u0005s\u0000\u0000"+ - "\u01a8\u01a9\u0005t\u0000\u0000\u01a9\u01aa\u0005a\u0000\u0000\u01aa\u01ab"+ - "\u0005t\u0000\u0000\u01ab\u01ac\u0005s\u0000\u0000\u01ac\u01ad\u0001\u0000"+ - "\u0000\u0000\u01ad\u01ae\u0006\u0007\u0000\u0000\u01ae\u001d\u0001\u0000"+ - "\u0000\u0000\u01af\u01b0\u0005k\u0000\u0000\u01b0\u01b1\u0005e\u0000\u0000"+ - "\u01b1\u01b2\u0005e\u0000\u0000\u01b2\u01b3\u0005p\u0000\u0000\u01b3\u01b4"+ - "\u0001\u0000\u0000\u0000\u01b4\u01b5\u0006\b\u0001\u0000\u01b5\u001f\u0001"+ - "\u0000\u0000\u0000\u01b6\u01b7\u0005l\u0000\u0000\u01b7\u01b8\u0005i\u0000"+ - "\u0000\u01b8\u01b9\u0005m\u0000\u0000\u01b9\u01ba\u0005i\u0000\u0000\u01ba"+ - "\u01bb\u0005t\u0000\u0000\u01bb\u01bc\u0001\u0000\u0000\u0000\u01bc\u01bd"+ - "\u0006\t\u0000\u0000\u01bd!\u0001\u0000\u0000\u0000\u01be\u01bf\u0005"+ - "m\u0000\u0000\u01bf\u01c0\u0005e\u0000\u0000\u01c0\u01c1\u0005t\u0000"+ - "\u0000\u01c1\u01c2\u0005a\u0000\u0000\u01c2\u01c3\u0001\u0000\u0000\u0000"+ - "\u01c3\u01c4\u0006\n\u0005\u0000\u01c4#\u0001\u0000\u0000\u0000\u01c5"+ - "\u01c6\u0005m\u0000\u0000\u01c6\u01c7\u0005e\u0000\u0000\u01c7\u01c8\u0005"+ - "t\u0000\u0000\u01c8\u01c9\u0005r\u0000\u0000\u01c9\u01ca\u0005i\u0000"+ - "\u0000\u01ca\u01cb\u0005c\u0000\u0000\u01cb\u01cc\u0005s\u0000\u0000\u01cc"+ - "\u01cd\u0001\u0000\u0000\u0000\u01cd\u01ce\u0006\u000b\u0006\u0000\u01ce"+ - "%\u0001\u0000\u0000\u0000\u01cf\u01d0\u0005m\u0000\u0000\u01d0\u01d1\u0005"+ - "v\u0000\u0000\u01d1\u01d2\u0005_\u0000\u0000\u01d2\u01d3\u0005e\u0000"+ - "\u0000\u01d3\u01d4\u0005x\u0000\u0000\u01d4\u01d5\u0005p\u0000\u0000\u01d5"+ - "\u01d6\u0005a\u0000\u0000\u01d6\u01d7\u0005n\u0000\u0000\u01d7\u01d8\u0005"+ - "d\u0000\u0000\u01d8\u01d9\u0001\u0000\u0000\u0000\u01d9\u01da\u0006\f"+ - "\u0007\u0000\u01da\'\u0001\u0000\u0000\u0000\u01db\u01dc\u0005r\u0000"+ - "\u0000\u01dc\u01dd\u0005e\u0000\u0000\u01dd\u01de\u0005n\u0000\u0000\u01de"+ - "\u01df\u0005a\u0000\u0000\u01df\u01e0\u0005m\u0000\u0000\u01e0\u01e1\u0005"+ - "e\u0000\u0000\u01e1\u01e2\u0001\u0000\u0000\u0000\u01e2\u01e3\u0006\r"+ - "\b\u0000\u01e3)\u0001\u0000\u0000\u0000\u01e4\u01e5\u0005r\u0000\u0000"+ - "\u01e5\u01e6\u0005o\u0000\u0000\u01e6\u01e7\u0005w\u0000\u0000\u01e7\u01e8"+ - "\u0001\u0000\u0000\u0000\u01e8\u01e9\u0006\u000e\u0000\u0000\u01e9+\u0001"+ - "\u0000\u0000\u0000\u01ea\u01eb\u0005s\u0000\u0000\u01eb\u01ec\u0005h\u0000"+ - "\u0000\u01ec\u01ed\u0005o\u0000\u0000\u01ed\u01ee\u0005w\u0000\u0000\u01ee"+ - "\u01ef\u0001\u0000\u0000\u0000\u01ef\u01f0\u0006\u000f\t\u0000\u01f0-"+ - "\u0001\u0000\u0000\u0000\u01f1\u01f2\u0005s\u0000\u0000\u01f2\u01f3\u0005"+ - "o\u0000\u0000\u01f3\u01f4\u0005r\u0000\u0000\u01f4\u01f5\u0005t\u0000"+ - "\u0000\u01f5\u01f6\u0001\u0000\u0000\u0000\u01f6\u01f7\u0006\u0010\u0000"+ - "\u0000\u01f7/\u0001\u0000\u0000\u0000\u01f8\u01f9\u0005s\u0000\u0000\u01f9"+ - "\u01fa\u0005t\u0000\u0000\u01fa\u01fb\u0005a\u0000\u0000\u01fb\u01fc\u0005"+ - "t\u0000\u0000\u01fc\u01fd\u0005s\u0000\u0000\u01fd\u01fe\u0001\u0000\u0000"+ - "\u0000\u01fe\u01ff\u0006\u0011\u0000\u0000\u01ff1\u0001\u0000\u0000\u0000"+ - "\u0200\u0201\u0005w\u0000\u0000\u0201\u0202\u0005h\u0000\u0000\u0202\u0203"+ - "\u0005e\u0000\u0000\u0203\u0204\u0005r\u0000\u0000\u0204\u0205\u0005e"+ - "\u0000\u0000\u0205\u0206\u0001\u0000\u0000\u0000\u0206\u0207\u0006\u0012"+ - "\u0000\u0000\u02073\u0001\u0000\u0000\u0000\u0208\u020a\b\u0000\u0000"+ - "\u0000\u0209\u0208\u0001\u0000\u0000\u0000\u020a\u020b\u0001\u0000\u0000"+ - "\u0000\u020b\u0209\u0001\u0000\u0000\u0000\u020b\u020c\u0001\u0000\u0000"+ - "\u0000\u020c\u020d\u0001\u0000\u0000\u0000\u020d\u020e\u0006\u0013\u0000"+ - "\u0000\u020e5\u0001\u0000\u0000\u0000\u020f\u0210\u0005/\u0000\u0000\u0210"+ - "\u0211\u0005/\u0000\u0000\u0211\u0215\u0001\u0000\u0000\u0000\u0212\u0214"+ - "\b\u0001\u0000\u0000\u0213\u0212\u0001\u0000\u0000\u0000\u0214\u0217\u0001"+ - "\u0000\u0000\u0000\u0215\u0213\u0001\u0000\u0000\u0000\u0215\u0216\u0001"+ - "\u0000\u0000\u0000\u0216\u0219\u0001\u0000\u0000\u0000\u0217\u0215\u0001"+ - "\u0000\u0000\u0000\u0218\u021a\u0005\r\u0000\u0000\u0219\u0218\u0001\u0000"+ - "\u0000\u0000\u0219\u021a\u0001\u0000\u0000\u0000\u021a\u021c\u0001\u0000"+ - "\u0000\u0000\u021b\u021d\u0005\n\u0000\u0000\u021c\u021b\u0001\u0000\u0000"+ - "\u0000\u021c\u021d\u0001\u0000\u0000\u0000\u021d\u021e\u0001\u0000\u0000"+ - "\u0000\u021e\u021f\u0006\u0014\n\u0000\u021f7\u0001\u0000\u0000\u0000"+ - "\u0220\u0221\u0005/\u0000\u0000\u0221\u0222\u0005*\u0000\u0000\u0222\u0227"+ - "\u0001\u0000\u0000\u0000\u0223\u0226\u00038\u0015\u0000\u0224\u0226\t"+ - "\u0000\u0000\u0000\u0225\u0223\u0001\u0000\u0000\u0000\u0225\u0224\u0001"+ - "\u0000\u0000\u0000\u0226\u0229\u0001\u0000\u0000\u0000\u0227\u0228\u0001"+ - "\u0000\u0000\u0000\u0227\u0225\u0001\u0000\u0000\u0000\u0228\u022a\u0001"+ - "\u0000\u0000\u0000\u0229\u0227\u0001\u0000\u0000\u0000\u022a\u022b\u0005"+ - "*\u0000\u0000\u022b\u022c\u0005/\u0000\u0000\u022c\u022d\u0001\u0000\u0000"+ - "\u0000\u022d\u022e\u0006\u0015\n\u0000\u022e9\u0001\u0000\u0000\u0000"+ - "\u022f\u0231\u0007\u0002\u0000\u0000\u0230\u022f\u0001\u0000\u0000\u0000"+ - "\u0231\u0232\u0001\u0000\u0000\u0000\u0232\u0230\u0001\u0000\u0000\u0000"+ - "\u0232\u0233\u0001\u0000\u0000\u0000\u0233\u0234\u0001\u0000\u0000\u0000"+ - "\u0234\u0235\u0006\u0016\n\u0000\u0235;\u0001\u0000\u0000\u0000\u0236"+ - "\u023a\b\u0003\u0000\u0000\u0237\u0238\u0005/\u0000\u0000\u0238\u023a"+ - "\b\u0004\u0000\u0000\u0239\u0236\u0001\u0000\u0000\u0000\u0239\u0237\u0001"+ - "\u0000\u0000\u0000\u023a=\u0001\u0000\u0000\u0000\u023b\u023d\u0003<\u0017"+ - "\u0000\u023c\u023b\u0001\u0000\u0000\u0000\u023d\u023e\u0001\u0000\u0000"+ - "\u0000\u023e\u023c\u0001\u0000\u0000\u0000\u023e\u023f\u0001\u0000\u0000"+ - "\u0000\u023f?\u0001\u0000\u0000\u0000\u0240\u0241\u0003\u00acO\u0000\u0241"+ - "\u0242\u0001\u0000\u0000\u0000\u0242\u0243\u0006\u0019\u000b\u0000\u0243"+ - "\u0244\u0006\u0019\f\u0000\u0244A\u0001\u0000\u0000\u0000\u0245\u0246"+ - "\u0003J\u001e\u0000\u0246\u0247\u0001\u0000\u0000\u0000\u0247\u0248\u0006"+ - "\u001a\r\u0000\u0248\u0249\u0006\u001a\u000e\u0000\u0249C\u0001\u0000"+ - "\u0000\u0000\u024a\u024b\u0003:\u0016\u0000\u024b\u024c\u0001\u0000\u0000"+ - "\u0000\u024c\u024d\u0006\u001b\n\u0000\u024dE\u0001\u0000\u0000\u0000"+ - "\u024e\u024f\u00036\u0014\u0000\u024f\u0250\u0001\u0000\u0000\u0000\u0250"+ - "\u0251\u0006\u001c\n\u0000\u0251G\u0001\u0000\u0000\u0000\u0252\u0253"+ - "\u00038\u0015\u0000\u0253\u0254\u0001\u0000\u0000\u0000\u0254\u0255\u0006"+ - "\u001d\n\u0000\u0255I\u0001\u0000\u0000\u0000\u0256\u0257\u0005|\u0000"+ - "\u0000\u0257\u0258\u0001\u0000\u0000\u0000\u0258\u0259\u0006\u001e\u000e"+ - "\u0000\u0259K\u0001\u0000\u0000\u0000\u025a\u025b\u0007\u0005\u0000\u0000"+ - "\u025bM\u0001\u0000\u0000\u0000\u025c\u025d\u0007\u0006\u0000\u0000\u025d"+ - "O\u0001\u0000\u0000\u0000\u025e\u025f\u0005\\\u0000\u0000\u025f\u0260"+ - "\u0007\u0007\u0000\u0000\u0260Q\u0001\u0000\u0000\u0000\u0261\u0262\b"+ - "\b\u0000\u0000\u0262S\u0001\u0000\u0000\u0000\u0263\u0265\u0007\t\u0000"+ - "\u0000\u0264\u0266\u0007\n\u0000\u0000\u0265\u0264\u0001\u0000\u0000\u0000"+ - "\u0265\u0266\u0001\u0000\u0000\u0000\u0266\u0268\u0001\u0000\u0000\u0000"+ - "\u0267\u0269\u0003L\u001f\u0000\u0268\u0267\u0001\u0000\u0000\u0000\u0269"+ - "\u026a\u0001\u0000\u0000\u0000\u026a\u0268\u0001\u0000\u0000\u0000\u026a"+ - "\u026b\u0001\u0000\u0000\u0000\u026bU\u0001\u0000\u0000\u0000\u026c\u026d"+ - "\u0005@\u0000\u0000\u026dW\u0001\u0000\u0000\u0000\u026e\u026f\u0005`"+ - "\u0000\u0000\u026fY\u0001\u0000\u0000\u0000\u0270\u0274\b\u000b\u0000"+ - "\u0000\u0271\u0272\u0005`\u0000\u0000\u0272\u0274\u0005`\u0000\u0000\u0273"+ - "\u0270\u0001\u0000\u0000\u0000\u0273\u0271\u0001\u0000\u0000\u0000\u0274"+ - "[\u0001\u0000\u0000\u0000\u0275\u0276\u0005_\u0000\u0000\u0276]\u0001"+ - "\u0000\u0000\u0000\u0277\u027b\u0003N \u0000\u0278\u027b\u0003L\u001f"+ - "\u0000\u0279\u027b\u0003\\\'\u0000\u027a\u0277\u0001\u0000\u0000\u0000"+ - "\u027a\u0278\u0001\u0000\u0000\u0000\u027a\u0279\u0001\u0000\u0000\u0000"+ - "\u027b_\u0001\u0000\u0000\u0000\u027c\u0281\u0005\"\u0000\u0000\u027d"+ - "\u0280\u0003P!\u0000\u027e\u0280\u0003R\"\u0000\u027f\u027d\u0001\u0000"+ - "\u0000\u0000\u027f\u027e\u0001\u0000\u0000\u0000\u0280\u0283\u0001\u0000"+ - "\u0000\u0000\u0281\u027f\u0001\u0000\u0000\u0000\u0281\u0282\u0001\u0000"+ - "\u0000\u0000\u0282\u0284\u0001\u0000\u0000\u0000\u0283\u0281\u0001\u0000"+ - "\u0000\u0000\u0284\u029a\u0005\"\u0000\u0000\u0285\u0286\u0005\"\u0000"+ - "\u0000\u0286\u0287\u0005\"\u0000\u0000\u0287\u0288\u0005\"\u0000\u0000"+ - "\u0288\u028c\u0001\u0000\u0000\u0000\u0289\u028b\b\u0001\u0000\u0000\u028a"+ - "\u0289\u0001\u0000\u0000\u0000\u028b\u028e\u0001\u0000\u0000\u0000\u028c"+ - "\u028d\u0001\u0000\u0000\u0000\u028c\u028a\u0001\u0000\u0000\u0000\u028d"+ - "\u028f\u0001\u0000\u0000\u0000\u028e\u028c\u0001\u0000\u0000\u0000\u028f"+ - "\u0290\u0005\"\u0000\u0000\u0290\u0291\u0005\"\u0000\u0000\u0291\u0292"+ - "\u0005\"\u0000\u0000\u0292\u0294\u0001\u0000\u0000\u0000\u0293\u0295\u0005"+ - "\"\u0000\u0000\u0294\u0293\u0001\u0000\u0000\u0000\u0294\u0295\u0001\u0000"+ - "\u0000\u0000\u0295\u0297\u0001\u0000\u0000\u0000\u0296\u0298\u0005\"\u0000"+ - "\u0000\u0297\u0296\u0001\u0000\u0000\u0000\u0297\u0298\u0001\u0000\u0000"+ - "\u0000\u0298\u029a\u0001\u0000\u0000\u0000\u0299\u027c\u0001\u0000\u0000"+ - "\u0000\u0299\u0285\u0001\u0000\u0000\u0000\u029aa\u0001\u0000\u0000\u0000"+ - "\u029b\u029d\u0003L\u001f\u0000\u029c\u029b\u0001\u0000\u0000\u0000\u029d"+ - "\u029e\u0001\u0000\u0000\u0000\u029e\u029c\u0001\u0000\u0000\u0000\u029e"+ - "\u029f\u0001\u0000\u0000\u0000\u029fc\u0001\u0000\u0000\u0000\u02a0\u02a2"+ - "\u0003L\u001f\u0000\u02a1\u02a0\u0001\u0000\u0000\u0000\u02a2\u02a3\u0001"+ - "\u0000\u0000\u0000\u02a3\u02a1\u0001\u0000\u0000\u0000\u02a3\u02a4\u0001"+ - "\u0000\u0000\u0000\u02a4\u02a5\u0001\u0000\u0000\u0000\u02a5\u02a9\u0003"+ - "t3\u0000\u02a6\u02a8\u0003L\u001f\u0000\u02a7\u02a6\u0001\u0000\u0000"+ - "\u0000\u02a8\u02ab\u0001\u0000\u0000\u0000\u02a9\u02a7\u0001\u0000\u0000"+ - "\u0000\u02a9\u02aa\u0001\u0000\u0000\u0000\u02aa\u02cb\u0001\u0000\u0000"+ - "\u0000\u02ab\u02a9\u0001\u0000\u0000\u0000\u02ac\u02ae\u0003t3\u0000\u02ad"+ - "\u02af\u0003L\u001f\u0000\u02ae\u02ad\u0001\u0000\u0000\u0000\u02af\u02b0"+ - "\u0001\u0000\u0000\u0000\u02b0\u02ae\u0001\u0000\u0000\u0000\u02b0\u02b1"+ - "\u0001\u0000\u0000\u0000\u02b1\u02cb\u0001\u0000\u0000\u0000\u02b2\u02b4"+ - "\u0003L\u001f\u0000\u02b3\u02b2\u0001\u0000\u0000\u0000\u02b4\u02b5\u0001"+ - "\u0000\u0000\u0000\u02b5\u02b3\u0001\u0000\u0000\u0000\u02b5\u02b6\u0001"+ - "\u0000\u0000\u0000\u02b6\u02be\u0001\u0000\u0000\u0000\u02b7\u02bb\u0003"+ - "t3\u0000\u02b8\u02ba\u0003L\u001f\u0000\u02b9\u02b8\u0001\u0000\u0000"+ - "\u0000\u02ba\u02bd\u0001\u0000\u0000\u0000\u02bb\u02b9\u0001\u0000\u0000"+ - "\u0000\u02bb\u02bc\u0001\u0000\u0000\u0000\u02bc\u02bf\u0001\u0000\u0000"+ - "\u0000\u02bd\u02bb\u0001\u0000\u0000\u0000\u02be\u02b7\u0001\u0000\u0000"+ - "\u0000\u02be\u02bf\u0001\u0000\u0000\u0000\u02bf\u02c0\u0001\u0000\u0000"+ - "\u0000\u02c0\u02c1\u0003T#\u0000\u02c1\u02cb\u0001\u0000\u0000\u0000\u02c2"+ - "\u02c4\u0003t3\u0000\u02c3\u02c5\u0003L\u001f\u0000\u02c4\u02c3\u0001"+ - "\u0000\u0000\u0000\u02c5\u02c6\u0001\u0000\u0000\u0000\u02c6\u02c4\u0001"+ - "\u0000\u0000\u0000\u02c6\u02c7\u0001\u0000\u0000\u0000\u02c7\u02c8\u0001"+ - "\u0000\u0000\u0000\u02c8\u02c9\u0003T#\u0000\u02c9\u02cb\u0001\u0000\u0000"+ - "\u0000\u02ca\u02a1\u0001\u0000\u0000\u0000\u02ca\u02ac\u0001\u0000\u0000"+ - "\u0000\u02ca\u02b3\u0001\u0000\u0000\u0000\u02ca\u02c2\u0001\u0000\u0000"+ - "\u0000\u02cbe\u0001\u0000\u0000\u0000\u02cc\u02cd\u0005b\u0000\u0000\u02cd"+ - "\u02ce\u0005y\u0000\u0000\u02ceg\u0001\u0000\u0000\u0000\u02cf\u02d0\u0005"+ - "a\u0000\u0000\u02d0\u02d1\u0005n\u0000\u0000\u02d1\u02d2\u0005d\u0000"+ - "\u0000\u02d2i\u0001\u0000\u0000\u0000\u02d3\u02d4\u0005a\u0000\u0000\u02d4"+ - "\u02d5\u0005s\u0000\u0000\u02d5\u02d6\u0005c\u0000\u0000\u02d6k\u0001"+ - "\u0000\u0000\u0000\u02d7\u02d8\u0005=\u0000\u0000\u02d8m\u0001\u0000\u0000"+ - "\u0000\u02d9\u02da\u0005:\u0000\u0000\u02da\u02db\u0005:\u0000\u0000\u02db"+ - "o\u0001\u0000\u0000\u0000\u02dc\u02dd\u0005,\u0000\u0000\u02ddq\u0001"+ - "\u0000\u0000\u0000\u02de\u02df\u0005d\u0000\u0000\u02df\u02e0\u0005e\u0000"+ - "\u0000\u02e0\u02e1\u0005s\u0000\u0000\u02e1\u02e2\u0005c\u0000\u0000\u02e2"+ - "s\u0001\u0000\u0000\u0000\u02e3\u02e4\u0005.\u0000\u0000\u02e4u\u0001"+ - "\u0000\u0000\u0000\u02e5\u02e6\u0005f\u0000\u0000\u02e6\u02e7\u0005a\u0000"+ - "\u0000\u02e7\u02e8\u0005l\u0000\u0000\u02e8\u02e9\u0005s\u0000\u0000\u02e9"+ - "\u02ea\u0005e\u0000\u0000\u02eaw\u0001\u0000\u0000\u0000\u02eb\u02ec\u0005"+ - "f\u0000\u0000\u02ec\u02ed\u0005i\u0000\u0000\u02ed\u02ee\u0005r\u0000"+ - "\u0000\u02ee\u02ef\u0005s\u0000\u0000\u02ef\u02f0\u0005t\u0000\u0000\u02f0"+ - "y\u0001\u0000\u0000\u0000\u02f1\u02f2\u0005l\u0000\u0000\u02f2\u02f3\u0005"+ - "a\u0000\u0000\u02f3\u02f4\u0005s\u0000\u0000\u02f4\u02f5\u0005t\u0000"+ - "\u0000\u02f5{\u0001\u0000\u0000\u0000\u02f6\u02f7\u0005(\u0000\u0000\u02f7"+ - "}\u0001\u0000\u0000\u0000\u02f8\u02f9\u0005i\u0000\u0000\u02f9\u02fa\u0005"+ - "n\u0000\u0000\u02fa\u007f\u0001\u0000\u0000\u0000\u02fb\u02fc\u0005i\u0000"+ - "\u0000\u02fc\u02fd\u0005s\u0000\u0000\u02fd\u0081\u0001\u0000\u0000\u0000"+ - "\u02fe\u02ff\u0005l\u0000\u0000\u02ff\u0300\u0005i\u0000\u0000\u0300\u0301"+ - "\u0005k\u0000\u0000\u0301\u0302\u0005e\u0000\u0000\u0302\u0083\u0001\u0000"+ - "\u0000\u0000\u0303\u0304\u0005n\u0000\u0000\u0304\u0305\u0005o\u0000\u0000"+ - "\u0305\u0306\u0005t\u0000\u0000\u0306\u0085\u0001\u0000\u0000\u0000\u0307"+ - "\u0308\u0005n\u0000\u0000\u0308\u0309\u0005u\u0000\u0000\u0309\u030a\u0005"+ - "l\u0000\u0000\u030a\u030b\u0005l\u0000\u0000\u030b\u0087\u0001\u0000\u0000"+ - "\u0000\u030c\u030d\u0005n\u0000\u0000\u030d\u030e\u0005u\u0000\u0000\u030e"+ - "\u030f\u0005l\u0000\u0000\u030f\u0310\u0005l\u0000\u0000\u0310\u0311\u0005"+ - "s\u0000\u0000\u0311\u0089\u0001\u0000\u0000\u0000\u0312\u0313\u0005o\u0000"+ - "\u0000\u0313\u0314\u0005r\u0000\u0000\u0314\u008b\u0001\u0000\u0000\u0000"+ - "\u0315\u0316\u0005?\u0000\u0000\u0316\u008d\u0001\u0000\u0000\u0000\u0317"+ - "\u0318\u0005r\u0000\u0000\u0318\u0319\u0005l\u0000\u0000\u0319\u031a\u0005"+ - "i\u0000\u0000\u031a\u031b\u0005k\u0000\u0000\u031b\u031c\u0005e\u0000"+ - "\u0000\u031c\u008f\u0001\u0000\u0000\u0000\u031d\u031e\u0005)\u0000\u0000"+ - "\u031e\u0091\u0001\u0000\u0000\u0000\u031f\u0320\u0005t\u0000\u0000\u0320"+ - "\u0321\u0005r\u0000\u0000\u0321\u0322\u0005u\u0000\u0000\u0322\u0323\u0005"+ - "e\u0000\u0000\u0323\u0093\u0001\u0000\u0000\u0000\u0324\u0325\u0005=\u0000"+ - "\u0000\u0325\u0326\u0005=\u0000\u0000\u0326\u0095\u0001\u0000\u0000\u0000"+ - "\u0327\u0328\u0005=\u0000\u0000\u0328\u0329\u0005~\u0000\u0000\u0329\u0097"+ - "\u0001\u0000\u0000\u0000\u032a\u032b\u0005!\u0000\u0000\u032b\u032c\u0005"+ - "=\u0000\u0000\u032c\u0099\u0001\u0000\u0000\u0000\u032d\u032e\u0005<\u0000"+ - "\u0000\u032e\u009b\u0001\u0000\u0000\u0000\u032f\u0330\u0005<\u0000\u0000"+ - "\u0330\u0331\u0005=\u0000\u0000\u0331\u009d\u0001\u0000\u0000\u0000\u0332"+ - "\u0333\u0005>\u0000\u0000\u0333\u009f\u0001\u0000\u0000\u0000\u0334\u0335"+ - "\u0005>\u0000\u0000\u0335\u0336\u0005=\u0000\u0000\u0336\u00a1\u0001\u0000"+ - "\u0000\u0000\u0337\u0338\u0005+\u0000\u0000\u0338\u00a3\u0001\u0000\u0000"+ - "\u0000\u0339\u033a\u0005-\u0000\u0000\u033a\u00a5\u0001\u0000\u0000\u0000"+ - "\u033b\u033c\u0005*\u0000\u0000\u033c\u00a7\u0001\u0000\u0000\u0000\u033d"+ - "\u033e\u0005/\u0000\u0000\u033e\u00a9\u0001\u0000\u0000\u0000\u033f\u0340"+ - "\u0005%\u0000\u0000\u0340\u00ab\u0001\u0000\u0000\u0000\u0341\u0342\u0005"+ - "[\u0000\u0000\u0342\u0343\u0001\u0000\u0000\u0000\u0343\u0344\u0006O\u0000"+ - "\u0000\u0344\u0345\u0006O\u0000\u0000\u0345\u00ad\u0001\u0000\u0000\u0000"+ - "\u0346\u0347\u0005]\u0000\u0000\u0347\u0348\u0001\u0000\u0000\u0000\u0348"+ - "\u0349\u0006P\u000e\u0000\u0349\u034a\u0006P\u000e\u0000\u034a\u00af\u0001"+ - "\u0000\u0000\u0000\u034b\u034f\u0003N \u0000\u034c\u034e\u0003^(\u0000"+ - "\u034d\u034c\u0001\u0000\u0000\u0000\u034e\u0351\u0001\u0000\u0000\u0000"+ - "\u034f\u034d\u0001\u0000\u0000\u0000\u034f\u0350\u0001\u0000\u0000\u0000"+ - "\u0350\u035c\u0001\u0000\u0000\u0000\u0351\u034f\u0001\u0000\u0000\u0000"+ - "\u0352\u0355\u0003\\\'\u0000\u0353\u0355\u0003V$\u0000\u0354\u0352\u0001"+ - "\u0000\u0000\u0000\u0354\u0353\u0001\u0000\u0000\u0000\u0355\u0357\u0001"+ - "\u0000\u0000\u0000\u0356\u0358\u0003^(\u0000\u0357\u0356\u0001\u0000\u0000"+ - "\u0000\u0358\u0359\u0001\u0000\u0000\u0000\u0359\u0357\u0001\u0000\u0000"+ - "\u0000\u0359\u035a\u0001\u0000\u0000\u0000\u035a\u035c\u0001\u0000\u0000"+ - "\u0000\u035b\u034b\u0001\u0000\u0000\u0000\u035b\u0354\u0001\u0000\u0000"+ - "\u0000\u035c\u00b1\u0001\u0000\u0000\u0000\u035d\u035f\u0003X%\u0000\u035e"+ - "\u0360\u0003Z&\u0000\u035f\u035e\u0001\u0000\u0000\u0000\u0360\u0361\u0001"+ - "\u0000\u0000\u0000\u0361\u035f\u0001\u0000\u0000\u0000\u0361\u0362\u0001"+ - "\u0000\u0000\u0000\u0362\u0363\u0001\u0000\u0000\u0000\u0363\u0364\u0003"+ - "X%\u0000\u0364\u00b3\u0001\u0000\u0000\u0000\u0365\u0366\u0003\u00b2R"+ - "\u0000\u0366\u00b5\u0001\u0000\u0000\u0000\u0367\u0368\u00036\u0014\u0000"+ - "\u0368\u0369\u0001\u0000\u0000\u0000\u0369\u036a\u0006T\n\u0000\u036a"+ - "\u00b7\u0001\u0000\u0000\u0000\u036b\u036c\u00038\u0015\u0000\u036c\u036d"+ - "\u0001\u0000\u0000\u0000\u036d\u036e\u0006U\n\u0000\u036e\u00b9\u0001"+ - "\u0000\u0000\u0000\u036f\u0370\u0003:\u0016\u0000\u0370\u0371\u0001\u0000"+ - "\u0000\u0000\u0371\u0372\u0006V\n\u0000\u0372\u00bb\u0001\u0000\u0000"+ - "\u0000\u0373\u0374\u0003J\u001e\u0000\u0374\u0375\u0001\u0000\u0000\u0000"+ - "\u0375\u0376\u0006W\r\u0000\u0376\u0377\u0006W\u000e\u0000\u0377\u00bd"+ - "\u0001\u0000\u0000\u0000\u0378\u0379\u0003\u00acO\u0000\u0379\u037a\u0001"+ - "\u0000\u0000\u0000\u037a\u037b\u0006X\u000b\u0000\u037b\u00bf\u0001\u0000"+ - "\u0000\u0000\u037c\u037d\u0003\u00aeP\u0000\u037d\u037e\u0001\u0000\u0000"+ - "\u0000\u037e\u037f\u0006Y\u000f\u0000\u037f\u00c1\u0001\u0000\u0000\u0000"+ - "\u0380\u0381\u0003p1\u0000\u0381\u0382\u0001\u0000\u0000\u0000\u0382\u0383"+ - "\u0006Z\u0010\u0000\u0383\u00c3\u0001\u0000\u0000\u0000\u0384\u0385\u0003"+ - "l/\u0000\u0385\u0386\u0001\u0000\u0000\u0000\u0386\u0387\u0006[\u0011"+ - "\u0000\u0387\u00c5\u0001\u0000\u0000\u0000\u0388\u0389\u0003`)\u0000\u0389"+ - "\u038a\u0001\u0000\u0000\u0000\u038a\u038b\u0006\\\u0012\u0000\u038b\u00c7"+ - "\u0001\u0000\u0000\u0000\u038c\u038d\u0005m\u0000\u0000\u038d\u038e\u0005"+ - "e\u0000\u0000\u038e\u038f\u0005t\u0000\u0000\u038f\u0390\u0005a\u0000"+ - "\u0000\u0390\u0391\u0005d\u0000\u0000\u0391\u0392\u0005a\u0000\u0000\u0392"+ - "\u0393\u0005t\u0000\u0000\u0393\u0394\u0005a\u0000\u0000\u0394\u00c9\u0001"+ - "\u0000\u0000\u0000\u0395\u0396\u0003>\u0018\u0000\u0396\u0397\u0001\u0000"+ - "\u0000\u0000\u0397\u0398\u0006^\u0013\u0000\u0398\u00cb\u0001\u0000\u0000"+ - "\u0000\u0399\u039a\u00036\u0014\u0000\u039a\u039b\u0001\u0000\u0000\u0000"+ - "\u039b\u039c\u0006_\n\u0000\u039c\u00cd\u0001\u0000\u0000\u0000\u039d"+ - "\u039e\u00038\u0015\u0000\u039e\u039f\u0001\u0000\u0000\u0000\u039f\u03a0"+ - "\u0006`\n\u0000\u03a0\u00cf\u0001\u0000\u0000\u0000\u03a1\u03a2\u0003"+ - ":\u0016\u0000\u03a2\u03a3\u0001\u0000\u0000\u0000\u03a3\u03a4\u0006a\n"+ - "\u0000\u03a4\u00d1\u0001\u0000\u0000\u0000\u03a5\u03a6\u0003J\u001e\u0000"+ - "\u03a6\u03a7\u0001\u0000\u0000\u0000\u03a7\u03a8\u0006b\r\u0000\u03a8"+ - "\u03a9\u0006b\u000e\u0000\u03a9\u00d3\u0001\u0000\u0000\u0000\u03aa\u03ab"+ - "\u0003t3\u0000\u03ab\u03ac\u0001\u0000\u0000\u0000\u03ac\u03ad\u0006c"+ - "\u0014\u0000\u03ad\u00d5\u0001\u0000\u0000\u0000\u03ae\u03af\u0003p1\u0000"+ - "\u03af\u03b0\u0001\u0000\u0000\u0000\u03b0\u03b1\u0006d\u0010\u0000\u03b1"+ - "\u00d7\u0001\u0000\u0000\u0000\u03b2\u03b7\u0003N \u0000\u03b3\u03b7\u0003"+ - "L\u001f\u0000\u03b4\u03b7\u0003\\\'\u0000\u03b5\u03b7\u0003\u00a6L\u0000"+ - "\u03b6\u03b2\u0001\u0000\u0000\u0000\u03b6\u03b3\u0001\u0000\u0000\u0000"+ - "\u03b6\u03b4\u0001\u0000\u0000\u0000\u03b6\u03b5\u0001\u0000\u0000\u0000"+ - "\u03b7\u00d9\u0001\u0000\u0000\u0000\u03b8\u03bb\u0003N \u0000\u03b9\u03bb"+ - "\u0003\u00a6L\u0000\u03ba\u03b8\u0001\u0000\u0000\u0000\u03ba\u03b9\u0001"+ - "\u0000\u0000\u0000\u03bb\u03bf\u0001\u0000\u0000\u0000\u03bc\u03be\u0003"+ - "\u00d8e\u0000\u03bd\u03bc\u0001\u0000\u0000\u0000\u03be\u03c1\u0001\u0000"+ - "\u0000\u0000\u03bf\u03bd\u0001\u0000\u0000\u0000\u03bf\u03c0\u0001\u0000"+ - "\u0000\u0000\u03c0\u03cc\u0001\u0000\u0000\u0000\u03c1\u03bf\u0001\u0000"+ - "\u0000\u0000\u03c2\u03c5\u0003\\\'\u0000\u03c3\u03c5\u0003V$\u0000\u03c4"+ - "\u03c2\u0001\u0000\u0000\u0000\u03c4\u03c3\u0001\u0000\u0000\u0000\u03c5"+ - "\u03c7\u0001\u0000\u0000\u0000\u03c6\u03c8\u0003\u00d8e\u0000\u03c7\u03c6"+ - "\u0001\u0000\u0000\u0000\u03c8\u03c9\u0001\u0000\u0000\u0000\u03c9\u03c7"+ - "\u0001\u0000\u0000\u0000\u03c9\u03ca\u0001\u0000\u0000\u0000\u03ca\u03cc"+ - "\u0001\u0000\u0000\u0000\u03cb\u03ba\u0001\u0000\u0000\u0000\u03cb\u03c4"+ - "\u0001\u0000\u0000\u0000\u03cc\u00db\u0001\u0000\u0000\u0000\u03cd\u03d0"+ - "\u0003\u00daf\u0000\u03ce\u03d0\u0003\u00b2R\u0000\u03cf\u03cd\u0001\u0000"+ - "\u0000\u0000\u03cf\u03ce\u0001\u0000\u0000\u0000\u03d0\u03d1\u0001\u0000"+ - "\u0000\u0000\u03d1\u03cf\u0001\u0000\u0000\u0000\u03d1\u03d2\u0001\u0000"+ - "\u0000\u0000\u03d2\u00dd\u0001\u0000\u0000\u0000\u03d3\u03d4\u00036\u0014"+ - "\u0000\u03d4\u03d5\u0001\u0000\u0000\u0000\u03d5\u03d6\u0006h\n\u0000"+ - "\u03d6\u00df\u0001\u0000\u0000\u0000\u03d7\u03d8\u00038\u0015\u0000\u03d8"+ - "\u03d9\u0001\u0000\u0000\u0000\u03d9\u03da\u0006i\n\u0000\u03da\u00e1"+ - "\u0001\u0000\u0000\u0000\u03db\u03dc\u0003:\u0016\u0000\u03dc\u03dd\u0001"+ - "\u0000\u0000\u0000\u03dd\u03de\u0006j\n\u0000\u03de\u00e3\u0001\u0000"+ - "\u0000\u0000\u03df\u03e0\u0003J\u001e\u0000\u03e0\u03e1\u0001\u0000\u0000"+ - "\u0000\u03e1\u03e2\u0006k\r\u0000\u03e2\u03e3\u0006k\u000e\u0000\u03e3"+ - "\u00e5\u0001\u0000\u0000\u0000\u03e4\u03e5\u0003l/\u0000\u03e5\u03e6\u0001"+ - "\u0000\u0000\u0000\u03e6\u03e7\u0006l\u0011\u0000\u03e7\u00e7\u0001\u0000"+ - "\u0000\u0000\u03e8\u03e9\u0003p1\u0000\u03e9\u03ea\u0001\u0000\u0000\u0000"+ - "\u03ea\u03eb\u0006m\u0010\u0000\u03eb\u00e9\u0001\u0000\u0000\u0000\u03ec"+ - "\u03ed\u0003t3\u0000\u03ed\u03ee\u0001\u0000\u0000\u0000\u03ee\u03ef\u0006"+ - "n\u0014\u0000\u03ef\u00eb\u0001\u0000\u0000\u0000\u03f0\u03f1\u0005a\u0000"+ - "\u0000\u03f1\u03f2\u0005s\u0000\u0000\u03f2\u00ed\u0001\u0000\u0000\u0000"+ - "\u03f3\u03f4\u0003\u00dcg\u0000\u03f4\u03f5\u0001\u0000\u0000\u0000\u03f5"+ - "\u03f6\u0006p\u0015\u0000\u03f6\u00ef\u0001\u0000\u0000\u0000\u03f7\u03f8"+ - "\u00036\u0014\u0000\u03f8\u03f9\u0001\u0000\u0000\u0000\u03f9\u03fa\u0006"+ - "q\n\u0000\u03fa\u00f1\u0001\u0000\u0000\u0000\u03fb\u03fc\u00038\u0015"+ - "\u0000\u03fc\u03fd\u0001\u0000\u0000\u0000\u03fd\u03fe\u0006r\n\u0000"+ - "\u03fe\u00f3\u0001\u0000\u0000\u0000\u03ff\u0400\u0003:\u0016\u0000\u0400"+ - "\u0401\u0001\u0000\u0000\u0000\u0401\u0402\u0006s\n\u0000\u0402\u00f5"+ - "\u0001\u0000\u0000\u0000\u0403\u0404\u0003J\u001e\u0000\u0404\u0405\u0001"+ - "\u0000\u0000\u0000\u0405\u0406\u0006t\r\u0000\u0406\u0407\u0006t\u000e"+ - "\u0000\u0407\u00f7\u0001\u0000\u0000\u0000\u0408\u0409\u0003\u00acO\u0000"+ - "\u0409\u040a\u0001\u0000\u0000\u0000\u040a\u040b\u0006u\u000b\u0000\u040b"+ - "\u040c\u0006u\u0016\u0000\u040c\u00f9\u0001\u0000\u0000\u0000\u040d\u040e"+ - "\u0005o\u0000\u0000\u040e\u040f\u0005n\u0000\u0000\u040f\u0410\u0001\u0000"+ - "\u0000\u0000\u0410\u0411\u0006v\u0017\u0000\u0411\u00fb\u0001\u0000\u0000"+ - "\u0000\u0412\u0413\u0005w\u0000\u0000\u0413\u0414\u0005i\u0000\u0000\u0414"+ - "\u0415\u0005t\u0000\u0000\u0415\u0416\u0005h\u0000\u0000\u0416\u0417\u0001"+ - "\u0000\u0000\u0000\u0417\u0418\u0006w\u0017\u0000\u0418\u00fd\u0001\u0000"+ - "\u0000\u0000\u0419\u041a\b\f\u0000\u0000\u041a\u00ff\u0001\u0000\u0000"+ - "\u0000\u041b\u041d\u0003\u00fex\u0000\u041c\u041b\u0001\u0000\u0000\u0000"+ - "\u041d\u041e\u0001\u0000\u0000\u0000\u041e\u041c\u0001\u0000\u0000\u0000"+ - "\u041e\u041f\u0001\u0000\u0000\u0000\u041f\u0420\u0001\u0000\u0000\u0000"+ - "\u0420\u0421\u0003\u0144\u009b\u0000\u0421\u0423\u0001\u0000\u0000\u0000"+ - "\u0422\u041c\u0001\u0000\u0000\u0000\u0422\u0423\u0001\u0000\u0000\u0000"+ - "\u0423\u0425\u0001\u0000\u0000\u0000\u0424\u0426\u0003\u00fex\u0000\u0425"+ - "\u0424\u0001\u0000\u0000\u0000\u0426\u0427\u0001\u0000\u0000\u0000\u0427"+ - "\u0425\u0001\u0000\u0000\u0000\u0427\u0428\u0001\u0000\u0000\u0000\u0428"+ - "\u0101\u0001\u0000\u0000\u0000\u0429\u042a\u0003\u00b4S\u0000\u042a\u042b"+ - "\u0001\u0000\u0000\u0000\u042b\u042c\u0006z\u0018\u0000\u042c\u0103\u0001"+ - "\u0000\u0000\u0000\u042d\u042e\u0003\u0100y\u0000\u042e\u042f\u0001\u0000"+ - "\u0000\u0000\u042f\u0430\u0006{\u0019\u0000\u0430\u0105\u0001\u0000\u0000"+ - "\u0000\u0431\u0432\u00036\u0014\u0000\u0432\u0433\u0001\u0000\u0000\u0000"+ - "\u0433\u0434\u0006|\n\u0000\u0434\u0107\u0001\u0000\u0000\u0000\u0435"+ - "\u0436\u00038\u0015\u0000\u0436\u0437\u0001\u0000\u0000\u0000\u0437\u0438"+ - "\u0006}\n\u0000\u0438\u0109\u0001\u0000\u0000\u0000\u0439\u043a\u0003"+ - ":\u0016\u0000\u043a\u043b\u0001\u0000\u0000\u0000\u043b\u043c\u0006~\n"+ - "\u0000\u043c\u010b\u0001\u0000\u0000\u0000\u043d\u043e\u0003J\u001e\u0000"+ - "\u043e\u043f\u0001\u0000\u0000\u0000\u043f\u0440\u0006\u007f\r\u0000\u0440"+ - "\u0441\u0006\u007f\u000e\u0000\u0441\u0442\u0006\u007f\u000e\u0000\u0442"+ - "\u010d\u0001\u0000\u0000\u0000\u0443\u0444\u0003l/\u0000\u0444\u0445\u0001"+ - "\u0000\u0000\u0000\u0445\u0446\u0006\u0080\u0011\u0000\u0446\u010f\u0001"+ - "\u0000\u0000\u0000\u0447\u0448\u0003p1\u0000\u0448\u0449\u0001\u0000\u0000"+ - "\u0000\u0449\u044a\u0006\u0081\u0010\u0000\u044a\u0111\u0001\u0000\u0000"+ - "\u0000\u044b\u044c\u0003t3\u0000\u044c\u044d\u0001\u0000\u0000\u0000\u044d"+ - "\u044e\u0006\u0082\u0014\u0000\u044e\u0113\u0001\u0000\u0000\u0000\u044f"+ - "\u0450\u0003\u00fcw\u0000\u0450\u0451\u0001\u0000\u0000\u0000\u0451\u0452"+ - "\u0006\u0083\u001a\u0000\u0452\u0115\u0001\u0000\u0000\u0000\u0453\u0454"+ - "\u0003\u00dcg\u0000\u0454\u0455\u0001\u0000\u0000\u0000\u0455\u0456\u0006"+ - "\u0084\u0015\u0000\u0456\u0117\u0001\u0000\u0000\u0000\u0457\u0458\u0003"+ - "\u00b4S\u0000\u0458\u0459\u0001\u0000\u0000\u0000\u0459\u045a\u0006\u0085"+ - "\u0018\u0000\u045a\u0119\u0001\u0000\u0000\u0000\u045b\u045c\u00036\u0014"+ - "\u0000\u045c\u045d\u0001\u0000\u0000\u0000\u045d\u045e\u0006\u0086\n\u0000"+ - "\u045e\u011b\u0001\u0000\u0000\u0000\u045f\u0460\u00038\u0015\u0000\u0460"+ - "\u0461\u0001\u0000\u0000\u0000\u0461\u0462\u0006\u0087\n\u0000\u0462\u011d"+ - "\u0001\u0000\u0000\u0000\u0463\u0464\u0003:\u0016\u0000\u0464\u0465\u0001"+ - "\u0000\u0000\u0000\u0465\u0466\u0006\u0088\n\u0000\u0466\u011f\u0001\u0000"+ - "\u0000\u0000\u0467\u0468\u0003J\u001e\u0000\u0468\u0469\u0001\u0000\u0000"+ - "\u0000\u0469\u046a\u0006\u0089\r\u0000\u046a\u046b\u0006\u0089\u000e\u0000"+ - "\u046b\u0121\u0001\u0000\u0000\u0000\u046c\u046d\u0003t3\u0000\u046d\u046e"+ - "\u0001\u0000\u0000\u0000\u046e\u046f\u0006\u008a\u0014\u0000\u046f\u0123"+ - "\u0001\u0000\u0000\u0000\u0470\u0471\u0003\u00b4S\u0000\u0471\u0472\u0001"+ - "\u0000\u0000\u0000\u0472\u0473\u0006\u008b\u0018\u0000\u0473\u0125\u0001"+ - "\u0000\u0000\u0000\u0474\u0475\u0003\u00b0Q\u0000\u0475\u0476\u0001\u0000"+ - "\u0000\u0000\u0476\u0477\u0006\u008c\u001b\u0000\u0477\u0127\u0001\u0000"+ - "\u0000\u0000\u0478\u0479\u00036\u0014\u0000\u0479\u047a\u0001\u0000\u0000"+ - "\u0000\u047a\u047b\u0006\u008d\n\u0000\u047b\u0129\u0001\u0000\u0000\u0000"+ - "\u047c\u047d\u00038\u0015\u0000\u047d\u047e\u0001\u0000\u0000\u0000\u047e"+ - "\u047f\u0006\u008e\n\u0000\u047f\u012b\u0001\u0000\u0000\u0000\u0480\u0481"+ - "\u0003:\u0016\u0000\u0481\u0482\u0001\u0000\u0000\u0000\u0482\u0483\u0006"+ - "\u008f\n\u0000\u0483\u012d\u0001\u0000\u0000\u0000\u0484\u0485\u0003J"+ - "\u001e\u0000\u0485\u0486\u0001\u0000\u0000\u0000\u0486\u0487\u0006\u0090"+ - "\r\u0000\u0487\u0488\u0006\u0090\u000e\u0000\u0488\u012f\u0001\u0000\u0000"+ - "\u0000\u0489\u048a\u0005i\u0000\u0000\u048a\u048b\u0005n\u0000\u0000\u048b"+ - "\u048c\u0005f\u0000\u0000\u048c\u048d\u0005o\u0000\u0000\u048d\u0131\u0001"+ - "\u0000\u0000\u0000\u048e\u048f\u00036\u0014\u0000\u048f\u0490\u0001\u0000"+ - "\u0000\u0000\u0490\u0491\u0006\u0092\n\u0000\u0491\u0133\u0001\u0000\u0000"+ - "\u0000\u0492\u0493\u00038\u0015\u0000\u0493\u0494\u0001\u0000\u0000\u0000"+ - "\u0494\u0495\u0006\u0093\n\u0000\u0495\u0135\u0001\u0000\u0000\u0000\u0496"+ - "\u0497\u0003:\u0016\u0000\u0497\u0498\u0001\u0000\u0000\u0000\u0498\u0499"+ - "\u0006\u0094\n\u0000\u0499\u0137\u0001\u0000\u0000\u0000\u049a\u049b\u0003"+ - "J\u001e\u0000\u049b\u049c\u0001\u0000\u0000\u0000\u049c\u049d\u0006\u0095"+ - "\r\u0000\u049d\u049e\u0006\u0095\u000e\u0000\u049e\u0139\u0001\u0000\u0000"+ - "\u0000\u049f\u04a0\u0005f\u0000\u0000\u04a0\u04a1\u0005u\u0000\u0000\u04a1"+ - "\u04a2\u0005n\u0000\u0000\u04a2\u04a3\u0005c\u0000\u0000\u04a3\u04a4\u0005"+ - "t\u0000\u0000\u04a4\u04a5\u0005i\u0000\u0000\u04a5\u04a6\u0005o\u0000"+ - "\u0000\u04a6\u04a7\u0005n\u0000\u0000\u04a7\u04a8\u0005s\u0000\u0000\u04a8"+ - "\u013b\u0001\u0000\u0000\u0000\u04a9\u04aa\u00036\u0014\u0000\u04aa\u04ab"+ - "\u0001\u0000\u0000\u0000\u04ab\u04ac\u0006\u0097\n\u0000\u04ac\u013d\u0001"+ - "\u0000\u0000\u0000\u04ad\u04ae\u00038\u0015\u0000\u04ae\u04af\u0001\u0000"+ - "\u0000\u0000\u04af\u04b0\u0006\u0098\n\u0000\u04b0\u013f\u0001\u0000\u0000"+ - "\u0000\u04b1\u04b2\u0003:\u0016\u0000\u04b2\u04b3\u0001\u0000\u0000\u0000"+ - "\u04b3\u04b4\u0006\u0099\n\u0000\u04b4\u0141\u0001\u0000\u0000\u0000\u04b5"+ - "\u04b6\u0003\u00aeP\u0000\u04b6\u04b7\u0001\u0000\u0000\u0000\u04b7\u04b8"+ - "\u0006\u009a\u000f\u0000\u04b8\u04b9\u0006\u009a\u000e\u0000\u04b9\u0143"+ - "\u0001\u0000\u0000\u0000\u04ba\u04bb\u0005:\u0000\u0000\u04bb\u0145\u0001"+ - "\u0000\u0000\u0000\u04bc\u04c2\u0003V$\u0000\u04bd\u04c2\u0003L\u001f"+ - "\u0000\u04be\u04c2\u0003t3\u0000\u04bf\u04c2\u0003N \u0000\u04c0\u04c2"+ - "\u0003\\\'\u0000\u04c1\u04bc\u0001\u0000\u0000\u0000\u04c1\u04bd\u0001"+ - "\u0000\u0000\u0000\u04c1\u04be\u0001\u0000\u0000\u0000\u04c1\u04bf\u0001"+ - "\u0000\u0000\u0000\u04c1\u04c0\u0001\u0000\u0000\u0000\u04c2\u04c3\u0001"+ - "\u0000\u0000\u0000\u04c3\u04c1\u0001\u0000\u0000\u0000\u04c3\u04c4\u0001"+ - "\u0000\u0000\u0000\u04c4\u0147\u0001\u0000\u0000\u0000\u04c5\u04c6\u0003"+ - "6\u0014\u0000\u04c6\u04c7\u0001\u0000\u0000\u0000\u04c7\u04c8\u0006\u009d"+ - "\n\u0000\u04c8\u0149\u0001\u0000\u0000\u0000\u04c9\u04ca\u00038\u0015"+ - "\u0000\u04ca\u04cb\u0001\u0000\u0000\u0000\u04cb\u04cc\u0006\u009e\n\u0000"+ - "\u04cc\u014b\u0001\u0000\u0000\u0000\u04cd\u04ce\u0003:\u0016\u0000\u04ce"+ - "\u04cf\u0001\u0000\u0000\u0000\u04cf\u04d0\u0006\u009f\n\u0000\u04d0\u014d"+ - "\u0001\u0000\u0000\u0000\u04d1\u04d2\u0003J\u001e\u0000\u04d2\u04d3\u0001"+ - "\u0000\u0000\u0000\u04d3\u04d4\u0006\u00a0\r\u0000\u04d4\u04d5\u0006\u00a0"+ - "\u000e\u0000\u04d5\u014f\u0001\u0000\u0000\u0000\u04d6\u04d7\u0003>\u0018"+ - "\u0000\u04d7\u04d8\u0001\u0000\u0000\u0000\u04d8\u04d9\u0006\u00a1\u0013"+ - "\u0000\u04d9\u04da\u0006\u00a1\u000e\u0000\u04da\u04db\u0006\u00a1\u001c"+ - "\u0000\u04db\u0151\u0001\u0000\u0000\u0000\u04dc\u04dd\u00036\u0014\u0000"+ - "\u04dd\u04de\u0001\u0000\u0000\u0000\u04de\u04df\u0006\u00a2\n\u0000\u04df"+ - "\u0153\u0001\u0000\u0000\u0000\u04e0\u04e1\u00038\u0015\u0000\u04e1\u04e2"+ - "\u0001\u0000\u0000\u0000\u04e2\u04e3\u0006\u00a3\n\u0000\u04e3\u0155\u0001"+ - "\u0000\u0000\u0000\u04e4\u04e5\u0003:\u0016\u0000\u04e5\u04e6\u0001\u0000"+ - "\u0000\u0000\u04e6\u04e7\u0006\u00a4\n\u0000\u04e7\u0157\u0001\u0000\u0000"+ - "\u0000\u04e8\u04e9\u0003p1\u0000\u04e9\u04ea\u0001\u0000\u0000\u0000\u04ea"+ - "\u04eb\u0006\u00a5\u0010\u0000\u04eb\u04ec\u0006\u00a5\u000e\u0000\u04ec"+ - "\u04ed\u0006\u00a5\u0006\u0000\u04ed\u0159\u0001\u0000\u0000\u0000\u04ee"+ - "\u04ef\u00036\u0014\u0000\u04ef\u04f0\u0001\u0000\u0000\u0000\u04f0\u04f1"+ - "\u0006\u00a6\n\u0000\u04f1\u015b\u0001\u0000\u0000\u0000\u04f2\u04f3\u0003"+ - "8\u0015\u0000\u04f3\u04f4\u0001\u0000\u0000\u0000\u04f4\u04f5\u0006\u00a7"+ - "\n\u0000\u04f5\u015d\u0001\u0000\u0000\u0000\u04f6\u04f7\u0003:\u0016"+ - "\u0000\u04f7\u04f8\u0001\u0000\u0000\u0000\u04f8\u04f9\u0006\u00a8\n\u0000"+ - "\u04f9\u015f\u0001\u0000\u0000\u0000\u04fa\u04fb\u0003\u00b4S\u0000\u04fb"+ - "\u04fc\u0001\u0000\u0000\u0000\u04fc\u04fd\u0006\u00a9\u000e\u0000\u04fd"+ - "\u04fe\u0006\u00a9\u0000\u0000\u04fe\u04ff\u0006\u00a9\u0018\u0000\u04ff"+ - "\u0161\u0001\u0000\u0000\u0000\u0500\u0501\u0003\u00b0Q\u0000\u0501\u0502"+ - "\u0001\u0000\u0000\u0000\u0502\u0503\u0006\u00aa\u000e\u0000\u0503\u0504"+ - "\u0006\u00aa\u0000\u0000\u0504\u0505\u0006\u00aa\u001b\u0000\u0505\u0163"+ - "\u0001\u0000\u0000\u0000\u0506\u0507\u0003f,\u0000\u0507\u0508\u0001\u0000"+ - "\u0000\u0000\u0508\u0509\u0006\u00ab\u000e\u0000\u0509\u050a\u0006\u00ab"+ - "\u0000\u0000\u050a\u050b\u0006\u00ab\u001d\u0000\u050b\u0165\u0001\u0000"+ - "\u0000\u0000\u050c\u050d\u0003J\u001e\u0000\u050d\u050e\u0001\u0000\u0000"+ - "\u0000\u050e\u050f\u0006\u00ac\r\u0000\u050f\u0510\u0006\u00ac\u000e\u0000"+ - "\u0510\u0167\u0001\u0000\u0000\u0000<\u0000\u0001\u0002\u0003\u0004\u0005"+ - "\u0006\u0007\b\t\n\u000b\f\r\u020b\u0215\u0219\u021c\u0225\u0227\u0232"+ - "\u0239\u023e\u0265\u026a\u0273\u027a\u027f\u0281\u028c\u0294\u0297\u0299"+ - "\u029e\u02a3\u02a9\u02b0\u02b5\u02bb\u02be\u02c6\u02ca\u034f\u0354\u0359"+ - "\u035b\u0361\u03b6\u03ba\u03bf\u03c4\u03c9\u03cb\u03cf\u03d1\u041e\u0422"+ - "\u0427\u04c1\u04c3\u001e\u0005\u0002\u0000\u0005\u0004\u0000\u0005\u0006"+ - "\u0000\u0005\u0001\u0000\u0005\u0003\u0000\u0005\n\u0000\u0005\f\u0000"+ - "\u0005\b\u0000\u0005\u0005\u0000\u0005\t\u0000\u0000\u0001\u0000\u0007"+ - "C\u0000\u0005\u0000\u0000\u0007\u001c\u0000\u0004\u0000\u0000\u0007D\u0000"+ - "\u0007%\u0000\u0007#\u0000\u0007\u001d\u0000\u0007\u0018\u0000\u0007\'"+ - "\u0000\u0007N\u0000\u0005\u000b\u0000\u0005\u0007\u0000\u0007F\u0000\u0007"+ - "X\u0000\u0007W\u0000\u0007E\u0000\u0005\r\u0000\u0007 \u0000"; + "\r\u0168\u0001\u0000\u0000\u0000\r\u016a\u0001\u0000\u0000\u0000\r\u016c"+ + "\u0001\u0000\u0000\u0000\r\u016e\u0001\u0000\u0000\u0000\u000e\u0170\u0001"+ + "\u0000\u0000\u0000\u000e\u0172\u0001\u0000\u0000\u0000\u000e\u0174\u0001"+ + "\u0000\u0000\u0000\u000e\u0176\u0001\u0000\u0000\u0000\u000e\u0178\u0001"+ + "\u0000\u0000\u0000\u000f\u017a\u0001\u0000\u0000\u0000\u000f\u017c\u0001"+ + "\u0000\u0000\u0000\u000f\u017e\u0001\u0000\u0000\u0000\u000f\u0180\u0001"+ + "\u0000\u0000\u0000\u000f\u0182\u0001\u0000\u0000\u0000\u000f\u0184\u0001"+ + "\u0000\u0000\u0000\u000f\u0186\u0001\u0000\u0000\u0000\u000f\u0188\u0001"+ + "\u0000\u0000\u0000\u0010\u018a\u0001\u0000\u0000\u0000\u0012\u0194\u0001"+ + "\u0000\u0000\u0000\u0014\u019b\u0001\u0000\u0000\u0000\u0016\u01a4\u0001"+ + "\u0000\u0000\u0000\u0018\u01ab\u0001\u0000\u0000\u0000\u001a\u01b5\u0001"+ + "\u0000\u0000\u0000\u001c\u01bc\u0001\u0000\u0000\u0000\u001e\u01c3\u0001"+ + "\u0000\u0000\u0000 \u01d1\u0001\u0000\u0000\u0000\"\u01d8\u0001\u0000"+ + "\u0000\u0000$\u01e0\u0001\u0000\u0000\u0000&\u01e9\u0001\u0000\u0000\u0000"+ + "(\u01f0\u0001\u0000\u0000\u0000*\u01fa\u0001\u0000\u0000\u0000,\u0206"+ + "\u0001\u0000\u0000\u0000.\u020f\u0001\u0000\u0000\u00000\u0215\u0001\u0000"+ + "\u0000\u00002\u021c\u0001\u0000\u0000\u00004\u0223\u0001\u0000\u0000\u0000"+ + "6\u022b\u0001\u0000\u0000\u00008\u0234\u0001\u0000\u0000\u0000:\u023a"+ + "\u0001\u0000\u0000\u0000<\u024b\u0001\u0000\u0000\u0000>\u025b\u0001\u0000"+ + "\u0000\u0000@\u0264\u0001\u0000\u0000\u0000B\u0267\u0001\u0000\u0000\u0000"+ + "D\u026b\u0001\u0000\u0000\u0000F\u0270\u0001\u0000\u0000\u0000H\u0275"+ + "\u0001\u0000\u0000\u0000J\u0279\u0001\u0000\u0000\u0000L\u027d\u0001\u0000"+ + "\u0000\u0000N\u0281\u0001\u0000\u0000\u0000P\u0285\u0001\u0000\u0000\u0000"+ + "R\u0287\u0001\u0000\u0000\u0000T\u0289\u0001\u0000\u0000\u0000V\u028c"+ + "\u0001\u0000\u0000\u0000X\u028e\u0001\u0000\u0000\u0000Z\u0297\u0001\u0000"+ + "\u0000\u0000\\\u0299\u0001\u0000\u0000\u0000^\u029e\u0001\u0000\u0000"+ + "\u0000`\u02a0\u0001\u0000\u0000\u0000b\u02a5\u0001\u0000\u0000\u0000d"+ + "\u02c4\u0001\u0000\u0000\u0000f\u02c7\u0001\u0000\u0000\u0000h\u02f5\u0001"+ + "\u0000\u0000\u0000j\u02f7\u0001\u0000\u0000\u0000l\u02fa\u0001\u0000\u0000"+ + "\u0000n\u02fe\u0001\u0000\u0000\u0000p\u0302\u0001\u0000\u0000\u0000r"+ + "\u0304\u0001\u0000\u0000\u0000t\u0307\u0001\u0000\u0000\u0000v\u0309\u0001"+ + "\u0000\u0000\u0000x\u030e\u0001\u0000\u0000\u0000z\u0310\u0001\u0000\u0000"+ + "\u0000|\u0316\u0001\u0000\u0000\u0000~\u031c\u0001\u0000\u0000\u0000\u0080"+ + "\u0321\u0001\u0000\u0000\u0000\u0082\u0323\u0001\u0000\u0000\u0000\u0084"+ + "\u0326\u0001\u0000\u0000\u0000\u0086\u0329\u0001\u0000\u0000\u0000\u0088"+ + "\u032e\u0001\u0000\u0000\u0000\u008a\u0332\u0001\u0000\u0000\u0000\u008c"+ + "\u0337\u0001\u0000\u0000\u0000\u008e\u033d\u0001\u0000\u0000\u0000\u0090"+ + "\u0340\u0001\u0000\u0000\u0000\u0092\u0342\u0001\u0000\u0000\u0000\u0094"+ + "\u0348\u0001\u0000\u0000\u0000\u0096\u034a\u0001\u0000\u0000\u0000\u0098"+ + "\u034f\u0001\u0000\u0000\u0000\u009a\u0352\u0001\u0000\u0000\u0000\u009c"+ + "\u0355\u0001\u0000\u0000\u0000\u009e\u0358\u0001\u0000\u0000\u0000\u00a0"+ + "\u035a\u0001\u0000\u0000\u0000\u00a2\u035d\u0001\u0000\u0000\u0000\u00a4"+ + "\u035f\u0001\u0000\u0000\u0000\u00a6\u0362\u0001\u0000\u0000\u0000\u00a8"+ + "\u0364\u0001\u0000\u0000\u0000\u00aa\u0366\u0001\u0000\u0000\u0000\u00ac"+ + "\u0368\u0001\u0000\u0000\u0000\u00ae\u036a\u0001\u0000\u0000\u0000\u00b0"+ + "\u036c\u0001\u0000\u0000\u0000\u00b2\u0371\u0001\u0000\u0000\u0000\u00b4"+ + "\u0386\u0001\u0000\u0000\u0000\u00b6\u0388\u0001\u0000\u0000\u0000\u00b8"+ + "\u0390\u0001\u0000\u0000\u0000\u00ba\u0392\u0001\u0000\u0000\u0000\u00bc"+ + "\u0396\u0001\u0000\u0000\u0000\u00be\u039a\u0001\u0000\u0000\u0000\u00c0"+ + "\u039e\u0001\u0000\u0000\u0000\u00c2\u03a3\u0001\u0000\u0000\u0000\u00c4"+ + "\u03a7\u0001\u0000\u0000\u0000\u00c6\u03ab\u0001\u0000\u0000\u0000\u00c8"+ + "\u03af\u0001\u0000\u0000\u0000\u00ca\u03b3\u0001\u0000\u0000\u0000\u00cc"+ + "\u03b7\u0001\u0000\u0000\u0000\u00ce\u03c0\u0001\u0000\u0000\u0000\u00d0"+ + "\u03c4\u0001\u0000\u0000\u0000\u00d2\u03c8\u0001\u0000\u0000\u0000\u00d4"+ + "\u03cc\u0001\u0000\u0000\u0000\u00d6\u03d0\u0001\u0000\u0000\u0000\u00d8"+ + "\u03d5\u0001\u0000\u0000\u0000\u00da\u03d9\u0001\u0000\u0000\u0000\u00dc"+ + "\u03e1\u0001\u0000\u0000\u0000\u00de\u03f6\u0001\u0000\u0000\u0000\u00e0"+ + "\u03fa\u0001\u0000\u0000\u0000\u00e2\u03fe\u0001\u0000\u0000\u0000\u00e4"+ + "\u0402\u0001\u0000\u0000\u0000\u00e6\u0406\u0001\u0000\u0000\u0000\u00e8"+ + "\u040a\u0001\u0000\u0000\u0000\u00ea\u040f\u0001\u0000\u0000\u0000\u00ec"+ + "\u0413\u0001\u0000\u0000\u0000\u00ee\u0417\u0001\u0000\u0000\u0000\u00f0"+ + "\u041b\u0001\u0000\u0000\u0000\u00f2\u041e\u0001\u0000\u0000\u0000\u00f4"+ + "\u0422\u0001\u0000\u0000\u0000\u00f6\u0426\u0001\u0000\u0000\u0000\u00f8"+ + "\u042a\u0001\u0000\u0000\u0000\u00fa\u042e\u0001\u0000\u0000\u0000\u00fc"+ + "\u0433\u0001\u0000\u0000\u0000\u00fe\u0438\u0001\u0000\u0000\u0000\u0100"+ + "\u043d\u0001\u0000\u0000\u0000\u0102\u0444\u0001\u0000\u0000\u0000\u0104"+ + "\u044d\u0001\u0000\u0000\u0000\u0106\u0454\u0001\u0000\u0000\u0000\u0108"+ + "\u0458\u0001\u0000\u0000\u0000\u010a\u045c\u0001\u0000\u0000\u0000\u010c"+ + "\u0460\u0001\u0000\u0000\u0000\u010e\u0464\u0001\u0000\u0000\u0000\u0110"+ + "\u0468\u0001\u0000\u0000\u0000\u0112\u046e\u0001\u0000\u0000\u0000\u0114"+ + "\u0472\u0001\u0000\u0000\u0000\u0116\u0476\u0001\u0000\u0000\u0000\u0118"+ + "\u047a\u0001\u0000\u0000\u0000\u011a\u047e\u0001\u0000\u0000\u0000\u011c"+ + "\u0482\u0001\u0000\u0000\u0000\u011e\u0486\u0001\u0000\u0000\u0000\u0120"+ + "\u048a\u0001\u0000\u0000\u0000\u0122\u048e\u0001\u0000\u0000\u0000\u0124"+ + "\u0492\u0001\u0000\u0000\u0000\u0126\u0497\u0001\u0000\u0000\u0000\u0128"+ + "\u049b\u0001\u0000\u0000\u0000\u012a\u049f\u0001\u0000\u0000\u0000\u012c"+ + "\u04a4\u0001\u0000\u0000\u0000\u012e\u04a8\u0001\u0000\u0000\u0000\u0130"+ + "\u04ac\u0001\u0000\u0000\u0000\u0132\u04b0\u0001\u0000\u0000\u0000\u0134"+ + "\u04b4\u0001\u0000\u0000\u0000\u0136\u04ba\u0001\u0000\u0000\u0000\u0138"+ + "\u04be\u0001\u0000\u0000\u0000\u013a\u04c2\u0001\u0000\u0000\u0000\u013c"+ + "\u04c6\u0001\u0000\u0000\u0000\u013e\u04ca\u0001\u0000\u0000\u0000\u0140"+ + "\u04ce\u0001\u0000\u0000\u0000\u0142\u04d2\u0001\u0000\u0000\u0000\u0144"+ + "\u04d7\u0001\u0000\u0000\u0000\u0146\u04db\u0001\u0000\u0000\u0000\u0148"+ + "\u04df\u0001\u0000\u0000\u0000\u014a\u04e3\u0001\u0000\u0000\u0000\u014c"+ + "\u04e7\u0001\u0000\u0000\u0000\u014e\u04eb\u0001\u0000\u0000\u0000\u0150"+ + "\u04ef\u0001\u0000\u0000\u0000\u0152\u04f4\u0001\u0000\u0000\u0000\u0154"+ + "\u04f9\u0001\u0000\u0000\u0000\u0156\u04fd\u0001\u0000\u0000\u0000\u0158"+ + "\u0501\u0001\u0000\u0000\u0000\u015a\u0505\u0001\u0000\u0000\u0000\u015c"+ + "\u050a\u0001\u0000\u0000\u0000\u015e\u0514\u0001\u0000\u0000\u0000\u0160"+ + "\u0518\u0001\u0000\u0000\u0000\u0162\u051c\u0001\u0000\u0000\u0000\u0164"+ + "\u0520\u0001\u0000\u0000\u0000\u0166\u0525\u0001\u0000\u0000\u0000\u0168"+ + "\u052c\u0001\u0000\u0000\u0000\u016a\u0530\u0001\u0000\u0000\u0000\u016c"+ + "\u0534\u0001\u0000\u0000\u0000\u016e\u0538\u0001\u0000\u0000\u0000\u0170"+ + "\u053c\u0001\u0000\u0000\u0000\u0172\u0541\u0001\u0000\u0000\u0000\u0174"+ + "\u0547\u0001\u0000\u0000\u0000\u0176\u054b\u0001\u0000\u0000\u0000\u0178"+ + "\u054f\u0001\u0000\u0000\u0000\u017a\u0553\u0001\u0000\u0000\u0000\u017c"+ + "\u0559\u0001\u0000\u0000\u0000\u017e\u055d\u0001\u0000\u0000\u0000\u0180"+ + "\u0561\u0001\u0000\u0000\u0000\u0182\u0565\u0001\u0000\u0000\u0000\u0184"+ + "\u056b\u0001\u0000\u0000\u0000\u0186\u0571\u0001\u0000\u0000\u0000\u0188"+ + "\u0577\u0001\u0000\u0000\u0000\u018a\u018b\u0005d\u0000\u0000\u018b\u018c"+ + "\u0005i\u0000\u0000\u018c\u018d\u0005s\u0000\u0000\u018d\u018e\u0005s"+ + "\u0000\u0000\u018e\u018f\u0005e\u0000\u0000\u018f\u0190\u0005c\u0000\u0000"+ + "\u0190\u0191\u0005t\u0000\u0000\u0191\u0192\u0001\u0000\u0000\u0000\u0192"+ + "\u0193\u0006\u0000\u0000\u0000\u0193\u0011\u0001\u0000\u0000\u0000\u0194"+ + "\u0195\u0005d\u0000\u0000\u0195\u0196\u0005r\u0000\u0000\u0196\u0197\u0005"+ + "o\u0000\u0000\u0197\u0198\u0005p\u0000\u0000\u0198\u0199\u0001\u0000\u0000"+ + "\u0000\u0199\u019a\u0006\u0001\u0001\u0000\u019a\u0013\u0001\u0000\u0000"+ + "\u0000\u019b\u019c\u0005e\u0000\u0000\u019c\u019d\u0005n\u0000\u0000\u019d"+ + "\u019e\u0005r\u0000\u0000\u019e\u019f\u0005i\u0000\u0000\u019f\u01a0\u0005"+ + "c\u0000\u0000\u01a0\u01a1\u0005h\u0000\u0000\u01a1\u01a2\u0001\u0000\u0000"+ + "\u0000\u01a2\u01a3\u0006\u0002\u0002\u0000\u01a3\u0015\u0001\u0000\u0000"+ + "\u0000\u01a4\u01a5\u0005e\u0000\u0000\u01a5\u01a6\u0005v\u0000\u0000\u01a6"+ + "\u01a7\u0005a\u0000\u0000\u01a7\u01a8\u0005l\u0000\u0000\u01a8\u01a9\u0001"+ + "\u0000\u0000\u0000\u01a9\u01aa\u0006\u0003\u0000\u0000\u01aa\u0017\u0001"+ + "\u0000\u0000\u0000\u01ab\u01ac\u0005e\u0000\u0000\u01ac\u01ad\u0005x\u0000"+ + "\u0000\u01ad\u01ae\u0005p\u0000\u0000\u01ae\u01af\u0005l\u0000\u0000\u01af"+ + "\u01b0\u0005a\u0000\u0000\u01b0\u01b1\u0005i\u0000\u0000\u01b1\u01b2\u0005"+ + "n\u0000\u0000\u01b2\u01b3\u0001\u0000\u0000\u0000\u01b3\u01b4\u0006\u0004"+ + "\u0003\u0000\u01b4\u0019\u0001\u0000\u0000\u0000\u01b5\u01b6\u0005f\u0000"+ + "\u0000\u01b6\u01b7\u0005r\u0000\u0000\u01b7\u01b8\u0005o\u0000\u0000\u01b8"+ + "\u01b9\u0005m\u0000\u0000\u01b9\u01ba\u0001\u0000\u0000\u0000\u01ba\u01bb"+ + "\u0006\u0005\u0004\u0000\u01bb\u001b\u0001\u0000\u0000\u0000\u01bc\u01bd"+ + "\u0005g\u0000\u0000\u01bd\u01be\u0005r\u0000\u0000\u01be\u01bf\u0005o"+ + "\u0000\u0000\u01bf\u01c0\u0005k\u0000\u0000\u01c0\u01c1\u0001\u0000\u0000"+ + "\u0000\u01c1\u01c2\u0006\u0006\u0000\u0000\u01c2\u001d\u0001\u0000\u0000"+ + "\u0000\u01c3\u01c4\u0005i\u0000\u0000\u01c4\u01c5\u0005n\u0000\u0000\u01c5"+ + "\u01c6\u0005l\u0000\u0000\u01c6\u01c7\u0005i\u0000\u0000\u01c7\u01c8\u0005"+ + "n\u0000\u0000\u01c8\u01c9\u0005e\u0000\u0000\u01c9\u01ca\u0005s\u0000"+ + "\u0000\u01ca\u01cb\u0005t\u0000\u0000\u01cb\u01cc\u0005a\u0000\u0000\u01cc"+ + "\u01cd\u0005t\u0000\u0000\u01cd\u01ce\u0005s\u0000\u0000\u01ce\u01cf\u0001"+ + "\u0000\u0000\u0000\u01cf\u01d0\u0006\u0007\u0000\u0000\u01d0\u001f\u0001"+ + "\u0000\u0000\u0000\u01d1\u01d2\u0005k\u0000\u0000\u01d2\u01d3\u0005e\u0000"+ + "\u0000\u01d3\u01d4\u0005e\u0000\u0000\u01d4\u01d5\u0005p\u0000\u0000\u01d5"+ + "\u01d6\u0001\u0000\u0000\u0000\u01d6\u01d7\u0006\b\u0001\u0000\u01d7!"+ + "\u0001\u0000\u0000\u0000\u01d8\u01d9\u0005l\u0000\u0000\u01d9\u01da\u0005"+ + "i\u0000\u0000\u01da\u01db\u0005m\u0000\u0000\u01db\u01dc\u0005i\u0000"+ + "\u0000\u01dc\u01dd\u0005t\u0000\u0000\u01dd\u01de\u0001\u0000\u0000\u0000"+ + "\u01de\u01df\u0006\t\u0000\u0000\u01df#\u0001\u0000\u0000\u0000\u01e0"+ + "\u01e1\u0005l\u0000\u0000\u01e1\u01e2\u0005o\u0000\u0000\u01e2\u01e3\u0005"+ + "o\u0000\u0000\u01e3\u01e4\u0005k\u0000\u0000\u01e4\u01e5\u0005u\u0000"+ + "\u0000\u01e5\u01e6\u0005p\u0000\u0000\u01e6\u01e7\u0001\u0000\u0000\u0000"+ + "\u01e7\u01e8\u0006\n\u0005\u0000\u01e8%\u0001\u0000\u0000\u0000\u01e9"+ + "\u01ea\u0005m\u0000\u0000\u01ea\u01eb\u0005e\u0000\u0000\u01eb\u01ec\u0005"+ + "t\u0000\u0000\u01ec\u01ed\u0005a\u0000\u0000\u01ed\u01ee\u0001\u0000\u0000"+ + "\u0000\u01ee\u01ef\u0006\u000b\u0006\u0000\u01ef\'\u0001\u0000\u0000\u0000"+ + "\u01f0\u01f1\u0005m\u0000\u0000\u01f1\u01f2\u0005e\u0000\u0000\u01f2\u01f3"+ + "\u0005t\u0000\u0000\u01f3\u01f4\u0005r\u0000\u0000\u01f4\u01f5\u0005i"+ + "\u0000\u0000\u01f5\u01f6\u0005c\u0000\u0000\u01f6\u01f7\u0005s\u0000\u0000"+ + "\u01f7\u01f8\u0001\u0000\u0000\u0000\u01f8\u01f9\u0006\f\u0007\u0000\u01f9"+ + ")\u0001\u0000\u0000\u0000\u01fa\u01fb\u0005m\u0000\u0000\u01fb\u01fc\u0005"+ + "v\u0000\u0000\u01fc\u01fd\u0005_\u0000\u0000\u01fd\u01fe\u0005e\u0000"+ + "\u0000\u01fe\u01ff\u0005x\u0000\u0000\u01ff\u0200\u0005p\u0000\u0000\u0200"+ + "\u0201\u0005a\u0000\u0000\u0201\u0202\u0005n\u0000\u0000\u0202\u0203\u0005"+ + "d\u0000\u0000\u0203\u0204\u0001\u0000\u0000\u0000\u0204\u0205\u0006\r"+ + "\b\u0000\u0205+\u0001\u0000\u0000\u0000\u0206\u0207\u0005r\u0000\u0000"+ + "\u0207\u0208\u0005e\u0000\u0000\u0208\u0209\u0005n\u0000\u0000\u0209\u020a"+ + "\u0005a\u0000\u0000\u020a\u020b\u0005m\u0000\u0000\u020b\u020c\u0005e"+ + "\u0000\u0000\u020c\u020d\u0001\u0000\u0000\u0000\u020d\u020e\u0006\u000e"+ + "\t\u0000\u020e-\u0001\u0000\u0000\u0000\u020f\u0210\u0005r\u0000\u0000"+ + "\u0210\u0211\u0005o\u0000\u0000\u0211\u0212\u0005w\u0000\u0000\u0212\u0213"+ + "\u0001\u0000\u0000\u0000\u0213\u0214\u0006\u000f\u0000\u0000\u0214/\u0001"+ + "\u0000\u0000\u0000\u0215\u0216\u0005s\u0000\u0000\u0216\u0217\u0005h\u0000"+ + "\u0000\u0217\u0218\u0005o\u0000\u0000\u0218\u0219\u0005w\u0000\u0000\u0219"+ + "\u021a\u0001\u0000\u0000\u0000\u021a\u021b\u0006\u0010\n\u0000\u021b1"+ + "\u0001\u0000\u0000\u0000\u021c\u021d\u0005s\u0000\u0000\u021d\u021e\u0005"+ + "o\u0000\u0000\u021e\u021f\u0005r\u0000\u0000\u021f\u0220\u0005t\u0000"+ + "\u0000\u0220\u0221\u0001\u0000\u0000\u0000\u0221\u0222\u0006\u0011\u0000"+ + "\u0000\u02223\u0001\u0000\u0000\u0000\u0223\u0224\u0005s\u0000\u0000\u0224"+ + "\u0225\u0005t\u0000\u0000\u0225\u0226\u0005a\u0000\u0000\u0226\u0227\u0005"+ + "t\u0000\u0000\u0227\u0228\u0005s\u0000\u0000\u0228\u0229\u0001\u0000\u0000"+ + "\u0000\u0229\u022a\u0006\u0012\u0000\u0000\u022a5\u0001\u0000\u0000\u0000"+ + "\u022b\u022c\u0005w\u0000\u0000\u022c\u022d\u0005h\u0000\u0000\u022d\u022e"+ + "\u0005e\u0000\u0000\u022e\u022f\u0005r\u0000\u0000\u022f\u0230\u0005e"+ + "\u0000\u0000\u0230\u0231\u0001\u0000\u0000\u0000\u0231\u0232\u0006\u0013"+ + "\u0000\u0000\u02327\u0001\u0000\u0000\u0000\u0233\u0235\b\u0000\u0000"+ + "\u0000\u0234\u0233\u0001\u0000\u0000\u0000\u0235\u0236\u0001\u0000\u0000"+ + "\u0000\u0236\u0234\u0001\u0000\u0000\u0000\u0236\u0237\u0001\u0000\u0000"+ + "\u0000\u0237\u0238\u0001\u0000\u0000\u0000\u0238\u0239\u0006\u0014\u0000"+ + "\u0000\u02399\u0001\u0000\u0000\u0000\u023a\u023b\u0005/\u0000\u0000\u023b"+ + "\u023c\u0005/\u0000\u0000\u023c\u0240\u0001\u0000\u0000\u0000\u023d\u023f"+ + "\b\u0001\u0000\u0000\u023e\u023d\u0001\u0000\u0000\u0000\u023f\u0242\u0001"+ + "\u0000\u0000\u0000\u0240\u023e\u0001\u0000\u0000\u0000\u0240\u0241\u0001"+ + "\u0000\u0000\u0000\u0241\u0244\u0001\u0000\u0000\u0000\u0242\u0240\u0001"+ + "\u0000\u0000\u0000\u0243\u0245\u0005\r\u0000\u0000\u0244\u0243\u0001\u0000"+ + "\u0000\u0000\u0244\u0245\u0001\u0000\u0000\u0000\u0245\u0247\u0001\u0000"+ + "\u0000\u0000\u0246\u0248\u0005\n\u0000\u0000\u0247\u0246\u0001\u0000\u0000"+ + "\u0000\u0247\u0248\u0001\u0000\u0000\u0000\u0248\u0249\u0001\u0000\u0000"+ + "\u0000\u0249\u024a\u0006\u0015\u000b\u0000\u024a;\u0001\u0000\u0000\u0000"+ + "\u024b\u024c\u0005/\u0000\u0000\u024c\u024d\u0005*\u0000\u0000\u024d\u0252"+ + "\u0001\u0000\u0000\u0000\u024e\u0251\u0003<\u0016\u0000\u024f\u0251\t"+ + "\u0000\u0000\u0000\u0250\u024e\u0001\u0000\u0000\u0000\u0250\u024f\u0001"+ + "\u0000\u0000\u0000\u0251\u0254\u0001\u0000\u0000\u0000\u0252\u0253\u0001"+ + "\u0000\u0000\u0000\u0252\u0250\u0001\u0000\u0000\u0000\u0253\u0255\u0001"+ + "\u0000\u0000\u0000\u0254\u0252\u0001\u0000\u0000\u0000\u0255\u0256\u0005"+ + "*\u0000\u0000\u0256\u0257\u0005/\u0000\u0000\u0257\u0258\u0001\u0000\u0000"+ + "\u0000\u0258\u0259\u0006\u0016\u000b\u0000\u0259=\u0001\u0000\u0000\u0000"+ + "\u025a\u025c\u0007\u0002\u0000\u0000\u025b\u025a\u0001\u0000\u0000\u0000"+ + "\u025c\u025d\u0001\u0000\u0000\u0000\u025d\u025b\u0001\u0000\u0000\u0000"+ + "\u025d\u025e\u0001\u0000\u0000\u0000\u025e\u025f\u0001\u0000\u0000\u0000"+ + "\u025f\u0260\u0006\u0017\u000b\u0000\u0260?\u0001\u0000\u0000\u0000\u0261"+ + "\u0265\b\u0003\u0000\u0000\u0262\u0263\u0005/\u0000\u0000\u0263\u0265"+ + "\b\u0004\u0000\u0000\u0264\u0261\u0001\u0000\u0000\u0000\u0264\u0262\u0001"+ + "\u0000\u0000\u0000\u0265A\u0001\u0000\u0000\u0000\u0266\u0268\u0003@\u0018"+ + "\u0000\u0267\u0266\u0001\u0000\u0000\u0000\u0268\u0269\u0001\u0000\u0000"+ + "\u0000\u0269\u0267\u0001\u0000\u0000\u0000\u0269\u026a\u0001\u0000\u0000"+ + "\u0000\u026aC\u0001\u0000\u0000\u0000\u026b\u026c\u0003\u00b0P\u0000\u026c"+ + "\u026d\u0001\u0000\u0000\u0000\u026d\u026e\u0006\u001a\f\u0000\u026e\u026f"+ + "\u0006\u001a\r\u0000\u026fE\u0001\u0000\u0000\u0000\u0270\u0271\u0003"+ + "N\u001f\u0000\u0271\u0272\u0001\u0000\u0000\u0000\u0272\u0273\u0006\u001b"+ + "\u000e\u0000\u0273\u0274\u0006\u001b\u000f\u0000\u0274G\u0001\u0000\u0000"+ + "\u0000\u0275\u0276\u0003>\u0017\u0000\u0276\u0277\u0001\u0000\u0000\u0000"+ + "\u0277\u0278\u0006\u001c\u000b\u0000\u0278I\u0001\u0000\u0000\u0000\u0279"+ + "\u027a\u0003:\u0015\u0000\u027a\u027b\u0001\u0000\u0000\u0000\u027b\u027c"+ + "\u0006\u001d\u000b\u0000\u027cK\u0001\u0000\u0000\u0000\u027d\u027e\u0003"+ + "<\u0016\u0000\u027e\u027f\u0001\u0000\u0000\u0000\u027f\u0280\u0006\u001e"+ + "\u000b\u0000\u0280M\u0001\u0000\u0000\u0000\u0281\u0282\u0005|\u0000\u0000"+ + "\u0282\u0283\u0001\u0000\u0000\u0000\u0283\u0284\u0006\u001f\u000f\u0000"+ + "\u0284O\u0001\u0000\u0000\u0000\u0285\u0286\u0007\u0005\u0000\u0000\u0286"+ + "Q\u0001\u0000\u0000\u0000\u0287\u0288\u0007\u0006\u0000\u0000\u0288S\u0001"+ + "\u0000\u0000\u0000\u0289\u028a\u0005\\\u0000\u0000\u028a\u028b\u0007\u0007"+ + "\u0000\u0000\u028bU\u0001\u0000\u0000\u0000\u028c\u028d\b\b\u0000\u0000"+ + "\u028dW\u0001\u0000\u0000\u0000\u028e\u0290\u0007\t\u0000\u0000\u028f"+ + "\u0291\u0007\n\u0000\u0000\u0290\u028f\u0001\u0000\u0000\u0000\u0290\u0291"+ + "\u0001\u0000\u0000\u0000\u0291\u0293\u0001\u0000\u0000\u0000\u0292\u0294"+ + "\u0003P \u0000\u0293\u0292\u0001\u0000\u0000\u0000\u0294\u0295\u0001\u0000"+ + "\u0000\u0000\u0295\u0293\u0001\u0000\u0000\u0000\u0295\u0296\u0001\u0000"+ + "\u0000\u0000\u0296Y\u0001\u0000\u0000\u0000\u0297\u0298\u0005@\u0000\u0000"+ + "\u0298[\u0001\u0000\u0000\u0000\u0299\u029a\u0005`\u0000\u0000\u029a]"+ + "\u0001\u0000\u0000\u0000\u029b\u029f\b\u000b\u0000\u0000\u029c\u029d\u0005"+ + "`\u0000\u0000\u029d\u029f\u0005`\u0000\u0000\u029e\u029b\u0001\u0000\u0000"+ + "\u0000\u029e\u029c\u0001\u0000\u0000\u0000\u029f_\u0001\u0000\u0000\u0000"+ + "\u02a0\u02a1\u0005_\u0000\u0000\u02a1a\u0001\u0000\u0000\u0000\u02a2\u02a6"+ + "\u0003R!\u0000\u02a3\u02a6\u0003P \u0000\u02a4\u02a6\u0003`(\u0000\u02a5"+ + "\u02a2\u0001\u0000\u0000\u0000\u02a5\u02a3\u0001\u0000\u0000\u0000\u02a5"+ + "\u02a4\u0001\u0000\u0000\u0000\u02a6c\u0001\u0000\u0000\u0000\u02a7\u02ac"+ + "\u0005\"\u0000\u0000\u02a8\u02ab\u0003T\"\u0000\u02a9\u02ab\u0003V#\u0000"+ + "\u02aa\u02a8\u0001\u0000\u0000\u0000\u02aa\u02a9\u0001\u0000\u0000\u0000"+ + "\u02ab\u02ae\u0001\u0000\u0000\u0000\u02ac\u02aa\u0001\u0000\u0000\u0000"+ + "\u02ac\u02ad\u0001\u0000\u0000\u0000\u02ad\u02af\u0001\u0000\u0000\u0000"+ + "\u02ae\u02ac\u0001\u0000\u0000\u0000\u02af\u02c5\u0005\"\u0000\u0000\u02b0"+ + "\u02b1\u0005\"\u0000\u0000\u02b1\u02b2\u0005\"\u0000\u0000\u02b2\u02b3"+ + "\u0005\"\u0000\u0000\u02b3\u02b7\u0001\u0000\u0000\u0000\u02b4\u02b6\b"+ + "\u0001\u0000\u0000\u02b5\u02b4\u0001\u0000\u0000\u0000\u02b6\u02b9\u0001"+ + "\u0000\u0000\u0000\u02b7\u02b8\u0001\u0000\u0000\u0000\u02b7\u02b5\u0001"+ + "\u0000\u0000\u0000\u02b8\u02ba\u0001\u0000\u0000\u0000\u02b9\u02b7\u0001"+ + "\u0000\u0000\u0000\u02ba\u02bb\u0005\"\u0000\u0000\u02bb\u02bc\u0005\""+ + "\u0000\u0000\u02bc\u02bd\u0005\"\u0000\u0000\u02bd\u02bf\u0001\u0000\u0000"+ + "\u0000\u02be\u02c0\u0005\"\u0000\u0000\u02bf\u02be\u0001\u0000\u0000\u0000"+ + "\u02bf\u02c0\u0001\u0000\u0000\u0000\u02c0\u02c2\u0001\u0000\u0000\u0000"+ + "\u02c1\u02c3\u0005\"\u0000\u0000\u02c2\u02c1\u0001\u0000\u0000\u0000\u02c2"+ + "\u02c3\u0001\u0000\u0000\u0000\u02c3\u02c5\u0001\u0000\u0000\u0000\u02c4"+ + "\u02a7\u0001\u0000\u0000\u0000\u02c4\u02b0\u0001\u0000\u0000\u0000\u02c5"+ + "e\u0001\u0000\u0000\u0000\u02c6\u02c8\u0003P \u0000\u02c7\u02c6\u0001"+ + "\u0000\u0000\u0000\u02c8\u02c9\u0001\u0000\u0000\u0000\u02c9\u02c7\u0001"+ + "\u0000\u0000\u0000\u02c9\u02ca\u0001\u0000\u0000\u0000\u02cag\u0001\u0000"+ + "\u0000\u0000\u02cb\u02cd\u0003P \u0000\u02cc\u02cb\u0001\u0000\u0000\u0000"+ + "\u02cd\u02ce\u0001\u0000\u0000\u0000\u02ce\u02cc\u0001\u0000\u0000\u0000"+ + "\u02ce\u02cf\u0001\u0000\u0000\u0000\u02cf\u02d0\u0001\u0000\u0000\u0000"+ + "\u02d0\u02d4\u0003x4\u0000\u02d1\u02d3\u0003P \u0000\u02d2\u02d1\u0001"+ + "\u0000\u0000\u0000\u02d3\u02d6\u0001\u0000\u0000\u0000\u02d4\u02d2\u0001"+ + "\u0000\u0000\u0000\u02d4\u02d5\u0001\u0000\u0000\u0000\u02d5\u02f6\u0001"+ + "\u0000\u0000\u0000\u02d6\u02d4\u0001\u0000\u0000\u0000\u02d7\u02d9\u0003"+ + "x4\u0000\u02d8\u02da\u0003P \u0000\u02d9\u02d8\u0001\u0000\u0000\u0000"+ + "\u02da\u02db\u0001\u0000\u0000\u0000\u02db\u02d9\u0001\u0000\u0000\u0000"+ + "\u02db\u02dc\u0001\u0000\u0000\u0000\u02dc\u02f6\u0001\u0000\u0000\u0000"+ + "\u02dd\u02df\u0003P \u0000\u02de\u02dd\u0001\u0000\u0000\u0000\u02df\u02e0"+ + "\u0001\u0000\u0000\u0000\u02e0\u02de\u0001\u0000\u0000\u0000\u02e0\u02e1"+ + "\u0001\u0000\u0000\u0000\u02e1\u02e9\u0001\u0000\u0000\u0000\u02e2\u02e6"+ + "\u0003x4\u0000\u02e3\u02e5\u0003P \u0000\u02e4\u02e3\u0001\u0000\u0000"+ + "\u0000\u02e5\u02e8\u0001\u0000\u0000\u0000\u02e6\u02e4\u0001\u0000\u0000"+ + "\u0000\u02e6\u02e7\u0001\u0000\u0000\u0000\u02e7\u02ea\u0001\u0000\u0000"+ + "\u0000\u02e8\u02e6\u0001\u0000\u0000\u0000\u02e9\u02e2\u0001\u0000\u0000"+ + "\u0000\u02e9\u02ea\u0001\u0000\u0000\u0000\u02ea\u02eb\u0001\u0000\u0000"+ + "\u0000\u02eb\u02ec\u0003X$\u0000\u02ec\u02f6\u0001\u0000\u0000\u0000\u02ed"+ + "\u02ef\u0003x4\u0000\u02ee\u02f0\u0003P \u0000\u02ef\u02ee\u0001\u0000"+ + "\u0000\u0000\u02f0\u02f1\u0001\u0000\u0000\u0000\u02f1\u02ef\u0001\u0000"+ + "\u0000\u0000\u02f1\u02f2\u0001\u0000\u0000\u0000\u02f2\u02f3\u0001\u0000"+ + "\u0000\u0000\u02f3\u02f4\u0003X$\u0000\u02f4\u02f6\u0001\u0000\u0000\u0000"+ + "\u02f5\u02cc\u0001\u0000\u0000\u0000\u02f5\u02d7\u0001\u0000\u0000\u0000"+ + "\u02f5\u02de\u0001\u0000\u0000\u0000\u02f5\u02ed\u0001\u0000\u0000\u0000"+ + "\u02f6i\u0001\u0000\u0000\u0000\u02f7\u02f8\u0005b\u0000\u0000\u02f8\u02f9"+ + "\u0005y\u0000\u0000\u02f9k\u0001\u0000\u0000\u0000\u02fa\u02fb\u0005a"+ + "\u0000\u0000\u02fb\u02fc\u0005n\u0000\u0000\u02fc\u02fd\u0005d\u0000\u0000"+ + "\u02fdm\u0001\u0000\u0000\u0000\u02fe\u02ff\u0005a\u0000\u0000\u02ff\u0300"+ + "\u0005s\u0000\u0000\u0300\u0301\u0005c\u0000\u0000\u0301o\u0001\u0000"+ + "\u0000\u0000\u0302\u0303\u0005=\u0000\u0000\u0303q\u0001\u0000\u0000\u0000"+ + "\u0304\u0305\u0005:\u0000\u0000\u0305\u0306\u0005:\u0000\u0000\u0306s"+ + "\u0001\u0000\u0000\u0000\u0307\u0308\u0005,\u0000\u0000\u0308u\u0001\u0000"+ + "\u0000\u0000\u0309\u030a\u0005d\u0000\u0000\u030a\u030b\u0005e\u0000\u0000"+ + "\u030b\u030c\u0005s\u0000\u0000\u030c\u030d\u0005c\u0000\u0000\u030dw"+ + "\u0001\u0000\u0000\u0000\u030e\u030f\u0005.\u0000\u0000\u030fy\u0001\u0000"+ + "\u0000\u0000\u0310\u0311\u0005f\u0000\u0000\u0311\u0312\u0005a\u0000\u0000"+ + "\u0312\u0313\u0005l\u0000\u0000\u0313\u0314\u0005s\u0000\u0000\u0314\u0315"+ + "\u0005e\u0000\u0000\u0315{\u0001\u0000\u0000\u0000\u0316\u0317\u0005f"+ + "\u0000\u0000\u0317\u0318\u0005i\u0000\u0000\u0318\u0319\u0005r\u0000\u0000"+ + "\u0319\u031a\u0005s\u0000\u0000\u031a\u031b\u0005t\u0000\u0000\u031b}"+ + "\u0001\u0000\u0000\u0000\u031c\u031d\u0005l\u0000\u0000\u031d\u031e\u0005"+ + "a\u0000\u0000\u031e\u031f\u0005s\u0000\u0000\u031f\u0320\u0005t\u0000"+ + "\u0000\u0320\u007f\u0001\u0000\u0000\u0000\u0321\u0322\u0005(\u0000\u0000"+ + "\u0322\u0081\u0001\u0000\u0000\u0000\u0323\u0324\u0005i\u0000\u0000\u0324"+ + "\u0325\u0005n\u0000\u0000\u0325\u0083\u0001\u0000\u0000\u0000\u0326\u0327"+ + "\u0005i\u0000\u0000\u0327\u0328\u0005s\u0000\u0000\u0328\u0085\u0001\u0000"+ + "\u0000\u0000\u0329\u032a\u0005l\u0000\u0000\u032a\u032b\u0005i\u0000\u0000"+ + "\u032b\u032c\u0005k\u0000\u0000\u032c\u032d\u0005e\u0000\u0000\u032d\u0087"+ + "\u0001\u0000\u0000\u0000\u032e\u032f\u0005n\u0000\u0000\u032f\u0330\u0005"+ + "o\u0000\u0000\u0330\u0331\u0005t\u0000\u0000\u0331\u0089\u0001\u0000\u0000"+ + "\u0000\u0332\u0333\u0005n\u0000\u0000\u0333\u0334\u0005u\u0000\u0000\u0334"+ + "\u0335\u0005l\u0000\u0000\u0335\u0336\u0005l\u0000\u0000\u0336\u008b\u0001"+ + "\u0000\u0000\u0000\u0337\u0338\u0005n\u0000\u0000\u0338\u0339\u0005u\u0000"+ + "\u0000\u0339\u033a\u0005l\u0000\u0000\u033a\u033b\u0005l\u0000\u0000\u033b"+ + "\u033c\u0005s\u0000\u0000\u033c\u008d\u0001\u0000\u0000\u0000\u033d\u033e"+ + "\u0005o\u0000\u0000\u033e\u033f\u0005r\u0000\u0000\u033f\u008f\u0001\u0000"+ + "\u0000\u0000\u0340\u0341\u0005?\u0000\u0000\u0341\u0091\u0001\u0000\u0000"+ + "\u0000\u0342\u0343\u0005r\u0000\u0000\u0343\u0344\u0005l\u0000\u0000\u0344"+ + "\u0345\u0005i\u0000\u0000\u0345\u0346\u0005k\u0000\u0000\u0346\u0347\u0005"+ + "e\u0000\u0000\u0347\u0093\u0001\u0000\u0000\u0000\u0348\u0349\u0005)\u0000"+ + "\u0000\u0349\u0095\u0001\u0000\u0000\u0000\u034a\u034b\u0005t\u0000\u0000"+ + "\u034b\u034c\u0005r\u0000\u0000\u034c\u034d\u0005u\u0000\u0000\u034d\u034e"+ + "\u0005e\u0000\u0000\u034e\u0097\u0001\u0000\u0000\u0000\u034f\u0350\u0005"+ + "=\u0000\u0000\u0350\u0351\u0005=\u0000\u0000\u0351\u0099\u0001\u0000\u0000"+ + "\u0000\u0352\u0353\u0005=\u0000\u0000\u0353\u0354\u0005~\u0000\u0000\u0354"+ + "\u009b\u0001\u0000\u0000\u0000\u0355\u0356\u0005!\u0000\u0000\u0356\u0357"+ + "\u0005=\u0000\u0000\u0357\u009d\u0001\u0000\u0000\u0000\u0358\u0359\u0005"+ + "<\u0000\u0000\u0359\u009f\u0001\u0000\u0000\u0000\u035a\u035b\u0005<\u0000"+ + "\u0000\u035b\u035c\u0005=\u0000\u0000\u035c\u00a1\u0001\u0000\u0000\u0000"+ + "\u035d\u035e\u0005>\u0000\u0000\u035e\u00a3\u0001\u0000\u0000\u0000\u035f"+ + "\u0360\u0005>\u0000\u0000\u0360\u0361\u0005=\u0000\u0000\u0361\u00a5\u0001"+ + "\u0000\u0000\u0000\u0362\u0363\u0005+\u0000\u0000\u0363\u00a7\u0001\u0000"+ + "\u0000\u0000\u0364\u0365\u0005-\u0000\u0000\u0365\u00a9\u0001\u0000\u0000"+ + "\u0000\u0366\u0367\u0005*\u0000\u0000\u0367\u00ab\u0001\u0000\u0000\u0000"+ + "\u0368\u0369\u0005/\u0000\u0000\u0369\u00ad\u0001\u0000\u0000\u0000\u036a"+ + "\u036b\u0005%\u0000\u0000\u036b\u00af\u0001\u0000\u0000\u0000\u036c\u036d"+ + "\u0005[\u0000\u0000\u036d\u036e\u0001\u0000\u0000\u0000\u036e\u036f\u0006"+ + "P\u0000\u0000\u036f\u0370\u0006P\u0000\u0000\u0370\u00b1\u0001\u0000\u0000"+ + "\u0000\u0371\u0372\u0005]\u0000\u0000\u0372\u0373\u0001\u0000\u0000\u0000"+ + "\u0373\u0374\u0006Q\u000f\u0000\u0374\u0375\u0006Q\u000f\u0000\u0375\u00b3"+ + "\u0001\u0000\u0000\u0000\u0376\u037a\u0003R!\u0000\u0377\u0379\u0003b"+ + ")\u0000\u0378\u0377\u0001\u0000\u0000\u0000\u0379\u037c\u0001\u0000\u0000"+ + "\u0000\u037a\u0378\u0001\u0000\u0000\u0000\u037a\u037b\u0001\u0000\u0000"+ + "\u0000\u037b\u0387\u0001\u0000\u0000\u0000\u037c\u037a\u0001\u0000\u0000"+ + "\u0000\u037d\u0380\u0003`(\u0000\u037e\u0380\u0003Z%\u0000\u037f\u037d"+ + "\u0001\u0000\u0000\u0000\u037f\u037e\u0001\u0000\u0000\u0000\u0380\u0382"+ + "\u0001\u0000\u0000\u0000\u0381\u0383\u0003b)\u0000\u0382\u0381\u0001\u0000"+ + "\u0000\u0000\u0383\u0384\u0001\u0000\u0000\u0000\u0384\u0382\u0001\u0000"+ + "\u0000\u0000\u0384\u0385\u0001\u0000\u0000\u0000\u0385\u0387\u0001\u0000"+ + "\u0000\u0000\u0386\u0376\u0001\u0000\u0000\u0000\u0386\u037f\u0001\u0000"+ + "\u0000\u0000\u0387\u00b5\u0001\u0000\u0000\u0000\u0388\u038a\u0003\\&"+ + "\u0000\u0389\u038b\u0003^\'\u0000\u038a\u0389\u0001\u0000\u0000\u0000"+ + "\u038b\u038c\u0001\u0000\u0000\u0000\u038c\u038a\u0001\u0000\u0000\u0000"+ + "\u038c\u038d\u0001\u0000\u0000\u0000\u038d\u038e\u0001\u0000\u0000\u0000"+ + "\u038e\u038f\u0003\\&\u0000\u038f\u00b7\u0001\u0000\u0000\u0000\u0390"+ + "\u0391\u0003\u00b6S\u0000\u0391\u00b9\u0001\u0000\u0000\u0000\u0392\u0393"+ + "\u0003:\u0015\u0000\u0393\u0394\u0001\u0000\u0000\u0000\u0394\u0395\u0006"+ + "U\u000b\u0000\u0395\u00bb\u0001\u0000\u0000\u0000\u0396\u0397\u0003<\u0016"+ + "\u0000\u0397\u0398\u0001\u0000\u0000\u0000\u0398\u0399\u0006V\u000b\u0000"+ + "\u0399\u00bd\u0001\u0000\u0000\u0000\u039a\u039b\u0003>\u0017\u0000\u039b"+ + "\u039c\u0001\u0000\u0000\u0000\u039c\u039d\u0006W\u000b\u0000\u039d\u00bf"+ + "\u0001\u0000\u0000\u0000\u039e\u039f\u0003N\u001f\u0000\u039f\u03a0\u0001"+ + "\u0000\u0000\u0000\u03a0\u03a1\u0006X\u000e\u0000\u03a1\u03a2\u0006X\u000f"+ + "\u0000\u03a2\u00c1\u0001\u0000\u0000\u0000\u03a3\u03a4\u0003\u00b0P\u0000"+ + "\u03a4\u03a5\u0001\u0000\u0000\u0000\u03a5\u03a6\u0006Y\f\u0000\u03a6"+ + "\u00c3\u0001\u0000\u0000\u0000\u03a7\u03a8\u0003\u00b2Q\u0000\u03a8\u03a9"+ + "\u0001\u0000\u0000\u0000\u03a9\u03aa\u0006Z\u0010\u0000\u03aa\u00c5\u0001"+ + "\u0000\u0000\u0000\u03ab\u03ac\u0003t2\u0000\u03ac\u03ad\u0001\u0000\u0000"+ + "\u0000\u03ad\u03ae\u0006[\u0011\u0000\u03ae\u00c7\u0001\u0000\u0000\u0000"+ + "\u03af\u03b0\u0003p0\u0000\u03b0\u03b1\u0001\u0000\u0000\u0000\u03b1\u03b2"+ + "\u0006\\\u0012\u0000\u03b2\u00c9\u0001\u0000\u0000\u0000\u03b3\u03b4\u0003"+ + "d*\u0000\u03b4\u03b5\u0001\u0000\u0000\u0000\u03b5\u03b6\u0006]\u0013"+ + "\u0000\u03b6\u00cb\u0001\u0000\u0000\u0000\u03b7\u03b8\u0005m\u0000\u0000"+ + "\u03b8\u03b9\u0005e\u0000\u0000\u03b9\u03ba\u0005t\u0000\u0000\u03ba\u03bb"+ + "\u0005a\u0000\u0000\u03bb\u03bc\u0005d\u0000\u0000\u03bc\u03bd\u0005a"+ + "\u0000\u0000\u03bd\u03be\u0005t\u0000\u0000\u03be\u03bf\u0005a\u0000\u0000"+ + "\u03bf\u00cd\u0001\u0000\u0000\u0000\u03c0\u03c1\u0003B\u0019\u0000\u03c1"+ + "\u03c2\u0001\u0000\u0000\u0000\u03c2\u03c3\u0006_\u0014\u0000\u03c3\u00cf"+ + "\u0001\u0000\u0000\u0000\u03c4\u03c5\u0003:\u0015\u0000\u03c5\u03c6\u0001"+ + "\u0000\u0000\u0000\u03c6\u03c7\u0006`\u000b\u0000\u03c7\u00d1\u0001\u0000"+ + "\u0000\u0000\u03c8\u03c9\u0003<\u0016\u0000\u03c9\u03ca\u0001\u0000\u0000"+ + "\u0000\u03ca\u03cb\u0006a\u000b\u0000\u03cb\u00d3\u0001\u0000\u0000\u0000"+ + "\u03cc\u03cd\u0003>\u0017\u0000\u03cd\u03ce\u0001\u0000\u0000\u0000\u03ce"+ + "\u03cf\u0006b\u000b\u0000\u03cf\u00d5\u0001\u0000\u0000\u0000\u03d0\u03d1"+ + "\u0003N\u001f\u0000\u03d1\u03d2\u0001\u0000\u0000\u0000\u03d2\u03d3\u0006"+ + "c\u000e\u0000\u03d3\u03d4\u0006c\u000f\u0000\u03d4\u00d7\u0001\u0000\u0000"+ + "\u0000\u03d5\u03d6\u0003x4\u0000\u03d6\u03d7\u0001\u0000\u0000\u0000\u03d7"+ + "\u03d8\u0006d\u0015\u0000\u03d8\u00d9\u0001\u0000\u0000\u0000\u03d9\u03da"+ + "\u0003t2\u0000\u03da\u03db\u0001\u0000\u0000\u0000\u03db\u03dc\u0006e"+ + "\u0011\u0000\u03dc\u00db\u0001\u0000\u0000\u0000\u03dd\u03e2\u0003R!\u0000"+ + "\u03de\u03e2\u0003P \u0000\u03df\u03e2\u0003`(\u0000\u03e0\u03e2\u0003"+ + "\u00aaM\u0000\u03e1\u03dd\u0001\u0000\u0000\u0000\u03e1\u03de\u0001\u0000"+ + "\u0000\u0000\u03e1\u03df\u0001\u0000\u0000\u0000\u03e1\u03e0\u0001\u0000"+ + "\u0000\u0000\u03e2\u00dd\u0001\u0000\u0000\u0000\u03e3\u03e6\u0003R!\u0000"+ + "\u03e4\u03e6\u0003\u00aaM\u0000\u03e5\u03e3\u0001\u0000\u0000\u0000\u03e5"+ + "\u03e4\u0001\u0000\u0000\u0000\u03e6\u03ea\u0001\u0000\u0000\u0000\u03e7"+ + "\u03e9\u0003\u00dcf\u0000\u03e8\u03e7\u0001\u0000\u0000\u0000\u03e9\u03ec"+ + "\u0001\u0000\u0000\u0000\u03ea\u03e8\u0001\u0000\u0000\u0000\u03ea\u03eb"+ + "\u0001\u0000\u0000\u0000\u03eb\u03f7\u0001\u0000\u0000\u0000\u03ec\u03ea"+ + "\u0001\u0000\u0000\u0000\u03ed\u03f0\u0003`(\u0000\u03ee\u03f0\u0003Z"+ + "%\u0000\u03ef\u03ed\u0001\u0000\u0000\u0000\u03ef\u03ee\u0001\u0000\u0000"+ + "\u0000\u03f0\u03f2\u0001\u0000\u0000\u0000\u03f1\u03f3\u0003\u00dcf\u0000"+ + "\u03f2\u03f1\u0001\u0000\u0000\u0000\u03f3\u03f4\u0001\u0000\u0000\u0000"+ + "\u03f4\u03f2\u0001\u0000\u0000\u0000\u03f4\u03f5\u0001\u0000\u0000\u0000"+ + "\u03f5\u03f7\u0001\u0000\u0000\u0000\u03f6\u03e5\u0001\u0000\u0000\u0000"+ + "\u03f6\u03ef\u0001\u0000\u0000\u0000\u03f7\u00df\u0001\u0000\u0000\u0000"+ + "\u03f8\u03fb\u0003\u00deg\u0000\u03f9\u03fb\u0003\u00b6S\u0000\u03fa\u03f8"+ + "\u0001\u0000\u0000\u0000\u03fa\u03f9\u0001\u0000\u0000\u0000\u03fb\u03fc"+ + "\u0001\u0000\u0000\u0000\u03fc\u03fa\u0001\u0000\u0000\u0000\u03fc\u03fd"+ + "\u0001\u0000\u0000\u0000\u03fd\u00e1\u0001\u0000\u0000\u0000\u03fe\u03ff"+ + "\u0003:\u0015\u0000\u03ff\u0400\u0001\u0000\u0000\u0000\u0400\u0401\u0006"+ + "i\u000b\u0000\u0401\u00e3\u0001\u0000\u0000\u0000\u0402\u0403\u0003<\u0016"+ + "\u0000\u0403\u0404\u0001\u0000\u0000\u0000\u0404\u0405\u0006j\u000b\u0000"+ + "\u0405\u00e5\u0001\u0000\u0000\u0000\u0406\u0407\u0003>\u0017\u0000\u0407"+ + "\u0408\u0001\u0000\u0000\u0000\u0408\u0409\u0006k\u000b\u0000\u0409\u00e7"+ + "\u0001\u0000\u0000\u0000\u040a\u040b\u0003N\u001f\u0000\u040b\u040c\u0001"+ + "\u0000\u0000\u0000\u040c\u040d\u0006l\u000e\u0000\u040d\u040e\u0006l\u000f"+ + "\u0000\u040e\u00e9\u0001\u0000\u0000\u0000\u040f\u0410\u0003p0\u0000\u0410"+ + "\u0411\u0001\u0000\u0000\u0000\u0411\u0412\u0006m\u0012\u0000\u0412\u00eb"+ + "\u0001\u0000\u0000\u0000\u0413\u0414\u0003t2\u0000\u0414\u0415\u0001\u0000"+ + "\u0000\u0000\u0415\u0416\u0006n\u0011\u0000\u0416\u00ed\u0001\u0000\u0000"+ + "\u0000\u0417\u0418\u0003x4\u0000\u0418\u0419\u0001\u0000\u0000\u0000\u0419"+ + "\u041a\u0006o\u0015\u0000\u041a\u00ef\u0001\u0000\u0000\u0000\u041b\u041c"+ + "\u0005a\u0000\u0000\u041c\u041d\u0005s\u0000\u0000\u041d\u00f1\u0001\u0000"+ + "\u0000\u0000\u041e\u041f\u0003\u00e0h\u0000\u041f\u0420\u0001\u0000\u0000"+ + "\u0000\u0420\u0421\u0006q\u0016\u0000\u0421\u00f3\u0001\u0000\u0000\u0000"+ + "\u0422\u0423\u0003:\u0015\u0000\u0423\u0424\u0001\u0000\u0000\u0000\u0424"+ + "\u0425\u0006r\u000b\u0000\u0425\u00f5\u0001\u0000\u0000\u0000\u0426\u0427"+ + "\u0003<\u0016\u0000\u0427\u0428\u0001\u0000\u0000\u0000\u0428\u0429\u0006"+ + "s\u000b\u0000\u0429\u00f7\u0001\u0000\u0000\u0000\u042a\u042b\u0003>\u0017"+ + "\u0000\u042b\u042c\u0001\u0000\u0000\u0000\u042c\u042d\u0006t\u000b\u0000"+ + "\u042d\u00f9\u0001\u0000\u0000\u0000\u042e\u042f\u0003N\u001f\u0000\u042f"+ + "\u0430\u0001\u0000\u0000\u0000\u0430\u0431\u0006u\u000e\u0000\u0431\u0432"+ + "\u0006u\u000f\u0000\u0432\u00fb\u0001\u0000\u0000\u0000\u0433\u0434\u0003"+ + "\u00b0P\u0000\u0434\u0435\u0001\u0000\u0000\u0000\u0435\u0436\u0006v\f"+ + "\u0000\u0436\u0437\u0006v\u0017\u0000\u0437\u00fd\u0001\u0000\u0000\u0000"+ + "\u0438\u0439\u0005o\u0000\u0000\u0439\u043a\u0005n\u0000\u0000\u043a\u043b"+ + "\u0001\u0000\u0000\u0000\u043b\u043c\u0006w\u0018\u0000\u043c\u00ff\u0001"+ + "\u0000\u0000\u0000\u043d\u043e\u0005w\u0000\u0000\u043e\u043f\u0005i\u0000"+ + "\u0000\u043f\u0440\u0005t\u0000\u0000\u0440\u0441\u0005h\u0000\u0000\u0441"+ + "\u0442\u0001\u0000\u0000\u0000\u0442\u0443\u0006x\u0018\u0000\u0443\u0101"+ + "\u0001\u0000\u0000\u0000\u0444\u0445\b\f\u0000\u0000\u0445\u0103\u0001"+ + "\u0000\u0000\u0000\u0446\u0448\u0003\u0102y\u0000\u0447\u0446\u0001\u0000"+ + "\u0000\u0000\u0448\u0449\u0001\u0000\u0000\u0000\u0449\u0447\u0001\u0000"+ + "\u0000\u0000\u0449\u044a\u0001\u0000\u0000\u0000\u044a\u044b\u0001\u0000"+ + "\u0000\u0000\u044b\u044c\u0003\u0166\u00ab\u0000\u044c\u044e\u0001\u0000"+ + "\u0000\u0000\u044d\u0447\u0001\u0000\u0000\u0000\u044d\u044e\u0001\u0000"+ + "\u0000\u0000\u044e\u0450\u0001\u0000\u0000\u0000\u044f\u0451\u0003\u0102"+ + "y\u0000\u0450\u044f\u0001\u0000\u0000\u0000\u0451\u0452\u0001\u0000\u0000"+ + "\u0000\u0452\u0450\u0001\u0000\u0000\u0000\u0452\u0453\u0001\u0000\u0000"+ + "\u0000\u0453\u0105\u0001\u0000\u0000\u0000\u0454\u0455\u0003\u00b8T\u0000"+ + "\u0455\u0456\u0001\u0000\u0000\u0000\u0456\u0457\u0006{\u0019\u0000\u0457"+ + "\u0107\u0001\u0000\u0000\u0000\u0458\u0459\u0003\u0104z\u0000\u0459\u045a"+ + "\u0001\u0000\u0000\u0000\u045a\u045b\u0006|\u001a\u0000\u045b\u0109\u0001"+ + "\u0000\u0000\u0000\u045c\u045d\u0003:\u0015\u0000\u045d\u045e\u0001\u0000"+ + "\u0000\u0000\u045e\u045f\u0006}\u000b\u0000\u045f\u010b\u0001\u0000\u0000"+ + "\u0000\u0460\u0461\u0003<\u0016\u0000\u0461\u0462\u0001\u0000\u0000\u0000"+ + "\u0462\u0463\u0006~\u000b\u0000\u0463\u010d\u0001\u0000\u0000\u0000\u0464"+ + "\u0465\u0003>\u0017\u0000\u0465\u0466\u0001\u0000\u0000\u0000\u0466\u0467"+ + "\u0006\u007f\u000b\u0000\u0467\u010f\u0001\u0000\u0000\u0000\u0468\u0469"+ + "\u0003N\u001f\u0000\u0469\u046a\u0001\u0000\u0000\u0000\u046a\u046b\u0006"+ + "\u0080\u000e\u0000\u046b\u046c\u0006\u0080\u000f\u0000\u046c\u046d\u0006"+ + "\u0080\u000f\u0000\u046d\u0111\u0001\u0000\u0000\u0000\u046e\u046f\u0003"+ + "p0\u0000\u046f\u0470\u0001\u0000\u0000\u0000\u0470\u0471\u0006\u0081\u0012"+ + "\u0000\u0471\u0113\u0001\u0000\u0000\u0000\u0472\u0473\u0003t2\u0000\u0473"+ + "\u0474\u0001\u0000\u0000\u0000\u0474\u0475\u0006\u0082\u0011\u0000\u0475"+ + "\u0115\u0001\u0000\u0000\u0000\u0476\u0477\u0003x4\u0000\u0477\u0478\u0001"+ + "\u0000\u0000\u0000\u0478\u0479\u0006\u0083\u0015\u0000\u0479\u0117\u0001"+ + "\u0000\u0000\u0000\u047a\u047b\u0003\u0100x\u0000\u047b\u047c\u0001\u0000"+ + "\u0000\u0000\u047c\u047d\u0006\u0084\u001b\u0000\u047d\u0119\u0001\u0000"+ + "\u0000\u0000\u047e\u047f\u0003\u00e0h\u0000\u047f\u0480\u0001\u0000\u0000"+ + "\u0000\u0480\u0481\u0006\u0085\u0016\u0000\u0481\u011b\u0001\u0000\u0000"+ + "\u0000\u0482\u0483\u0003\u00b8T\u0000\u0483\u0484\u0001\u0000\u0000\u0000"+ + "\u0484\u0485\u0006\u0086\u0019\u0000\u0485\u011d\u0001\u0000\u0000\u0000"+ + "\u0486\u0487\u0003:\u0015\u0000\u0487\u0488\u0001\u0000\u0000\u0000\u0488"+ + "\u0489\u0006\u0087\u000b\u0000\u0489\u011f\u0001\u0000\u0000\u0000\u048a"+ + "\u048b\u0003<\u0016\u0000\u048b\u048c\u0001\u0000\u0000\u0000\u048c\u048d"+ + "\u0006\u0088\u000b\u0000\u048d\u0121\u0001\u0000\u0000\u0000\u048e\u048f"+ + "\u0003>\u0017\u0000\u048f\u0490\u0001\u0000\u0000\u0000\u0490\u0491\u0006"+ + "\u0089\u000b\u0000\u0491\u0123\u0001\u0000\u0000\u0000\u0492\u0493\u0003"+ + "N\u001f\u0000\u0493\u0494\u0001\u0000\u0000\u0000\u0494\u0495\u0006\u008a"+ + "\u000e\u0000\u0495\u0496\u0006\u008a\u000f\u0000\u0496\u0125\u0001\u0000"+ + "\u0000\u0000\u0497\u0498\u0003t2\u0000\u0498\u0499\u0001\u0000\u0000\u0000"+ + "\u0499\u049a\u0006\u008b\u0011\u0000\u049a\u0127\u0001\u0000\u0000\u0000"+ + "\u049b\u049c\u0003x4\u0000\u049c\u049d\u0001\u0000\u0000\u0000\u049d\u049e"+ + "\u0006\u008c\u0015\u0000\u049e\u0129\u0001\u0000\u0000\u0000\u049f\u04a0"+ + "\u0003\u00few\u0000\u04a0\u04a1\u0001\u0000\u0000\u0000\u04a1\u04a2\u0006"+ + "\u008d\u001c\u0000\u04a2\u04a3\u0006\u008d\u001d\u0000\u04a3\u012b\u0001"+ + "\u0000\u0000\u0000\u04a4\u04a5\u0003B\u0019\u0000\u04a5\u04a6\u0001\u0000"+ + "\u0000\u0000\u04a6\u04a7\u0006\u008e\u0014\u0000\u04a7\u012d\u0001\u0000"+ + "\u0000\u0000\u04a8\u04a9\u0003:\u0015\u0000\u04a9\u04aa\u0001\u0000\u0000"+ + "\u0000\u04aa\u04ab\u0006\u008f\u000b\u0000\u04ab\u012f\u0001\u0000\u0000"+ + "\u0000\u04ac\u04ad\u0003<\u0016\u0000\u04ad\u04ae\u0001\u0000\u0000\u0000"+ + "\u04ae\u04af\u0006\u0090\u000b\u0000\u04af\u0131\u0001\u0000\u0000\u0000"+ + "\u04b0\u04b1\u0003>\u0017\u0000\u04b1\u04b2\u0001\u0000\u0000\u0000\u04b2"+ + "\u04b3\u0006\u0091\u000b\u0000\u04b3\u0133\u0001\u0000\u0000\u0000\u04b4"+ + "\u04b5\u0003N\u001f\u0000\u04b5\u04b6\u0001\u0000\u0000\u0000\u04b6\u04b7"+ + "\u0006\u0092\u000e\u0000\u04b7\u04b8\u0006\u0092\u000f\u0000\u04b8\u04b9"+ + "\u0006\u0092\u000f\u0000\u04b9\u0135\u0001\u0000\u0000\u0000\u04ba\u04bb"+ + "\u0003t2\u0000\u04bb\u04bc\u0001\u0000\u0000\u0000\u04bc\u04bd\u0006\u0093"+ + "\u0011\u0000\u04bd\u0137\u0001\u0000\u0000\u0000\u04be\u04bf\u0003x4\u0000"+ + "\u04bf\u04c0\u0001\u0000\u0000\u0000\u04c0\u04c1\u0006\u0094\u0015\u0000"+ + "\u04c1\u0139\u0001\u0000\u0000\u0000\u04c2\u04c3\u0003\u00e0h\u0000\u04c3"+ + "\u04c4\u0001\u0000\u0000\u0000\u04c4\u04c5\u0006\u0095\u0016\u0000\u04c5"+ + "\u013b\u0001\u0000\u0000\u0000\u04c6\u04c7\u0003:\u0015\u0000\u04c7\u04c8"+ + "\u0001\u0000\u0000\u0000\u04c8\u04c9\u0006\u0096\u000b\u0000\u04c9\u013d"+ + "\u0001\u0000\u0000\u0000\u04ca\u04cb\u0003<\u0016\u0000\u04cb\u04cc\u0001"+ + "\u0000\u0000\u0000\u04cc\u04cd\u0006\u0097\u000b\u0000\u04cd\u013f\u0001"+ + "\u0000\u0000\u0000\u04ce\u04cf\u0003>\u0017\u0000\u04cf\u04d0\u0001\u0000"+ + "\u0000\u0000\u04d0\u04d1\u0006\u0098\u000b\u0000\u04d1\u0141\u0001\u0000"+ + "\u0000\u0000\u04d2\u04d3\u0003N\u001f\u0000\u04d3\u04d4\u0001\u0000\u0000"+ + "\u0000\u04d4\u04d5\u0006\u0099\u000e\u0000\u04d5\u04d6\u0006\u0099\u000f"+ + "\u0000\u04d6\u0143\u0001\u0000\u0000\u0000\u04d7\u04d8\u0003x4\u0000\u04d8"+ + "\u04d9\u0001\u0000\u0000\u0000\u04d9\u04da\u0006\u009a\u0015\u0000\u04da"+ + "\u0145\u0001\u0000\u0000\u0000\u04db\u04dc\u0003\u00b8T\u0000\u04dc\u04dd"+ + "\u0001\u0000\u0000\u0000\u04dd\u04de\u0006\u009b\u0019\u0000\u04de\u0147"+ + "\u0001\u0000\u0000\u0000\u04df\u04e0\u0003\u00b4R\u0000\u04e0\u04e1\u0001"+ + "\u0000\u0000\u0000\u04e1\u04e2\u0006\u009c\u001e\u0000\u04e2\u0149\u0001"+ + "\u0000\u0000\u0000\u04e3\u04e4\u0003:\u0015\u0000\u04e4\u04e5\u0001\u0000"+ + "\u0000\u0000\u04e5\u04e6\u0006\u009d\u000b\u0000\u04e6\u014b\u0001\u0000"+ + "\u0000\u0000\u04e7\u04e8\u0003<\u0016\u0000\u04e8\u04e9\u0001\u0000\u0000"+ + "\u0000\u04e9\u04ea\u0006\u009e\u000b\u0000\u04ea\u014d\u0001\u0000\u0000"+ + "\u0000\u04eb\u04ec\u0003>\u0017\u0000\u04ec\u04ed\u0001\u0000\u0000\u0000"+ + "\u04ed\u04ee\u0006\u009f\u000b\u0000\u04ee\u014f\u0001\u0000\u0000\u0000"+ + "\u04ef\u04f0\u0003N\u001f\u0000\u04f0\u04f1\u0001\u0000\u0000\u0000\u04f1"+ + "\u04f2\u0006\u00a0\u000e\u0000\u04f2\u04f3\u0006\u00a0\u000f\u0000\u04f3"+ + "\u0151\u0001\u0000\u0000\u0000\u04f4\u04f5\u0005i\u0000\u0000\u04f5\u04f6"+ + "\u0005n\u0000\u0000\u04f6\u04f7\u0005f\u0000\u0000\u04f7\u04f8\u0005o"+ + "\u0000\u0000\u04f8\u0153\u0001\u0000\u0000\u0000\u04f9\u04fa\u0003:\u0015"+ + "\u0000\u04fa\u04fb\u0001\u0000\u0000\u0000\u04fb\u04fc\u0006\u00a2\u000b"+ + "\u0000\u04fc\u0155\u0001\u0000\u0000\u0000\u04fd\u04fe\u0003<\u0016\u0000"+ + "\u04fe\u04ff\u0001\u0000\u0000\u0000\u04ff\u0500\u0006\u00a3\u000b\u0000"+ + "\u0500\u0157\u0001\u0000\u0000\u0000\u0501\u0502\u0003>\u0017\u0000\u0502"+ + "\u0503\u0001\u0000\u0000\u0000\u0503\u0504\u0006\u00a4\u000b\u0000\u0504"+ + "\u0159\u0001\u0000\u0000\u0000\u0505\u0506\u0003N\u001f\u0000\u0506\u0507"+ + "\u0001\u0000\u0000\u0000\u0507\u0508\u0006\u00a5\u000e\u0000\u0508\u0509"+ + "\u0006\u00a5\u000f\u0000\u0509\u015b\u0001\u0000\u0000\u0000\u050a\u050b"+ + "\u0005f\u0000\u0000\u050b\u050c\u0005u\u0000\u0000\u050c\u050d\u0005n"+ + "\u0000\u0000\u050d\u050e\u0005c\u0000\u0000\u050e\u050f\u0005t\u0000\u0000"+ + "\u050f\u0510\u0005i\u0000\u0000\u0510\u0511\u0005o\u0000\u0000\u0511\u0512"+ + "\u0005n\u0000\u0000\u0512\u0513\u0005s\u0000\u0000\u0513\u015d\u0001\u0000"+ + "\u0000\u0000\u0514\u0515\u0003:\u0015\u0000\u0515\u0516\u0001\u0000\u0000"+ + "\u0000\u0516\u0517\u0006\u00a7\u000b\u0000\u0517\u015f\u0001\u0000\u0000"+ + "\u0000\u0518\u0519\u0003<\u0016\u0000\u0519\u051a\u0001\u0000\u0000\u0000"+ + "\u051a\u051b\u0006\u00a8\u000b\u0000\u051b\u0161\u0001\u0000\u0000\u0000"+ + "\u051c\u051d\u0003>\u0017\u0000\u051d\u051e\u0001\u0000\u0000\u0000\u051e"+ + "\u051f\u0006\u00a9\u000b\u0000\u051f\u0163\u0001\u0000\u0000\u0000\u0520"+ + "\u0521\u0003\u00b2Q\u0000\u0521\u0522\u0001\u0000\u0000\u0000\u0522\u0523"+ + "\u0006\u00aa\u0010\u0000\u0523\u0524\u0006\u00aa\u000f\u0000\u0524\u0165"+ + "\u0001\u0000\u0000\u0000\u0525\u0526\u0005:\u0000\u0000\u0526\u0167\u0001"+ + "\u0000\u0000\u0000\u0527\u052d\u0003Z%\u0000\u0528\u052d\u0003P \u0000"+ + "\u0529\u052d\u0003x4\u0000\u052a\u052d\u0003R!\u0000\u052b\u052d\u0003"+ + "`(\u0000\u052c\u0527\u0001\u0000\u0000\u0000\u052c\u0528\u0001\u0000\u0000"+ + "\u0000\u052c\u0529\u0001\u0000\u0000\u0000\u052c\u052a\u0001\u0000\u0000"+ + "\u0000\u052c\u052b\u0001\u0000\u0000\u0000\u052d\u052e\u0001\u0000\u0000"+ + "\u0000\u052e\u052c\u0001\u0000\u0000\u0000\u052e\u052f\u0001\u0000\u0000"+ + "\u0000\u052f\u0169\u0001\u0000\u0000\u0000\u0530\u0531\u0003:\u0015\u0000"+ + "\u0531\u0532\u0001\u0000\u0000\u0000\u0532\u0533\u0006\u00ad\u000b\u0000"+ + "\u0533\u016b\u0001\u0000\u0000\u0000\u0534\u0535\u0003<\u0016\u0000\u0535"+ + "\u0536\u0001\u0000\u0000\u0000\u0536\u0537\u0006\u00ae\u000b\u0000\u0537"+ + "\u016d\u0001\u0000\u0000\u0000\u0538\u0539\u0003>\u0017\u0000\u0539\u053a"+ + "\u0001\u0000\u0000\u0000\u053a\u053b\u0006\u00af\u000b\u0000\u053b\u016f"+ + "\u0001\u0000\u0000\u0000\u053c\u053d\u0003N\u001f\u0000\u053d\u053e\u0001"+ + "\u0000\u0000\u0000\u053e\u053f\u0006\u00b0\u000e\u0000\u053f\u0540\u0006"+ + "\u00b0\u000f\u0000\u0540\u0171\u0001\u0000\u0000\u0000\u0541\u0542\u0003"+ + "B\u0019\u0000\u0542\u0543\u0001\u0000\u0000\u0000\u0543\u0544\u0006\u00b1"+ + "\u0014\u0000\u0544\u0545\u0006\u00b1\u000f\u0000\u0545\u0546\u0006\u00b1"+ + "\u001f\u0000\u0546\u0173\u0001\u0000\u0000\u0000\u0547\u0548\u0003:\u0015"+ + "\u0000\u0548\u0549\u0001\u0000\u0000\u0000\u0549\u054a\u0006\u00b2\u000b"+ + "\u0000\u054a\u0175\u0001\u0000\u0000\u0000\u054b\u054c\u0003<\u0016\u0000"+ + "\u054c\u054d\u0001\u0000\u0000\u0000\u054d\u054e\u0006\u00b3\u000b\u0000"+ + "\u054e\u0177\u0001\u0000\u0000\u0000\u054f\u0550\u0003>\u0017\u0000\u0550"+ + "\u0551\u0001\u0000\u0000\u0000\u0551\u0552\u0006\u00b4\u000b\u0000\u0552"+ + "\u0179\u0001\u0000\u0000\u0000\u0553\u0554\u0003t2\u0000\u0554\u0555\u0001"+ + "\u0000\u0000\u0000\u0555\u0556\u0006\u00b5\u0011\u0000\u0556\u0557\u0006"+ + "\u00b5\u000f\u0000\u0557\u0558\u0006\u00b5\u0007\u0000\u0558\u017b\u0001"+ + "\u0000\u0000\u0000\u0559\u055a\u0003:\u0015\u0000\u055a\u055b\u0001\u0000"+ + "\u0000\u0000\u055b\u055c\u0006\u00b6\u000b\u0000\u055c\u017d\u0001\u0000"+ + "\u0000\u0000\u055d\u055e\u0003<\u0016\u0000\u055e\u055f\u0001\u0000\u0000"+ + "\u0000\u055f\u0560\u0006\u00b7\u000b\u0000\u0560\u017f\u0001\u0000\u0000"+ + "\u0000\u0561\u0562\u0003>\u0017\u0000\u0562\u0563\u0001\u0000\u0000\u0000"+ + "\u0563\u0564\u0006\u00b8\u000b\u0000\u0564\u0181\u0001\u0000\u0000\u0000"+ + "\u0565\u0566\u0003\u00b8T\u0000\u0566\u0567\u0001\u0000\u0000\u0000\u0567"+ + "\u0568\u0006\u00b9\u000f\u0000\u0568\u0569\u0006\u00b9\u0000\u0000\u0569"+ + "\u056a\u0006\u00b9\u0019\u0000\u056a\u0183\u0001\u0000\u0000\u0000\u056b"+ + "\u056c\u0003\u00b4R\u0000\u056c\u056d\u0001\u0000\u0000\u0000\u056d\u056e"+ + "\u0006\u00ba\u000f\u0000\u056e\u056f\u0006\u00ba\u0000\u0000\u056f\u0570"+ + "\u0006\u00ba\u001e\u0000\u0570\u0185\u0001\u0000\u0000\u0000\u0571\u0572"+ + "\u0003j-\u0000\u0572\u0573\u0001\u0000\u0000\u0000\u0573\u0574\u0006\u00bb"+ + "\u000f\u0000\u0574\u0575\u0006\u00bb\u0000\u0000\u0575\u0576\u0006\u00bb"+ + " \u0000\u0576\u0187\u0001\u0000\u0000\u0000\u0577\u0578\u0003N\u001f\u0000"+ + "\u0578\u0579\u0001\u0000\u0000\u0000\u0579\u057a\u0006\u00bc\u000e\u0000"+ + "\u057a\u057b\u0006\u00bc\u000f\u0000\u057b\u0189\u0001\u0000\u0000\u0000"+ + ">\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e"+ + "\u000f\u0236\u0240\u0244\u0247\u0250\u0252\u025d\u0264\u0269\u0290\u0295"+ + "\u029e\u02a5\u02aa\u02ac\u02b7\u02bf\u02c2\u02c4\u02c9\u02ce\u02d4\u02db"+ + "\u02e0\u02e6\u02e9\u02f1\u02f5\u037a\u037f\u0384\u0386\u038c\u03e1\u03e5"+ + "\u03ea\u03ef\u03f4\u03f6\u03fa\u03fc\u0449\u044d\u0452\u052c\u052e!\u0005"+ + "\u0002\u0000\u0005\u0004\u0000\u0005\u0006\u0000\u0005\u0001\u0000\u0005"+ + "\u0003\u0000\u0005\b\u0000\u0005\f\u0000\u0005\u000e\u0000\u0005\n\u0000"+ + "\u0005\u0005\u0000\u0005\u000b\u0000\u0000\u0001\u0000\u0007D\u0000\u0005"+ + "\u0000\u0000\u0007\u001d\u0000\u0004\u0000\u0000\u0007E\u0000\u0007&\u0000"+ + "\u0007$\u0000\u0007\u001e\u0000\u0007\u0019\u0000\u0007(\u0000\u0007O"+ + "\u0000\u0005\r\u0000\u0005\u0007\u0000\u0007G\u0000\u0007Y\u0000\u0007"+ + "X\u0000\u0007W\u0000\u0005\t\u0000\u0007F\u0000\u0005\u000f\u0000\u0007"+ + "!\u0000"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp index d6f90975aefac..76663717c5624 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp @@ -10,6 +10,7 @@ null 'inlinestats' 'keep' 'limit' +'lookup' 'meta' 'metrics' 'mv_expand' @@ -97,6 +98,12 @@ null null null null +null +null +null +null +null +null 'info' null null @@ -129,6 +136,7 @@ GROK INLINESTATS KEEP LIMIT +LOOKUP META METRICS MV_EXPAND @@ -213,6 +221,12 @@ ENRICH_WS ENRICH_FIELD_LINE_COMMENT ENRICH_FIELD_MULTILINE_COMMENT ENRICH_FIELD_WS +LOOKUP_LINE_COMMENT +LOOKUP_MULTILINE_COMMENT +LOOKUP_WS +LOOKUP_FIELD_LINE_COMMENT +LOOKUP_FIELD_MULTILINE_COMMENT +LOOKUP_FIELD_WS MVEXPAND_LINE_COMMENT MVEXPAND_MULTILINE_COMMENT MVEXPAND_WS @@ -263,6 +277,7 @@ statsCommand inlinestatsCommand qualifiedName qualifiedNamePattern +qualifiedNamePatterns identifier identifierPattern constant @@ -290,7 +305,8 @@ showCommand metaCommand enrichCommand enrichWithClause +lookupCommand atn: -[4, 1, 116, 542, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 116, 8, 1, 10, 1, 12, 1, 119, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 127, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 142, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 154, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 161, 8, 5, 10, 5, 12, 5, 164, 9, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 171, 8, 5, 1, 5, 1, 5, 3, 5, 175, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 183, 8, 5, 10, 5, 12, 5, 186, 9, 5, 1, 6, 1, 6, 3, 6, 190, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 197, 8, 6, 1, 6, 1, 6, 1, 6, 3, 6, 202, 8, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 3, 7, 209, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 215, 8, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 223, 8, 8, 10, 8, 12, 8, 226, 9, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 3, 9, 236, 8, 9, 1, 9, 1, 9, 1, 9, 5, 9, 241, 8, 9, 10, 9, 12, 9, 244, 9, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 5, 10, 252, 8, 10, 10, 10, 12, 10, 255, 9, 10, 3, 10, 257, 8, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 5, 13, 269, 8, 13, 10, 13, 12, 13, 272, 9, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 279, 8, 14, 1, 15, 1, 15, 1, 15, 1, 15, 5, 15, 285, 8, 15, 10, 15, 12, 15, 288, 9, 15, 1, 15, 3, 15, 291, 8, 15, 1, 16, 1, 16, 1, 17, 1, 17, 3, 17, 297, 8, 17, 1, 18, 1, 18, 1, 18, 1, 18, 5, 18, 303, 8, 18, 10, 18, 12, 18, 306, 9, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 5, 20, 316, 8, 20, 10, 20, 12, 20, 319, 9, 20, 1, 20, 3, 20, 322, 8, 20, 1, 20, 1, 20, 3, 20, 326, 8, 20, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 3, 22, 333, 8, 22, 1, 22, 1, 22, 3, 22, 337, 8, 22, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 343, 8, 23, 1, 24, 1, 24, 1, 24, 5, 24, 348, 8, 24, 10, 24, 12, 24, 351, 9, 24, 1, 25, 1, 25, 1, 25, 5, 25, 356, 8, 25, 10, 25, 12, 25, 359, 9, 25, 1, 26, 1, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 5, 28, 378, 8, 28, 10, 28, 12, 28, 381, 9, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 5, 28, 389, 8, 28, 10, 28, 12, 28, 392, 9, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 5, 28, 400, 8, 28, 10, 28, 12, 28, 403, 9, 28, 1, 28, 1, 28, 3, 28, 407, 8, 28, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 5, 30, 416, 8, 30, 10, 30, 12, 30, 419, 9, 30, 1, 31, 1, 31, 3, 31, 423, 8, 31, 1, 31, 1, 31, 3, 31, 427, 8, 31, 1, 32, 1, 32, 1, 32, 1, 32, 5, 32, 433, 8, 32, 10, 32, 12, 32, 436, 9, 32, 1, 33, 1, 33, 1, 33, 1, 33, 5, 33, 442, 8, 33, 10, 33, 12, 33, 445, 9, 33, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 451, 8, 34, 10, 34, 12, 34, 454, 9, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 464, 8, 36, 1, 37, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 5, 39, 476, 8, 39, 10, 39, 12, 39, 479, 9, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 42, 1, 42, 3, 42, 489, 8, 42, 1, 43, 3, 43, 492, 8, 43, 1, 43, 1, 43, 1, 44, 3, 44, 497, 8, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 3, 51, 522, 8, 51, 1, 51, 1, 51, 1, 51, 1, 51, 5, 51, 528, 8, 51, 10, 51, 12, 51, 531, 9, 51, 3, 51, 533, 8, 51, 1, 52, 1, 52, 1, 52, 3, 52, 538, 8, 52, 1, 52, 1, 52, 1, 52, 0, 4, 2, 10, 16, 18, 53, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 0, 7, 1, 0, 62, 63, 1, 0, 64, 66, 1, 0, 69, 70, 2, 0, 34, 34, 38, 38, 1, 0, 41, 42, 2, 0, 40, 40, 54, 54, 2, 0, 55, 55, 57, 61, 570, 0, 106, 1, 0, 0, 0, 2, 109, 1, 0, 0, 0, 4, 126, 1, 0, 0, 0, 6, 141, 1, 0, 0, 0, 8, 143, 1, 0, 0, 0, 10, 174, 1, 0, 0, 0, 12, 201, 1, 0, 0, 0, 14, 208, 1, 0, 0, 0, 16, 214, 1, 0, 0, 0, 18, 235, 1, 0, 0, 0, 20, 245, 1, 0, 0, 0, 22, 260, 1, 0, 0, 0, 24, 262, 1, 0, 0, 0, 26, 265, 1, 0, 0, 0, 28, 278, 1, 0, 0, 0, 30, 280, 1, 0, 0, 0, 32, 292, 1, 0, 0, 0, 34, 296, 1, 0, 0, 0, 36, 298, 1, 0, 0, 0, 38, 307, 1, 0, 0, 0, 40, 311, 1, 0, 0, 0, 42, 327, 1, 0, 0, 0, 44, 330, 1, 0, 0, 0, 46, 338, 1, 0, 0, 0, 48, 344, 1, 0, 0, 0, 50, 352, 1, 0, 0, 0, 52, 360, 1, 0, 0, 0, 54, 362, 1, 0, 0, 0, 56, 406, 1, 0, 0, 0, 58, 408, 1, 0, 0, 0, 60, 411, 1, 0, 0, 0, 62, 420, 1, 0, 0, 0, 64, 428, 1, 0, 0, 0, 66, 437, 1, 0, 0, 0, 68, 446, 1, 0, 0, 0, 70, 455, 1, 0, 0, 0, 72, 459, 1, 0, 0, 0, 74, 465, 1, 0, 0, 0, 76, 469, 1, 0, 0, 0, 78, 472, 1, 0, 0, 0, 80, 480, 1, 0, 0, 0, 82, 484, 1, 0, 0, 0, 84, 488, 1, 0, 0, 0, 86, 491, 1, 0, 0, 0, 88, 496, 1, 0, 0, 0, 90, 500, 1, 0, 0, 0, 92, 502, 1, 0, 0, 0, 94, 504, 1, 0, 0, 0, 96, 507, 1, 0, 0, 0, 98, 511, 1, 0, 0, 0, 100, 514, 1, 0, 0, 0, 102, 517, 1, 0, 0, 0, 104, 537, 1, 0, 0, 0, 106, 107, 3, 2, 1, 0, 107, 108, 5, 0, 0, 1, 108, 1, 1, 0, 0, 0, 109, 110, 6, 1, -1, 0, 110, 111, 3, 4, 2, 0, 111, 117, 1, 0, 0, 0, 112, 113, 10, 1, 0, 0, 113, 114, 5, 28, 0, 0, 114, 116, 3, 6, 3, 0, 115, 112, 1, 0, 0, 0, 116, 119, 1, 0, 0, 0, 117, 115, 1, 0, 0, 0, 117, 118, 1, 0, 0, 0, 118, 3, 1, 0, 0, 0, 119, 117, 1, 0, 0, 0, 120, 127, 3, 94, 47, 0, 121, 127, 3, 30, 15, 0, 122, 127, 3, 24, 12, 0, 123, 127, 3, 40, 20, 0, 124, 127, 3, 98, 49, 0, 125, 127, 3, 100, 50, 0, 126, 120, 1, 0, 0, 0, 126, 121, 1, 0, 0, 0, 126, 122, 1, 0, 0, 0, 126, 123, 1, 0, 0, 0, 126, 124, 1, 0, 0, 0, 126, 125, 1, 0, 0, 0, 127, 5, 1, 0, 0, 0, 128, 142, 3, 42, 21, 0, 129, 142, 3, 46, 23, 0, 130, 142, 3, 58, 29, 0, 131, 142, 3, 64, 32, 0, 132, 142, 3, 60, 30, 0, 133, 142, 3, 44, 22, 0, 134, 142, 3, 8, 4, 0, 135, 142, 3, 66, 33, 0, 136, 142, 3, 68, 34, 0, 137, 142, 3, 72, 36, 0, 138, 142, 3, 74, 37, 0, 139, 142, 3, 102, 51, 0, 140, 142, 3, 76, 38, 0, 141, 128, 1, 0, 0, 0, 141, 129, 1, 0, 0, 0, 141, 130, 1, 0, 0, 0, 141, 131, 1, 0, 0, 0, 141, 132, 1, 0, 0, 0, 141, 133, 1, 0, 0, 0, 141, 134, 1, 0, 0, 0, 141, 135, 1, 0, 0, 0, 141, 136, 1, 0, 0, 0, 141, 137, 1, 0, 0, 0, 141, 138, 1, 0, 0, 0, 141, 139, 1, 0, 0, 0, 141, 140, 1, 0, 0, 0, 142, 7, 1, 0, 0, 0, 143, 144, 5, 19, 0, 0, 144, 145, 3, 10, 5, 0, 145, 9, 1, 0, 0, 0, 146, 147, 6, 5, -1, 0, 147, 148, 5, 47, 0, 0, 148, 175, 3, 10, 5, 7, 149, 175, 3, 14, 7, 0, 150, 175, 3, 12, 6, 0, 151, 153, 3, 14, 7, 0, 152, 154, 5, 47, 0, 0, 153, 152, 1, 0, 0, 0, 153, 154, 1, 0, 0, 0, 154, 155, 1, 0, 0, 0, 155, 156, 5, 44, 0, 0, 156, 157, 5, 43, 0, 0, 157, 162, 3, 14, 7, 0, 158, 159, 5, 37, 0, 0, 159, 161, 3, 14, 7, 0, 160, 158, 1, 0, 0, 0, 161, 164, 1, 0, 0, 0, 162, 160, 1, 0, 0, 0, 162, 163, 1, 0, 0, 0, 163, 165, 1, 0, 0, 0, 164, 162, 1, 0, 0, 0, 165, 166, 5, 53, 0, 0, 166, 175, 1, 0, 0, 0, 167, 168, 3, 14, 7, 0, 168, 170, 5, 45, 0, 0, 169, 171, 5, 47, 0, 0, 170, 169, 1, 0, 0, 0, 170, 171, 1, 0, 0, 0, 171, 172, 1, 0, 0, 0, 172, 173, 5, 48, 0, 0, 173, 175, 1, 0, 0, 0, 174, 146, 1, 0, 0, 0, 174, 149, 1, 0, 0, 0, 174, 150, 1, 0, 0, 0, 174, 151, 1, 0, 0, 0, 174, 167, 1, 0, 0, 0, 175, 184, 1, 0, 0, 0, 176, 177, 10, 4, 0, 0, 177, 178, 5, 33, 0, 0, 178, 183, 3, 10, 5, 5, 179, 180, 10, 3, 0, 0, 180, 181, 5, 50, 0, 0, 181, 183, 3, 10, 5, 4, 182, 176, 1, 0, 0, 0, 182, 179, 1, 0, 0, 0, 183, 186, 1, 0, 0, 0, 184, 182, 1, 0, 0, 0, 184, 185, 1, 0, 0, 0, 185, 11, 1, 0, 0, 0, 186, 184, 1, 0, 0, 0, 187, 189, 3, 14, 7, 0, 188, 190, 5, 47, 0, 0, 189, 188, 1, 0, 0, 0, 189, 190, 1, 0, 0, 0, 190, 191, 1, 0, 0, 0, 191, 192, 5, 46, 0, 0, 192, 193, 3, 90, 45, 0, 193, 202, 1, 0, 0, 0, 194, 196, 3, 14, 7, 0, 195, 197, 5, 47, 0, 0, 196, 195, 1, 0, 0, 0, 196, 197, 1, 0, 0, 0, 197, 198, 1, 0, 0, 0, 198, 199, 5, 52, 0, 0, 199, 200, 3, 90, 45, 0, 200, 202, 1, 0, 0, 0, 201, 187, 1, 0, 0, 0, 201, 194, 1, 0, 0, 0, 202, 13, 1, 0, 0, 0, 203, 209, 3, 16, 8, 0, 204, 205, 3, 16, 8, 0, 205, 206, 3, 92, 46, 0, 206, 207, 3, 16, 8, 0, 207, 209, 1, 0, 0, 0, 208, 203, 1, 0, 0, 0, 208, 204, 1, 0, 0, 0, 209, 15, 1, 0, 0, 0, 210, 211, 6, 8, -1, 0, 211, 215, 3, 18, 9, 0, 212, 213, 7, 0, 0, 0, 213, 215, 3, 16, 8, 3, 214, 210, 1, 0, 0, 0, 214, 212, 1, 0, 0, 0, 215, 224, 1, 0, 0, 0, 216, 217, 10, 2, 0, 0, 217, 218, 7, 1, 0, 0, 218, 223, 3, 16, 8, 3, 219, 220, 10, 1, 0, 0, 220, 221, 7, 0, 0, 0, 221, 223, 3, 16, 8, 2, 222, 216, 1, 0, 0, 0, 222, 219, 1, 0, 0, 0, 223, 226, 1, 0, 0, 0, 224, 222, 1, 0, 0, 0, 224, 225, 1, 0, 0, 0, 225, 17, 1, 0, 0, 0, 226, 224, 1, 0, 0, 0, 227, 228, 6, 9, -1, 0, 228, 236, 3, 56, 28, 0, 229, 236, 3, 48, 24, 0, 230, 236, 3, 20, 10, 0, 231, 232, 5, 43, 0, 0, 232, 233, 3, 10, 5, 0, 233, 234, 5, 53, 0, 0, 234, 236, 1, 0, 0, 0, 235, 227, 1, 0, 0, 0, 235, 229, 1, 0, 0, 0, 235, 230, 1, 0, 0, 0, 235, 231, 1, 0, 0, 0, 236, 242, 1, 0, 0, 0, 237, 238, 10, 1, 0, 0, 238, 239, 5, 36, 0, 0, 239, 241, 3, 22, 11, 0, 240, 237, 1, 0, 0, 0, 241, 244, 1, 0, 0, 0, 242, 240, 1, 0, 0, 0, 242, 243, 1, 0, 0, 0, 243, 19, 1, 0, 0, 0, 244, 242, 1, 0, 0, 0, 245, 246, 3, 52, 26, 0, 246, 256, 5, 43, 0, 0, 247, 257, 5, 64, 0, 0, 248, 253, 3, 10, 5, 0, 249, 250, 5, 37, 0, 0, 250, 252, 3, 10, 5, 0, 251, 249, 1, 0, 0, 0, 252, 255, 1, 0, 0, 0, 253, 251, 1, 0, 0, 0, 253, 254, 1, 0, 0, 0, 254, 257, 1, 0, 0, 0, 255, 253, 1, 0, 0, 0, 256, 247, 1, 0, 0, 0, 256, 248, 1, 0, 0, 0, 256, 257, 1, 0, 0, 0, 257, 258, 1, 0, 0, 0, 258, 259, 5, 53, 0, 0, 259, 21, 1, 0, 0, 0, 260, 261, 3, 52, 26, 0, 261, 23, 1, 0, 0, 0, 262, 263, 5, 15, 0, 0, 263, 264, 3, 26, 13, 0, 264, 25, 1, 0, 0, 0, 265, 270, 3, 28, 14, 0, 266, 267, 5, 37, 0, 0, 267, 269, 3, 28, 14, 0, 268, 266, 1, 0, 0, 0, 269, 272, 1, 0, 0, 0, 270, 268, 1, 0, 0, 0, 270, 271, 1, 0, 0, 0, 271, 27, 1, 0, 0, 0, 272, 270, 1, 0, 0, 0, 273, 279, 3, 10, 5, 0, 274, 275, 3, 48, 24, 0, 275, 276, 5, 35, 0, 0, 276, 277, 3, 10, 5, 0, 277, 279, 1, 0, 0, 0, 278, 273, 1, 0, 0, 0, 278, 274, 1, 0, 0, 0, 279, 29, 1, 0, 0, 0, 280, 281, 5, 6, 0, 0, 281, 286, 3, 32, 16, 0, 282, 283, 5, 37, 0, 0, 283, 285, 3, 32, 16, 0, 284, 282, 1, 0, 0, 0, 285, 288, 1, 0, 0, 0, 286, 284, 1, 0, 0, 0, 286, 287, 1, 0, 0, 0, 287, 290, 1, 0, 0, 0, 288, 286, 1, 0, 0, 0, 289, 291, 3, 34, 17, 0, 290, 289, 1, 0, 0, 0, 290, 291, 1, 0, 0, 0, 291, 31, 1, 0, 0, 0, 292, 293, 5, 24, 0, 0, 293, 33, 1, 0, 0, 0, 294, 297, 3, 36, 18, 0, 295, 297, 3, 38, 19, 0, 296, 294, 1, 0, 0, 0, 296, 295, 1, 0, 0, 0, 297, 35, 1, 0, 0, 0, 298, 299, 5, 74, 0, 0, 299, 304, 3, 32, 16, 0, 300, 301, 5, 37, 0, 0, 301, 303, 3, 32, 16, 0, 302, 300, 1, 0, 0, 0, 303, 306, 1, 0, 0, 0, 304, 302, 1, 0, 0, 0, 304, 305, 1, 0, 0, 0, 305, 37, 1, 0, 0, 0, 306, 304, 1, 0, 0, 0, 307, 308, 5, 67, 0, 0, 308, 309, 3, 36, 18, 0, 309, 310, 5, 68, 0, 0, 310, 39, 1, 0, 0, 0, 311, 312, 5, 12, 0, 0, 312, 317, 3, 32, 16, 0, 313, 314, 5, 37, 0, 0, 314, 316, 3, 32, 16, 0, 315, 313, 1, 0, 0, 0, 316, 319, 1, 0, 0, 0, 317, 315, 1, 0, 0, 0, 317, 318, 1, 0, 0, 0, 318, 321, 1, 0, 0, 0, 319, 317, 1, 0, 0, 0, 320, 322, 3, 26, 13, 0, 321, 320, 1, 0, 0, 0, 321, 322, 1, 0, 0, 0, 322, 325, 1, 0, 0, 0, 323, 324, 5, 32, 0, 0, 324, 326, 3, 26, 13, 0, 325, 323, 1, 0, 0, 0, 325, 326, 1, 0, 0, 0, 326, 41, 1, 0, 0, 0, 327, 328, 5, 4, 0, 0, 328, 329, 3, 26, 13, 0, 329, 43, 1, 0, 0, 0, 330, 332, 5, 18, 0, 0, 331, 333, 3, 26, 13, 0, 332, 331, 1, 0, 0, 0, 332, 333, 1, 0, 0, 0, 333, 336, 1, 0, 0, 0, 334, 335, 5, 32, 0, 0, 335, 337, 3, 26, 13, 0, 336, 334, 1, 0, 0, 0, 336, 337, 1, 0, 0, 0, 337, 45, 1, 0, 0, 0, 338, 339, 5, 8, 0, 0, 339, 342, 3, 26, 13, 0, 340, 341, 5, 32, 0, 0, 341, 343, 3, 26, 13, 0, 342, 340, 1, 0, 0, 0, 342, 343, 1, 0, 0, 0, 343, 47, 1, 0, 0, 0, 344, 349, 3, 52, 26, 0, 345, 346, 5, 39, 0, 0, 346, 348, 3, 52, 26, 0, 347, 345, 1, 0, 0, 0, 348, 351, 1, 0, 0, 0, 349, 347, 1, 0, 0, 0, 349, 350, 1, 0, 0, 0, 350, 49, 1, 0, 0, 0, 351, 349, 1, 0, 0, 0, 352, 357, 3, 54, 27, 0, 353, 354, 5, 39, 0, 0, 354, 356, 3, 54, 27, 0, 355, 353, 1, 0, 0, 0, 356, 359, 1, 0, 0, 0, 357, 355, 1, 0, 0, 0, 357, 358, 1, 0, 0, 0, 358, 51, 1, 0, 0, 0, 359, 357, 1, 0, 0, 0, 360, 361, 7, 2, 0, 0, 361, 53, 1, 0, 0, 0, 362, 363, 5, 78, 0, 0, 363, 55, 1, 0, 0, 0, 364, 407, 5, 48, 0, 0, 365, 366, 3, 88, 44, 0, 366, 367, 5, 69, 0, 0, 367, 407, 1, 0, 0, 0, 368, 407, 3, 86, 43, 0, 369, 407, 3, 88, 44, 0, 370, 407, 3, 82, 41, 0, 371, 407, 5, 51, 0, 0, 372, 407, 3, 90, 45, 0, 373, 374, 5, 67, 0, 0, 374, 379, 3, 84, 42, 0, 375, 376, 5, 37, 0, 0, 376, 378, 3, 84, 42, 0, 377, 375, 1, 0, 0, 0, 378, 381, 1, 0, 0, 0, 379, 377, 1, 0, 0, 0, 379, 380, 1, 0, 0, 0, 380, 382, 1, 0, 0, 0, 381, 379, 1, 0, 0, 0, 382, 383, 5, 68, 0, 0, 383, 407, 1, 0, 0, 0, 384, 385, 5, 67, 0, 0, 385, 390, 3, 82, 41, 0, 386, 387, 5, 37, 0, 0, 387, 389, 3, 82, 41, 0, 388, 386, 1, 0, 0, 0, 389, 392, 1, 0, 0, 0, 390, 388, 1, 0, 0, 0, 390, 391, 1, 0, 0, 0, 391, 393, 1, 0, 0, 0, 392, 390, 1, 0, 0, 0, 393, 394, 5, 68, 0, 0, 394, 407, 1, 0, 0, 0, 395, 396, 5, 67, 0, 0, 396, 401, 3, 90, 45, 0, 397, 398, 5, 37, 0, 0, 398, 400, 3, 90, 45, 0, 399, 397, 1, 0, 0, 0, 400, 403, 1, 0, 0, 0, 401, 399, 1, 0, 0, 0, 401, 402, 1, 0, 0, 0, 402, 404, 1, 0, 0, 0, 403, 401, 1, 0, 0, 0, 404, 405, 5, 68, 0, 0, 405, 407, 1, 0, 0, 0, 406, 364, 1, 0, 0, 0, 406, 365, 1, 0, 0, 0, 406, 368, 1, 0, 0, 0, 406, 369, 1, 0, 0, 0, 406, 370, 1, 0, 0, 0, 406, 371, 1, 0, 0, 0, 406, 372, 1, 0, 0, 0, 406, 373, 1, 0, 0, 0, 406, 384, 1, 0, 0, 0, 406, 395, 1, 0, 0, 0, 407, 57, 1, 0, 0, 0, 408, 409, 5, 10, 0, 0, 409, 410, 5, 30, 0, 0, 410, 59, 1, 0, 0, 0, 411, 412, 5, 17, 0, 0, 412, 417, 3, 62, 31, 0, 413, 414, 5, 37, 0, 0, 414, 416, 3, 62, 31, 0, 415, 413, 1, 0, 0, 0, 416, 419, 1, 0, 0, 0, 417, 415, 1, 0, 0, 0, 417, 418, 1, 0, 0, 0, 418, 61, 1, 0, 0, 0, 419, 417, 1, 0, 0, 0, 420, 422, 3, 10, 5, 0, 421, 423, 7, 3, 0, 0, 422, 421, 1, 0, 0, 0, 422, 423, 1, 0, 0, 0, 423, 426, 1, 0, 0, 0, 424, 425, 5, 49, 0, 0, 425, 427, 7, 4, 0, 0, 426, 424, 1, 0, 0, 0, 426, 427, 1, 0, 0, 0, 427, 63, 1, 0, 0, 0, 428, 429, 5, 9, 0, 0, 429, 434, 3, 50, 25, 0, 430, 431, 5, 37, 0, 0, 431, 433, 3, 50, 25, 0, 432, 430, 1, 0, 0, 0, 433, 436, 1, 0, 0, 0, 434, 432, 1, 0, 0, 0, 434, 435, 1, 0, 0, 0, 435, 65, 1, 0, 0, 0, 436, 434, 1, 0, 0, 0, 437, 438, 5, 2, 0, 0, 438, 443, 3, 50, 25, 0, 439, 440, 5, 37, 0, 0, 440, 442, 3, 50, 25, 0, 441, 439, 1, 0, 0, 0, 442, 445, 1, 0, 0, 0, 443, 441, 1, 0, 0, 0, 443, 444, 1, 0, 0, 0, 444, 67, 1, 0, 0, 0, 445, 443, 1, 0, 0, 0, 446, 447, 5, 14, 0, 0, 447, 452, 3, 70, 35, 0, 448, 449, 5, 37, 0, 0, 449, 451, 3, 70, 35, 0, 450, 448, 1, 0, 0, 0, 451, 454, 1, 0, 0, 0, 452, 450, 1, 0, 0, 0, 452, 453, 1, 0, 0, 0, 453, 69, 1, 0, 0, 0, 454, 452, 1, 0, 0, 0, 455, 456, 3, 50, 25, 0, 456, 457, 5, 82, 0, 0, 457, 458, 3, 50, 25, 0, 458, 71, 1, 0, 0, 0, 459, 460, 5, 1, 0, 0, 460, 461, 3, 18, 9, 0, 461, 463, 3, 90, 45, 0, 462, 464, 3, 78, 39, 0, 463, 462, 1, 0, 0, 0, 463, 464, 1, 0, 0, 0, 464, 73, 1, 0, 0, 0, 465, 466, 5, 7, 0, 0, 466, 467, 3, 18, 9, 0, 467, 468, 3, 90, 45, 0, 468, 75, 1, 0, 0, 0, 469, 470, 5, 13, 0, 0, 470, 471, 3, 48, 24, 0, 471, 77, 1, 0, 0, 0, 472, 477, 3, 80, 40, 0, 473, 474, 5, 37, 0, 0, 474, 476, 3, 80, 40, 0, 475, 473, 1, 0, 0, 0, 476, 479, 1, 0, 0, 0, 477, 475, 1, 0, 0, 0, 477, 478, 1, 0, 0, 0, 478, 79, 1, 0, 0, 0, 479, 477, 1, 0, 0, 0, 480, 481, 3, 52, 26, 0, 481, 482, 5, 35, 0, 0, 482, 483, 3, 56, 28, 0, 483, 81, 1, 0, 0, 0, 484, 485, 7, 5, 0, 0, 485, 83, 1, 0, 0, 0, 486, 489, 3, 86, 43, 0, 487, 489, 3, 88, 44, 0, 488, 486, 1, 0, 0, 0, 488, 487, 1, 0, 0, 0, 489, 85, 1, 0, 0, 0, 490, 492, 7, 0, 0, 0, 491, 490, 1, 0, 0, 0, 491, 492, 1, 0, 0, 0, 492, 493, 1, 0, 0, 0, 493, 494, 5, 31, 0, 0, 494, 87, 1, 0, 0, 0, 495, 497, 7, 0, 0, 0, 496, 495, 1, 0, 0, 0, 496, 497, 1, 0, 0, 0, 497, 498, 1, 0, 0, 0, 498, 499, 5, 30, 0, 0, 499, 89, 1, 0, 0, 0, 500, 501, 5, 29, 0, 0, 501, 91, 1, 0, 0, 0, 502, 503, 7, 6, 0, 0, 503, 93, 1, 0, 0, 0, 504, 505, 5, 5, 0, 0, 505, 506, 3, 96, 48, 0, 506, 95, 1, 0, 0, 0, 507, 508, 5, 67, 0, 0, 508, 509, 3, 2, 1, 0, 509, 510, 5, 68, 0, 0, 510, 97, 1, 0, 0, 0, 511, 512, 5, 16, 0, 0, 512, 513, 5, 98, 0, 0, 513, 99, 1, 0, 0, 0, 514, 515, 5, 11, 0, 0, 515, 516, 5, 102, 0, 0, 516, 101, 1, 0, 0, 0, 517, 518, 5, 3, 0, 0, 518, 521, 5, 88, 0, 0, 519, 520, 5, 86, 0, 0, 520, 522, 3, 50, 25, 0, 521, 519, 1, 0, 0, 0, 521, 522, 1, 0, 0, 0, 522, 532, 1, 0, 0, 0, 523, 524, 5, 87, 0, 0, 524, 529, 3, 104, 52, 0, 525, 526, 5, 37, 0, 0, 526, 528, 3, 104, 52, 0, 527, 525, 1, 0, 0, 0, 528, 531, 1, 0, 0, 0, 529, 527, 1, 0, 0, 0, 529, 530, 1, 0, 0, 0, 530, 533, 1, 0, 0, 0, 531, 529, 1, 0, 0, 0, 532, 523, 1, 0, 0, 0, 532, 533, 1, 0, 0, 0, 533, 103, 1, 0, 0, 0, 534, 535, 3, 50, 25, 0, 535, 536, 5, 35, 0, 0, 536, 538, 1, 0, 0, 0, 537, 534, 1, 0, 0, 0, 537, 538, 1, 0, 0, 0, 538, 539, 1, 0, 0, 0, 539, 540, 3, 50, 25, 0, 540, 105, 1, 0, 0, 0, 53, 117, 126, 141, 153, 162, 170, 174, 182, 184, 189, 196, 201, 208, 214, 222, 224, 235, 242, 253, 256, 270, 278, 286, 290, 296, 304, 317, 321, 325, 332, 336, 342, 349, 357, 379, 390, 401, 406, 417, 422, 426, 434, 443, 452, 463, 477, 488, 491, 496, 521, 529, 532, 537] \ No newline at end of file +[4, 1, 123, 548, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 120, 8, 1, 10, 1, 12, 1, 123, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 131, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 147, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 159, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 166, 8, 5, 10, 5, 12, 5, 169, 9, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 176, 8, 5, 1, 5, 1, 5, 3, 5, 180, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 188, 8, 5, 10, 5, 12, 5, 191, 9, 5, 1, 6, 1, 6, 3, 6, 195, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 202, 8, 6, 1, 6, 1, 6, 1, 6, 3, 6, 207, 8, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 3, 7, 214, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 220, 8, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 228, 8, 8, 10, 8, 12, 8, 231, 9, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 3, 9, 241, 8, 9, 1, 9, 1, 9, 1, 9, 5, 9, 246, 8, 9, 10, 9, 12, 9, 249, 9, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 5, 10, 257, 8, 10, 10, 10, 12, 10, 260, 9, 10, 3, 10, 262, 8, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 5, 13, 274, 8, 13, 10, 13, 12, 13, 277, 9, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 284, 8, 14, 1, 15, 1, 15, 1, 15, 1, 15, 5, 15, 290, 8, 15, 10, 15, 12, 15, 293, 9, 15, 1, 15, 3, 15, 296, 8, 15, 1, 16, 1, 16, 1, 17, 1, 17, 3, 17, 302, 8, 17, 1, 18, 1, 18, 1, 18, 1, 18, 5, 18, 308, 8, 18, 10, 18, 12, 18, 311, 9, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 5, 20, 321, 8, 20, 10, 20, 12, 20, 324, 9, 20, 1, 20, 3, 20, 327, 8, 20, 1, 20, 1, 20, 3, 20, 331, 8, 20, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 3, 22, 338, 8, 22, 1, 22, 1, 22, 3, 22, 342, 8, 22, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 348, 8, 23, 1, 24, 1, 24, 1, 24, 5, 24, 353, 8, 24, 10, 24, 12, 24, 356, 9, 24, 1, 25, 1, 25, 1, 25, 5, 25, 361, 8, 25, 10, 25, 12, 25, 364, 9, 25, 1, 26, 1, 26, 1, 26, 5, 26, 369, 8, 26, 10, 26, 12, 26, 372, 9, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 5, 29, 391, 8, 29, 10, 29, 12, 29, 394, 9, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 5, 29, 402, 8, 29, 10, 29, 12, 29, 405, 9, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 5, 29, 413, 8, 29, 10, 29, 12, 29, 416, 9, 29, 1, 29, 1, 29, 3, 29, 420, 8, 29, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 5, 31, 429, 8, 31, 10, 31, 12, 31, 432, 9, 31, 1, 32, 1, 32, 3, 32, 436, 8, 32, 1, 32, 1, 32, 3, 32, 440, 8, 32, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 452, 8, 35, 10, 35, 12, 35, 455, 9, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 465, 8, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 5, 40, 477, 8, 40, 10, 40, 12, 40, 480, 9, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 43, 1, 43, 3, 43, 490, 8, 43, 1, 44, 3, 44, 493, 8, 44, 1, 44, 1, 44, 1, 45, 3, 45, 498, 8, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 3, 52, 523, 8, 52, 1, 52, 1, 52, 1, 52, 1, 52, 5, 52, 529, 8, 52, 10, 52, 12, 52, 532, 9, 52, 3, 52, 534, 8, 52, 1, 53, 1, 53, 1, 53, 3, 53, 539, 8, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 0, 4, 2, 10, 16, 18, 55, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 0, 7, 1, 0, 63, 64, 1, 0, 65, 67, 1, 0, 70, 71, 2, 0, 35, 35, 39, 39, 1, 0, 42, 43, 2, 0, 41, 41, 55, 55, 2, 0, 56, 56, 58, 62, 574, 0, 110, 1, 0, 0, 0, 2, 113, 1, 0, 0, 0, 4, 130, 1, 0, 0, 0, 6, 146, 1, 0, 0, 0, 8, 148, 1, 0, 0, 0, 10, 179, 1, 0, 0, 0, 12, 206, 1, 0, 0, 0, 14, 213, 1, 0, 0, 0, 16, 219, 1, 0, 0, 0, 18, 240, 1, 0, 0, 0, 20, 250, 1, 0, 0, 0, 22, 265, 1, 0, 0, 0, 24, 267, 1, 0, 0, 0, 26, 270, 1, 0, 0, 0, 28, 283, 1, 0, 0, 0, 30, 285, 1, 0, 0, 0, 32, 297, 1, 0, 0, 0, 34, 301, 1, 0, 0, 0, 36, 303, 1, 0, 0, 0, 38, 312, 1, 0, 0, 0, 40, 316, 1, 0, 0, 0, 42, 332, 1, 0, 0, 0, 44, 335, 1, 0, 0, 0, 46, 343, 1, 0, 0, 0, 48, 349, 1, 0, 0, 0, 50, 357, 1, 0, 0, 0, 52, 365, 1, 0, 0, 0, 54, 373, 1, 0, 0, 0, 56, 375, 1, 0, 0, 0, 58, 419, 1, 0, 0, 0, 60, 421, 1, 0, 0, 0, 62, 424, 1, 0, 0, 0, 64, 433, 1, 0, 0, 0, 66, 441, 1, 0, 0, 0, 68, 444, 1, 0, 0, 0, 70, 447, 1, 0, 0, 0, 72, 456, 1, 0, 0, 0, 74, 460, 1, 0, 0, 0, 76, 466, 1, 0, 0, 0, 78, 470, 1, 0, 0, 0, 80, 473, 1, 0, 0, 0, 82, 481, 1, 0, 0, 0, 84, 485, 1, 0, 0, 0, 86, 489, 1, 0, 0, 0, 88, 492, 1, 0, 0, 0, 90, 497, 1, 0, 0, 0, 92, 501, 1, 0, 0, 0, 94, 503, 1, 0, 0, 0, 96, 505, 1, 0, 0, 0, 98, 508, 1, 0, 0, 0, 100, 512, 1, 0, 0, 0, 102, 515, 1, 0, 0, 0, 104, 518, 1, 0, 0, 0, 106, 538, 1, 0, 0, 0, 108, 542, 1, 0, 0, 0, 110, 111, 3, 2, 1, 0, 111, 112, 5, 0, 0, 1, 112, 1, 1, 0, 0, 0, 113, 114, 6, 1, -1, 0, 114, 115, 3, 4, 2, 0, 115, 121, 1, 0, 0, 0, 116, 117, 10, 1, 0, 0, 117, 118, 5, 29, 0, 0, 118, 120, 3, 6, 3, 0, 119, 116, 1, 0, 0, 0, 120, 123, 1, 0, 0, 0, 121, 119, 1, 0, 0, 0, 121, 122, 1, 0, 0, 0, 122, 3, 1, 0, 0, 0, 123, 121, 1, 0, 0, 0, 124, 131, 3, 96, 48, 0, 125, 131, 3, 30, 15, 0, 126, 131, 3, 24, 12, 0, 127, 131, 3, 40, 20, 0, 128, 131, 3, 100, 50, 0, 129, 131, 3, 102, 51, 0, 130, 124, 1, 0, 0, 0, 130, 125, 1, 0, 0, 0, 130, 126, 1, 0, 0, 0, 130, 127, 1, 0, 0, 0, 130, 128, 1, 0, 0, 0, 130, 129, 1, 0, 0, 0, 131, 5, 1, 0, 0, 0, 132, 147, 3, 42, 21, 0, 133, 147, 3, 46, 23, 0, 134, 147, 3, 60, 30, 0, 135, 147, 3, 108, 54, 0, 136, 147, 3, 66, 33, 0, 137, 147, 3, 62, 31, 0, 138, 147, 3, 44, 22, 0, 139, 147, 3, 8, 4, 0, 140, 147, 3, 68, 34, 0, 141, 147, 3, 70, 35, 0, 142, 147, 3, 74, 37, 0, 143, 147, 3, 76, 38, 0, 144, 147, 3, 104, 52, 0, 145, 147, 3, 78, 39, 0, 146, 132, 1, 0, 0, 0, 146, 133, 1, 0, 0, 0, 146, 134, 1, 0, 0, 0, 146, 135, 1, 0, 0, 0, 146, 136, 1, 0, 0, 0, 146, 137, 1, 0, 0, 0, 146, 138, 1, 0, 0, 0, 146, 139, 1, 0, 0, 0, 146, 140, 1, 0, 0, 0, 146, 141, 1, 0, 0, 0, 146, 142, 1, 0, 0, 0, 146, 143, 1, 0, 0, 0, 146, 144, 1, 0, 0, 0, 146, 145, 1, 0, 0, 0, 147, 7, 1, 0, 0, 0, 148, 149, 5, 20, 0, 0, 149, 150, 3, 10, 5, 0, 150, 9, 1, 0, 0, 0, 151, 152, 6, 5, -1, 0, 152, 153, 5, 48, 0, 0, 153, 180, 3, 10, 5, 7, 154, 180, 3, 14, 7, 0, 155, 180, 3, 12, 6, 0, 156, 158, 3, 14, 7, 0, 157, 159, 5, 48, 0, 0, 158, 157, 1, 0, 0, 0, 158, 159, 1, 0, 0, 0, 159, 160, 1, 0, 0, 0, 160, 161, 5, 45, 0, 0, 161, 162, 5, 44, 0, 0, 162, 167, 3, 14, 7, 0, 163, 164, 5, 38, 0, 0, 164, 166, 3, 14, 7, 0, 165, 163, 1, 0, 0, 0, 166, 169, 1, 0, 0, 0, 167, 165, 1, 0, 0, 0, 167, 168, 1, 0, 0, 0, 168, 170, 1, 0, 0, 0, 169, 167, 1, 0, 0, 0, 170, 171, 5, 54, 0, 0, 171, 180, 1, 0, 0, 0, 172, 173, 3, 14, 7, 0, 173, 175, 5, 46, 0, 0, 174, 176, 5, 48, 0, 0, 175, 174, 1, 0, 0, 0, 175, 176, 1, 0, 0, 0, 176, 177, 1, 0, 0, 0, 177, 178, 5, 49, 0, 0, 178, 180, 1, 0, 0, 0, 179, 151, 1, 0, 0, 0, 179, 154, 1, 0, 0, 0, 179, 155, 1, 0, 0, 0, 179, 156, 1, 0, 0, 0, 179, 172, 1, 0, 0, 0, 180, 189, 1, 0, 0, 0, 181, 182, 10, 4, 0, 0, 182, 183, 5, 34, 0, 0, 183, 188, 3, 10, 5, 5, 184, 185, 10, 3, 0, 0, 185, 186, 5, 51, 0, 0, 186, 188, 3, 10, 5, 4, 187, 181, 1, 0, 0, 0, 187, 184, 1, 0, 0, 0, 188, 191, 1, 0, 0, 0, 189, 187, 1, 0, 0, 0, 189, 190, 1, 0, 0, 0, 190, 11, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 192, 194, 3, 14, 7, 0, 193, 195, 5, 48, 0, 0, 194, 193, 1, 0, 0, 0, 194, 195, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 197, 5, 47, 0, 0, 197, 198, 3, 92, 46, 0, 198, 207, 1, 0, 0, 0, 199, 201, 3, 14, 7, 0, 200, 202, 5, 48, 0, 0, 201, 200, 1, 0, 0, 0, 201, 202, 1, 0, 0, 0, 202, 203, 1, 0, 0, 0, 203, 204, 5, 53, 0, 0, 204, 205, 3, 92, 46, 0, 205, 207, 1, 0, 0, 0, 206, 192, 1, 0, 0, 0, 206, 199, 1, 0, 0, 0, 207, 13, 1, 0, 0, 0, 208, 214, 3, 16, 8, 0, 209, 210, 3, 16, 8, 0, 210, 211, 3, 94, 47, 0, 211, 212, 3, 16, 8, 0, 212, 214, 1, 0, 0, 0, 213, 208, 1, 0, 0, 0, 213, 209, 1, 0, 0, 0, 214, 15, 1, 0, 0, 0, 215, 216, 6, 8, -1, 0, 216, 220, 3, 18, 9, 0, 217, 218, 7, 0, 0, 0, 218, 220, 3, 16, 8, 3, 219, 215, 1, 0, 0, 0, 219, 217, 1, 0, 0, 0, 220, 229, 1, 0, 0, 0, 221, 222, 10, 2, 0, 0, 222, 223, 7, 1, 0, 0, 223, 228, 3, 16, 8, 3, 224, 225, 10, 1, 0, 0, 225, 226, 7, 0, 0, 0, 226, 228, 3, 16, 8, 2, 227, 221, 1, 0, 0, 0, 227, 224, 1, 0, 0, 0, 228, 231, 1, 0, 0, 0, 229, 227, 1, 0, 0, 0, 229, 230, 1, 0, 0, 0, 230, 17, 1, 0, 0, 0, 231, 229, 1, 0, 0, 0, 232, 233, 6, 9, -1, 0, 233, 241, 3, 58, 29, 0, 234, 241, 3, 48, 24, 0, 235, 241, 3, 20, 10, 0, 236, 237, 5, 44, 0, 0, 237, 238, 3, 10, 5, 0, 238, 239, 5, 54, 0, 0, 239, 241, 1, 0, 0, 0, 240, 232, 1, 0, 0, 0, 240, 234, 1, 0, 0, 0, 240, 235, 1, 0, 0, 0, 240, 236, 1, 0, 0, 0, 241, 247, 1, 0, 0, 0, 242, 243, 10, 1, 0, 0, 243, 244, 5, 37, 0, 0, 244, 246, 3, 22, 11, 0, 245, 242, 1, 0, 0, 0, 246, 249, 1, 0, 0, 0, 247, 245, 1, 0, 0, 0, 247, 248, 1, 0, 0, 0, 248, 19, 1, 0, 0, 0, 249, 247, 1, 0, 0, 0, 250, 251, 3, 54, 27, 0, 251, 261, 5, 44, 0, 0, 252, 262, 5, 65, 0, 0, 253, 258, 3, 10, 5, 0, 254, 255, 5, 38, 0, 0, 255, 257, 3, 10, 5, 0, 256, 254, 1, 0, 0, 0, 257, 260, 1, 0, 0, 0, 258, 256, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 262, 1, 0, 0, 0, 260, 258, 1, 0, 0, 0, 261, 252, 1, 0, 0, 0, 261, 253, 1, 0, 0, 0, 261, 262, 1, 0, 0, 0, 262, 263, 1, 0, 0, 0, 263, 264, 5, 54, 0, 0, 264, 21, 1, 0, 0, 0, 265, 266, 3, 54, 27, 0, 266, 23, 1, 0, 0, 0, 267, 268, 5, 16, 0, 0, 268, 269, 3, 26, 13, 0, 269, 25, 1, 0, 0, 0, 270, 275, 3, 28, 14, 0, 271, 272, 5, 38, 0, 0, 272, 274, 3, 28, 14, 0, 273, 271, 1, 0, 0, 0, 274, 277, 1, 0, 0, 0, 275, 273, 1, 0, 0, 0, 275, 276, 1, 0, 0, 0, 276, 27, 1, 0, 0, 0, 277, 275, 1, 0, 0, 0, 278, 284, 3, 10, 5, 0, 279, 280, 3, 48, 24, 0, 280, 281, 5, 36, 0, 0, 281, 282, 3, 10, 5, 0, 282, 284, 1, 0, 0, 0, 283, 278, 1, 0, 0, 0, 283, 279, 1, 0, 0, 0, 284, 29, 1, 0, 0, 0, 285, 286, 5, 6, 0, 0, 286, 291, 3, 32, 16, 0, 287, 288, 5, 38, 0, 0, 288, 290, 3, 32, 16, 0, 289, 287, 1, 0, 0, 0, 290, 293, 1, 0, 0, 0, 291, 289, 1, 0, 0, 0, 291, 292, 1, 0, 0, 0, 292, 295, 1, 0, 0, 0, 293, 291, 1, 0, 0, 0, 294, 296, 3, 34, 17, 0, 295, 294, 1, 0, 0, 0, 295, 296, 1, 0, 0, 0, 296, 31, 1, 0, 0, 0, 297, 298, 5, 25, 0, 0, 298, 33, 1, 0, 0, 0, 299, 302, 3, 36, 18, 0, 300, 302, 3, 38, 19, 0, 301, 299, 1, 0, 0, 0, 301, 300, 1, 0, 0, 0, 302, 35, 1, 0, 0, 0, 303, 304, 5, 75, 0, 0, 304, 309, 3, 32, 16, 0, 305, 306, 5, 38, 0, 0, 306, 308, 3, 32, 16, 0, 307, 305, 1, 0, 0, 0, 308, 311, 1, 0, 0, 0, 309, 307, 1, 0, 0, 0, 309, 310, 1, 0, 0, 0, 310, 37, 1, 0, 0, 0, 311, 309, 1, 0, 0, 0, 312, 313, 5, 68, 0, 0, 313, 314, 3, 36, 18, 0, 314, 315, 5, 69, 0, 0, 315, 39, 1, 0, 0, 0, 316, 317, 5, 13, 0, 0, 317, 322, 3, 32, 16, 0, 318, 319, 5, 38, 0, 0, 319, 321, 3, 32, 16, 0, 320, 318, 1, 0, 0, 0, 321, 324, 1, 0, 0, 0, 322, 320, 1, 0, 0, 0, 322, 323, 1, 0, 0, 0, 323, 326, 1, 0, 0, 0, 324, 322, 1, 0, 0, 0, 325, 327, 3, 26, 13, 0, 326, 325, 1, 0, 0, 0, 326, 327, 1, 0, 0, 0, 327, 330, 1, 0, 0, 0, 328, 329, 5, 33, 0, 0, 329, 331, 3, 26, 13, 0, 330, 328, 1, 0, 0, 0, 330, 331, 1, 0, 0, 0, 331, 41, 1, 0, 0, 0, 332, 333, 5, 4, 0, 0, 333, 334, 3, 26, 13, 0, 334, 43, 1, 0, 0, 0, 335, 337, 5, 19, 0, 0, 336, 338, 3, 26, 13, 0, 337, 336, 1, 0, 0, 0, 337, 338, 1, 0, 0, 0, 338, 341, 1, 0, 0, 0, 339, 340, 5, 33, 0, 0, 340, 342, 3, 26, 13, 0, 341, 339, 1, 0, 0, 0, 341, 342, 1, 0, 0, 0, 342, 45, 1, 0, 0, 0, 343, 344, 5, 8, 0, 0, 344, 347, 3, 26, 13, 0, 345, 346, 5, 33, 0, 0, 346, 348, 3, 26, 13, 0, 347, 345, 1, 0, 0, 0, 347, 348, 1, 0, 0, 0, 348, 47, 1, 0, 0, 0, 349, 354, 3, 54, 27, 0, 350, 351, 5, 40, 0, 0, 351, 353, 3, 54, 27, 0, 352, 350, 1, 0, 0, 0, 353, 356, 1, 0, 0, 0, 354, 352, 1, 0, 0, 0, 354, 355, 1, 0, 0, 0, 355, 49, 1, 0, 0, 0, 356, 354, 1, 0, 0, 0, 357, 362, 3, 56, 28, 0, 358, 359, 5, 40, 0, 0, 359, 361, 3, 56, 28, 0, 360, 358, 1, 0, 0, 0, 361, 364, 1, 0, 0, 0, 362, 360, 1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, 51, 1, 0, 0, 0, 364, 362, 1, 0, 0, 0, 365, 370, 3, 50, 25, 0, 366, 367, 5, 38, 0, 0, 367, 369, 3, 50, 25, 0, 368, 366, 1, 0, 0, 0, 369, 372, 1, 0, 0, 0, 370, 368, 1, 0, 0, 0, 370, 371, 1, 0, 0, 0, 371, 53, 1, 0, 0, 0, 372, 370, 1, 0, 0, 0, 373, 374, 7, 2, 0, 0, 374, 55, 1, 0, 0, 0, 375, 376, 5, 79, 0, 0, 376, 57, 1, 0, 0, 0, 377, 420, 5, 49, 0, 0, 378, 379, 3, 90, 45, 0, 379, 380, 5, 70, 0, 0, 380, 420, 1, 0, 0, 0, 381, 420, 3, 88, 44, 0, 382, 420, 3, 90, 45, 0, 383, 420, 3, 84, 42, 0, 384, 420, 5, 52, 0, 0, 385, 420, 3, 92, 46, 0, 386, 387, 5, 68, 0, 0, 387, 392, 3, 86, 43, 0, 388, 389, 5, 38, 0, 0, 389, 391, 3, 86, 43, 0, 390, 388, 1, 0, 0, 0, 391, 394, 1, 0, 0, 0, 392, 390, 1, 0, 0, 0, 392, 393, 1, 0, 0, 0, 393, 395, 1, 0, 0, 0, 394, 392, 1, 0, 0, 0, 395, 396, 5, 69, 0, 0, 396, 420, 1, 0, 0, 0, 397, 398, 5, 68, 0, 0, 398, 403, 3, 84, 42, 0, 399, 400, 5, 38, 0, 0, 400, 402, 3, 84, 42, 0, 401, 399, 1, 0, 0, 0, 402, 405, 1, 0, 0, 0, 403, 401, 1, 0, 0, 0, 403, 404, 1, 0, 0, 0, 404, 406, 1, 0, 0, 0, 405, 403, 1, 0, 0, 0, 406, 407, 5, 69, 0, 0, 407, 420, 1, 0, 0, 0, 408, 409, 5, 68, 0, 0, 409, 414, 3, 92, 46, 0, 410, 411, 5, 38, 0, 0, 411, 413, 3, 92, 46, 0, 412, 410, 1, 0, 0, 0, 413, 416, 1, 0, 0, 0, 414, 412, 1, 0, 0, 0, 414, 415, 1, 0, 0, 0, 415, 417, 1, 0, 0, 0, 416, 414, 1, 0, 0, 0, 417, 418, 5, 69, 0, 0, 418, 420, 1, 0, 0, 0, 419, 377, 1, 0, 0, 0, 419, 378, 1, 0, 0, 0, 419, 381, 1, 0, 0, 0, 419, 382, 1, 0, 0, 0, 419, 383, 1, 0, 0, 0, 419, 384, 1, 0, 0, 0, 419, 385, 1, 0, 0, 0, 419, 386, 1, 0, 0, 0, 419, 397, 1, 0, 0, 0, 419, 408, 1, 0, 0, 0, 420, 59, 1, 0, 0, 0, 421, 422, 5, 10, 0, 0, 422, 423, 5, 31, 0, 0, 423, 61, 1, 0, 0, 0, 424, 425, 5, 18, 0, 0, 425, 430, 3, 64, 32, 0, 426, 427, 5, 38, 0, 0, 427, 429, 3, 64, 32, 0, 428, 426, 1, 0, 0, 0, 429, 432, 1, 0, 0, 0, 430, 428, 1, 0, 0, 0, 430, 431, 1, 0, 0, 0, 431, 63, 1, 0, 0, 0, 432, 430, 1, 0, 0, 0, 433, 435, 3, 10, 5, 0, 434, 436, 7, 3, 0, 0, 435, 434, 1, 0, 0, 0, 435, 436, 1, 0, 0, 0, 436, 439, 1, 0, 0, 0, 437, 438, 5, 50, 0, 0, 438, 440, 7, 4, 0, 0, 439, 437, 1, 0, 0, 0, 439, 440, 1, 0, 0, 0, 440, 65, 1, 0, 0, 0, 441, 442, 5, 9, 0, 0, 442, 443, 3, 52, 26, 0, 443, 67, 1, 0, 0, 0, 444, 445, 5, 2, 0, 0, 445, 446, 3, 52, 26, 0, 446, 69, 1, 0, 0, 0, 447, 448, 5, 15, 0, 0, 448, 453, 3, 72, 36, 0, 449, 450, 5, 38, 0, 0, 450, 452, 3, 72, 36, 0, 451, 449, 1, 0, 0, 0, 452, 455, 1, 0, 0, 0, 453, 451, 1, 0, 0, 0, 453, 454, 1, 0, 0, 0, 454, 71, 1, 0, 0, 0, 455, 453, 1, 0, 0, 0, 456, 457, 3, 50, 25, 0, 457, 458, 5, 83, 0, 0, 458, 459, 3, 50, 25, 0, 459, 73, 1, 0, 0, 0, 460, 461, 5, 1, 0, 0, 461, 462, 3, 18, 9, 0, 462, 464, 3, 92, 46, 0, 463, 465, 3, 80, 40, 0, 464, 463, 1, 0, 0, 0, 464, 465, 1, 0, 0, 0, 465, 75, 1, 0, 0, 0, 466, 467, 5, 7, 0, 0, 467, 468, 3, 18, 9, 0, 468, 469, 3, 92, 46, 0, 469, 77, 1, 0, 0, 0, 470, 471, 5, 14, 0, 0, 471, 472, 3, 48, 24, 0, 472, 79, 1, 0, 0, 0, 473, 478, 3, 82, 41, 0, 474, 475, 5, 38, 0, 0, 475, 477, 3, 82, 41, 0, 476, 474, 1, 0, 0, 0, 477, 480, 1, 0, 0, 0, 478, 476, 1, 0, 0, 0, 478, 479, 1, 0, 0, 0, 479, 81, 1, 0, 0, 0, 480, 478, 1, 0, 0, 0, 481, 482, 3, 54, 27, 0, 482, 483, 5, 36, 0, 0, 483, 484, 3, 58, 29, 0, 484, 83, 1, 0, 0, 0, 485, 486, 7, 5, 0, 0, 486, 85, 1, 0, 0, 0, 487, 490, 3, 88, 44, 0, 488, 490, 3, 90, 45, 0, 489, 487, 1, 0, 0, 0, 489, 488, 1, 0, 0, 0, 490, 87, 1, 0, 0, 0, 491, 493, 7, 0, 0, 0, 492, 491, 1, 0, 0, 0, 492, 493, 1, 0, 0, 0, 493, 494, 1, 0, 0, 0, 494, 495, 5, 32, 0, 0, 495, 89, 1, 0, 0, 0, 496, 498, 7, 0, 0, 0, 497, 496, 1, 0, 0, 0, 497, 498, 1, 0, 0, 0, 498, 499, 1, 0, 0, 0, 499, 500, 5, 31, 0, 0, 500, 91, 1, 0, 0, 0, 501, 502, 5, 30, 0, 0, 502, 93, 1, 0, 0, 0, 503, 504, 7, 6, 0, 0, 504, 95, 1, 0, 0, 0, 505, 506, 5, 5, 0, 0, 506, 507, 3, 98, 49, 0, 507, 97, 1, 0, 0, 0, 508, 509, 5, 68, 0, 0, 509, 510, 3, 2, 1, 0, 510, 511, 5, 69, 0, 0, 511, 99, 1, 0, 0, 0, 512, 513, 5, 17, 0, 0, 513, 514, 5, 105, 0, 0, 514, 101, 1, 0, 0, 0, 515, 516, 5, 12, 0, 0, 516, 517, 5, 109, 0, 0, 517, 103, 1, 0, 0, 0, 518, 519, 5, 3, 0, 0, 519, 522, 5, 89, 0, 0, 520, 521, 5, 87, 0, 0, 521, 523, 3, 50, 25, 0, 522, 520, 1, 0, 0, 0, 522, 523, 1, 0, 0, 0, 523, 533, 1, 0, 0, 0, 524, 525, 5, 88, 0, 0, 525, 530, 3, 106, 53, 0, 526, 527, 5, 38, 0, 0, 527, 529, 3, 106, 53, 0, 528, 526, 1, 0, 0, 0, 529, 532, 1, 0, 0, 0, 530, 528, 1, 0, 0, 0, 530, 531, 1, 0, 0, 0, 531, 534, 1, 0, 0, 0, 532, 530, 1, 0, 0, 0, 533, 524, 1, 0, 0, 0, 533, 534, 1, 0, 0, 0, 534, 105, 1, 0, 0, 0, 535, 536, 3, 50, 25, 0, 536, 537, 5, 36, 0, 0, 537, 539, 1, 0, 0, 0, 538, 535, 1, 0, 0, 0, 538, 539, 1, 0, 0, 0, 539, 540, 1, 0, 0, 0, 540, 541, 3, 50, 25, 0, 541, 107, 1, 0, 0, 0, 542, 543, 5, 11, 0, 0, 543, 544, 5, 25, 0, 0, 544, 545, 5, 87, 0, 0, 545, 546, 3, 52, 26, 0, 546, 109, 1, 0, 0, 0, 52, 121, 130, 146, 158, 167, 175, 179, 187, 189, 194, 201, 206, 213, 219, 227, 229, 240, 247, 258, 261, 275, 283, 291, 295, 301, 309, 322, 326, 330, 337, 341, 347, 354, 362, 370, 392, 403, 414, 419, 430, 435, 439, 453, 464, 478, 489, 492, 497, 522, 530, 533, 538] \ No newline at end of file diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java index 1d6be711f9814..1c136a946a0f3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java @@ -18,28 +18,30 @@ public class EsqlBaseParser extends Parser { new PredictionContextCache(); public static final int DISSECT=1, DROP=2, ENRICH=3, EVAL=4, EXPLAIN=5, FROM=6, GROK=7, INLINESTATS=8, - KEEP=9, LIMIT=10, META=11, METRICS=12, MV_EXPAND=13, RENAME=14, ROW=15, - SHOW=16, SORT=17, STATS=18, WHERE=19, UNKNOWN_CMD=20, LINE_COMMENT=21, - MULTILINE_COMMENT=22, WS=23, INDEX_UNQUOTED_IDENTIFIER=24, EXPLAIN_WS=25, - EXPLAIN_LINE_COMMENT=26, EXPLAIN_MULTILINE_COMMENT=27, PIPE=28, QUOTED_STRING=29, - INTEGER_LITERAL=30, DECIMAL_LITERAL=31, BY=32, AND=33, ASC=34, ASSIGN=35, - CAST_OP=36, COMMA=37, DESC=38, DOT=39, FALSE=40, FIRST=41, LAST=42, LP=43, - IN=44, IS=45, LIKE=46, NOT=47, NULL=48, NULLS=49, OR=50, PARAM=51, RLIKE=52, - RP=53, TRUE=54, EQ=55, CIEQ=56, NEQ=57, LT=58, LTE=59, GT=60, GTE=61, - PLUS=62, MINUS=63, ASTERISK=64, SLASH=65, PERCENT=66, OPENING_BRACKET=67, - CLOSING_BRACKET=68, UNQUOTED_IDENTIFIER=69, QUOTED_IDENTIFIER=70, EXPR_LINE_COMMENT=71, - EXPR_MULTILINE_COMMENT=72, EXPR_WS=73, METADATA=74, FROM_LINE_COMMENT=75, - FROM_MULTILINE_COMMENT=76, FROM_WS=77, ID_PATTERN=78, PROJECT_LINE_COMMENT=79, - PROJECT_MULTILINE_COMMENT=80, PROJECT_WS=81, AS=82, RENAME_LINE_COMMENT=83, - RENAME_MULTILINE_COMMENT=84, RENAME_WS=85, ON=86, WITH=87, ENRICH_POLICY_NAME=88, - ENRICH_LINE_COMMENT=89, ENRICH_MULTILINE_COMMENT=90, ENRICH_WS=91, ENRICH_FIELD_LINE_COMMENT=92, - ENRICH_FIELD_MULTILINE_COMMENT=93, ENRICH_FIELD_WS=94, MVEXPAND_LINE_COMMENT=95, - MVEXPAND_MULTILINE_COMMENT=96, MVEXPAND_WS=97, INFO=98, SHOW_LINE_COMMENT=99, - SHOW_MULTILINE_COMMENT=100, SHOW_WS=101, FUNCTIONS=102, META_LINE_COMMENT=103, - META_MULTILINE_COMMENT=104, META_WS=105, COLON=106, SETTING=107, SETTING_LINE_COMMENT=108, - SETTTING_MULTILINE_COMMENT=109, SETTING_WS=110, METRICS_LINE_COMMENT=111, - METRICS_MULTILINE_COMMENT=112, METRICS_WS=113, CLOSING_METRICS_LINE_COMMENT=114, - CLOSING_METRICS_MULTILINE_COMMENT=115, CLOSING_METRICS_WS=116; + KEEP=9, LIMIT=10, LOOKUP=11, META=12, METRICS=13, MV_EXPAND=14, RENAME=15, + ROW=16, SHOW=17, SORT=18, STATS=19, WHERE=20, UNKNOWN_CMD=21, LINE_COMMENT=22, + MULTILINE_COMMENT=23, WS=24, INDEX_UNQUOTED_IDENTIFIER=25, EXPLAIN_WS=26, + EXPLAIN_LINE_COMMENT=27, EXPLAIN_MULTILINE_COMMENT=28, PIPE=29, QUOTED_STRING=30, + INTEGER_LITERAL=31, DECIMAL_LITERAL=32, BY=33, AND=34, ASC=35, ASSIGN=36, + CAST_OP=37, COMMA=38, DESC=39, DOT=40, FALSE=41, FIRST=42, LAST=43, LP=44, + IN=45, IS=46, LIKE=47, NOT=48, NULL=49, NULLS=50, OR=51, PARAM=52, RLIKE=53, + RP=54, TRUE=55, EQ=56, CIEQ=57, NEQ=58, LT=59, LTE=60, GT=61, GTE=62, + PLUS=63, MINUS=64, ASTERISK=65, SLASH=66, PERCENT=67, OPENING_BRACKET=68, + CLOSING_BRACKET=69, UNQUOTED_IDENTIFIER=70, QUOTED_IDENTIFIER=71, EXPR_LINE_COMMENT=72, + EXPR_MULTILINE_COMMENT=73, EXPR_WS=74, METADATA=75, FROM_LINE_COMMENT=76, + FROM_MULTILINE_COMMENT=77, FROM_WS=78, ID_PATTERN=79, PROJECT_LINE_COMMENT=80, + PROJECT_MULTILINE_COMMENT=81, PROJECT_WS=82, AS=83, RENAME_LINE_COMMENT=84, + RENAME_MULTILINE_COMMENT=85, RENAME_WS=86, ON=87, WITH=88, ENRICH_POLICY_NAME=89, + ENRICH_LINE_COMMENT=90, ENRICH_MULTILINE_COMMENT=91, ENRICH_WS=92, ENRICH_FIELD_LINE_COMMENT=93, + ENRICH_FIELD_MULTILINE_COMMENT=94, ENRICH_FIELD_WS=95, LOOKUP_LINE_COMMENT=96, + LOOKUP_MULTILINE_COMMENT=97, LOOKUP_WS=98, LOOKUP_FIELD_LINE_COMMENT=99, + LOOKUP_FIELD_MULTILINE_COMMENT=100, LOOKUP_FIELD_WS=101, MVEXPAND_LINE_COMMENT=102, + MVEXPAND_MULTILINE_COMMENT=103, MVEXPAND_WS=104, INFO=105, SHOW_LINE_COMMENT=106, + SHOW_MULTILINE_COMMENT=107, SHOW_WS=108, FUNCTIONS=109, META_LINE_COMMENT=110, + META_MULTILINE_COMMENT=111, META_WS=112, COLON=113, SETTING=114, SETTING_LINE_COMMENT=115, + SETTTING_MULTILINE_COMMENT=116, SETTING_WS=117, METRICS_LINE_COMMENT=118, + METRICS_MULTILINE_COMMENT=119, METRICS_WS=120, CLOSING_METRICS_LINE_COMMENT=121, + CLOSING_METRICS_MULTILINE_COMMENT=122, CLOSING_METRICS_WS=123; public static final int RULE_singleStatement = 0, RULE_query = 1, RULE_sourceCommand = 2, RULE_processingCommand = 3, RULE_whereCommand = 4, RULE_booleanExpression = 5, RULE_regexBooleanExpression = 6, @@ -49,15 +51,16 @@ public class EsqlBaseParser extends Parser { RULE_metadata = 17, RULE_metadataOption = 18, RULE_deprecated_metadata = 19, RULE_metricsCommand = 20, RULE_evalCommand = 21, RULE_statsCommand = 22, RULE_inlinestatsCommand = 23, RULE_qualifiedName = 24, RULE_qualifiedNamePattern = 25, - RULE_identifier = 26, RULE_identifierPattern = 27, RULE_constant = 28, - RULE_limitCommand = 29, RULE_sortCommand = 30, RULE_orderExpression = 31, - RULE_keepCommand = 32, RULE_dropCommand = 33, RULE_renameCommand = 34, - RULE_renameClause = 35, RULE_dissectCommand = 36, RULE_grokCommand = 37, - RULE_mvExpandCommand = 38, RULE_commandOptions = 39, RULE_commandOption = 40, - RULE_booleanValue = 41, RULE_numericValue = 42, RULE_decimalValue = 43, - RULE_integerValue = 44, RULE_string = 45, RULE_comparisonOperator = 46, - RULE_explainCommand = 47, RULE_subqueryExpression = 48, RULE_showCommand = 49, - RULE_metaCommand = 50, RULE_enrichCommand = 51, RULE_enrichWithClause = 52; + RULE_qualifiedNamePatterns = 26, RULE_identifier = 27, RULE_identifierPattern = 28, + RULE_constant = 29, RULE_limitCommand = 30, RULE_sortCommand = 31, RULE_orderExpression = 32, + RULE_keepCommand = 33, RULE_dropCommand = 34, RULE_renameCommand = 35, + RULE_renameClause = 36, RULE_dissectCommand = 37, RULE_grokCommand = 38, + RULE_mvExpandCommand = 39, RULE_commandOptions = 40, RULE_commandOption = 41, + RULE_booleanValue = 42, RULE_numericValue = 43, RULE_decimalValue = 44, + RULE_integerValue = 45, RULE_string = 46, RULE_comparisonOperator = 47, + RULE_explainCommand = 48, RULE_subqueryExpression = 49, RULE_showCommand = 50, + RULE_metaCommand = 51, RULE_enrichCommand = 52, RULE_enrichWithClause = 53, + RULE_lookupCommand = 54; private static String[] makeRuleNames() { return new String[] { "singleStatement", "query", "sourceCommand", "processingCommand", "whereCommand", @@ -65,13 +68,13 @@ private static String[] makeRuleNames() { "primaryExpression", "functionExpression", "dataType", "rowCommand", "fields", "field", "fromCommand", "indexIdentifier", "metadata", "metadataOption", "deprecated_metadata", "metricsCommand", "evalCommand", "statsCommand", - "inlinestatsCommand", "qualifiedName", "qualifiedNamePattern", "identifier", - "identifierPattern", "constant", "limitCommand", "sortCommand", "orderExpression", - "keepCommand", "dropCommand", "renameCommand", "renameClause", "dissectCommand", - "grokCommand", "mvExpandCommand", "commandOptions", "commandOption", - "booleanValue", "numericValue", "decimalValue", "integerValue", "string", - "comparisonOperator", "explainCommand", "subqueryExpression", "showCommand", - "metaCommand", "enrichCommand", "enrichWithClause" + "inlinestatsCommand", "qualifiedName", "qualifiedNamePattern", "qualifiedNamePatterns", + "identifier", "identifierPattern", "constant", "limitCommand", "sortCommand", + "orderExpression", "keepCommand", "dropCommand", "renameCommand", "renameClause", + "dissectCommand", "grokCommand", "mvExpandCommand", "commandOptions", + "commandOption", "booleanValue", "numericValue", "decimalValue", "integerValue", + "string", "comparisonOperator", "explainCommand", "subqueryExpression", + "showCommand", "metaCommand", "enrichCommand", "enrichWithClause", "lookupCommand" }; } public static final String[] ruleNames = makeRuleNames(); @@ -79,25 +82,26 @@ private static String[] makeRuleNames() { private static String[] makeLiteralNames() { return new String[] { null, "'dissect'", "'drop'", "'enrich'", "'eval'", "'explain'", "'from'", - "'grok'", "'inlinestats'", "'keep'", "'limit'", "'meta'", "'metrics'", - "'mv_expand'", "'rename'", "'row'", "'show'", "'sort'", "'stats'", "'where'", - null, null, null, null, null, null, null, null, "'|'", null, null, null, - "'by'", "'and'", "'asc'", "'='", "'::'", "','", "'desc'", "'.'", "'false'", - "'first'", "'last'", "'('", "'in'", "'is'", "'like'", "'not'", "'null'", - "'nulls'", "'or'", "'?'", "'rlike'", "')'", "'true'", "'=='", "'=~'", - "'!='", "'<'", "'<='", "'>'", "'>='", "'+'", "'-'", "'*'", "'/'", "'%'", - null, "']'", null, null, null, null, null, "'metadata'", null, null, - null, null, null, null, null, "'as'", null, null, null, "'on'", "'with'", - null, null, null, null, null, null, null, null, null, null, "'info'", - null, null, null, "'functions'", null, null, null, "':'" + "'grok'", "'inlinestats'", "'keep'", "'limit'", "'lookup'", "'meta'", + "'metrics'", "'mv_expand'", "'rename'", "'row'", "'show'", "'sort'", + "'stats'", "'where'", null, null, null, null, null, null, null, null, + "'|'", null, null, null, "'by'", "'and'", "'asc'", "'='", "'::'", "','", + "'desc'", "'.'", "'false'", "'first'", "'last'", "'('", "'in'", "'is'", + "'like'", "'not'", "'null'", "'nulls'", "'or'", "'?'", "'rlike'", "')'", + "'true'", "'=='", "'=~'", "'!='", "'<'", "'<='", "'>'", "'>='", "'+'", + "'-'", "'*'", "'/'", "'%'", null, "']'", null, null, null, null, null, + "'metadata'", null, null, null, null, null, null, null, "'as'", null, + null, null, "'on'", "'with'", null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, "'info'", null, + null, null, "'functions'", null, null, null, "':'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static String[] makeSymbolicNames() { return new String[] { null, "DISSECT", "DROP", "ENRICH", "EVAL", "EXPLAIN", "FROM", "GROK", - "INLINESTATS", "KEEP", "LIMIT", "META", "METRICS", "MV_EXPAND", "RENAME", - "ROW", "SHOW", "SORT", "STATS", "WHERE", "UNKNOWN_CMD", "LINE_COMMENT", + "INLINESTATS", "KEEP", "LIMIT", "LOOKUP", "META", "METRICS", "MV_EXPAND", + "RENAME", "ROW", "SHOW", "SORT", "STATS", "WHERE", "UNKNOWN_CMD", "LINE_COMMENT", "MULTILINE_COMMENT", "WS", "INDEX_UNQUOTED_IDENTIFIER", "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", "EXPLAIN_MULTILINE_COMMENT", "PIPE", "QUOTED_STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "AND", "ASC", "ASSIGN", "CAST_OP", @@ -111,7 +115,9 @@ private static String[] makeSymbolicNames() { "AS", "RENAME_LINE_COMMENT", "RENAME_MULTILINE_COMMENT", "RENAME_WS", "ON", "WITH", "ENRICH_POLICY_NAME", "ENRICH_LINE_COMMENT", "ENRICH_MULTILINE_COMMENT", "ENRICH_WS", "ENRICH_FIELD_LINE_COMMENT", "ENRICH_FIELD_MULTILINE_COMMENT", - "ENRICH_FIELD_WS", "MVEXPAND_LINE_COMMENT", "MVEXPAND_MULTILINE_COMMENT", + "ENRICH_FIELD_WS", "LOOKUP_LINE_COMMENT", "LOOKUP_MULTILINE_COMMENT", + "LOOKUP_WS", "LOOKUP_FIELD_LINE_COMMENT", "LOOKUP_FIELD_MULTILINE_COMMENT", + "LOOKUP_FIELD_WS", "MVEXPAND_LINE_COMMENT", "MVEXPAND_MULTILINE_COMMENT", "MVEXPAND_WS", "INFO", "SHOW_LINE_COMMENT", "SHOW_MULTILINE_COMMENT", "SHOW_WS", "FUNCTIONS", "META_LINE_COMMENT", "META_MULTILINE_COMMENT", "META_WS", "COLON", "SETTING", "SETTING_LINE_COMMENT", "SETTTING_MULTILINE_COMMENT", @@ -204,9 +210,9 @@ public final SingleStatementContext singleStatement() throws RecognitionExceptio try { enterOuterAlt(_localctx, 1); { - setState(106); + setState(110); query(0); - setState(107); + setState(111); match(EOF); } } @@ -302,11 +308,11 @@ private QueryContext query(int _p) throws RecognitionException { _ctx = _localctx; _prevctx = _localctx; - setState(110); + setState(114); sourceCommand(); } _ctx.stop = _input.LT(-1); - setState(117); + setState(121); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,0,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { @@ -317,16 +323,16 @@ private QueryContext query(int _p) throws RecognitionException { { _localctx = new CompositeQueryContext(new QueryContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_query); - setState(112); + setState(116); if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)"); - setState(113); + setState(117); match(PIPE); - setState(114); + setState(118); processingCommand(); } } } - setState(119); + setState(123); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,0,_ctx); } @@ -387,48 +393,48 @@ public final SourceCommandContext sourceCommand() throws RecognitionException { SourceCommandContext _localctx = new SourceCommandContext(_ctx, getState()); enterRule(_localctx, 4, RULE_sourceCommand); try { - setState(126); + setState(130); _errHandler.sync(this); switch (_input.LA(1)) { case EXPLAIN: enterOuterAlt(_localctx, 1); { - setState(120); + setState(124); explainCommand(); } break; case FROM: enterOuterAlt(_localctx, 2); { - setState(121); + setState(125); fromCommand(); } break; case ROW: enterOuterAlt(_localctx, 3); { - setState(122); + setState(126); rowCommand(); } break; case METRICS: enterOuterAlt(_localctx, 4); { - setState(123); + setState(127); metricsCommand(); } break; case SHOW: enterOuterAlt(_localctx, 5); { - setState(124); + setState(128); showCommand(); } break; case META: enterOuterAlt(_localctx, 6); { - setState(125); + setState(129); metaCommand(); } break; @@ -458,6 +464,9 @@ public InlinestatsCommandContext inlinestatsCommand() { public LimitCommandContext limitCommand() { return getRuleContext(LimitCommandContext.class,0); } + public LookupCommandContext lookupCommand() { + return getRuleContext(LookupCommandContext.class,0); + } public KeepCommandContext keepCommand() { return getRuleContext(KeepCommandContext.class,0); } @@ -512,97 +521,104 @@ public final ProcessingCommandContext processingCommand() throws RecognitionExce ProcessingCommandContext _localctx = new ProcessingCommandContext(_ctx, getState()); enterRule(_localctx, 6, RULE_processingCommand); try { - setState(141); + setState(146); _errHandler.sync(this); switch (_input.LA(1)) { case EVAL: enterOuterAlt(_localctx, 1); { - setState(128); + setState(132); evalCommand(); } break; case INLINESTATS: enterOuterAlt(_localctx, 2); { - setState(129); + setState(133); inlinestatsCommand(); } break; case LIMIT: enterOuterAlt(_localctx, 3); { - setState(130); + setState(134); limitCommand(); } break; - case KEEP: + case LOOKUP: enterOuterAlt(_localctx, 4); { - setState(131); + setState(135); + lookupCommand(); + } + break; + case KEEP: + enterOuterAlt(_localctx, 5); + { + setState(136); keepCommand(); } break; case SORT: - enterOuterAlt(_localctx, 5); + enterOuterAlt(_localctx, 6); { - setState(132); + setState(137); sortCommand(); } break; case STATS: - enterOuterAlt(_localctx, 6); + enterOuterAlt(_localctx, 7); { - setState(133); + setState(138); statsCommand(); } break; case WHERE: - enterOuterAlt(_localctx, 7); + enterOuterAlt(_localctx, 8); { - setState(134); + setState(139); whereCommand(); } break; case DROP: - enterOuterAlt(_localctx, 8); + enterOuterAlt(_localctx, 9); { - setState(135); + setState(140); dropCommand(); } break; case RENAME: - enterOuterAlt(_localctx, 9); + enterOuterAlt(_localctx, 10); { - setState(136); + setState(141); renameCommand(); } break; case DISSECT: - enterOuterAlt(_localctx, 10); + enterOuterAlt(_localctx, 11); { - setState(137); + setState(142); dissectCommand(); } break; case GROK: - enterOuterAlt(_localctx, 11); + enterOuterAlt(_localctx, 12); { - setState(138); + setState(143); grokCommand(); } break; case ENRICH: - enterOuterAlt(_localctx, 12); + enterOuterAlt(_localctx, 13); { - setState(139); + setState(144); enrichCommand(); } break; case MV_EXPAND: - enterOuterAlt(_localctx, 13); + enterOuterAlt(_localctx, 14); { - setState(140); + setState(145); mvExpandCommand(); } break; @@ -653,9 +669,9 @@ public final WhereCommandContext whereCommand() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(143); + setState(148); match(WHERE); - setState(144); + setState(149); booleanExpression(0); } } @@ -850,7 +866,7 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc int _alt; enterOuterAlt(_localctx, 1); { - setState(174); + setState(179); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,6,_ctx) ) { case 1: @@ -859,9 +875,9 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _ctx = _localctx; _prevctx = _localctx; - setState(147); + setState(152); match(NOT); - setState(148); + setState(153); booleanExpression(7); } break; @@ -870,7 +886,7 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _localctx = new BooleanDefaultContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(149); + setState(154); valueExpression(); } break; @@ -879,7 +895,7 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _localctx = new RegexExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(150); + setState(155); regexBooleanExpression(); } break; @@ -888,41 +904,41 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _localctx = new LogicalInContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(151); + setState(156); valueExpression(); - setState(153); + setState(158); _errHandler.sync(this); _la = _input.LA(1); if (_la==NOT) { { - setState(152); + setState(157); match(NOT); } } - setState(155); + setState(160); match(IN); - setState(156); + setState(161); match(LP); - setState(157); - valueExpression(); setState(162); + valueExpression(); + setState(167); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(158); + setState(163); match(COMMA); - setState(159); + setState(164); valueExpression(); } } - setState(164); + setState(169); _errHandler.sync(this); _la = _input.LA(1); } - setState(165); + setState(170); match(RP); } break; @@ -931,27 +947,27 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _localctx = new IsNullContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(167); + setState(172); valueExpression(); - setState(168); + setState(173); match(IS); - setState(170); + setState(175); _errHandler.sync(this); _la = _input.LA(1); if (_la==NOT) { { - setState(169); + setState(174); match(NOT); } } - setState(172); + setState(177); match(NULL); } break; } _ctx.stop = _input.LT(-1); - setState(184); + setState(189); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,8,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { @@ -959,7 +975,7 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc if ( _parseListeners!=null ) triggerExitRuleEvent(); _prevctx = _localctx; { - setState(182); + setState(187); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,7,_ctx) ) { case 1: @@ -967,11 +983,11 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _localctx = new LogicalBinaryContext(new BooleanExpressionContext(_parentctx, _parentState)); ((LogicalBinaryContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_booleanExpression); - setState(176); + setState(181); if (!(precpred(_ctx, 4))) throw new FailedPredicateException(this, "precpred(_ctx, 4)"); - setState(177); + setState(182); ((LogicalBinaryContext)_localctx).operator = match(AND); - setState(178); + setState(183); ((LogicalBinaryContext)_localctx).right = booleanExpression(5); } break; @@ -980,18 +996,18 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc _localctx = new LogicalBinaryContext(new BooleanExpressionContext(_parentctx, _parentState)); ((LogicalBinaryContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_booleanExpression); - setState(179); + setState(184); if (!(precpred(_ctx, 3))) throw new FailedPredicateException(this, "precpred(_ctx, 3)"); - setState(180); + setState(185); ((LogicalBinaryContext)_localctx).operator = match(OR); - setState(181); + setState(186); ((LogicalBinaryContext)_localctx).right = booleanExpression(4); } break; } } } - setState(186); + setState(191); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,8,_ctx); } @@ -1046,48 +1062,48 @@ public final RegexBooleanExpressionContext regexBooleanExpression() throws Recog enterRule(_localctx, 12, RULE_regexBooleanExpression); int _la; try { - setState(201); + setState(206); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,11,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(187); + setState(192); valueExpression(); - setState(189); + setState(194); _errHandler.sync(this); _la = _input.LA(1); if (_la==NOT) { { - setState(188); + setState(193); match(NOT); } } - setState(191); + setState(196); ((RegexBooleanExpressionContext)_localctx).kind = match(LIKE); - setState(192); + setState(197); ((RegexBooleanExpressionContext)_localctx).pattern = string(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(194); + setState(199); valueExpression(); - setState(196); + setState(201); _errHandler.sync(this); _la = _input.LA(1); if (_la==NOT) { { - setState(195); + setState(200); match(NOT); } } - setState(198); + setState(203); ((RegexBooleanExpressionContext)_localctx).kind = match(RLIKE); - setState(199); + setState(204); ((RegexBooleanExpressionContext)_localctx).pattern = string(); } break; @@ -1173,14 +1189,14 @@ public final ValueExpressionContext valueExpression() throws RecognitionExceptio ValueExpressionContext _localctx = new ValueExpressionContext(_ctx, getState()); enterRule(_localctx, 14, RULE_valueExpression); try { - setState(208); + setState(213); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,12,_ctx) ) { case 1: _localctx = new ValueExpressionDefaultContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(203); + setState(208); operatorExpression(0); } break; @@ -1188,11 +1204,11 @@ public final ValueExpressionContext valueExpression() throws RecognitionExceptio _localctx = new ComparisonContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(204); + setState(209); ((ComparisonContext)_localctx).left = operatorExpression(0); - setState(205); + setState(210); comparisonOperator(); - setState(206); + setState(211); ((ComparisonContext)_localctx).right = operatorExpression(0); } break; @@ -1317,7 +1333,7 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE int _alt; enterOuterAlt(_localctx, 1); { - setState(214); + setState(219); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,13,_ctx) ) { case 1: @@ -1326,7 +1342,7 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE _ctx = _localctx; _prevctx = _localctx; - setState(211); + setState(216); primaryExpression(0); } break; @@ -1335,7 +1351,7 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE _localctx = new ArithmeticUnaryContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(212); + setState(217); ((ArithmeticUnaryContext)_localctx).operator = _input.LT(1); _la = _input.LA(1); if ( !(_la==PLUS || _la==MINUS) ) { @@ -1346,13 +1362,13 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE _errHandler.reportMatch(this); consume(); } - setState(213); + setState(218); operatorExpression(3); } break; } _ctx.stop = _input.LT(-1); - setState(224); + setState(229); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,15,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { @@ -1360,7 +1376,7 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE if ( _parseListeners!=null ) triggerExitRuleEvent(); _prevctx = _localctx; { - setState(222); + setState(227); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,14,_ctx) ) { case 1: @@ -1368,12 +1384,12 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE _localctx = new ArithmeticBinaryContext(new OperatorExpressionContext(_parentctx, _parentState)); ((ArithmeticBinaryContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_operatorExpression); - setState(216); + setState(221); if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)"); - setState(217); + setState(222); ((ArithmeticBinaryContext)_localctx).operator = _input.LT(1); _la = _input.LA(1); - if ( !(((((_la - 64)) & ~0x3f) == 0 && ((1L << (_la - 64)) & 7L) != 0)) ) { + if ( !(((((_la - 65)) & ~0x3f) == 0 && ((1L << (_la - 65)) & 7L) != 0)) ) { ((ArithmeticBinaryContext)_localctx).operator = (Token)_errHandler.recoverInline(this); } else { @@ -1381,7 +1397,7 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE _errHandler.reportMatch(this); consume(); } - setState(218); + setState(223); ((ArithmeticBinaryContext)_localctx).right = operatorExpression(3); } break; @@ -1390,9 +1406,9 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE _localctx = new ArithmeticBinaryContext(new OperatorExpressionContext(_parentctx, _parentState)); ((ArithmeticBinaryContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_operatorExpression); - setState(219); + setState(224); if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)"); - setState(220); + setState(225); ((ArithmeticBinaryContext)_localctx).operator = _input.LT(1); _la = _input.LA(1); if ( !(_la==PLUS || _la==MINUS) ) { @@ -1403,14 +1419,14 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE _errHandler.reportMatch(this); consume(); } - setState(221); + setState(226); ((ArithmeticBinaryContext)_localctx).right = operatorExpression(2); } break; } } } - setState(226); + setState(231); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,15,_ctx); } @@ -1568,7 +1584,7 @@ private PrimaryExpressionContext primaryExpression(int _p) throws RecognitionExc int _alt; enterOuterAlt(_localctx, 1); { - setState(235); + setState(240); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,16,_ctx) ) { case 1: @@ -1577,7 +1593,7 @@ private PrimaryExpressionContext primaryExpression(int _p) throws RecognitionExc _ctx = _localctx; _prevctx = _localctx; - setState(228); + setState(233); constant(); } break; @@ -1586,7 +1602,7 @@ private PrimaryExpressionContext primaryExpression(int _p) throws RecognitionExc _localctx = new DereferenceContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(229); + setState(234); qualifiedName(); } break; @@ -1595,7 +1611,7 @@ private PrimaryExpressionContext primaryExpression(int _p) throws RecognitionExc _localctx = new FunctionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(230); + setState(235); functionExpression(); } break; @@ -1604,17 +1620,17 @@ private PrimaryExpressionContext primaryExpression(int _p) throws RecognitionExc _localctx = new ParenthesizedExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(231); + setState(236); match(LP); - setState(232); + setState(237); booleanExpression(0); - setState(233); + setState(238); match(RP); } break; } _ctx.stop = _input.LT(-1); - setState(242); + setState(247); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,17,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { @@ -1625,16 +1641,16 @@ private PrimaryExpressionContext primaryExpression(int _p) throws RecognitionExc { _localctx = new InlineCastContext(new PrimaryExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_primaryExpression); - setState(237); + setState(242); if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)"); - setState(238); + setState(243); match(CAST_OP); - setState(239); + setState(244); dataType(); } } } - setState(244); + setState(249); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,17,_ctx); } @@ -1696,16 +1712,16 @@ public final FunctionExpressionContext functionExpression() throws RecognitionEx try { enterOuterAlt(_localctx, 1); { - setState(245); + setState(250); identifier(); - setState(246); + setState(251); match(LP); - setState(256); + setState(261); _errHandler.sync(this); switch (_input.LA(1)) { case ASTERISK: { - setState(247); + setState(252); match(ASTERISK); } break; @@ -1725,21 +1741,21 @@ public final FunctionExpressionContext functionExpression() throws RecognitionEx case QUOTED_IDENTIFIER: { { - setState(248); - booleanExpression(0); setState(253); + booleanExpression(0); + setState(258); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(249); + setState(254); match(COMMA); - setState(250); + setState(255); booleanExpression(0); } } - setState(255); + setState(260); _errHandler.sync(this); _la = _input.LA(1); } @@ -1751,7 +1767,7 @@ public final FunctionExpressionContext functionExpression() throws RecognitionEx default: break; } - setState(258); + setState(263); match(RP); } } @@ -1809,7 +1825,7 @@ public final DataTypeContext dataType() throws RecognitionException { _localctx = new ToDataTypeContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(260); + setState(265); identifier(); } } @@ -1856,9 +1872,9 @@ public final RowCommandContext rowCommand() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(262); + setState(267); match(ROW); - setState(263); + setState(268); fields(); } } @@ -1912,23 +1928,23 @@ public final FieldsContext fields() throws RecognitionException { int _alt; enterOuterAlt(_localctx, 1); { - setState(265); - field(); setState(270); + field(); + setState(275); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,20,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(266); + setState(271); match(COMMA); - setState(267); + setState(272); field(); } } } - setState(272); + setState(277); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,20,_ctx); } @@ -1978,24 +1994,24 @@ public final FieldContext field() throws RecognitionException { FieldContext _localctx = new FieldContext(_ctx, getState()); enterRule(_localctx, 28, RULE_field); try { - setState(278); + setState(283); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,21,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(273); + setState(278); booleanExpression(0); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(274); + setState(279); qualifiedName(); - setState(275); + setState(280); match(ASSIGN); - setState(276); + setState(281); booleanExpression(0); } break; @@ -2055,34 +2071,34 @@ public final FromCommandContext fromCommand() throws RecognitionException { int _alt; enterOuterAlt(_localctx, 1); { - setState(280); + setState(285); match(FROM); - setState(281); - indexIdentifier(); setState(286); + indexIdentifier(); + setState(291); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,22,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(282); + setState(287); match(COMMA); - setState(283); + setState(288); indexIdentifier(); } } } - setState(288); + setState(293); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,22,_ctx); } - setState(290); + setState(295); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,23,_ctx) ) { case 1: { - setState(289); + setState(294); metadata(); } break; @@ -2129,7 +2145,7 @@ public final IndexIdentifierContext indexIdentifier() throws RecognitionExceptio try { enterOuterAlt(_localctx, 1); { - setState(292); + setState(297); match(INDEX_UNQUOTED_IDENTIFIER); } } @@ -2176,20 +2192,20 @@ public final MetadataContext metadata() throws RecognitionException { MetadataContext _localctx = new MetadataContext(_ctx, getState()); enterRule(_localctx, 34, RULE_metadata); try { - setState(296); + setState(301); _errHandler.sync(this); switch (_input.LA(1)) { case METADATA: enterOuterAlt(_localctx, 1); { - setState(294); + setState(299); metadataOption(); } break; case OPENING_BRACKET: enterOuterAlt(_localctx, 2); { - setState(295); + setState(300); deprecated_metadata(); } break; @@ -2248,25 +2264,25 @@ public final MetadataOptionContext metadataOption() throws RecognitionException int _alt; enterOuterAlt(_localctx, 1); { - setState(298); + setState(303); match(METADATA); - setState(299); - indexIdentifier(); setState(304); + indexIdentifier(); + setState(309); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,25,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(300); + setState(305); match(COMMA); - setState(301); + setState(306); indexIdentifier(); } } } - setState(306); + setState(311); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,25,_ctx); } @@ -2315,11 +2331,11 @@ public final Deprecated_metadataContext deprecated_metadata() throws Recognition try { enterOuterAlt(_localctx, 1); { - setState(307); + setState(312); match(OPENING_BRACKET); - setState(308); + setState(313); metadataOption(); - setState(309); + setState(314); match(CLOSING_BRACKET); } } @@ -2383,46 +2399,46 @@ public final MetricsCommandContext metricsCommand() throws RecognitionException int _alt; enterOuterAlt(_localctx, 1); { - setState(311); + setState(316); match(METRICS); - setState(312); - indexIdentifier(); setState(317); + indexIdentifier(); + setState(322); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,26,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(313); + setState(318); match(COMMA); - setState(314); + setState(319); indexIdentifier(); } } } - setState(319); + setState(324); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,26,_ctx); } - setState(321); + setState(326); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,27,_ctx) ) { case 1: { - setState(320); + setState(325); ((MetricsCommandContext)_localctx).aggregates = fields(); } break; } - setState(325); + setState(330); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,28,_ctx) ) { case 1: { - setState(323); + setState(328); match(BY); - setState(324); + setState(329); ((MetricsCommandContext)_localctx).grouping = fields(); } break; @@ -2472,9 +2488,9 @@ public final EvalCommandContext evalCommand() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(327); + setState(332); match(EVAL); - setState(328); + setState(333); fields(); } } @@ -2527,26 +2543,26 @@ public final StatsCommandContext statsCommand() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(330); + setState(335); match(STATS); - setState(332); + setState(337); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,29,_ctx) ) { case 1: { - setState(331); + setState(336); ((StatsCommandContext)_localctx).stats = fields(); } break; } - setState(336); + setState(341); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,30,_ctx) ) { case 1: { - setState(334); + setState(339); match(BY); - setState(335); + setState(340); ((StatsCommandContext)_localctx).grouping = fields(); } break; @@ -2602,18 +2618,18 @@ public final InlinestatsCommandContext inlinestatsCommand() throws RecognitionEx try { enterOuterAlt(_localctx, 1); { - setState(338); + setState(343); match(INLINESTATS); - setState(339); + setState(344); ((InlinestatsCommandContext)_localctx).stats = fields(); - setState(342); + setState(347); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,31,_ctx) ) { case 1: { - setState(340); + setState(345); match(BY); - setState(341); + setState(346); ((InlinestatsCommandContext)_localctx).grouping = fields(); } break; @@ -2670,23 +2686,23 @@ public final QualifiedNameContext qualifiedName() throws RecognitionException { int _alt; enterOuterAlt(_localctx, 1); { - setState(344); - identifier(); setState(349); + identifier(); + setState(354); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,32,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(345); + setState(350); match(DOT); - setState(346); + setState(351); identifier(); } } } - setState(351); + setState(356); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,32,_ctx); } @@ -2742,23 +2758,23 @@ public final QualifiedNamePatternContext qualifiedNamePattern() throws Recogniti int _alt; enterOuterAlt(_localctx, 1); { - setState(352); - identifierPattern(); setState(357); + identifierPattern(); + setState(362); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,33,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(353); + setState(358); match(DOT); - setState(354); + setState(359); identifierPattern(); } } } - setState(359); + setState(364); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,33,_ctx); } @@ -2775,6 +2791,78 @@ public final QualifiedNamePatternContext qualifiedNamePattern() throws Recogniti return _localctx; } + @SuppressWarnings("CheckReturnValue") + public static class QualifiedNamePatternsContext extends ParserRuleContext { + public List qualifiedNamePattern() { + return getRuleContexts(QualifiedNamePatternContext.class); + } + public QualifiedNamePatternContext qualifiedNamePattern(int i) { + return getRuleContext(QualifiedNamePatternContext.class,i); + } + public List COMMA() { return getTokens(EsqlBaseParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(EsqlBaseParser.COMMA, i); + } + @SuppressWarnings("this-escape") + public QualifiedNamePatternsContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_qualifiedNamePatterns; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof EsqlBaseParserListener ) ((EsqlBaseParserListener)listener).enterQualifiedNamePatterns(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof EsqlBaseParserListener ) ((EsqlBaseParserListener)listener).exitQualifiedNamePatterns(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof EsqlBaseParserVisitor ) return ((EsqlBaseParserVisitor)visitor).visitQualifiedNamePatterns(this); + else return visitor.visitChildren(this); + } + } + + public final QualifiedNamePatternsContext qualifiedNamePatterns() throws RecognitionException { + QualifiedNamePatternsContext _localctx = new QualifiedNamePatternsContext(_ctx, getState()); + enterRule(_localctx, 52, RULE_qualifiedNamePatterns); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(365); + qualifiedNamePattern(); + setState(370); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,34,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(366); + match(COMMA); + setState(367); + qualifiedNamePattern(); + } + } + } + setState(372); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,34,_ctx); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + @SuppressWarnings("CheckReturnValue") public static class IdentifierContext extends ParserRuleContext { public TerminalNode UNQUOTED_IDENTIFIER() { return getToken(EsqlBaseParser.UNQUOTED_IDENTIFIER, 0); } @@ -2801,12 +2889,12 @@ public T accept(ParseTreeVisitor visitor) { public final IdentifierContext identifier() throws RecognitionException { IdentifierContext _localctx = new IdentifierContext(_ctx, getState()); - enterRule(_localctx, 52, RULE_identifier); + enterRule(_localctx, 54, RULE_identifier); int _la; try { enterOuterAlt(_localctx, 1); { - setState(360); + setState(373); _la = _input.LA(1); if ( !(_la==UNQUOTED_IDENTIFIER || _la==QUOTED_IDENTIFIER) ) { _errHandler.recoverInline(this); @@ -2854,11 +2942,11 @@ public T accept(ParseTreeVisitor visitor) { public final IdentifierPatternContext identifierPattern() throws RecognitionException { IdentifierPatternContext _localctx = new IdentifierPatternContext(_ctx, getState()); - enterRule(_localctx, 54, RULE_identifierPattern); + enterRule(_localctx, 56, RULE_identifierPattern); try { enterOuterAlt(_localctx, 1); { - setState(362); + setState(375); match(ID_PATTERN); } } @@ -3124,17 +3212,17 @@ public T accept(ParseTreeVisitor visitor) { public final ConstantContext constant() throws RecognitionException { ConstantContext _localctx = new ConstantContext(_ctx, getState()); - enterRule(_localctx, 56, RULE_constant); + enterRule(_localctx, 58, RULE_constant); int _la; try { - setState(406); + setState(419); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,37,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,38,_ctx) ) { case 1: _localctx = new NullLiteralContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(364); + setState(377); match(NULL); } break; @@ -3142,9 +3230,9 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new QualifiedIntegerLiteralContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(365); + setState(378); integerValue(); - setState(366); + setState(379); match(UNQUOTED_IDENTIFIER); } break; @@ -3152,7 +3240,7 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new DecimalLiteralContext(_localctx); enterOuterAlt(_localctx, 3); { - setState(368); + setState(381); decimalValue(); } break; @@ -3160,7 +3248,7 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new IntegerLiteralContext(_localctx); enterOuterAlt(_localctx, 4); { - setState(369); + setState(382); integerValue(); } break; @@ -3168,7 +3256,7 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new BooleanLiteralContext(_localctx); enterOuterAlt(_localctx, 5); { - setState(370); + setState(383); booleanValue(); } break; @@ -3176,7 +3264,7 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new InputParamContext(_localctx); enterOuterAlt(_localctx, 6); { - setState(371); + setState(384); match(PARAM); } break; @@ -3184,7 +3272,7 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new StringLiteralContext(_localctx); enterOuterAlt(_localctx, 7); { - setState(372); + setState(385); string(); } break; @@ -3192,27 +3280,27 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new NumericArrayLiteralContext(_localctx); enterOuterAlt(_localctx, 8); { - setState(373); + setState(386); match(OPENING_BRACKET); - setState(374); + setState(387); numericValue(); - setState(379); + setState(392); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(375); + setState(388); match(COMMA); - setState(376); + setState(389); numericValue(); } } - setState(381); + setState(394); _errHandler.sync(this); _la = _input.LA(1); } - setState(382); + setState(395); match(CLOSING_BRACKET); } break; @@ -3220,27 +3308,27 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new BooleanArrayLiteralContext(_localctx); enterOuterAlt(_localctx, 9); { - setState(384); + setState(397); match(OPENING_BRACKET); - setState(385); + setState(398); booleanValue(); - setState(390); + setState(403); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(386); + setState(399); match(COMMA); - setState(387); + setState(400); booleanValue(); } } - setState(392); + setState(405); _errHandler.sync(this); _la = _input.LA(1); } - setState(393); + setState(406); match(CLOSING_BRACKET); } break; @@ -3248,27 +3336,27 @@ public final ConstantContext constant() throws RecognitionException { _localctx = new StringArrayLiteralContext(_localctx); enterOuterAlt(_localctx, 10); { - setState(395); + setState(408); match(OPENING_BRACKET); - setState(396); + setState(409); string(); - setState(401); + setState(414); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(397); + setState(410); match(COMMA); - setState(398); + setState(411); string(); } } - setState(403); + setState(416); _errHandler.sync(this); _la = _input.LA(1); } - setState(404); + setState(417); match(CLOSING_BRACKET); } break; @@ -3311,13 +3399,13 @@ public T accept(ParseTreeVisitor visitor) { public final LimitCommandContext limitCommand() throws RecognitionException { LimitCommandContext _localctx = new LimitCommandContext(_ctx, getState()); - enterRule(_localctx, 58, RULE_limitCommand); + enterRule(_localctx, 60, RULE_limitCommand); try { enterOuterAlt(_localctx, 1); { - setState(408); + setState(421); match(LIMIT); - setState(409); + setState(422); match(INTEGER_LITERAL); } } @@ -3367,32 +3455,32 @@ public T accept(ParseTreeVisitor visitor) { public final SortCommandContext sortCommand() throws RecognitionException { SortCommandContext _localctx = new SortCommandContext(_ctx, getState()); - enterRule(_localctx, 60, RULE_sortCommand); + enterRule(_localctx, 62, RULE_sortCommand); try { int _alt; enterOuterAlt(_localctx, 1); { - setState(411); + setState(424); match(SORT); - setState(412); + setState(425); orderExpression(); - setState(417); + setState(430); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,38,_ctx); + _alt = getInterpreter().adaptivePredict(_input,39,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(413); + setState(426); match(COMMA); - setState(414); + setState(427); orderExpression(); } } } - setState(419); + setState(432); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,38,_ctx); + _alt = getInterpreter().adaptivePredict(_input,39,_ctx); } } } @@ -3441,19 +3529,19 @@ public T accept(ParseTreeVisitor visitor) { public final OrderExpressionContext orderExpression() throws RecognitionException { OrderExpressionContext _localctx = new OrderExpressionContext(_ctx, getState()); - enterRule(_localctx, 62, RULE_orderExpression); + enterRule(_localctx, 64, RULE_orderExpression); int _la; try { enterOuterAlt(_localctx, 1); { - setState(420); + setState(433); booleanExpression(0); - setState(422); + setState(435); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,39,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,40,_ctx) ) { case 1: { - setState(421); + setState(434); ((OrderExpressionContext)_localctx).ordering = _input.LT(1); _la = _input.LA(1); if ( !(_la==ASC || _la==DESC) ) { @@ -3467,14 +3555,14 @@ public final OrderExpressionContext orderExpression() throws RecognitionExceptio } break; } - setState(426); + setState(439); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,40,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,41,_ctx) ) { case 1: { - setState(424); + setState(437); match(NULLS); - setState(425); + setState(438); ((OrderExpressionContext)_localctx).nullOrdering = _input.LT(1); _la = _input.LA(1); if ( !(_la==FIRST || _la==LAST) ) { @@ -3504,15 +3592,8 @@ public final OrderExpressionContext orderExpression() throws RecognitionExceptio @SuppressWarnings("CheckReturnValue") public static class KeepCommandContext extends ParserRuleContext { public TerminalNode KEEP() { return getToken(EsqlBaseParser.KEEP, 0); } - public List qualifiedNamePattern() { - return getRuleContexts(QualifiedNamePatternContext.class); - } - public QualifiedNamePatternContext qualifiedNamePattern(int i) { - return getRuleContext(QualifiedNamePatternContext.class,i); - } - public List COMMA() { return getTokens(EsqlBaseParser.COMMA); } - public TerminalNode COMMA(int i) { - return getToken(EsqlBaseParser.COMMA, i); + public QualifiedNamePatternsContext qualifiedNamePatterns() { + return getRuleContext(QualifiedNamePatternsContext.class,0); } @SuppressWarnings("this-escape") public KeepCommandContext(ParserRuleContext parent, int invokingState) { @@ -3536,33 +3617,14 @@ public T accept(ParseTreeVisitor visitor) { public final KeepCommandContext keepCommand() throws RecognitionException { KeepCommandContext _localctx = new KeepCommandContext(_ctx, getState()); - enterRule(_localctx, 64, RULE_keepCommand); + enterRule(_localctx, 66, RULE_keepCommand); try { - int _alt; enterOuterAlt(_localctx, 1); { - setState(428); + setState(441); match(KEEP); - setState(429); - qualifiedNamePattern(); - setState(434); - _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,41,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { - if ( _alt==1 ) { - { - { - setState(430); - match(COMMA); - setState(431); - qualifiedNamePattern(); - } - } - } - setState(436); - _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,41,_ctx); - } + setState(442); + qualifiedNamePatterns(); } } catch (RecognitionException re) { @@ -3579,15 +3641,8 @@ public final KeepCommandContext keepCommand() throws RecognitionException { @SuppressWarnings("CheckReturnValue") public static class DropCommandContext extends ParserRuleContext { public TerminalNode DROP() { return getToken(EsqlBaseParser.DROP, 0); } - public List qualifiedNamePattern() { - return getRuleContexts(QualifiedNamePatternContext.class); - } - public QualifiedNamePatternContext qualifiedNamePattern(int i) { - return getRuleContext(QualifiedNamePatternContext.class,i); - } - public List COMMA() { return getTokens(EsqlBaseParser.COMMA); } - public TerminalNode COMMA(int i) { - return getToken(EsqlBaseParser.COMMA, i); + public QualifiedNamePatternsContext qualifiedNamePatterns() { + return getRuleContext(QualifiedNamePatternsContext.class,0); } @SuppressWarnings("this-escape") public DropCommandContext(ParserRuleContext parent, int invokingState) { @@ -3611,33 +3666,14 @@ public T accept(ParseTreeVisitor visitor) { public final DropCommandContext dropCommand() throws RecognitionException { DropCommandContext _localctx = new DropCommandContext(_ctx, getState()); - enterRule(_localctx, 66, RULE_dropCommand); + enterRule(_localctx, 68, RULE_dropCommand); try { - int _alt; enterOuterAlt(_localctx, 1); { - setState(437); + setState(444); match(DROP); - setState(438); - qualifiedNamePattern(); - setState(443); - _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,42,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { - if ( _alt==1 ) { - { - { - setState(439); - match(COMMA); - setState(440); - qualifiedNamePattern(); - } - } - } - setState(445); - _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,42,_ctx); - } + setState(445); + qualifiedNamePatterns(); } } catch (RecognitionException re) { @@ -3686,32 +3722,32 @@ public T accept(ParseTreeVisitor visitor) { public final RenameCommandContext renameCommand() throws RecognitionException { RenameCommandContext _localctx = new RenameCommandContext(_ctx, getState()); - enterRule(_localctx, 68, RULE_renameCommand); + enterRule(_localctx, 70, RULE_renameCommand); try { int _alt; enterOuterAlt(_localctx, 1); { - setState(446); - match(RENAME); setState(447); + match(RENAME); + setState(448); renameClause(); - setState(452); + setState(453); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,43,_ctx); + _alt = getInterpreter().adaptivePredict(_input,42,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(448); - match(COMMA); setState(449); + match(COMMA); + setState(450); renameClause(); } } } - setState(454); + setState(455); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,43,_ctx); + _alt = getInterpreter().adaptivePredict(_input,42,_ctx); } } } @@ -3759,15 +3795,15 @@ public T accept(ParseTreeVisitor visitor) { public final RenameClauseContext renameClause() throws RecognitionException { RenameClauseContext _localctx = new RenameClauseContext(_ctx, getState()); - enterRule(_localctx, 70, RULE_renameClause); + enterRule(_localctx, 72, RULE_renameClause); try { enterOuterAlt(_localctx, 1); { - setState(455); - ((RenameClauseContext)_localctx).oldName = qualifiedNamePattern(); setState(456); - match(AS); + ((RenameClauseContext)_localctx).oldName = qualifiedNamePattern(); setState(457); + match(AS); + setState(458); ((RenameClauseContext)_localctx).newName = qualifiedNamePattern(); } } @@ -3816,22 +3852,22 @@ public T accept(ParseTreeVisitor visitor) { public final DissectCommandContext dissectCommand() throws RecognitionException { DissectCommandContext _localctx = new DissectCommandContext(_ctx, getState()); - enterRule(_localctx, 72, RULE_dissectCommand); + enterRule(_localctx, 74, RULE_dissectCommand); try { enterOuterAlt(_localctx, 1); { - setState(459); - match(DISSECT); setState(460); - primaryExpression(0); + match(DISSECT); setState(461); + primaryExpression(0); + setState(462); string(); - setState(463); + setState(464); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,44,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,43,_ctx) ) { case 1: { - setState(462); + setState(463); commandOptions(); } break; @@ -3880,15 +3916,15 @@ public T accept(ParseTreeVisitor visitor) { public final GrokCommandContext grokCommand() throws RecognitionException { GrokCommandContext _localctx = new GrokCommandContext(_ctx, getState()); - enterRule(_localctx, 74, RULE_grokCommand); + enterRule(_localctx, 76, RULE_grokCommand); try { enterOuterAlt(_localctx, 1); { - setState(465); - match(GROK); setState(466); - primaryExpression(0); + match(GROK); setState(467); + primaryExpression(0); + setState(468); string(); } } @@ -3931,13 +3967,13 @@ public T accept(ParseTreeVisitor visitor) { public final MvExpandCommandContext mvExpandCommand() throws RecognitionException { MvExpandCommandContext _localctx = new MvExpandCommandContext(_ctx, getState()); - enterRule(_localctx, 76, RULE_mvExpandCommand); + enterRule(_localctx, 78, RULE_mvExpandCommand); try { enterOuterAlt(_localctx, 1); { - setState(469); - match(MV_EXPAND); setState(470); + match(MV_EXPAND); + setState(471); qualifiedName(); } } @@ -3986,30 +4022,30 @@ public T accept(ParseTreeVisitor visitor) { public final CommandOptionsContext commandOptions() throws RecognitionException { CommandOptionsContext _localctx = new CommandOptionsContext(_ctx, getState()); - enterRule(_localctx, 78, RULE_commandOptions); + enterRule(_localctx, 80, RULE_commandOptions); try { int _alt; enterOuterAlt(_localctx, 1); { - setState(472); + setState(473); commandOption(); - setState(477); + setState(478); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,45,_ctx); + _alt = getInterpreter().adaptivePredict(_input,44,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(473); - match(COMMA); setState(474); + match(COMMA); + setState(475); commandOption(); } } } - setState(479); + setState(480); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,45,_ctx); + _alt = getInterpreter().adaptivePredict(_input,44,_ctx); } } } @@ -4055,15 +4091,15 @@ public T accept(ParseTreeVisitor visitor) { public final CommandOptionContext commandOption() throws RecognitionException { CommandOptionContext _localctx = new CommandOptionContext(_ctx, getState()); - enterRule(_localctx, 80, RULE_commandOption); + enterRule(_localctx, 82, RULE_commandOption); try { enterOuterAlt(_localctx, 1); { - setState(480); - identifier(); setState(481); - match(ASSIGN); + identifier(); setState(482); + match(ASSIGN); + setState(483); constant(); } } @@ -4104,12 +4140,12 @@ public T accept(ParseTreeVisitor visitor) { public final BooleanValueContext booleanValue() throws RecognitionException { BooleanValueContext _localctx = new BooleanValueContext(_ctx, getState()); - enterRule(_localctx, 82, RULE_booleanValue); + enterRule(_localctx, 84, RULE_booleanValue); int _la; try { enterOuterAlt(_localctx, 1); { - setState(484); + setState(485); _la = _input.LA(1); if ( !(_la==FALSE || _la==TRUE) ) { _errHandler.recoverInline(this); @@ -4162,22 +4198,22 @@ public T accept(ParseTreeVisitor visitor) { public final NumericValueContext numericValue() throws RecognitionException { NumericValueContext _localctx = new NumericValueContext(_ctx, getState()); - enterRule(_localctx, 84, RULE_numericValue); + enterRule(_localctx, 86, RULE_numericValue); try { - setState(488); + setState(489); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,46,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,45,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(486); + setState(487); decimalValue(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(487); + setState(488); integerValue(); } break; @@ -4221,17 +4257,17 @@ public T accept(ParseTreeVisitor visitor) { public final DecimalValueContext decimalValue() throws RecognitionException { DecimalValueContext _localctx = new DecimalValueContext(_ctx, getState()); - enterRule(_localctx, 86, RULE_decimalValue); + enterRule(_localctx, 88, RULE_decimalValue); int _la; try { enterOuterAlt(_localctx, 1); { - setState(491); + setState(492); _errHandler.sync(this); _la = _input.LA(1); if (_la==PLUS || _la==MINUS) { { - setState(490); + setState(491); _la = _input.LA(1); if ( !(_la==PLUS || _la==MINUS) ) { _errHandler.recoverInline(this); @@ -4244,7 +4280,7 @@ public final DecimalValueContext decimalValue() throws RecognitionException { } } - setState(493); + setState(494); match(DECIMAL_LITERAL); } } @@ -4286,17 +4322,17 @@ public T accept(ParseTreeVisitor visitor) { public final IntegerValueContext integerValue() throws RecognitionException { IntegerValueContext _localctx = new IntegerValueContext(_ctx, getState()); - enterRule(_localctx, 88, RULE_integerValue); + enterRule(_localctx, 90, RULE_integerValue); int _la; try { enterOuterAlt(_localctx, 1); { - setState(496); + setState(497); _errHandler.sync(this); _la = _input.LA(1); if (_la==PLUS || _la==MINUS) { { - setState(495); + setState(496); _la = _input.LA(1); if ( !(_la==PLUS || _la==MINUS) ) { _errHandler.recoverInline(this); @@ -4309,7 +4345,7 @@ public final IntegerValueContext integerValue() throws RecognitionException { } } - setState(498); + setState(499); match(INTEGER_LITERAL); } } @@ -4349,11 +4385,11 @@ public T accept(ParseTreeVisitor visitor) { public final StringContext string() throws RecognitionException { StringContext _localctx = new StringContext(_ctx, getState()); - enterRule(_localctx, 90, RULE_string); + enterRule(_localctx, 92, RULE_string); try { enterOuterAlt(_localctx, 1); { - setState(500); + setState(501); match(QUOTED_STRING); } } @@ -4398,14 +4434,14 @@ public T accept(ParseTreeVisitor visitor) { public final ComparisonOperatorContext comparisonOperator() throws RecognitionException { ComparisonOperatorContext _localctx = new ComparisonOperatorContext(_ctx, getState()); - enterRule(_localctx, 92, RULE_comparisonOperator); + enterRule(_localctx, 94, RULE_comparisonOperator); int _la; try { enterOuterAlt(_localctx, 1); { - setState(502); + setState(503); _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 4503599627370496000L) != 0)) ) { + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 9007199254740992000L) != 0)) ) { _errHandler.recoverInline(this); } else { @@ -4454,13 +4490,13 @@ public T accept(ParseTreeVisitor visitor) { public final ExplainCommandContext explainCommand() throws RecognitionException { ExplainCommandContext _localctx = new ExplainCommandContext(_ctx, getState()); - enterRule(_localctx, 94, RULE_explainCommand); + enterRule(_localctx, 96, RULE_explainCommand); try { enterOuterAlt(_localctx, 1); { - setState(504); - match(EXPLAIN); setState(505); + match(EXPLAIN); + setState(506); subqueryExpression(); } } @@ -4504,15 +4540,15 @@ public T accept(ParseTreeVisitor visitor) { public final SubqueryExpressionContext subqueryExpression() throws RecognitionException { SubqueryExpressionContext _localctx = new SubqueryExpressionContext(_ctx, getState()); - enterRule(_localctx, 96, RULE_subqueryExpression); + enterRule(_localctx, 98, RULE_subqueryExpression); try { enterOuterAlt(_localctx, 1); { - setState(507); - match(OPENING_BRACKET); setState(508); - query(0); + match(OPENING_BRACKET); setState(509); + query(0); + setState(510); match(CLOSING_BRACKET); } } @@ -4564,14 +4600,14 @@ public T accept(ParseTreeVisitor visitor) { public final ShowCommandContext showCommand() throws RecognitionException { ShowCommandContext _localctx = new ShowCommandContext(_ctx, getState()); - enterRule(_localctx, 98, RULE_showCommand); + enterRule(_localctx, 100, RULE_showCommand); try { _localctx = new ShowInfoContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(511); - match(SHOW); setState(512); + match(SHOW); + setState(513); match(INFO); } } @@ -4623,14 +4659,14 @@ public T accept(ParseTreeVisitor visitor) { public final MetaCommandContext metaCommand() throws RecognitionException { MetaCommandContext _localctx = new MetaCommandContext(_ctx, getState()); - enterRule(_localctx, 100, RULE_metaCommand); + enterRule(_localctx, 102, RULE_metaCommand); try { _localctx = new MetaFunctionsContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(514); - match(META); setState(515); + match(META); + setState(516); match(FUNCTIONS); } } @@ -4688,53 +4724,53 @@ public T accept(ParseTreeVisitor visitor) { public final EnrichCommandContext enrichCommand() throws RecognitionException { EnrichCommandContext _localctx = new EnrichCommandContext(_ctx, getState()); - enterRule(_localctx, 102, RULE_enrichCommand); + enterRule(_localctx, 104, RULE_enrichCommand); try { int _alt; enterOuterAlt(_localctx, 1); { - setState(517); - match(ENRICH); setState(518); + match(ENRICH); + setState(519); ((EnrichCommandContext)_localctx).policyName = match(ENRICH_POLICY_NAME); - setState(521); + setState(522); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,49,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,48,_ctx) ) { case 1: { - setState(519); - match(ON); setState(520); + match(ON); + setState(521); ((EnrichCommandContext)_localctx).matchField = qualifiedNamePattern(); } break; } - setState(532); + setState(533); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,51,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,50,_ctx) ) { case 1: { - setState(523); - match(WITH); setState(524); + match(WITH); + setState(525); enrichWithClause(); - setState(529); + setState(530); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,50,_ctx); + _alt = getInterpreter().adaptivePredict(_input,49,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(525); - match(COMMA); setState(526); + match(COMMA); + setState(527); enrichWithClause(); } } } - setState(531); + setState(532); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,50,_ctx); + _alt = getInterpreter().adaptivePredict(_input,49,_ctx); } } break; @@ -4785,23 +4821,23 @@ public T accept(ParseTreeVisitor visitor) { public final EnrichWithClauseContext enrichWithClause() throws RecognitionException { EnrichWithClauseContext _localctx = new EnrichWithClauseContext(_ctx, getState()); - enterRule(_localctx, 104, RULE_enrichWithClause); + enterRule(_localctx, 106, RULE_enrichWithClause); try { enterOuterAlt(_localctx, 1); { - setState(537); + setState(538); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,52,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,51,_ctx) ) { case 1: { - setState(534); - ((EnrichWithClauseContext)_localctx).newName = qualifiedNamePattern(); setState(535); + ((EnrichWithClauseContext)_localctx).newName = qualifiedNamePattern(); + setState(536); match(ASSIGN); } break; } - setState(539); + setState(540); ((EnrichWithClauseContext)_localctx).enrichField = qualifiedNamePattern(); } } @@ -4816,6 +4852,63 @@ public final EnrichWithClauseContext enrichWithClause() throws RecognitionExcept return _localctx; } + @SuppressWarnings("CheckReturnValue") + public static class LookupCommandContext extends ParserRuleContext { + public Token tableName; + public QualifiedNamePatternsContext matchFields; + public TerminalNode LOOKUP() { return getToken(EsqlBaseParser.LOOKUP, 0); } + public TerminalNode ON() { return getToken(EsqlBaseParser.ON, 0); } + public TerminalNode INDEX_UNQUOTED_IDENTIFIER() { return getToken(EsqlBaseParser.INDEX_UNQUOTED_IDENTIFIER, 0); } + public QualifiedNamePatternsContext qualifiedNamePatterns() { + return getRuleContext(QualifiedNamePatternsContext.class,0); + } + @SuppressWarnings("this-escape") + public LookupCommandContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_lookupCommand; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof EsqlBaseParserListener ) ((EsqlBaseParserListener)listener).enterLookupCommand(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof EsqlBaseParserListener ) ((EsqlBaseParserListener)listener).exitLookupCommand(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof EsqlBaseParserVisitor ) return ((EsqlBaseParserVisitor)visitor).visitLookupCommand(this); + else return visitor.visitChildren(this); + } + } + + public final LookupCommandContext lookupCommand() throws RecognitionException { + LookupCommandContext _localctx = new LookupCommandContext(_ctx, getState()); + enterRule(_localctx, 108, RULE_lookupCommand); + try { + enterOuterAlt(_localctx, 1); + { + setState(542); + match(LOOKUP); + setState(543); + ((LookupCommandContext)_localctx).tableName = match(INDEX_UNQUOTED_IDENTIFIER); + setState(544); + match(ON); + setState(545); + ((LookupCommandContext)_localctx).matchFields = qualifiedNamePatterns(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { switch (ruleIndex) { case 1: @@ -4863,7 +4956,7 @@ private boolean primaryExpression_sempred(PrimaryExpressionContext _localctx, in } public static final String _serializedATN = - "\u0004\u0001t\u021e\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ + "\u0004\u0001{\u0224\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ "\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b\u0007\u000b\u0002"+ @@ -4877,338 +4970,341 @@ private boolean primaryExpression_sempred(PrimaryExpressionContext _localctx, in "#\u0007#\u0002$\u0007$\u0002%\u0007%\u0002&\u0007&\u0002\'\u0007\'\u0002"+ "(\u0007(\u0002)\u0007)\u0002*\u0007*\u0002+\u0007+\u0002,\u0007,\u0002"+ "-\u0007-\u0002.\u0007.\u0002/\u0007/\u00020\u00070\u00021\u00071\u0002"+ - "2\u00072\u00023\u00073\u00024\u00074\u0001\u0000\u0001\u0000\u0001\u0000"+ - "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ - "\u0005\u0001t\b\u0001\n\u0001\f\u0001w\t\u0001\u0001\u0002\u0001\u0002"+ - "\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0003\u0002\u007f\b\u0002"+ - "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+ - "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+ - "\u0001\u0003\u0003\u0003\u008e\b\u0003\u0001\u0004\u0001\u0004\u0001\u0004"+ - "\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+ - "\u0001\u0005\u0003\u0005\u009a\b\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+ - "\u0001\u0005\u0001\u0005\u0005\u0005\u00a1\b\u0005\n\u0005\f\u0005\u00a4"+ - "\t\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0003"+ - "\u0005\u00ab\b\u0005\u0001\u0005\u0001\u0005\u0003\u0005\u00af\b\u0005"+ - "\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+ - "\u0005\u0005\u00b7\b\u0005\n\u0005\f\u0005\u00ba\t\u0005\u0001\u0006\u0001"+ - "\u0006\u0003\u0006\u00be\b\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001"+ - "\u0006\u0001\u0006\u0003\u0006\u00c5\b\u0006\u0001\u0006\u0001\u0006\u0001"+ - "\u0006\u0003\u0006\u00ca\b\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0001"+ - "\u0007\u0001\u0007\u0003\u0007\u00d1\b\u0007\u0001\b\u0001\b\u0001\b\u0001"+ - "\b\u0003\b\u00d7\b\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0005"+ - "\b\u00df\b\b\n\b\f\b\u00e2\t\b\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t"+ - "\u0001\t\u0001\t\u0001\t\u0003\t\u00ec\b\t\u0001\t\u0001\t\u0001\t\u0005"+ - "\t\u00f1\b\t\n\t\f\t\u00f4\t\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n"+ - "\u0001\n\u0005\n\u00fc\b\n\n\n\f\n\u00ff\t\n\u0003\n\u0101\b\n\u0001\n"+ - "\u0001\n\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001\f\u0001\r\u0001"+ - "\r\u0001\r\u0005\r\u010d\b\r\n\r\f\r\u0110\t\r\u0001\u000e\u0001\u000e"+ - "\u0001\u000e\u0001\u000e\u0001\u000e\u0003\u000e\u0117\b\u000e\u0001\u000f"+ - "\u0001\u000f\u0001\u000f\u0001\u000f\u0005\u000f\u011d\b\u000f\n\u000f"+ - "\f\u000f\u0120\t\u000f\u0001\u000f\u0003\u000f\u0123\b\u000f\u0001\u0010"+ - "\u0001\u0010\u0001\u0011\u0001\u0011\u0003\u0011\u0129\b\u0011\u0001\u0012"+ - "\u0001\u0012\u0001\u0012\u0001\u0012\u0005\u0012\u012f\b\u0012\n\u0012"+ - "\f\u0012\u0132\t\u0012\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013"+ - "\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0005\u0014\u013c\b\u0014"+ - "\n\u0014\f\u0014\u013f\t\u0014\u0001\u0014\u0003\u0014\u0142\b\u0014\u0001"+ - "\u0014\u0001\u0014\u0003\u0014\u0146\b\u0014\u0001\u0015\u0001\u0015\u0001"+ - "\u0015\u0001\u0016\u0001\u0016\u0003\u0016\u014d\b\u0016\u0001\u0016\u0001"+ - "\u0016\u0003\u0016\u0151\b\u0016\u0001\u0017\u0001\u0017\u0001\u0017\u0001"+ - "\u0017\u0003\u0017\u0157\b\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0005"+ - "\u0018\u015c\b\u0018\n\u0018\f\u0018\u015f\t\u0018\u0001\u0019\u0001\u0019"+ - "\u0001\u0019\u0005\u0019\u0164\b\u0019\n\u0019\f\u0019\u0167\t\u0019\u0001"+ - "\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001"+ - "\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001"+ - "\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0005\u001c\u017a"+ - "\b\u001c\n\u001c\f\u001c\u017d\t\u001c\u0001\u001c\u0001\u001c\u0001\u001c"+ - "\u0001\u001c\u0001\u001c\u0001\u001c\u0005\u001c\u0185\b\u001c\n\u001c"+ - "\f\u001c\u0188\t\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c"+ - "\u0001\u001c\u0001\u001c\u0005\u001c\u0190\b\u001c\n\u001c\f\u001c\u0193"+ - "\t\u001c\u0001\u001c\u0001\u001c\u0003\u001c\u0197\b\u001c\u0001\u001d"+ - "\u0001\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e"+ - "\u0005\u001e\u01a0\b\u001e\n\u001e\f\u001e\u01a3\t\u001e\u0001\u001f\u0001"+ - "\u001f\u0003\u001f\u01a7\b\u001f\u0001\u001f\u0001\u001f\u0003\u001f\u01ab"+ - "\b\u001f\u0001 \u0001 \u0001 \u0001 \u0005 \u01b1\b \n \f \u01b4\t \u0001"+ - "!\u0001!\u0001!\u0001!\u0005!\u01ba\b!\n!\f!\u01bd\t!\u0001\"\u0001\""+ - "\u0001\"\u0001\"\u0005\"\u01c3\b\"\n\"\f\"\u01c6\t\"\u0001#\u0001#\u0001"+ - "#\u0001#\u0001$\u0001$\u0001$\u0001$\u0003$\u01d0\b$\u0001%\u0001%\u0001"+ - "%\u0001%\u0001&\u0001&\u0001&\u0001\'\u0001\'\u0001\'\u0005\'\u01dc\b"+ - "\'\n\'\f\'\u01df\t\'\u0001(\u0001(\u0001(\u0001(\u0001)\u0001)\u0001*"+ - "\u0001*\u0003*\u01e9\b*\u0001+\u0003+\u01ec\b+\u0001+\u0001+\u0001,\u0003"+ - ",\u01f1\b,\u0001,\u0001,\u0001-\u0001-\u0001.\u0001.\u0001/\u0001/\u0001"+ - "/\u00010\u00010\u00010\u00010\u00011\u00011\u00011\u00012\u00012\u0001"+ - "2\u00013\u00013\u00013\u00013\u00033\u020a\b3\u00013\u00013\u00013\u0001"+ - "3\u00053\u0210\b3\n3\f3\u0213\t3\u00033\u0215\b3\u00014\u00014\u00014"+ - "\u00034\u021a\b4\u00014\u00014\u00014\u0000\u0004\u0002\n\u0010\u0012"+ - "5\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010\u0012\u0014\u0016\u0018\u001a"+ - "\u001c\u001e \"$&(*,.02468:<>@BDFHJLNPRTVXZ\\^`bdfh\u0000\u0007\u0001"+ - "\u0000>?\u0001\u0000@B\u0001\u0000EF\u0002\u0000\"\"&&\u0001\u0000)*\u0002"+ - "\u0000((66\u0002\u0000779=\u023a\u0000j\u0001\u0000\u0000\u0000\u0002"+ - "m\u0001\u0000\u0000\u0000\u0004~\u0001\u0000\u0000\u0000\u0006\u008d\u0001"+ - "\u0000\u0000\u0000\b\u008f\u0001\u0000\u0000\u0000\n\u00ae\u0001\u0000"+ - "\u0000\u0000\f\u00c9\u0001\u0000\u0000\u0000\u000e\u00d0\u0001\u0000\u0000"+ - "\u0000\u0010\u00d6\u0001\u0000\u0000\u0000\u0012\u00eb\u0001\u0000\u0000"+ - "\u0000\u0014\u00f5\u0001\u0000\u0000\u0000\u0016\u0104\u0001\u0000\u0000"+ - "\u0000\u0018\u0106\u0001\u0000\u0000\u0000\u001a\u0109\u0001\u0000\u0000"+ - "\u0000\u001c\u0116\u0001\u0000\u0000\u0000\u001e\u0118\u0001\u0000\u0000"+ - "\u0000 \u0124\u0001\u0000\u0000\u0000\"\u0128\u0001\u0000\u0000\u0000"+ - "$\u012a\u0001\u0000\u0000\u0000&\u0133\u0001\u0000\u0000\u0000(\u0137"+ - "\u0001\u0000\u0000\u0000*\u0147\u0001\u0000\u0000\u0000,\u014a\u0001\u0000"+ - "\u0000\u0000.\u0152\u0001\u0000\u0000\u00000\u0158\u0001\u0000\u0000\u0000"+ - "2\u0160\u0001\u0000\u0000\u00004\u0168\u0001\u0000\u0000\u00006\u016a"+ - "\u0001\u0000\u0000\u00008\u0196\u0001\u0000\u0000\u0000:\u0198\u0001\u0000"+ - "\u0000\u0000<\u019b\u0001\u0000\u0000\u0000>\u01a4\u0001\u0000\u0000\u0000"+ - "@\u01ac\u0001\u0000\u0000\u0000B\u01b5\u0001\u0000\u0000\u0000D\u01be"+ - "\u0001\u0000\u0000\u0000F\u01c7\u0001\u0000\u0000\u0000H\u01cb\u0001\u0000"+ - "\u0000\u0000J\u01d1\u0001\u0000\u0000\u0000L\u01d5\u0001\u0000\u0000\u0000"+ - "N\u01d8\u0001\u0000\u0000\u0000P\u01e0\u0001\u0000\u0000\u0000R\u01e4"+ - "\u0001\u0000\u0000\u0000T\u01e8\u0001\u0000\u0000\u0000V\u01eb\u0001\u0000"+ - "\u0000\u0000X\u01f0\u0001\u0000\u0000\u0000Z\u01f4\u0001\u0000\u0000\u0000"+ - "\\\u01f6\u0001\u0000\u0000\u0000^\u01f8\u0001\u0000\u0000\u0000`\u01fb"+ - "\u0001\u0000\u0000\u0000b\u01ff\u0001\u0000\u0000\u0000d\u0202\u0001\u0000"+ - "\u0000\u0000f\u0205\u0001\u0000\u0000\u0000h\u0219\u0001\u0000\u0000\u0000"+ - "jk\u0003\u0002\u0001\u0000kl\u0005\u0000\u0000\u0001l\u0001\u0001\u0000"+ - "\u0000\u0000mn\u0006\u0001\uffff\uffff\u0000no\u0003\u0004\u0002\u0000"+ - "ou\u0001\u0000\u0000\u0000pq\n\u0001\u0000\u0000qr\u0005\u001c\u0000\u0000"+ - "rt\u0003\u0006\u0003\u0000sp\u0001\u0000\u0000\u0000tw\u0001\u0000\u0000"+ - "\u0000us\u0001\u0000\u0000\u0000uv\u0001\u0000\u0000\u0000v\u0003\u0001"+ - "\u0000\u0000\u0000wu\u0001\u0000\u0000\u0000x\u007f\u0003^/\u0000y\u007f"+ - "\u0003\u001e\u000f\u0000z\u007f\u0003\u0018\f\u0000{\u007f\u0003(\u0014"+ - "\u0000|\u007f\u0003b1\u0000}\u007f\u0003d2\u0000~x\u0001\u0000\u0000\u0000"+ - "~y\u0001\u0000\u0000\u0000~z\u0001\u0000\u0000\u0000~{\u0001\u0000\u0000"+ - "\u0000~|\u0001\u0000\u0000\u0000~}\u0001\u0000\u0000\u0000\u007f\u0005"+ - "\u0001\u0000\u0000\u0000\u0080\u008e\u0003*\u0015\u0000\u0081\u008e\u0003"+ - ".\u0017\u0000\u0082\u008e\u0003:\u001d\u0000\u0083\u008e\u0003@ \u0000"+ - "\u0084\u008e\u0003<\u001e\u0000\u0085\u008e\u0003,\u0016\u0000\u0086\u008e"+ - "\u0003\b\u0004\u0000\u0087\u008e\u0003B!\u0000\u0088\u008e\u0003D\"\u0000"+ - "\u0089\u008e\u0003H$\u0000\u008a\u008e\u0003J%\u0000\u008b\u008e\u0003"+ - "f3\u0000\u008c\u008e\u0003L&\u0000\u008d\u0080\u0001\u0000\u0000\u0000"+ - "\u008d\u0081\u0001\u0000\u0000\u0000\u008d\u0082\u0001\u0000\u0000\u0000"+ - "\u008d\u0083\u0001\u0000\u0000\u0000\u008d\u0084\u0001\u0000\u0000\u0000"+ - "\u008d\u0085\u0001\u0000\u0000\u0000\u008d\u0086\u0001\u0000\u0000\u0000"+ - "\u008d\u0087\u0001\u0000\u0000\u0000\u008d\u0088\u0001\u0000\u0000\u0000"+ - "\u008d\u0089\u0001\u0000\u0000\u0000\u008d\u008a\u0001\u0000\u0000\u0000"+ - "\u008d\u008b\u0001\u0000\u0000\u0000\u008d\u008c\u0001\u0000\u0000\u0000"+ - "\u008e\u0007\u0001\u0000\u0000\u0000\u008f\u0090\u0005\u0013\u0000\u0000"+ - "\u0090\u0091\u0003\n\u0005\u0000\u0091\t\u0001\u0000\u0000\u0000\u0092"+ - "\u0093\u0006\u0005\uffff\uffff\u0000\u0093\u0094\u0005/\u0000\u0000\u0094"+ - "\u00af\u0003\n\u0005\u0007\u0095\u00af\u0003\u000e\u0007\u0000\u0096\u00af"+ - "\u0003\f\u0006\u0000\u0097\u0099\u0003\u000e\u0007\u0000\u0098\u009a\u0005"+ - "/\u0000\u0000\u0099\u0098\u0001\u0000\u0000\u0000\u0099\u009a\u0001\u0000"+ - "\u0000\u0000\u009a\u009b\u0001\u0000\u0000\u0000\u009b\u009c\u0005,\u0000"+ - "\u0000\u009c\u009d\u0005+\u0000\u0000\u009d\u00a2\u0003\u000e\u0007\u0000"+ - "\u009e\u009f\u0005%\u0000\u0000\u009f\u00a1\u0003\u000e\u0007\u0000\u00a0"+ - "\u009e\u0001\u0000\u0000\u0000\u00a1\u00a4\u0001\u0000\u0000\u0000\u00a2"+ - "\u00a0\u0001\u0000\u0000\u0000\u00a2\u00a3\u0001\u0000\u0000\u0000\u00a3"+ - "\u00a5\u0001\u0000\u0000\u0000\u00a4\u00a2\u0001\u0000\u0000\u0000\u00a5"+ - "\u00a6\u00055\u0000\u0000\u00a6\u00af\u0001\u0000\u0000\u0000\u00a7\u00a8"+ - "\u0003\u000e\u0007\u0000\u00a8\u00aa\u0005-\u0000\u0000\u00a9\u00ab\u0005"+ - "/\u0000\u0000\u00aa\u00a9\u0001\u0000\u0000\u0000\u00aa\u00ab\u0001\u0000"+ - "\u0000\u0000\u00ab\u00ac\u0001\u0000\u0000\u0000\u00ac\u00ad\u00050\u0000"+ - "\u0000\u00ad\u00af\u0001\u0000\u0000\u0000\u00ae\u0092\u0001\u0000\u0000"+ - "\u0000\u00ae\u0095\u0001\u0000\u0000\u0000\u00ae\u0096\u0001\u0000\u0000"+ - "\u0000\u00ae\u0097\u0001\u0000\u0000\u0000\u00ae\u00a7\u0001\u0000\u0000"+ - "\u0000\u00af\u00b8\u0001\u0000\u0000\u0000\u00b0\u00b1\n\u0004\u0000\u0000"+ - "\u00b1\u00b2\u0005!\u0000\u0000\u00b2\u00b7\u0003\n\u0005\u0005\u00b3"+ - "\u00b4\n\u0003\u0000\u0000\u00b4\u00b5\u00052\u0000\u0000\u00b5\u00b7"+ - "\u0003\n\u0005\u0004\u00b6\u00b0\u0001\u0000\u0000\u0000\u00b6\u00b3\u0001"+ - "\u0000\u0000\u0000\u00b7\u00ba\u0001\u0000\u0000\u0000\u00b8\u00b6\u0001"+ - "\u0000\u0000\u0000\u00b8\u00b9\u0001\u0000\u0000\u0000\u00b9\u000b\u0001"+ - "\u0000\u0000\u0000\u00ba\u00b8\u0001\u0000\u0000\u0000\u00bb\u00bd\u0003"+ - "\u000e\u0007\u0000\u00bc\u00be\u0005/\u0000\u0000\u00bd\u00bc\u0001\u0000"+ - "\u0000\u0000\u00bd\u00be\u0001\u0000\u0000\u0000\u00be\u00bf\u0001\u0000"+ - "\u0000\u0000\u00bf\u00c0\u0005.\u0000\u0000\u00c0\u00c1\u0003Z-\u0000"+ - "\u00c1\u00ca\u0001\u0000\u0000\u0000\u00c2\u00c4\u0003\u000e\u0007\u0000"+ - "\u00c3\u00c5\u0005/\u0000\u0000\u00c4\u00c3\u0001\u0000\u0000\u0000\u00c4"+ - "\u00c5\u0001\u0000\u0000\u0000\u00c5\u00c6\u0001\u0000\u0000\u0000\u00c6"+ - "\u00c7\u00054\u0000\u0000\u00c7\u00c8\u0003Z-\u0000\u00c8\u00ca\u0001"+ - "\u0000\u0000\u0000\u00c9\u00bb\u0001\u0000\u0000\u0000\u00c9\u00c2\u0001"+ - "\u0000\u0000\u0000\u00ca\r\u0001\u0000\u0000\u0000\u00cb\u00d1\u0003\u0010"+ - "\b\u0000\u00cc\u00cd\u0003\u0010\b\u0000\u00cd\u00ce\u0003\\.\u0000\u00ce"+ - "\u00cf\u0003\u0010\b\u0000\u00cf\u00d1\u0001\u0000\u0000\u0000\u00d0\u00cb"+ - "\u0001\u0000\u0000\u0000\u00d0\u00cc\u0001\u0000\u0000\u0000\u00d1\u000f"+ - "\u0001\u0000\u0000\u0000\u00d2\u00d3\u0006\b\uffff\uffff\u0000\u00d3\u00d7"+ - "\u0003\u0012\t\u0000\u00d4\u00d5\u0007\u0000\u0000\u0000\u00d5\u00d7\u0003"+ - "\u0010\b\u0003\u00d6\u00d2\u0001\u0000\u0000\u0000\u00d6\u00d4\u0001\u0000"+ - "\u0000\u0000\u00d7\u00e0\u0001\u0000\u0000\u0000\u00d8\u00d9\n\u0002\u0000"+ - "\u0000\u00d9\u00da\u0007\u0001\u0000\u0000\u00da\u00df\u0003\u0010\b\u0003"+ - "\u00db\u00dc\n\u0001\u0000\u0000\u00dc\u00dd\u0007\u0000\u0000\u0000\u00dd"+ - "\u00df\u0003\u0010\b\u0002\u00de\u00d8\u0001\u0000\u0000\u0000\u00de\u00db"+ - "\u0001\u0000\u0000\u0000\u00df\u00e2\u0001\u0000\u0000\u0000\u00e0\u00de"+ - "\u0001\u0000\u0000\u0000\u00e0\u00e1\u0001\u0000\u0000\u0000\u00e1\u0011"+ - "\u0001\u0000\u0000\u0000\u00e2\u00e0\u0001\u0000\u0000\u0000\u00e3\u00e4"+ - "\u0006\t\uffff\uffff\u0000\u00e4\u00ec\u00038\u001c\u0000\u00e5\u00ec"+ - "\u00030\u0018\u0000\u00e6\u00ec\u0003\u0014\n\u0000\u00e7\u00e8\u0005"+ - "+\u0000\u0000\u00e8\u00e9\u0003\n\u0005\u0000\u00e9\u00ea\u00055\u0000"+ - "\u0000\u00ea\u00ec\u0001\u0000\u0000\u0000\u00eb\u00e3\u0001\u0000\u0000"+ - "\u0000\u00eb\u00e5\u0001\u0000\u0000\u0000\u00eb\u00e6\u0001\u0000\u0000"+ - "\u0000\u00eb\u00e7\u0001\u0000\u0000\u0000\u00ec\u00f2\u0001\u0000\u0000"+ - "\u0000\u00ed\u00ee\n\u0001\u0000\u0000\u00ee\u00ef\u0005$\u0000\u0000"+ - "\u00ef\u00f1\u0003\u0016\u000b\u0000\u00f0\u00ed\u0001\u0000\u0000\u0000"+ - "\u00f1\u00f4\u0001\u0000\u0000\u0000\u00f2\u00f0\u0001\u0000\u0000\u0000"+ - "\u00f2\u00f3\u0001\u0000\u0000\u0000\u00f3\u0013\u0001\u0000\u0000\u0000"+ - "\u00f4\u00f2\u0001\u0000\u0000\u0000\u00f5\u00f6\u00034\u001a\u0000\u00f6"+ - "\u0100\u0005+\u0000\u0000\u00f7\u0101\u0005@\u0000\u0000\u00f8\u00fd\u0003"+ - "\n\u0005\u0000\u00f9\u00fa\u0005%\u0000\u0000\u00fa\u00fc\u0003\n\u0005"+ - "\u0000\u00fb\u00f9\u0001\u0000\u0000\u0000\u00fc\u00ff\u0001\u0000\u0000"+ - "\u0000\u00fd\u00fb\u0001\u0000\u0000\u0000\u00fd\u00fe\u0001\u0000\u0000"+ - "\u0000\u00fe\u0101\u0001\u0000\u0000\u0000\u00ff\u00fd\u0001\u0000\u0000"+ - "\u0000\u0100\u00f7\u0001\u0000\u0000\u0000\u0100\u00f8\u0001\u0000\u0000"+ - "\u0000\u0100\u0101\u0001\u0000\u0000\u0000\u0101\u0102\u0001\u0000\u0000"+ - "\u0000\u0102\u0103\u00055\u0000\u0000\u0103\u0015\u0001\u0000\u0000\u0000"+ - "\u0104\u0105\u00034\u001a\u0000\u0105\u0017\u0001\u0000\u0000\u0000\u0106"+ - "\u0107\u0005\u000f\u0000\u0000\u0107\u0108\u0003\u001a\r\u0000\u0108\u0019"+ - "\u0001\u0000\u0000\u0000\u0109\u010e\u0003\u001c\u000e\u0000\u010a\u010b"+ - "\u0005%\u0000\u0000\u010b\u010d\u0003\u001c\u000e\u0000\u010c\u010a\u0001"+ - "\u0000\u0000\u0000\u010d\u0110\u0001\u0000\u0000\u0000\u010e\u010c\u0001"+ - "\u0000\u0000\u0000\u010e\u010f\u0001\u0000\u0000\u0000\u010f\u001b\u0001"+ - "\u0000\u0000\u0000\u0110\u010e\u0001\u0000\u0000\u0000\u0111\u0117\u0003"+ - "\n\u0005\u0000\u0112\u0113\u00030\u0018\u0000\u0113\u0114\u0005#\u0000"+ - "\u0000\u0114\u0115\u0003\n\u0005\u0000\u0115\u0117\u0001\u0000\u0000\u0000"+ - "\u0116\u0111\u0001\u0000\u0000\u0000\u0116\u0112\u0001\u0000\u0000\u0000"+ - "\u0117\u001d\u0001\u0000\u0000\u0000\u0118\u0119\u0005\u0006\u0000\u0000"+ - "\u0119\u011e\u0003 \u0010\u0000\u011a\u011b\u0005%\u0000\u0000\u011b\u011d"+ - "\u0003 \u0010\u0000\u011c\u011a\u0001\u0000\u0000\u0000\u011d\u0120\u0001"+ - "\u0000\u0000\u0000\u011e\u011c\u0001\u0000\u0000\u0000\u011e\u011f\u0001"+ - "\u0000\u0000\u0000\u011f\u0122\u0001\u0000\u0000\u0000\u0120\u011e\u0001"+ - "\u0000\u0000\u0000\u0121\u0123\u0003\"\u0011\u0000\u0122\u0121\u0001\u0000"+ - "\u0000\u0000\u0122\u0123\u0001\u0000\u0000\u0000\u0123\u001f\u0001\u0000"+ - "\u0000\u0000\u0124\u0125\u0005\u0018\u0000\u0000\u0125!\u0001\u0000\u0000"+ - "\u0000\u0126\u0129\u0003$\u0012\u0000\u0127\u0129\u0003&\u0013\u0000\u0128"+ - "\u0126\u0001\u0000\u0000\u0000\u0128\u0127\u0001\u0000\u0000\u0000\u0129"+ - "#\u0001\u0000\u0000\u0000\u012a\u012b\u0005J\u0000\u0000\u012b\u0130\u0003"+ - " \u0010\u0000\u012c\u012d\u0005%\u0000\u0000\u012d\u012f\u0003 \u0010"+ - "\u0000\u012e\u012c\u0001\u0000\u0000\u0000\u012f\u0132\u0001\u0000\u0000"+ - "\u0000\u0130\u012e\u0001\u0000\u0000\u0000\u0130\u0131\u0001\u0000\u0000"+ - "\u0000\u0131%\u0001\u0000\u0000\u0000\u0132\u0130\u0001\u0000\u0000\u0000"+ - "\u0133\u0134\u0005C\u0000\u0000\u0134\u0135\u0003$\u0012\u0000\u0135\u0136"+ - "\u0005D\u0000\u0000\u0136\'\u0001\u0000\u0000\u0000\u0137\u0138\u0005"+ - "\f\u0000\u0000\u0138\u013d\u0003 \u0010\u0000\u0139\u013a\u0005%\u0000"+ - "\u0000\u013a\u013c\u0003 \u0010\u0000\u013b\u0139\u0001\u0000\u0000\u0000"+ - "\u013c\u013f\u0001\u0000\u0000\u0000\u013d\u013b\u0001\u0000\u0000\u0000"+ - "\u013d\u013e\u0001\u0000\u0000\u0000\u013e\u0141\u0001\u0000\u0000\u0000"+ - "\u013f\u013d\u0001\u0000\u0000\u0000\u0140\u0142\u0003\u001a\r\u0000\u0141"+ - "\u0140\u0001\u0000\u0000\u0000\u0141\u0142\u0001\u0000\u0000\u0000\u0142"+ - "\u0145\u0001\u0000\u0000\u0000\u0143\u0144\u0005 \u0000\u0000\u0144\u0146"+ - "\u0003\u001a\r\u0000\u0145\u0143\u0001\u0000\u0000\u0000\u0145\u0146\u0001"+ - "\u0000\u0000\u0000\u0146)\u0001\u0000\u0000\u0000\u0147\u0148\u0005\u0004"+ - "\u0000\u0000\u0148\u0149\u0003\u001a\r\u0000\u0149+\u0001\u0000\u0000"+ - "\u0000\u014a\u014c\u0005\u0012\u0000\u0000\u014b\u014d\u0003\u001a\r\u0000"+ - "\u014c\u014b\u0001\u0000\u0000\u0000\u014c\u014d\u0001\u0000\u0000\u0000"+ - "\u014d\u0150\u0001\u0000\u0000\u0000\u014e\u014f\u0005 \u0000\u0000\u014f"+ - "\u0151\u0003\u001a\r\u0000\u0150\u014e\u0001\u0000\u0000\u0000\u0150\u0151"+ - "\u0001\u0000\u0000\u0000\u0151-\u0001\u0000\u0000\u0000\u0152\u0153\u0005"+ - "\b\u0000\u0000\u0153\u0156\u0003\u001a\r\u0000\u0154\u0155\u0005 \u0000"+ - "\u0000\u0155\u0157\u0003\u001a\r\u0000\u0156\u0154\u0001\u0000\u0000\u0000"+ - "\u0156\u0157\u0001\u0000\u0000\u0000\u0157/\u0001\u0000\u0000\u0000\u0158"+ - "\u015d\u00034\u001a\u0000\u0159\u015a\u0005\'\u0000\u0000\u015a\u015c"+ - "\u00034\u001a\u0000\u015b\u0159\u0001\u0000\u0000\u0000\u015c\u015f\u0001"+ - "\u0000\u0000\u0000\u015d\u015b\u0001\u0000\u0000\u0000\u015d\u015e\u0001"+ - "\u0000\u0000\u0000\u015e1\u0001\u0000\u0000\u0000\u015f\u015d\u0001\u0000"+ - "\u0000\u0000\u0160\u0165\u00036\u001b\u0000\u0161\u0162\u0005\'\u0000"+ - "\u0000\u0162\u0164\u00036\u001b\u0000\u0163\u0161\u0001\u0000\u0000\u0000"+ - "\u0164\u0167\u0001\u0000\u0000\u0000\u0165\u0163\u0001\u0000\u0000\u0000"+ - "\u0165\u0166\u0001\u0000\u0000\u0000\u01663\u0001\u0000\u0000\u0000\u0167"+ - "\u0165\u0001\u0000\u0000\u0000\u0168\u0169\u0007\u0002\u0000\u0000\u0169"+ - "5\u0001\u0000\u0000\u0000\u016a\u016b\u0005N\u0000\u0000\u016b7\u0001"+ - "\u0000\u0000\u0000\u016c\u0197\u00050\u0000\u0000\u016d\u016e\u0003X,"+ - "\u0000\u016e\u016f\u0005E\u0000\u0000\u016f\u0197\u0001\u0000\u0000\u0000"+ - "\u0170\u0197\u0003V+\u0000\u0171\u0197\u0003X,\u0000\u0172\u0197\u0003"+ - "R)\u0000\u0173\u0197\u00053\u0000\u0000\u0174\u0197\u0003Z-\u0000\u0175"+ - "\u0176\u0005C\u0000\u0000\u0176\u017b\u0003T*\u0000\u0177\u0178\u0005"+ - "%\u0000\u0000\u0178\u017a\u0003T*\u0000\u0179\u0177\u0001\u0000\u0000"+ - "\u0000\u017a\u017d\u0001\u0000\u0000\u0000\u017b\u0179\u0001\u0000\u0000"+ - "\u0000\u017b\u017c\u0001\u0000\u0000\u0000\u017c\u017e\u0001\u0000\u0000"+ - "\u0000\u017d\u017b\u0001\u0000\u0000\u0000\u017e\u017f\u0005D\u0000\u0000"+ - "\u017f\u0197\u0001\u0000\u0000\u0000\u0180\u0181\u0005C\u0000\u0000\u0181"+ - "\u0186\u0003R)\u0000\u0182\u0183\u0005%\u0000\u0000\u0183\u0185\u0003"+ - "R)\u0000\u0184\u0182\u0001\u0000\u0000\u0000\u0185\u0188\u0001\u0000\u0000"+ - "\u0000\u0186\u0184\u0001\u0000\u0000\u0000\u0186\u0187\u0001\u0000\u0000"+ - "\u0000\u0187\u0189\u0001\u0000\u0000\u0000\u0188\u0186\u0001\u0000\u0000"+ - "\u0000\u0189\u018a\u0005D\u0000\u0000\u018a\u0197\u0001\u0000\u0000\u0000"+ - "\u018b\u018c\u0005C\u0000\u0000\u018c\u0191\u0003Z-\u0000\u018d\u018e"+ - "\u0005%\u0000\u0000\u018e\u0190\u0003Z-\u0000\u018f\u018d\u0001\u0000"+ - "\u0000\u0000\u0190\u0193\u0001\u0000\u0000\u0000\u0191\u018f\u0001\u0000"+ - "\u0000\u0000\u0191\u0192\u0001\u0000\u0000\u0000\u0192\u0194\u0001\u0000"+ - "\u0000\u0000\u0193\u0191\u0001\u0000\u0000\u0000\u0194\u0195\u0005D\u0000"+ - "\u0000\u0195\u0197\u0001\u0000\u0000\u0000\u0196\u016c\u0001\u0000\u0000"+ - "\u0000\u0196\u016d\u0001\u0000\u0000\u0000\u0196\u0170\u0001\u0000\u0000"+ - "\u0000\u0196\u0171\u0001\u0000\u0000\u0000\u0196\u0172\u0001\u0000\u0000"+ - "\u0000\u0196\u0173\u0001\u0000\u0000\u0000\u0196\u0174\u0001\u0000\u0000"+ - "\u0000\u0196\u0175\u0001\u0000\u0000\u0000\u0196\u0180\u0001\u0000\u0000"+ - "\u0000\u0196\u018b\u0001\u0000\u0000\u0000\u01979\u0001\u0000\u0000\u0000"+ - "\u0198\u0199\u0005\n\u0000\u0000\u0199\u019a\u0005\u001e\u0000\u0000\u019a"+ - ";\u0001\u0000\u0000\u0000\u019b\u019c\u0005\u0011\u0000\u0000\u019c\u01a1"+ - "\u0003>\u001f\u0000\u019d\u019e\u0005%\u0000\u0000\u019e\u01a0\u0003>"+ - "\u001f\u0000\u019f\u019d\u0001\u0000\u0000\u0000\u01a0\u01a3\u0001\u0000"+ - "\u0000\u0000\u01a1\u019f\u0001\u0000\u0000\u0000\u01a1\u01a2\u0001\u0000"+ - "\u0000\u0000\u01a2=\u0001\u0000\u0000\u0000\u01a3\u01a1\u0001\u0000\u0000"+ - "\u0000\u01a4\u01a6\u0003\n\u0005\u0000\u01a5\u01a7\u0007\u0003\u0000\u0000"+ - "\u01a6\u01a5\u0001\u0000\u0000\u0000\u01a6\u01a7\u0001\u0000\u0000\u0000"+ - "\u01a7\u01aa\u0001\u0000\u0000\u0000\u01a8\u01a9\u00051\u0000\u0000\u01a9"+ - "\u01ab\u0007\u0004\u0000\u0000\u01aa\u01a8\u0001\u0000\u0000\u0000\u01aa"+ - "\u01ab\u0001\u0000\u0000\u0000\u01ab?\u0001\u0000\u0000\u0000\u01ac\u01ad"+ - "\u0005\t\u0000\u0000\u01ad\u01b2\u00032\u0019\u0000\u01ae\u01af\u0005"+ - "%\u0000\u0000\u01af\u01b1\u00032\u0019\u0000\u01b0\u01ae\u0001\u0000\u0000"+ - "\u0000\u01b1\u01b4\u0001\u0000\u0000\u0000\u01b2\u01b0\u0001\u0000\u0000"+ - "\u0000\u01b2\u01b3\u0001\u0000\u0000\u0000\u01b3A\u0001\u0000\u0000\u0000"+ - "\u01b4\u01b2\u0001\u0000\u0000\u0000\u01b5\u01b6\u0005\u0002\u0000\u0000"+ - "\u01b6\u01bb\u00032\u0019\u0000\u01b7\u01b8\u0005%\u0000\u0000\u01b8\u01ba"+ - "\u00032\u0019\u0000\u01b9\u01b7\u0001\u0000\u0000\u0000\u01ba\u01bd\u0001"+ - "\u0000\u0000\u0000\u01bb\u01b9\u0001\u0000\u0000\u0000\u01bb\u01bc\u0001"+ - "\u0000\u0000\u0000\u01bcC\u0001\u0000\u0000\u0000\u01bd\u01bb\u0001\u0000"+ - "\u0000\u0000\u01be\u01bf\u0005\u000e\u0000\u0000\u01bf\u01c4\u0003F#\u0000"+ - "\u01c0\u01c1\u0005%\u0000\u0000\u01c1\u01c3\u0003F#\u0000\u01c2\u01c0"+ - "\u0001\u0000\u0000\u0000\u01c3\u01c6\u0001\u0000\u0000\u0000\u01c4\u01c2"+ - "\u0001\u0000\u0000\u0000\u01c4\u01c5\u0001\u0000\u0000\u0000\u01c5E\u0001"+ - "\u0000\u0000\u0000\u01c6\u01c4\u0001\u0000\u0000\u0000\u01c7\u01c8\u0003"+ - "2\u0019\u0000\u01c8\u01c9\u0005R\u0000\u0000\u01c9\u01ca\u00032\u0019"+ - "\u0000\u01caG\u0001\u0000\u0000\u0000\u01cb\u01cc\u0005\u0001\u0000\u0000"+ - "\u01cc\u01cd\u0003\u0012\t\u0000\u01cd\u01cf\u0003Z-\u0000\u01ce\u01d0"+ - "\u0003N\'\u0000\u01cf\u01ce\u0001\u0000\u0000\u0000\u01cf\u01d0\u0001"+ - "\u0000\u0000\u0000\u01d0I\u0001\u0000\u0000\u0000\u01d1\u01d2\u0005\u0007"+ - "\u0000\u0000\u01d2\u01d3\u0003\u0012\t\u0000\u01d3\u01d4\u0003Z-\u0000"+ - "\u01d4K\u0001\u0000\u0000\u0000\u01d5\u01d6\u0005\r\u0000\u0000\u01d6"+ - "\u01d7\u00030\u0018\u0000\u01d7M\u0001\u0000\u0000\u0000\u01d8\u01dd\u0003"+ - "P(\u0000\u01d9\u01da\u0005%\u0000\u0000\u01da\u01dc\u0003P(\u0000\u01db"+ - "\u01d9\u0001\u0000\u0000\u0000\u01dc\u01df\u0001\u0000\u0000\u0000\u01dd"+ - "\u01db\u0001\u0000\u0000\u0000\u01dd\u01de\u0001\u0000\u0000\u0000\u01de"+ - "O\u0001\u0000\u0000\u0000\u01df\u01dd\u0001\u0000\u0000\u0000\u01e0\u01e1"+ - "\u00034\u001a\u0000\u01e1\u01e2\u0005#\u0000\u0000\u01e2\u01e3\u00038"+ - "\u001c\u0000\u01e3Q\u0001\u0000\u0000\u0000\u01e4\u01e5\u0007\u0005\u0000"+ - "\u0000\u01e5S\u0001\u0000\u0000\u0000\u01e6\u01e9\u0003V+\u0000\u01e7"+ - "\u01e9\u0003X,\u0000\u01e8\u01e6\u0001\u0000\u0000\u0000\u01e8\u01e7\u0001"+ - "\u0000\u0000\u0000\u01e9U\u0001\u0000\u0000\u0000\u01ea\u01ec\u0007\u0000"+ - "\u0000\u0000\u01eb\u01ea\u0001\u0000\u0000\u0000\u01eb\u01ec\u0001\u0000"+ - "\u0000\u0000\u01ec\u01ed\u0001\u0000\u0000\u0000\u01ed\u01ee\u0005\u001f"+ - "\u0000\u0000\u01eeW\u0001\u0000\u0000\u0000\u01ef\u01f1\u0007\u0000\u0000"+ - "\u0000\u01f0\u01ef\u0001\u0000\u0000\u0000\u01f0\u01f1\u0001\u0000\u0000"+ - "\u0000\u01f1\u01f2\u0001\u0000\u0000\u0000\u01f2\u01f3\u0005\u001e\u0000"+ - "\u0000\u01f3Y\u0001\u0000\u0000\u0000\u01f4\u01f5\u0005\u001d\u0000\u0000"+ - "\u01f5[\u0001\u0000\u0000\u0000\u01f6\u01f7\u0007\u0006\u0000\u0000\u01f7"+ - "]\u0001\u0000\u0000\u0000\u01f8\u01f9\u0005\u0005\u0000\u0000\u01f9\u01fa"+ - "\u0003`0\u0000\u01fa_\u0001\u0000\u0000\u0000\u01fb\u01fc\u0005C\u0000"+ - "\u0000\u01fc\u01fd\u0003\u0002\u0001\u0000\u01fd\u01fe\u0005D\u0000\u0000"+ - "\u01fea\u0001\u0000\u0000\u0000\u01ff\u0200\u0005\u0010\u0000\u0000\u0200"+ - "\u0201\u0005b\u0000\u0000\u0201c\u0001\u0000\u0000\u0000\u0202\u0203\u0005"+ - "\u000b\u0000\u0000\u0203\u0204\u0005f\u0000\u0000\u0204e\u0001\u0000\u0000"+ - "\u0000\u0205\u0206\u0005\u0003\u0000\u0000\u0206\u0209\u0005X\u0000\u0000"+ - "\u0207\u0208\u0005V\u0000\u0000\u0208\u020a\u00032\u0019\u0000\u0209\u0207"+ - "\u0001\u0000\u0000\u0000\u0209\u020a\u0001\u0000\u0000\u0000\u020a\u0214"+ - "\u0001\u0000\u0000\u0000\u020b\u020c\u0005W\u0000\u0000\u020c\u0211\u0003"+ - "h4\u0000\u020d\u020e\u0005%\u0000\u0000\u020e\u0210\u0003h4\u0000\u020f"+ - "\u020d\u0001\u0000\u0000\u0000\u0210\u0213\u0001\u0000\u0000\u0000\u0211"+ - "\u020f\u0001\u0000\u0000\u0000\u0211\u0212\u0001\u0000\u0000\u0000\u0212"+ - "\u0215\u0001\u0000\u0000\u0000\u0213\u0211\u0001\u0000\u0000\u0000\u0214"+ - "\u020b\u0001\u0000\u0000\u0000\u0214\u0215\u0001\u0000\u0000\u0000\u0215"+ - "g\u0001\u0000\u0000\u0000\u0216\u0217\u00032\u0019\u0000\u0217\u0218\u0005"+ - "#\u0000\u0000\u0218\u021a\u0001\u0000\u0000\u0000\u0219\u0216\u0001\u0000"+ - "\u0000\u0000\u0219\u021a\u0001\u0000\u0000\u0000\u021a\u021b\u0001\u0000"+ - "\u0000\u0000\u021b\u021c\u00032\u0019\u0000\u021ci\u0001\u0000\u0000\u0000"+ - "5u~\u008d\u0099\u00a2\u00aa\u00ae\u00b6\u00b8\u00bd\u00c4\u00c9\u00d0"+ - "\u00d6\u00de\u00e0\u00eb\u00f2\u00fd\u0100\u010e\u0116\u011e\u0122\u0128"+ - "\u0130\u013d\u0141\u0145\u014c\u0150\u0156\u015d\u0165\u017b\u0186\u0191"+ - "\u0196\u01a1\u01a6\u01aa\u01b2\u01bb\u01c4\u01cf\u01dd\u01e8\u01eb\u01f0"+ - "\u0209\u0211\u0214\u0219"; + "2\u00072\u00023\u00073\u00024\u00074\u00025\u00075\u00026\u00076\u0001"+ + "\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ + "\u0001\u0001\u0001\u0001\u0001\u0005\u0001x\b\u0001\n\u0001\f\u0001{\t"+ + "\u0001\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001"+ + "\u0002\u0003\u0002\u0083\b\u0002\u0001\u0003\u0001\u0003\u0001\u0003\u0001"+ + "\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001"+ + "\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0003\u0003\u0093"+ + "\b\u0003\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001"+ + "\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0003\u0005\u009f"+ + "\b\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0005"+ + "\u0005\u00a6\b\u0005\n\u0005\f\u0005\u00a9\t\u0005\u0001\u0005\u0001\u0005"+ + "\u0001\u0005\u0001\u0005\u0001\u0005\u0003\u0005\u00b0\b\u0005\u0001\u0005"+ + "\u0001\u0005\u0003\u0005\u00b4\b\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+ + "\u0001\u0005\u0001\u0005\u0001\u0005\u0005\u0005\u00bc\b\u0005\n\u0005"+ + "\f\u0005\u00bf\t\u0005\u0001\u0006\u0001\u0006\u0003\u0006\u00c3\b\u0006"+ + "\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0003\u0006"+ + "\u00ca\b\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0003\u0006\u00cf\b"+ + "\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0003"+ + "\u0007\u00d6\b\u0007\u0001\b\u0001\b\u0001\b\u0001\b\u0003\b\u00dc\b\b"+ + "\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0005\b\u00e4\b\b\n\b"+ + "\f\b\u00e7\t\b\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t"+ + "\u0001\t\u0003\t\u00f1\b\t\u0001\t\u0001\t\u0001\t\u0005\t\u00f6\b\t\n"+ + "\t\f\t\u00f9\t\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0005"+ + "\n\u0101\b\n\n\n\f\n\u0104\t\n\u0003\n\u0106\b\n\u0001\n\u0001\n\u0001"+ + "\u000b\u0001\u000b\u0001\f\u0001\f\u0001\f\u0001\r\u0001\r\u0001\r\u0005"+ + "\r\u0112\b\r\n\r\f\r\u0115\t\r\u0001\u000e\u0001\u000e\u0001\u000e\u0001"+ + "\u000e\u0001\u000e\u0003\u000e\u011c\b\u000e\u0001\u000f\u0001\u000f\u0001"+ + "\u000f\u0001\u000f\u0005\u000f\u0122\b\u000f\n\u000f\f\u000f\u0125\t\u000f"+ + "\u0001\u000f\u0003\u000f\u0128\b\u000f\u0001\u0010\u0001\u0010\u0001\u0011"+ + "\u0001\u0011\u0003\u0011\u012e\b\u0011\u0001\u0012\u0001\u0012\u0001\u0012"+ + "\u0001\u0012\u0005\u0012\u0134\b\u0012\n\u0012\f\u0012\u0137\t\u0012\u0001"+ + "\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0014\u0001\u0014\u0001"+ + "\u0014\u0001\u0014\u0005\u0014\u0141\b\u0014\n\u0014\f\u0014\u0144\t\u0014"+ + "\u0001\u0014\u0003\u0014\u0147\b\u0014\u0001\u0014\u0001\u0014\u0003\u0014"+ + "\u014b\b\u0014\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016"+ + "\u0003\u0016\u0152\b\u0016\u0001\u0016\u0001\u0016\u0003\u0016\u0156\b"+ + "\u0016\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017\u0003\u0017\u015c"+ + "\b\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0005\u0018\u0161\b\u0018"+ + "\n\u0018\f\u0018\u0164\t\u0018\u0001\u0019\u0001\u0019\u0001\u0019\u0005"+ + "\u0019\u0169\b\u0019\n\u0019\f\u0019\u016c\t\u0019\u0001\u001a\u0001\u001a"+ + "\u0001\u001a\u0005\u001a\u0171\b\u001a\n\u001a\f\u001a\u0174\t\u001a\u0001"+ + "\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001\u001d\u0001\u001d\u0001"+ + "\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001"+ + "\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0005\u001d\u0187"+ + "\b\u001d\n\u001d\f\u001d\u018a\t\u001d\u0001\u001d\u0001\u001d\u0001\u001d"+ + "\u0001\u001d\u0001\u001d\u0001\u001d\u0005\u001d\u0192\b\u001d\n\u001d"+ + "\f\u001d\u0195\t\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d"+ + "\u0001\u001d\u0001\u001d\u0005\u001d\u019d\b\u001d\n\u001d\f\u001d\u01a0"+ + "\t\u001d\u0001\u001d\u0001\u001d\u0003\u001d\u01a4\b\u001d\u0001\u001e"+ + "\u0001\u001e\u0001\u001e\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f"+ + "\u0005\u001f\u01ad\b\u001f\n\u001f\f\u001f\u01b0\t\u001f\u0001 \u0001"+ + " \u0003 \u01b4\b \u0001 \u0001 \u0003 \u01b8\b \u0001!\u0001!\u0001!\u0001"+ + "\"\u0001\"\u0001\"\u0001#\u0001#\u0001#\u0001#\u0005#\u01c4\b#\n#\f#\u01c7"+ + "\t#\u0001$\u0001$\u0001$\u0001$\u0001%\u0001%\u0001%\u0001%\u0003%\u01d1"+ + "\b%\u0001&\u0001&\u0001&\u0001&\u0001\'\u0001\'\u0001\'\u0001(\u0001("+ + "\u0001(\u0005(\u01dd\b(\n(\f(\u01e0\t(\u0001)\u0001)\u0001)\u0001)\u0001"+ + "*\u0001*\u0001+\u0001+\u0003+\u01ea\b+\u0001,\u0003,\u01ed\b,\u0001,\u0001"+ + ",\u0001-\u0003-\u01f2\b-\u0001-\u0001-\u0001.\u0001.\u0001/\u0001/\u0001"+ + "0\u00010\u00010\u00011\u00011\u00011\u00011\u00012\u00012\u00012\u0001"+ + "3\u00013\u00013\u00014\u00014\u00014\u00014\u00034\u020b\b4\u00014\u0001"+ + "4\u00014\u00014\u00054\u0211\b4\n4\f4\u0214\t4\u00034\u0216\b4\u00015"+ + "\u00015\u00015\u00035\u021b\b5\u00015\u00015\u00016\u00016\u00016\u0001"+ + "6\u00016\u00016\u0000\u0004\u0002\n\u0010\u00127\u0000\u0002\u0004\u0006"+ + "\b\n\f\u000e\u0010\u0012\u0014\u0016\u0018\u001a\u001c\u001e \"$&(*,."+ + "02468:<>@BDFHJLNPRTVXZ\\^`bdfhjl\u0000\u0007\u0001\u0000?@\u0001\u0000"+ + "AC\u0001\u0000FG\u0002\u0000##\'\'\u0001\u0000*+\u0002\u0000))77\u0002"+ + "\u000088:>\u023e\u0000n\u0001\u0000\u0000\u0000\u0002q\u0001\u0000\u0000"+ + "\u0000\u0004\u0082\u0001\u0000\u0000\u0000\u0006\u0092\u0001\u0000\u0000"+ + "\u0000\b\u0094\u0001\u0000\u0000\u0000\n\u00b3\u0001\u0000\u0000\u0000"+ + "\f\u00ce\u0001\u0000\u0000\u0000\u000e\u00d5\u0001\u0000\u0000\u0000\u0010"+ + "\u00db\u0001\u0000\u0000\u0000\u0012\u00f0\u0001\u0000\u0000\u0000\u0014"+ + "\u00fa\u0001\u0000\u0000\u0000\u0016\u0109\u0001\u0000\u0000\u0000\u0018"+ + "\u010b\u0001\u0000\u0000\u0000\u001a\u010e\u0001\u0000\u0000\u0000\u001c"+ + "\u011b\u0001\u0000\u0000\u0000\u001e\u011d\u0001\u0000\u0000\u0000 \u0129"+ + "\u0001\u0000\u0000\u0000\"\u012d\u0001\u0000\u0000\u0000$\u012f\u0001"+ + "\u0000\u0000\u0000&\u0138\u0001\u0000\u0000\u0000(\u013c\u0001\u0000\u0000"+ + "\u0000*\u014c\u0001\u0000\u0000\u0000,\u014f\u0001\u0000\u0000\u0000."+ + "\u0157\u0001\u0000\u0000\u00000\u015d\u0001\u0000\u0000\u00002\u0165\u0001"+ + "\u0000\u0000\u00004\u016d\u0001\u0000\u0000\u00006\u0175\u0001\u0000\u0000"+ + "\u00008\u0177\u0001\u0000\u0000\u0000:\u01a3\u0001\u0000\u0000\u0000<"+ + "\u01a5\u0001\u0000\u0000\u0000>\u01a8\u0001\u0000\u0000\u0000@\u01b1\u0001"+ + "\u0000\u0000\u0000B\u01b9\u0001\u0000\u0000\u0000D\u01bc\u0001\u0000\u0000"+ + "\u0000F\u01bf\u0001\u0000\u0000\u0000H\u01c8\u0001\u0000\u0000\u0000J"+ + "\u01cc\u0001\u0000\u0000\u0000L\u01d2\u0001\u0000\u0000\u0000N\u01d6\u0001"+ + "\u0000\u0000\u0000P\u01d9\u0001\u0000\u0000\u0000R\u01e1\u0001\u0000\u0000"+ + "\u0000T\u01e5\u0001\u0000\u0000\u0000V\u01e9\u0001\u0000\u0000\u0000X"+ + "\u01ec\u0001\u0000\u0000\u0000Z\u01f1\u0001\u0000\u0000\u0000\\\u01f5"+ + "\u0001\u0000\u0000\u0000^\u01f7\u0001\u0000\u0000\u0000`\u01f9\u0001\u0000"+ + "\u0000\u0000b\u01fc\u0001\u0000\u0000\u0000d\u0200\u0001\u0000\u0000\u0000"+ + "f\u0203\u0001\u0000\u0000\u0000h\u0206\u0001\u0000\u0000\u0000j\u021a"+ + "\u0001\u0000\u0000\u0000l\u021e\u0001\u0000\u0000\u0000no\u0003\u0002"+ + "\u0001\u0000op\u0005\u0000\u0000\u0001p\u0001\u0001\u0000\u0000\u0000"+ + "qr\u0006\u0001\uffff\uffff\u0000rs\u0003\u0004\u0002\u0000sy\u0001\u0000"+ + "\u0000\u0000tu\n\u0001\u0000\u0000uv\u0005\u001d\u0000\u0000vx\u0003\u0006"+ + "\u0003\u0000wt\u0001\u0000\u0000\u0000x{\u0001\u0000\u0000\u0000yw\u0001"+ + "\u0000\u0000\u0000yz\u0001\u0000\u0000\u0000z\u0003\u0001\u0000\u0000"+ + "\u0000{y\u0001\u0000\u0000\u0000|\u0083\u0003`0\u0000}\u0083\u0003\u001e"+ + "\u000f\u0000~\u0083\u0003\u0018\f\u0000\u007f\u0083\u0003(\u0014\u0000"+ + "\u0080\u0083\u0003d2\u0000\u0081\u0083\u0003f3\u0000\u0082|\u0001\u0000"+ + "\u0000\u0000\u0082}\u0001\u0000\u0000\u0000\u0082~\u0001\u0000\u0000\u0000"+ + "\u0082\u007f\u0001\u0000\u0000\u0000\u0082\u0080\u0001\u0000\u0000\u0000"+ + "\u0082\u0081\u0001\u0000\u0000\u0000\u0083\u0005\u0001\u0000\u0000\u0000"+ + "\u0084\u0093\u0003*\u0015\u0000\u0085\u0093\u0003.\u0017\u0000\u0086\u0093"+ + "\u0003<\u001e\u0000\u0087\u0093\u0003l6\u0000\u0088\u0093\u0003B!\u0000"+ + "\u0089\u0093\u0003>\u001f\u0000\u008a\u0093\u0003,\u0016\u0000\u008b\u0093"+ + "\u0003\b\u0004\u0000\u008c\u0093\u0003D\"\u0000\u008d\u0093\u0003F#\u0000"+ + "\u008e\u0093\u0003J%\u0000\u008f\u0093\u0003L&\u0000\u0090\u0093\u0003"+ + "h4\u0000\u0091\u0093\u0003N\'\u0000\u0092\u0084\u0001\u0000\u0000\u0000"+ + "\u0092\u0085\u0001\u0000\u0000\u0000\u0092\u0086\u0001\u0000\u0000\u0000"+ + "\u0092\u0087\u0001\u0000\u0000\u0000\u0092\u0088\u0001\u0000\u0000\u0000"+ + "\u0092\u0089\u0001\u0000\u0000\u0000\u0092\u008a\u0001\u0000\u0000\u0000"+ + "\u0092\u008b\u0001\u0000\u0000\u0000\u0092\u008c\u0001\u0000\u0000\u0000"+ + "\u0092\u008d\u0001\u0000\u0000\u0000\u0092\u008e\u0001\u0000\u0000\u0000"+ + "\u0092\u008f\u0001\u0000\u0000\u0000\u0092\u0090\u0001\u0000\u0000\u0000"+ + "\u0092\u0091\u0001\u0000\u0000\u0000\u0093\u0007\u0001\u0000\u0000\u0000"+ + "\u0094\u0095\u0005\u0014\u0000\u0000\u0095\u0096\u0003\n\u0005\u0000\u0096"+ + "\t\u0001\u0000\u0000\u0000\u0097\u0098\u0006\u0005\uffff\uffff\u0000\u0098"+ + "\u0099\u00050\u0000\u0000\u0099\u00b4\u0003\n\u0005\u0007\u009a\u00b4"+ + "\u0003\u000e\u0007\u0000\u009b\u00b4\u0003\f\u0006\u0000\u009c\u009e\u0003"+ + "\u000e\u0007\u0000\u009d\u009f\u00050\u0000\u0000\u009e\u009d\u0001\u0000"+ + "\u0000\u0000\u009e\u009f\u0001\u0000\u0000\u0000\u009f\u00a0\u0001\u0000"+ + "\u0000\u0000\u00a0\u00a1\u0005-\u0000\u0000\u00a1\u00a2\u0005,\u0000\u0000"+ + "\u00a2\u00a7\u0003\u000e\u0007\u0000\u00a3\u00a4\u0005&\u0000\u0000\u00a4"+ + "\u00a6\u0003\u000e\u0007\u0000\u00a5\u00a3\u0001\u0000\u0000\u0000\u00a6"+ + "\u00a9\u0001\u0000\u0000\u0000\u00a7\u00a5\u0001\u0000\u0000\u0000\u00a7"+ + "\u00a8\u0001\u0000\u0000\u0000\u00a8\u00aa\u0001\u0000\u0000\u0000\u00a9"+ + "\u00a7\u0001\u0000\u0000\u0000\u00aa\u00ab\u00056\u0000\u0000\u00ab\u00b4"+ + "\u0001\u0000\u0000\u0000\u00ac\u00ad\u0003\u000e\u0007\u0000\u00ad\u00af"+ + "\u0005.\u0000\u0000\u00ae\u00b0\u00050\u0000\u0000\u00af\u00ae\u0001\u0000"+ + "\u0000\u0000\u00af\u00b0\u0001\u0000\u0000\u0000\u00b0\u00b1\u0001\u0000"+ + "\u0000\u0000\u00b1\u00b2\u00051\u0000\u0000\u00b2\u00b4\u0001\u0000\u0000"+ + "\u0000\u00b3\u0097\u0001\u0000\u0000\u0000\u00b3\u009a\u0001\u0000\u0000"+ + "\u0000\u00b3\u009b\u0001\u0000\u0000\u0000\u00b3\u009c\u0001\u0000\u0000"+ + "\u0000\u00b3\u00ac\u0001\u0000\u0000\u0000\u00b4\u00bd\u0001\u0000\u0000"+ + "\u0000\u00b5\u00b6\n\u0004\u0000\u0000\u00b6\u00b7\u0005\"\u0000\u0000"+ + "\u00b7\u00bc\u0003\n\u0005\u0005\u00b8\u00b9\n\u0003\u0000\u0000\u00b9"+ + "\u00ba\u00053\u0000\u0000\u00ba\u00bc\u0003\n\u0005\u0004\u00bb\u00b5"+ + "\u0001\u0000\u0000\u0000\u00bb\u00b8\u0001\u0000\u0000\u0000\u00bc\u00bf"+ + "\u0001\u0000\u0000\u0000\u00bd\u00bb\u0001\u0000\u0000\u0000\u00bd\u00be"+ + "\u0001\u0000\u0000\u0000\u00be\u000b\u0001\u0000\u0000\u0000\u00bf\u00bd"+ + "\u0001\u0000\u0000\u0000\u00c0\u00c2\u0003\u000e\u0007\u0000\u00c1\u00c3"+ + "\u00050\u0000\u0000\u00c2\u00c1\u0001\u0000\u0000\u0000\u00c2\u00c3\u0001"+ + "\u0000\u0000\u0000\u00c3\u00c4\u0001\u0000\u0000\u0000\u00c4\u00c5\u0005"+ + "/\u0000\u0000\u00c5\u00c6\u0003\\.\u0000\u00c6\u00cf\u0001\u0000\u0000"+ + "\u0000\u00c7\u00c9\u0003\u000e\u0007\u0000\u00c8\u00ca\u00050\u0000\u0000"+ + "\u00c9\u00c8\u0001\u0000\u0000\u0000\u00c9\u00ca\u0001\u0000\u0000\u0000"+ + "\u00ca\u00cb\u0001\u0000\u0000\u0000\u00cb\u00cc\u00055\u0000\u0000\u00cc"+ + "\u00cd\u0003\\.\u0000\u00cd\u00cf\u0001\u0000\u0000\u0000\u00ce\u00c0"+ + "\u0001\u0000\u0000\u0000\u00ce\u00c7\u0001\u0000\u0000\u0000\u00cf\r\u0001"+ + "\u0000\u0000\u0000\u00d0\u00d6\u0003\u0010\b\u0000\u00d1\u00d2\u0003\u0010"+ + "\b\u0000\u00d2\u00d3\u0003^/\u0000\u00d3\u00d4\u0003\u0010\b\u0000\u00d4"+ + "\u00d6\u0001\u0000\u0000\u0000\u00d5\u00d0\u0001\u0000\u0000\u0000\u00d5"+ + "\u00d1\u0001\u0000\u0000\u0000\u00d6\u000f\u0001\u0000\u0000\u0000\u00d7"+ + "\u00d8\u0006\b\uffff\uffff\u0000\u00d8\u00dc\u0003\u0012\t\u0000\u00d9"+ + "\u00da\u0007\u0000\u0000\u0000\u00da\u00dc\u0003\u0010\b\u0003\u00db\u00d7"+ + "\u0001\u0000\u0000\u0000\u00db\u00d9\u0001\u0000\u0000\u0000\u00dc\u00e5"+ + "\u0001\u0000\u0000\u0000\u00dd\u00de\n\u0002\u0000\u0000\u00de\u00df\u0007"+ + "\u0001\u0000\u0000\u00df\u00e4\u0003\u0010\b\u0003\u00e0\u00e1\n\u0001"+ + "\u0000\u0000\u00e1\u00e2\u0007\u0000\u0000\u0000\u00e2\u00e4\u0003\u0010"+ + "\b\u0002\u00e3\u00dd\u0001\u0000\u0000\u0000\u00e3\u00e0\u0001\u0000\u0000"+ + "\u0000\u00e4\u00e7\u0001\u0000\u0000\u0000\u00e5\u00e3\u0001\u0000\u0000"+ + "\u0000\u00e5\u00e6\u0001\u0000\u0000\u0000\u00e6\u0011\u0001\u0000\u0000"+ + "\u0000\u00e7\u00e5\u0001\u0000\u0000\u0000\u00e8\u00e9\u0006\t\uffff\uffff"+ + "\u0000\u00e9\u00f1\u0003:\u001d\u0000\u00ea\u00f1\u00030\u0018\u0000\u00eb"+ + "\u00f1\u0003\u0014\n\u0000\u00ec\u00ed\u0005,\u0000\u0000\u00ed\u00ee"+ + "\u0003\n\u0005\u0000\u00ee\u00ef\u00056\u0000\u0000\u00ef\u00f1\u0001"+ + "\u0000\u0000\u0000\u00f0\u00e8\u0001\u0000\u0000\u0000\u00f0\u00ea\u0001"+ + "\u0000\u0000\u0000\u00f0\u00eb\u0001\u0000\u0000\u0000\u00f0\u00ec\u0001"+ + "\u0000\u0000\u0000\u00f1\u00f7\u0001\u0000\u0000\u0000\u00f2\u00f3\n\u0001"+ + "\u0000\u0000\u00f3\u00f4\u0005%\u0000\u0000\u00f4\u00f6\u0003\u0016\u000b"+ + "\u0000\u00f5\u00f2\u0001\u0000\u0000\u0000\u00f6\u00f9\u0001\u0000\u0000"+ + "\u0000\u00f7\u00f5\u0001\u0000\u0000\u0000\u00f7\u00f8\u0001\u0000\u0000"+ + "\u0000\u00f8\u0013\u0001\u0000\u0000\u0000\u00f9\u00f7\u0001\u0000\u0000"+ + "\u0000\u00fa\u00fb\u00036\u001b\u0000\u00fb\u0105\u0005,\u0000\u0000\u00fc"+ + "\u0106\u0005A\u0000\u0000\u00fd\u0102\u0003\n\u0005\u0000\u00fe\u00ff"+ + "\u0005&\u0000\u0000\u00ff\u0101\u0003\n\u0005\u0000\u0100\u00fe\u0001"+ + "\u0000\u0000\u0000\u0101\u0104\u0001\u0000\u0000\u0000\u0102\u0100\u0001"+ + "\u0000\u0000\u0000\u0102\u0103\u0001\u0000\u0000\u0000\u0103\u0106\u0001"+ + "\u0000\u0000\u0000\u0104\u0102\u0001\u0000\u0000\u0000\u0105\u00fc\u0001"+ + "\u0000\u0000\u0000\u0105\u00fd\u0001\u0000\u0000\u0000\u0105\u0106\u0001"+ + "\u0000\u0000\u0000\u0106\u0107\u0001\u0000\u0000\u0000\u0107\u0108\u0005"+ + "6\u0000\u0000\u0108\u0015\u0001\u0000\u0000\u0000\u0109\u010a\u00036\u001b"+ + "\u0000\u010a\u0017\u0001\u0000\u0000\u0000\u010b\u010c\u0005\u0010\u0000"+ + "\u0000\u010c\u010d\u0003\u001a\r\u0000\u010d\u0019\u0001\u0000\u0000\u0000"+ + "\u010e\u0113\u0003\u001c\u000e\u0000\u010f\u0110\u0005&\u0000\u0000\u0110"+ + "\u0112\u0003\u001c\u000e\u0000\u0111\u010f\u0001\u0000\u0000\u0000\u0112"+ + "\u0115\u0001\u0000\u0000\u0000\u0113\u0111\u0001\u0000\u0000\u0000\u0113"+ + "\u0114\u0001\u0000\u0000\u0000\u0114\u001b\u0001\u0000\u0000\u0000\u0115"+ + "\u0113\u0001\u0000\u0000\u0000\u0116\u011c\u0003\n\u0005\u0000\u0117\u0118"+ + "\u00030\u0018\u0000\u0118\u0119\u0005$\u0000\u0000\u0119\u011a\u0003\n"+ + "\u0005\u0000\u011a\u011c\u0001\u0000\u0000\u0000\u011b\u0116\u0001\u0000"+ + "\u0000\u0000\u011b\u0117\u0001\u0000\u0000\u0000\u011c\u001d\u0001\u0000"+ + "\u0000\u0000\u011d\u011e\u0005\u0006\u0000\u0000\u011e\u0123\u0003 \u0010"+ + "\u0000\u011f\u0120\u0005&\u0000\u0000\u0120\u0122\u0003 \u0010\u0000\u0121"+ + "\u011f\u0001\u0000\u0000\u0000\u0122\u0125\u0001\u0000\u0000\u0000\u0123"+ + "\u0121\u0001\u0000\u0000\u0000\u0123\u0124\u0001\u0000\u0000\u0000\u0124"+ + "\u0127\u0001\u0000\u0000\u0000\u0125\u0123\u0001\u0000\u0000\u0000\u0126"+ + "\u0128\u0003\"\u0011\u0000\u0127\u0126\u0001\u0000\u0000\u0000\u0127\u0128"+ + "\u0001\u0000\u0000\u0000\u0128\u001f\u0001\u0000\u0000\u0000\u0129\u012a"+ + "\u0005\u0019\u0000\u0000\u012a!\u0001\u0000\u0000\u0000\u012b\u012e\u0003"+ + "$\u0012\u0000\u012c\u012e\u0003&\u0013\u0000\u012d\u012b\u0001\u0000\u0000"+ + "\u0000\u012d\u012c\u0001\u0000\u0000\u0000\u012e#\u0001\u0000\u0000\u0000"+ + "\u012f\u0130\u0005K\u0000\u0000\u0130\u0135\u0003 \u0010\u0000\u0131\u0132"+ + "\u0005&\u0000\u0000\u0132\u0134\u0003 \u0010\u0000\u0133\u0131\u0001\u0000"+ + "\u0000\u0000\u0134\u0137\u0001\u0000\u0000\u0000\u0135\u0133\u0001\u0000"+ + "\u0000\u0000\u0135\u0136\u0001\u0000\u0000\u0000\u0136%\u0001\u0000\u0000"+ + "\u0000\u0137\u0135\u0001\u0000\u0000\u0000\u0138\u0139\u0005D\u0000\u0000"+ + "\u0139\u013a\u0003$\u0012\u0000\u013a\u013b\u0005E\u0000\u0000\u013b\'"+ + "\u0001\u0000\u0000\u0000\u013c\u013d\u0005\r\u0000\u0000\u013d\u0142\u0003"+ + " \u0010\u0000\u013e\u013f\u0005&\u0000\u0000\u013f\u0141\u0003 \u0010"+ + "\u0000\u0140\u013e\u0001\u0000\u0000\u0000\u0141\u0144\u0001\u0000\u0000"+ + "\u0000\u0142\u0140\u0001\u0000\u0000\u0000\u0142\u0143\u0001\u0000\u0000"+ + "\u0000\u0143\u0146\u0001\u0000\u0000\u0000\u0144\u0142\u0001\u0000\u0000"+ + "\u0000\u0145\u0147\u0003\u001a\r\u0000\u0146\u0145\u0001\u0000\u0000\u0000"+ + "\u0146\u0147\u0001\u0000\u0000\u0000\u0147\u014a\u0001\u0000\u0000\u0000"+ + "\u0148\u0149\u0005!\u0000\u0000\u0149\u014b\u0003\u001a\r\u0000\u014a"+ + "\u0148\u0001\u0000\u0000\u0000\u014a\u014b\u0001\u0000\u0000\u0000\u014b"+ + ")\u0001\u0000\u0000\u0000\u014c\u014d\u0005\u0004\u0000\u0000\u014d\u014e"+ + "\u0003\u001a\r\u0000\u014e+\u0001\u0000\u0000\u0000\u014f\u0151\u0005"+ + "\u0013\u0000\u0000\u0150\u0152\u0003\u001a\r\u0000\u0151\u0150\u0001\u0000"+ + "\u0000\u0000\u0151\u0152\u0001\u0000\u0000\u0000\u0152\u0155\u0001\u0000"+ + "\u0000\u0000\u0153\u0154\u0005!\u0000\u0000\u0154\u0156\u0003\u001a\r"+ + "\u0000\u0155\u0153\u0001\u0000\u0000\u0000\u0155\u0156\u0001\u0000\u0000"+ + "\u0000\u0156-\u0001\u0000\u0000\u0000\u0157\u0158\u0005\b\u0000\u0000"+ + "\u0158\u015b\u0003\u001a\r\u0000\u0159\u015a\u0005!\u0000\u0000\u015a"+ + "\u015c\u0003\u001a\r\u0000\u015b\u0159\u0001\u0000\u0000\u0000\u015b\u015c"+ + "\u0001\u0000\u0000\u0000\u015c/\u0001\u0000\u0000\u0000\u015d\u0162\u0003"+ + "6\u001b\u0000\u015e\u015f\u0005(\u0000\u0000\u015f\u0161\u00036\u001b"+ + "\u0000\u0160\u015e\u0001\u0000\u0000\u0000\u0161\u0164\u0001\u0000\u0000"+ + "\u0000\u0162\u0160\u0001\u0000\u0000\u0000\u0162\u0163\u0001\u0000\u0000"+ + "\u0000\u01631\u0001\u0000\u0000\u0000\u0164\u0162\u0001\u0000\u0000\u0000"+ + "\u0165\u016a\u00038\u001c\u0000\u0166\u0167\u0005(\u0000\u0000\u0167\u0169"+ + "\u00038\u001c\u0000\u0168\u0166\u0001\u0000\u0000\u0000\u0169\u016c\u0001"+ + "\u0000\u0000\u0000\u016a\u0168\u0001\u0000\u0000\u0000\u016a\u016b\u0001"+ + "\u0000\u0000\u0000\u016b3\u0001\u0000\u0000\u0000\u016c\u016a\u0001\u0000"+ + "\u0000\u0000\u016d\u0172\u00032\u0019\u0000\u016e\u016f\u0005&\u0000\u0000"+ + "\u016f\u0171\u00032\u0019\u0000\u0170\u016e\u0001\u0000\u0000\u0000\u0171"+ + "\u0174\u0001\u0000\u0000\u0000\u0172\u0170\u0001\u0000\u0000\u0000\u0172"+ + "\u0173\u0001\u0000\u0000\u0000\u01735\u0001\u0000\u0000\u0000\u0174\u0172"+ + "\u0001\u0000\u0000\u0000\u0175\u0176\u0007\u0002\u0000\u0000\u01767\u0001"+ + "\u0000\u0000\u0000\u0177\u0178\u0005O\u0000\u0000\u01789\u0001\u0000\u0000"+ + "\u0000\u0179\u01a4\u00051\u0000\u0000\u017a\u017b\u0003Z-\u0000\u017b"+ + "\u017c\u0005F\u0000\u0000\u017c\u01a4\u0001\u0000\u0000\u0000\u017d\u01a4"+ + "\u0003X,\u0000\u017e\u01a4\u0003Z-\u0000\u017f\u01a4\u0003T*\u0000\u0180"+ + "\u01a4\u00054\u0000\u0000\u0181\u01a4\u0003\\.\u0000\u0182\u0183\u0005"+ + "D\u0000\u0000\u0183\u0188\u0003V+\u0000\u0184\u0185\u0005&\u0000\u0000"+ + "\u0185\u0187\u0003V+\u0000\u0186\u0184\u0001\u0000\u0000\u0000\u0187\u018a"+ + "\u0001\u0000\u0000\u0000\u0188\u0186\u0001\u0000\u0000\u0000\u0188\u0189"+ + "\u0001\u0000\u0000\u0000\u0189\u018b\u0001\u0000\u0000\u0000\u018a\u0188"+ + "\u0001\u0000\u0000\u0000\u018b\u018c\u0005E\u0000\u0000\u018c\u01a4\u0001"+ + "\u0000\u0000\u0000\u018d\u018e\u0005D\u0000\u0000\u018e\u0193\u0003T*"+ + "\u0000\u018f\u0190\u0005&\u0000\u0000\u0190\u0192\u0003T*\u0000\u0191"+ + "\u018f\u0001\u0000\u0000\u0000\u0192\u0195\u0001\u0000\u0000\u0000\u0193"+ + "\u0191\u0001\u0000\u0000\u0000\u0193\u0194\u0001\u0000\u0000\u0000\u0194"+ + "\u0196\u0001\u0000\u0000\u0000\u0195\u0193\u0001\u0000\u0000\u0000\u0196"+ + "\u0197\u0005E\u0000\u0000\u0197\u01a4\u0001\u0000\u0000\u0000\u0198\u0199"+ + "\u0005D\u0000\u0000\u0199\u019e\u0003\\.\u0000\u019a\u019b\u0005&\u0000"+ + "\u0000\u019b\u019d\u0003\\.\u0000\u019c\u019a\u0001\u0000\u0000\u0000"+ + "\u019d\u01a0\u0001\u0000\u0000\u0000\u019e\u019c\u0001\u0000\u0000\u0000"+ + "\u019e\u019f\u0001\u0000\u0000\u0000\u019f\u01a1\u0001\u0000\u0000\u0000"+ + "\u01a0\u019e\u0001\u0000\u0000\u0000\u01a1\u01a2\u0005E\u0000\u0000\u01a2"+ + "\u01a4\u0001\u0000\u0000\u0000\u01a3\u0179\u0001\u0000\u0000\u0000\u01a3"+ + "\u017a\u0001\u0000\u0000\u0000\u01a3\u017d\u0001\u0000\u0000\u0000\u01a3"+ + "\u017e\u0001\u0000\u0000\u0000\u01a3\u017f\u0001\u0000\u0000\u0000\u01a3"+ + "\u0180\u0001\u0000\u0000\u0000\u01a3\u0181\u0001\u0000\u0000\u0000\u01a3"+ + "\u0182\u0001\u0000\u0000\u0000\u01a3\u018d\u0001\u0000\u0000\u0000\u01a3"+ + "\u0198\u0001\u0000\u0000\u0000\u01a4;\u0001\u0000\u0000\u0000\u01a5\u01a6"+ + "\u0005\n\u0000\u0000\u01a6\u01a7\u0005\u001f\u0000\u0000\u01a7=\u0001"+ + "\u0000\u0000\u0000\u01a8\u01a9\u0005\u0012\u0000\u0000\u01a9\u01ae\u0003"+ + "@ \u0000\u01aa\u01ab\u0005&\u0000\u0000\u01ab\u01ad\u0003@ \u0000\u01ac"+ + "\u01aa\u0001\u0000\u0000\u0000\u01ad\u01b0\u0001\u0000\u0000\u0000\u01ae"+ + "\u01ac\u0001\u0000\u0000\u0000\u01ae\u01af\u0001\u0000\u0000\u0000\u01af"+ + "?\u0001\u0000\u0000\u0000\u01b0\u01ae\u0001\u0000\u0000\u0000\u01b1\u01b3"+ + "\u0003\n\u0005\u0000\u01b2\u01b4\u0007\u0003\u0000\u0000\u01b3\u01b2\u0001"+ + "\u0000\u0000\u0000\u01b3\u01b4\u0001\u0000\u0000\u0000\u01b4\u01b7\u0001"+ + "\u0000\u0000\u0000\u01b5\u01b6\u00052\u0000\u0000\u01b6\u01b8\u0007\u0004"+ + "\u0000\u0000\u01b7\u01b5\u0001\u0000\u0000\u0000\u01b7\u01b8\u0001\u0000"+ + "\u0000\u0000\u01b8A\u0001\u0000\u0000\u0000\u01b9\u01ba\u0005\t\u0000"+ + "\u0000\u01ba\u01bb\u00034\u001a\u0000\u01bbC\u0001\u0000\u0000\u0000\u01bc"+ + "\u01bd\u0005\u0002\u0000\u0000\u01bd\u01be\u00034\u001a\u0000\u01beE\u0001"+ + "\u0000\u0000\u0000\u01bf\u01c0\u0005\u000f\u0000\u0000\u01c0\u01c5\u0003"+ + "H$\u0000\u01c1\u01c2\u0005&\u0000\u0000\u01c2\u01c4\u0003H$\u0000\u01c3"+ + "\u01c1\u0001\u0000\u0000\u0000\u01c4\u01c7\u0001\u0000\u0000\u0000\u01c5"+ + "\u01c3\u0001\u0000\u0000\u0000\u01c5\u01c6\u0001\u0000\u0000\u0000\u01c6"+ + "G\u0001\u0000\u0000\u0000\u01c7\u01c5\u0001\u0000\u0000\u0000\u01c8\u01c9"+ + "\u00032\u0019\u0000\u01c9\u01ca\u0005S\u0000\u0000\u01ca\u01cb\u00032"+ + "\u0019\u0000\u01cbI\u0001\u0000\u0000\u0000\u01cc\u01cd\u0005\u0001\u0000"+ + "\u0000\u01cd\u01ce\u0003\u0012\t\u0000\u01ce\u01d0\u0003\\.\u0000\u01cf"+ + "\u01d1\u0003P(\u0000\u01d0\u01cf\u0001\u0000\u0000\u0000\u01d0\u01d1\u0001"+ + "\u0000\u0000\u0000\u01d1K\u0001\u0000\u0000\u0000\u01d2\u01d3\u0005\u0007"+ + "\u0000\u0000\u01d3\u01d4\u0003\u0012\t\u0000\u01d4\u01d5\u0003\\.\u0000"+ + "\u01d5M\u0001\u0000\u0000\u0000\u01d6\u01d7\u0005\u000e\u0000\u0000\u01d7"+ + "\u01d8\u00030\u0018\u0000\u01d8O\u0001\u0000\u0000\u0000\u01d9\u01de\u0003"+ + "R)\u0000\u01da\u01db\u0005&\u0000\u0000\u01db\u01dd\u0003R)\u0000\u01dc"+ + "\u01da\u0001\u0000\u0000\u0000\u01dd\u01e0\u0001\u0000\u0000\u0000\u01de"+ + "\u01dc\u0001\u0000\u0000\u0000\u01de\u01df\u0001\u0000\u0000\u0000\u01df"+ + "Q\u0001\u0000\u0000\u0000\u01e0\u01de\u0001\u0000\u0000\u0000\u01e1\u01e2"+ + "\u00036\u001b\u0000\u01e2\u01e3\u0005$\u0000\u0000\u01e3\u01e4\u0003:"+ + "\u001d\u0000\u01e4S\u0001\u0000\u0000\u0000\u01e5\u01e6\u0007\u0005\u0000"+ + "\u0000\u01e6U\u0001\u0000\u0000\u0000\u01e7\u01ea\u0003X,\u0000\u01e8"+ + "\u01ea\u0003Z-\u0000\u01e9\u01e7\u0001\u0000\u0000\u0000\u01e9\u01e8\u0001"+ + "\u0000\u0000\u0000\u01eaW\u0001\u0000\u0000\u0000\u01eb\u01ed\u0007\u0000"+ + "\u0000\u0000\u01ec\u01eb\u0001\u0000\u0000\u0000\u01ec\u01ed\u0001\u0000"+ + "\u0000\u0000\u01ed\u01ee\u0001\u0000\u0000\u0000\u01ee\u01ef\u0005 \u0000"+ + "\u0000\u01efY\u0001\u0000\u0000\u0000\u01f0\u01f2\u0007\u0000\u0000\u0000"+ + "\u01f1\u01f0\u0001\u0000\u0000\u0000\u01f1\u01f2\u0001\u0000\u0000\u0000"+ + "\u01f2\u01f3\u0001\u0000\u0000\u0000\u01f3\u01f4\u0005\u001f\u0000\u0000"+ + "\u01f4[\u0001\u0000\u0000\u0000\u01f5\u01f6\u0005\u001e\u0000\u0000\u01f6"+ + "]\u0001\u0000\u0000\u0000\u01f7\u01f8\u0007\u0006\u0000\u0000\u01f8_\u0001"+ + "\u0000\u0000\u0000\u01f9\u01fa\u0005\u0005\u0000\u0000\u01fa\u01fb\u0003"+ + "b1\u0000\u01fba\u0001\u0000\u0000\u0000\u01fc\u01fd\u0005D\u0000\u0000"+ + "\u01fd\u01fe\u0003\u0002\u0001\u0000\u01fe\u01ff\u0005E\u0000\u0000\u01ff"+ + "c\u0001\u0000\u0000\u0000\u0200\u0201\u0005\u0011\u0000\u0000\u0201\u0202"+ + "\u0005i\u0000\u0000\u0202e\u0001\u0000\u0000\u0000\u0203\u0204\u0005\f"+ + "\u0000\u0000\u0204\u0205\u0005m\u0000\u0000\u0205g\u0001\u0000\u0000\u0000"+ + "\u0206\u0207\u0005\u0003\u0000\u0000\u0207\u020a\u0005Y\u0000\u0000\u0208"+ + "\u0209\u0005W\u0000\u0000\u0209\u020b\u00032\u0019\u0000\u020a\u0208\u0001"+ + "\u0000\u0000\u0000\u020a\u020b\u0001\u0000\u0000\u0000\u020b\u0215\u0001"+ + "\u0000\u0000\u0000\u020c\u020d\u0005X\u0000\u0000\u020d\u0212\u0003j5"+ + "\u0000\u020e\u020f\u0005&\u0000\u0000\u020f\u0211\u0003j5\u0000\u0210"+ + "\u020e\u0001\u0000\u0000\u0000\u0211\u0214\u0001\u0000\u0000\u0000\u0212"+ + "\u0210\u0001\u0000\u0000\u0000\u0212\u0213\u0001\u0000\u0000\u0000\u0213"+ + "\u0216\u0001\u0000\u0000\u0000\u0214\u0212\u0001\u0000\u0000\u0000\u0215"+ + "\u020c\u0001\u0000\u0000\u0000\u0215\u0216\u0001\u0000\u0000\u0000\u0216"+ + "i\u0001\u0000\u0000\u0000\u0217\u0218\u00032\u0019\u0000\u0218\u0219\u0005"+ + "$\u0000\u0000\u0219\u021b\u0001\u0000\u0000\u0000\u021a\u0217\u0001\u0000"+ + "\u0000\u0000\u021a\u021b\u0001\u0000\u0000\u0000\u021b\u021c\u0001\u0000"+ + "\u0000\u0000\u021c\u021d\u00032\u0019\u0000\u021dk\u0001\u0000\u0000\u0000"+ + "\u021e\u021f\u0005\u000b\u0000\u0000\u021f\u0220\u0005\u0019\u0000\u0000"+ + "\u0220\u0221\u0005W\u0000\u0000\u0221\u0222\u00034\u001a\u0000\u0222m"+ + "\u0001\u0000\u0000\u00004y\u0082\u0092\u009e\u00a7\u00af\u00b3\u00bb\u00bd"+ + "\u00c2\u00c9\u00ce\u00d5\u00db\u00e3\u00e5\u00f0\u00f7\u0102\u0105\u0113"+ + "\u011b\u0123\u0127\u012d\u0135\u0142\u0146\u014a\u0151\u0155\u015b\u0162"+ + "\u016a\u0172\u0188\u0193\u019e\u01a3\u01ae\u01b3\u01b7\u01c5\u01d0\u01de"+ + "\u01e9\u01ec\u01f1\u020a\u0212\u0215\u021a"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseListener.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseListener.java index e77e0294bba0b..760e8f4cb9cd3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseListener.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseListener.java @@ -480,6 +480,18 @@ public class EsqlBaseParserBaseListener implements EsqlBaseParserListener { *

The default implementation does nothing.

*/ @Override public void exitQualifiedNamePattern(EsqlBaseParser.QualifiedNamePatternContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterQualifiedNamePatterns(EsqlBaseParser.QualifiedNamePatternsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitQualifiedNamePatterns(EsqlBaseParser.QualifiedNamePatternsContext ctx) { } /** * {@inheritDoc} * @@ -912,6 +924,18 @@ public class EsqlBaseParserBaseListener implements EsqlBaseParserListener { *

The default implementation does nothing.

*/ @Override public void exitEnrichWithClause(EsqlBaseParser.EnrichWithClauseContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterLookupCommand(EsqlBaseParser.LookupCommandContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitLookupCommand(EsqlBaseParser.LookupCommandContext ctx) { } /** * {@inheritDoc} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseVisitor.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseVisitor.java index 66308d91dce19..aee998364f947 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseVisitor.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseVisitor.java @@ -285,6 +285,13 @@ public class EsqlBaseParserBaseVisitor extends AbstractParseTreeVisitor im * {@link #visitChildren} on {@code ctx}.

*/ @Override public T visitQualifiedNamePattern(EsqlBaseParser.QualifiedNamePatternContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitQualifiedNamePatterns(EsqlBaseParser.QualifiedNamePatternsContext ctx) { return visitChildren(ctx); } /** * {@inheritDoc} * @@ -537,4 +544,11 @@ public class EsqlBaseParserBaseVisitor extends AbstractParseTreeVisitor im * {@link #visitChildren} on {@code ctx}.

*/ @Override public T visitEnrichWithClause(EsqlBaseParser.EnrichWithClauseContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitLookupCommand(EsqlBaseParser.LookupCommandContext ctx) { return visitChildren(ctx); } } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserListener.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserListener.java index 978ac68670752..0c53191ab9ab7 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserListener.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserListener.java @@ -435,6 +435,16 @@ public interface EsqlBaseParserListener extends ParseTreeListener { * @param ctx the parse tree */ void exitQualifiedNamePattern(EsqlBaseParser.QualifiedNamePatternContext ctx); + /** + * Enter a parse tree produced by {@link EsqlBaseParser#qualifiedNamePatterns}. + * @param ctx the parse tree + */ + void enterQualifiedNamePatterns(EsqlBaseParser.QualifiedNamePatternsContext ctx); + /** + * Exit a parse tree produced by {@link EsqlBaseParser#qualifiedNamePatterns}. + * @param ctx the parse tree + */ + void exitQualifiedNamePatterns(EsqlBaseParser.QualifiedNamePatternsContext ctx); /** * Enter a parse tree produced by {@link EsqlBaseParser#identifier}. * @param ctx the parse tree @@ -819,4 +829,14 @@ public interface EsqlBaseParserListener extends ParseTreeListener { * @param ctx the parse tree */ void exitEnrichWithClause(EsqlBaseParser.EnrichWithClauseContext ctx); + /** + * Enter a parse tree produced by {@link EsqlBaseParser#lookupCommand}. + * @param ctx the parse tree + */ + void enterLookupCommand(EsqlBaseParser.LookupCommandContext ctx); + /** + * Exit a parse tree produced by {@link EsqlBaseParser#lookupCommand}. + * @param ctx the parse tree + */ + void exitLookupCommand(EsqlBaseParser.LookupCommandContext ctx); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserVisitor.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserVisitor.java index bd24afcd28c4a..54f506c9d3b3c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserVisitor.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserVisitor.java @@ -263,6 +263,12 @@ public interface EsqlBaseParserVisitor extends ParseTreeVisitor { * @return the visitor result */ T visitQualifiedNamePattern(EsqlBaseParser.QualifiedNamePatternContext ctx); + /** + * Visit a parse tree produced by {@link EsqlBaseParser#qualifiedNamePatterns}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitQualifiedNamePatterns(EsqlBaseParser.QualifiedNamePatternsContext ctx); /** * Visit a parse tree produced by {@link EsqlBaseParser#identifier}. * @param ctx the parse tree @@ -491,4 +497,10 @@ public interface EsqlBaseParserVisitor extends ParseTreeVisitor { * @return the visitor result */ T visitEnrichWithClause(EsqlBaseParser.EnrichWithClauseContext ctx); + /** + * Visit a parse tree produced by {@link EsqlBaseParser#lookupCommand}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitLookupCommand(EsqlBaseParser.LookupCommandContext ctx); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java index c80488cad4190..d026ffbeecbe2 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java @@ -71,7 +71,9 @@ import java.util.Locale; import java.util.Map; import java.util.function.BiFunction; +import java.util.function.Consumer; +import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static org.elasticsearch.xpack.esql.core.parser.ParserUtils.source; import static org.elasticsearch.xpack.esql.core.parser.ParserUtils.typedParsing; @@ -242,6 +244,37 @@ public UnresolvedAttribute visitQualifiedName(EsqlBaseParser.QualifiedNameContex return new UnresolvedAttribute(source(ctx), Strings.collectionToDelimitedString(strings, ".")); } + @Override + public List visitQualifiedNamePatterns(EsqlBaseParser.QualifiedNamePatternsContext ctx) { + return visitQualifiedNamePatterns(ctx, ne -> {}); + } + + protected List visitQualifiedNamePatterns( + EsqlBaseParser.QualifiedNamePatternsContext ctx, + Consumer checker + ) { + if (ctx == null) { + return emptyList(); + } + List identifiers = ctx.qualifiedNamePattern(); + List names = new ArrayList<>(identifiers.size()); + + for (EsqlBaseParser.QualifiedNamePatternContext patternContext : identifiers) { + names.add(visitQualifiedNamePattern(patternContext, checker)); + } + + return names; + } + + protected NamedExpression visitQualifiedNamePattern( + EsqlBaseParser.QualifiedNamePatternContext patternContext, + Consumer checker + ) { + NamedExpression ne = visitQualifiedNamePattern(patternContext); + checker.accept(ne); + return ne; + } + @Override public NamedExpression visitQualifiedNamePattern(EsqlBaseParser.QualifiedNamePatternContext ctx) { if (ctx == null) { @@ -601,11 +634,12 @@ public NamedExpression visitEnrichWithClause(EsqlBaseParser.EnrichWithClauseCont } private NamedExpression enrichFieldName(EsqlBaseParser.QualifiedNamePatternContext ctx) { - var name = visitQualifiedNamePattern(ctx); - if (name instanceof UnresolvedNamePattern up) { - throw new ParsingException(source(ctx), "Using wildcards [*] in ENRICH WITH projections is not allowed [{}]", up.pattern()); - } - return name; + return visitQualifiedNamePattern(ctx, ne -> { + if (ne instanceof UnresolvedNamePattern up) { + var src = ne.source(); + throw new ParsingException(src, "Using wildcards [*] in ENRICH WITH projections is not allowed [{}]", up.pattern()); + } + }); } @Override diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java index a7a3d0b816e79..9d13af4f7eba7 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java @@ -38,9 +38,9 @@ import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.Holder; import org.elasticsearch.xpack.esql.expression.UnresolvedNamePattern; import org.elasticsearch.xpack.esql.parser.EsqlBaseParser.MetadataOptionContext; -import org.elasticsearch.xpack.esql.parser.EsqlBaseParser.QualifiedNamePatternContext; import org.elasticsearch.xpack.esql.plan.logical.Dissect; import org.elasticsearch.xpack.esql.plan.logical.Drop; import org.elasticsearch.xpack.esql.plan.logical.Enrich; @@ -317,17 +317,12 @@ public Explain visitExplainCommand(EsqlBaseParser.ExplainCommandContext ctx) { @Override public PlanFactory visitDropCommand(EsqlBaseParser.DropCommandContext ctx) { - var identifiers = ctx.qualifiedNamePattern(); - List removals = new ArrayList<>(identifiers.size()); - - for (QualifiedNamePatternContext patternContext : identifiers) { - NamedExpression ne = visitQualifiedNamePattern(patternContext); + List removals = visitQualifiedNamePatterns(ctx.qualifiedNamePatterns(), ne -> { if (ne instanceof UnresolvedStar) { var src = ne.source(); throw new ParsingException(src, "Removing all fields is not allowed [{}]", src.text()); } - removals.add(ne); - } + }); return child -> new Drop(source(ctx), child, removals); } @@ -340,21 +335,18 @@ public PlanFactory visitRenameCommand(EsqlBaseParser.RenameCommandContext ctx) { @Override public PlanFactory visitKeepCommand(EsqlBaseParser.KeepCommandContext ctx) { - var identifiers = ctx.qualifiedNamePattern(); - List projections = new ArrayList<>(identifiers.size()); - boolean hasSeenStar = false; - for (QualifiedNamePatternContext patternContext : identifiers) { - NamedExpression ne = visitQualifiedNamePattern(patternContext); + final Holder hasSeenStar = new Holder<>(false); + List projections = visitQualifiedNamePatterns(ctx.qualifiedNamePatterns(), ne -> { if (ne instanceof UnresolvedStar) { - if (hasSeenStar) { + if (hasSeenStar.get()) { var src = ne.source(); throw new ParsingException(src, "Cannot specify [*] more than once", src.text()); } else { - hasSeenStar = true; + hasSeenStar.set(Boolean.TRUE); } } - projections.add(ne); - } + }); + return child -> new Keep(source(ctx), child, projections); } @@ -437,5 +429,24 @@ public LogicalPlan visitMetricsCommand(EsqlBaseParser.MetricsCommandContext ctx) return new EsqlAggregate(source, unresolvedRelation, stats.groupings, stats.aggregates); } + @Override + public PlanFactory visitLookupCommand(EsqlBaseParser.LookupCommandContext ctx) { + if (false == Build.current().isSnapshot()) { + throw new ParsingException(source(ctx), "LOOKUP is in preview and only available in SNAPSHOT build"); + } + var source = source(ctx); + + List matchFields = visitQualifiedNamePatterns(ctx.qualifiedNamePatterns(), ne -> { + if (ne instanceof UnresolvedNamePattern || ne instanceof UnresolvedStar) { + var src = ne.source(); + throw new ParsingException(src, "Using wildcards [*] in LOOKUP ON is not allowed yet [{}]", src.text()); + } + }); + + Literal tableName = new Literal(source, ctx.tableName.getText(), DataTypes.KEYWORD); + + throw new ParsingException(source, "LOOKUP not yet supported"); + } + interface PlanFactory extends Function {} } 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 49a6dfc37cfc1..11ee262c6a682 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 @@ -1878,6 +1878,15 @@ public void testInOnText() { """, "mapping-multi-field-variation.json", "text"); } + public void testLookup() { + var e = expectThrows(ParsingException.class, () -> analyze(""" + FROM test + | RENAME languages AS int + | LOOKUP int_number_names ON int + """)); + assertThat(e.getMessage(), containsString("LOOKUP not yet supported")); + } + private void verifyUnsupported(String query, String errorMessage) { verifyUnsupported(query, errorMessage, "mapping-multi-field-variation.json"); } diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/150_lookup.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/150_lookup.yml new file mode 100644 index 0000000000000..e8b372e6d7e8e --- /dev/null +++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/150_lookup.yml @@ -0,0 +1,42 @@ +index named lookup: + - do: + bulk: + index: lookup + refresh: true + body: + - { index: { } } + - { f: 1 } + + - do: + esql.query: + body: + query: 'FROM lookup | LIMIT 1' + - match: { columns.0.name: f } + - match: { columns.0.type: long } + - length: { values: 1 } + - match: { values.0.0: 1 } + +--- +lookup command unsupported: + - requires: + test_runner_features: [capabilities] + capabilities: + - method: POST + path: /_query + parameters: [method, path, parameters, capabilities] + capabilities: [lookup] + reason: "LOOKUP command required" + + - do: + bulk: + index: lookup + refresh: true + body: + - { index: { } } + - { f: 1 } + + - do: + catch: /LOOKUP not yet supported/ + esql.query: + body: + query: 'FROM lookup | LOOKUP a ON foo' From e931596bcef10b1538d93cc0407388f43b3fbe37 Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 28 May 2024 19:27:04 +0100 Subject: [PATCH 014/208] Fix trappy timeouts in watcher actions (#109098) Relates #107984 --- .../api/watcher.get_settings.json | 7 ++++- .../rest-api-spec/api/watcher.start.json | 7 ++++- .../rest-api-spec/api/watcher.stop.json | 7 ++++- .../api/watcher.update_settings.json | 11 +++++++- .../org/elasticsearch/TransportVersions.java | 1 + .../actions/put/GetWatcherSettingsAction.java | 24 ++++++++++++---- .../put/UpdateWatcherSettingsAction.java | 28 ++++++++++++++++--- .../service/WatcherServiceRequest.java | 5 ++-- .../service/WatcherServiceRequestBuilder.java | 5 ++-- .../AbstractWatcherIntegrationTestCase.java | 4 +-- .../elasticsearch/xpack/watcher/Watcher.java | 4 +-- .../action/RestGetWatcherSettingsAction.java | 3 +- .../RestUpdateWatcherSettingsAction.java | 10 ++++++- .../rest/action/RestWatchServiceAction.java | 12 +++----- .../TransportGetWatcherSettingsAction.java | 2 +- .../TransportUpdateWatcherSettingsAction.java | 2 +- .../bench/WatcherScheduleEngineBenchmark.java | 3 +- 17 files changed, 101 insertions(+), 34 deletions(-) diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.get_settings.json b/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.get_settings.json index 6bd8cf5fc9228..3ae59c9d024a7 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.get_settings.json +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.get_settings.json @@ -18,6 +18,11 @@ } ] }, - "params":{} + "params":{ + "master_timeout":{ + "type":"time", + "description":"Specify timeout for connection to master" + } + } } } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.start.json b/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.start.json index a7884a41198ce..ad0682c8d7b19 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.start.json +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.start.json @@ -19,6 +19,11 @@ } ] }, - "params":{} + "params":{ + "master_timeout":{ + "type":"time", + "description":"Specify timeout for connection to master" + } + } } } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.stop.json b/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.stop.json index c3e85287767fd..b1a67119df153 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.stop.json +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.stop.json @@ -19,6 +19,11 @@ } ] }, - "params":{} + "params":{ + "master_timeout":{ + "type":"time", + "description":"Specify timeout for connection to master" + } + } } } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.update_settings.json b/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.update_settings.json index 5e04e16862a66..5a6a8d4a787ad 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.update_settings.json +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/watcher.update_settings.json @@ -18,7 +18,16 @@ } ] }, - "params":{}, + "params":{ + "timeout":{ + "type":"time", + "description":"Specify timeout for waiting for acknowledgement from all nodes" + }, + "master_timeout":{ + "type":"time", + "description":"Specify timeout for connection to master" + } + }, "body":{ "description": "An object with the new index settings", "required": true diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java index 22460775300f3..f10c079c2e82c 100644 --- a/server/src/main/java/org/elasticsearch/TransportVersions.java +++ b/server/src/main/java/org/elasticsearch/TransportVersions.java @@ -179,6 +179,7 @@ static TransportVersion def(int id) { public static final TransportVersion FAILURE_STORE_TELEMETRY = def(8_670_00_0); public static final TransportVersion ADD_METADATA_FLATTENED_TO_ROLES = def(8_671_00_0); public static final TransportVersion ML_INFERENCE_GOOGLE_AI_STUDIO_COMPLETION_ADDED = def(8_672_00_0); + public static final TransportVersion WATCHER_REQUEST_TIMEOUTS = def(8_673_00_0); /* * STOP! READ THIS FIRST! No, really, diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/put/GetWatcherSettingsAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/put/GetWatcherSettingsAction.java index 902c6db07dc89..f1d046f09b0f7 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/put/GetWatcherSettingsAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/put/GetWatcherSettingsAction.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.core.watcher.transport.actions.put; +import org.elasticsearch.TransportVersions; import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.ActionType; @@ -14,6 +15,7 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; @@ -30,16 +32,28 @@ public GetWatcherSettingsAction() { public static class Request extends MasterNodeReadRequest { - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); + public Request(TimeValue masterNodeTimeout) { + super(masterNodeTimeout); } - public Request(StreamInput in) throws IOException { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); + public static Request readFrom(StreamInput in) throws IOException { + if (in.getTransportVersion().onOrAfter(TransportVersions.WATCHER_REQUEST_TIMEOUTS)) { + return new Request(in); + } else { + return new Request(TimeValue.THIRTY_SECONDS); + } + } + + private Request(StreamInput in) throws IOException { + super(in); } @Override - public void writeTo(StreamOutput out) throws IOException {} + public void writeTo(StreamOutput out) throws IOException { + if (out.getTransportVersion().onOrAfter(TransportVersions.WATCHER_REQUEST_TIMEOUTS)) { + super.writeTo(out); + } + } @Override public ActionRequestValidationException validate() { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/put/UpdateWatcherSettingsAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/put/UpdateWatcherSettingsAction.java index b6d999ebbf380..5da714021eb3a 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/put/UpdateWatcherSettingsAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/put/UpdateWatcherSettingsAction.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.core.watcher.transport.actions.put; +import org.elasticsearch.TransportVersions; import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.ActionType; import org.elasticsearch.action.ValidateActions; @@ -16,6 +17,8 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.util.set.Sets; +import org.elasticsearch.core.TimeValue; +import org.elasticsearch.core.UpdateForV9; import java.io.IOException; import java.util.Map; @@ -38,18 +41,35 @@ public UpdateWatcherSettingsAction() { public static class Request extends AcknowledgedRequest { private final Map settings; - public Request(Map settings) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout, Map settings) { + super(masterNodeTimeout, ackTimeout); this.settings = settings; } - public Request(StreamInput in) throws IOException { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public static Request readFrom(StreamInput in) throws IOException { + if (in.getTransportVersion().onOrAfter(TransportVersions.WATCHER_REQUEST_TIMEOUTS)) { + return new Request(in); + } else { + return new Request(TimeValue.THIRTY_SECONDS, TimeValue.THIRTY_SECONDS, in); + } + } + + private Request(StreamInput in) throws IOException { + super(in); + this.settings = in.readGenericMap(); + } + + @UpdateForV9 // bwc no longer required + private Request(TimeValue masterNodeTimeout, TimeValue ackTimeout, StreamInput in) throws IOException { + super(masterNodeTimeout, ackTimeout); this.settings = in.readGenericMap(); } @Override public void writeTo(StreamOutput out) throws IOException { + if (out.getTransportVersion().onOrAfter(TransportVersions.WATCHER_REQUEST_TIMEOUTS)) { + super.writeTo(out); + } out.writeGenericMap(this.settings); } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/service/WatcherServiceRequest.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/service/WatcherServiceRequest.java index 449179e4f18f6..4ccbcdf41949a 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/service/WatcherServiceRequest.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/service/WatcherServiceRequest.java @@ -11,6 +11,7 @@ import org.elasticsearch.action.support.master.MasterNodeRequest; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; import java.util.Locale; @@ -29,8 +30,8 @@ public WatcherServiceRequest(StreamInput in) throws IOException { command = Command.valueOf(in.readString().toUpperCase(Locale.ROOT)); } - public WatcherServiceRequest() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); + public WatcherServiceRequest(TimeValue masterNodeTimeout) { + super(masterNodeTimeout); } /** diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/service/WatcherServiceRequestBuilder.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/service/WatcherServiceRequestBuilder.java index 67284d54e3112..07dd80c167d1b 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/service/WatcherServiceRequestBuilder.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/service/WatcherServiceRequestBuilder.java @@ -9,14 +9,15 @@ import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder; import org.elasticsearch.client.internal.ElasticsearchClient; +import org.elasticsearch.core.TimeValue; public class WatcherServiceRequestBuilder extends MasterNodeOperationRequestBuilder< WatcherServiceRequest, AcknowledgedResponse, WatcherServiceRequestBuilder> { - public WatcherServiceRequestBuilder(ElasticsearchClient client) { - super(client, WatcherServiceAction.INSTANCE, new WatcherServiceRequest()); + public WatcherServiceRequestBuilder(TimeValue masterNodeTimeout, ElasticsearchClient client) { + super(client, WatcherServiceAction.INSTANCE, new WatcherServiceRequest(masterNodeTimeout)); } /** diff --git a/x-pack/plugin/watcher/src/internalClusterTest/java/org/elasticsearch/xpack/watcher/test/AbstractWatcherIntegrationTestCase.java b/x-pack/plugin/watcher/src/internalClusterTest/java/org/elasticsearch/xpack/watcher/test/AbstractWatcherIntegrationTestCase.java index 41e23b54b0375..3b9ea0bd18d47 100644 --- a/x-pack/plugin/watcher/src/internalClusterTest/java/org/elasticsearch/xpack/watcher/test/AbstractWatcherIntegrationTestCase.java +++ b/x-pack/plugin/watcher/src/internalClusterTest/java/org/elasticsearch/xpack/watcher/test/AbstractWatcherIntegrationTestCase.java @@ -540,7 +540,7 @@ protected void startWatcher() throws Exception { boolean isAllStateStopped = states.stream().allMatch(w -> w == WatcherState.STOPPED); if (isAllStateStopped) { - assertAcked(new WatcherServiceRequestBuilder(client()).start().get()); + assertAcked(new WatcherServiceRequestBuilder(TEST_REQUEST_TIMEOUT, client()).start().get()); throw new AssertionError("all nodes are stopped, restarting"); } @@ -582,7 +582,7 @@ protected void stopWatcher() throws Exception { boolean isAllStateStarted = states.stream().allMatch(w -> w == WatcherState.STARTED); if (isAllStateStarted) { - assertAcked(new WatcherServiceRequestBuilder(client()).stop().get()); + assertAcked(new WatcherServiceRequestBuilder(TEST_REQUEST_TIMEOUT, client()).stop().get()); throw new AssertionError("all nodes are started, stopping"); } diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java index 010c3611c1f96..f8f910c38c080 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java @@ -834,7 +834,7 @@ public void prepareForIndicesMigration(ClusterService clusterService, Client cli .orElse(false); if (manuallyStopped == false) { - WatcherServiceRequest serviceRequest = new WatcherServiceRequest(); + WatcherServiceRequest serviceRequest = new WatcherServiceRequest(TimeValue.THIRTY_SECONDS /* TODO should this be longer? */); serviceRequest.stop(); originClient.execute(WatcherServiceAction.INSTANCE, serviceRequest, ActionListener.wrap((response) -> { listener.onResponse(Collections.singletonMap("manually_stopped", manuallyStopped)); @@ -855,7 +855,7 @@ public void indicesMigrationComplete( Client originClient = new OriginSettingClient(client, WATCHER_ORIGIN); boolean manuallyStopped = (boolean) preUpgradeMetadata.getOrDefault("manually_stopped", false); if (manuallyStopped == false) { - WatcherServiceRequest serviceRequest = new WatcherServiceRequest(); + WatcherServiceRequest serviceRequest = new WatcherServiceRequest(TimeValue.THIRTY_SECONDS /* TODO should this be longer? */); serviceRequest.start(); originClient.execute(WatcherServiceAction.INSTANCE, serviceRequest, ActionListener.wrap((response) -> { listener.onResponse(response.isAcknowledged()); diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestGetWatcherSettingsAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestGetWatcherSettingsAction.java index ca3cfbaaedd72..73a933c9c2e46 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestGetWatcherSettingsAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestGetWatcherSettingsAction.java @@ -10,6 +10,7 @@ import org.elasticsearch.client.internal.node.NodeClient; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestUtils; import org.elasticsearch.rest.action.RestToXContentListener; import org.elasticsearch.xpack.core.watcher.transport.actions.put.GetWatcherSettingsAction; @@ -33,7 +34,7 @@ public List routes() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - GetWatcherSettingsAction.Request req = new GetWatcherSettingsAction.Request(); + GetWatcherSettingsAction.Request req = new GetWatcherSettingsAction.Request(RestUtils.getMasterNodeTimeout(request)); return channel -> client.execute(GetWatcherSettingsAction.INSTANCE, req, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestUpdateWatcherSettingsAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestUpdateWatcherSettingsAction.java index 3861573c1e421..26f64a0918141 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestUpdateWatcherSettingsAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestUpdateWatcherSettingsAction.java @@ -10,6 +10,7 @@ import org.elasticsearch.client.internal.node.NodeClient; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestUtils; import org.elasticsearch.rest.action.RestToXContentListener; import org.elasticsearch.xpack.core.watcher.transport.actions.put.UpdateWatcherSettingsAction; @@ -33,7 +34,14 @@ public List routes() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - UpdateWatcherSettingsAction.Request req = new UpdateWatcherSettingsAction.Request(request.contentParser().map()); + final UpdateWatcherSettingsAction.Request req; + try (var contentParser = request.contentParser()) { + req = new UpdateWatcherSettingsAction.Request( + RestUtils.getMasterNodeTimeout(request), + RestUtils.getAckTimeout(request), + contentParser.map() + ); + } return channel -> client.execute(UpdateWatcherSettingsAction.INSTANCE, req, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestWatchServiceAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestWatchServiceAction.java index 7824f9f46c2f6..f6b9ae9c4031c 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestWatchServiceAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestWatchServiceAction.java @@ -11,6 +11,7 @@ import org.elasticsearch.core.RestApiVersion; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestUtils; import org.elasticsearch.rest.action.RestToXContentListener; import org.elasticsearch.xpack.core.watcher.transport.actions.service.WatcherServiceAction; import org.elasticsearch.xpack.core.watcher.transport.actions.service.WatcherServiceRequest; @@ -18,7 +19,6 @@ import java.util.List; import static org.elasticsearch.rest.RestRequest.Method.POST; -import static org.elasticsearch.rest.RestUtils.getMasterNodeTimeout; public class RestWatchServiceAction extends BaseRestHandler { @@ -34,11 +34,8 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - return channel -> client.execute( - WatcherServiceAction.INSTANCE, - new WatcherServiceRequest().start(), - new RestToXContentListener<>(channel) - ); + final var req = new WatcherServiceRequest(RestUtils.getMasterNodeTimeout(request)).start(); + return channel -> client.execute(WatcherServiceAction.INSTANCE, req, new RestToXContentListener<>(channel)); } public static class StopRestHandler extends BaseRestHandler { @@ -55,8 +52,7 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { - final WatcherServiceRequest request = new WatcherServiceRequest().stop(); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + final var request = new WatcherServiceRequest(RestUtils.getMasterNodeTimeout(restRequest)).stop(); return channel -> client.execute(WatcherServiceAction.INSTANCE, request, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/TransportGetWatcherSettingsAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/TransportGetWatcherSettingsAction.java index 0c52057100860..f0fe010962697 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/TransportGetWatcherSettingsAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/TransportGetWatcherSettingsAction.java @@ -46,7 +46,7 @@ public TransportGetWatcherSettingsAction( clusterService, threadPool, actionFilters, - GetWatcherSettingsAction.Request::new, + GetWatcherSettingsAction.Request::readFrom, indexNameExpressionResolver, GetWatcherSettingsAction.Response::new, EsExecutors.DIRECT_EXECUTOR_SERVICE diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/TransportUpdateWatcherSettingsAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/TransportUpdateWatcherSettingsAction.java index 94ef321806033..8064a17d451e3 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/TransportUpdateWatcherSettingsAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/TransportUpdateWatcherSettingsAction.java @@ -69,7 +69,7 @@ public TransportUpdateWatcherSettingsAction( clusterService, threadPool, actionFilters, - UpdateWatcherSettingsAction.Request::new, + UpdateWatcherSettingsAction.Request::readFrom, indexNameExpressionResolver, AcknowledgedResponse::readFrom, EsExecutors.DIRECT_EXECUTOR_SERVICE diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/bench/WatcherScheduleEngineBenchmark.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/bench/WatcherScheduleEngineBenchmark.java index 670da0b8f788d..53ca2fb3b3a35 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/bench/WatcherScheduleEngineBenchmark.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/bench/WatcherScheduleEngineBenchmark.java @@ -26,6 +26,7 @@ import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.aggregations.metrics.Percentiles; import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPoolStats; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.watcher.WatcherState; @@ -242,7 +243,7 @@ public void run() { Percentiles percentiles = searchResponse.getAggregations().get("percentile_delay"); stats.setDelayPercentiles(percentiles); stats.setAvgJvmUsed(jvmUsedHeapSpace); - new WatcherServiceRequestBuilder(client).stop().get(); + new WatcherServiceRequestBuilder(ESTestCase.TEST_REQUEST_TIMEOUT, client).stop().get(); } ); } From 4275c927f3052723b33f80f2a2cb88e775acf7e6 Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 28 May 2024 19:49:05 +0100 Subject: [PATCH 015/208] Fix trappy timeouts in SLM modules (#109122) Relates #107984 --- .../action/DeleteSnapshotLifecycleAction.java | 11 ++-- .../ExecuteSnapshotLifecycleAction.java | 26 ++------- .../ExecuteSnapshotRetentionAction.java | 16 ++---- .../action/GetSnapshotLifecycleAction.java | 10 +--- .../action/PutSnapshotLifecycleAction.java | 31 +++------- .../xpack/core/slm/action/StartSLMAction.java | 5 +- .../xpack/core/slm/action/StopSLMAction.java | 5 +- .../ilm/LifecycleOperationSnapshotTests.java | 6 +- .../xpack/slm/SLMFileSettingsIT.java | 10 +++- .../slm/SLMSnapshotBlockingIntegTests.java | 56 ++++++++++++++----- .../SnapshotLifecycleInitialisationTests.java | 2 + .../slm/action/ReservedSnapshotAction.java | 17 +++++- .../RestDeleteSnapshotLifecycleAction.java | 10 ++-- .../RestExecuteSnapshotLifecycleAction.java | 9 +-- .../RestExecuteSnapshotRetentionAction.java | 4 +- .../RestGetSnapshotLifecycleAction.java | 10 ++-- .../RestPutSnapshotLifecycleAction.java | 10 ++-- .../xpack/slm/action/RestStartSLMAction.java | 4 +- .../xpack/slm/action/RestStopSLMAction.java | 4 +- ...ransportDeleteSnapshotLifecycleAction.java | 9 --- ...vedSnapshotLifecycleStateServiceTests.java | 9 ++- .../action/TransportStopSLMActionTests.java | 2 +- 22 files changed, 133 insertions(+), 133 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/DeleteSnapshotLifecycleAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/DeleteSnapshotLifecycleAction.java index 6e083295b0863..fb461a772f465 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/DeleteSnapshotLifecycleAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/DeleteSnapshotLifecycleAction.java @@ -12,6 +12,7 @@ import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; import java.util.Objects; @@ -26,19 +27,15 @@ protected DeleteSnapshotLifecycleAction() { public static class Request extends AcknowledgedRequest { - private String lifecycleId; + private final String lifecycleId; public Request(StreamInput in) throws IOException { super(in); lifecycleId = in.readString(); } - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); - } - - public Request(String lifecycleId) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout, String lifecycleId) { + super(masterNodeTimeout, ackTimeout); this.lifecycleId = Objects.requireNonNull(lifecycleId, "id may not be null"); } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/ExecuteSnapshotLifecycleAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/ExecuteSnapshotLifecycleAction.java index 442ff6b2bfb66..7793c628fb7cc 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/ExecuteSnapshotLifecycleAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/ExecuteSnapshotLifecycleAction.java @@ -10,9 +10,9 @@ import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.ActionType; import org.elasticsearch.action.support.master.AcknowledgedRequest; -import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; @@ -31,12 +31,12 @@ protected ExecuteSnapshotLifecycleAction() { super(NAME); } - public static class Request extends AcknowledgedRequest implements ToXContentObject { + public static class Request extends AcknowledgedRequest { - private String lifecycleId; + private final String lifecycleId; - public Request(String lifecycleId) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout, String lifecycleId) { + super(masterNodeTimeout, ackTimeout); this.lifecycleId = lifecycleId; } @@ -45,10 +45,6 @@ public Request(StreamInput in) throws IOException { lifecycleId = in.readString(); } - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); - } - public String getLifecycleId() { return this.lifecycleId; } @@ -59,13 +55,6 @@ public void writeTo(StreamOutput out) throws IOException { out.writeString(lifecycleId); } - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.endObject(); - return builder; - } - @Override public int hashCode() { return Objects.hash(lifecycleId); @@ -82,11 +71,6 @@ public boolean equals(Object obj) { Request other = (Request) obj; return lifecycleId.equals(other.lifecycleId); } - - @Override - public String toString() { - return Strings.toString(this); - } } public static class Response extends ActionResponse implements ToXContentObject { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/ExecuteSnapshotRetentionAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/ExecuteSnapshotRetentionAction.java index e4d698f48d252..b374b510625f9 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/ExecuteSnapshotRetentionAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/ExecuteSnapshotRetentionAction.java @@ -11,8 +11,7 @@ import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.xcontent.ToXContentObject; -import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.core.TimeValue; import java.io.IOException; @@ -24,23 +23,16 @@ protected ExecuteSnapshotRetentionAction() { super(NAME); } - public static class Request extends AcknowledgedRequest implements ToXContentObject { + public static class Request extends AcknowledgedRequest { - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout) { + super(masterNodeTimeout, ackTimeout); } public Request(StreamInput in) throws IOException { super(in); } - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.endObject(); - return builder; - } - @Override public int hashCode() { return super.hashCode(); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/GetSnapshotLifecycleAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/GetSnapshotLifecycleAction.java index ad62b155da41c..dd330739d3e69 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/GetSnapshotLifecycleAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/GetSnapshotLifecycleAction.java @@ -13,6 +13,7 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xpack.core.slm.SnapshotLifecyclePolicyItem; @@ -34,8 +35,8 @@ public static class Request extends AcknowledgedRequest implements ToXContentObject { + public static class Request extends AcknowledgedRequest { - private String lifecycleId; - private SnapshotLifecyclePolicy lifecycle; + private final String lifecycleId; + private final SnapshotLifecyclePolicy lifecycle; - public Request(String lifecycleId, SnapshotLifecyclePolicy lifecycle) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout, String lifecycleId, SnapshotLifecyclePolicy lifecycle) { + super(masterNodeTimeout, ackTimeout); this.lifecycleId = lifecycleId; this.lifecycle = lifecycle; } @@ -47,10 +46,6 @@ public Request(StreamInput in) throws IOException { lifecycle = new SnapshotLifecyclePolicy(in); } - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); - } - public String getLifecycleId() { return this.lifecycleId; } @@ -59,8 +54,8 @@ public SnapshotLifecyclePolicy getLifecycle() { return this.lifecycle; } - public static Request parseRequest(String lifecycleId, XContentParser parser) { - return new Request(lifecycleId, SnapshotLifecyclePolicy.parse(parser, lifecycleId)); + public static Request parseRequest(TimeValue masterNodeTimeout, TimeValue ackTimeout, String lifecycleId, XContentParser parser) { + return new Request(masterNodeTimeout, ackTimeout, lifecycleId, SnapshotLifecyclePolicy.parse(parser, lifecycleId)); } @Override @@ -75,14 +70,6 @@ public ActionRequestValidationException validate() { return lifecycle.validate(); } - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.field(lifecycleId, lifecycle); - builder.endObject(); - return builder; - } - @Override public int hashCode() { return Objects.hash(lifecycleId, lifecycle); @@ -102,7 +89,7 @@ public boolean equals(Object obj) { @Override public String toString() { - return Strings.toString(this); + return Strings.toString((b, p) -> b.field(lifecycleId, lifecycle)); } } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/StartSLMAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/StartSLMAction.java index 666701ac1f885..bacb8f4cd613e 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/StartSLMAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/StartSLMAction.java @@ -11,6 +11,7 @@ import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; @@ -28,8 +29,8 @@ public Request(StreamInput in) throws IOException { super(in); } - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout) { + super(masterNodeTimeout, ackTimeout); } @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/StopSLMAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/StopSLMAction.java index 4aae048b5e5b6..57bd414bed842 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/StopSLMAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/slm/action/StopSLMAction.java @@ -11,6 +11,7 @@ import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; @@ -28,8 +29,8 @@ public Request(StreamInput in) throws IOException { super(in); } - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout) { + super(masterNodeTimeout, ackTimeout); } @Override diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/LifecycleOperationSnapshotTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/LifecycleOperationSnapshotTests.java index 22eef3d8940a3..aa9da48eb8f8f 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/LifecycleOperationSnapshotTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/LifecycleOperationSnapshotTests.java @@ -63,6 +63,8 @@ public void testModeSnapshotRestore() throws Exception { client().execute( PutSnapshotLifecycleAction.INSTANCE, new PutSnapshotLifecycleAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, "slm-policy", new SnapshotLifecyclePolicy( "slm-policy", @@ -91,7 +93,7 @@ public void testModeSnapshotRestore() throws Exception { // Take snapshot ExecuteSnapshotLifecycleAction.Response resp = client().execute( ExecuteSnapshotLifecycleAction.INSTANCE, - new ExecuteSnapshotLifecycleAction.Request("slm-policy") + new ExecuteSnapshotLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "slm-policy") ).get(); final String snapshotName = resp.getSnapshotName(); // Wait for the snapshot to be successful @@ -110,7 +112,7 @@ public void testModeSnapshotRestore() throws Exception { }); assertAcked(client().execute(ILMActions.STOP, new StopILMRequest()).get()); - assertAcked(client().execute(StopSLMAction.INSTANCE, new StopSLMAction.Request()).get()); + assertAcked(client().execute(StopSLMAction.INSTANCE, new StopSLMAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)).get()); assertBusy(() -> assertThat(ilmMode(), equalTo(OperationMode.STOPPED))); assertBusy(() -> assertThat(slmMode(), equalTo(OperationMode.STOPPED))); diff --git a/x-pack/plugin/slm/src/internalClusterTest/java/org/elasticsearch/xpack/slm/SLMFileSettingsIT.java b/x-pack/plugin/slm/src/internalClusterTest/java/org/elasticsearch/xpack/slm/SLMFileSettingsIT.java index 725bf412b3198..c68e7174923f8 100644 --- a/x-pack/plugin/slm/src/internalClusterTest/java/org/elasticsearch/xpack/slm/SLMFileSettingsIT.java +++ b/x-pack/plugin/slm/src/internalClusterTest/java/org/elasticsearch/xpack/slm/SLMFileSettingsIT.java @@ -259,7 +259,7 @@ public void testSettingsApplied() throws Exception { assertBusy(() -> { GetSnapshotLifecycleAction.Response getResp = client().execute( GetSnapshotLifecycleAction.INSTANCE, - new GetSnapshotLifecycleAction.Request(policyName) + new GetSnapshotLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policyName) ).get(); logger.info("--> checking for snapshot complete..."); @@ -357,7 +357,11 @@ public void testErrorSaved() throws Exception { } private String executePolicy(String policyId) { - ExecuteSnapshotLifecycleAction.Request executeReq = new ExecuteSnapshotLifecycleAction.Request(policyId); + ExecuteSnapshotLifecycleAction.Request executeReq = new ExecuteSnapshotLifecycleAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, + policyId + ); ExecuteSnapshotLifecycleAction.Response resp = null; try { resp = client().execute(ExecuteSnapshotLifecycleAction.INSTANCE, executeReq).get(); @@ -392,7 +396,7 @@ private PutSnapshotLifecycleAction.Request sampleRestRequest(String name) throws var parser = JSON.xContent().createParser(XContentParserConfiguration.EMPTY, bis) ) { var policy = SnapshotLifecyclePolicy.parse(parser, name); - return new PutSnapshotLifecycleAction.Request(name, policy); + return new PutSnapshotLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, name, policy); } } } diff --git a/x-pack/plugin/slm/src/internalClusterTest/java/org/elasticsearch/xpack/slm/SLMSnapshotBlockingIntegTests.java b/x-pack/plugin/slm/src/internalClusterTest/java/org/elasticsearch/xpack/slm/SLMSnapshotBlockingIntegTests.java index d1e6c56ae1517..3787761a2b287 100644 --- a/x-pack/plugin/slm/src/internalClusterTest/java/org/elasticsearch/xpack/slm/SLMSnapshotBlockingIntegTests.java +++ b/x-pack/plugin/slm/src/internalClusterTest/java/org/elasticsearch/xpack/slm/SLMSnapshotBlockingIntegTests.java @@ -127,7 +127,7 @@ public void testSnapshotInProgress() throws Exception { assertBusy(() -> { GetSnapshotLifecycleAction.Response getResp = client().execute( GetSnapshotLifecycleAction.INSTANCE, - new GetSnapshotLifecycleAction.Request(policyName) + new GetSnapshotLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policyName) ).get(); logger.info("--> checking for in progress snapshot..."); @@ -215,7 +215,7 @@ public void testRetentionWhileSnapshotInProgress() throws Exception { logger.info("--> at least one data node has hit the block"); GetSnapshotLifecycleAction.Response getResp = client().execute( GetSnapshotLifecycleAction.INSTANCE, - new GetSnapshotLifecycleAction.Request(policyId) + new GetSnapshotLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policyId) ).get(); logger.info("--> checking for in progress snapshot..."); @@ -235,9 +235,10 @@ public void testRetentionWhileSnapshotInProgress() throws Exception { // Run retention logger.info("--> triggering retention"); assertTrue( - client().execute(ExecuteSnapshotRetentionAction.INSTANCE, new ExecuteSnapshotRetentionAction.Request()) - .get() - .isAcknowledged() + client().execute( + ExecuteSnapshotRetentionAction.INSTANCE, + new ExecuteSnapshotRetentionAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get().isAcknowledged() ); logger.info("--> unblocking snapshots"); @@ -313,7 +314,10 @@ public void testRetentionWithMultipleRepositories() throws Exception { new SnapshotRetentionConfiguration(null, 1, 2) ); logger.info("--> start snapshot"); - client().execute(ExecuteSnapshotLifecycleAction.INSTANCE, new ExecuteSnapshotLifecycleAction.Request(policyId)).get(); + client().execute( + ExecuteSnapshotLifecycleAction.INSTANCE, + new ExecuteSnapshotLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policyId) + ).get(); // make sure the SLM history data stream is green and won't not be green for long because of delayed allocation when data nodes // are stopped ensureGreen(SLM_HISTORY_DATA_STREAM); @@ -360,7 +364,7 @@ private void testUnsuccessfulSnapshotRetention(boolean partialSuccess) throws Ex logger.info("--> start snapshot"); ActionFuture snapshotFuture = client().execute( ExecuteSnapshotLifecycleAction.INSTANCE, - new ExecuteSnapshotLifecycleAction.Request(policyId) + new ExecuteSnapshotLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policyId) ); waitForBlock(internalCluster().getMasterName(), REPO); @@ -395,7 +399,12 @@ private void testUnsuccessfulSnapshotRetention(boolean partialSuccess) throws Ex // Run retention - we'll check the results later to make sure it's had time to run. { logger.info("--> executing SLM retention"); - assertAcked(client().execute(ExecuteSnapshotRetentionAction.INSTANCE, new ExecuteSnapshotRetentionAction.Request()).get()); + assertAcked( + client().execute( + ExecuteSnapshotRetentionAction.INSTANCE, + new ExecuteSnapshotRetentionAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get() + ); } // Take a successful snapshot @@ -413,7 +422,7 @@ private void testUnsuccessfulSnapshotRetention(boolean partialSuccess) throws Ex ActionFuture snapshotResponse = client().execute( ExecuteSnapshotLifecycleAction.INSTANCE, - new ExecuteSnapshotLifecycleAction.Request(policyId) + new ExecuteSnapshotLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policyId) ); logger.info("--> waiting for snapshot to complete"); successfulSnapshotName.set(snapshotResponse.get().getSnapshotName()); @@ -446,7 +455,12 @@ private void testUnsuccessfulSnapshotRetention(boolean partialSuccess) throws Ex // Run retention again and make sure the failure was deleted { logger.info("--> executing SLM retention"); - assertAcked(client().execute(ExecuteSnapshotRetentionAction.INSTANCE, new ExecuteSnapshotRetentionAction.Request()).get()); + assertAcked( + client().execute( + ExecuteSnapshotRetentionAction.INSTANCE, + new ExecuteSnapshotRetentionAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get() + ); logger.info("--> waiting for {} snapshot [{}] to be deleted", expectedUnsuccessfulState, failedSnapshotName.get()); assertBusy(() -> { try { @@ -497,7 +511,7 @@ public void testSLMRetentionAfterRestore() throws Exception { assertBusy(() -> { GetSnapshotLifecycleAction.Response getResp = client().execute( GetSnapshotLifecycleAction.INSTANCE, - new GetSnapshotLifecycleAction.Request(policyName) + new GetSnapshotLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policyName) ).get(); logger.info("--> checking for in progress snapshot..."); @@ -518,7 +532,12 @@ public void testSLMRetentionAfterRestore() throws Exception { assertThat(resp.status(), equalTo(RestStatus.OK)); logger.info("--> executing SLM retention"); - assertAcked(client().execute(ExecuteSnapshotRetentionAction.INSTANCE, new ExecuteSnapshotRetentionAction.Request()).get()); + assertAcked( + client().execute( + ExecuteSnapshotRetentionAction.INSTANCE, + new ExecuteSnapshotRetentionAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get() + ); logger.info("--> waiting for {} snapshot to be deleted", snapshotName); assertBusy(() -> { try { @@ -595,7 +614,12 @@ private void createSnapshotPolicy( retention ); - PutSnapshotLifecycleAction.Request putLifecycle = new PutSnapshotLifecycleAction.Request(policyName, policy); + PutSnapshotLifecycleAction.Request putLifecycle = new PutSnapshotLifecycleAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, + policyName, + policy + ); try { client().execute(PutSnapshotLifecycleAction.INSTANCE, putLifecycle).get(); } catch (Exception e) { @@ -608,7 +632,11 @@ private void createSnapshotPolicy( * Execute the given policy and return the generated snapshot name */ private String executePolicy(String policyId) { - ExecuteSnapshotLifecycleAction.Request executeReq = new ExecuteSnapshotLifecycleAction.Request(policyId); + ExecuteSnapshotLifecycleAction.Request executeReq = new ExecuteSnapshotLifecycleAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, + policyId + ); ExecuteSnapshotLifecycleAction.Response resp = null; try { resp = client().execute(ExecuteSnapshotLifecycleAction.INSTANCE, executeReq).get(); diff --git a/x-pack/plugin/slm/src/internalClusterTest/java/org/elasticsearch/xpack/slm/SnapshotLifecycleInitialisationTests.java b/x-pack/plugin/slm/src/internalClusterTest/java/org/elasticsearch/xpack/slm/SnapshotLifecycleInitialisationTests.java index 6d0cd2142fe6e..e5e71a38ce6b4 100644 --- a/x-pack/plugin/slm/src/internalClusterTest/java/org/elasticsearch/xpack/slm/SnapshotLifecycleInitialisationTests.java +++ b/x-pack/plugin/slm/src/internalClusterTest/java/org/elasticsearch/xpack/slm/SnapshotLifecycleInitialisationTests.java @@ -69,6 +69,8 @@ public void testSLMIsInRunningModeWhenILMIsDisabled() throws Exception { client().execute( PutSnapshotLifecycleAction.INSTANCE, new Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, "snapshot-policy", new SnapshotLifecyclePolicy( "test-policy", diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotAction.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotAction.java index fe385a6389d55..f14edd89b826d 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotAction.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotAction.java @@ -7,12 +7,15 @@ package org.elasticsearch.xpack.slm.action; +import org.elasticsearch.action.ActionListener; import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.reservedstate.ReservedClusterStateHandler; import org.elasticsearch.reservedstate.TransformState; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xpack.core.slm.SnapshotLifecyclePolicy; +import org.elasticsearch.xpack.core.slm.action.DeleteSnapshotLifecycleAction; import org.elasticsearch.xpack.core.slm.action.PutSnapshotLifecycleAction; import org.elasticsearch.xpack.slm.SnapshotLifecycleService; @@ -51,7 +54,13 @@ private Collection prepare(List exceptions = new ArrayList<>(); for (var policy : policies) { - PutSnapshotLifecycleAction.Request request = new PutSnapshotLifecycleAction.Request(policy.getId(), policy); + // timeouts don't matter here + PutSnapshotLifecycleAction.Request request = new PutSnapshotLifecycleAction.Request( + TimeValue.THIRTY_SECONDS, + TimeValue.THIRTY_SECONDS, + policy.getId(), + policy + ); try { validate(request); SnapshotLifecycleService.validateRepositoryExists(request.getLifecycle().getRepository(), state); @@ -91,7 +100,11 @@ public TransformState transform(Object source, TransformState prevState) throws toDelete.removeAll(entities); for (var policyToDelete : toDelete) { - var task = new TransportDeleteSnapshotLifecycleAction.DeleteSnapshotPolicyTask(policyToDelete); + // timeouts don't matter here + var task = new TransportDeleteSnapshotLifecycleAction.DeleteSnapshotPolicyTask( + new DeleteSnapshotLifecycleAction.Request(TimeValue.THIRTY_SECONDS, TimeValue.THIRTY_SECONDS, policyToDelete), + ActionListener.noop() + ); state = task.execute(state); } diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestDeleteSnapshotLifecycleAction.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestDeleteSnapshotLifecycleAction.java index d3eef098f2083..1dd10ddf74768 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestDeleteSnapshotLifecycleAction.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestDeleteSnapshotLifecycleAction.java @@ -36,11 +36,11 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - String lifecycleId = request.param("name"); - DeleteSnapshotLifecycleAction.Request req = new DeleteSnapshotLifecycleAction.Request(lifecycleId); - req.ackTimeout(getAckTimeout(request)); - req.masterNodeTimeout(getMasterNodeTimeout(request)); - + final var req = new DeleteSnapshotLifecycleAction.Request( + getMasterNodeTimeout(request), + getAckTimeout(request), + request.param("name") + ); return channel -> client.execute(DeleteSnapshotLifecycleAction.INSTANCE, req, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestExecuteSnapshotLifecycleAction.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestExecuteSnapshotLifecycleAction.java index 4b5b072101c36..8132c7443abe2 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestExecuteSnapshotLifecycleAction.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestExecuteSnapshotLifecycleAction.java @@ -37,10 +37,11 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - String snapLifecycleId = request.param("name"); - ExecuteSnapshotLifecycleAction.Request req = new ExecuteSnapshotLifecycleAction.Request(snapLifecycleId); - req.ackTimeout(getAckTimeout(request)); - req.masterNodeTimeout(getMasterNodeTimeout(request)); + final var req = new ExecuteSnapshotLifecycleAction.Request( + getMasterNodeTimeout(request), + getAckTimeout(request), + request.param("name") + ); return channel -> client.execute(ExecuteSnapshotLifecycleAction.INSTANCE, req, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestExecuteSnapshotRetentionAction.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestExecuteSnapshotRetentionAction.java index e00854879c32b..b133348fd958a 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestExecuteSnapshotRetentionAction.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestExecuteSnapshotRetentionAction.java @@ -36,9 +36,7 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - ExecuteSnapshotRetentionAction.Request req = new ExecuteSnapshotRetentionAction.Request(); - req.ackTimeout(getAckTimeout(request)); - req.masterNodeTimeout(getMasterNodeTimeout(request)); + final var req = new ExecuteSnapshotRetentionAction.Request(getMasterNodeTimeout(request), getAckTimeout(request)); return channel -> client.execute(ExecuteSnapshotRetentionAction.INSTANCE, req, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestGetSnapshotLifecycleAction.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestGetSnapshotLifecycleAction.java index c327a14fee236..10475b6940c0e 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestGetSnapshotLifecycleAction.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestGetSnapshotLifecycleAction.java @@ -37,11 +37,11 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - String[] lifecycleNames = Strings.splitStringByCommaToArray(request.param("name")); - GetSnapshotLifecycleAction.Request req = new GetSnapshotLifecycleAction.Request(lifecycleNames); - req.ackTimeout(getAckTimeout(request)); - req.masterNodeTimeout(getMasterNodeTimeout(request)); - + final var req = new GetSnapshotLifecycleAction.Request( + getMasterNodeTimeout(request), + getAckTimeout(request), + Strings.splitStringByCommaToArray(request.param("name")) + ); return channel -> client.execute(GetSnapshotLifecycleAction.INSTANCE, req, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestPutSnapshotLifecycleAction.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestPutSnapshotLifecycleAction.java index 3db974a9af0a9..747ba60115ae7 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestPutSnapshotLifecycleAction.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestPutSnapshotLifecycleAction.java @@ -38,11 +38,13 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - String snapLifecycleName = request.param("name"); try (XContentParser parser = request.contentParser()) { - PutSnapshotLifecycleAction.Request req = PutSnapshotLifecycleAction.Request.parseRequest(snapLifecycleName, parser); - req.ackTimeout(getAckTimeout(request)); - req.masterNodeTimeout(getMasterNodeTimeout(request)); + final var req = PutSnapshotLifecycleAction.Request.parseRequest( + getMasterNodeTimeout(request), + getAckTimeout(request), + request.param("name"), + parser + ); return channel -> client.execute(PutSnapshotLifecycleAction.INSTANCE, req, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestStartSLMAction.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestStartSLMAction.java index 3463346377f6c..9d1df9d72d2fe 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestStartSLMAction.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestStartSLMAction.java @@ -36,9 +36,7 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { - StartSLMAction.Request request = new StartSLMAction.Request(); - request.ackTimeout(getAckTimeout(restRequest)); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + final var request = new StartSLMAction.Request(getMasterNodeTimeout(restRequest), getAckTimeout(restRequest)); return channel -> client.execute(StartSLMAction.INSTANCE, request, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestStopSLMAction.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestStopSLMAction.java index 8c5d7296fac86..8a6280091b4fd 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestStopSLMAction.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/RestStopSLMAction.java @@ -36,9 +36,7 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { - StopSLMAction.Request request = new StopSLMAction.Request(); - request.ackTimeout(getAckTimeout(restRequest)); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + final var request = new StopSLMAction.Request(getMasterNodeTimeout(restRequest), getAckTimeout(restRequest)); return channel -> client.execute(StopSLMAction.INSTANCE, request, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/TransportDeleteSnapshotLifecycleAction.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/TransportDeleteSnapshotLifecycleAction.java index 3b2dc9e23d172..062954e40d82c 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/TransportDeleteSnapshotLifecycleAction.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/TransportDeleteSnapshotLifecycleAction.java @@ -23,7 +23,6 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.util.concurrent.EsExecutors; import org.elasticsearch.core.SuppressForbidden; -import org.elasticsearch.reservedstate.ReservedClusterStateHandler; import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; @@ -84,14 +83,6 @@ public static class DeleteSnapshotPolicyTask extends AckedClusterStateUpdateTask this.request = request; } - /** - * Used by the {@link ReservedClusterStateHandler} for SLM - * {@link ReservedSnapshotAction} - */ - DeleteSnapshotPolicyTask(String policyId) { - this(new DeleteSnapshotLifecycleAction.Request(policyId), null); - } - @Override public ClusterState execute(ClusterState currentState) { SnapshotLifecycleMetadata snapMeta = currentState.metadata().custom(SnapshotLifecycleMetadata.TYPE); diff --git a/x-pack/plugin/slm/src/test/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotLifecycleStateServiceTests.java b/x-pack/plugin/slm/src/test/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotLifecycleStateServiceTests.java index c2e3786a1afe7..1bb8e0183b2ea 100644 --- a/x-pack/plugin/slm/src/test/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotLifecycleStateServiceTests.java +++ b/x-pack/plugin/slm/src/test/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotLifecycleStateServiceTests.java @@ -377,7 +377,7 @@ public void testDeleteSLMReservedStateHandler() { ); assertEquals(ReservedSnapshotAction.NAME, deleteAction.reservedStateHandlerName().get()); - var request = new DeleteSnapshotLifecycleAction.Request("daily-snapshots1"); + var request = new DeleteSnapshotLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "daily-snapshots1"); assertThat(deleteAction.modifiedKeys(request), containsInAnyOrder("daily-snapshots1")); } @@ -411,7 +411,12 @@ public void testPutSLMReservedStateHandler() throws Exception { }"""; try (XContentParser parser = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, json)) { - var request = PutSnapshotLifecycleAction.Request.parseRequest("daily-snapshots", parser); + var request = PutSnapshotLifecycleAction.Request.parseRequest( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, + "daily-snapshots", + parser + ); assertThat(putAction.modifiedKeys(request), containsInAnyOrder("daily-snapshots")); } diff --git a/x-pack/plugin/slm/src/test/java/org/elasticsearch/xpack/slm/action/TransportStopSLMActionTests.java b/x-pack/plugin/slm/src/test/java/org/elasticsearch/xpack/slm/action/TransportStopSLMActionTests.java index 64ede24c9f65a..1c7b810de3d62 100644 --- a/x-pack/plugin/slm/src/test/java/org/elasticsearch/xpack/slm/action/TransportStopSLMActionTests.java +++ b/x-pack/plugin/slm/src/test/java/org/elasticsearch/xpack/slm/action/TransportStopSLMActionTests.java @@ -51,7 +51,7 @@ public void testStopILMClusterStatePriorityIsImmediate() { new TaskId(randomLong() + ":" + randomLong()), emptyMap() ); - StopSLMAction.Request request = new StopSLMAction.Request(); + StopSLMAction.Request request = new StopSLMAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); transportStopSLMAction.masterOperation(task, request, ClusterState.EMPTY_STATE, ActionListener.noop()); verify(clusterService).submitUnbatchedStateUpdateTask( From 7504fed0b3c8e78818ffa2014c16a2e285adf18d Mon Sep 17 00:00:00 2001 From: Jake Landis Date: Tue, 28 May 2024 13:51:21 -0500 Subject: [PATCH 016/208] remote_cluster role documentation and expose to built in privs API (#108840) This commit introduces the documentation for remote_clusters which is used to help express the monitor_enrich privilege needed to use the ENRICH keyword across clusters when using the API key based CCS security model. This commit also adds "remote_clusters" to the built in privs API to for easier consumption in Kibana. --- .../security/get-builtin-privileges.asciidoc | 8 +++- .../authorization/managing-roles.asciidoc | 37 ++++++++++++++++++- .../GetBuiltinPrivilegesResponse.java | 26 ++++++++++--- .../TransportGetBuiltinPrivilegesAction.java | 4 +- .../RestGetBuiltinPrivilegesAction.java | 4 ++ 5 files changed, 70 insertions(+), 9 deletions(-) diff --git a/docs/reference/rest-api/security/get-builtin-privileges.asciidoc b/docs/reference/rest-api/security/get-builtin-privileges.asciidoc index 63f906d29b4d6..bbd0ca03c0473 100644 --- a/docs/reference/rest-api/security/get-builtin-privileges.asciidoc +++ b/docs/reference/rest-api/security/get-builtin-privileges.asciidoc @@ -45,6 +45,9 @@ version of {es}. <> that are understood by this version of {es}. +`remote_cluster`:: (array of string) The list of +<> privileges that are understood by this version +of {es}. [[security-api-get-builtin-privileges-example]] ==== {api-examples-title} @@ -56,7 +59,7 @@ The following example retrieves the names of all builtin privileges: GET /_security/privilege/_builtin -------------------------------------------------- -A successful call returns an object with "cluster" and "index" fields. +A successful call returns an object with "cluster", "index", and "remote_cluster" fields. [source,console-result] -------------------------------------------------- @@ -145,6 +148,9 @@ A successful call returns an object with "cluster" and "index" fields. "read_cross_cluster", "view_index_metadata", "write" + ], + "remote_cluster" : [ + "monitor_enrich" ] } -------------------------------------------------- diff --git a/docs/reference/security/authorization/managing-roles.asciidoc b/docs/reference/security/authorization/managing-roles.asciidoc index a6197327db683..253aa33822234 100644 --- a/docs/reference/security/authorization/managing-roles.asciidoc +++ b/docs/reference/security/authorization/managing-roles.asciidoc @@ -12,7 +12,8 @@ A role is defined by the following JSON structure: "global": { ... }, <3> "indices": [ ... ], <4> "applications": [ ... ], <5> - "remote_indices": [ ... ] <6> + "remote_indices": [ ... ], <6> + "remote_cluster": [ ... ] <7> } ----- // NOTCONSOLE @@ -35,6 +36,10 @@ A role is defined by the following JSON structure: <>. This field is optional (missing `remote_indices` privileges effectively mean no index level permissions for any API key based remote clusters). +<7> A list of cluster permissions entries for + <>. + This field is optional (missing `remote_cluster` privileges effectively means + no additional cluster permissions for any API key based remote clusters). [[valid-role-name]] NOTE: Role names must be at least 1 and no more than 507 characters. They can @@ -209,6 +214,36 @@ The following describes the structure of a remote indices permissions entry: restricted indices, you must set this field to `true` (default is `false`), and then the `names` field will cover the restricted indices as well. +[[roles-remote-cluster-priv]] +==== Remote cluster privileges + +For <>, remote cluster privileges +can be used to specify additional cluster privileges for matching remote clusters. + +NOTE: Remote cluster privileges are only effective for remote clusters configured with the API key based model. +They have no effect on remote clusters configured with the certificate based model. + +The following describes the structure of a remote cluster permissions entry: + +[source,js] +------- +{ + "clusters": [ ... ], <1> + "privileges": [ ... ] <2> +} +------- +// NOTCONSOLE +<1> A list of remote cluster aliases. It supports literal strings as well as +<> and <>. +This field is required. +<2> The cluster level privileges for the remote cluster. The allowed values here are a subset of the +<>. This field is required. + +The `monitor_enrich` privilege for remote clusters was introduced in version +8.15.0. Currently, this is the only privilege available for remote clusters and +is required to enable users to use the `ENRICH` keyword in ES|QL queries across +clusters. + ==== Example The following snippet shows an example definition of a `clicks_admin` role: diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/privilege/GetBuiltinPrivilegesResponse.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/privilege/GetBuiltinPrivilegesResponse.java index 328089a73b2f5..27b7d48ea2cfb 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/privilege/GetBuiltinPrivilegesResponse.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/privilege/GetBuiltinPrivilegesResponse.java @@ -23,17 +23,27 @@ public final class GetBuiltinPrivilegesResponse extends ActionResponse { private final String[] clusterPrivileges; private final String[] indexPrivileges; + private final String[] remoteClusterPrivileges; + // used by serverless public GetBuiltinPrivilegesResponse(Collection clusterPrivileges, Collection indexPrivileges) { - this.clusterPrivileges = Objects.requireNonNull( - clusterPrivileges.toArray(Strings.EMPTY_ARRAY), - "Cluster privileges cannot be null" - ); - this.indexPrivileges = Objects.requireNonNull(indexPrivileges.toArray(Strings.EMPTY_ARRAY), "Index privileges cannot be null"); + this(clusterPrivileges, indexPrivileges, Collections.emptySet()); + } + + public GetBuiltinPrivilegesResponse( + Collection clusterPrivileges, + Collection indexPrivileges, + Collection remoteClusterPrivileges + ) { + this.clusterPrivileges = Objects.requireNonNull(clusterPrivileges, "Cluster privileges cannot be null") + .toArray(Strings.EMPTY_ARRAY); + this.indexPrivileges = Objects.requireNonNull(indexPrivileges, "Index privileges cannot be null").toArray(Strings.EMPTY_ARRAY); + this.remoteClusterPrivileges = Objects.requireNonNull(remoteClusterPrivileges, "Remote cluster privileges cannot be null") + .toArray(Strings.EMPTY_ARRAY); } public GetBuiltinPrivilegesResponse() { - this(Collections.emptySet(), Collections.emptySet()); + this(Collections.emptySet(), Collections.emptySet(), Collections.emptySet()); } public String[] getClusterPrivileges() { @@ -44,6 +54,10 @@ public String[] getIndexPrivileges() { return indexPrivileges; } + public String[] getRemoteClusterPrivileges() { + return remoteClusterPrivileges; + } + @Override public void writeTo(StreamOutput out) throws IOException { TransportAction.localOnly(); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/privilege/TransportGetBuiltinPrivilegesAction.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/privilege/TransportGetBuiltinPrivilegesAction.java index 8ea8ec3e0dcd9..62f0087c1a2d2 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/privilege/TransportGetBuiltinPrivilegesAction.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/privilege/TransportGetBuiltinPrivilegesAction.java @@ -15,6 +15,7 @@ import org.elasticsearch.xpack.core.security.action.privilege.GetBuiltinPrivilegesAction; import org.elasticsearch.xpack.core.security.action.privilege.GetBuiltinPrivilegesRequest; import org.elasticsearch.xpack.core.security.action.privilege.GetBuiltinPrivilegesResponse; +import org.elasticsearch.xpack.core.security.authz.permission.RemoteClusterPermissions; import org.elasticsearch.xpack.core.security.authz.privilege.ClusterPrivilegeResolver; import org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege; @@ -34,7 +35,8 @@ public TransportGetBuiltinPrivilegesAction(ActionFilters actionFilters, Transpor protected void doExecute(Task task, GetBuiltinPrivilegesRequest request, ActionListener listener) { final TreeSet cluster = new TreeSet<>(ClusterPrivilegeResolver.names()); final TreeSet index = new TreeSet<>(IndexPrivilege.names()); - listener.onResponse(new GetBuiltinPrivilegesResponse(cluster, index)); + final TreeSet remoteCluster = new TreeSet<>(RemoteClusterPermissions.getSupportedRemoteClusterPermissions()); + listener.onResponse(new GetBuiltinPrivilegesResponse(cluster, index, remoteCluster)); } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/privilege/RestGetBuiltinPrivilegesAction.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/privilege/RestGetBuiltinPrivilegesAction.java index 334e560312db1..d804559bba0ec 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/privilege/RestGetBuiltinPrivilegesAction.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/privilege/RestGetBuiltinPrivilegesAction.java @@ -73,6 +73,10 @@ public RestResponse buildResponse(GetBuiltinPrivilegesResponse response, XConten builder.startObject(); builder.array("cluster", translatedResponse.getClusterPrivileges()); builder.array("index", translatedResponse.getIndexPrivileges()); + String[] remoteClusterPrivileges = translatedResponse.getRemoteClusterPrivileges(); + if (remoteClusterPrivileges.length > 0) { // remote clusters are not supported in stateless mode, so hide entirely + builder.array("remote_cluster", remoteClusterPrivileges); + } builder.endObject(); return new RestResponse(RestStatus.OK, builder); } From 96075deff3806f7b7e7c0c07696a0ee44d59e2a5 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com> Date: Tue, 28 May 2024 15:15:26 -0400 Subject: [PATCH 017/208] [ML] Refactoring http settings and adding stats endpoint (#108219) * Refactoring http settings and adding comments * Removing new line * Adding stats endpoint * Improving comment and adding tests * Fixing typo in setting name * Switching to TransportNodesAction * Fixing test * Trying to fix test * Adding equals hashcode * Trying to send to all nodes * Renaming to .diagnostics * Removing unneeded variable --------- Co-authored-by: Elastic Machine --- .../action/GetInferenceDiagnosticsAction.java | 254 ++++++++++++++++++ ...nceDiagnosticsActionNodeResponseTests.java | 85 ++++++ ...ferenceDiagnosticsActionResponseTests.java | 70 +++++ .../xpack/inference/InferencePlugin.java | 18 +- ...ransportGetInferenceDiagnosticsAction.java | 78 ++++++ .../xpack/inference/common/Truncator.java | 2 +- .../inference/external/http/HttpClient.java | 19 ++ .../external/http/HttpClientManager.java | 94 ++++--- .../inference/external/http/HttpSettings.java | 5 +- .../xpack/inference/rest/Paths.java | 1 + .../RestGetInferenceDiagnosticsAction.java | 44 +++ .../external/http/HttpClientManagerTests.java | 2 +- .../xpack/security/operator/Constants.java | 1 + 13 files changed, 629 insertions(+), 44 deletions(-) create mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/GetInferenceDiagnosticsAction.java create mode 100644 x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/inference/action/GetInferenceDiagnosticsActionNodeResponseTests.java create mode 100644 x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/inference/action/GetInferenceDiagnosticsActionResponseTests.java create mode 100644 x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportGetInferenceDiagnosticsAction.java create mode 100644 x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestGetInferenceDiagnosticsAction.java diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/GetInferenceDiagnosticsAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/GetInferenceDiagnosticsAction.java new file mode 100644 index 0000000000000..29edc88ecda70 --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/GetInferenceDiagnosticsAction.java @@ -0,0 +1,254 @@ +/* + * 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.core.inference.action; + +import org.apache.http.pool.PoolStats; +import org.elasticsearch.action.ActionType; +import org.elasticsearch.action.FailedNodeException; +import org.elasticsearch.action.support.TransportAction; +import org.elasticsearch.action.support.nodes.BaseNodeResponse; +import org.elasticsearch.action.support.nodes.BaseNodesRequest; +import org.elasticsearch.action.support.nodes.BaseNodesResponse; +import org.elasticsearch.cluster.ClusterName; +import org.elasticsearch.cluster.node.DiscoveryNode; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.transport.TransportRequest; +import org.elasticsearch.xcontent.ToXContentFragment; +import org.elasticsearch.xcontent.ToXContentObject; +import org.elasticsearch.xcontent.XContentBuilder; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; + +public class GetInferenceDiagnosticsAction extends ActionType { + + public static final GetInferenceDiagnosticsAction INSTANCE = new GetInferenceDiagnosticsAction(); + public static final String NAME = "cluster:monitor/xpack/inference/diagnostics/get"; + + public GetInferenceDiagnosticsAction() { + super(NAME); + } + + public static class Request extends BaseNodesRequest { + + public Request() { + super((String[]) null); + } + + public Request(StreamInput in) throws IOException { + super(in); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + return true; + } + + @Override + public int hashCode() { + // The class doesn't have any members at the moment so return the same hash code + return Objects.hash(NAME); + } + + @Override + public void writeTo(StreamOutput out) { + TransportAction.localOnly(); + } + } + + public static class NodeRequest extends TransportRequest { + public NodeRequest(StreamInput in) throws IOException { + super(in); + } + + public NodeRequest() {} + } + + public static class Response extends BaseNodesResponse implements Writeable, ToXContentObject { + + public Response(StreamInput in) throws IOException { + super(in); + } + + public Response(ClusterName clusterName, List nodes, List failures) { + super(clusterName, nodes, failures); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + + for (var entry : getNodesMap().entrySet()) { + NodeResponse response = entry.getValue(); + + builder.startObject(entry.getKey()); + response.toXContent(builder, params); + builder.endObject(); + } + + builder.endObject(); + return builder; + } + + @Override + protected List readNodesFrom(StreamInput in) throws IOException { + return in.readCollectionAsList(NodeResponse::new); + } + + @Override + protected void writeNodesTo(StreamOutput out, List nodes) throws IOException { + out.writeCollection(nodes); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Response that = (Response) o; + return Objects.equals(getNodes(), that.getNodes()) && Objects.equals(failures(), that.failures()); + } + + @Override + public int hashCode() { + return Objects.hash(getNodes(), failures()); + } + } + + public static class NodeResponse extends BaseNodeResponse implements ToXContentFragment { + static final String CONNECTION_POOL_STATS_FIELD_NAME = "connection_pool_stats"; + + private final ConnectionPoolStats connectionPoolStats; + + public NodeResponse(DiscoveryNode node, PoolStats poolStats) { + super(node); + connectionPoolStats = ConnectionPoolStats.of(poolStats); + } + + public NodeResponse(StreamInput in) throws IOException { + super(in); + + connectionPoolStats = new ConnectionPoolStats(in); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + connectionPoolStats.writeTo(out); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.field(CONNECTION_POOL_STATS_FIELD_NAME, connectionPoolStats, params); + return builder; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + NodeResponse response = (NodeResponse) o; + return Objects.equals(connectionPoolStats, response.connectionPoolStats); + } + + @Override + public int hashCode() { + return Objects.hash(connectionPoolStats); + } + + ConnectionPoolStats getConnectionPoolStats() { + return connectionPoolStats; + } + + static class ConnectionPoolStats implements ToXContentObject, Writeable { + static final String LEASED_CONNECTIONS = "leased_connections"; + static final String PENDING_CONNECTIONS = "pending_connections"; + static final String AVAILABLE_CONNECTIONS = "available_connections"; + static final String MAX_CONNECTIONS = "max_connections"; + + static ConnectionPoolStats of(PoolStats poolStats) { + return new ConnectionPoolStats(poolStats.getLeased(), poolStats.getPending(), poolStats.getAvailable(), poolStats.getMax()); + } + + private final int leasedConnections; + private final int pendingConnections; + private final int availableConnections; + private final int maxConnections; + + ConnectionPoolStats(int leasedConnections, int pendingConnections, int availableConnections, int maxConnections) { + this.leasedConnections = leasedConnections; + this.pendingConnections = pendingConnections; + this.availableConnections = availableConnections; + this.maxConnections = maxConnections; + } + + ConnectionPoolStats(StreamInput in) throws IOException { + this.leasedConnections = in.readVInt(); + this.pendingConnections = in.readVInt(); + this.availableConnections = in.readVInt(); + this.maxConnections = in.readVInt(); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(LEASED_CONNECTIONS, leasedConnections); + builder.field(PENDING_CONNECTIONS, pendingConnections); + builder.field(AVAILABLE_CONNECTIONS, availableConnections); + builder.field(MAX_CONNECTIONS, maxConnections); + builder.endObject(); + + return builder; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeVInt(leasedConnections); + out.writeVInt(pendingConnections); + out.writeVInt(availableConnections); + out.writeVInt(maxConnections); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConnectionPoolStats that = (ConnectionPoolStats) o; + return leasedConnections == that.leasedConnections + && pendingConnections == that.pendingConnections + && availableConnections == that.availableConnections + && maxConnections == that.maxConnections; + } + + @Override + public int hashCode() { + return Objects.hash(leasedConnections, pendingConnections, availableConnections, maxConnections); + } + + int getLeasedConnections() { + return leasedConnections; + } + + int getPendingConnections() { + return pendingConnections; + } + + int getAvailableConnections() { + return availableConnections; + } + + int getMaxConnections() { + return maxConnections; + } + } + } +} diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/inference/action/GetInferenceDiagnosticsActionNodeResponseTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/inference/action/GetInferenceDiagnosticsActionNodeResponseTests.java new file mode 100644 index 0000000000000..a21354eb5a73d --- /dev/null +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/inference/action/GetInferenceDiagnosticsActionNodeResponseTests.java @@ -0,0 +1,85 @@ +/* + * 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.core.inference.action; + +import org.apache.http.pool.PoolStats; +import org.elasticsearch.cluster.node.DiscoveryNode; +import org.elasticsearch.cluster.node.DiscoveryNodeUtils; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.test.AbstractWireSerializingTestCase; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +public class GetInferenceDiagnosticsActionNodeResponseTests extends AbstractWireSerializingTestCase< + GetInferenceDiagnosticsAction.NodeResponse> { + public static GetInferenceDiagnosticsAction.NodeResponse createRandom() { + DiscoveryNode node = DiscoveryNodeUtils.create("id"); + var randomPoolStats = new PoolStats(randomInt(), randomInt(), randomInt(), randomInt()); + + return new GetInferenceDiagnosticsAction.NodeResponse(node, randomPoolStats); + } + + @Override + protected Writeable.Reader instanceReader() { + return GetInferenceDiagnosticsAction.NodeResponse::new; + } + + @Override + protected GetInferenceDiagnosticsAction.NodeResponse createTestInstance() { + return createRandom(); + } + + @Override + protected GetInferenceDiagnosticsAction.NodeResponse mutateInstance(GetInferenceDiagnosticsAction.NodeResponse instance) + throws IOException { + var select = randomIntBetween(0, 3); + var connPoolStats = instance.getConnectionPoolStats(); + + return switch (select) { + case 0 -> new GetInferenceDiagnosticsAction.NodeResponse( + instance.getNode(), + new PoolStats( + randomInt(), + connPoolStats.getPendingConnections(), + connPoolStats.getAvailableConnections(), + connPoolStats.getMaxConnections() + ) + ); + case 1 -> new GetInferenceDiagnosticsAction.NodeResponse( + instance.getNode(), + new PoolStats( + connPoolStats.getLeasedConnections(), + randomInt(), + connPoolStats.getAvailableConnections(), + connPoolStats.getMaxConnections() + ) + ); + case 2 -> new GetInferenceDiagnosticsAction.NodeResponse( + instance.getNode(), + new PoolStats( + connPoolStats.getLeasedConnections(), + connPoolStats.getPendingConnections(), + randomInt(), + connPoolStats.getMaxConnections() + ) + ); + case 3 -> new GetInferenceDiagnosticsAction.NodeResponse( + instance.getNode(), + new PoolStats( + connPoolStats.getLeasedConnections(), + connPoolStats.getPendingConnections(), + connPoolStats.getAvailableConnections(), + randomInt() + ) + ); + default -> throw new UnsupportedEncodingException(Strings.format("Encountered unsupported case %s", select)); + }; + } +} diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/inference/action/GetInferenceDiagnosticsActionResponseTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/inference/action/GetInferenceDiagnosticsActionResponseTests.java new file mode 100644 index 0000000000000..e3eb42efdc791 --- /dev/null +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/inference/action/GetInferenceDiagnosticsActionResponseTests.java @@ -0,0 +1,70 @@ +/* + * 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.core.inference.action; + +import org.apache.http.pool.PoolStats; +import org.elasticsearch.cluster.ClusterName; +import org.elasticsearch.cluster.node.DiscoveryNodeUtils; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xcontent.XContentFactory; +import org.elasticsearch.xcontent.XContentType; +import org.hamcrest.CoreMatchers; + +import java.io.IOException; +import java.util.List; + +public class GetInferenceDiagnosticsActionResponseTests extends AbstractWireSerializingTestCase { + + public static GetInferenceDiagnosticsAction.Response createRandom() { + List responses = randomList( + 2, + 10, + GetInferenceDiagnosticsActionNodeResponseTests::createRandom + ); + return new GetInferenceDiagnosticsAction.Response(ClusterName.DEFAULT, responses, List.of()); + } + + public void testToXContent() throws IOException { + var node = DiscoveryNodeUtils.create("id"); + var poolStats = new PoolStats(1, 2, 3, 4); + var entity = new GetInferenceDiagnosticsAction.Response( + ClusterName.DEFAULT, + List.of(new GetInferenceDiagnosticsAction.NodeResponse(node, poolStats)), + List.of() + ); + + XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON); + entity.toXContent(builder, null); + String xContentResult = org.elasticsearch.common.Strings.toString(builder); + + assertThat(xContentResult, CoreMatchers.is(""" + {"id":{"connection_pool_stats":{"leased_connections":1,"pending_connections":2,"available_connections":3,""" + """ + "max_connections":4}}}""")); + } + + @Override + protected Writeable.Reader instanceReader() { + return GetInferenceDiagnosticsAction.Response::new; + } + + @Override + protected GetInferenceDiagnosticsAction.Response createTestInstance() { + return createRandom(); + } + + @Override + protected GetInferenceDiagnosticsAction.Response mutateInstance(GetInferenceDiagnosticsAction.Response instance) { + return new GetInferenceDiagnosticsAction.Response( + ClusterName.DEFAULT, + instance.getNodes().subList(1, instance.getNodes().size()), + List.of() + ); + } +} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java index 83fc7323eab40..108da3beef789 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java @@ -39,10 +39,12 @@ import org.elasticsearch.xpack.core.ClientHelper; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.core.inference.action.DeleteInferenceModelAction; +import org.elasticsearch.xpack.core.inference.action.GetInferenceDiagnosticsAction; import org.elasticsearch.xpack.core.inference.action.GetInferenceModelAction; import org.elasticsearch.xpack.core.inference.action.InferenceAction; import org.elasticsearch.xpack.core.inference.action.PutInferenceModelAction; import org.elasticsearch.xpack.inference.action.TransportDeleteInferenceModelAction; +import org.elasticsearch.xpack.inference.action.TransportGetInferenceDiagnosticsAction; import org.elasticsearch.xpack.inference.action.TransportGetInferenceModelAction; import org.elasticsearch.xpack.inference.action.TransportInferenceAction; import org.elasticsearch.xpack.inference.action.TransportInferenceUsageAction; @@ -59,6 +61,7 @@ import org.elasticsearch.xpack.inference.queries.SemanticQueryBuilder; import org.elasticsearch.xpack.inference.registry.ModelRegistry; import org.elasticsearch.xpack.inference.rest.RestDeleteInferenceModelAction; +import org.elasticsearch.xpack.inference.rest.RestGetInferenceDiagnosticsAction; import org.elasticsearch.xpack.inference.rest.RestGetInferenceModelAction; import org.elasticsearch.xpack.inference.rest.RestInferenceAction; import org.elasticsearch.xpack.inference.rest.RestPutInferenceModelAction; @@ -123,7 +126,8 @@ public InferencePlugin(Settings settings) { new ActionHandler<>(GetInferenceModelAction.INSTANCE, TransportGetInferenceModelAction.class), new ActionHandler<>(PutInferenceModelAction.INSTANCE, TransportPutInferenceModelAction.class), new ActionHandler<>(DeleteInferenceModelAction.INSTANCE, TransportDeleteInferenceModelAction.class), - new ActionHandler<>(XPackUsageFeatureAction.INFERENCE, TransportInferenceUsageAction.class) + new ActionHandler<>(XPackUsageFeatureAction.INFERENCE, TransportInferenceUsageAction.class), + new ActionHandler<>(GetInferenceDiagnosticsAction.INSTANCE, TransportGetInferenceDiagnosticsAction.class) ); } @@ -143,7 +147,8 @@ public List getRestHandlers( new RestInferenceAction(), new RestGetInferenceModelAction(), new RestPutInferenceModelAction(), - new RestDeleteInferenceModelAction() + new RestDeleteInferenceModelAction(), + new RestGetInferenceDiagnosticsAction() ); } @@ -153,11 +158,8 @@ public Collection createComponents(PluginServices services) { var truncator = new Truncator(settings, services.clusterService()); serviceComponents.set(new ServiceComponents(services.threadPool(), throttlerManager, settings, truncator)); - var httpRequestSenderFactory = new HttpRequestSender.Factory( - serviceComponents.get(), - HttpClientManager.create(settings, services.threadPool(), services.clusterService(), throttlerManager), - services.clusterService() - ); + var httpClientManager = HttpClientManager.create(settings, services.threadPool(), services.clusterService(), throttlerManager); + var httpRequestSenderFactory = new HttpRequestSender.Factory(serviceComponents.get(), httpClientManager, services.clusterService()); httpFactory.set(httpRequestSenderFactory); ModelRegistry modelRegistry = new ModelRegistry(services.client()); @@ -178,7 +180,7 @@ public Collection createComponents(PluginServices services) { var actionFilter = new ShardBulkInferenceActionFilter(registry, modelRegistry); shardBulkInferenceActionFilter.set(actionFilter); - return List.of(modelRegistry, registry); + return List.of(modelRegistry, registry, httpClientManager); } @Override diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportGetInferenceDiagnosticsAction.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportGetInferenceDiagnosticsAction.java new file mode 100644 index 0000000000000..8c9ab8f4cdffa --- /dev/null +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportGetInferenceDiagnosticsAction.java @@ -0,0 +1,78 @@ +/* + * 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.inference.action; + +import org.elasticsearch.action.FailedNodeException; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.nodes.TransportNodesAction; +import org.elasticsearch.cluster.node.DiscoveryNode; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.tasks.Task; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.inference.action.GetInferenceDiagnosticsAction; +import org.elasticsearch.xpack.inference.external.http.HttpClientManager; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; + +public class TransportGetInferenceDiagnosticsAction extends TransportNodesAction< + GetInferenceDiagnosticsAction.Request, + GetInferenceDiagnosticsAction.Response, + GetInferenceDiagnosticsAction.NodeRequest, + GetInferenceDiagnosticsAction.NodeResponse> { + + private final HttpClientManager httpClientManager; + + @Inject + public TransportGetInferenceDiagnosticsAction( + ThreadPool threadPool, + ClusterService clusterService, + TransportService transportService, + ActionFilters actionFilters, + HttpClientManager httpClientManager + ) { + super( + GetInferenceDiagnosticsAction.NAME, + clusterService, + transportService, + actionFilters, + GetInferenceDiagnosticsAction.NodeRequest::new, + threadPool.executor(ThreadPool.Names.MANAGEMENT) + ); + + this.httpClientManager = Objects.requireNonNull(httpClientManager); + } + + @Override + protected GetInferenceDiagnosticsAction.Response newResponse( + GetInferenceDiagnosticsAction.Request request, + List nodeResponses, + List failures + ) { + return new GetInferenceDiagnosticsAction.Response(clusterService.getClusterName(), nodeResponses, failures); + } + + @Override + protected GetInferenceDiagnosticsAction.NodeRequest newNodeRequest(GetInferenceDiagnosticsAction.Request request) { + return new GetInferenceDiagnosticsAction.NodeRequest(); + } + + @Override + protected GetInferenceDiagnosticsAction.NodeResponse newNodeResponse(StreamInput in, DiscoveryNode node) throws IOException { + return new GetInferenceDiagnosticsAction.NodeResponse(in); + } + + @Override + protected GetInferenceDiagnosticsAction.NodeResponse nodeOperation(GetInferenceDiagnosticsAction.NodeRequest request, Task task) { + return new GetInferenceDiagnosticsAction.NodeResponse(transportService.getLocalNode(), httpClientManager.getPoolStats()); + } +} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/common/Truncator.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/common/Truncator.java index 2da509d0d9520..eabed7f6a7bd3 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/common/Truncator.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/common/Truncator.java @@ -26,7 +26,7 @@ public class Truncator { * Defines the percentage to reduce the input text for an inference request. */ static final Setting REDUCTION_PERCENTAGE_SETTING = Setting.doubleSetting( - "xpack.inference.truncator.reducation_percentage", + "xpack.inference.truncator.reduction_percentage", 0.5, 0.01, 0.99, diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/http/HttpClient.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/http/HttpClient.java index 99631c380b9fa..5ae137419b366 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/http/HttpClient.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/http/HttpClient.java @@ -66,6 +66,25 @@ private static CloseableHttpAsyncClient createAsyncClient(PoolingNHttpClientConn // so we don't want to support cookies to avoid accidental authentication for unauthorized users clientBuilder.disableCookieManagement(); + /* + By default, if a keep-alive header is not returned by the server then the connection will be kept alive + indefinitely. In this situation the default keep alive strategy will return -1. Since we use a connection eviction thread, + connections that are idle past the max idle time will be closed with the eviction thread executes. If that functionality proves + not to be sufficient we can add a keep-alive strategy to the builder below. + + In my testing, setting a keep-alive didn't actually influence when the connection would be removed from the pool. Setting a low + keep alive forced later requests that occurred after the duration to recreate the connection. The stale connections would not be + removed from the pool until the eviction thread closes expired connections. + + My understanding is that a connection marked as ready to be closed because of an elapsed keep-alive time will only be put into + expiry status when another request is made. + + For more info see the tutorial here under section keep-alive strategy: + https://hc.apache.org/httpcomponents-client-4.5.x/current/tutorial/html/connmgmt.html + + And this stackoverflow question: + https://stackoverflow.com/questions/64676200/understanding-the-lifecycle-of-a-connection-managed-by-poolinghttpclientconnecti + */ return clientBuilder.build(); } diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/http/HttpClientManager.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/http/HttpClientManager.java index ab3a8a8c0e043..8be3b76f68c54 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/http/HttpClientManager.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/http/HttpClientManager.java @@ -12,6 +12,7 @@ import org.apache.http.impl.nio.reactor.IOReactorConfig; import org.apache.http.nio.reactor.ConnectingIOReactor; import org.apache.http.nio.reactor.IOReactorException; +import org.apache.http.pool.PoolStats; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.elasticsearch.ElasticsearchException; @@ -31,12 +32,24 @@ public class HttpClientManager implements Closeable { private static final Logger logger = LogManager.getLogger(HttpClientManager.class); /** + * The maximum number of total connections the connection pool can lease to all routes. * From googling around the connection pools maxTotal value should be close to the number of available threads. * * https://stackoverflow.com/questions/30989637/how-to-decide-optimal-settings-for-setmaxtotal-and-setdefaultmaxperroute */ - public static final Setting MAX_CONNECTIONS = Setting.intSetting( - "xpack.inference.http.max_connections", + public static final Setting MAX_TOTAL_CONNECTIONS = Setting.intSetting( + "xpack.inference.http.max_total_connections", + 50, // default + 1, // min + Setting.Property.NodeScope, + Setting.Property.Dynamic + ); + + /** + * The max number of connections a single route can lease. + */ + public static final Setting MAX_ROUTE_CONNECTIONS = Setting.intSetting( + "xpack.inference.http.max_route_connections", 20, // default 1, // min Setting.Property.NodeScope, @@ -51,20 +64,30 @@ public class HttpClientManager implements Closeable { Setting.Property.Dynamic ); - private static final TimeValue DEFAULT_CONNECTION_EVICTION_MAX_IDLE_TIME_SETTING = DEFAULT_CONNECTION_EVICTION_THREAD_INTERVAL_TIME; - public static final Setting CONNECTION_EVICTION_MAX_IDLE_TIME_SETTING = Setting.timeSetting( + private static final TimeValue DEFAULT_CONNECTION_MAX_IDLE_TIME_SETTING = DEFAULT_CONNECTION_EVICTION_THREAD_INTERVAL_TIME; + /** + * The max duration of time for a connection to be marked as idle and ready to be closed. This defines the amount of time + * a connection can be unused in the connection pool before being closed the next time the eviction thread runs. + * It also defines the keep-alive value for the connection if one is not specified by the 3rd party service's server. + * + * For more info see the answer here: + * https://stackoverflow.com/questions/64676200/understanding-the-lifecycle-of-a-connection-managed-by-poolinghttpclientconnecti + */ + public static final Setting CONNECTION_MAX_IDLE_TIME_SETTING = Setting.timeSetting( "xpack.inference.http.connection_eviction_max_idle_time", - DEFAULT_CONNECTION_EVICTION_MAX_IDLE_TIME_SETTING, + DEFAULT_CONNECTION_MAX_IDLE_TIME_SETTING, Setting.Property.NodeScope, Setting.Property.Dynamic ); private final ThreadPool threadPool; private final PoolingNHttpClientConnectionManager connectionManager; - private EvictorSettings evictorSettings; private IdleConnectionEvictor connectionEvictor; private final HttpClient httpClient; + private volatile TimeValue evictionInterval; + private volatile TimeValue connectionMaxIdle; + public static HttpClientManager create( Settings settings, ThreadPool threadPool, @@ -86,11 +109,13 @@ public static HttpClientManager create( this.threadPool = threadPool; this.connectionManager = connectionManager; - setMaxConnections(MAX_CONNECTIONS.get(settings)); + setMaxConnections(MAX_TOTAL_CONNECTIONS.get(settings)); + setMaxRouteConnections(MAX_ROUTE_CONNECTIONS.get(settings)); this.httpClient = HttpClient.create(new HttpSettings(settings, clusterService), threadPool, connectionManager, throttlerManager); - evictorSettings = new EvictorSettings(settings); + this.evictionInterval = CONNECTION_EVICTION_THREAD_INTERVAL_SETTING.get(settings); + this.connectionMaxIdle = CONNECTION_MAX_IDLE_TIME_SETTING.get(settings); connectionEvictor = createConnectionEvictor(); this.addSettingsUpdateConsumers(clusterService); @@ -107,22 +132,34 @@ private static PoolingNHttpClientConnectionManager createConnectionManager() { throw new ElasticsearchException(message, e); } + /* + The max time to live for open connections in the pool will not be set because we don't specify a ttl in the constructor. + This meaning that there should not be a limit. + We can control the TTL dynamically using the IdleConnectionEvictor and keep-alive strategy. + The max idle time cluster setting will dictate how much time an open connection can be unused for before it can be closed. + */ return new PoolingNHttpClientConnectionManager(ioReactor); } private void addSettingsUpdateConsumers(ClusterService clusterService) { - clusterService.getClusterSettings().addSettingsUpdateConsumer(MAX_CONNECTIONS, this::setMaxConnections); + clusterService.getClusterSettings().addSettingsUpdateConsumer(MAX_TOTAL_CONNECTIONS, this::setMaxConnections); + clusterService.getClusterSettings().addSettingsUpdateConsumer(MAX_ROUTE_CONNECTIONS, this::setMaxRouteConnections); clusterService.getClusterSettings() .addSettingsUpdateConsumer(CONNECTION_EVICTION_THREAD_INTERVAL_SETTING, this::setEvictionInterval); - clusterService.getClusterSettings().addSettingsUpdateConsumer(CONNECTION_EVICTION_MAX_IDLE_TIME_SETTING, this::setEvictionMaxIdle); + clusterService.getClusterSettings().addSettingsUpdateConsumer(CONNECTION_MAX_IDLE_TIME_SETTING, this::setConnectionMaxIdle); } private IdleConnectionEvictor createConnectionEvictor() { - return new IdleConnectionEvictor(threadPool, connectionManager, evictorSettings.evictionInterval, evictorSettings.evictionMaxIdle); + return new IdleConnectionEvictor(threadPool, connectionManager, evictionInterval, connectionMaxIdle); } public static List> getSettings() { - return List.of(MAX_CONNECTIONS, CONNECTION_EVICTION_THREAD_INTERVAL_SETTING, CONNECTION_EVICTION_MAX_IDLE_TIME_SETTING); + return List.of( + MAX_TOTAL_CONNECTIONS, + MAX_ROUTE_CONNECTIONS, + CONNECTION_EVICTION_THREAD_INTERVAL_SETTING, + CONNECTION_MAX_IDLE_TIME_SETTING + ); } public void start() { @@ -134,6 +171,10 @@ public HttpClient getHttpClient() { return httpClient; } + public PoolStats getPoolStats() { + return connectionManager.getTotalStats(); + } + @Override public void close() throws IOException { httpClient.close(); @@ -142,6 +183,9 @@ public void close() throws IOException { private void setMaxConnections(int maxConnections) { connectionManager.setMaxTotal(maxConnections); + } + + private void setMaxRouteConnections(int maxConnections) { connectionManager.setDefaultMaxPerRoute(maxConnections); } @@ -153,32 +197,16 @@ boolean isEvictionThreadRunning() { // default for testing void setEvictionInterval(TimeValue evictionInterval) { logger.debug(() -> format("Eviction thread's interval time updated to [%s]", evictionInterval)); - - evictorSettings = new EvictorSettings(evictionInterval, evictorSettings.evictionMaxIdle); + this.evictionInterval = evictionInterval; connectionEvictor.close(); connectionEvictor = createConnectionEvictor(); connectionEvictor.start(); } - void setEvictionMaxIdle(TimeValue evictionMaxIdle) { - logger.debug(() -> format("Eviction thread's max idle time updated to [%s]", evictionMaxIdle)); - evictorSettings = new EvictorSettings(evictorSettings.evictionInterval, evictionMaxIdle); - connectionEvictor.setMaxIdleTime(evictionMaxIdle); - } - - private static class EvictorSettings { - private final TimeValue evictionInterval; - private final TimeValue evictionMaxIdle; - - EvictorSettings(Settings settings) { - this.evictionInterval = CONNECTION_EVICTION_THREAD_INTERVAL_SETTING.get(settings); - this.evictionMaxIdle = CONNECTION_EVICTION_MAX_IDLE_TIME_SETTING.get(settings); - } - - EvictorSettings(TimeValue evictionInterval, TimeValue evictionMaxIdle) { - this.evictionInterval = evictionInterval; - this.evictionMaxIdle = evictionMaxIdle; - } + void setConnectionMaxIdle(TimeValue connectionMaxIdle) { + logger.debug(() -> format("Eviction thread's max idle time updated to [%s]", connectionMaxIdle)); + this.connectionMaxIdle = connectionMaxIdle; + connectionEvictor.setMaxIdleTime(connectionMaxIdle); } } diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/http/HttpSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/http/HttpSettings.java index 07d998dff956e..ef5fec24c3d59 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/http/HttpSettings.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/http/HttpSettings.java @@ -14,6 +14,7 @@ import org.elasticsearch.common.unit.ByteSizeValue; import java.util.List; +import java.util.Objects; public class HttpSettings { // These settings are default scope for testing @@ -29,7 +30,9 @@ public class HttpSettings { private volatile ByteSizeValue maxResponseSize; public HttpSettings(Settings settings, ClusterService clusterService) { - this.maxResponseSize = MAX_HTTP_RESPONSE_SIZE.get(settings); + Objects.requireNonNull(clusterService); + Objects.requireNonNull(settings); + maxResponseSize = MAX_HTTP_RESPONSE_SIZE.get(settings); clusterService.getClusterSettings().addSettingsUpdateConsumer(MAX_HTTP_RESPONSE_SIZE, this::setMaxResponseSize); } diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/Paths.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/Paths.java index 1fc67d379a703..e33931f3d2f8d 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/Paths.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/Paths.java @@ -13,6 +13,7 @@ public final class Paths { static final String TASK_TYPE_OR_INFERENCE_ID = "task_type_or_id"; static final String INFERENCE_ID_PATH = "_inference/{" + TASK_TYPE_OR_INFERENCE_ID + "}"; static final String TASK_TYPE_INFERENCE_ID_PATH = "_inference/{" + TASK_TYPE_OR_INFERENCE_ID + "}/{" + INFERENCE_ID + "}"; + static final String INFERENCE_DIAGNOSTICS_PATH = "_inference/.diagnostics"; private Paths() { diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestGetInferenceDiagnosticsAction.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestGetInferenceDiagnosticsAction.java new file mode 100644 index 0000000000000..18ee2bc348bd3 --- /dev/null +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestGetInferenceDiagnosticsAction.java @@ -0,0 +1,44 @@ +/* + * 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.inference.rest; + +import org.elasticsearch.client.internal.node.NodeClient; +import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.Scope; +import org.elasticsearch.rest.ServerlessScope; +import org.elasticsearch.rest.action.RestToXContentListener; +import org.elasticsearch.xpack.core.inference.action.GetInferenceDiagnosticsAction; + +import java.util.List; + +import static org.elasticsearch.rest.RestRequest.Method.GET; +import static org.elasticsearch.xpack.inference.rest.Paths.INFERENCE_DIAGNOSTICS_PATH; + +@ServerlessScope(Scope.INTERNAL) +public class RestGetInferenceDiagnosticsAction extends BaseRestHandler { + + @Override + public String getName() { + return "get_inference_diagnostics_action"; + } + + @Override + public List routes() { + return List.of(new Route(GET, INFERENCE_DIAGNOSTICS_PATH)); + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { + return channel -> client.execute( + GetInferenceDiagnosticsAction.INSTANCE, + new GetInferenceDiagnosticsAction.Request(), + new RestToXContentListener<>(channel) + ); + } +} diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/http/HttpClientManagerTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/http/HttpClientManagerTests.java index cfdf2e8bb8bcd..7bd8186299522 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/http/HttpClientManagerTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/http/HttpClientManagerTests.java @@ -106,7 +106,7 @@ public void test_DoesNotStartANewEvictor_WithNewEvictionMaxIdle() { ); var evictionMaxIdle = TimeValue.timeValueSeconds(1); - manager.setEvictionMaxIdle(evictionMaxIdle); + manager.setConnectionMaxIdle(evictionMaxIdle); assertFalse(manager.isEvictionThreadRunning()); } diff --git a/x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/Constants.java b/x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/Constants.java index 28f768d13dbf1..ae5af54f078dd 100644 --- a/x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/Constants.java +++ b/x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/Constants.java @@ -369,6 +369,7 @@ public class Constants { "cluster:monitor/xpack/esql/stats/dist", "cluster:monitor/xpack/inference", "cluster:monitor/xpack/inference/get", + "cluster:monitor/xpack/inference/diagnostics/get", "cluster:monitor/xpack/info", "cluster:monitor/xpack/info/aggregate_metric", "cluster:monitor/xpack/info/analytics", From d880c76fad39333cae24ad2a3169b7495dcacb95 Mon Sep 17 00:00:00 2001 From: Mike Pellegrini Date: Tue, 28 May 2024 16:14:08 -0400 Subject: [PATCH 018/208] Handle partial semantic_text updates submitted through the Update API (#108880) Update TransportUpdateAction to remove stale inference results from _source when a semantic_text field with multiple source fields is partially updated through the Update API. --- .../action/update/TransportUpdateAction.java | 99 ++- .../index/mapper/InferenceFieldMapper.java | 9 + ...appingLookupInferenceFieldMapperTests.java | 5 + .../mapper/SemanticTextFieldMapper.java | 24 +- .../inference/30_semantic_text_inference.yml | 317 +-------- .../60_semantic_text_inference_update.yml | 612 ++++++++++++++++++ 6 files changed, 749 insertions(+), 317 deletions(-) create mode 100644 x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/60_semantic_text_inference_update.yml diff --git a/server/src/main/java/org/elasticsearch/action/update/TransportUpdateAction.java b/server/src/main/java/org/elasticsearch/action/update/TransportUpdateAction.java index ad297c14981aa..cd899d732e916 100644 --- a/server/src/main/java/org/elasticsearch/action/update/TransportUpdateAction.java +++ b/server/src/main/java/org/elasticsearch/action/update/TransportUpdateAction.java @@ -8,6 +8,7 @@ package org.elasticsearch.action.update; +import org.elasticsearch.ElasticsearchStatusException; import org.elasticsearch.ResourceAlreadyExistsException; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionRunnable; @@ -27,6 +28,7 @@ import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.metadata.InferenceFieldMetadata; import org.elasticsearch.cluster.routing.IndexRouting; import org.elasticsearch.cluster.routing.RoutingTable; import org.elasticsearch.cluster.routing.ShardIterator; @@ -36,13 +38,18 @@ import org.elasticsearch.common.io.stream.NotSerializableExceptionWrapper; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.core.Tuple; import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.IndexService; import org.elasticsearch.index.engine.VersionConflictEngineException; +import org.elasticsearch.index.mapper.InferenceFieldMapper; +import org.elasticsearch.index.mapper.Mapper; +import org.elasticsearch.index.mapper.MappingLookup; import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.indices.IndicesService; +import org.elasticsearch.rest.RestStatus; import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool.Names; @@ -179,7 +186,13 @@ protected void shardOperation(final UpdateRequest request, final ActionListener< final ShardId shardId = request.getShardId(); final IndexService indexService = indicesService.indexServiceSafe(shardId.getIndex()); final IndexShard indexShard = indexService.getShard(shardId.getId()); - final UpdateHelper.Result result = updateHelper.prepare(request, indexShard, threadPool::absoluteTimeInMillis); + final UpdateHelper.Result result = deleteInferenceResults( + request, + updateHelper.prepare(request, indexShard, threadPool::absoluteTimeInMillis), + indexService.getMetadata(), + indexShard.mapperService().mappingLookup() + ); + switch (result.getResponseResult()) { case CREATED -> { IndexRequest upsertRequest = result.action(); @@ -333,4 +346,88 @@ private void handleUpdateFailureWithRetry( } listener.onFailure(cause instanceof Exception ? (Exception) cause : new NotSerializableExceptionWrapper(cause)); } + + /** + *

+ * Delete stale inference results from the provided {@link UpdateHelper.Result} instance. + *

+ *

+ * We need to do this because when handling Bulk API requests (which the Update API generates), we assume any inference results present + * in source are up-to-date. + * We do this to support reindex and update by query use cases without re-generating inference results unnecessarily. + *

+ * + * @param updateRequest The update request + * @param result The result generated using the update request + * @param indexMetadata The index metadata + * @param mappingLookup The index's mapping lookup + * @return A result with stale inference results removed from source + */ + private static UpdateHelper.Result deleteInferenceResults( + UpdateRequest updateRequest, + UpdateHelper.Result result, + IndexMetadata indexMetadata, + MappingLookup mappingLookup + ) { + if (result.getResponseResult() != DocWriteResponse.Result.UPDATED) { + return result; + } + + Map inferenceFields = indexMetadata.getInferenceFields(); + if (inferenceFields.isEmpty()) { + return result; + } + + if (updateRequest.script() != null) { + throw new ElasticsearchStatusException( + "Cannot apply update with a script on indices that contain inference field(s)", + RestStatus.BAD_REQUEST + ); + } + + IndexRequest doc = updateRequest.doc(); + if (doc == null) { + // No doc update, nothing to do + return result; + } + + Map updateRequestSource = doc.sourceAsMap(); + Map updatedSource = result.updatedSourceAsMap(); + boolean updatedSourceModified = false; + for (var entry : inferenceFields.entrySet()) { + String inferenceFieldName = entry.getKey(); + Mapper mapper = mappingLookup.getMapper(inferenceFieldName); + + if (mapper instanceof InferenceFieldMapper inferenceFieldMapper) { + String[] sourceFields = entry.getValue().getSourceFields(); + for (String sourceField : sourceFields) { + if (sourceField.equals(inferenceFieldName) == false + && XContentMapValues.extractValue(sourceField, updateRequestSource) != null) { + // Replace the inference field's value with its original value (i.e. the user-specified value). + // This has two important side effects: + // - The inference field value will remain parsable by its mapper + // - The inference results will be removed, forcing them to be re-generated downstream + updatedSource.put(inferenceFieldName, inferenceFieldMapper.getOriginalValue(updatedSource)); + updatedSourceModified = true; + break; + } + } + } else { + throw new IllegalStateException( + "Field [" + inferenceFieldName + "] is of type [ " + mapper.typeName() + "], which is not an inference field" + ); + } + } + + UpdateHelper.Result returnedResult = result; + if (updatedSourceModified) { + XContentType contentType = result.updateSourceContentType(); + IndexRequest indexRequest = result.action(); + indexRequest.source(updatedSource, contentType); + + returnedResult = new UpdateHelper.Result(indexRequest, result.getResponseResult(), updatedSource, contentType); + } + + return returnedResult; + } } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/InferenceFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/InferenceFieldMapper.java index 2b0833c72021b..cab06dc8a4e35 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/InferenceFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/InferenceFieldMapper.java @@ -11,6 +11,7 @@ import org.elasticsearch.cluster.metadata.InferenceFieldMetadata; import org.elasticsearch.inference.InferenceService; +import java.util.Map; import java.util.Set; /** @@ -24,4 +25,12 @@ public interface InferenceFieldMapper { * @param sourcePaths The source path that populates the input for the field (before inference) */ InferenceFieldMetadata getMetadata(Set sourcePaths); + + /** + * Get the field's original value (i.e. the value the user specified) from the provided source. + * + * @param sourceAsMap The source as a map + * @return The field's original value, or {@code null} if none was provided + */ + Object getOriginalValue(Map sourceAsMap); } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/MappingLookupInferenceFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/MappingLookupInferenceFieldMapperTests.java index b13f6b79b0de5..5b636c985f695 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/MappingLookupInferenceFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/MappingLookupInferenceFieldMapperTests.java @@ -104,6 +104,11 @@ public InferenceFieldMetadata getMetadata(Set sourcePaths) { return new InferenceFieldMetadata(name(), INFERENCE_ID, sourcePaths.toArray(new String[0])); } + @Override + public Object getOriginalValue(Map sourceAsMap) { + return null; + } + @Override protected void parseCreateField(DocumentParserContext context) throws IOException {} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/mapper/SemanticTextFieldMapper.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/mapper/SemanticTextFieldMapper.java index 8324b121dfc4f..6874938f1e118 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/mapper/SemanticTextFieldMapper.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/mapper/SemanticTextFieldMapper.java @@ -13,6 +13,7 @@ import org.elasticsearch.common.Explicit; import org.elasticsearch.common.Strings; import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.core.Nullable; import org.elasticsearch.core.Tuple; import org.elasticsearch.index.IndexVersion; @@ -65,6 +66,7 @@ import static org.elasticsearch.xpack.inference.mapper.SemanticTextField.CHUNKS_FIELD; import static org.elasticsearch.xpack.inference.mapper.SemanticTextField.INFERENCE_FIELD; import static org.elasticsearch.xpack.inference.mapper.SemanticTextField.INFERENCE_ID_FIELD; +import static org.elasticsearch.xpack.inference.mapper.SemanticTextField.TEXT_FIELD; import static org.elasticsearch.xpack.inference.mapper.SemanticTextField.getChunksFieldName; import static org.elasticsearch.xpack.inference.mapper.SemanticTextField.getEmbeddingsFieldName; import static org.elasticsearch.xpack.inference.mapper.SemanticTextField.getOriginalTextFieldName; @@ -188,6 +190,7 @@ protected void parseCreateField(DocumentParserContext context) throws IOExceptio if (parser.currentToken() == XContentParser.Token.VALUE_NULL) { return; } + XContentLocation xContentLocation = parser.getTokenLocation(); final SemanticTextField field; boolean isWithinLeaf = context.path().isWithinLeafObject(); @@ -197,6 +200,7 @@ protected void parseCreateField(DocumentParserContext context) throws IOExceptio } finally { context.path().setWithinLeafObject(isWithinLeaf); } + final String fullFieldName = fieldType().name(); if (field.inference().inferenceId().equals(fieldType().getInferenceId()) == false) { throw new DocumentParsingException( @@ -211,6 +215,7 @@ protected void parseCreateField(DocumentParserContext context) throws IOExceptio ) ); } + final SemanticTextFieldMapper mapper; if (fieldType().getModelSettings() == null) { context.path().remove(); @@ -241,6 +246,7 @@ protected void parseCreateField(DocumentParserContext context) throws IOExceptio } mapper = this; } + var chunksField = mapper.fieldType().getChunksField(); var embeddingsField = mapper.fieldType().getEmbeddingsField(); for (var chunk : field.inference().chunks()) { @@ -276,6 +282,20 @@ public InferenceFieldMetadata getMetadata(Set sourcePaths) { return new InferenceFieldMetadata(name(), fieldType().inferenceId, copyFields); } + @Override + public Object getOriginalValue(Map sourceAsMap) { + Object fieldValue = sourceAsMap.get(name()); + if (fieldValue == null) { + return null; + } else if (fieldValue instanceof Map == false) { + // Don't try to further validate the non-map value, that will be handled when the source is fully parsed + return fieldValue; + } + + Map fieldValueMap = XContentMapValues.nodeMapValue(fieldValue, "Field [" + name() + "]"); + return XContentMapValues.extractValue(TEXT_FIELD, fieldValueMap); + } + public static class SemanticTextFieldType extends SimpleMappedFieldType { private final String inferenceId; private final SemanticTextField.ModelSettings modelSettings; @@ -284,14 +304,14 @@ public static class SemanticTextFieldType extends SimpleMappedFieldType { public SemanticTextFieldType( String name, - String modelId, + String inferenceId, SemanticTextField.ModelSettings modelSettings, ObjectMapper inferenceField, IndexVersion indexVersionCreated, Map meta ) { super(name, false, false, false, TextSearchInfo.NONE, meta); - this.inferenceId = modelId; + this.inferenceId = inferenceId; this.modelSettings = modelSettings; this.inferenceField = inferenceField; this.indexVersionCreated = indexVersionCreated; diff --git a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/30_semantic_text_inference.yml b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/30_semantic_text_inference.yml index d4769ac1a1af3..9987b43822cc0 100644 --- a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/30_semantic_text_inference.yml +++ b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/30_semantic_text_inference.yml @@ -17,6 +17,7 @@ setup: "task_settings": { } } + - do: inference.put: task_type: text_embedding @@ -214,126 +215,6 @@ setup: - length: { hits.hits.1.inner_hits.dense_field\.inference\.chunks.hits.hits.0.fields.dense_field\.inference\.chunks.0.text: 1 } - length: { hits.hits.1.inner_hits.dense_field\.inference\.chunks.hits.hits.1.fields.dense_field\.inference\.chunks.0.text: 1 } - - ---- -"Updating non semantic_text fields does not recalculate embeddings": - - do: - index: - index: test-index - id: doc_1 - body: - sparse_field: "inference test" - dense_field: "another inference test" - non_inference_field: "non inference test" - - - do: - get: - index: test-index - id: doc_1 - - - set: { _source.sparse_field.inference.chunks.0.embeddings: sparse_field_embedding } - - set: { _source.dense_field.inference.chunks.0.embeddings: dense_field_embedding } - - - do: - update: - index: test-index - id: doc_1 - body: - doc: - non_inference_field: "another non inference test" - - - do: - get: - index: test-index - id: doc_1 - - - match: { _source.sparse_field.text: "inference test" } - - match: { _source.sparse_field.inference.chunks.0.text: "inference test" } - - match: { _source.sparse_field.inference.chunks.0.embeddings: $sparse_field_embedding } - - match: { _source.dense_field.text: "another inference test" } - - match: { _source.dense_field.inference.chunks.0.text: "another inference test" } - - match: { _source.dense_field.inference.chunks.0.embeddings: $dense_field_embedding } - - match: { _source.non_inference_field: "another non inference test" } - ---- -"Updating semantic_text fields recalculates embeddings": - - do: - index: - index: test-index - id: doc_1 - body: - sparse_field: "inference test" - dense_field: "another inference test" - non_inference_field: "non inference test" - - - do: - get: - index: test-index - id: doc_1 - - - match: { _source.sparse_field.text: "inference test" } - - match: { _source.sparse_field.inference.chunks.0.text: "inference test" } - - match: { _source.dense_field.text: "another inference test" } - - match: { _source.dense_field.inference.chunks.0.text: "another inference test" } - - match: { _source.non_inference_field: "non inference test" } - - - do: - bulk: - index: test-index - body: - - '{"update": {"_id": "doc_1"}}' - - '{"doc":{"sparse_field": "I am a test", "dense_field": "I am a teapot"}}' - - - do: - get: - index: test-index - id: doc_1 - - - match: { _source.sparse_field.text: "I am a test" } - - match: { _source.sparse_field.inference.chunks.0.text: "I am a test" } - - match: { _source.dense_field.text: "I am a teapot" } - - match: { _source.dense_field.inference.chunks.0.text: "I am a teapot" } - - match: { _source.non_inference_field: "non inference test" } - - - do: - update: - index: test-index - id: doc_1 - body: - doc: - sparse_field: "updated inference test" - dense_field: "another updated inference test" - - - do: - get: - index: test-index - id: doc_1 - - - match: { _source.sparse_field.text: "updated inference test" } - - match: { _source.sparse_field.inference.chunks.0.text: "updated inference test" } - - match: { _source.dense_field.text: "another updated inference test" } - - match: { _source.dense_field.inference.chunks.0.text: "another updated inference test" } - - match: { _source.non_inference_field: "non inference test" } - - - do: - bulk: - index: test-index - body: - - '{"update": {"_id": "doc_1"}}' - - '{"doc":{"sparse_field": "bulk inference test", "dense_field": "bulk updated inference test"}}' - - - do: - get: - index: test-index - id: doc_1 - - - match: { _source.sparse_field.text: "bulk inference test" } - - match: { _source.sparse_field.inference.chunks.0.text: "bulk inference test" } - - match: { _source.dense_field.text: "bulk updated inference test" } - - match: { _source.dense_field.inference.chunks.0.text: "bulk updated inference test" } - - match: { _source.non_inference_field: "non inference test" } - --- "Reindex works for semantic_text fields": - do: @@ -426,27 +307,7 @@ setup: non_inference_field: "non inference test" --- -"Updates with script are not allowed": - - do: - bulk: - index: test-index - body: - - '{"index": {"_id": "doc_1"}}' - - '{"doc":{"sparse_field": "I am a test", "dense_field": "I am a teapot"}}' - - - do: - bulk: - index: test-index - body: - - '{"update": {"_id": "doc_1"}}' - - '{"script": "ctx._source.new_field = \"hello\"", "scripted_upsert": true}' - - - match: { errors: true } - - match: { items.0.update.status: 400 } - - match: { items.0.update.error.reason: "Cannot apply update with a script on indices that contain [semantic_text] field(s)" } - ---- -"semantic_text copy_to calculate inference for source fields": +"semantic_text copy_to calculates embeddings for source fields": - do: indices.create: index: test-copy-to-index @@ -486,78 +347,8 @@ setup: - match: { _source.sparse_field.inference.chunks.2.text: "inference test" } - exists: _source.sparse_field.inference.chunks.2.embeddings - --- -"semantic_text copy_to needs values for every source field for updates": - - do: - indices.create: - index: test-copy-to-index - body: - mappings: - properties: - sparse_field: - type: semantic_text - inference_id: sparse-inference-id - source_field: - type: text - copy_to: sparse_field - another_source_field: - type: text - copy_to: sparse_field - - # Not every source field needed on creation - - do: - index: - index: test-copy-to-index - id: doc_1 - body: - source_field: "a single source field provided" - sparse_field: "inference test" - - # Every source field needed on bulk updates - - do: - bulk: - body: - - '{"update": {"_index": "test-copy-to-index", "_id": "doc_1"}}' - - '{"doc": {"source_field": "a single source field is kept as provided via bulk", "sparse_field": "updated inference test" }}' - - - match: { items.0.update.status: 400 } - - match: { items.0.update.error.reason: "Field [another_source_field] must be specified on an update request to calculate inference for field [sparse_field]" } - - ---- -"Update works for now - but will be unsupported later to avoid dealing with missing semantic_text fields content or copy_to fields": - - do: - index: - index: test-index - id: doc_1 - body: - sparse_field: "inference test" - dense_field: "another inference test" - non_inference_field: "non inference test" - - - do: - update: - index: test-index - id: doc_1 - body: - doc: { "sparse_field": "updated inference test", "dense_field": "another updated inference test", "non_inference_field": "updated non inference test" } - - - do: - get: - index: test-index - id: doc_1 - - - match: { _source.sparse_field.text: "updated inference test" } - - exists: _source.sparse_field.inference.chunks.0.embeddings - - match: { _source.sparse_field.inference.chunks.0.text: "updated inference test" } - - match: { _source.dense_field.text: "another updated inference test" } - - exists: _source.dense_field.inference.chunks.0.embeddings - - match: { _source.dense_field.inference.chunks.0.text: "another updated inference test" } - - match: { _source.non_inference_field: "updated non inference test" } - ---- -"Calculates text expansion results for bulk updates - index": +"Calculates embeddings for bulk operations - index": - do: bulk: body: @@ -580,108 +371,6 @@ setup: - match: { _source.dense_field.inference.chunks.0.text: "another inference test" } - match: { _source.non_inference_field: "non inference test" } ---- -"Calculates text expansion results for bulk updates - update": - - do: - bulk: - body: - - '{"index": {"_index": "test-index", "_id": "doc_1"}}' - - '{"sparse_field": "inference test", "dense_field": "another inference test", "non_inference_field": "non inference test"}' - - - match: { errors: false } - - match: { items.0.index.result: "created" } - - - do: - bulk: - body: - - '{"update": {"_index": "test-index", "_id": "doc_1"}}' - - '{"doc": { "sparse_field": "updated inference test", "dense_field": "another updated inference test", "non_inference_field": "updated non inference test" }}' - - - match: { errors: false } - - match: { items.0.update.result: "updated" } - - - do: - get: - index: test-index - id: doc_1 - - - match: { _source.sparse_field.text: "updated inference test" } - - exists: _source.sparse_field.inference.chunks.0.embeddings - - match: { _source.sparse_field.inference.chunks.0.text: "updated inference test" } - - match: { _source.dense_field.text: "another updated inference test" } - - exists: _source.dense_field.inference.chunks.0.embeddings - - match: { _source.dense_field.inference.chunks.0.text: "another updated inference test" } - - match: { _source.non_inference_field: "updated non inference test" } - - # Script update not supported - - do: - bulk: - body: - - '{"update": {"_index": "test-index", "_id": "doc_1"}}' - - '{"script": {"source": {"ctx.sparse_field": "updated inference test"}}}' - - - match: { errors: true } - - match: { items.0.update.status: 400 } - - match: { items.0.update.error.reason: "Cannot apply update with a script on indices that contain [semantic_text] field(s)" } - ---- -"Calculates text expansion results for bulk updates - upsert": - # Initial update fails - - do: - bulk: - body: - - '{"update": {"_index": "test-index", "_id": "doc_1"}}' - - '{"doc": { "sparse_field": "inference test", "dense_field": "another inference test", "non_inference_field": "non inference test" }}' - - - match: { errors: true } - - match: { items.0.update.status: 404 } - - # Update as upsert - - do: - bulk: - body: - - '{"update": {"_index": "test-index", "_id": "doc_1"}}' - - '{"doc": { "sparse_field": "inference test", "dense_field": "another inference test", "non_inference_field": "non inference test" }, "doc_as_upsert": true}' - - - match: { errors: false } - - match: { items.0.update.result: "created" } - - - do: - get: - index: test-index - id: doc_1 - - - match: { _source.sparse_field.text: "inference test" } - - exists: _source.sparse_field.inference.chunks.0.embeddings - - match: { _source.sparse_field.inference.chunks.0.text: "inference test" } - - match: { _source.dense_field.text: "another inference test" } - - exists: _source.dense_field.inference.chunks.0.embeddings - - match: { _source.dense_field.inference.chunks.0.text: "another inference test" } - - match: { _source.non_inference_field: "non inference test" } - - - do: - bulk: - body: - - '{"update": {"_index": "test-index", "_id": "doc_1"}}' - - '{"doc": { "sparse_field": "updated inference test", "dense_field": "another updated inference test", "non_inference_field": "updated non inference test" }, "doc_as_upsert": true}' - - - match: { errors: false } - - match: { items.0.update.result: "updated" } - - - do: - get: - index: test-index - id: doc_1 - - - match: { _source.sparse_field.text: "updated inference test" } - - exists: _source.sparse_field.inference.chunks.0.embeddings - - match: { _source.sparse_field.inference.chunks.0.text: "updated inference test" } - - match: { _source.dense_field.text: "another updated inference test" } - - exists: _source.dense_field.inference.chunks.0.embeddings - - match: { _source.dense_field.inference.chunks.0.text: "another updated inference test" } - - match: { _source.non_inference_field: "updated non inference test" } - - --- "Update by query picks up new semantic_text fields": diff --git a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/60_semantic_text_inference_update.yml b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/60_semantic_text_inference_update.yml new file mode 100644 index 0000000000000..59ce439d954a2 --- /dev/null +++ b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/60_semantic_text_inference_update.yml @@ -0,0 +1,612 @@ +setup: + - requires: + cluster_features: "gte_v8.15.0" + reason: semantic_text introduced in 8.15.0 + + - do: + inference.put: + task_type: sparse_embedding + inference_id: sparse-inference-id + body: > + { + "service": "test_service", + "service_settings": { + "model": "my_model", + "api_key": "abc64" + }, + "task_settings": { + } + } + + - do: + inference.put: + task_type: text_embedding + inference_id: dense-inference-id + body: > + { + "service": "text_embedding_test_service", + "service_settings": { + "model": "my_model", + "dimensions": 10, + "similarity": "cosine", + "api_key": "abc64" + }, + "task_settings": { + } + } + + - do: + indices.create: + index: test-index + body: + mappings: + properties: + sparse_field: + type: semantic_text + inference_id: sparse-inference-id + dense_field: + type: semantic_text + inference_id: dense-inference-id + non_inference_field: + type: text + +--- +"Updating non semantic_text fields does not recalculate embeddings": + - do: + index: + index: test-index + id: doc_1 + body: + sparse_field: "inference test" + dense_field: "another inference test" + non_inference_field: "non inference test" + + - do: + get: + index: test-index + id: doc_1 + + - set: { _source.sparse_field.inference.chunks.0.embeddings: sparse_field_embedding } + - set: { _source.dense_field.inference.chunks.0.embeddings: dense_field_embedding } + + - do: + update: + index: test-index + id: doc_1 + body: + doc: + non_inference_field: "another non inference test" + + - do: + get: + index: test-index + id: doc_1 + + - match: { _source.sparse_field.text: "inference test" } + - match: { _source.sparse_field.inference.chunks.0.text: "inference test" } + - match: { _source.sparse_field.inference.chunks.0.embeddings: $sparse_field_embedding } + - match: { _source.dense_field.text: "another inference test" } + - match: { _source.dense_field.inference.chunks.0.text: "another inference test" } + - match: { _source.dense_field.inference.chunks.0.embeddings: $dense_field_embedding } + - match: { _source.non_inference_field: "another non inference test" } + +--- +"Updating semantic_text fields recalculates embeddings": + - do: + index: + index: test-index + id: doc_1 + body: + sparse_field: "inference test" + dense_field: "another inference test" + non_inference_field: "non inference test" + + - do: + get: + index: test-index + id: doc_1 + + - match: { _source.sparse_field.text: "inference test" } + - match: { _source.sparse_field.inference.chunks.0.text: "inference test" } + - match: { _source.dense_field.text: "another inference test" } + - match: { _source.dense_field.inference.chunks.0.text: "another inference test" } + - match: { _source.non_inference_field: "non inference test" } + + - do: + bulk: + index: test-index + body: + - '{"update": {"_id": "doc_1"}}' + - '{"doc":{"sparse_field": "I am a test", "dense_field": "I am a teapot"}}' + + - do: + get: + index: test-index + id: doc_1 + + - match: { _source.sparse_field.text: "I am a test" } + - match: { _source.sparse_field.inference.chunks.0.text: "I am a test" } + - match: { _source.dense_field.text: "I am a teapot" } + - match: { _source.dense_field.inference.chunks.0.text: "I am a teapot" } + - match: { _source.non_inference_field: "non inference test" } + + - do: + update: + index: test-index + id: doc_1 + body: + doc: + sparse_field: "updated inference test" + dense_field: "another updated inference test" + + - do: + get: + index: test-index + id: doc_1 + + - match: { _source.sparse_field.text: "updated inference test" } + - match: { _source.sparse_field.inference.chunks.0.text: "updated inference test" } + - match: { _source.dense_field.text: "another updated inference test" } + - match: { _source.dense_field.inference.chunks.0.text: "another updated inference test" } + - match: { _source.non_inference_field: "non inference test" } + + - do: + bulk: + index: test-index + body: + - '{"update": {"_id": "doc_1"}}' + - '{"doc":{"sparse_field": "bulk inference test", "dense_field": "bulk updated inference test"}}' + + - do: + get: + index: test-index + id: doc_1 + + - match: { _source.sparse_field.text: "bulk inference test" } + - match: { _source.sparse_field.inference.chunks.0.text: "bulk inference test" } + - match: { _source.dense_field.text: "bulk updated inference test" } + - match: { _source.dense_field.inference.chunks.0.text: "bulk updated inference test" } + - match: { _source.non_inference_field: "non inference test" } + +--- +"Update logic handles source fields in object fields": + - do: + indices.create: + index: test-copy-to-index + body: + mappings: + properties: + sparse_field: + type: semantic_text + inference_id: sparse-inference-id + dense_field: + type: semantic_text + inference_id: dense-inference-id + object_source: + properties: + sparse_field: + type: text + copy_to: sparse_field + dense_field: + type: text + copy_to: dense_field + + - do: + index: + index: test-copy-to-index + id: doc_1 + body: + sparse_field: "sparse data 1" + dense_field: "dense data 1" + + - do: + get: + index: test-copy-to-index + id: doc_1 + + - match: { _source.sparse_field.text: "sparse data 1" } + - length: { _source.sparse_field.inference.chunks: 1 } + - match: { _source.sparse_field.inference.chunks.0.text: "sparse data 1" } + - match: { _source.dense_field.text: "dense data 1" } + - length: { _source.dense_field.inference.chunks: 1 } + - match: { _source.dense_field.inference.chunks.0.text: "dense data 1" } + + - do: + bulk: + index: test-copy-to-index + body: + - '{"update": {"_id": "doc_1"}}' + - > + { + "doc": { + "sparse_field": "sparse data 1", + "object_source.sparse_field": "sparse data 2", + "dense_field": "dense data 1", + "object_source.dense_field": "dense data 2" + } + } + + - do: + get: + index: test-copy-to-index + id: doc_1 + + - match: { _source.sparse_field.text: "sparse data 1" } + - length: { _source.sparse_field.inference.chunks: 2 } + - match: { _source.sparse_field.inference.chunks.0.text: "sparse data 2" } + - match: { _source.sparse_field.inference.chunks.1.text: "sparse data 1" } + - match: { _source.dense_field.text: "dense data 1" } + - length: { _source.dense_field.inference.chunks: 2 } + - match: { _source.dense_field.inference.chunks.0.text: "dense data 1" } + - match: { _source.dense_field.inference.chunks.1.text: "dense data 2" } + + - do: + update: + index: test-copy-to-index + id: doc_1 + body: + doc: + { + "sparse_field": "sparse data 1", + "object_source.sparse_field": "sparse data 3", + "dense_field": "dense data 1", + "object_source.dense_field": "dense data 3" + } + + - do: + get: + index: test-copy-to-index + id: doc_1 + + - match: { _source.sparse_field.text: "sparse data 1" } + - length: { _source.sparse_field.inference.chunks: 2 } + - match: { _source.sparse_field.inference.chunks.0.text: "sparse data 3" } + - match: { _source.sparse_field.inference.chunks.1.text: "sparse data 1" } + - match: { _source.dense_field.text: "dense data 1" } + - length: { _source.dense_field.inference.chunks: 2 } + - match: { _source.dense_field.inference.chunks.0.text: "dense data 1" } + - match: { _source.dense_field.inference.chunks.1.text: "dense data 3" } + +--- +"Updates fail when the updated value is invalid": + - do: + index: + index: test-index + id: doc_1 + body: + sparse_field: "inference test" + dense_field: "another inference test" + non_inference_field: "non inference test" + + - do: + get: + index: test-index + id: doc_1 + + - match: { _source.sparse_field.text: "inference test" } + - match: { _source.sparse_field.inference.chunks.0.text: "inference test" } + - match: { _source.dense_field.text: "another inference test" } + - match: { _source.dense_field.inference.chunks.0.text: "another inference test" } + - match: { _source.non_inference_field: "non inference test" } + + - do: + bulk: + index: test-index + body: + - '{"update": {"_id": "doc_1"}}' + - '{"doc":{"sparse_field": [{"key": "value"}], "dense_field": [{"key": "value"}]}}' + + - match: { errors: true } + - match: { items.0.update.status: 400 } + - match: { items.0.update.error.reason: "/Invalid\\ format\\ for\\ field\\ \\[(dense|sparse)_field\\].+/" } + + - do: + catch: bad_request + update: + index: test-index + id: doc_1 + body: + doc: { "sparse_field": [{"key": "value"}], "dense_field": [{"key": "value"}] } + + - match: { error.type: "status_exception" } + - match: { error.reason: "/Invalid\\ format\\ for\\ field\\ \\[(dense|sparse)_field\\].+/" } + +--- +"Partial updates work when using the update API": + - do: + indices.create: + index: test-copy-to-index + body: + mappings: + properties: + sparse_field: + type: semantic_text + inference_id: sparse-inference-id + sparse_source_field: + type: text + copy_to: sparse_field + dense_field: + type: semantic_text + inference_id: dense-inference-id + dense_source_field: + type: text + copy_to: dense_field + + - do: + index: + index: test-copy-to-index + id: doc_1 + body: + sparse_field: "sparse data 1" + sparse_source_field: "sparse data 2" + dense_field: "dense data 1" + dense_source_field: "dense data 2" + + - do: + get: + index: test-copy-to-index + id: doc_1 + + - length: { _source.sparse_field.inference.chunks: 2 } + - match: { _source.sparse_field.inference.chunks.1.text: "sparse data 2" } + - exists: _source.sparse_field.inference.chunks.1.embeddings + - length: { _source.dense_field.inference.chunks: 2 } + - match: { _source.dense_field.inference.chunks.1.text: "dense data 2" } + - exists: _source.dense_field.inference.chunks.1.embeddings + + - do: + update: + index: test-copy-to-index + id: doc_1 + body: + doc: { "sparse_source_field": "sparse data 3", "dense_source_field": "dense data 3" } + + - do: + get: + index: test-copy-to-index + id: doc_1 + + - match: { _source.sparse_field.text: "sparse data 1" } + - length: { _source.sparse_field.inference.chunks: 2 } + - match: { _source.sparse_field.inference.chunks.1.text: "sparse data 3" } + - exists: _source.sparse_field.inference.chunks.1.embeddings + - match: { _source.dense_field.text: "dense data 1" } + - length: { _source.dense_field.inference.chunks: 2 } + - match: { _source.dense_field.inference.chunks.1.text: "dense data 3" } + - exists: _source.dense_field.inference.chunks.1.embeddings + +--- +"Partial updates work when using the update API and the semantic_text field's original value is null": + - do: + indices.create: + index: test-copy-to-index + body: + mappings: + properties: + sparse_field: + type: semantic_text + inference_id: sparse-inference-id + sparse_source_field: + type: text + copy_to: sparse_field + dense_field: + type: semantic_text + inference_id: dense-inference-id + dense_source_field: + type: text + copy_to: dense_field + + # Don't set sparse_field or dense_field so their original value is null + - do: + index: + index: test-copy-to-index + id: doc_1 + body: + sparse_source_field: "sparse data 2" + dense_source_field: "dense data 2" + + - do: + get: + index: test-copy-to-index + id: doc_1 + + - match: { _source.sparse_field.text: null } + - length: { _source.sparse_field.inference.chunks: 1 } + - match: { _source.sparse_field.inference.chunks.0.text: "sparse data 2" } + - exists: _source.sparse_field.inference.chunks.0.embeddings + - match: { _source.dense_field.text: null } + - length: { _source.dense_field.inference.chunks: 1 } + - match: { _source.dense_field.inference.chunks.0.text: "dense data 2" } + - exists: _source.dense_field.inference.chunks.0.embeddings + + - do: + update: + index: test-copy-to-index + id: doc_1 + body: + doc: { "sparse_source_field": "sparse data 3", "dense_source_field": "dense data 3" } + + - do: + get: + index: test-copy-to-index + id: doc_1 + + - match: { _source.sparse_field.text: null } + - length: { _source.sparse_field.inference.chunks: 1 } + - match: { _source.sparse_field.inference.chunks.0.text: "sparse data 3" } + - exists: _source.sparse_field.inference.chunks.0.embeddings + - match: { _source.dense_field.text: null } + - length: { _source.dense_field.inference.chunks: 1 } + - match: { _source.dense_field.inference.chunks.0.text: "dense data 3" } + - exists: _source.dense_field.inference.chunks.0.embeddings + +--- +"Updates with script are not allowed": + - do: + bulk: + index: test-index + body: + - '{"index": {"_id": "doc_1"}}' + - '{"doc":{"sparse_field": "I am a test", "dense_field": "I am a teapot"}}' + + - do: + bulk: + index: test-index + body: + - '{"update": {"_id": "doc_1"}}' + - '{"script": "ctx._source.new_field = \"hello\"", "scripted_upsert": true}' + + - match: { errors: true } + - match: { items.0.update.status: 400 } + - match: { items.0.update.error.reason: "Cannot apply update with a script on indices that contain [semantic_text] field(s)" } + + - do: + catch: bad_request + update: + index: test-index + id: doc_1 + body: + script: + source: "ctx._source.new_field = \"hello\"" + lang: "painless" + + - match: { error.type: "status_exception" } + - match: { error.reason: "Cannot apply update with a script on indices that contain inference field(s)" } + +--- +"semantic_text copy_to needs values for every source field for bulk updates": + - do: + indices.create: + index: test-copy-to-index + body: + mappings: + properties: + sparse_field: + type: semantic_text + inference_id: sparse-inference-id + source_field: + type: text + copy_to: sparse_field + another_source_field: + type: text + copy_to: sparse_field + + # Not every source field needed on creation + - do: + index: + index: test-copy-to-index + id: doc_1 + body: + source_field: "a single source field provided" + sparse_field: "inference test" + + # Every source field needed on bulk updates + - do: + bulk: + body: + - '{"update": {"_index": "test-copy-to-index", "_id": "doc_1"}}' + - '{"doc": {"source_field": "a single source field is kept as provided via bulk", "sparse_field": "updated inference test" }}' + + - match: { items.0.update.status: 400 } + - match: { items.0.update.error.reason: "Field [another_source_field] must be specified on an update request to calculate inference for field [sparse_field]" } + +--- +"Calculates embeddings for bulk operations - update": + - do: + bulk: + body: + - '{"index": {"_index": "test-index", "_id": "doc_1"}}' + - '{"sparse_field": "inference test", "dense_field": "another inference test", "non_inference_field": "non inference test"}' + + - match: { errors: false } + - match: { items.0.index.result: "created" } + + - do: + bulk: + body: + - '{"update": {"_index": "test-index", "_id": "doc_1"}}' + - '{"doc": { "sparse_field": "updated inference test", "dense_field": "another updated inference test", "non_inference_field": "updated non inference test" }}' + + - match: { errors: false } + - match: { items.0.update.result: "updated" } + + - do: + get: + index: test-index + id: doc_1 + + - match: { _source.sparse_field.text: "updated inference test" } + - exists: _source.sparse_field.inference.chunks.0.embeddings + - match: { _source.sparse_field.inference.chunks.0.text: "updated inference test" } + - match: { _source.dense_field.text: "another updated inference test" } + - exists: _source.dense_field.inference.chunks.0.embeddings + - match: { _source.dense_field.inference.chunks.0.text: "another updated inference test" } + - match: { _source.non_inference_field: "updated non inference test" } + + # Script update not supported + - do: + bulk: + body: + - '{"update": {"_index": "test-index", "_id": "doc_1"}}' + - '{"script": {"source": {"ctx.sparse_field": "updated inference test"}}}' + + - match: { errors: true } + - match: { items.0.update.status: 400 } + - match: { items.0.update.error.reason: "Cannot apply update with a script on indices that contain [semantic_text] field(s)" } + +--- +"Calculates embeddings for bulk operations - upsert": + # Initial update fails + - do: + bulk: + body: + - '{"update": {"_index": "test-index", "_id": "doc_1"}}' + - '{"doc": { "sparse_field": "inference test", "dense_field": "another inference test", "non_inference_field": "non inference test" }}' + + - match: { errors: true } + - match: { items.0.update.status: 404 } + + # Update as upsert + - do: + bulk: + body: + - '{"update": {"_index": "test-index", "_id": "doc_1"}}' + - '{"doc": { "sparse_field": "inference test", "dense_field": "another inference test", "non_inference_field": "non inference test" }, "doc_as_upsert": true}' + + - match: { errors: false } + - match: { items.0.update.result: "created" } + + - do: + get: + index: test-index + id: doc_1 + + - match: { _source.sparse_field.text: "inference test" } + - exists: _source.sparse_field.inference.chunks.0.embeddings + - match: { _source.sparse_field.inference.chunks.0.text: "inference test" } + - match: { _source.dense_field.text: "another inference test" } + - exists: _source.dense_field.inference.chunks.0.embeddings + - match: { _source.dense_field.inference.chunks.0.text: "another inference test" } + - match: { _source.non_inference_field: "non inference test" } + + - do: + bulk: + body: + - '{"update": {"_index": "test-index", "_id": "doc_1"}}' + - '{"doc": { "sparse_field": "updated inference test", "dense_field": "another updated inference test", "non_inference_field": "updated non inference test" }, "doc_as_upsert": true}' + + - match: { errors: false } + - match: { items.0.update.result: "updated" } + + - do: + get: + index: test-index + id: doc_1 + + - match: { _source.sparse_field.text: "updated inference test" } + - exists: _source.sparse_field.inference.chunks.0.embeddings + - match: { _source.sparse_field.inference.chunks.0.text: "updated inference test" } + - match: { _source.dense_field.text: "another updated inference test" } + - exists: _source.dense_field.inference.chunks.0.embeddings + - match: { _source.dense_field.inference.chunks.0.text: "another updated inference test" } + - match: { _source.non_inference_field: "updated non inference test" } From f73fedc52ad87d961213045945f0d3f9383f3124 Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 28 May 2024 21:40:00 +0100 Subject: [PATCH 019/208] Fix trappy timeouts in ILM (#109112) Relates #107984 --- .../existence/FrozenExistenceDeciderIT.java | 2 +- .../xpack/core/ilm/StartILMRequest.java | 6 +- .../xpack/core/ilm/StopILMRequest.java | 6 +- .../ilm/action/DeleteLifecycleAction.java | 14 ++-- .../core/ilm/action/GetLifecycleAction.java | 10 +-- .../core/ilm/action/PutLifecycleRequest.java | 32 +++++---- .../RemoveIndexLifecyclePolicyAction.java | 9 +-- .../core/template/IndexTemplateRegistry.java | 4 +- .../xpack/core/ilm/StartILMRequestTests.java | 2 +- .../xpack/core/ilm/StopILMRequestTests.java | 2 +- .../action/DeleteLifecycleRequestTests.java | 4 +- .../ilm/action/GetLifecycleRequestTests.java | 4 +- .../ilm/action/PutLifecycleRequestTests.java | 20 +++++- ...emoveIndexLifecyclePolicyRequestTests.java | 9 ++- .../downsample/ILMDownsampleDisruptionIT.java | 2 +- .../ClusterStateWaitThresholdBreachTests.java | 2 +- ...ataStreamAndIndexLifecycleMixingTests.java | 10 +-- .../xpack/ilm/DataTiersMigrationsTests.java | 4 +- .../xpack/ilm/ILMMultiNodeIT.java | 2 +- .../ilm/ILMMultiNodeWithCCRDisabledIT.java | 2 +- .../IndexLifecycleInitialisationTests.java | 65 ++++++++++++------- .../ilm/action/ReservedLifecycleAction.java | 10 ++- .../ilm/action/RestDeleteLifecycleAction.java | 8 ++- .../ilm/action/RestGetLifecycleAction.java | 8 ++- .../ilm/action/RestPutLifecycleAction.java | 23 ++++--- .../RestRemoveIndexLifecyclePolicyAction.java | 8 ++- .../xpack/ilm/action/RestStartILMAction.java | 4 +- .../xpack/ilm/action/RestStopAction.java | 4 +- .../TransportDeleteLifecycleAction.java | 9 --- .../ilm/LifecycleOperationSnapshotTests.java | 4 +- .../TransportDeleteLifecycleActionTests.java | 6 +- .../TransportPutLifecycleActionTests.java | 12 +++- .../action/TransportStopILMActionTests.java | 2 +- 33 files changed, 183 insertions(+), 126 deletions(-) diff --git a/x-pack/plugin/autoscaling/src/internalClusterTest/java/org/elasticsearch/xpack/autoscaling/existence/FrozenExistenceDeciderIT.java b/x-pack/plugin/autoscaling/src/internalClusterTest/java/org/elasticsearch/xpack/autoscaling/existence/FrozenExistenceDeciderIT.java index c72d5e83d2bd3..3e729e9139c2b 100644 --- a/x-pack/plugin/autoscaling/src/internalClusterTest/java/org/elasticsearch/xpack/autoscaling/existence/FrozenExistenceDeciderIT.java +++ b/x-pack/plugin/autoscaling/src/internalClusterTest/java/org/elasticsearch/xpack/autoscaling/existence/FrozenExistenceDeciderIT.java @@ -99,7 +99,7 @@ public void testZeroToOne() throws Exception { singletonMap(SearchableSnapshotAction.NAME, new SearchableSnapshotAction(fsRepoName, randomBoolean())) ); LifecyclePolicy lifecyclePolicy = new LifecyclePolicy("policy", Map.of("hot", hotPhase, "frozen", frozenPhase)); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); Settings settings = Settings.builder() diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/StartILMRequest.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/StartILMRequest.java index c790d76746c1d..214803d2d7679 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/StartILMRequest.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/StartILMRequest.java @@ -9,6 +9,7 @@ import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; @@ -16,11 +17,10 @@ public class StartILMRequest extends AcknowledgedRequest { public StartILMRequest(StreamInput in) throws IOException { super(in); - } - public StartILMRequest() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public StartILMRequest(TimeValue masterNodeTimeout, TimeValue ackTimeout) { + super(masterNodeTimeout, ackTimeout); } @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/StopILMRequest.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/StopILMRequest.java index 82c6d8ba4800b..130795dd69d11 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/StopILMRequest.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/StopILMRequest.java @@ -9,6 +9,7 @@ import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; @@ -16,11 +17,10 @@ public class StopILMRequest extends AcknowledgedRequest { public StopILMRequest(StreamInput in) throws IOException { super(in); - } - public StopILMRequest() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public StopILMRequest(TimeValue masterNodeTimeout, TimeValue ackTimeout) { + super(masterNodeTimeout, ackTimeout); } @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/DeleteLifecycleAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/DeleteLifecycleAction.java index 01adb18caac7d..3a97954b1f2dd 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/DeleteLifecycleAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/DeleteLifecycleAction.java @@ -12,7 +12,7 @@ import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.xcontent.ParseField; +import org.elasticsearch.core.TimeValue; import java.io.IOException; import java.util.Objects; @@ -29,12 +29,10 @@ protected DeleteLifecycleAction() { public static class Request extends AcknowledgedRequest { - public static final ParseField POLICY_FIELD = new ParseField("policy"); + private final String policyName; - private String policyName; - - public Request(String policyName) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout, String policyName) { + super(masterNodeTimeout, ackTimeout); this.policyName = policyName; } @@ -43,10 +41,6 @@ public Request(StreamInput in) throws IOException { policyName = in.readString(); } - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); - } - public String getPolicyName() { return policyName; } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/GetLifecycleAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/GetLifecycleAction.java index d359498f33621..60042ab666c60 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/GetLifecycleAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/GetLifecycleAction.java @@ -17,6 +17,7 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.xcontent.ChunkedToXContentObject; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.tasks.CancellableTask; import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.TaskId; @@ -103,8 +104,8 @@ public Iterator toXContentChunked(ToXContent.Params outerParams) { public static class Request extends AcknowledgedRequest { private final String[] policyNames; - public Request(String... policyNames) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout, String... policyNames) { + super(masterNodeTimeout, ackTimeout); if (policyNames == null) { throw new IllegalArgumentException("ids cannot be null"); } @@ -116,11 +117,6 @@ public Request(StreamInput in) throws IOException { policyNames = in.readStringArray(); } - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); - policyNames = Strings.EMPTY_ARRAY; - } - @Override public Task createTask(long id, String type, String action, TaskId parentTaskId, Map headers) { return new CancellableTask(id, type, action, "get-lifecycle-task", parentTaskId, headers); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/PutLifecycleRequest.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/PutLifecycleRequest.java index ebaaf42246251..c955c30c163eb 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/PutLifecycleRequest.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/PutLifecycleRequest.java @@ -12,6 +12,7 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.ConstructingObjectParser; import org.elasticsearch.xcontent.ParseField; import org.elasticsearch.xcontent.ToXContentObject; @@ -25,20 +26,31 @@ public class PutLifecycleRequest extends AcknowledgedRequest implements ToXContentObject { + public interface Factory { + PutLifecycleRequest create(LifecyclePolicy lifecyclePolicy); + + String getPolicyName(); + } + public static final ParseField POLICY_FIELD = new ParseField("policy"); - private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( "put_lifecycle_request", - a -> new PutLifecycleRequest((LifecyclePolicy) a[0]) + false, + (a, factory) -> factory.create((LifecyclePolicy) a[0]) ); static { - PARSER.declareObject(ConstructingObjectParser.constructorArg(), LifecyclePolicy::parse, POLICY_FIELD); + PARSER.declareObject( + ConstructingObjectParser.constructorArg(), + (parser, factory) -> LifecyclePolicy.parse(parser, factory.getPolicyName()), + POLICY_FIELD + ); } - private LifecyclePolicy policy; + private final LifecyclePolicy policy; - public PutLifecycleRequest(LifecyclePolicy policy) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public PutLifecycleRequest(TimeValue masterNodeTimeout, TimeValue ackTimeout, LifecyclePolicy policy) { + super(masterNodeTimeout, ackTimeout); this.policy = policy; } @@ -47,10 +59,6 @@ public PutLifecycleRequest(StreamInput in) throws IOException { policy = new LifecyclePolicy(in); } - public PutLifecycleRequest() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); - } - public LifecyclePolicy getPolicy() { return policy; } @@ -71,8 +79,8 @@ public ActionRequestValidationException validate() { return err; } - public static PutLifecycleRequest parseRequest(String name, XContentParser parser) { - return PARSER.apply(parser, name); + public static PutLifecycleRequest parseRequest(Factory factory, XContentParser parser) { + return PARSER.apply(parser, factory); } @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/RemoveIndexLifecyclePolicyAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/RemoveIndexLifecyclePolicyAction.java index e45e4096e0a81..21ce966d17828 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/RemoveIndexLifecyclePolicyAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/action/RemoveIndexLifecyclePolicyAction.java @@ -14,6 +14,7 @@ import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.ConstructingObjectParser; import org.elasticsearch.xcontent.ParseField; import org.elasticsearch.xcontent.ToXContentObject; @@ -113,12 +114,8 @@ public Request(StreamInput in) throws IOException { indicesOptions = IndicesOptions.readIndicesOptions(in); } - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); - } - - public Request(String... indices) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout, String... indices) { + super(masterNodeTimeout, ackTimeout); if (indices == null) { throw new IllegalArgumentException("indices cannot be null"); } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/template/IndexTemplateRegistry.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/template/IndexTemplateRegistry.java index e189116b0179c..87092c45bf032 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/template/IndexTemplateRegistry.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/template/IndexTemplateRegistry.java @@ -76,6 +76,8 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener { private static final Logger logger = LogManager.getLogger(IndexTemplateRegistry.class); + private static final TimeValue REGISTRY_ACTION_TIMEOUT = TimeValue.THIRTY_SECONDS; // TODO should this be longer? + protected final Settings settings; protected final Client client; protected final ThreadPool threadPool; @@ -614,7 +616,7 @@ protected boolean isUpgradeRequired(LifecyclePolicy currentPolicy, LifecyclePoli private void putPolicy(final LifecyclePolicy policy, final AtomicBoolean creationCheck) { final Executor executor = threadPool.generic(); executor.execute(() -> { - PutLifecycleRequest request = new PutLifecycleRequest(policy); + PutLifecycleRequest request = new PutLifecycleRequest(REGISTRY_ACTION_TIMEOUT, REGISTRY_ACTION_TIMEOUT, policy); request.masterNodeTimeout(TimeValue.MAX_VALUE); executeAsyncWithOrigin( client.threadPool().getThreadContext(), diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/StartILMRequestTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/StartILMRequestTests.java index 308cb1a948916..f2252e53724aa 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/StartILMRequestTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/StartILMRequestTests.java @@ -14,7 +14,7 @@ public class StartILMRequestTests extends AbstractWireSerializingTestCase instanceReader() { @Override protected Request mutateInstance(Request request) { - return new Request(request.getPolicyName() + randomAlphaOfLengthBetween(1, 10)); + return new Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, request.getPolicyName() + randomAlphaOfLengthBetween(1, 10)); } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/action/GetLifecycleRequestTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/action/GetLifecycleRequestTests.java index 6aa55eb7f7a0a..fc963a7bc45e2 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/action/GetLifecycleRequestTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/action/GetLifecycleRequestTests.java @@ -16,7 +16,7 @@ public class GetLifecycleRequestTests extends AbstractWireSerializingTestCase instanceReader() { @Override protected PutLifecycleRequest doParseInstance(XContentParser parser) { - return PutLifecycleRequest.parseRequest(lifecycleName, parser); + return PutLifecycleRequest.parseRequest(new PutLifecycleRequest.Factory() { + @Override + public PutLifecycleRequest create(LifecyclePolicy lifecyclePolicy) { + return new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); + } + + @Override + public String getPolicyName() { + return lifecycleName; + } + }, parser); } @Override @@ -130,7 +144,7 @@ protected PutLifecycleRequest mutateInstance(PutLifecycleRequest request) { request.getPolicy(), () -> LifecyclePolicyTests.randomTimeseriesLifecyclePolicy(name) ); - return new PutLifecycleRequest(policy); + return new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policy); } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/action/RemoveIndexLifecyclePolicyRequestTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/action/RemoveIndexLifecyclePolicyRequestTests.java index 4bb58540a14e2..f998e15d0b798 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/action/RemoveIndexLifecyclePolicyRequestTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/action/RemoveIndexLifecyclePolicyRequestTests.java @@ -18,7 +18,7 @@ public class RemoveIndexLifecyclePolicyRequestTests extends AbstractWireSerializ @Override protected Request createTestInstance() { - Request request = new Request(generateRandomStringArray(20, 20, false)); + Request request = new Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, generateRandomStringArray(20, 20, false)); if (randomBoolean()) { IndicesOptions indicesOptions = IndicesOptions.fromOptions( randomBoolean(), @@ -67,13 +67,16 @@ protected Request mutateInstance(Request instance) { ); default -> throw new AssertionError("Illegal randomisation branch"); } - Request newRequest = new Request(indices); + Request newRequest = new Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, indices); newRequest.indicesOptions(indicesOptions); return newRequest; } public void testNullIndices() { - IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new Request((String[]) null)); + IllegalArgumentException exception = expectThrows( + IllegalArgumentException.class, + () -> new Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, (String[]) null) + ); assertEquals("indices cannot be null", exception.getMessage()); } diff --git a/x-pack/plugin/downsample/src/internalClusterTest/java/org/elasticsearch/xpack/downsample/ILMDownsampleDisruptionIT.java b/x-pack/plugin/downsample/src/internalClusterTest/java/org/elasticsearch/xpack/downsample/ILMDownsampleDisruptionIT.java index e4091af0fedf2..8a0d9edae4993 100644 --- a/x-pack/plugin/downsample/src/internalClusterTest/java/org/elasticsearch/xpack/downsample/ILMDownsampleDisruptionIT.java +++ b/x-pack/plugin/downsample/src/internalClusterTest/java/org/elasticsearch/xpack/downsample/ILMDownsampleDisruptionIT.java @@ -136,7 +136,7 @@ public void setup(final String sourceIndex, int numOfShards, int numOfReplicas, ) ); LifecyclePolicy policy = new LifecyclePolicy(POLICY_NAME, phases); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(policy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).actionGet()); } diff --git a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ClusterStateWaitThresholdBreachTests.java b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ClusterStateWaitThresholdBreachTests.java index 7602a2cd16e78..55daa8104c12a 100644 --- a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ClusterStateWaitThresholdBreachTests.java +++ b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ClusterStateWaitThresholdBreachTests.java @@ -91,7 +91,7 @@ public void testWaitInShrunkShardsAllocatedExceedsThreshold() throws Exception { Map.of(MigrateAction.NAME, MigrateAction.DISABLED, ShrinkAction.NAME, new ShrinkAction(1, null, false)) ); LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, Map.of("warm", warmPhase)); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); // we're configuring a very high number of replicas. this will make ths shrunk index unable to allocate successfully, so ILM will diff --git a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/DataStreamAndIndexLifecycleMixingTests.java b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/DataStreamAndIndexLifecycleMixingTests.java index 7278b0e6c7f49..6d6f292d112f9 100644 --- a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/DataStreamAndIndexLifecycleMixingTests.java +++ b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/DataStreamAndIndexLifecycleMixingTests.java @@ -107,7 +107,7 @@ public void testIndexTemplateSwapsILMForDataStreamLifecycle() throws Exception { RolloverAction rolloverIlmAction = new RolloverAction(RolloverConditions.newBuilder().addMaxIndexDocsCondition(2L).build()); Phase hotPhase = new Phase("hot", TimeValue.ZERO, Map.of(rolloverIlmAction.getWriteableName(), rolloverIlmAction)); LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, Map.of("hot", hotPhase)); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); putComposableIndexTemplate( @@ -289,7 +289,7 @@ public void testUpdateIndexTemplateFromILMtoBothILMAndDataStreamLifecycle() thro RolloverAction rolloverIlmAction = new RolloverAction(RolloverConditions.newBuilder().addMaxIndexDocsCondition(2L).build()); Phase hotPhase = new Phase("hot", TimeValue.ZERO, Map.of(rolloverIlmAction.getWriteableName(), rolloverIlmAction)); LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, Map.of("hot", hotPhase)); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); putComposableIndexTemplate( @@ -464,7 +464,7 @@ public void testUpdateIndexTemplateToDataStreamLifecyclePreference() throws Exce RolloverAction rolloverIlmAction = new RolloverAction(RolloverConditions.newBuilder().addMaxIndexDocsCondition(2L).build()); Phase hotPhase = new Phase("hot", TimeValue.ZERO, Map.of(rolloverIlmAction.getWriteableName(), rolloverIlmAction)); LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, Map.of("hot", hotPhase)); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); putComposableIndexTemplate( @@ -718,7 +718,7 @@ public void testUpdateIndexTemplateToMigrateFromDataStreamLifecycleToIlm() throw RolloverAction rolloverIlmAction = new RolloverAction(RolloverConditions.newBuilder().addMaxIndexDocsCondition(2L).build()); Phase hotPhase = new Phase("hot", TimeValue.ZERO, Map.of(rolloverIlmAction.getWriteableName(), rolloverIlmAction)); LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, Map.of("hot", hotPhase)); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); // let's update the index template to remove the data stream lifecycle configuration and replace it with an ILM configuration @@ -813,7 +813,7 @@ public void testGetDataStreamResponse() throws Exception { RolloverAction rolloverIlmAction = new RolloverAction(RolloverConditions.newBuilder().addMaxIndexDocsCondition(2L).build()); Phase hotPhase = new Phase("hot", TimeValue.ZERO, Map.of(rolloverIlmAction.getWriteableName(), rolloverIlmAction)); LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, Map.of("hot", hotPhase)); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); putComposableIndexTemplate( diff --git a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/DataTiersMigrationsTests.java b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/DataTiersMigrationsTests.java index bf5ab23823614..01288b4135d15 100644 --- a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/DataTiersMigrationsTests.java +++ b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/DataTiersMigrationsTests.java @@ -105,7 +105,7 @@ public void testIndexDataTierMigration() throws Exception { Phase warmPhase = new Phase("warm", TimeValue.ZERO, Collections.emptyMap()); Phase coldPhase = new Phase("cold", TimeValue.ZERO, Collections.emptyMap()); LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, Map.of("hot", hotPhase, "warm", warmPhase, "cold", coldPhase)); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); Settings settings = Settings.builder() @@ -166,7 +166,7 @@ public void testUserOptsOutOfTierMigration() throws Exception { Phase warmPhase = new Phase("warm", TimeValue.ZERO, Collections.emptyMap()); Phase coldPhase = new Phase("cold", TimeValue.ZERO, Collections.emptyMap()); LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, Map.of("hot", hotPhase, "warm", warmPhase, "cold", coldPhase)); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); Settings settings = Settings.builder() diff --git a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ILMMultiNodeIT.java b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ILMMultiNodeIT.java index 46c47869d8651..b443c769407c5 100644 --- a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ILMMultiNodeIT.java +++ b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ILMMultiNodeIT.java @@ -76,7 +76,7 @@ public void testShrinkOnTiers() throws Exception { phases.put(hotPhase.getName(), hotPhase); phases.put(warmPhase.getName(), warmPhase); LifecyclePolicy lifecyclePolicy = new LifecyclePolicy("shrink-policy", phases); - client().execute(ILMActions.PUT, new PutLifecycleRequest(lifecyclePolicy)).get(); + client().execute(ILMActions.PUT, new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy)).get(); Template t = new Template( Settings.builder() diff --git a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ILMMultiNodeWithCCRDisabledIT.java b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ILMMultiNodeWithCCRDisabledIT.java index 07c82f3dcfe98..e02dd5fe45676 100644 --- a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ILMMultiNodeWithCCRDisabledIT.java +++ b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ILMMultiNodeWithCCRDisabledIT.java @@ -76,7 +76,7 @@ public void testShrinkOnTiers() throws Exception { Phase hotPhase = new Phase("hot", TimeValue.ZERO, actions); LifecyclePolicy lifecyclePolicy = new LifecyclePolicy("shrink-policy", Collections.singletonMap(hotPhase.getName(), hotPhase)); - client().execute(ILMActions.PUT, new PutLifecycleRequest(lifecyclePolicy)).get(); + client().execute(ILMActions.PUT, new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy)).get(); Template t = new Template( Settings.builder() diff --git a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/IndexLifecycleInitialisationTests.java b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/IndexLifecycleInitialisationTests.java index 209330a3be2de..3530f33704beb 100644 --- a/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/IndexLifecycleInitialisationTests.java +++ b/x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/IndexLifecycleInitialisationTests.java @@ -144,24 +144,29 @@ public void testSingleNodeCluster() throws Exception { // test get-lifecycle behavior when IndexLifecycleMetadata is null GetLifecycleAction.Response getUninitializedLifecycleResponse = client().execute( GetLifecycleAction.INSTANCE, - new GetLifecycleAction.Request() + new GetLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) ).get(); assertThat(getUninitializedLifecycleResponse.getPolicies().size(), equalTo(0)); ExecutionException exception = expectThrows( ExecutionException.class, - () -> client().execute(GetLifecycleAction.INSTANCE, new GetLifecycleAction.Request("non-existent-policy")).get() + () -> client().execute( + GetLifecycleAction.INSTANCE, + new GetLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "non-existent-policy") + ).get() ); assertThat(exception.getMessage(), containsString("Lifecycle policy not found: [non-existent-policy]")); logger.info("Creating lifecycle [test_lifecycle]"); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); long lowerBoundModifiedDate = Instant.now().toEpochMilli(); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); long upperBoundModifiedDate = Instant.now().toEpochMilli(); // assert version and modified_date - GetLifecycleAction.Response getLifecycleResponse = client().execute(GetLifecycleAction.INSTANCE, new GetLifecycleAction.Request()) - .get(); + GetLifecycleAction.Response getLifecycleResponse = client().execute( + GetLifecycleAction.INSTANCE, + new GetLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get(); assertThat(getLifecycleResponse.getPolicies().size(), equalTo(1)); GetLifecycleAction.LifecyclePolicyResponseItem responseItem = getLifecycleResponse.getPolicies().get(0); assertThat(responseItem.getLifecyclePolicy(), equalTo(lifecyclePolicy)); @@ -199,21 +204,26 @@ public void testNoOpPolicyUpdates() throws Exception { phases.put("hot", new Phase("hot", TimeValue.ZERO, Map.of())); LifecyclePolicy policy = new LifecyclePolicy("mypolicy", phases); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(policy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); - GetLifecycleAction.Response getLifecycleResponse = client().execute(GetLifecycleAction.INSTANCE, new GetLifecycleAction.Request()) - .get(); + GetLifecycleAction.Response getLifecycleResponse = client().execute( + GetLifecycleAction.INSTANCE, + new GetLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get(); assertThat(getLifecycleResponse.getPolicies().size(), equalTo(1)); GetLifecycleAction.LifecyclePolicyResponseItem responseItem = getLifecycleResponse.getPolicies().get(0); assertThat(responseItem.getLifecyclePolicy(), equalTo(policy)); assertThat(responseItem.getVersion(), equalTo(1L)); // Put the same policy in place, which should be a no-op - putLifecycleRequest = new PutLifecycleRequest(policy); + putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); - getLifecycleResponse = client().execute(GetLifecycleAction.INSTANCE, new GetLifecycleAction.Request()).get(); + getLifecycleResponse = client().execute( + GetLifecycleAction.INSTANCE, + new GetLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get(); assertThat(getLifecycleResponse.getPolicies().size(), equalTo(1)); responseItem = getLifecycleResponse.getPolicies().get(0); assertThat(responseItem.getLifecyclePolicy(), equalTo(policy)); @@ -225,10 +235,13 @@ public void testNoOpPolicyUpdates() throws Exception { newPhases.put("cold", new Phase("cold", TimeValue.timeValueDays(1), Map.of())); policy = new LifecyclePolicy("mypolicy", newPhases); - putLifecycleRequest = new PutLifecycleRequest(policy); + putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); - getLifecycleResponse = client().execute(GetLifecycleAction.INSTANCE, new GetLifecycleAction.Request()).get(); + getLifecycleResponse = client().execute( + GetLifecycleAction.INSTANCE, + new GetLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get(); assertThat(getLifecycleResponse.getPolicies().size(), equalTo(1)); responseItem = getLifecycleResponse.getPolicies().get(0); assertThat(responseItem.getLifecyclePolicy(), equalTo(policy)); @@ -241,11 +254,13 @@ public void testExplainExecution() throws Exception { logger.info("Starting server1"); internalCluster().startNode(); logger.info("Creating lifecycle [test_lifecycle]"); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); - GetLifecycleAction.Response getLifecycleResponse = client().execute(GetLifecycleAction.INSTANCE, new GetLifecycleAction.Request()) - .get(); + GetLifecycleAction.Response getLifecycleResponse = client().execute( + GetLifecycleAction.INSTANCE, + new GetLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get(); assertThat(getLifecycleResponse.getPolicies().size(), equalTo(1)); GetLifecycleAction.LifecyclePolicyResponseItem responseItem = getLifecycleResponse.getPolicies().get(0); assertThat(responseItem.getLifecyclePolicy(), equalTo(lifecyclePolicy)); @@ -314,11 +329,13 @@ public void testExplainParseOriginationDate() throws Exception { logger.info("Starting server2"); internalCluster().startNode(); logger.info("Creating lifecycle [test_lifecycle]"); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); - GetLifecycleAction.Response getLifecycleResponse = client().execute(GetLifecycleAction.INSTANCE, new GetLifecycleAction.Request()) - .get(); + GetLifecycleAction.Response getLifecycleResponse = client().execute( + GetLifecycleAction.INSTANCE, + new GetLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get(); assertThat(getLifecycleResponse.getPolicies().size(), equalTo(1)); GetLifecycleAction.LifecyclePolicyResponseItem responseItem = getLifecycleResponse.getPolicies().get(0); assertThat(responseItem.getLifecyclePolicy(), equalTo(lifecyclePolicy)); @@ -402,7 +419,7 @@ public void testMasterDedicatedDataDedicated() throws Exception { } logger.info("Creating lifecycle [test_lifecycle]"); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); logger.info("Creating index [test]"); CreateIndexResponse createIndexResponse = indicesAdmin().create(new CreateIndexRequest("test").settings(settings)).actionGet(); @@ -430,7 +447,7 @@ public void testCreatePolicyWhenStopped() throws Exception { final String server_1 = internalCluster().startNode(); final String node1 = getLocalNodeId(server_1); - assertAcked(client().execute(ILMActions.STOP, new StopILMRequest()).get()); + assertAcked(client().execute(ILMActions.STOP, new StopILMRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)).get()); assertBusy(() -> { OperationMode mode = client().execute( GetStatusAction.INSTANCE, @@ -441,14 +458,16 @@ public void testCreatePolicyWhenStopped() throws Exception { }); logger.info("Creating lifecycle [test_lifecycle]"); - PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); long lowerBoundModifiedDate = Instant.now().toEpochMilli(); assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).get()); long upperBoundModifiedDate = Instant.now().toEpochMilli(); // assert version and modified_date - GetLifecycleAction.Response getLifecycleResponse = client().execute(GetLifecycleAction.INSTANCE, new GetLifecycleAction.Request()) - .get(); + GetLifecycleAction.Response getLifecycleResponse = client().execute( + GetLifecycleAction.INSTANCE, + new GetLifecycleAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ).get(); assertThat(getLifecycleResponse.getPolicies().size(), equalTo(1)); GetLifecycleAction.LifecyclePolicyResponseItem responseItem = getLifecycleResponse.getPolicies().get(0); assertThat(responseItem.getLifecyclePolicy(), equalTo(lifecyclePolicy)); diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/ReservedLifecycleAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/ReservedLifecycleAction.java index 947a028e9262e..ba41e29531b76 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/ReservedLifecycleAction.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/ReservedLifecycleAction.java @@ -7,8 +7,10 @@ package org.elasticsearch.xpack.ilm.action; +import org.elasticsearch.action.ActionListener; import org.elasticsearch.client.internal.Client; import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.reservedstate.ReservedClusterStateHandler; import org.elasticsearch.reservedstate.TransformState; @@ -16,6 +18,7 @@ import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xpack.core.ilm.LifecyclePolicy; +import org.elasticsearch.xpack.core.ilm.action.DeleteLifecycleAction; import org.elasticsearch.xpack.core.ilm.action.PutLifecycleRequest; import java.io.IOException; @@ -61,7 +64,8 @@ public Collection prepare(Object input) throws IOException List policies = (List) input; for (var policy : policies) { - PutLifecycleRequest request = new PutLifecycleRequest(policy); + // timeouts don't matter here + PutLifecycleRequest request = new PutLifecycleRequest(TimeValue.THIRTY_SECONDS, TimeValue.THIRTY_SECONDS, policy); validate(request); result.add(request); } @@ -93,7 +97,9 @@ public TransformState transform(Object source, TransformState prevState) throws for (var policyToDelete : toDelete) { TransportDeleteLifecycleAction.DeleteLifecyclePolicyTask task = new TransportDeleteLifecycleAction.DeleteLifecyclePolicyTask( - policyToDelete + // timeouts don't matter here + new DeleteLifecycleAction.Request(TimeValue.THIRTY_SECONDS, TimeValue.THIRTY_SECONDS, policyToDelete), + ActionListener.noop() ); state = task.execute(state); } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestDeleteLifecycleAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestDeleteLifecycleAction.java index 8e8ec714f380d..688925cd41fec 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestDeleteLifecycleAction.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestDeleteLifecycleAction.java @@ -34,9 +34,11 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { String lifecycleName = restRequest.param("name"); - DeleteLifecycleAction.Request deleteLifecycleRequest = new DeleteLifecycleAction.Request(lifecycleName); - deleteLifecycleRequest.ackTimeout(getAckTimeout(restRequest)); - deleteLifecycleRequest.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + DeleteLifecycleAction.Request deleteLifecycleRequest = new DeleteLifecycleAction.Request( + getMasterNodeTimeout(restRequest), + getAckTimeout(restRequest), + lifecycleName + ); return channel -> client.execute(DeleteLifecycleAction.INSTANCE, deleteLifecycleRequest, new RestToXContentListener<>(channel)); } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestGetLifecycleAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestGetLifecycleAction.java index 5a9923c014d6d..3de071a977dc6 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestGetLifecycleAction.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestGetLifecycleAction.java @@ -36,9 +36,11 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { String[] lifecycleNames = Strings.splitStringByCommaToArray(restRequest.param("name")); - GetLifecycleAction.Request getLifecycleRequest = new GetLifecycleAction.Request(lifecycleNames); - getLifecycleRequest.ackTimeout(getAckTimeout(restRequest)); - getLifecycleRequest.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + GetLifecycleAction.Request getLifecycleRequest = new GetLifecycleAction.Request( + getMasterNodeTimeout(restRequest), + getAckTimeout(restRequest), + lifecycleNames + ); return channel -> new RestCancellableNodeClient(client, restRequest.getHttpChannel()).execute( GetLifecycleAction.INSTANCE, diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestPutLifecycleAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestPutLifecycleAction.java index d07c498e21ec2..ba9dc4340474f 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestPutLifecycleAction.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestPutLifecycleAction.java @@ -11,7 +11,7 @@ import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestToXContentListener; -import org.elasticsearch.xcontent.XContentParser; +import org.elasticsearch.xpack.core.ilm.LifecyclePolicy; import org.elasticsearch.xpack.core.ilm.action.ILMActions; import org.elasticsearch.xpack.core.ilm.action.PutLifecycleRequest; @@ -36,13 +36,20 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException { - String lifecycleName = restRequest.param("name"); - try (XContentParser parser = restRequest.contentParser()) { - PutLifecycleRequest putLifecycleRequest = PutLifecycleRequest.parseRequest(lifecycleName, parser); - putLifecycleRequest.ackTimeout(getAckTimeout(restRequest)); - putLifecycleRequest.masterNodeTimeout(getMasterNodeTimeout(restRequest)); - - return channel -> client.execute(ILMActions.PUT, putLifecycleRequest, new RestToXContentListener<>(channel)); + final PutLifecycleRequest putLifecycleRequest; + try (var parser = restRequest.contentParser()) { + putLifecycleRequest = PutLifecycleRequest.parseRequest(new PutLifecycleRequest.Factory() { + @Override + public PutLifecycleRequest create(LifecyclePolicy lifecyclePolicy) { + return new PutLifecycleRequest(getMasterNodeTimeout(restRequest), getAckTimeout(restRequest), lifecyclePolicy); + } + + @Override + public String getPolicyName() { + return restRequest.param("name"); + } + }, parser); } + return channel -> client.execute(ILMActions.PUT, putLifecycleRequest, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestRemoveIndexLifecyclePolicyAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestRemoveIndexLifecyclePolicyAction.java index a011aa3d38b64..d750dfb257834 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestRemoveIndexLifecyclePolicyAction.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestRemoveIndexLifecyclePolicyAction.java @@ -18,6 +18,7 @@ import java.util.List; import static org.elasticsearch.rest.RestRequest.Method.POST; +import static org.elasticsearch.rest.RestUtils.getAckTimeout; import static org.elasticsearch.rest.RestUtils.getMasterNodeTimeout; public class RestRemoveIndexLifecyclePolicyAction extends BaseRestHandler { @@ -35,8 +36,11 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { String[] indexes = Strings.splitStringByCommaToArray(restRequest.param("index")); - RemoveIndexLifecyclePolicyAction.Request changePolicyRequest = new RemoveIndexLifecyclePolicyAction.Request(indexes); - changePolicyRequest.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + RemoveIndexLifecyclePolicyAction.Request changePolicyRequest = new RemoveIndexLifecyclePolicyAction.Request( + getMasterNodeTimeout(restRequest), + getAckTimeout(restRequest), + indexes + ); changePolicyRequest.indicesOptions(IndicesOptions.fromRequest(restRequest, changePolicyRequest.indicesOptions())); return channel -> client.execute( diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestStartILMAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestStartILMAction.java index bba6261b323f9..ad0d9b0d289d0 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestStartILMAction.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestStartILMAction.java @@ -34,9 +34,7 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { - StartILMRequest request = new StartILMRequest(); - request.ackTimeout(getAckTimeout(restRequest)); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + StartILMRequest request = new StartILMRequest(getMasterNodeTimeout(restRequest), getAckTimeout(restRequest)); return channel -> client.execute(ILMActions.START, request, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestStopAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestStopAction.java index 96954f4dbca42..d68bbe86fc7d9 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestStopAction.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/RestStopAction.java @@ -34,9 +34,7 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { - StopILMRequest request = new StopILMRequest(); - request.ackTimeout(getAckTimeout(restRequest)); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + StopILMRequest request = new StopILMRequest(getMasterNodeTimeout(restRequest), getAckTimeout(restRequest)); return channel -> client.execute(ILMActions.STOP, request, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/TransportDeleteLifecycleAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/TransportDeleteLifecycleAction.java index e222d8f6dd9d8..05f9fe7820baf 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/TransportDeleteLifecycleAction.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/TransportDeleteLifecycleAction.java @@ -23,7 +23,6 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.util.concurrent.EsExecutors; import org.elasticsearch.core.SuppressForbidden; -import org.elasticsearch.reservedstate.ReservedClusterStateHandler; import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; @@ -76,14 +75,6 @@ public DeleteLifecyclePolicyTask(Request request, ActionListener assertThat(ilmMode(), equalTo(OperationMode.STOPPED))); assertBusy(() -> assertThat(slmMode(), equalTo(OperationMode.STOPPED))); diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/TransportDeleteLifecycleActionTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/TransportDeleteLifecycleActionTests.java index 3e0f19246dfe3..e75a609d236ed 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/TransportDeleteLifecycleActionTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/TransportDeleteLifecycleActionTests.java @@ -32,7 +32,11 @@ public void testReservedStateHandler() { ); assertEquals(ReservedLifecycleAction.NAME, putAction.reservedStateHandlerName().get()); - DeleteLifecycleAction.Request request = new DeleteLifecycleAction.Request("my_timeseries_lifecycle2"); + DeleteLifecycleAction.Request request = new DeleteLifecycleAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, + "my_timeseries_lifecycle2" + ); assertThat(putAction.modifiedKeys(request), containsInAnyOrder("my_timeseries_lifecycle2")); } } diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/TransportPutLifecycleActionTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/TransportPutLifecycleActionTests.java index e69e91192cf13..7f4e70bc1b306 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/TransportPutLifecycleActionTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/TransportPutLifecycleActionTests.java @@ -75,7 +75,17 @@ public void testReservedStateHandler() throws Exception { }"""; try (XContentParser parser = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, json)) { - PutLifecycleRequest request = PutLifecycleRequest.parseRequest("my_timeseries_lifecycle2", parser); + PutLifecycleRequest request = PutLifecycleRequest.parseRequest(new PutLifecycleRequest.Factory() { + @Override + public PutLifecycleRequest create(LifecyclePolicy lifecyclePolicy) { + return new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, lifecyclePolicy); + } + + @Override + public String getPolicyName() { + return "my_timeseries_lifecycle2"; + } + }, parser); assertThat(putAction.modifiedKeys(request), containsInAnyOrder("my_timeseries_lifecycle2")); } diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/TransportStopILMActionTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/TransportStopILMActionTests.java index 69ff6215aea01..8c0fede4c11dc 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/TransportStopILMActionTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/TransportStopILMActionTests.java @@ -52,7 +52,7 @@ public void testStopILMClusterStatePriorityIsImmediate() { new TaskId(randomLong() + ":" + randomLong()), emptyMap() ); - StopILMRequest request = new StopILMRequest(); + StopILMRequest request = new StopILMRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); transportStopILMAction.masterOperation(task, request, ClusterState.EMPTY_STATE, ActionListener.noop()); verify(clusterService).submitUnbatchedStateUpdateTask( From fc07f58be8bda3923c2fecb7fd3268b32be47032 Mon Sep 17 00:00:00 2001 From: Tim Grein Date: Wed, 29 May 2024 08:43:55 +0200 Subject: [PATCH 020/208] [Inference API] Use ModelConfigurations.SERVICE_SETTINGS as scope (#109072) --- .../elasticsearch/CustomElandInternalServiceSettings.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elasticsearch/CustomElandInternalServiceSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elasticsearch/CustomElandInternalServiceSettings.java index ba98090c92522..c62855c09cff2 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elasticsearch/CustomElandInternalServiceSettings.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elasticsearch/CustomElandInternalServiceSettings.java @@ -12,6 +12,7 @@ import org.elasticsearch.common.ValidationException; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.inference.ModelConfigurations; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xpack.inference.services.ServiceUtils; @@ -45,8 +46,7 @@ public static Builder fromMap(Map map) { validateParameters(numAllocations, validationException, numThreads); - String modelId = ServiceUtils.extractRequiredString(map, MODEL_ID, "ServiceSettings", validationException); // TODO check if this is - // the correct scope + String modelId = ServiceUtils.extractRequiredString(map, MODEL_ID, ModelConfigurations.SERVICE_SETTINGS, validationException); if (validationException.validationErrors().isEmpty() == false) { throw validationException; From 0e03920560c2bbd486d205b2f0c06b44235e909f Mon Sep 17 00:00:00 2001 From: David Turner Date: Wed, 29 May 2024 08:14:15 +0100 Subject: [PATCH 021/208] Clean up licensing APIs (#109121) Fixes trappy timeouts related to #107984 and also cleans up all the indirection via unnecessary request builders. --- .../license/ClusterStateLicenseService.java | 4 +- .../license/GetBasicStatusRequest.java | 5 +- .../license/GetBasicStatusRequestBuilder.java | 17 --- .../license/GetLicenseRequestBuilder.java | 30 ----- .../license/GetTrialStatusRequest.java | 5 +- .../license/GetTrialStatusRequestBuilder.java | 17 --- .../license/LicensingClient.java | 42 ------ .../license/PostStartBasicRequest.java | 5 +- .../license/PostStartBasicRequestBuilder.java | 22 ---- .../license/PostStartTrialRequest.java | 5 +- .../license/PostStartTrialRequestBuilder.java | 22 ---- .../license/PutLicenseRequest.java | 5 +- .../license/PutLicenseRequestBuilder.java | 49 ------- .../license/RestGetBasicStatus.java | 6 +- .../license/RestGetLicenseAction.java | 3 +- .../license/RestGetTrialStatus.java | 6 +- .../license/RestPostStartBasicLicense.java | 4 +- .../license/RestPostStartTrialLicense.java | 3 +- .../license/RestPutLicenseAction.java | 4 +- .../license/TransportDeleteLicenseAction.java | 6 +- .../internal/MutableLicenseService.java | 3 +- .../xpack/license/GetLicenseRequest.java | 5 +- .../AbstractLicensesIntegrationTestCase.java | 17 +++ ...lusterStateLicenseServiceClusterTests.java | 32 +++-- .../ClusterStateLicenseServiceTests.java | 4 +- .../license/LicenseFIPSTests.java | 4 +- .../license/LicenseTLSTests.java | 2 +- .../license/LicensesAcknowledgementTests.java | 4 +- .../license/LicensesManagerServiceTests.java | 2 +- .../license/LicensesTransportTests.java | 122 ++++++++---------- .../license/StartBasicLicenseTests.java | 65 ++++++---- .../license/StartTrialLicenseTests.java | 66 ++++------ .../org/elasticsearch/license/TestUtils.java | 5 +- .../xpack/core/XPackPluginTests.java | 7 +- .../lucene/bwc/AbstractArchiveTestCase.java | 3 +- .../lucene/bwc/ArchiveLicenseIntegTests.java | 11 +- .../SearchableSnapshotsLicenseIntegTests.java | 7 +- 37 files changed, 231 insertions(+), 388 deletions(-) delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetBasicStatusRequestBuilder.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetLicenseRequestBuilder.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetTrialStatusRequestBuilder.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicensingClient.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/license/PostStartBasicRequestBuilder.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/license/PostStartTrialRequestBuilder.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/license/PutLicenseRequestBuilder.java diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/ClusterStateLicenseService.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/ClusterStateLicenseService.java index 7cab82559c7fc..b352a9abce886 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/ClusterStateLicenseService.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/ClusterStateLicenseService.java @@ -303,8 +303,8 @@ public void triggered(SchedulerEngine.Event event) { * Remove license from the cluster state metadata */ @Override - public void removeLicense(ActionListener listener) { - final PostStartBasicRequest startBasicRequest = new PostStartBasicRequest().acknowledge(true); + public void removeLicense(TimeValue masterNodeTimeout, TimeValue ackTimeout, ActionListener listener) { + final PostStartBasicRequest startBasicRequest = new PostStartBasicRequest(masterNodeTimeout, ackTimeout).acknowledge(true); @SuppressWarnings("unchecked") final StartBasicClusterTask task = new StartBasicClusterTask( logger, diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetBasicStatusRequest.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetBasicStatusRequest.java index 9e8e707db6b86..7ef61ca07f821 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetBasicStatusRequest.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetBasicStatusRequest.java @@ -9,13 +9,14 @@ import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.support.master.MasterNodeReadRequest; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; public class GetBasicStatusRequest extends MasterNodeReadRequest { - public GetBasicStatusRequest() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); + public GetBasicStatusRequest(TimeValue masterNodeTimeout) { + super(masterNodeTimeout); } public GetBasicStatusRequest(StreamInput in) throws IOException { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetBasicStatusRequestBuilder.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetBasicStatusRequestBuilder.java deleted file mode 100644 index 160b3648444aa..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetBasicStatusRequestBuilder.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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.license; - -import org.elasticsearch.action.ActionRequestBuilder; -import org.elasticsearch.client.internal.ElasticsearchClient; - -class GetBasicStatusRequestBuilder extends ActionRequestBuilder { - - GetBasicStatusRequestBuilder(ElasticsearchClient client) { - super(client, GetBasicStatusAction.INSTANCE, new GetBasicStatusRequest()); - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetLicenseRequestBuilder.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetLicenseRequestBuilder.java deleted file mode 100644 index 560ab2b861f8a..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetLicenseRequestBuilder.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.license; - -import org.elasticsearch.action.support.master.MasterNodeReadOperationRequestBuilder; -import org.elasticsearch.client.internal.ElasticsearchClient; -import org.elasticsearch.protocol.xpack.license.GetLicenseRequest; - -public class GetLicenseRequestBuilder extends MasterNodeReadOperationRequestBuilder< - GetLicenseRequest, - GetLicenseResponse, - GetLicenseRequestBuilder> { - - public GetLicenseRequestBuilder(ElasticsearchClient client) { - this(client, GetLicenseAction.INSTANCE); - } - - /** - * Creates new get licenses request builder - * - * @param client elasticsearch client - */ - public GetLicenseRequestBuilder(ElasticsearchClient client, GetLicenseAction action) { - super(client, action, new GetLicenseRequest()); - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetTrialStatusRequest.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetTrialStatusRequest.java index cae967058fb73..3643e4e7857ec 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetTrialStatusRequest.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetTrialStatusRequest.java @@ -9,13 +9,14 @@ import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.support.master.MasterNodeReadRequest; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; public class GetTrialStatusRequest extends MasterNodeReadRequest { - public GetTrialStatusRequest() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); + public GetTrialStatusRequest(TimeValue masterNodeTimeout) { + super(masterNodeTimeout); } public GetTrialStatusRequest(StreamInput in) throws IOException { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetTrialStatusRequestBuilder.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetTrialStatusRequestBuilder.java deleted file mode 100644 index 6c51def015082..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/GetTrialStatusRequestBuilder.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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.license; - -import org.elasticsearch.action.ActionRequestBuilder; -import org.elasticsearch.client.internal.ElasticsearchClient; - -class GetTrialStatusRequestBuilder extends ActionRequestBuilder { - - GetTrialStatusRequestBuilder(ElasticsearchClient client) { - super(client, GetTrialStatusAction.INSTANCE, new GetTrialStatusRequest()); - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicensingClient.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicensingClient.java deleted file mode 100644 index 5396d45126bb5..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicensingClient.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.license; - -import org.elasticsearch.client.internal.ElasticsearchClient; - -public class LicensingClient { - - private final ElasticsearchClient client; - - public LicensingClient(ElasticsearchClient client) { - this.client = client; - } - - public PutLicenseRequestBuilder preparePutLicense(License license) { - return new PutLicenseRequestBuilder(client).setLicense(license); - } - - public GetLicenseRequestBuilder prepareGetLicense() { - return new GetLicenseRequestBuilder(client); - } - - public PostStartTrialRequestBuilder preparePostStartTrial() { - return new PostStartTrialRequestBuilder(client); - } - - public GetTrialStatusRequestBuilder prepareGetStartTrial() { - return new GetTrialStatusRequestBuilder(client); - } - - public PostStartBasicRequestBuilder preparePostStartBasic() { - return new PostStartBasicRequestBuilder(client); - } - - public GetBasicStatusRequestBuilder prepareGetStartBasic() { - return new GetBasicStatusRequestBuilder(client); - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PostStartBasicRequest.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PostStartBasicRequest.java index 7e9b0ebf44bee..e3f77ca97cd1c 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PostStartBasicRequest.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PostStartBasicRequest.java @@ -9,6 +9,7 @@ import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; @@ -16,8 +17,8 @@ public class PostStartBasicRequest extends AcknowledgedRequest { - - PostStartBasicRequestBuilder(ElasticsearchClient client) { - super(client, PostStartBasicAction.INSTANCE, new PostStartBasicRequest()); - } - - public PostStartBasicRequestBuilder setAcknowledge(boolean acknowledge) { - request.acknowledge(acknowledge); - return this; - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PostStartTrialRequest.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PostStartTrialRequest.java index 5d7ee5648bd10..835d75180a821 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PostStartTrialRequest.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PostStartTrialRequest.java @@ -10,6 +10,7 @@ import org.elasticsearch.action.support.master.MasterNodeRequest; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; @@ -18,8 +19,8 @@ public class PostStartTrialRequest extends MasterNodeRequest { - - PostStartTrialRequestBuilder(ElasticsearchClient client) { - super(client, PostStartTrialAction.INSTANCE, new PostStartTrialRequest()); - } - - public PostStartTrialRequestBuilder setAcknowledge(boolean acknowledge) { - request.acknowledge(acknowledge); - return this; - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PutLicenseRequest.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PutLicenseRequest.java index d97b0aa7f4ff6..ed74ccc69731c 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PutLicenseRequest.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PutLicenseRequest.java @@ -12,6 +12,7 @@ import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.XContentType; import java.io.IOException; @@ -27,8 +28,8 @@ public PutLicenseRequest(StreamInput in) throws IOException { acknowledge = in.readBoolean(); } - public PutLicenseRequest() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public PutLicenseRequest(TimeValue masterNodeTimeout, TimeValue ackTimeout) { + super(masterNodeTimeout, ackTimeout); } @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PutLicenseRequestBuilder.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PutLicenseRequestBuilder.java deleted file mode 100644 index 532e63e24d09e..0000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/PutLicenseRequestBuilder.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.license; - -import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder; -import org.elasticsearch.client.internal.ElasticsearchClient; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.protocol.xpack.license.PutLicenseResponse; -import org.elasticsearch.xcontent.XContentType; - -/** - * Register license request builder - */ -public class PutLicenseRequestBuilder extends AcknowledgedRequestBuilder { - - /** - * Constructs register license request - * - * @param client elasticsearch client - */ - public PutLicenseRequestBuilder(ElasticsearchClient client) { - super(client, PutLicenseAction.INSTANCE, new PutLicenseRequest()); - } - - /** - * Sets the license - * - * @param license license - * @return this builder - */ - public PutLicenseRequestBuilder setLicense(License license) { - request.license(license); - return this; - } - - public PutLicenseRequestBuilder setLicense(BytesReference licenseSource, XContentType xContentType) { - request.license(licenseSource, xContentType); - return this; - } - - public PutLicenseRequestBuilder setAcknowledge(boolean acknowledge) { - request.acknowledge(acknowledge); - return this; - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetBasicStatus.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetBasicStatus.java index c1efbc7513e4a..e0428c0ff2039 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetBasicStatus.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetBasicStatus.java @@ -11,6 +11,7 @@ import org.elasticsearch.core.RestApiVersion; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestUtils; import org.elasticsearch.rest.action.RestToXContentListener; import java.util.List; @@ -29,8 +30,9 @@ public List routes() { } @Override - protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - return channel -> new GetBasicStatusRequestBuilder(client).execute(new RestToXContentListener<>(channel)); + protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { + final var request = new GetBasicStatusRequest(RestUtils.getMasterNodeTimeout(restRequest)); + return channel -> client.execute(GetBasicStatusAction.INSTANCE, request, new RestToXContentListener<>(channel)); } @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetLicenseAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetLicenseAction.java index 75826bc0b1828..4240119df457d 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetLicenseAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetLicenseAction.java @@ -16,6 +16,7 @@ import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestResponse; +import org.elasticsearch.rest.RestUtils; import org.elasticsearch.rest.Scope; import org.elasticsearch.rest.ServerlessScope; import org.elasticsearch.rest.action.RestBuilderListener; @@ -84,7 +85,7 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC } final ToXContent.Params params = new ToXContent.DelegatingMapParams(overrideParams, request); - GetLicenseRequest getLicenseRequest = new GetLicenseRequest(); + GetLicenseRequest getLicenseRequest = new GetLicenseRequest(RestUtils.getMasterNodeTimeout(request)); getLicenseRequest.local(request.paramAsBoolean("local", getLicenseRequest.local())); return channel -> client.admin() .cluster() diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetTrialStatus.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetTrialStatus.java index b453551749d8b..e42db16ded401 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetTrialStatus.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetTrialStatus.java @@ -11,6 +11,7 @@ import org.elasticsearch.core.RestApiVersion; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestUtils; import org.elasticsearch.rest.action.RestToXContentListener; import java.util.List; @@ -29,8 +30,9 @@ public List routes() { } @Override - protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - return channel -> new GetTrialStatusRequestBuilder(client).execute(new RestToXContentListener<>(channel)); + protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { + final var request = new GetTrialStatusRequest(RestUtils.getMasterNodeTimeout(restRequest)); + return channel -> client.execute(GetTrialStatusAction.INSTANCE, request, new RestToXContentListener<>(channel)); } @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestPostStartBasicLicense.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestPostStartBasicLicense.java index 1a1a568393789..64556bcf69ecf 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestPostStartBasicLicense.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestPostStartBasicLicense.java @@ -33,10 +33,8 @@ public List routes() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - PostStartBasicRequest startBasicRequest = new PostStartBasicRequest(); + PostStartBasicRequest startBasicRequest = new PostStartBasicRequest(getMasterNodeTimeout(request), getAckTimeout(request)); startBasicRequest.acknowledge(request.paramAsBoolean("acknowledge", false)); - startBasicRequest.ackTimeout(getAckTimeout(request)); - startBasicRequest.masterNodeTimeout(getMasterNodeTimeout(request)); return channel -> client.execute( PostStartBasicAction.INSTANCE, startBasicRequest, diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestPostStartTrialLicense.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestPostStartTrialLicense.java index 6ae1719383afb..56fae76c2e2b8 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestPostStartTrialLicense.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestPostStartTrialLicense.java @@ -12,6 +12,7 @@ import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestResponse; +import org.elasticsearch.rest.RestUtils; import org.elasticsearch.rest.action.RestBuilderListener; import org.elasticsearch.xcontent.XContentBuilder; @@ -34,7 +35,7 @@ public List routes() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - PostStartTrialRequest startTrialRequest = new PostStartTrialRequest(); + PostStartTrialRequest startTrialRequest = new PostStartTrialRequest(RestUtils.getMasterNodeTimeout(request)); startTrialRequest.setType(request.param("type", License.LicenseType.TRIAL.getTypeName())); startTrialRequest.acknowledge(request.paramAsBoolean("acknowledge", false)); return channel -> client.execute(PostStartTrialAction.INSTANCE, startTrialRequest, new RestBuilderListener<>(channel) { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestPutLicenseAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestPutLicenseAction.java index 2d86a75947ba0..0798be6e53a14 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestPutLicenseAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestPutLicenseAction.java @@ -44,11 +44,9 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC if (request.hasContent() == false) { throw new IllegalArgumentException("The license must be provided in the request body"); } - PutLicenseRequest putLicenseRequest = new PutLicenseRequest(); + PutLicenseRequest putLicenseRequest = new PutLicenseRequest(getMasterNodeTimeout(request), getAckTimeout(request)); putLicenseRequest.license(request.content(), request.getXContentType()); putLicenseRequest.acknowledge(request.paramAsBoolean("acknowledge", false)); - putLicenseRequest.ackTimeout(getAckTimeout(request)); - putLicenseRequest.masterNodeTimeout(getMasterNodeTimeout(request)); if (License.LicenseType.isBasic(putLicenseRequest.license().type())) { throw new IllegalArgumentException( diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/TransportDeleteLicenseAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/TransportDeleteLicenseAction.java index 7ac59e1dc327a..5739655c88eea 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/TransportDeleteLicenseAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/TransportDeleteLicenseAction.java @@ -63,6 +63,10 @@ protected void masterOperation( ClusterState state, final ActionListener listener ) throws ElasticsearchException { - licenseService.removeLicense(listener.map(r -> AcknowledgedResponse.of(r.isAcknowledged()))); + licenseService.removeLicense( + request.masterNodeTimeout(), + request.ackTimeout(), + listener.map(r -> AcknowledgedResponse.of(r.isAcknowledged())) + ); } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/internal/MutableLicenseService.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/internal/MutableLicenseService.java index 72650daa1215e..8632e60c2ee4f 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/internal/MutableLicenseService.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/internal/MutableLicenseService.java @@ -10,6 +10,7 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.component.LifecycleComponent; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.license.LicenseService; import org.elasticsearch.license.LicensesMetadata; import org.elasticsearch.license.PostStartBasicRequest; @@ -35,7 +36,7 @@ public interface MutableLicenseService extends LicenseService, LifecycleComponen * Removes the current license. Implementations should remove the current license and ensure that attempts to read returns * {@link LicensesMetadata#LICENSE_TOMBSTONE} if a license was removed. Additionally the {@link XPackLicenseState} must be updated. */ - void removeLicense(ActionListener listener); + void removeLicense(TimeValue masterNodeTimeout, TimeValue ackTimeout, ActionListener listener); /** * Installs a basic license. diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/protocol/xpack/license/GetLicenseRequest.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/protocol/xpack/license/GetLicenseRequest.java index ea4e53aced5fe..b05b87b699a72 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/protocol/xpack/license/GetLicenseRequest.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/protocol/xpack/license/GetLicenseRequest.java @@ -9,13 +9,14 @@ import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.support.master.MasterNodeReadRequest; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; public class GetLicenseRequest extends MasterNodeReadRequest { - public GetLicenseRequest() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); + public GetLicenseRequest(TimeValue masterNodeTimeout) { + super(masterNodeTimeout); } public GetLicenseRequest(StreamInput in) throws IOException { diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/AbstractLicensesIntegrationTestCase.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/AbstractLicensesIntegrationTestCase.java index aa3a4f44e2f12..a09f7d5ca3f52 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/AbstractLicensesIntegrationTestCase.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/AbstractLicensesIntegrationTestCase.java @@ -14,6 +14,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.Nullable; import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.protocol.xpack.license.GetLicenseRequest; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.xpack.core.LocalStateCompositeXPackPlugin; import org.elasticsearch.xpack.core.XPackSettings; @@ -100,4 +101,20 @@ protected void assertLicenseActive(boolean active) throws Exception { }); } + protected static GetLicenseResponse getLicense() { + return safeGet(clusterAdmin().execute(GetLicenseAction.INSTANCE, new GetLicenseRequest(TEST_REQUEST_TIMEOUT))); + } + + protected static GetTrialStatusResponse getTrialStatus() { + return safeGet(clusterAdmin().execute(GetTrialStatusAction.INSTANCE, new GetTrialStatusRequest(TEST_REQUEST_TIMEOUT))); + } + + protected static PostStartBasicResponse startBasic() { + return safeGet( + clusterAdmin().execute( + PostStartBasicAction.INSTANCE, + new PostStartBasicRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT).acknowledge(true) + ) + ); + } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/ClusterStateLicenseServiceClusterTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/ClusterStateLicenseServiceClusterTests.java index 338c1ebfb4e21..00bf1c7fe174f 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/ClusterStateLicenseServiceClusterTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/ClusterStateLicenseServiceClusterTests.java @@ -10,6 +10,7 @@ import org.elasticsearch.cluster.node.DiscoveryNodeRole; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.TimeValue; +import org.elasticsearch.protocol.xpack.license.GetLicenseRequest; import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import java.util.Set; @@ -40,18 +41,22 @@ public void testClusterRestartWithLicense() throws Exception { ensureGreen(); logger.info("--> put signed license"); - LicensingClient licensingClient = new LicensingClient(client()); License license = TestUtils.generateSignedLicense(TimeValue.timeValueMinutes(1)); putLicense(license); - assertThat(licensingClient.prepareGetLicense().get().license(), equalTo(license)); + assertThat( + client().execute(GetLicenseAction.INSTANCE, new GetLicenseRequest(TEST_REQUEST_TIMEOUT)).get().license(), + equalTo(license) + ); assertOperationMode(license.operationMode()); logger.info("--> restart all nodes"); internalCluster().fullRestart(); ensureYellow(); - licensingClient = new LicensingClient(client()); logger.info("--> get and check signed license"); - assertThat(licensingClient.prepareGetLicense().get().license(), equalTo(license)); + assertThat( + client().execute(GetLicenseAction.INSTANCE, new GetLicenseRequest(TEST_REQUEST_TIMEOUT)).get().license(), + equalTo(license) + ); logger.info("--> remove licenses"); assertAcked( @@ -62,9 +67,12 @@ public void testClusterRestartWithLicense() throws Exception { logger.info("--> restart all nodes"); internalCluster().fullRestart(); - licensingClient = new LicensingClient(client()); ensureYellow(); - assertTrue(License.LicenseType.isBasic(licensingClient.prepareGetLicense().get().license().type())); + assertTrue( + License.LicenseType.isBasic( + client().execute(GetLicenseAction.INSTANCE, new GetLicenseRequest(TEST_REQUEST_TIMEOUT)).get().license().type() + ) + ); assertOperationMode(License.OperationMode.BASIC); wipeAllLicenses(); @@ -103,15 +111,19 @@ public void testClusterRestartWithOldSignature() throws Exception { ensureGreen(); assertLicenseActive(true); putLicense(TestUtils.generateSignedLicenseOldSignature()); - LicensingClient licensingClient = new LicensingClient(client()); - assertThat(licensingClient.prepareGetLicense().get().license().version(), equalTo(License.VERSION_START_DATE)); + assertThat( + client().execute(GetLicenseAction.INSTANCE, new GetLicenseRequest(TEST_REQUEST_TIMEOUT)).get().license().version(), + equalTo(License.VERSION_START_DATE) + ); logger.info("--> restart node"); internalCluster().fullRestart(); // restart so that license is updated ensureYellow(); logger.info("--> await node for enabled"); assertLicenseActive(true); - licensingClient = new LicensingClient(client()); - assertThat(licensingClient.prepareGetLicense().get().license().version(), equalTo(License.VERSION_CURRENT)); // license updated + assertThat( + client().execute(GetLicenseAction.INSTANCE, new GetLicenseRequest(TEST_REQUEST_TIMEOUT)).get().license().version(), + equalTo(License.VERSION_CURRENT) + ); // license updated internalCluster().fullRestart(); // restart once more and verify updated license is active ensureYellow(); logger.info("--> await node for enabled"); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/ClusterStateLicenseServiceTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/ClusterStateLicenseServiceTests.java index 33f162a06f350..c0c7c5c59d24b 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/ClusterStateLicenseServiceTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/ClusterStateLicenseServiceTests.java @@ -202,7 +202,7 @@ public void testStartBasicStartsNewLicenseIfFieldsDifferent() throws Exception { assertThat(response.getStatus(), equalTo(PostStartBasicResponse.Status.GENERATED_BASIC)); }; final PlainActionFuture future = new PlainActionFuture<>(); - service.startBasicLicense(new PostStartBasicRequest(), future); + service.startBasicLicense(new PostStartBasicRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT), future); if (future.isDone()) { // If validation failed, the future might be done without calling the updater task. @@ -289,7 +289,7 @@ private void tryRegisterLicense(Settings baseSettings, License license, Consumer new FeatureService(List.of()) ); - final PutLicenseRequest request = new PutLicenseRequest(); + final PutLicenseRequest request = new PutLicenseRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.license(toSpec(license), XContentType.JSON); final PlainActionFuture future = new PlainActionFuture<>(); service.registerLicense(request, future); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicenseFIPSTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicenseFIPSTests.java index 212ca265ac477..39bbaa0e53872 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicenseFIPSTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicenseFIPSTests.java @@ -21,7 +21,7 @@ public class LicenseFIPSTests extends AbstractClusterStateLicenseServiceTestCase public void testFIPSCheckWithAllowedLicense() throws Exception { License newLicense = TestUtils.generateSignedLicense(randomFrom("trial", "platinum"), TimeValue.timeValueHours(24L)); - PutLicenseRequest request = new PutLicenseRequest(); + PutLicenseRequest request = new PutLicenseRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.acknowledge(true); request.license(newLicense); Settings settings = Settings.builder() @@ -45,7 +45,7 @@ public void testFIPSCheckWithAllowedLicense() throws Exception { public void testFIPSCheckWithoutAllowedLicense() throws Exception { License newLicense = TestUtils.generateSignedLicense(randomFrom("gold", "standard"), TimeValue.timeValueHours(24L)); - PutLicenseRequest request = new PutLicenseRequest(); + PutLicenseRequest request = new PutLicenseRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.acknowledge(true); request.license(newLicense); Settings settings = Settings.builder() diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicenseTLSTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicenseTLSTests.java index e72c0261e93ca..736f355c542e5 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicenseTLSTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicenseTLSTests.java @@ -31,7 +31,7 @@ public class LicenseTLSTests extends AbstractClusterStateLicenseServiceTestCase public void testApplyLicenseInDevMode() throws Exception { License newLicense = TestUtils.generateSignedLicense(randomFrom("gold", "platinum"), TimeValue.timeValueHours(24L)); - PutLicenseRequest request = new PutLicenseRequest(); + PutLicenseRequest request = new PutLicenseRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.acknowledge(true); request.license(newLicense); Settings settings = Settings.builder().put("xpack.security.enabled", true).build(); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesAcknowledgementTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesAcknowledgementTests.java index f23262e8b4d42..5a0b175db24c8 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesAcknowledgementTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesAcknowledgementTests.java @@ -29,14 +29,14 @@ public void testAcknowledgment() throws Exception { // try installing a signed license long issueDate = System.currentTimeMillis() - TimeValue.timeValueHours(24 * 2).getMillis(); License signedLicense = TestUtils.generateSignedLicense("trial", License.VERSION_CURRENT, issueDate, timeValueHours(10)); - PutLicenseRequest putLicenseRequest = new PutLicenseRequest().license(signedLicense); + PutLicenseRequest putLicenseRequest = new PutLicenseRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT).license(signedLicense); // ensure acknowledgement message was part of the response licenseService.registerLicense(putLicenseRequest, new AssertingLicensesUpdateResponse(false, LicensesStatus.VALID, true)); assertThat(licenseService.getLicense(), not(signedLicense)); verify(clusterService, times(0)).submitUnbatchedStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class)); // try installing a signed license with acknowledgement - putLicenseRequest = new PutLicenseRequest().license(signedLicense).acknowledge(true); + putLicenseRequest = new PutLicenseRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT).license(signedLicense).acknowledge(true); // ensure license was installed and no acknowledgment message was returned licenseService.registerLicense(putLicenseRequest, new AssertingLicensesUpdateResponse(true, LicensesStatus.VALID, false)); verify(clusterService, times(1)).submitUnbatchedStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class)); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesManagerServiceTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesManagerServiceTests.java index 7207a823c543b..0ea55617d86b2 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesManagerServiceTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesManagerServiceTests.java @@ -127,7 +127,7 @@ public void testRemoveLicenses() throws Exception { private void removeAndAckSignedLicenses(final MutableLicenseService licenseService) { final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean success = new AtomicBoolean(false); - licenseService.removeLicense(new ActionListener() { + licenseService.removeLicense(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, new ActionListener() { @Override public void onResponse(PostStartBasicResponse postStartBasicResponse) { if (postStartBasicResponse.isAcknowledged()) { diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesTransportTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesTransportTests.java index 7e9152c0cf18e..afecf0da5d55d 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesTransportTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesTransportTests.java @@ -6,13 +6,13 @@ */ package org.elasticsearch.license; -import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.TimeValue; import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.protocol.xpack.license.GetLicenseRequest; import org.elasticsearch.protocol.xpack.license.LicensesStatus; import org.elasticsearch.protocol.xpack.license.PutLicenseResponse; import org.elasticsearch.test.ESSingleNodeTestCase; @@ -24,6 +24,9 @@ import java.util.Collection; import java.util.Collections; import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.function.UnaryOperator; import static org.elasticsearch.license.TestUtils.dateMath; import static org.elasticsearch.license.TestUtils.generateExpiredNonBasicLicense; @@ -59,12 +62,7 @@ public void testEmptyGetLicense() throws Exception { // basic license is added async, we should wait for it assertBusy(() -> { try { - final ActionFuture getLicenseFuture = new GetLicenseRequestBuilder( - clusterAdmin(), - GetLicenseAction.INSTANCE - ).execute(); - final GetLicenseResponse getLicenseResponse; - getLicenseResponse = getLicenseFuture.get(); + final GetLicenseResponse getLicenseResponse = getLicense(); assertNotNull(getLicenseResponse.license()); assertThat(getLicenseResponse.license().operationMode(), equalTo(License.OperationMode.BASIC)); } catch (Exception e) { @@ -77,15 +75,12 @@ public void testPutLicense() throws Exception { License signedLicense = generateSignedLicense(TimeValue.timeValueMinutes(2)); // put license - PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(clusterAdmin()).setLicense(signedLicense) - .setAcknowledge(true); - PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get(); + final var putLicenseResponse = putLicense(plr -> plr.license(signedLicense).acknowledge(true)); assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); // get and check license - GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(clusterAdmin(), GetLicenseAction.INSTANCE).get(); - assertThat(getLicenseResponse.license(), equalTo(signedLicense)); + assertThat(getLicense().license(), equalTo(signedLicense)); } public void testPutLicenseFromString() throws Exception { @@ -93,17 +88,14 @@ public void testPutLicenseFromString() throws Exception { String licenseString = TestUtils.dumpLicense(signedLicense); // put license source - PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(clusterAdmin()).setLicense( - new BytesArray(licenseString.getBytes(StandardCharsets.UTF_8)), - XContentType.JSON - ).setAcknowledge(true); - PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get(); + final var putLicenseResponse = putLicense( + plr -> plr.license(new BytesArray(licenseString.getBytes(StandardCharsets.UTF_8)), XContentType.JSON).acknowledge(true) + ); assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); // get and check license - GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(clusterAdmin(), GetLicenseAction.INSTANCE).get(); - assertThat(getLicenseResponse.license(), equalTo(signedLicense)); + assertThat(getLicense().license(), equalTo(signedLicense)); } public void testPutInvalidLicense() throws Exception { @@ -115,81 +107,57 @@ public void testPutInvalidLicense() throws Exception { .expiryDate(signedLicense.expiryDate() + 10 * 24 * 60 * 60 * 1000L) .validate() .build(); - - PutLicenseRequestBuilder builder = new PutLicenseRequestBuilder(clusterAdmin()); - builder.setLicense(tamperedLicense); - - // try to put license (should be invalid) - final PutLicenseResponse putLicenseResponse = builder.get(); + final var putLicenseResponse = putLicense(plr -> plr.license(tamperedLicense).acknowledge(randomBoolean())); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.INVALID)); // try to get invalid license - GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(clusterAdmin(), GetLicenseAction.INSTANCE).get(); - assertThat(getLicenseResponse.license(), not(tamperedLicense)); + assertThat(getLicense().license(), not(tamperedLicense)); } public void testPutBasicLicenseIsInvalid() throws Exception { License signedLicense = generateSignedLicense("basic", License.VERSION_CURRENT, -1, TimeValue.timeValueMinutes(2)); - PutLicenseRequestBuilder builder = new PutLicenseRequestBuilder(clusterAdmin()); - builder.setLicense(signedLicense); - // try to put license (should be invalid) - IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, builder::get); + final var putLicenseFuture = putLicenseFuture(plr -> plr.license(signedLicense).acknowledge(randomBoolean())); + IllegalArgumentException iae = expectThrows(ExecutionException.class, IllegalArgumentException.class, putLicenseFuture::get); assertEquals(iae.getMessage(), "Registering basic licenses is not allowed."); // try to get invalid license - GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(clusterAdmin(), GetLicenseAction.INSTANCE).get(); - assertThat(getLicenseResponse.license(), not(signedLicense)); + assertThat(getLicense().license(), not(signedLicense)); } public void testPutExpiredLicense() throws Exception { License expiredLicense = generateExpiredNonBasicLicense(); - PutLicenseRequestBuilder builder = new PutLicenseRequestBuilder(clusterAdmin()); - builder.setLicense(expiredLicense); - PutLicenseResponse putLicenseResponse = builder.get(); + final var putLicenseResponse = putLicense(plr -> plr.license(expiredLicense).acknowledge(randomBoolean())); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.EXPIRED)); // get license should not return the expired license - GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(clusterAdmin(), GetLicenseAction.INSTANCE).get(); - assertThat(getLicenseResponse.license(), not(expiredLicense)); + assertThat(getLicense().license(), not(expiredLicense)); } public void testPutLicensesSimple() throws Exception { License goldSignedLicense = generateSignedLicense("gold", TimeValue.timeValueMinutes(5)); - PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(clusterAdmin()).setLicense(goldSignedLicense) - .setAcknowledge(true); - PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get(); - assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); - GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(clusterAdmin(), GetLicenseAction.INSTANCE).get(); - assertThat(getLicenseResponse.license(), equalTo(goldSignedLicense)); + final var putGoldLicenseResponse = putLicense(plr -> plr.license(goldSignedLicense).acknowledge(true)); + assertThat(putGoldLicenseResponse.status(), equalTo(LicensesStatus.VALID)); + assertThat(getLicense().license(), equalTo(goldSignedLicense)); License platinumSignedLicense = generateSignedLicense("platinum", TimeValue.timeValueMinutes(2)); - putLicenseRequestBuilder.setLicense(platinumSignedLicense); - putLicenseResponse = putLicenseRequestBuilder.get(); - assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); - assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); - getLicenseResponse = new GetLicenseRequestBuilder(clusterAdmin(), GetLicenseAction.INSTANCE).get(); - assertThat(getLicenseResponse.license(), equalTo(platinumSignedLicense)); + final var putPlatinumLicenseResponse = putLicense(plr -> plr.license(platinumSignedLicense).acknowledge(true)); + assertThat(putPlatinumLicenseResponse.isAcknowledged(), equalTo(true)); + assertThat(putPlatinumLicenseResponse.status(), equalTo(LicensesStatus.VALID)); + assertThat(getLicense().license(), equalTo(platinumSignedLicense)); } public void testRemoveLicensesSimple() throws Exception { License goldLicense = generateSignedLicense("gold", TimeValue.timeValueMinutes(5)); - PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(clusterAdmin()).setLicense(goldLicense) - .setAcknowledge(true); - PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get(); + PutLicenseResponse putLicenseResponse = putLicense(plr -> plr.license(goldLicense).acknowledge(true)); assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); - GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(clusterAdmin(), GetLicenseAction.INSTANCE).get(); - assertThat(getLicenseResponse.license(), equalTo(goldLicense)); + assertThat(getLicense().license(), equalTo(goldLicense)); // delete all licenses - AcknowledgedResponse deleteLicenseResponse = clusterAdmin().execute( - TransportDeleteLicenseAction.TYPE, - new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) - ).get(); + AcknowledgedResponse deleteLicenseResponse = deleteLicense(); assertThat(deleteLicenseResponse.isAcknowledged(), equalTo(true)); // get licenses (expected no licenses) - getLicenseResponse = new GetLicenseRequestBuilder(clusterAdmin(), GetLicenseAction.INSTANCE).get(); - assertTrue(License.LicenseType.isBasic(getLicenseResponse.license().type())); + assertTrue(License.LicenseType.isBasic(getLicense().license().type())); } public void testLicenseIsRejectWhenStartDateLaterThanNow() throws Exception { @@ -206,9 +174,7 @@ public void testLicenseIsRejectWhenStartDateLaterThanNow() throws Exception { .maxNodes(5); License license = TestUtils.generateSignedLicense(builder); - PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(clusterAdmin()).setLicense(license) - .setAcknowledge(true); - PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get(); + PutLicenseResponse putLicenseResponse = putLicense(plr -> plr.license(license).acknowledge(true)); assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.INVALID)); } @@ -227,10 +193,32 @@ public void testLicenseIsAcceptedWhenStartDateBeforeThanNow() throws Exception { .maxNodes(5); License license = TestUtils.generateSignedLicense(builder); - PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(clusterAdmin()).setLicense(license) - .setAcknowledge(true); - PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get(); + PutLicenseResponse putLicenseResponse = putLicense(plr -> plr.license(license).acknowledge(true)); assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); } + + private GetLicenseResponse getLicense() { + return safeGet(clusterAdmin().execute(GetLicenseAction.INSTANCE, new GetLicenseRequest(TEST_REQUEST_TIMEOUT))); + } + + private Future putLicenseFuture(UnaryOperator onRequest) { + return clusterAdmin().execute( + PutLicenseAction.INSTANCE, + onRequest.apply(new PutLicenseRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)) + ); + } + + private PutLicenseResponse putLicense(UnaryOperator onRequest) { + return safeGet(putLicenseFuture(onRequest)); + } + + private AcknowledgedResponse deleteLicense() { + return safeGet( + clusterAdmin().execute( + TransportDeleteLicenseAction.TYPE, + new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT) + ) + ); + } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/StartBasicLicenseTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/StartBasicLicenseTests.java index cdaa5a2f86be7..be46ccf5e6ce6 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/StartBasicLicenseTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/StartBasicLicenseTests.java @@ -20,6 +20,7 @@ import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE; import static org.elasticsearch.test.NodeRoles.addRoles; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; @ESIntegTestCase.ClusterScope(scope = SUITE) public class StartBasicLicenseTests extends AbstractLicensesIntegrationTestCase { @@ -38,38 +39,28 @@ protected Collection> nodePlugins() { } public void testStartBasicLicense() throws Exception { - LicensingClient licensingClient = new LicensingClient(client()); - License license = TestUtils.generateSignedLicense("trial", License.VERSION_CURRENT, -1, TimeValue.timeValueHours(24)); - licensingClient.preparePutLicense(license).get(); + generateAndPutTestLicense(); - assertBusy(() -> { - GetLicenseResponse getLicenseResponse = licensingClient.prepareGetLicense().get(); - assertEquals("trial", getLicenseResponse.license().type()); - }); + assertBusy(() -> assertEquals("trial", getLicense().license().type())); - GetBasicStatusResponse response = licensingClient.prepareGetStartBasic().get(); - assertTrue(response.isEligibleToStartBasic()); + assertTrue(getBasicStatus().isEligibleToStartBasic()); - PostStartBasicResponse startResponse = licensingClient.preparePostStartBasic().setAcknowledge(true).get(); + PostStartBasicResponse startResponse = startBasic(true); assertTrue(startResponse.isAcknowledged()); assertTrue(startResponse.getStatus().isBasicStarted()); - assertBusy(() -> { - GetLicenseResponse currentLicense = licensingClient.prepareGetLicense().get(); - assertEquals("basic", currentLicense.license().type()); - }); + assertBusy(() -> assertEquals("basic", getLicense().license().type())); - long expirationMillis = licensingClient.prepareGetLicense().get().license().expiryDate(); + long expirationMillis = getLicense().license().expiryDate(); assertEquals(LicenseSettings.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS, expirationMillis); - GetLicenseResponse licenseResponse = licensingClient.prepareGetLicense().get(); + GetLicenseResponse licenseResponse = getLicense(); assertEquals("basic", licenseResponse.license().type()); assertEquals(XPackInfoResponse.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS, licenseResponse.license().expiryDate()); - GetBasicStatusResponse response4 = licensingClient.prepareGetStartBasic().get(); - assertFalse(response4.isEligibleToStartBasic()); + assertFalse(getBasicStatus().isEligibleToStartBasic()); - PostStartBasicResponse response5 = licensingClient.preparePostStartBasic().setAcknowledge(true).get(); + PostStartBasicResponse response5 = startBasic(true); assertEquals(403, response5.status().getStatus()); assertFalse(response5.getStatus().isBasicStarted()); assertTrue(response5.isAcknowledged()); @@ -77,16 +68,11 @@ public void testStartBasicLicense() throws Exception { } public void testUnacknowledgedStartBasicLicense() throws Exception { - LicensingClient licensingClient = new LicensingClient(client()); - License license = TestUtils.generateSignedLicense("trial", License.VERSION_CURRENT, -1, TimeValue.timeValueHours(24)); - licensingClient.preparePutLicense(license).get(); + generateAndPutTestLicense(); - assertBusy(() -> { - GetLicenseResponse getLicenseResponse = licensingClient.prepareGetLicense().get(); - assertEquals("trial", getLicenseResponse.license().type()); - }); + assertBusy(() -> assertEquals("trial", getLicense().license().type())); - PostStartBasicResponse response = licensingClient.preparePostStartBasic().get(); + PostStartBasicResponse response = startBasic(false); assertEquals(200, response.status().getStatus()); assertFalse(response.isAcknowledged()); assertFalse(response.getStatus().isBasicStarted()); @@ -97,4 +83,29 @@ public void testUnacknowledgedStartBasicLicense() throws Exception { response.getAcknowledgeMessage() ); } + + private static GetBasicStatusResponse getBasicStatus() { + return safeGet(clusterAdmin().execute(GetBasicStatusAction.INSTANCE, new GetBasicStatusRequest(TEST_REQUEST_TIMEOUT))); + } + + private static PostStartBasicResponse startBasic(boolean acknowledged) { + return safeGet( + clusterAdmin().execute( + PostStartBasicAction.INSTANCE, + new PostStartBasicRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT).acknowledge(acknowledged) + ) + ); + } + + private static void generateAndPutTestLicense() throws Exception { + final var license = TestUtils.generateSignedLicense("trial", License.VERSION_CURRENT, -1, TimeValue.timeValueHours(24)); + assertAcked( + safeGet( + client().execute( + PutLicenseAction.INSTANCE, + new PutLicenseRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT).license(license).acknowledge(randomBoolean()) + ) + ) + ); + } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/StartTrialLicenseTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/StartTrialLicenseTests.java index bd9f058f88100..cd69ea7d1dc62 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/StartTrialLicenseTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/StartTrialLicenseTests.java @@ -6,6 +6,7 @@ */ package org.elasticsearch.license; +import org.elasticsearch.action.ActionFuture; import org.elasticsearch.cluster.node.DiscoveryNodeRole; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.plugins.Plugin; @@ -15,9 +16,11 @@ import java.util.Arrays; import java.util.Collection; import java.util.Set; +import java.util.function.UnaryOperator; import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE; import static org.elasticsearch.test.NodeRoles.addRoles; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.hamcrest.Matchers.containsString; @ESIntegTestCase.ClusterScope(scope = SUITE) @@ -37,74 +40,55 @@ protected Collection> nodePlugins() { } public void testStartTrial() throws Exception { - LicensingClient licensingClient = new LicensingClient(client()); ensureStartingWithBasic(); - GetTrialStatusResponse response = licensingClient.prepareGetStartTrial().get(); - assertTrue(response.isEligibleToStartTrial()); + assertTrue(getTrialStatus().isEligibleToStartTrial()); + + License.LicenseType type = randomFrom(LicenseSettings.VALID_TRIAL_TYPES); // Test that starting will fail without acknowledgement - PostStartTrialRequestBuilder builder = licensingClient.preparePostStartTrial(); - builder.request().setType(randomFrom(LicenseSettings.VALID_TRIAL_TYPES).getTypeName()); - PostStartTrialResponse response2 = builder.get(); + final PostStartTrialResponse response2 = startTrial(pstr -> pstr.setType(type.getTypeName())); assertEquals(200, response2.getStatus().getRestStatus().getStatus()); assertFalse(response2.getStatus().isTrialStarted()); assertEquals("Operation failed: Needs acknowledgement.", response2.getStatus().getErrorMessage()); - assertBusy(() -> { - GetLicenseResponse getLicenseResponse = licensingClient.prepareGetLicense().get(); - assertEquals("basic", getLicenseResponse.license().type()); - }); - - License.LicenseType type = randomFrom(LicenseSettings.VALID_TRIAL_TYPES); + assertBusy(() -> assertEquals("basic", getLicense().license().type())); - PostStartTrialRequestBuilder builder2 = licensingClient.preparePostStartTrial(); - builder2.setAcknowledge(true); - builder2.request().setType(type.getTypeName()); - PostStartTrialResponse response3 = builder2.get(); + final PostStartTrialResponse response3 = startTrial(pstr -> pstr.setType(type.getTypeName()).acknowledge(true)); assertEquals(200, response3.getStatus().getRestStatus().getStatus()); assertTrue(response3.getStatus().isTrialStarted()); - assertBusy(() -> { - GetLicenseResponse postTrialLicenseResponse = licensingClient.prepareGetLicense().get(); - assertEquals(type.getTypeName(), postTrialLicenseResponse.license().type()); - }); + assertBusy(() -> assertEquals(type.getTypeName(), getLicense().license().type())); - GetTrialStatusResponse response4 = licensingClient.prepareGetStartTrial().get(); - assertFalse(response4.isEligibleToStartTrial()); + assertFalse(getTrialStatus().isEligibleToStartTrial()); License.LicenseType secondAttemptType = randomFrom(LicenseSettings.VALID_TRIAL_TYPES); - - PostStartTrialRequestBuilder builder3 = licensingClient.preparePostStartTrial(); - builder3.setAcknowledge(true); - builder3.request().setType(secondAttemptType.getTypeName()); - PostStartTrialResponse response5 = builder3.get(); + PostStartTrialResponse response5 = startTrial(pstr -> pstr.setType(secondAttemptType.getTypeName()).acknowledge(true)); assertEquals(403, response5.getStatus().getRestStatus().getStatus()); assertFalse(response5.getStatus().isTrialStarted()); assertEquals("Operation failed: Trial was already activated.", response5.getStatus().getErrorMessage()); } public void testInvalidType() throws Exception { - LicensingClient licensingClient = new LicensingClient(client()); ensureStartingWithBasic(); - - PostStartTrialRequestBuilder builder = licensingClient.preparePostStartTrial(); - builder.request().setType("basic"); - IllegalArgumentException e = expectThrows(IllegalArgumentException.class, builder::get); + final var future = startTrialFuture(pstr -> pstr.setType("basic").acknowledge(randomBoolean())); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, future::actionGet); assertThat(e.getMessage(), containsString("Cannot start trial of type [basic]. Valid trial types are [")); } private void ensureStartingWithBasic() throws Exception { - LicensingClient licensingClient = new LicensingClient(client()); - GetLicenseResponse getLicenseResponse = licensingClient.prepareGetLicense().get(); - - if ("basic".equals(getLicenseResponse.license().type()) == false) { - licensingClient.preparePostStartBasic().setAcknowledge(true).get(); + if ("basic".equals(getLicense().license().type()) == false) { + assertAcked(startBasic()); } - assertBusy(() -> { - GetLicenseResponse postTrialLicenseResponse = licensingClient.prepareGetLicense().get(); - assertEquals("basic", postTrialLicenseResponse.license().type()); - }); + assertBusy(() -> assertEquals("basic", getLicense().license().type())); + } + + private ActionFuture startTrialFuture(UnaryOperator onRequest) { + return client().execute(PostStartTrialAction.INSTANCE, onRequest.apply(new PostStartTrialRequest(TEST_REQUEST_TIMEOUT))); + } + + private PostStartTrialResponse startTrial(UnaryOperator onRequest) { + return safeGet(startTrialFuture(onRequest)); } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/TestUtils.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/TestUtils.java index caf554015382d..14ec60dc931d3 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/license/TestUtils.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/license/TestUtils.java @@ -20,6 +20,7 @@ import org.elasticsearch.license.licensor.LicenseSigner; import org.elasticsearch.protocol.xpack.license.LicensesStatus; import org.elasticsearch.protocol.xpack.license.PutLicenseResponse; +import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.XContentFactory; @@ -381,7 +382,9 @@ public static void registerAndAckSignedLicenses( License license, final LicensesStatus expectedStatus ) { - PutLicenseRequest putLicenseRequest = new PutLicenseRequest().license(license).acknowledge(true); + PutLicenseRequest putLicenseRequest = new PutLicenseRequest(ESTestCase.TEST_REQUEST_TIMEOUT, ESTestCase.TEST_REQUEST_TIMEOUT) + .license(license) + .acknowledge(true); final CountDownLatch latch = new CountDownLatch(1); final AtomicReference status = new AtomicReference<>(); licenseService.registerLicense(putLicenseRequest, new ActionListener() { diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/XPackPluginTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/XPackPluginTests.java index d4c8dfa5fd0a7..ab6e7356a6e02 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/XPackPluginTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/XPackPluginTests.java @@ -18,6 +18,7 @@ import org.elasticsearch.common.component.LifecycleListener; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.PathUtils; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.env.Environment; import org.elasticsearch.license.ClusterStateLicenseService; import org.elasticsearch.license.License; @@ -211,7 +212,11 @@ class TestLicenseService implements MutableLicenseService { public void registerLicense(PutLicenseRequest request, ActionListener listener) {} @Override - public void removeLicense(ActionListener listener) {} + public void removeLicense( + TimeValue masterNodeTimeout, + TimeValue ackTimeout, + ActionListener listener + ) {} @Override public void startBasicLicense(PostStartBasicRequest request, ActionListener listener) {} diff --git a/x-pack/plugin/old-lucene-versions/src/internalClusterTest/java/org/elasticsearch/xpack/lucene/bwc/AbstractArchiveTestCase.java b/x-pack/plugin/old-lucene-versions/src/internalClusterTest/java/org/elasticsearch/xpack/lucene/bwc/AbstractArchiveTestCase.java index 206dfbe6729d6..803c7f410c41d 100644 --- a/x-pack/plugin/old-lucene-versions/src/internalClusterTest/java/org/elasticsearch/xpack/lucene/bwc/AbstractArchiveTestCase.java +++ b/x-pack/plugin/old-lucene-versions/src/internalClusterTest/java/org/elasticsearch/xpack/lucene/bwc/AbstractArchiveTestCase.java @@ -118,7 +118,8 @@ public void createAndRestoreArchive() throws Exception { assertAcked(client().admin().indices().prepareDelete(indexName)); - PostStartTrialRequest request = new PostStartTrialRequest().setType(License.LicenseType.TRIAL.getTypeName()).acknowledge(true); + PostStartTrialRequest request = new PostStartTrialRequest(TEST_REQUEST_TIMEOUT).setType(License.LicenseType.TRIAL.getTypeName()) + .acknowledge(true); client().execute(PostStartTrialAction.INSTANCE, request).get(); } } diff --git a/x-pack/plugin/old-lucene-versions/src/internalClusterTest/java/org/elasticsearch/xpack/lucene/bwc/ArchiveLicenseIntegTests.java b/x-pack/plugin/old-lucene-versions/src/internalClusterTest/java/org/elasticsearch/xpack/lucene/bwc/ArchiveLicenseIntegTests.java index 0489390a21352..048e259eca977 100644 --- a/x-pack/plugin/old-lucene-versions/src/internalClusterTest/java/org/elasticsearch/xpack/lucene/bwc/ArchiveLicenseIntegTests.java +++ b/x-pack/plugin/old-lucene-versions/src/internalClusterTest/java/org/elasticsearch/xpack/lucene/bwc/ArchiveLicenseIntegTests.java @@ -61,7 +61,9 @@ public void testFailRestoreOnInvalidLicense() throws Exception { client().execute(TransportDeleteLicenseAction.TYPE, new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)) .get() ); - assertAcked(client().execute(PostStartBasicAction.INSTANCE, new PostStartBasicRequest()).get()); + assertAcked( + client().execute(PostStartBasicAction.INSTANCE, new PostStartBasicRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)).get() + ); ensureClusterSizeConsistency(); ensureClusterStateConsistency(); @@ -100,7 +102,9 @@ public void testShardAllocationOnInvalidLicense() throws Exception { client().execute(TransportDeleteLicenseAction.TYPE, new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)) .get() ); - assertAcked(client().execute(PostStartBasicAction.INSTANCE, new PostStartBasicRequest()).get()); + assertAcked( + client().execute(PostStartBasicAction.INSTANCE, new PostStartBasicRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)).get() + ); ensureClusterSizeConsistency(); ensureClusterStateConsistency(); @@ -128,7 +132,8 @@ public void testShardAllocationOnInvalidLicense() throws Exception { waitNoPendingTasksOnAll(); ensureClusterStateConsistency(); - PostStartTrialRequest request = new PostStartTrialRequest().setType(License.LicenseType.TRIAL.getTypeName()).acknowledge(true); + PostStartTrialRequest request = new PostStartTrialRequest(TEST_REQUEST_TIMEOUT).setType(License.LicenseType.TRIAL.getTypeName()) + .acknowledge(true); final PostStartTrialResponse response = client().execute(PostStartTrialAction.INSTANCE, request).get(); assertThat( response.getStatus(), diff --git a/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsLicenseIntegTests.java b/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsLicenseIntegTests.java index 3a218e4ca5e97..1216db4b17608 100644 --- a/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsLicenseIntegTests.java +++ b/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsLicenseIntegTests.java @@ -82,7 +82,9 @@ public void createAndMountSearchableSnapshot() throws Exception { client().execute(TransportDeleteLicenseAction.TYPE, new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)) .get() ); - assertAcked(client().execute(PostStartBasicAction.INSTANCE, new PostStartBasicRequest()).get()); + assertAcked( + client().execute(PostStartBasicAction.INSTANCE, new PostStartBasicRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)).get() + ); ensureClusterSizeConsistency(); ensureClusterStateConsistency(); @@ -163,7 +165,8 @@ public void testShardAllocationOnInvalidLicense() throws Exception { waitNoPendingTasksOnAll(); ensureClusterStateConsistency(); - PostStartTrialRequest request = new PostStartTrialRequest().setType(License.LicenseType.TRIAL.getTypeName()).acknowledge(true); + PostStartTrialRequest request = new PostStartTrialRequest(TEST_REQUEST_TIMEOUT).setType(License.LicenseType.TRIAL.getTypeName()) + .acknowledge(true); final PostStartTrialResponse response = client().execute(PostStartTrialAction.INSTANCE, request).get(); assertThat( response.getStatus(), From 58cb500ba67a30878bf30559ab646641ef177001 Mon Sep 17 00:00:00 2001 From: David Turner Date: Wed, 29 May 2024 08:14:28 +0100 Subject: [PATCH 022/208] Fix trappy timeouts in enrich module (#109136) Relates #107984 --- .../api/enrich.delete_policy.json | 6 + .../api/enrich.execute_policy.json | 4 + .../rest-api-spec/api/enrich.get_policy.json | 6 + .../rest-api-spec/api/enrich.put_policy.json | 6 + .../rest-api-spec/api/enrich.stats.json | 6 + .../action/DeleteEnrichPolicyAction.java | 5 +- .../core/enrich/action/EnrichStatsAction.java | 4 +- .../action/ExecuteEnrichPolicyAction.java | 5 +- .../enrich/action/GetEnrichPolicyAction.java | 16 +- .../enrich/action/PutEnrichPolicyAction.java | 9 +- .../xpack/enrich/EnrichMultiNodeIT.java | 36 +++-- .../xpack/enrich/EnrichProcessorIT.java | 6 +- .../xpack/enrich/EnrichRestartIT.java | 8 +- .../xpack/enrich/EnrichPolicyExecutor.java | 2 +- .../action/InternalExecutePolicyAction.java | 5 +- .../rest/RestDeleteEnrichPolicyAction.java | 6 +- .../enrich/rest/RestEnrichStatsAction.java | 6 +- .../rest/RestExecuteEnrichPolicyAction.java | 6 +- .../rest/RestGetEnrichPolicyAction.java | 10 +- .../rest/RestPutEnrichPolicyAction.java | 3 +- .../xpack/enrich/BasicEnrichTests.java | 41 +++-- .../enrich/EnrichPolicyExecutorTests.java | 19 ++- .../xpack/enrich/EnrichPolicyUpdateTests.java | 9 +- .../xpack/enrich/EnrichResiliencyTests.java | 6 +- .../DeleteEnrichPolicyActionRequestTests.java | 2 +- ...ExecuteEnrichPolicyActionRequestTests.java | 2 +- .../GetEnrichPolicyActionRequestTests.java | 2 +- ...ternalExecutePolicyActionRequestTests.java | 4 +- .../PutEnrichPolicyActionRequestTests.java | 2 +- ...ransportDeleteEnrichPolicyActionTests.java | 144 +++++++++++------- .../TransportGetEnrichPolicyActionTests.java | 55 ++++--- .../esql/action/CrossClustersEnrichIT.java | 17 ++- .../xpack/esql/action/EnrichIT.java | 8 +- .../enrich/EnrichStatsCollector.java | 2 +- 34 files changed, 280 insertions(+), 188 deletions(-) diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.delete_policy.json b/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.delete_policy.json index 3137f6b555361..5c6b05a548987 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.delete_policy.json +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.delete_policy.json @@ -22,6 +22,12 @@ } } ] + }, + "params": { + "master_timeout":{ + "type":"time", + "description":"Timeout for processing on master node" + } } } } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.execute_policy.json b/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.execute_policy.json index 5e4c8a2251d1d..2add255148508 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.execute_policy.json +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.execute_policy.json @@ -28,6 +28,10 @@ "type":"boolean", "default":true, "description":"Should the request should block until the execution is complete." + }, + "master_timeout":{ + "type":"time", + "description":"Timeout for processing on master node" } } } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.get_policy.json b/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.get_policy.json index a3eb51942c4fa..aed7397877393 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.get_policy.json +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.get_policy.json @@ -26,6 +26,12 @@ "methods": [ "GET" ] } ] + }, + "params": { + "master_timeout":{ + "type":"time", + "description":"Timeout for processing on master node" + } } } } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.put_policy.json b/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.put_policy.json index 0d1cefd3e40aa..287c7d96dca9d 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.put_policy.json +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.put_policy.json @@ -27,6 +27,12 @@ "body": { "description": "The enrich policy to register", "required": true + }, + "params": { + "master_timeout":{ + "type":"time", + "description":"Timeout for processing on master node" + } } } } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.stats.json b/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.stats.json index b4218acf30eac..afd314a0dc804 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.stats.json +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/enrich.stats.json @@ -16,6 +16,12 @@ "methods": [ "GET" ] } ] + }, + "params": { + "master_timeout":{ + "type":"time", + "description":"Timeout for processing on master node" + } } } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/DeleteEnrichPolicyAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/DeleteEnrichPolicyAction.java index 82f98176838ee..64dcd5afcb544 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/DeleteEnrichPolicyAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/DeleteEnrichPolicyAction.java @@ -12,6 +12,7 @@ import org.elasticsearch.action.support.master.MasterNodeRequest; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; import java.util.Objects; @@ -29,8 +30,8 @@ public static class Request extends MasterNodeRequest { - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); + public Request(TimeValue masterNodeTimeout) { + super(masterNodeTimeout); } public Request(StreamInput in) throws IOException { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/ExecuteEnrichPolicyAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/ExecuteEnrichPolicyAction.java index 5d629365a8096..65bae5e94852c 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/ExecuteEnrichPolicyAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/ExecuteEnrichPolicyAction.java @@ -12,6 +12,7 @@ import org.elasticsearch.action.support.master.MasterNodeRequest; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.tasks.TaskId; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; @@ -33,8 +34,8 @@ public static class Request extends MasterNodeRequest { private final String name; private boolean waitForCompletion; - public Request(String name) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); + public Request(TimeValue masterNodeTimeout, String name) { + super(masterNodeTimeout); this.name = Objects.requireNonNull(name, "name cannot be null"); this.waitForCompletion = true; } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/GetEnrichPolicyAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/GetEnrichPolicyAction.java index 37851a3641ebd..7f138dec7ee23 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/GetEnrichPolicyAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/GetEnrichPolicyAction.java @@ -12,13 +12,12 @@ import org.elasticsearch.action.support.master.MasterNodeReadRequest; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xpack.core.enrich.EnrichPolicy; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; @@ -38,19 +37,14 @@ public static class Request extends MasterNodeReadRequest { private final List names; - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); - this.names = new ArrayList<>(); - } - - public Request(String[] names) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); - this.names = Arrays.asList(names); + public Request(TimeValue masterNodeTimeout, String... names) { + super(masterNodeTimeout); + this.names = List.of(names); } public Request(StreamInput in) throws IOException { super(in); - this.names = in.readStringCollectionAsList(); + this.names = in.readStringCollectionAsImmutableList(); } @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/PutEnrichPolicyAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/PutEnrichPolicyAction.java index d1031828e0522..6a6b6ff34d60d 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/PutEnrichPolicyAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/PutEnrichPolicyAction.java @@ -12,6 +12,7 @@ import org.elasticsearch.action.support.master.MasterNodeRequest; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xpack.core.enrich.EnrichPolicy; @@ -27,8 +28,8 @@ private PutEnrichPolicyAction() { super(NAME); } - public static Request fromXContent(XContentParser parser, String name) throws IOException { - return new Request(name, EnrichPolicy.fromXContent(parser)); + public static Request fromXContent(TimeValue masterNodeTimeout, XContentParser parser, String name) throws IOException { + return new Request(masterNodeTimeout, name, EnrichPolicy.fromXContent(parser)); } public static class Request extends MasterNodeRequest { @@ -36,8 +37,8 @@ public static class Request extends MasterNodeRequest> keys, String coordinatingNo } } - EnrichStatsAction.Response statsResponse = client().execute(EnrichStatsAction.INSTANCE, new EnrichStatsAction.Request()) - .actionGet(); + EnrichStatsAction.Response statsResponse = client().execute( + EnrichStatsAction.INSTANCE, + new EnrichStatsAction.Request(TEST_REQUEST_TIMEOUT) + ).actionGet(); assertThat(statsResponse.getCoordinatorStats().size(), equalTo(internalCluster().size())); String nodeId = getNodeId(coordinatingNode); CoordinatorStats stats = statsResponse.getCoordinatorStats().stream().filter(s -> s.nodeId().equals(nodeId)).findAny().get(); @@ -321,11 +327,11 @@ private static void createAndExecutePolicy(String policyName, String indexName) MATCH_FIELD, List.of(DECORATE_FIELDS) ); - PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(policyName, enrichPolicy); + PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName, enrichPolicy); client().execute(PutEnrichPolicyAction.INSTANCE, request).actionGet(); final ActionFuture policyExecuteFuture = client().execute( ExecuteEnrichPolicyAction.INSTANCE, - new ExecuteEnrichPolicyAction.Request(policyName) + new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName) ); // Make sure we can deserialize enrich policy execution task status final List tasks = clusterAdmin().prepareListTasks().setActions(EnrichPolicyExecutor.TASK_ACTION).get().getTasks(); diff --git a/x-pack/plugin/enrich/src/internalClusterTest/java/org/elasticsearch/xpack/enrich/EnrichProcessorIT.java b/x-pack/plugin/enrich/src/internalClusterTest/java/org/elasticsearch/xpack/enrich/EnrichProcessorIT.java index f3d2403ce5d96..d646aed11d7d9 100644 --- a/x-pack/plugin/enrich/src/internalClusterTest/java/org/elasticsearch/xpack/enrich/EnrichProcessorIT.java +++ b/x-pack/plugin/enrich/src/internalClusterTest/java/org/elasticsearch/xpack/enrich/EnrichProcessorIT.java @@ -49,7 +49,7 @@ protected Settings nodeSettings() { public void testEnrichCacheValuesCannotBeCorrupted() { // Ensure enrich cache is empty - var statsRequest = new EnrichStatsAction.Request(); + var statsRequest = new EnrichStatsAction.Request(TEST_REQUEST_TIMEOUT); var statsResponse = client().execute(EnrichStatsAction.INSTANCE, statsRequest).actionGet(); assertThat(statsResponse.getCacheStats().size(), equalTo(1)); assertThat(statsResponse.getCacheStats().get(0).count(), equalTo(0L)); @@ -85,9 +85,9 @@ public void testEnrichCacheValuesCannotBeCorrupted() { client().index(indexRequest).actionGet(); // Store policy and execute it: - var putPolicyRequest = new PutEnrichPolicyAction.Request(policyName, enrichPolicy); + var putPolicyRequest = new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName, enrichPolicy); client().execute(PutEnrichPolicyAction.INSTANCE, putPolicyRequest).actionGet(); - var executePolicyRequest = new ExecuteEnrichPolicyAction.Request(policyName); + var executePolicyRequest = new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName); client().execute(ExecuteEnrichPolicyAction.INSTANCE, executePolicyRequest).actionGet(); var simulatePipelineRequest = new SimulatePipelineRequest(new BytesArray(""" diff --git a/x-pack/plugin/enrich/src/internalClusterTest/java/org/elasticsearch/xpack/enrich/EnrichRestartIT.java b/x-pack/plugin/enrich/src/internalClusterTest/java/org/elasticsearch/xpack/enrich/EnrichRestartIT.java index 86d18bcbbbbc4..9a77bea4ab78a 100644 --- a/x-pack/plugin/enrich/src/internalClusterTest/java/org/elasticsearch/xpack/enrich/EnrichRestartIT.java +++ b/x-pack/plugin/enrich/src/internalClusterTest/java/org/elasticsearch/xpack/enrich/EnrichRestartIT.java @@ -60,7 +60,7 @@ public void testRestart() throws Exception { createSourceIndices(client(), enrichPolicy); for (int i = 0; i < numPolicies; i++) { String policyName = POLICY_NAME + i; - PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(policyName, enrichPolicy); + PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName, enrichPolicy); client().execute(PutEnrichPolicyAction.INSTANCE, request).actionGet(); } @@ -71,8 +71,10 @@ public void testRestart() throws Exception { } private static void verifyPolicies(int numPolicies, EnrichPolicy enrichPolicy) { - GetEnrichPolicyAction.Response response = client().execute(GetEnrichPolicyAction.INSTANCE, new GetEnrichPolicyAction.Request()) - .actionGet(); + GetEnrichPolicyAction.Response response = client().execute( + GetEnrichPolicyAction.INSTANCE, + new GetEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT) + ).actionGet(); assertThat(response.getPolicies(), hasSize(numPolicies)); for (int i = 0; i < numPolicies; i++) { String policyName = POLICY_NAME + i; diff --git a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/EnrichPolicyExecutor.java b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/EnrichPolicyExecutor.java index ecb03615307f9..2ebe268cc788d 100644 --- a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/EnrichPolicyExecutor.java +++ b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/EnrichPolicyExecutor.java @@ -85,7 +85,7 @@ public void coordinatePolicyExecution( String enrichIndexName = EnrichPolicy.getIndexName(request.getName(), nowTimestamp); Releasable policyLock = tryLockingPolicy(request.getName(), enrichIndexName); try { - Request internalRequest = new Request(request.getName(), enrichIndexName); + Request internalRequest = new Request(request.masterNodeTimeout(), request.getName(), enrichIndexName); internalRequest.setWaitForCompletion(request.isWaitForCompletion()); internalRequest.setParentTask(request.getParentTask()); client.execute(InternalExecutePolicyAction.INSTANCE, internalRequest, ActionListener.wrap(response -> { diff --git a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/action/InternalExecutePolicyAction.java b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/action/InternalExecutePolicyAction.java index 769a86c5ec5b1..ed28599da9fbb 100644 --- a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/action/InternalExecutePolicyAction.java +++ b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/action/InternalExecutePolicyAction.java @@ -22,6 +22,7 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.util.concurrent.EsExecutors; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.TaskAwareRequest; import org.elasticsearch.tasks.TaskCancelledException; @@ -68,8 +69,8 @@ public static class Request extends ExecuteEnrichPolicyAction.Request { private final String enrichIndexName; - public Request(String name, String enrichIndexName) { - super(name); + public Request(TimeValue masterNodeTimeout, String name, String enrichIndexName) { + super(masterNodeTimeout, name); this.enrichIndexName = enrichIndexName; } diff --git a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestDeleteEnrichPolicyAction.java b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestDeleteEnrichPolicyAction.java index 26597f86b833c..810ec48edee8e 100644 --- a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestDeleteEnrichPolicyAction.java +++ b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestDeleteEnrichPolicyAction.java @@ -9,12 +9,12 @@ import org.elasticsearch.client.internal.node.NodeClient; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestUtils; import org.elasticsearch.rest.Scope; import org.elasticsearch.rest.ServerlessScope; import org.elasticsearch.rest.action.RestToXContentListener; import org.elasticsearch.xpack.core.enrich.action.DeleteEnrichPolicyAction; -import java.io.IOException; import java.util.List; import static org.elasticsearch.rest.RestRequest.Method.DELETE; @@ -33,8 +33,8 @@ public String getName() { } @Override - protected RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) throws IOException { - final DeleteEnrichPolicyAction.Request request = new DeleteEnrichPolicyAction.Request(restRequest.param("name")); + protected RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) { + final var request = new DeleteEnrichPolicyAction.Request(RestUtils.getMasterNodeTimeout(restRequest), restRequest.param("name")); return channel -> client.execute(DeleteEnrichPolicyAction.INSTANCE, request, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestEnrichStatsAction.java b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestEnrichStatsAction.java index e666319b563ea..3d64e7c1380fe 100644 --- a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestEnrichStatsAction.java +++ b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestEnrichStatsAction.java @@ -9,12 +9,12 @@ import org.elasticsearch.client.internal.node.NodeClient; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestUtils; import org.elasticsearch.rest.Scope; import org.elasticsearch.rest.ServerlessScope; import org.elasticsearch.rest.action.RestToXContentListener; import org.elasticsearch.xpack.core.enrich.action.EnrichStatsAction; -import java.io.IOException; import java.util.List; import static org.elasticsearch.rest.RestRequest.Method.GET; @@ -33,8 +33,8 @@ public String getName() { } @Override - protected RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) throws IOException { - final EnrichStatsAction.Request request = new EnrichStatsAction.Request(); + protected RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) { + final var request = new EnrichStatsAction.Request(RestUtils.getMasterNodeTimeout(restRequest)); return channel -> client.execute(EnrichStatsAction.INSTANCE, request, new RestToXContentListener<>(channel)); } diff --git a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestExecuteEnrichPolicyAction.java b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestExecuteEnrichPolicyAction.java index 15f5bdb736621..523e0bf25a71f 100644 --- a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestExecuteEnrichPolicyAction.java +++ b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestExecuteEnrichPolicyAction.java @@ -9,12 +9,12 @@ import org.elasticsearch.client.internal.node.NodeClient; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestUtils; import org.elasticsearch.rest.Scope; import org.elasticsearch.rest.ServerlessScope; import org.elasticsearch.rest.action.RestToXContentListener; import org.elasticsearch.xpack.core.enrich.action.ExecuteEnrichPolicyAction; -import java.io.IOException; import java.util.List; import static org.elasticsearch.rest.RestRequest.Method.POST; @@ -34,8 +34,8 @@ public String getName() { } @Override - protected RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) throws IOException { - final ExecuteEnrichPolicyAction.Request request = new ExecuteEnrichPolicyAction.Request(restRequest.param("name")); + protected RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) { + final var request = new ExecuteEnrichPolicyAction.Request(RestUtils.getMasterNodeTimeout(restRequest), restRequest.param("name")); request.setWaitForCompletion(restRequest.paramAsBoolean("wait_for_completion", true)); return channel -> client.execute(ExecuteEnrichPolicyAction.INSTANCE, request, new RestToXContentListener<>(channel)); } diff --git a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestGetEnrichPolicyAction.java b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestGetEnrichPolicyAction.java index 79dcd9315652f..2fb9f63c1eb4a 100644 --- a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestGetEnrichPolicyAction.java +++ b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestGetEnrichPolicyAction.java @@ -10,12 +10,12 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestUtils; import org.elasticsearch.rest.Scope; import org.elasticsearch.rest.ServerlessScope; import org.elasticsearch.rest.action.RestToXContentListener; import org.elasticsearch.xpack.core.enrich.action.GetEnrichPolicyAction; -import java.io.IOException; import java.util.List; import static org.elasticsearch.rest.RestRequest.Method.GET; @@ -34,9 +34,11 @@ public String getName() { } @Override - protected RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) throws IOException { - String[] names = Strings.splitStringByCommaToArray(restRequest.param("name")); - final GetEnrichPolicyAction.Request request = new GetEnrichPolicyAction.Request(names); + protected RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) { + final var request = new GetEnrichPolicyAction.Request( + RestUtils.getMasterNodeTimeout(restRequest), + Strings.splitStringByCommaToArray(restRequest.param("name")) + ); return channel -> client.execute(GetEnrichPolicyAction.INSTANCE, request, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestPutEnrichPolicyAction.java b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestPutEnrichPolicyAction.java index fb1522441fe43..f172d2e0cf411 100644 --- a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestPutEnrichPolicyAction.java +++ b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/rest/RestPutEnrichPolicyAction.java @@ -9,6 +9,7 @@ import org.elasticsearch.client.internal.node.NodeClient; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestUtils; import org.elasticsearch.rest.Scope; import org.elasticsearch.rest.ServerlessScope; import org.elasticsearch.rest.action.RestToXContentListener; @@ -41,7 +42,7 @@ protected RestChannelConsumer prepareRequest(final RestRequest restRequest, fina static PutEnrichPolicyAction.Request createRequest(RestRequest restRequest) throws IOException { try (XContentParser parser = restRequest.contentOrSourceParamParser()) { - return PutEnrichPolicyAction.fromXContent(parser, restRequest.param("name")); + return PutEnrichPolicyAction.fromXContent(RestUtils.getMasterNodeTimeout(restRequest), parser, restRequest.param("name")); } } } diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/BasicEnrichTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/BasicEnrichTests.java index e3822b366e122..d17728fdd8037 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/BasicEnrichTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/BasicEnrichTests.java @@ -93,9 +93,10 @@ public void testIngestDataWithMatchProcessor() { MATCH_FIELD, List.of(DECORATE_FIELDS) ); - PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(policyName, enrichPolicy); + PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName, enrichPolicy); client().execute(PutEnrichPolicyAction.INSTANCE, request).actionGet(); - client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(policyName)).actionGet(); + client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName)) + .actionGet(); String pipelineName = "my-pipeline"; String pipelineBody = Strings.format(""" @@ -146,8 +147,10 @@ public void testIngestDataWithMatchProcessor() { } } - EnrichStatsAction.Response statsResponse = client().execute(EnrichStatsAction.INSTANCE, new EnrichStatsAction.Request()) - .actionGet(); + EnrichStatsAction.Response statsResponse = client().execute( + EnrichStatsAction.INSTANCE, + new EnrichStatsAction.Request(TEST_REQUEST_TIMEOUT) + ).actionGet(); assertThat(statsResponse.getCoordinatorStats().size(), equalTo(1)); String localNodeId = getInstanceFromNode(ClusterService.class).localNode().getId(); assertThat(statsResponse.getCoordinatorStats().get(0).nodeId(), equalTo(localNodeId)); @@ -186,9 +189,10 @@ public void testIngestDataWithGeoMatchProcessor() { matchField, List.of(enrichField) ); - PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(policyName, enrichPolicy); + PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName, enrichPolicy); client().execute(PutEnrichPolicyAction.INSTANCE, request).actionGet(); - client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(policyName)).actionGet(); + client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName)) + .actionGet(); String pipelineName = "my-pipeline"; String pipelineBody = Strings.format(""" @@ -226,8 +230,10 @@ public void testIngestDataWithGeoMatchProcessor() { assertThat(entries.containsKey(matchField), is(true)); assertThat(entries.get(enrichField), equalTo("94040")); - EnrichStatsAction.Response statsResponse = client().execute(EnrichStatsAction.INSTANCE, new EnrichStatsAction.Request()) - .actionGet(); + EnrichStatsAction.Response statsResponse = client().execute( + EnrichStatsAction.INSTANCE, + new EnrichStatsAction.Request(TEST_REQUEST_TIMEOUT) + ).actionGet(); assertThat(statsResponse.getCoordinatorStats().size(), equalTo(1)); String localNodeId = getInstanceFromNode(ClusterService.class).localNode().getId(); assertThat(statsResponse.getCoordinatorStats().get(0).nodeId(), equalTo(localNodeId)); @@ -246,9 +252,10 @@ public void testMultiplePolicies() { client().admin().indices().refresh(new RefreshRequest("source-" + i)).actionGet(); EnrichPolicy enrichPolicy = new EnrichPolicy(EnrichPolicy.MATCH_TYPE, null, List.of("source-" + i), "key", List.of("value")); - PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(policyName, enrichPolicy); + PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName, enrichPolicy); client().execute(PutEnrichPolicyAction.INSTANCE, request).actionGet(); - client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(policyName)).actionGet(); + client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName)) + .actionGet(); String pipelineName = "pipeline" + i; String pipelineBody = Strings.format(""" @@ -290,11 +297,11 @@ public void testAsyncTaskExecute() throws Exception { } EnrichPolicy enrichPolicy = new EnrichPolicy(EnrichPolicy.MATCH_TYPE, null, List.of(sourceIndexName), "key", List.of("value")); - PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(policyName, enrichPolicy); + PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName, enrichPolicy); client().execute(PutEnrichPolicyAction.INSTANCE, request).actionGet(); ExecuteEnrichPolicyAction.Response executeResponse = client().execute( ExecuteEnrichPolicyAction.INSTANCE, - new ExecuteEnrichPolicyAction.Request(policyName).setWaitForCompletion(false) + new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName).setWaitForCompletion(false) ).actionGet(); assertThat(executeResponse.getStatus(), is(nullValue())); @@ -346,9 +353,10 @@ public void testTemplating() throws Exception { MATCH_FIELD, List.of(DECORATE_FIELDS) ); - PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(policyName, enrichPolicy); + PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName, enrichPolicy); client().execute(PutEnrichPolicyAction.INSTANCE, request).actionGet(); - client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(policyName)).actionGet(); + client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName)) + .actionGet(); String pipelineName = "my-pipeline"; String pipelineBody = Strings.format( @@ -384,9 +392,10 @@ public void testFailureAfterEnrich() throws Exception { MATCH_FIELD, Arrays.asList(DECORATE_FIELDS) ); - PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(policyName, enrichPolicy); + PutEnrichPolicyAction.Request request = new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName, enrichPolicy); client().execute(PutEnrichPolicyAction.INSTANCE, request).actionGet(); - client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(policyName)).actionGet(); + client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policyName)) + .actionGet(); // A pipeline with a foreach that uses a non existing field that is specified after enrich has run: String pipelineName = "my-pipeline"; diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichPolicyExecutorTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichPolicyExecutorTests.java index 9f0b18679666b..06f9eb21fe2dc 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichPolicyExecutorTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichPolicyExecutorTests.java @@ -88,7 +88,7 @@ public void testNonConcurrentPolicyCoordination() throws InterruptedException { // Launch a fake policy run that will block until firstTaskBlock is counted down. final CountDownLatch firstTaskComplete = new CountDownLatch(1); testExecutor.coordinatePolicyExecution( - new ExecuteEnrichPolicyAction.Request(testPolicyName), + new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, testPolicyName), new LatchedActionListener<>(ActionListener.noop(), firstTaskComplete) ); @@ -97,7 +97,10 @@ public void testNonConcurrentPolicyCoordination() throws InterruptedException { EsRejectedExecutionException.class, "Expected exception but nothing was thrown", () -> { - testExecutor.coordinatePolicyExecution(new ExecuteEnrichPolicyAction.Request(testPolicyName), ActionListener.noop()); + testExecutor.coordinatePolicyExecution( + new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, testPolicyName), + ActionListener.noop() + ); // Should throw exception on the previous statement, but if it doesn't, be a // good citizen and conclude the fake runs to keep the logs clean from interrupted exceptions latch.countDown(); @@ -118,7 +121,7 @@ public void testNonConcurrentPolicyCoordination() throws InterruptedException { // Ensure that the lock from the previous run has been cleared CountDownLatch secondTaskComplete = new CountDownLatch(1); testExecutor.coordinatePolicyExecution( - new ExecuteEnrichPolicyAction.Request(testPolicyName), + new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, testPolicyName), new LatchedActionListener<>(ActionListener.noop(), secondTaskComplete) ); secondTaskComplete.await(); @@ -144,13 +147,13 @@ public void testMaximumPolicyExecutionLimit() throws InterruptedException { // Launch a two fake policy runs that will block until counted down to use up the maximum concurrent final CountDownLatch firstTaskComplete = new CountDownLatch(1); testExecutor.coordinatePolicyExecution( - new ExecuteEnrichPolicyAction.Request(testPolicyBaseName + "1"), + new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, testPolicyBaseName + "1"), new LatchedActionListener<>(ActionListener.noop(), firstTaskComplete) ); final CountDownLatch secondTaskComplete = new CountDownLatch(1); testExecutor.coordinatePolicyExecution( - new ExecuteEnrichPolicyAction.Request(testPolicyBaseName + "2"), + new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, testPolicyBaseName + "2"), new LatchedActionListener<>(ActionListener.noop(), secondTaskComplete) ); @@ -160,7 +163,7 @@ public void testMaximumPolicyExecutionLimit() throws InterruptedException { "Expected exception but nothing was thrown", () -> { testExecutor.coordinatePolicyExecution( - new ExecuteEnrichPolicyAction.Request(testPolicyBaseName + "3"), + new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, testPolicyBaseName + "3"), ActionListener.noop() ); // Should throw exception on the previous statement, but if it doesn't, be a @@ -188,7 +191,7 @@ public void testMaximumPolicyExecutionLimit() throws InterruptedException { assertThat(locks.lockedPolices(), is(empty())); CountDownLatch finalTaskComplete = new CountDownLatch(1); testExecutor.coordinatePolicyExecution( - new ExecuteEnrichPolicyAction.Request(testPolicyBaseName + "1"), + new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, testPolicyBaseName + "1"), new LatchedActionListener<>(ActionListener.noop(), finalTaskComplete) ); finalTaskComplete.await(); @@ -279,7 +282,7 @@ protected void // Launch a fake policy run that will block until firstTaskBlock is counted down. PlainActionFuture firstTaskResult = new PlainActionFuture<>(); testExecutor.coordinatePolicyExecution( - new ExecuteEnrichPolicyAction.Request(testPolicyName).setWaitForCompletion(false), + new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, testPolicyName).setWaitForCompletion(false), firstTaskResult ); diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichPolicyUpdateTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichPolicyUpdateTests.java index 1e4426661e06c..b015e97909179 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichPolicyUpdateTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichPolicyUpdateTests.java @@ -52,11 +52,11 @@ public void testUpdatePolicyOnly() { EnrichPolicy instance1 = new EnrichPolicy(EnrichPolicy.MATCH_TYPE, null, List.of("index"), "key1", List.of("field1")); createSourceIndices(client(), instance1); - PutEnrichPolicyAction.Request putPolicyRequest = new PutEnrichPolicyAction.Request("my_policy", instance1); + PutEnrichPolicyAction.Request putPolicyRequest = new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, "my_policy", instance1); assertAcked(client().execute(PutEnrichPolicyAction.INSTANCE, putPolicyRequest).actionGet()); assertThat( "Execute failed", - client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request("my_policy")) + client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, "my_policy")) .actionGet() .getStatus() .isCompleted(), @@ -74,7 +74,10 @@ public void testUpdatePolicyOnly() { createSourceIndices(client(), instance2); ResourceAlreadyExistsException exc = expectThrows( ResourceAlreadyExistsException.class, - client().execute(PutEnrichPolicyAction.INSTANCE, new PutEnrichPolicyAction.Request("my_policy", instance2)) + client().execute( + PutEnrichPolicyAction.INSTANCE, + new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, "my_policy", instance2) + ) ); assertTrue(exc.getMessage().contains("policy [my_policy] already exists")); } diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichResiliencyTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichResiliencyTests.java index 6c62d7a315872..3a2bfd87cff14 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichResiliencyTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichResiliencyTests.java @@ -80,6 +80,7 @@ public void testWriteThreadLivenessBackToBack() throws Exception { client().execute( PutEnrichPolicyAction.INSTANCE, new PutEnrichPolicyAction.Request( + TEST_REQUEST_TIMEOUT, enrichPolicyName, new EnrichPolicy(EnrichPolicy.MATCH_TYPE, null, List.of(enrichIndexName), "my_key", List.of("my_value")) ) @@ -87,7 +88,7 @@ public void testWriteThreadLivenessBackToBack() throws Exception { client().execute( ExecuteEnrichPolicyAction.INSTANCE, - new ExecuteEnrichPolicyAction.Request(enrichPolicyName).setWaitForCompletion(true) + new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, enrichPolicyName).setWaitForCompletion(true) ).actionGet(); XContentBuilder pipe1 = JsonXContent.contentBuilder(); @@ -179,6 +180,7 @@ public void testWriteThreadLivenessWithPipeline() throws Exception { client().execute( PutEnrichPolicyAction.INSTANCE, new PutEnrichPolicyAction.Request( + TEST_REQUEST_TIMEOUT, enrichPolicyName, new EnrichPolicy(EnrichPolicy.MATCH_TYPE, null, List.of(enrichIndexName), "my_key", List.of("my_value")) ) @@ -186,7 +188,7 @@ public void testWriteThreadLivenessWithPipeline() throws Exception { client().execute( ExecuteEnrichPolicyAction.INSTANCE, - new ExecuteEnrichPolicyAction.Request(enrichPolicyName).setWaitForCompletion(true) + new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, enrichPolicyName).setWaitForCompletion(true) ).actionGet(); XContentBuilder pipe1 = JsonXContent.contentBuilder(); diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/DeleteEnrichPolicyActionRequestTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/DeleteEnrichPolicyActionRequestTests.java index 2e778d6b62215..e9cd348bf595e 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/DeleteEnrichPolicyActionRequestTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/DeleteEnrichPolicyActionRequestTests.java @@ -13,7 +13,7 @@ public class DeleteEnrichPolicyActionRequestTests extends AbstractWireSerializingTestCase { @Override protected DeleteEnrichPolicyAction.Request createTestInstance() { - return new DeleteEnrichPolicyAction.Request(randomAlphaOfLength(4)); + return new DeleteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, randomAlphaOfLength(4)); } @Override diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/ExecuteEnrichPolicyActionRequestTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/ExecuteEnrichPolicyActionRequestTests.java index a945f49ac97d2..08d156e1012cf 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/ExecuteEnrichPolicyActionRequestTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/ExecuteEnrichPolicyActionRequestTests.java @@ -14,7 +14,7 @@ public class ExecuteEnrichPolicyActionRequestTests extends AbstractWireSerializi @Override protected ExecuteEnrichPolicyAction.Request createTestInstance() { - return new ExecuteEnrichPolicyAction.Request(randomAlphaOfLength(3)); + return new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, randomAlphaOfLength(3)); } @Override diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/GetEnrichPolicyActionRequestTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/GetEnrichPolicyActionRequestTests.java index f84b72727bca3..051eadac48467 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/GetEnrichPolicyActionRequestTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/GetEnrichPolicyActionRequestTests.java @@ -14,7 +14,7 @@ public class GetEnrichPolicyActionRequestTests extends AbstractWireSerializingTe @Override protected GetEnrichPolicyAction.Request createTestInstance() { - return new GetEnrichPolicyAction.Request(generateRandomStringArray(0, 4, false)); + return new GetEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, generateRandomStringArray(0, 4, false)); } @Override diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/InternalExecutePolicyActionRequestTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/InternalExecutePolicyActionRequestTests.java index 1a7bf20466ca1..68d0517a28404 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/InternalExecutePolicyActionRequestTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/InternalExecutePolicyActionRequestTests.java @@ -19,7 +19,7 @@ protected Writeable.Reader instanceReader() { @Override protected Request createTestInstance() { - Request request = new Request(randomAlphaOfLength(3), randomAlphaOfLength(5)); + Request request = new Request(TEST_REQUEST_TIMEOUT, randomAlphaOfLength(3), randomAlphaOfLength(5)); if (randomBoolean()) { request.setWaitForCompletion(true); } @@ -39,7 +39,7 @@ protected Request mutateInstance(Request instance) { default -> throw new AssertionError("Illegal randomisation branch"); } - Request request = new Request(policyName, enrichIndexName); + Request request = new Request(TEST_REQUEST_TIMEOUT, policyName, enrichIndexName); request.setWaitForCompletion(waitForCompletion); return request; } diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/PutEnrichPolicyActionRequestTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/PutEnrichPolicyActionRequestTests.java index 7675524435d26..c2f698c323004 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/PutEnrichPolicyActionRequestTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/PutEnrichPolicyActionRequestTests.java @@ -19,7 +19,7 @@ public class PutEnrichPolicyActionRequestTests extends AbstractWireSerializingTe @Override protected PutEnrichPolicyAction.Request createTestInstance() { final EnrichPolicy policy = randomEnrichPolicy(XContentType.JSON); - return new PutEnrichPolicyAction.Request(randomAlphaOfLength(3), policy); + return new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, randomAlphaOfLength(3), policy); } @Override diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/TransportDeleteEnrichPolicyActionTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/TransportDeleteEnrichPolicyActionTests.java index 84700308662b9..32f39b0de1ef4 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/TransportDeleteEnrichPolicyActionTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/TransportDeleteEnrichPolicyActionTests.java @@ -60,17 +60,22 @@ public void testDeletePolicyDoesNotExistUnlocksPolicy() throws InterruptedExcept final CountDownLatch latch = new CountDownLatch(1); final AtomicReference reference = new AtomicReference<>(); final TransportDeleteEnrichPolicyAction transportAction = node().injector().getInstance(TransportDeleteEnrichPolicyAction.class); - ActionTestUtils.execute(transportAction, null, new DeleteEnrichPolicyAction.Request(fakeId), new ActionListener<>() { - @Override - public void onResponse(AcknowledgedResponse acknowledgedResponse) { - fail(); - } + ActionTestUtils.execute( + transportAction, + null, + new DeleteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, fakeId), + new ActionListener<>() { + @Override + public void onResponse(AcknowledgedResponse acknowledgedResponse) { + fail(); + } - public void onFailure(final Exception e) { - reference.set(e); - latch.countDown(); + public void onFailure(final Exception e) { + reference.set(e); + latch.countDown(); + } } - }); + ); latch.await(); assertNotNull(reference.get()); assertThat(reference.get(), instanceOf(ResourceNotFoundException.class)); @@ -92,17 +97,22 @@ public void testDeleteWithoutIndex() throws Exception { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference reference = new AtomicReference<>(); final TransportDeleteEnrichPolicyAction transportAction = node().injector().getInstance(TransportDeleteEnrichPolicyAction.class); - ActionTestUtils.execute(transportAction, null, new DeleteEnrichPolicyAction.Request(name), new ActionListener<>() { - @Override - public void onResponse(AcknowledgedResponse acknowledgedResponse) { - reference.set(acknowledgedResponse); - latch.countDown(); - } + ActionTestUtils.execute( + transportAction, + null, + new DeleteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, name), + new ActionListener<>() { + @Override + public void onResponse(AcknowledgedResponse acknowledgedResponse) { + reference.set(acknowledgedResponse); + latch.countDown(); + } - public void onFailure(final Exception e) { - fail(); + public void onFailure(final Exception e) { + fail(); + } } - }); + ); latch.await(); assertNotNull(reference.get()); assertTrue(reference.get().isAcknowledged()); @@ -137,17 +147,22 @@ public void testDeleteIsNotLocked() throws Exception { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference reference = new AtomicReference<>(); final TransportDeleteEnrichPolicyAction transportAction = node().injector().getInstance(TransportDeleteEnrichPolicyAction.class); - ActionTestUtils.execute(transportAction, null, new DeleteEnrichPolicyAction.Request(name), new ActionListener<>() { - @Override - public void onResponse(AcknowledgedResponse acknowledgedResponse) { - reference.set(acknowledgedResponse); - latch.countDown(); - } + ActionTestUtils.execute( + transportAction, + null, + new DeleteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, name), + new ActionListener<>() { + @Override + public void onResponse(AcknowledgedResponse acknowledgedResponse) { + reference.set(acknowledgedResponse); + latch.countDown(); + } - public void onFailure(final Exception e) { - fail(); + public void onFailure(final Exception e) { + fail(); + } } - }); + ); latch.await(); assertNotNull(reference.get()); assertTrue(reference.get().isAcknowledged()); @@ -188,17 +203,22 @@ public void testDeleteLocked() throws InterruptedException { { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference reference = new AtomicReference<>(); - ActionTestUtils.execute(transportAction, null, new DeleteEnrichPolicyAction.Request(name), new ActionListener<>() { - @Override - public void onResponse(AcknowledgedResponse acknowledgedResponse) { - fail(); - } - - public void onFailure(final Exception e) { - reference.set(e); - latch.countDown(); + ActionTestUtils.execute( + transportAction, + null, + new DeleteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, name), + new ActionListener<>() { + @Override + public void onResponse(AcknowledgedResponse acknowledgedResponse) { + fail(); + } + + public void onFailure(final Exception e) { + reference.set(e); + latch.countDown(); + } } - }); + ); latch.await(); assertNotNull(reference.get()); assertThat(reference.get(), instanceOf(EsRejectedExecutionException.class)); @@ -214,17 +234,22 @@ public void onFailure(final Exception e) { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference reference = new AtomicReference<>(); - ActionTestUtils.execute(transportAction, null, new DeleteEnrichPolicyAction.Request(name), new ActionListener<>() { - @Override - public void onResponse(AcknowledgedResponse acknowledgedResponse) { - reference.set(acknowledgedResponse); - latch.countDown(); - } - - public void onFailure(final Exception e) { - fail(); + ActionTestUtils.execute( + transportAction, + null, + new DeleteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, name), + new ActionListener<>() { + @Override + public void onResponse(AcknowledgedResponse acknowledgedResponse) { + reference.set(acknowledgedResponse); + latch.countDown(); + } + + public void onFailure(final Exception e) { + fail(); + } } - }); + ); latch.await(); assertNotNull(reference.get()); assertTrue(reference.get().isAcknowledged()); @@ -256,17 +281,22 @@ public void testDeletePolicyPrefixes() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference reference = new AtomicReference<>(); - ActionTestUtils.execute(transportAction, null, new DeleteEnrichPolicyAction.Request(name), new ActionListener<>() { - @Override - public void onResponse(AcknowledgedResponse acknowledgedResponse) { - reference.set(acknowledgedResponse); - latch.countDown(); - } - - public void onFailure(final Exception e) { - fail(); + ActionTestUtils.execute( + transportAction, + null, + new DeleteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, name), + new ActionListener<>() { + @Override + public void onResponse(AcknowledgedResponse acknowledgedResponse) { + reference.set(acknowledgedResponse); + latch.countDown(); + } + + public void onFailure(final Exception e) { + fail(); + } } - }); + ); latch.await(); assertNotNull(reference.get()); assertTrue(reference.get().isAcknowledged()); diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/TransportGetEnrichPolicyActionTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/TransportGetEnrichPolicyActionTests.java index 1a95627e9438d..6a3c1eb2555b1 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/TransportGetEnrichPolicyActionTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/TransportGetEnrichPolicyActionTests.java @@ -34,7 +34,7 @@ public void cleanupPolicies() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference reference = new AtomicReference<>(); final TransportGetEnrichPolicyAction transportAction = node().injector().getInstance(TransportGetEnrichPolicyAction.class); - ActionTestUtils.execute(transportAction, null, new GetEnrichPolicyAction.Request(), new ActionListener<>() { + ActionTestUtils.execute(transportAction, null, new GetEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT), new ActionListener<>() { @Override public void onResponse(GetEnrichPolicyAction.Response response) { reference.set(response); @@ -74,24 +74,18 @@ public void testListPolicies() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference reference = new AtomicReference<>(); final TransportGetEnrichPolicyAction transportAction = node().injector().getInstance(TransportGetEnrichPolicyAction.class); - ActionTestUtils.execute( - transportAction, - null, - // empty or null should return the same - randomBoolean() ? new GetEnrichPolicyAction.Request() : new GetEnrichPolicyAction.Request(new String[] {}), - new ActionListener<>() { - @Override - public void onResponse(GetEnrichPolicyAction.Response response) { - reference.set(response); - latch.countDown(); + ActionTestUtils.execute(transportAction, null, new GetEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT), new ActionListener<>() { + @Override + public void onResponse(GetEnrichPolicyAction.Response response) { + reference.set(response); + latch.countDown(); - } + } - public void onFailure(final Exception e) { - fail(); - } + public void onFailure(final Exception e) { + fail(); } - ); + }); latch.await(); assertNotNull(reference.get()); GetEnrichPolicyAction.Response response = reference.get(); @@ -107,7 +101,7 @@ public void testListEmptyPolicies() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference reference = new AtomicReference<>(); final TransportGetEnrichPolicyAction transportAction = node().injector().getInstance(TransportGetEnrichPolicyAction.class); - ActionTestUtils.execute(transportAction, null, new GetEnrichPolicyAction.Request(), new ActionListener<>() { + ActionTestUtils.execute(transportAction, null, new GetEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT), new ActionListener<>() { @Override public void onResponse(GetEnrichPolicyAction.Response response) { reference.set(response); @@ -141,17 +135,22 @@ public void testGetPolicy() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference reference = new AtomicReference<>(); final TransportGetEnrichPolicyAction transportAction = node().injector().getInstance(TransportGetEnrichPolicyAction.class); - ActionTestUtils.execute(transportAction, null, new GetEnrichPolicyAction.Request(new String[] { name }), new ActionListener<>() { - @Override - public void onResponse(GetEnrichPolicyAction.Response response) { - reference.set(response); - latch.countDown(); - } + ActionTestUtils.execute( + transportAction, + null, + new GetEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, name), + new ActionListener<>() { + @Override + public void onResponse(GetEnrichPolicyAction.Response response) { + reference.set(response); + latch.countDown(); + } - public void onFailure(final Exception e) { - fail(); + public void onFailure(final Exception e) { + fail(); + } } - }); + ); latch.await(); assertNotNull(reference.get()); GetEnrichPolicyAction.Response response = reference.get(); @@ -186,7 +185,7 @@ public void testGetMultiplePolicies() throws InterruptedException { ActionTestUtils.execute( transportAction, null, - new GetEnrichPolicyAction.Request(new String[] { name, anotherName }), + new GetEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, name, anotherName), new ActionListener<>() { @Override public void onResponse(GetEnrichPolicyAction.Response response) { @@ -220,7 +219,7 @@ public void testGetPolicyThrowsError() throws InterruptedException { ActionTestUtils.execute( transportAction, null, - new GetEnrichPolicyAction.Request(new String[] { "non-exists" }), + new GetEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, "non-exists"), new ActionListener<>() { @Override public void onResponse(GetEnrichPolicyAction.Response response) { diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersEnrichIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersEnrichIT.java index 12708fb626c36..147e62f7ee3bc 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersEnrichIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersEnrichIT.java @@ -118,8 +118,10 @@ public void setupHostsEnrich() { client.prepareIndex("hosts").setSource("ip", h.getKey(), "os", h.getValue()).get(); } client.admin().indices().prepareRefresh("hosts").get(); - client.execute(PutEnrichPolicyAction.INSTANCE, new PutEnrichPolicyAction.Request("hosts", hostPolicy)).actionGet(); - client.execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request("hosts")).actionGet(); + client.execute(PutEnrichPolicyAction.INSTANCE, new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, "hosts", hostPolicy)) + .actionGet(); + client.execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, "hosts")) + .actionGet(); assertAcked(client.admin().indices().prepareDelete("hosts")); } } @@ -137,8 +139,10 @@ public void setupVendorPolicy() { client.prepareIndex("vendors").setSource("os", v.getKey(), "vendor", v.getValue()).get(); } client.admin().indices().prepareRefresh("vendors").get(); - client.execute(PutEnrichPolicyAction.INSTANCE, new PutEnrichPolicyAction.Request("vendors", vendorPolicy)).actionGet(); - client.execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request("vendors")).actionGet(); + client.execute(PutEnrichPolicyAction.INSTANCE, new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, "vendors", vendorPolicy)) + .actionGet(); + client.execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, "vendors")) + .actionGet(); assertAcked(client.admin().indices().prepareDelete("vendors")); } } @@ -195,7 +199,10 @@ public void wipeEnrichPolicies() { for (String cluster : allClusters()) { cluster(cluster).wipe(Set.of()); for (String policy : List.of("hosts", "vendors")) { - client(cluster).execute(DeleteEnrichPolicyAction.INSTANCE, new DeleteEnrichPolicyAction.Request(policy)); + client(cluster).execute( + DeleteEnrichPolicyAction.INSTANCE, + new DeleteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, policy) + ); } } } diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EnrichIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EnrichIT.java index 1298e3374665b..5806cb8ef0982 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EnrichIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EnrichIT.java @@ -166,15 +166,17 @@ record Song(String id, String title, String artist, double length) { client().prepareIndex("songs").setSource("song_id", s.id, "title", s.title, "artist", s.artist, "length", s.length).get(); } client().admin().indices().prepareRefresh("songs").get(); - client().execute(PutEnrichPolicyAction.INSTANCE, new PutEnrichPolicyAction.Request("songs", policy)).actionGet(); - client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request("songs")).actionGet(); + client().execute(PutEnrichPolicyAction.INSTANCE, new PutEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, "songs", policy)) + .actionGet(); + client().execute(ExecuteEnrichPolicyAction.INSTANCE, new ExecuteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, "songs")) + .actionGet(); assertAcked(client().admin().indices().prepareDelete("songs")); } @After public void cleanEnrichPolicies() { cluster().wipe(Set.of()); - client().execute(DeleteEnrichPolicyAction.INSTANCE, new DeleteEnrichPolicyAction.Request("songs")); + client().execute(DeleteEnrichPolicyAction.INSTANCE, new DeleteEnrichPolicyAction.Request(TEST_REQUEST_TIMEOUT, "songs")); } @Before diff --git a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/collector/enrich/EnrichStatsCollector.java b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/collector/enrich/EnrichStatsCollector.java index 234bc8f72a52b..b9743f022da84 100644 --- a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/collector/enrich/EnrichStatsCollector.java +++ b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/collector/enrich/EnrichStatsCollector.java @@ -52,7 +52,7 @@ protected Collection doCollect(MonitoringDoc.Node node, long inte final long timestamp = timestamp(); final String clusterUuid = clusterUuid(clusterState); - final EnrichStatsAction.Request request = new EnrichStatsAction.Request(); + final EnrichStatsAction.Request request = new EnrichStatsAction.Request(getCollectionTimeout()); final EnrichStatsAction.Response response = client.execute(EnrichStatsAction.INSTANCE, request) .actionGet(getCollectionTimeout()); From e622101ac97496281f8bf87e537e1e0b4db30b9a Mon Sep 17 00:00:00 2001 From: Artem Prigoda Date: Wed, 29 May 2024 09:15:02 +0200 Subject: [PATCH 023/208] Fix TasksIT#testGetTaskWaitForCompletionWithoutStoringResult (#108094) It seems that the failure (the missed index) has always existed in the test scenario and it's supposed to be handled by TransportGetTaskAction.java. We catch IndexNotFoundException here and convert it to ResourceNotFoundException. Then we catch ResourceNotFoundException here and return a snapshot of a task as a response. In the stack trace, getFinishedTaskFromIndex was called from getRunningTaskFromNode, not from waitedForCompletion due to a race between creating a get request and unblocking request which are sent asynchronously. I've changed the waitForCompletionTestCase test method to unblock the task only after the request started waiting for the task completion by registering a removal listener. By doing so, we make sure we test the "wait for completion" branch when task is running. The part about the missed index seems to irrelevant, since waitedForCompletion is able to suppress the error and return a snapshot of running task which is not possible if getFinishedTaskFromIndex gets called directly from getRunningTaskFromNode. Resolves #107823 --- .../admin/cluster/node/tasks/TasksIT.java | 35 ++++++++++++------- .../tasks/get/TransportGetTaskAction.java | 14 ++++++-- .../test/tasks/MockTaskManager.java | 13 +++++++ .../test/tasks/MockTaskManagerListener.java | 3 ++ 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/node/tasks/TasksIT.java b/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/node/tasks/TasksIT.java index 8011be1d69a04..5ea1b869f417e 100644 --- a/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/node/tasks/TasksIT.java +++ b/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/node/tasks/TasksIT.java @@ -41,6 +41,7 @@ import org.elasticsearch.persistent.PersistentTasksCustomMetadata; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.tasks.RemovedTaskListener; import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.TaskCancelledException; import org.elasticsearch.tasks.TaskId; @@ -599,24 +600,32 @@ private void waitForCompletionTestCase(boolean storeResult, Function client().execute(TEST_TASK_ACTION, request) ); - ActionFuture waitResponseFuture; + var tasks = clusterAdmin().prepareListTasks().setActions(TEST_TASK_ACTION.name()).get().getTasks(); + assertThat(tasks, hasSize(1)); + TaskId taskId = tasks.get(0).taskId(); + clusterAdmin().prepareGetTask(taskId).get(); + + var taskManager = (MockTaskManager) internalCluster().getInstance( + TransportService.class, + clusterService().state().getNodes().resolveNode(taskId.getNodeId()).getName() + ).getTaskManager(); + var listener = new MockTaskManagerListener() { + @Override + public void onRemovedTaskListenerRegistered(RemovedTaskListener removedTaskListener) { + // Unblock the request only after it started waiting for task completion + client().execute(UNBLOCK_TASK_ACTION, new TestTaskPlugin.UnblockTestTasksRequest()); + } + }; + taskManager.addListener(listener); try { - var tasks = clusterAdmin().prepareListTasks().setActions(TEST_TASK_ACTION.name()).get().getTasks(); - assertThat(tasks, hasSize(1)); - var taskId = tasks.get(0).taskId(); - clusterAdmin().prepareGetTask(taskId).get(); - // Spin up a request to wait for the test task to finish - waitResponseFuture = wait.apply(taskId); + // The task will be unblocked as soon as the request started waiting for task completion + T waitResponse = wait.apply(taskId).get(); + validator.accept(waitResponse); } finally { - // Unblock the request so the wait for completion request can finish - client().execute(UNBLOCK_TASK_ACTION, new TestTaskPlugin.UnblockTestTasksRequest()).get(); + taskManager.removeListener(listener); } - // Now that the task is unblocked the list response will come back - T waitResponse = waitResponseFuture.get(); - validator.accept(waitResponse); - TestTaskPlugin.NodesResponse response = future.get(); assertEquals(emptyList(), response.failures()); } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/node/tasks/get/TransportGetTaskAction.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/node/tasks/get/TransportGetTaskAction.java index c8b33e6d569d2..85de3c65c798e 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/node/tasks/get/TransportGetTaskAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/node/tasks/get/TransportGetTaskAction.java @@ -141,9 +141,17 @@ void getRunningTaskFromNode(Task thisTask, GetTaskRequest request, ActionListene } else { if (request.getWaitForCompletion()) { final ListenableActionFuture future = new ListenableActionFuture<>(); - RemovedTaskListener removedTaskListener = task -> { - if (task.equals(runningTask)) { - future.onResponse(null); + RemovedTaskListener removedTaskListener = new RemovedTaskListener() { + @Override + public void onRemoved(Task task) { + if (task.equals(runningTask)) { + future.onResponse(null); + } + } + + @Override + public String toString() { + return "Waiting for task completion " + runningTask; } }; taskManager.registerRemovedTaskListener(removedTaskListener); diff --git a/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManager.java b/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManager.java index be2c0c332e41c..599868ab7f1f9 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManager.java +++ b/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManager.java @@ -13,6 +13,7 @@ import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.tasks.RemovedTaskListener; import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.TaskAwareRequest; import org.elasticsearch.tasks.TaskManager; @@ -84,4 +85,16 @@ public void addListener(MockTaskManagerListener listener) { public void removeListener(MockTaskManagerListener listener) { listeners.remove(listener); } + + @Override + public void registerRemovedTaskListener(RemovedTaskListener removedTaskListener) { + super.registerRemovedTaskListener(removedTaskListener); + for (MockTaskManagerListener listener : listeners) { + try { + listener.onRemovedTaskListenerRegistered(removedTaskListener); + } catch (Exception e) { + logger.warn("failed to notify task manager listener about a registered removed task listener", e); + } + } + } } diff --git a/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManagerListener.java b/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManagerListener.java index 4bebfae914219..1f915f26db70f 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManagerListener.java +++ b/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManagerListener.java @@ -8,6 +8,7 @@ package org.elasticsearch.test.tasks; +import org.elasticsearch.tasks.RemovedTaskListener; import org.elasticsearch.tasks.Task; /** @@ -17,4 +18,6 @@ public interface MockTaskManagerListener { default void onTaskRegistered(Task task) {}; default void onTaskUnregistered(Task task) {}; + + default void onRemovedTaskListenerRegistered(RemovedTaskListener removedTaskListener) {}; } From d9e6f5452e1bcad67c805570adf033e37865cfdf Mon Sep 17 00:00:00 2001 From: Jedr Blaszyk Date: Wed, 29 May 2024 10:34:51 +0200 Subject: [PATCH 024/208] [Connector API] Fix bug with with wrong target index for access control sync (#109097) --- docs/changelog/109097.yaml | 6 ++++++ .../sync_job/10_connector_sync_job_post.yml | 21 +++++++++++++++++++ .../application/connector/Connector.java | 5 +++++ .../connector/ConnectorTemplateRegistry.java | 1 + .../syncjob/ConnectorSyncJobIndexService.java | 12 +++++++---- .../ConnectorSyncJobIndexServiceTests.java | 13 ++++++++++++ 6 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 docs/changelog/109097.yaml diff --git a/docs/changelog/109097.yaml b/docs/changelog/109097.yaml new file mode 100644 index 0000000000000..a7520f4eaa9be --- /dev/null +++ b/docs/changelog/109097.yaml @@ -0,0 +1,6 @@ +pr: 109097 +summary: "[Connector API] Fix bug with with wrong target index for access control\ + \ sync" +area: Application +type: bug +issues: [] diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/sync_job/10_connector_sync_job_post.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/sync_job/10_connector_sync_job_post.yml index e703b153dd3bb..8a384eee6bb93 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/sync_job/10_connector_sync_job_post.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/sync_job/10_connector_sync_job_post.yml @@ -275,6 +275,27 @@ setup: - exists: created_at - exists: last_seen +--- +'Create access control sync job - expect prefixed connector index name': + - do: + connector.sync_job_post: + body: + id: test-connector + job_type: access_control + + - set: { id: id } + + - match: { id: $id } + + - do: + connector.sync_job_get: + connector_sync_job_id: $id + + - match: { connector.id: test-connector } + - match: { job_type: access_control } + - match: { connector.index_name: .search-acl-filter-search-test } + + --- 'Create connector sync job with non-existing connector id': - do: diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/Connector.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/Connector.java index e9361d78ad707..e9447149c7e6c 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/Connector.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/Connector.java @@ -34,6 +34,7 @@ import java.util.Objects; import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstructorArg; +import static org.elasticsearch.xpack.application.connector.ConnectorTemplateRegistry.ACCESS_CONTROL_INDEX_PREFIX; /** * Represents a Connector in the Elasticsearch ecosystem. Connectors are used for integrating @@ -269,6 +270,10 @@ public Connector(StreamInput in) throws IOException { } ); + public String getAccessControlIndexName() { + return ACCESS_CONTROL_INDEX_PREFIX + this.indexName; + } + static { PARSER.declareStringOrNull(optionalConstructorArg(), API_KEY_ID_FIELD); PARSER.declareStringOrNull(optionalConstructorArg(), API_KEY_SECRET_ID_FIELD); diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorTemplateRegistry.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorTemplateRegistry.java index e4ce4d8181fd8..41976bc6b4272 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorTemplateRegistry.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorTemplateRegistry.java @@ -46,6 +46,7 @@ public class ConnectorTemplateRegistry extends IndexTemplateRegistry { public static final String CONNECTOR_SYNC_JOBS_INDEX_NAME_PATTERN = ".elastic-connectors-sync-jobs-v1"; public static final String CONNECTOR_SYNC_JOBS_TEMPLATE_NAME = "elastic-connectors-sync-jobs"; + public static final String ACCESS_CONTROL_INDEX_PREFIX = ".search-acl-filter-"; public static final String ACCESS_CONTROL_INDEX_NAME_PATTERN = ".search-acl-filter-*"; public static final String ACCESS_CONTROL_TEMPLATE_NAME = "search-acl-filter"; diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/syncjob/ConnectorSyncJobIndexService.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/syncjob/ConnectorSyncJobIndexService.java index 85f8ef089c6fe..6d81bae3c2e9f 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/syncjob/ConnectorSyncJobIndexService.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/syncjob/ConnectorSyncJobIndexService.java @@ -96,8 +96,9 @@ public void createConnectorSyncJob( ActionListener listener ) { String connectorId = request.getId(); + ConnectorSyncJobType jobType = Objects.requireNonNullElse(request.getJobType(), ConnectorSyncJob.DEFAULT_JOB_TYPE); try { - getSyncJobConnectorInfo(connectorId, listener.delegateFailure((l, connector) -> { + getSyncJobConnectorInfo(connectorId, jobType, listener.delegateFailure((l, connector) -> { if (Strings.isNullOrEmpty(connector.getIndexName())) { l.onFailure( new ElasticsearchStatusException( @@ -125,7 +126,6 @@ public void createConnectorSyncJob( } Instant now = Instant.now(); - ConnectorSyncJobType jobType = Objects.requireNonNullElse(request.getJobType(), ConnectorSyncJob.DEFAULT_JOB_TYPE); ConnectorSyncJobTriggerMethod triggerMethod = Objects.requireNonNullElse( request.getTriggerMethod(), ConnectorSyncJob.DEFAULT_TRIGGER_METHOD @@ -494,7 +494,7 @@ private ConnectorSyncStatus getConnectorSyncJobStatusFromSearchResult(ConnectorS ); } - private void getSyncJobConnectorInfo(String connectorId, ActionListener listener) { + private void getSyncJobConnectorInfo(String connectorId, ConnectorSyncJobType jobType, ActionListener listener) { try { final GetRequest request = new GetRequest(ConnectorIndexService.CONNECTOR_INDEX_NAME, connectorId); @@ -514,11 +514,15 @@ public void onResponse(GetResponse response) { connectorId, XContentType.JSON ); + // Access control syncs write data to a separate index + String targetIndexName = jobType == ConnectorSyncJobType.ACCESS_CONTROL + ? connector.getAccessControlIndexName() + : connector.getIndexName(); // Build the connector representation for sync job final Connector syncJobConnector = new Connector.Builder().setConnectorId(connector.getConnectorId()) .setSyncJobFiltering(transformConnectorFilteringToSyncJobRepresentation(connector.getFiltering())) - .setIndexName(connector.getIndexName()) + .setIndexName(targetIndexName) .setLanguage(connector.getLanguage()) .setPipeline(connector.getPipeline()) .setServiceType(connector.getServiceType()) diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/syncjob/ConnectorSyncJobIndexServiceTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/syncjob/ConnectorSyncJobIndexServiceTests.java index 97ebea64eb2d8..5e854bb9d2396 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/syncjob/ConnectorSyncJobIndexServiceTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/syncjob/ConnectorSyncJobIndexServiceTests.java @@ -56,6 +56,7 @@ import java.util.stream.Collectors; import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder; +import static org.elasticsearch.xpack.application.connector.ConnectorTemplateRegistry.ACCESS_CONTROL_INDEX_PREFIX; import static org.elasticsearch.xpack.application.connector.ConnectorTestUtils.registerSimplifiedConnectorIndexTemplates; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; @@ -131,6 +132,18 @@ public void testCreateConnectorSyncJob() throws Exception { assertThat(connectorSyncJob.getDeletedDocumentCount(), equalTo(0L)); } + public void testCreateConnectorSyncJob_WithAccessControlJobType_IndexIsPrefixed() throws Exception { + PostConnectorSyncJobAction.Request createAccessControlJobRequest = ConnectorSyncJobTestUtils + .getRandomPostConnectorSyncJobActionRequest(connectorOneId, ConnectorSyncJobType.ACCESS_CONTROL); + + PostConnectorSyncJobAction.Response createAccessControlJobResponse = awaitPutConnectorSyncJob(createAccessControlJobRequest); + + ConnectorSyncJob connectorSyncJob = awaitGetConnectorSyncJob(createAccessControlJobResponse.getId()); + + assertThat(connectorSyncJob.getJobType(), equalTo(ConnectorSyncJobType.ACCESS_CONTROL)); + assertTrue(connectorSyncJob.getConnector().getIndexName().startsWith(ACCESS_CONTROL_INDEX_PREFIX)); + } + public void testCreateConnectorSyncJob_WithMissingJobType_ExpectDefaultJobTypeToBeSet() throws Exception { PostConnectorSyncJobAction.Request syncJobRequest = new PostConnectorSyncJobAction.Request( connectorOneId, From b84ad26c9b13fe4733fb30fd11aa353fc37e1a85 Mon Sep 17 00:00:00 2001 From: Tim Brooks Date: Wed, 29 May 2024 02:56:43 -0600 Subject: [PATCH 025/208] Use the unsafe future for read single region (#109139) We need to use the unsafe future to block on the same thread pool similar to read multi regions. --- .../blobcache/shared/SharedBlobCacheService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugin/blob-cache/src/main/java/org/elasticsearch/blobcache/shared/SharedBlobCacheService.java b/x-pack/plugin/blob-cache/src/main/java/org/elasticsearch/blobcache/shared/SharedBlobCacheService.java index c5ef1d7c2bf1d..218f12a97e1a6 100644 --- a/x-pack/plugin/blob-cache/src/main/java/org/elasticsearch/blobcache/shared/SharedBlobCacheService.java +++ b/x-pack/plugin/blob-cache/src/main/java/org/elasticsearch/blobcache/shared/SharedBlobCacheService.java @@ -1116,7 +1116,9 @@ private int readSingleRegion( RangeMissingHandler writer, int region ) throws InterruptedException, ExecutionException { - final PlainActionFuture readFuture = new PlainActionFuture<>(); + final PlainActionFuture readFuture = new UnsafePlainActionFuture<>( + BlobStoreRepository.STATELESS_SHARD_PREWARMING_THREAD_NAME + ); final CacheFileRegion fileRegion = get(cacheKey, length, region); final long regionStart = getRegionStart(region); fileRegion.populateAndRead( From 1044a0104f6868c52fcc4161f7f973ed3e5a4087 Mon Sep 17 00:00:00 2001 From: Jedr Blaszyk Date: Wed, 29 May 2024 11:48:58 +0200 Subject: [PATCH 026/208] [Connecor API] Add references to tutorial in docs (#109099) --- .../connector/apis/cancel-connector-sync-job-api.asciidoc | 2 ++ docs/reference/connector/apis/check-in-connector-api.asciidoc | 2 ++ .../connector/apis/check-in-connector-sync-job-api.asciidoc | 2 ++ docs/reference/connector/apis/connector-apis.asciidoc | 2 +- docs/reference/connector/apis/create-connector-api.asciidoc | 2 ++ .../connector/apis/create-connector-sync-job-api.asciidoc | 2 ++ docs/reference/connector/apis/delete-connector-api.asciidoc | 2 ++ .../connector/apis/delete-connector-sync-job-api.asciidoc | 2 ++ docs/reference/connector/apis/get-connector-api.asciidoc | 2 ++ .../connector/apis/get-connector-sync-job-api.asciidoc | 2 ++ .../connector/apis/list-connector-sync-jobs-api.asciidoc | 1 + docs/reference/connector/apis/list-connectors-api.asciidoc | 2 ++ .../connector/apis/set-connector-sync-job-error-api.asciidoc | 2 ++ .../connector/apis/set-connector-sync-job-stats-api.asciidoc | 2 ++ .../connector/apis/update-connector-api-key-id-api.asciidoc | 2 ++ .../connector/apis/update-connector-configuration-api.asciidoc | 1 + .../connector/apis/update-connector-error-api.asciidoc | 2 ++ .../connector/apis/update-connector-filtering-api.asciidoc | 2 ++ .../connector/apis/update-connector-index-name-api.asciidoc | 2 ++ .../connector/apis/update-connector-last-sync-api.asciidoc | 2 ++ .../apis/update-connector-name-description-api.asciidoc | 2 ++ .../connector/apis/update-connector-pipeline-api.asciidoc | 2 ++ .../connector/apis/update-connector-scheduling-api.asciidoc | 2 ++ .../connector/apis/update-connector-service-type-api.asciidoc | 2 ++ .../connector/apis/update-connector-status-api.asciidoc | 2 ++ 25 files changed, 47 insertions(+), 1 deletion(-) diff --git a/docs/reference/connector/apis/cancel-connector-sync-job-api.asciidoc b/docs/reference/connector/apis/cancel-connector-sync-job-api.asciidoc index 0519cfdf15984..105d395e42c8b 100644 --- a/docs/reference/connector/apis/cancel-connector-sync-job-api.asciidoc +++ b/docs/reference/connector/apis/cancel-connector-sync-job-api.asciidoc @@ -8,6 +8,8 @@ beta::[] Cancels a connector sync job. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[cancel-connector-sync-job-api-request]] ==== {api-request-title} `PUT _connector/_sync_job//_cancel` diff --git a/docs/reference/connector/apis/check-in-connector-api.asciidoc b/docs/reference/connector/apis/check-in-connector-api.asciidoc index e8119028ea24d..8c6b5161a3a72 100644 --- a/docs/reference/connector/apis/check-in-connector-api.asciidoc +++ b/docs/reference/connector/apis/check-in-connector-api.asciidoc @@ -8,6 +8,8 @@ preview::[] Updates the `last_seen` field of a connector with current timestamp. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[check-in-connector-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/check-in-connector-sync-job-api.asciidoc b/docs/reference/connector/apis/check-in-connector-sync-job-api.asciidoc index 482c2e8dd4a2f..a052fbb2418cc 100644 --- a/docs/reference/connector/apis/check-in-connector-sync-job-api.asciidoc +++ b/docs/reference/connector/apis/check-in-connector-sync-job-api.asciidoc @@ -8,6 +8,8 @@ preview::[] Checks in a connector sync job (updates `last_seen` to the current time). +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[check-in-connector-sync-job-api-request]] ==== {api-request-title} `PUT _connector/_sync_job//_check_in/` diff --git a/docs/reference/connector/apis/connector-apis.asciidoc b/docs/reference/connector/apis/connector-apis.asciidoc index c8b06bb1d0a6e..9d23fcf8d336e 100644 --- a/docs/reference/connector/apis/connector-apis.asciidoc +++ b/docs/reference/connector/apis/connector-apis.asciidoc @@ -3,7 +3,7 @@ beta::[] -The connector and sync jobs APIs provide a convenient way to create and manage Elastic {enterprise-search-ref}/connectors.html[connectors^] and sync jobs in an internal index. +The connector and sync jobs APIs provide a convenient way to create and manage Elastic {enterprise-search-ref}/connectors.html[connectors^] and sync jobs in an internal index. To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. Connectors are {es} integrations that bring content from third-party data sources, which can be deployed on {ecloud} or hosted on your own infrastructure: diff --git a/docs/reference/connector/apis/create-connector-api.asciidoc b/docs/reference/connector/apis/create-connector-api.asciidoc index 2d7944c52f21b..9bd49a3c5ef94 100644 --- a/docs/reference/connector/apis/create-connector-api.asciidoc +++ b/docs/reference/connector/apis/create-connector-api.asciidoc @@ -14,6 +14,8 @@ Connectors are {es} integrations that bring content from third-party data source Find a list of all supported service types in the {enterprise-search-ref}/connectors.html[connectors documentation^]. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [source,console] -------------------------------------------------- PUT _connector/my-connector diff --git a/docs/reference/connector/apis/create-connector-sync-job-api.asciidoc b/docs/reference/connector/apis/create-connector-sync-job-api.asciidoc index 43a2339c56847..c7cc866930dfb 100644 --- a/docs/reference/connector/apis/create-connector-sync-job-api.asciidoc +++ b/docs/reference/connector/apis/create-connector-sync-job-api.asciidoc @@ -9,6 +9,8 @@ beta::[] Creates a connector sync job. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [source, console] -------------------------------------------------- POST _connector/_sync_job diff --git a/docs/reference/connector/apis/delete-connector-api.asciidoc b/docs/reference/connector/apis/delete-connector-api.asciidoc index d8dfea8c401ce..23acd1b4755b1 100644 --- a/docs/reference/connector/apis/delete-connector-api.asciidoc +++ b/docs/reference/connector/apis/delete-connector-api.asciidoc @@ -11,6 +11,8 @@ This is a destructive action that is not recoverable. Note: this action doesn't delete any API key, ingest pipeline or data index associated with the connector. These need to be removed manually. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[delete-connector-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/delete-connector-sync-job-api.asciidoc b/docs/reference/connector/apis/delete-connector-sync-job-api.asciidoc index 0c3274454845c..7cdabb22f05ee 100644 --- a/docs/reference/connector/apis/delete-connector-sync-job-api.asciidoc +++ b/docs/reference/connector/apis/delete-connector-sync-job-api.asciidoc @@ -9,6 +9,8 @@ beta::[] Removes a connector sync job and its associated data. This is a destructive action that is not recoverable. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[delete-connector-sync-job-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/get-connector-api.asciidoc b/docs/reference/connector/apis/get-connector-api.asciidoc index 7e5186b146c51..4df792c8a0a1a 100644 --- a/docs/reference/connector/apis/get-connector-api.asciidoc +++ b/docs/reference/connector/apis/get-connector-api.asciidoc @@ -8,6 +8,8 @@ beta::[] Retrieves the details about a connector. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[get-connector-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/get-connector-sync-job-api.asciidoc b/docs/reference/connector/apis/get-connector-sync-job-api.asciidoc index e162fe191375c..fffdada2a2a82 100644 --- a/docs/reference/connector/apis/get-connector-sync-job-api.asciidoc +++ b/docs/reference/connector/apis/get-connector-sync-job-api.asciidoc @@ -8,6 +8,8 @@ beta::[] Retrieves the details about a connector sync job. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[get-connector-sync-job-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/list-connector-sync-jobs-api.asciidoc b/docs/reference/connector/apis/list-connector-sync-jobs-api.asciidoc index 6d06e7e6b9045..217b29451937d 100644 --- a/docs/reference/connector/apis/list-connector-sync-jobs-api.asciidoc +++ b/docs/reference/connector/apis/list-connector-sync-jobs-api.asciidoc @@ -9,6 +9,7 @@ beta::[] Returns information about all stored connector sync jobs ordered by their creation date in ascending order. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. [[list-connector-sync-jobs-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/list-connectors-api.asciidoc b/docs/reference/connector/apis/list-connectors-api.asciidoc index c24acec5e82ce..c7ea2afd8102f 100644 --- a/docs/reference/connector/apis/list-connectors-api.asciidoc +++ b/docs/reference/connector/apis/list-connectors-api.asciidoc @@ -9,6 +9,8 @@ beta::[] Returns information about all created connectors. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[list-connector-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/set-connector-sync-job-error-api.asciidoc b/docs/reference/connector/apis/set-connector-sync-job-error-api.asciidoc index 97b5c20f0813c..42203ed8e6103 100644 --- a/docs/reference/connector/apis/set-connector-sync-job-error-api.asciidoc +++ b/docs/reference/connector/apis/set-connector-sync-job-error-api.asciidoc @@ -8,6 +8,8 @@ preview::[] Sets a connector sync job error. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[set-connector-sync-job-error-api-request]] ==== {api-request-title} `PUT _connector/_sync_job//_error` diff --git a/docs/reference/connector/apis/set-connector-sync-job-stats-api.asciidoc b/docs/reference/connector/apis/set-connector-sync-job-stats-api.asciidoc index 405df07465a28..4dd9cc6e67ab2 100644 --- a/docs/reference/connector/apis/set-connector-sync-job-stats-api.asciidoc +++ b/docs/reference/connector/apis/set-connector-sync-job-stats-api.asciidoc @@ -8,6 +8,8 @@ preview::[] Sets connector sync job stats. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[set-connector-sync-job-stats-api-request]] ==== {api-request-title} `PUT _connector/_sync_job//_stats` diff --git a/docs/reference/connector/apis/update-connector-api-key-id-api.asciidoc b/docs/reference/connector/apis/update-connector-api-key-id-api.asciidoc index b2b9dd7958191..112ec821df7c9 100644 --- a/docs/reference/connector/apis/update-connector-api-key-id-api.asciidoc +++ b/docs/reference/connector/apis/update-connector-api-key-id-api.asciidoc @@ -15,6 +15,8 @@ The Connector Secret ID is only required for native connectors. Connector clients do not use this field. See the documentation for {enterprise-search-ref}/native-connectors.html#native-connectors-manage-API-keys-programmatically[managing native connector API keys programmatically^] for more details. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[update-connector-api-key-id-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/update-connector-configuration-api.asciidoc b/docs/reference/connector/apis/update-connector-configuration-api.asciidoc index 51252be4a04c3..e8a710cdacff0 100644 --- a/docs/reference/connector/apis/update-connector-configuration-api.asciidoc +++ b/docs/reference/connector/apis/update-connector-configuration-api.asciidoc @@ -8,6 +8,7 @@ beta::[] Updates a connector's `configuration`, allowing for config value updates within a registered configuration schema. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. [[update-connector-configuration-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/update-connector-error-api.asciidoc b/docs/reference/connector/apis/update-connector-error-api.asciidoc index 3ec03c6153f4b..67ea6b6d17cf0 100644 --- a/docs/reference/connector/apis/update-connector-error-api.asciidoc +++ b/docs/reference/connector/apis/update-connector-error-api.asciidoc @@ -8,6 +8,8 @@ preview::[] Updates the `error` field of a connector. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[update-connector-error-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/update-connector-filtering-api.asciidoc b/docs/reference/connector/apis/update-connector-filtering-api.asciidoc index 7ae80276d3151..861e72481a59a 100644 --- a/docs/reference/connector/apis/update-connector-filtering-api.asciidoc +++ b/docs/reference/connector/apis/update-connector-filtering-api.asciidoc @@ -10,6 +10,8 @@ Updates the draft `filtering` configuration of a connector and marks the draft v The filtering property is used to configure sync rules (both basic and advanced) for a connector. Learn more in the {enterprise-search-ref}/sync-rules.html[sync rules documentation]. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[update-connector-filtering-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/update-connector-index-name-api.asciidoc b/docs/reference/connector/apis/update-connector-index-name-api.asciidoc index 3f931d8ac5edd..d07007438e09c 100644 --- a/docs/reference/connector/apis/update-connector-index-name-api.asciidoc +++ b/docs/reference/connector/apis/update-connector-index-name-api.asciidoc @@ -8,6 +8,8 @@ beta::[] Updates the `index_name` field of a connector, specifying the index where the data ingested by the connector is stored. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[update-connector-index-name-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/update-connector-last-sync-api.asciidoc b/docs/reference/connector/apis/update-connector-last-sync-api.asciidoc index 9326855d3c5d8..918bf4f80a010 100644 --- a/docs/reference/connector/apis/update-connector-last-sync-api.asciidoc +++ b/docs/reference/connector/apis/update-connector-last-sync-api.asciidoc @@ -10,6 +10,8 @@ Updates the fields related to the last sync of a connector. This action is used for analytics and monitoring. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[update-connector-last-sync-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/update-connector-name-description-api.asciidoc b/docs/reference/connector/apis/update-connector-name-description-api.asciidoc index 9ecf0f5d175fd..7e16874da9fb4 100644 --- a/docs/reference/connector/apis/update-connector-name-description-api.asciidoc +++ b/docs/reference/connector/apis/update-connector-name-description-api.asciidoc @@ -9,6 +9,8 @@ beta::[] Updates the `name` and `description` fields of a connector. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[update-connector-name-description-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/update-connector-pipeline-api.asciidoc b/docs/reference/connector/apis/update-connector-pipeline-api.asciidoc index f8f804595eb19..01ed2e39702ea 100644 --- a/docs/reference/connector/apis/update-connector-pipeline-api.asciidoc +++ b/docs/reference/connector/apis/update-connector-pipeline-api.asciidoc @@ -10,6 +10,8 @@ Updates the `pipeline` configuration of a connector. When you create a new connector, the configuration of an <> is populated with default settings. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[update-connector-pipeline-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/update-connector-scheduling-api.asciidoc b/docs/reference/connector/apis/update-connector-scheduling-api.asciidoc index 6d30197dd3390..f932f4c959de2 100644 --- a/docs/reference/connector/apis/update-connector-scheduling-api.asciidoc +++ b/docs/reference/connector/apis/update-connector-scheduling-api.asciidoc @@ -8,6 +8,8 @@ beta::[] Updates the `scheduling` configuration of a connector. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[update-connector-scheduling-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/update-connector-service-type-api.asciidoc b/docs/reference/connector/apis/update-connector-service-type-api.asciidoc index fb61a25848a9d..139e9eddf4076 100644 --- a/docs/reference/connector/apis/update-connector-service-type-api.asciidoc +++ b/docs/reference/connector/apis/update-connector-service-type-api.asciidoc @@ -8,6 +8,8 @@ beta::[] Updates the `service_type` of a connector. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[update-connector-service-type-api-request]] ==== {api-request-title} diff --git a/docs/reference/connector/apis/update-connector-status-api.asciidoc b/docs/reference/connector/apis/update-connector-status-api.asciidoc index d444c82a1bde0..ee9dfcb5f880f 100644 --- a/docs/reference/connector/apis/update-connector-status-api.asciidoc +++ b/docs/reference/connector/apis/update-connector-status-api.asciidoc @@ -8,6 +8,8 @@ preview::[] Updates the `status` of a connector. +To get started with Connector APIs, check out the {enterprise-search-ref}/connectors-tutorial-api.html[tutorial^]. + [[update-connector-status-api-request]] ==== {api-request-title} From 67a8bd219c9de211f904e5c9fcea4502d2637137 Mon Sep 17 00:00:00 2001 From: Artem Prigoda Date: Wed, 29 May 2024 11:58:47 +0200 Subject: [PATCH 027/208] AwaitsFix: https://github.com/elastic/elasticsearch/issues/109154 --- muted-tests.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/muted-tests.yml b/muted-tests.yml index 4f64492466375..9d78a6714e35e 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -35,6 +35,10 @@ tests: - class: "org.elasticsearch.upgrades.MlTrainedModelsUpgradeIT" issue: "https://github.com/elastic/elasticsearch/issues/108993" method: "testTrainedModelInference" +- class: "org.elasticsearch.datastreams.DataStreamsClientYamlTestSuiteIT" + issue: "https://github.com/elastic/elasticsearch/issues/109154" + method: "test {p0=data_stream/200_rollover_failure_store/Lazily roll over a data\ + \ stream's failure store after an ingest failure}" # Examples: # # Mute a single test case in a YAML test suite: From f94c5416e30179a4b6cc0d2f564e96ea0961f800 Mon Sep 17 00:00:00 2001 From: David Turner Date: Wed, 29 May 2024 11:18:24 +0100 Subject: [PATCH 028/208] Fix trappy timeouts in CCR (#109151) Relates #107984 --- .../elasticsearch/xpack/ccr/AutoFollowIT.java | 35 +++++++++---- .../elasticsearch/xpack/ccr/CcrLicenseIT.java | 5 +- .../xpack/ccr/CcrRetentionLeaseIT.java | 19 +++++-- .../xpack/ccr/CloseFollowerIndexIT.java | 2 +- .../elasticsearch/xpack/ccr/FollowInfoIT.java | 32 +++++++----- .../xpack/ccr/FollowStatsIT.java | 24 ++++++--- .../xpack/ccr/IndexFollowingIT.java | 51 +++++++++++++++---- .../xpack/ccr/LocalIndexFollowingIT.java | 10 ++-- .../xpack/ccr/RestartIndexFollowingIT.java | 6 ++- .../ccr/action/AutoFollowCoordinator.java | 3 +- .../ccr/action/TransportPutFollowAction.java | 3 +- .../xpack/ccr/rest/RestCcrStatsAction.java | 3 +- .../RestDeleteAutoFollowPatternAction.java | 4 +- .../xpack/ccr/rest/RestFollowInfoAction.java | 3 +- .../rest/RestGetAutoFollowPatternAction.java | 3 +- .../RestPauseAutoFollowPatternAction.java | 4 +- .../xpack/ccr/rest/RestPauseFollowAction.java | 3 +- .../rest/RestPutAutoFollowPatternAction.java | 5 +- .../xpack/ccr/rest/RestPutFollowAction.java | 4 +- .../RestResumeAutoFollowPatternAction.java | 4 +- .../ccr/rest/RestResumeFollowAction.java | 8 ++- .../xpack/ccr/rest/RestUnfollowAction.java | 8 ++- .../elasticsearch/xpack/CcrIntegTestCase.java | 12 +++-- .../xpack/CcrSingleNodeTestCase.java | 6 +-- ...teAutoFollowPatternActionRequestTests.java | 16 ++++-- .../action/AutoFollowCoordinatorTests.java | 24 +++++++-- .../DeleteAutoFollowPatternRequestTests.java | 2 +- .../ccr/action/FollowInfoRequestTests.java | 2 +- .../GetAutoFollowPatternRequestTests.java | 2 +- .../PutAutoFollowPatternRequestTests.java | 18 +++---- .../action/PutFollowActionRequestTests.java | 8 +-- .../ResumeFollowActionRequestTests.java | 8 +-- ...tActivateAutoFollowPatternActionTests.java | 19 +++++-- ...ortDeleteAutoFollowPatternActionTests.java | 6 +-- ...nsportPutAutoFollowPatternActionTests.java | 6 +-- .../TransportResumeFollowActionTests.java | 2 +- .../ActivateAutoFollowPatternAction.java | 5 +- .../xpack/core/ccr/action/CcrStatsAction.java | 4 +- .../action/DeleteAutoFollowPatternAction.java | 5 +- .../core/ccr/action/FollowInfoAction.java | 5 +- .../action/GetAutoFollowPatternAction.java | 5 +- .../core/ccr/action/PauseFollowAction.java | 5 +- .../action/PutAutoFollowPatternAction.java | 10 ++-- .../core/ccr/action/PutFollowAction.java | 10 ++-- .../core/ccr/action/ResumeFollowAction.java | 10 ++-- .../xpack/core/ccr/action/UnfollowAction.java | 5 +- .../core/ilm/PauseFollowerIndexStep.java | 3 +- .../core/ilm/UnfollowFollowerIndexStep.java | 2 +- .../core/ccr/action/CcrStatsActionTests.java | 8 +-- .../collector/ccr/StatsCollector.java | 2 +- 50 files changed, 290 insertions(+), 159 deletions(-) diff --git a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/AutoFollowIT.java b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/AutoFollowIT.java index 8842d9ef35fec..bbd1905374d24 100644 --- a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/AutoFollowIT.java +++ b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/AutoFollowIT.java @@ -273,7 +273,7 @@ public void testAutoFollowParameterAreDelegated() throws Exception { .build(); // Enabling auto following: - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setRemoteCluster("leader_cluster"); request.setLeaderIndexPatterns(Collections.singletonList("logs-*")); // Need to set this, because following an index in the same cluster @@ -314,7 +314,7 @@ public void testAutoFollowParameterAreDelegated() throws Exception { createLeaderIndex("logs-201901", leaderIndexSettings); assertLongBusy(() -> { - FollowInfoAction.Request followInfoRequest = new FollowInfoAction.Request(); + FollowInfoAction.Request followInfoRequest = new FollowInfoAction.Request(TEST_REQUEST_TIMEOUT); followInfoRequest.setFollowerIndices("copy-logs-201901"); FollowInfoAction.Response followInfoResponse; try { @@ -662,7 +662,10 @@ public void testAutoFollowDatastreamWithClosingFollowerIndex() throws Exception .setSource("foo", "bar", DataStream.TIMESTAMP_FIELD_NAME, randomNonNegativeLong()) .get(); - PutAutoFollowPatternAction.Request followRequest = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request followRequest = new PutAutoFollowPatternAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT + ); followRequest.setName("pattern-1"); followRequest.setRemoteCluster("leader_cluster"); followRequest.setLeaderIndexPatterns(List.of("logs-*")); @@ -727,7 +730,7 @@ private void putAutoFollowPatterns(String name, String[] patterns) { } private void putAutoFollowPatterns(String name, String[] patterns, List exclusionPatterns) { - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setName(name); request.setRemoteCluster("leader_cluster"); request.setLeaderIndexPatterns(Arrays.asList(patterns)); @@ -742,7 +745,11 @@ private void putAutoFollowPatterns(String name, String[] patterns, List } private void deleteAutoFollowPattern(final String name) { - DeleteAutoFollowPatternAction.Request request = new DeleteAutoFollowPatternAction.Request(name); + DeleteAutoFollowPatternAction.Request request = new DeleteAutoFollowPatternAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, + name + ); if (randomBoolean()) { request.masterNodeTimeout(TimeValue.timeValueSeconds(randomFrom(10, 20, 30))); } @@ -750,7 +757,7 @@ private void deleteAutoFollowPattern(final String name) { } private AutoFollowStats getAutoFollowStats() { - CcrStatsAction.Request request = new CcrStatsAction.Request(); + CcrStatsAction.Request request = new CcrStatsAction.Request(TEST_REQUEST_TIMEOUT); if (randomBoolean()) { request.masterNodeTimeout(TimeValue.timeValueSeconds(randomFrom(10, 20, 30))); } @@ -764,7 +771,12 @@ private void createLeaderIndex(String index, Settings settings) { } private void pauseAutoFollowPattern(final String name) { - ActivateAutoFollowPatternAction.Request request = new ActivateAutoFollowPatternAction.Request(name, false); + ActivateAutoFollowPatternAction.Request request = new ActivateAutoFollowPatternAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, + name, + false + ); if (randomBoolean()) { request.masterNodeTimeout(TimeValue.timeValueSeconds(randomFrom(10, 20, 30))); } @@ -772,7 +784,12 @@ private void pauseAutoFollowPattern(final String name) { } private void resumeAutoFollowPattern(final String name) { - ActivateAutoFollowPatternAction.Request request = new ActivateAutoFollowPatternAction.Request(name, true); + ActivateAutoFollowPatternAction.Request request = new ActivateAutoFollowPatternAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, + name, + true + ); if (randomBoolean()) { request.masterNodeTimeout(TimeValue.timeValueSeconds(randomFrom(10, 20, 30))); } @@ -780,7 +797,7 @@ private void resumeAutoFollowPattern(final String name) { } private AutoFollowMetadata.AutoFollowPattern getAutoFollowPattern(final String name) { - GetAutoFollowPatternAction.Request request = new GetAutoFollowPatternAction.Request(); + GetAutoFollowPatternAction.Request request = new GetAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT); request.setName(name); if (randomBoolean()) { request.masterNodeTimeout(TimeValue.timeValueSeconds(randomFrom(10, 20, 30))); diff --git a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CcrLicenseIT.java b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CcrLicenseIT.java index 549c5146e6c79..f1febd8aea550 100644 --- a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CcrLicenseIT.java +++ b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CcrLicenseIT.java @@ -111,7 +111,10 @@ public void onFailure(final Exception e) { public void testThatPutAutoFollowPatternsIsUnavailableWithNonCompliantLicense() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); - final PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + final PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT + ); request.setName("name"); request.setRemoteCluster("leader"); request.setLeaderIndexPatterns(Collections.singletonList("*")); diff --git a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CcrRetentionLeaseIT.java b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CcrRetentionLeaseIT.java index 339662c996492..a0b25faea9256 100644 --- a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CcrRetentionLeaseIT.java +++ b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CcrRetentionLeaseIT.java @@ -472,7 +472,12 @@ public void testUnfollowRemovesRetentionLeases() throws Exception { pauseFollow(followerIndex); assertAcked(followerClient().admin().indices().close(new CloseIndexRequest(followerIndex)).actionGet()); - assertAcked(followerClient().execute(UnfollowAction.INSTANCE, new UnfollowAction.Request(followerIndex)).actionGet()); + assertAcked( + followerClient().execute( + UnfollowAction.INSTANCE, + new UnfollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, followerIndex) + ).actionGet() + ); final IndicesStatsResponse afterUnfollowStats = leaderClient().admin() .indices() @@ -541,7 +546,10 @@ public void testUnfollowFailsToRemoveRetentionLeases() throws Exception { final ElasticsearchException e = expectThrows( ElasticsearchException.class, - () -> followerClient().execute(UnfollowAction.INSTANCE, new UnfollowAction.Request(followerIndex)).actionGet() + () -> followerClient().execute( + UnfollowAction.INSTANCE, + new UnfollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, followerIndex) + ).actionGet() ); final ClusterStateResponse followerIndexClusterState = followerClient().admin() @@ -993,7 +1001,12 @@ public void onResponseReceived(final long responseRequestId, final Transport.Res pauseFollow(followerIndex); assertAcked(followerClient().admin().indices().close(new CloseIndexRequest(followerIndex)).actionGet()); - assertAcked(followerClient().execute(UnfollowAction.INSTANCE, new UnfollowAction.Request(followerIndex)).actionGet()); + assertAcked( + followerClient().execute( + UnfollowAction.INSTANCE, + new UnfollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, followerIndex) + ).actionGet() + ); unfollowLatch.countDown(); diff --git a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CloseFollowerIndexIT.java b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CloseFollowerIndexIT.java index a2d45e443e18f..9e84cdac34008 100644 --- a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CloseFollowerIndexIT.java +++ b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CloseFollowerIndexIT.java @@ -74,7 +74,7 @@ public void testCloseAndReopenFollowerIndex() throws Exception { assertAcked(leaderClient().admin().indices().prepareCreate("index1").setSource(leaderIndexSettings, XContentType.JSON)); ensureLeaderYellow("index1"); - PutFollowAction.Request followRequest = new PutFollowAction.Request(); + PutFollowAction.Request followRequest = new PutFollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); followRequest.setRemoteCluster("leader_cluster"); followRequest.setLeaderIndex("index1"); followRequest.setFollowerIndex("index2"); diff --git a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/FollowInfoIT.java b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/FollowInfoIT.java index efa7fcd0eec53..ab3b5f795d7a2 100644 --- a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/FollowInfoIT.java +++ b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/FollowInfoIT.java @@ -39,7 +39,7 @@ public void testFollowInfoApiFollowerIndexFiltering() throws Exception { followRequest = getPutFollowRequest("leader2", "follower2"); client().execute(PutFollowAction.INSTANCE, followRequest).get(); - FollowInfoAction.Request request = new FollowInfoAction.Request(); + FollowInfoAction.Request request = new FollowInfoAction.Request(TEST_REQUEST_TIMEOUT); request.setFollowerIndices("follower1"); FollowInfoAction.Response response = client().execute(FollowInfoAction.INSTANCE, request).actionGet(); assertThat(response.getFollowInfos().size(), equalTo(1)); @@ -48,7 +48,7 @@ public void testFollowInfoApiFollowerIndexFiltering() throws Exception { assertThat(response.getFollowInfos().get(0).getStatus(), equalTo(Status.ACTIVE)); assertThat(response.getFollowInfos().get(0).getParameters(), notNullValue()); - request = new FollowInfoAction.Request(); + request = new FollowInfoAction.Request(TEST_REQUEST_TIMEOUT); request.setFollowerIndices("follower2"); response = client().execute(FollowInfoAction.INSTANCE, request).actionGet(); assertThat(response.getFollowInfos().size(), equalTo(1)); @@ -57,7 +57,7 @@ public void testFollowInfoApiFollowerIndexFiltering() throws Exception { assertThat(response.getFollowInfos().get(0).getStatus(), equalTo(Status.ACTIVE)); assertThat(response.getFollowInfos().get(0).getParameters(), notNullValue()); - request = new FollowInfoAction.Request(); + request = new FollowInfoAction.Request(TEST_REQUEST_TIMEOUT); request.setFollowerIndices("_all"); response = client().execute(FollowInfoAction.INSTANCE, request).actionGet(); response.getFollowInfos().sort(Comparator.comparing(FollowInfoAction.Response.FollowerInfo::getFollowerIndex)); @@ -72,9 +72,11 @@ public void testFollowInfoApiFollowerIndexFiltering() throws Exception { assertThat(response.getFollowInfos().get(1).getParameters(), notNullValue()); // Pause follower1 index and check the follower info api: - assertAcked(client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request("follower1")).actionGet()); + assertAcked( + client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "follower1")).actionGet() + ); - request = new FollowInfoAction.Request(); + request = new FollowInfoAction.Request(TEST_REQUEST_TIMEOUT); request.setFollowerIndices("follower1"); response = client().execute(FollowInfoAction.INSTANCE, request).actionGet(); assertThat(response.getFollowInfos().size(), equalTo(1)); @@ -83,7 +85,7 @@ public void testFollowInfoApiFollowerIndexFiltering() throws Exception { assertThat(response.getFollowInfos().get(0).getStatus(), equalTo(Status.PAUSED)); assertThat(response.getFollowInfos().get(0).getParameters(), nullValue()); - request = new FollowInfoAction.Request(); + request = new FollowInfoAction.Request(TEST_REQUEST_TIMEOUT); request.setFollowerIndices("follower2"); response = client().execute(FollowInfoAction.INSTANCE, request).actionGet(); assertThat(response.getFollowInfos().size(), equalTo(1)); @@ -92,7 +94,7 @@ public void testFollowInfoApiFollowerIndexFiltering() throws Exception { assertThat(response.getFollowInfos().get(0).getStatus(), equalTo(Status.ACTIVE)); assertThat(response.getFollowInfos().get(0).getParameters(), notNullValue()); - request = new FollowInfoAction.Request(); + request = new FollowInfoAction.Request(TEST_REQUEST_TIMEOUT); request.setFollowerIndices("_all"); response = client().execute(FollowInfoAction.INSTANCE, request).actionGet(); response.getFollowInfos().sort(Comparator.comparing(FollowInfoAction.Response.FollowerInfo::getFollowerIndex)); @@ -106,7 +108,9 @@ public void testFollowInfoApiFollowerIndexFiltering() throws Exception { assertThat(response.getFollowInfos().get(1).getStatus(), equalTo(Status.ACTIVE)); assertThat(response.getFollowInfos().get(1).getParameters(), notNullValue()); - assertAcked(client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request("follower2")).actionGet()); + assertAcked( + client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "follower2")).actionGet() + ); } public void testFollowInfoApiIndexMissing() throws Exception { @@ -122,16 +126,20 @@ public void testFollowInfoApiIndexMissing() throws Exception { followRequest = getPutFollowRequest("leader2", "follower2"); client().execute(PutFollowAction.INSTANCE, followRequest).get(); - FollowInfoAction.Request request1 = new FollowInfoAction.Request(); + FollowInfoAction.Request request1 = new FollowInfoAction.Request(TEST_REQUEST_TIMEOUT); request1.setFollowerIndices("follower3"); expectThrows(IndexNotFoundException.class, () -> client().execute(FollowInfoAction.INSTANCE, request1).actionGet()); - FollowInfoAction.Request request2 = new FollowInfoAction.Request(); + FollowInfoAction.Request request2 = new FollowInfoAction.Request(TEST_REQUEST_TIMEOUT); request2.setFollowerIndices("follower2", "follower3"); expectThrows(IndexNotFoundException.class, () -> client().execute(FollowInfoAction.INSTANCE, request2).actionGet()); - assertAcked(client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request("follower1")).actionGet()); - assertAcked(client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request("follower2")).actionGet()); + assertAcked( + client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "follower1")).actionGet() + ); + assertAcked( + client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "follower2")).actionGet() + ); } } diff --git a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/FollowStatsIT.java b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/FollowStatsIT.java index ccf1c72a06178..9fcee30d30b39 100644 --- a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/FollowStatsIT.java +++ b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/FollowStatsIT.java @@ -100,14 +100,18 @@ public void testFollowStatsApiFollowerIndexFiltering() throws Exception { assertThat(response.getStatsResponses().get(0).status().followerIndex(), equalTo("follower1")); assertThat(response.getStatsResponses().get(1).status().followerIndex(), equalTo("follower2")); - assertAcked(client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request("follower1")).actionGet()); - assertAcked(client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request("follower2")).actionGet()); + assertAcked( + client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "follower1")).actionGet() + ); + assertAcked( + client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "follower2")).actionGet() + ); assertBusy(() -> { - List responseList = client().execute(CcrStatsAction.INSTANCE, new CcrStatsAction.Request()) - .actionGet() - .getFollowStats() - .getStatsResponses(); + List responseList = client().execute( + CcrStatsAction.INSTANCE, + new CcrStatsAction.Request(TEST_REQUEST_TIMEOUT) + ).actionGet().getFollowStats().getStatsResponses(); assertThat(responseList.size(), equalTo(0)); }); } @@ -139,7 +143,9 @@ public void testFollowStatsApiResourceNotFound() throws Exception { e = expectThrows(ResourceNotFoundException.class, () -> client().execute(FollowStatsAction.INSTANCE, statsRequest).actionGet()); assertThat(e.getMessage(), equalTo("No shard follow tasks for follower indices [follower2]")); - assertAcked(client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request("follower1")).actionGet()); + assertAcked( + client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "follower1")).actionGet() + ); } public void testFollowStatsApiWithDeletedFollowerIndex() throws Exception { @@ -202,7 +208,9 @@ public void testFollowStatsApiIncludeShardFollowStatsWithClosedFollowerIndex() t assertThat(response.getStatsResponses().size(), equalTo(1)); assertThat(response.getStatsResponses().get(0).status().followerIndex(), equalTo("follower1")); - assertAcked(client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request("follower1")).actionGet()); + assertAcked( + client().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "follower1")).actionGet() + ); } } diff --git a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/IndexFollowingIT.java b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/IndexFollowingIT.java index 097592a03d5d0..6361b6f89605e 100644 --- a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/IndexFollowingIT.java +++ b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/IndexFollowingIT.java @@ -435,7 +435,12 @@ public void testDoNotAllowPutMappingToFollower() throws Exception { assertThat(forbiddenException.status(), equalTo(RestStatus.FORBIDDEN)); pauseFollow("index-2"); followerClient().admin().indices().close(new CloseIndexRequest("index-2")).actionGet(); - assertAcked(followerClient().execute(UnfollowAction.INSTANCE, new UnfollowAction.Request("index-2")).actionGet()); + assertAcked( + followerClient().execute( + UnfollowAction.INSTANCE, + new UnfollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "index-2") + ).actionGet() + ); followerClient().admin().indices().open(new OpenIndexRequest("index-2")).actionGet(); assertAcked(followerClient().admin().indices().putMapping(putMappingRequest).actionGet()); } @@ -468,7 +473,12 @@ public void testAddAliasAfterUnfollow() throws Exception { followerClient().execute(PutFollowAction.INSTANCE, putFollow("leader", "follower")).get(); pauseFollow("follower"); followerClient().admin().indices().close(new CloseIndexRequest("follower").masterNodeTimeout(TimeValue.MAX_VALUE)).actionGet(); - assertAcked(followerClient().execute(UnfollowAction.INSTANCE, new UnfollowAction.Request("follower")).actionGet()); + assertAcked( + followerClient().execute( + UnfollowAction.INSTANCE, + new UnfollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "follower") + ).actionGet() + ); followerClient().admin().indices().open(new OpenIndexRequest("follower").masterNodeTimeout(TimeValue.MAX_VALUE)).actionGet(); final IndicesAliasesRequest request = new IndicesAliasesRequest().masterNodeTimeout(TimeValue.MAX_VALUE) .addAliasAction(IndicesAliasesRequest.AliasActions.add().index("follower").alias("follower_alias")); @@ -589,7 +599,7 @@ public void testFollowIndexWithNestedField() throws Exception { } public void testUnfollowNonExistingIndex() { - PauseFollowAction.Request unfollowRequest = new PauseFollowAction.Request("non-existing-index"); + PauseFollowAction.Request unfollowRequest = new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "non-existing-index"); expectThrows(IndexNotFoundException.class, () -> followerClient().execute(PauseFollowAction.INSTANCE, unfollowRequest).actionGet()); } @@ -899,25 +909,33 @@ public void testPauseIndex() throws Exception { ); followerClient().execute(PutFollowAction.INSTANCE, putFollow("leader", "follower")).get(); assertAcked(followerClient().admin().indices().prepareCreate("regular-index").setMasterNodeTimeout(TimeValue.MAX_VALUE)); - assertAcked(followerClient().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request("follower")).actionGet()); + assertAcked( + followerClient().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "follower")) + .actionGet() + ); assertThat( expectThrows( IllegalArgumentException.class, - () -> followerClient().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request("follower")).actionGet() + () -> followerClient().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "follower")) + .actionGet() ).getMessage(), equalTo("no shard follow tasks for [follower]") ); assertThat( expectThrows( IllegalArgumentException.class, - () -> followerClient().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request("regular-index")).actionGet() + () -> followerClient().execute( + PauseFollowAction.INSTANCE, + new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "regular-index") + ).actionGet() ).getMessage(), equalTo("index [regular-index] is not a follower index") ); assertThat( expectThrows( IndexNotFoundException.class, - () -> followerClient().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request("xyz")).actionGet() + () -> followerClient().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "xyz")) + .actionGet() ).getMessage(), equalTo("no such index [xyz]") ); @@ -937,7 +955,12 @@ public void testUnfollowIndex() throws Exception { // Turn follow index into a regular index by: pausing shard follow, close index, unfollow index and then open index: pauseFollow("index2"); followerClient().admin().indices().close(new CloseIndexRequest("index2").masterNodeTimeout(TimeValue.MAX_VALUE)).actionGet(); - assertAcked(followerClient().execute(UnfollowAction.INSTANCE, new UnfollowAction.Request("index2")).actionGet()); + assertAcked( + followerClient().execute( + UnfollowAction.INSTANCE, + new UnfollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "index2") + ).actionGet() + ); followerClient().admin().indices().open(new OpenIndexRequest("index2").masterNodeTimeout(TimeValue.MAX_VALUE)).actionGet(); ensureFollowerGreen("index2"); @@ -960,7 +983,10 @@ public void testUnknownClusterAlias() throws Exception { () -> followerClient().execute(PutFollowAction.INSTANCE, followRequest).actionGet() ); assertThat(e.getMessage(), equalTo("no such remote cluster: [another_cluster]")); - PutAutoFollowPatternAction.Request putAutoFollowRequest = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request putAutoFollowRequest = new PutAutoFollowPatternAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT + ); putAutoFollowRequest.setName("name"); putAutoFollowRequest.setRemoteCluster("another_cluster"); putAutoFollowRequest.setLeaderIndexPatterns(Collections.singletonList("logs-*")); @@ -1447,7 +1473,12 @@ private void runFallBehindTest( followerClient().admin().indices().prepareClose("index2").setMasterNodeTimeout(TimeValue.MAX_VALUE).get(); pauseFollow("index2"); if (randomBoolean()) { - assertAcked(followerClient().execute(UnfollowAction.INSTANCE, new UnfollowAction.Request("index2")).actionGet()); + assertAcked( + followerClient().execute( + UnfollowAction.INSTANCE, + new UnfollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "index2") + ).actionGet() + ); } final PutFollowAction.Request followRequest2 = putFollow("index1", "index2"); diff --git a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/LocalIndexFollowingIT.java b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/LocalIndexFollowingIT.java index 05fc3b037c795..41fed34ea2106 100644 --- a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/LocalIndexFollowingIT.java +++ b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/LocalIndexFollowingIT.java @@ -63,7 +63,7 @@ public void testFollowIndex() throws Exception { assertBusy(() -> assertHitCount(client().prepareSearch("follower"), firstBatchNumDocs + secondBatchNumDocs)); - PauseFollowAction.Request pauseRequest = new PauseFollowAction.Request("follower"); + PauseFollowAction.Request pauseRequest = new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "follower"); client().execute(PauseFollowAction.INSTANCE, pauseRequest); final long thirdBatchNumDocs = randomIntBetween(2, 64); @@ -136,7 +136,7 @@ public void testIndexingMetricsIncremented() throws Exception { } public void testRemoveRemoteConnection() throws Exception { - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setName("my_pattern"); request.setRemoteCluster("local"); request.setLeaderIndexPatterns(Collections.singletonList("logs-*")); @@ -152,7 +152,8 @@ public void testRemoveRemoteConnection() throws Exception { createIndex("logs-20200101", leaderIndexSettings); prepareIndex("logs-20200101").setSource("{}", XContentType.JSON).get(); assertBusy(() -> { - CcrStatsAction.Response response = client().execute(CcrStatsAction.INSTANCE, new CcrStatsAction.Request()).actionGet(); + CcrStatsAction.Response response = client().execute(CcrStatsAction.INSTANCE, new CcrStatsAction.Request(TEST_REQUEST_TIMEOUT)) + .actionGet(); assertThat( response.getAutoFollowStats().getNumberOfSuccessfulFollowIndices(), equalTo(previousNumberOfSuccessfulFollowedIndices + 1) @@ -171,7 +172,8 @@ public void testRemoveRemoteConnection() throws Exception { // This new document should be replicated to follower index: prepareIndex("logs-20200101").setSource("{}", XContentType.JSON).get(); assertBusy(() -> { - CcrStatsAction.Response response = client().execute(CcrStatsAction.INSTANCE, new CcrStatsAction.Request()).actionGet(); + CcrStatsAction.Response response = client().execute(CcrStatsAction.INSTANCE, new CcrStatsAction.Request(TEST_REQUEST_TIMEOUT)) + .actionGet(); assertThat( response.getAutoFollowStats().getNumberOfSuccessfulFollowIndices(), equalTo(previousNumberOfSuccessfulFollowedIndices + 2) diff --git a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/RestartIndexFollowingIT.java b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/RestartIndexFollowingIT.java index 5c152be35b509..18456b24d4618 100644 --- a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/RestartIndexFollowingIT.java +++ b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/RestartIndexFollowingIT.java @@ -118,12 +118,14 @@ public void testFollowIndex() throws Exception { }, 30L, TimeUnit.SECONDS); cleanRemoteCluster(); - assertAcked(followerClient().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request("index2")).actionGet()); + assertAcked( + followerClient().execute(PauseFollowAction.INSTANCE, new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, "index2")).actionGet() + ); assertAcked(followerClient().admin().indices().prepareClose("index2")); final ActionFuture unfollowFuture = followerClient().execute( UnfollowAction.INSTANCE, - new UnfollowAction.Request("index2") + new UnfollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "index2") ); final ElasticsearchException elasticsearchException = expectThrows(ElasticsearchException.class, unfollowFuture::actionGet); assertThat(elasticsearchException.getMessage(), containsString("no such remote cluster")); diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinator.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinator.java index a7bf572e9bf73..82af24d2293cc 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinator.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinator.java @@ -712,7 +712,8 @@ static PutFollowAction.Request generateRequest( final String leaderIndexName = indexToFollow.getName(); final String followIndexName = getFollowerIndexName(pattern, leaderIndexName); - PutFollowAction.Request request = new PutFollowAction.Request(); + // TODO use longer timeouts here? see https://github.com/elastic/elasticsearch/issues/109150 + PutFollowAction.Request request = new PutFollowAction.Request(TimeValue.THIRTY_SECONDS, TimeValue.THIRTY_SECONDS); request.setRemoteCluster(remoteCluster); request.setLeaderIndex(indexToFollow.getName()); request.setFollowerIndex(followIndexName); diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/TransportPutFollowAction.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/TransportPutFollowAction.java index a0917c1cef815..ed7587556bd28 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/TransportPutFollowAction.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/TransportPutFollowAction.java @@ -294,10 +294,9 @@ private void initiateFollowing( ) { assert request.waitForActiveShards() != ActiveShardCount.DEFAULT : "PutFollowAction does not support DEFAULT."; FollowParameters parameters = request.getParameters(); - ResumeFollowAction.Request resumeFollowRequest = new ResumeFollowAction.Request(); + ResumeFollowAction.Request resumeFollowRequest = new ResumeFollowAction.Request(request.masterNodeTimeout()); resumeFollowRequest.setFollowerIndex(request.getFollowerIndex()); resumeFollowRequest.setParameters(new FollowParameters(parameters)); - resumeFollowRequest.masterNodeTimeout(request.masterNodeTimeout()); clientWithHeaders.execute( ResumeFollowAction.INSTANCE, resumeFollowRequest, diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestCcrStatsAction.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestCcrStatsAction.java index 7c8ebc5a66e80..ff208b0b92f88 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestCcrStatsAction.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestCcrStatsAction.java @@ -38,11 +38,10 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) { - final CcrStatsAction.Request request = new CcrStatsAction.Request(); + final CcrStatsAction.Request request = new CcrStatsAction.Request(getMasterNodeTimeout(restRequest)); if (restRequest.hasParam("timeout")) { request.setTimeout(restRequest.paramAsTime("timeout", null)); } - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); return channel -> client.execute( CcrStatsAction.INSTANCE, request, diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestDeleteAutoFollowPatternAction.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestDeleteAutoFollowPatternAction.java index 1f96ea6be9dc5..65c00d94635c5 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestDeleteAutoFollowPatternAction.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestDeleteAutoFollowPatternAction.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.ccr.rest; import org.elasticsearch.client.internal.node.NodeClient; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestToXContentListener; @@ -32,8 +33,7 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { - Request request = new Request(restRequest.param("name")); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + final var request = new Request(getMasterNodeTimeout(restRequest), TimeValue.THIRTY_SECONDS, restRequest.param("name")); return channel -> client.execute(INSTANCE, request, new RestToXContentListener<>(channel)); } diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestFollowInfoAction.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestFollowInfoAction.java index e20c34fe38243..12fb8690adf66 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestFollowInfoAction.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestFollowInfoAction.java @@ -33,8 +33,7 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) { - final FollowInfoAction.Request request = new FollowInfoAction.Request(); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + final var request = new FollowInfoAction.Request(getMasterNodeTimeout(restRequest)); request.setFollowerIndices(Strings.splitStringByCommaToArray(restRequest.param("index"))); return channel -> client.execute(FollowInfoAction.INSTANCE, request, new RestRefCountedChunkedToXContentListener<>(channel)); } diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestGetAutoFollowPatternAction.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestGetAutoFollowPatternAction.java index 84a8d4f879e02..bb202d74d185a 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestGetAutoFollowPatternAction.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestGetAutoFollowPatternAction.java @@ -32,9 +32,8 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { - Request request = new Request(); + final var request = new Request(getMasterNodeTimeout(restRequest)); request.setName(restRequest.param("name")); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); return channel -> client.execute(INSTANCE, request, new RestToXContentListener<>(channel)); } diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPauseAutoFollowPatternAction.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPauseAutoFollowPatternAction.java index 5a2ba2fe736f7..b27960d5bc4ab 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPauseAutoFollowPatternAction.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPauseAutoFollowPatternAction.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.ccr.rest; import org.elasticsearch.client.internal.node.NodeClient; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestToXContentListener; @@ -32,8 +33,7 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) { - Request request = new Request(restRequest.param("name"), false); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + final var request = new Request(getMasterNodeTimeout(restRequest), TimeValue.THIRTY_SECONDS, restRequest.param("name"), false); return channel -> client.execute(INSTANCE, request, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPauseFollowAction.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPauseFollowAction.java index 8c0f79f0b2440..a5e967ba7ac5a 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPauseFollowAction.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPauseFollowAction.java @@ -32,8 +32,7 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { - Request request = new Request(restRequest.param("index")); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + final var request = new Request(getMasterNodeTimeout(restRequest), restRequest.param("index")); return channel -> client.execute(INSTANCE, request, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPutAutoFollowPatternAction.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPutAutoFollowPatternAction.java index cb42431022501..dedcb941483b0 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPutAutoFollowPatternAction.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPutAutoFollowPatternAction.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.ccr.rest; import org.elasticsearch.client.internal.node.NodeClient; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestToXContentListener; @@ -40,9 +41,7 @@ protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient private static Request createRequest(RestRequest restRequest) throws IOException { try (XContentParser parser = restRequest.contentOrSourceParamParser()) { - Request request = Request.fromXContent(parser, restRequest.param("name")); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); - return request; + return Request.fromXContent(getMasterNodeTimeout(restRequest), TimeValue.THIRTY_SECONDS, parser, restRequest.param("name")); } } } diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPutFollowAction.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPutFollowAction.java index 162431d68fb0f..d2063657c8784 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPutFollowAction.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestPutFollowAction.java @@ -8,6 +8,7 @@ import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.client.internal.node.NodeClient; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestToXContentListener; @@ -41,10 +42,9 @@ protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient private static Request createRequest(RestRequest restRequest) throws IOException { try (XContentParser parser = restRequest.contentOrSourceParamParser()) { - final Request request = Request.fromXContent(parser); + final var request = Request.fromXContent(getMasterNodeTimeout(restRequest), TimeValue.THIRTY_SECONDS, parser); request.waitForActiveShards(ActiveShardCount.parseString(restRequest.param("wait_for_active_shards"))); request.setFollowerIndex(restRequest.param("index")); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); return request; } } diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestResumeAutoFollowPatternAction.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestResumeAutoFollowPatternAction.java index 3e51386ef1069..13ef9a6d751f7 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestResumeAutoFollowPatternAction.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestResumeAutoFollowPatternAction.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.ccr.rest; import org.elasticsearch.client.internal.node.NodeClient; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestToXContentListener; @@ -32,8 +33,7 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) { - Request request = new Request(restRequest.param("name"), true); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + final var request = new Request(getMasterNodeTimeout(restRequest), TimeValue.THIRTY_SECONDS, restRequest.param("name"), true); return channel -> client.execute(INSTANCE, request, new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestResumeFollowAction.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestResumeFollowAction.java index 86a00ca1ff020..b519d76c841d2 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestResumeFollowAction.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestResumeFollowAction.java @@ -39,16 +39,14 @@ protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient } static Request createRequest(RestRequest restRequest) throws IOException { - Request request; if (restRequest.hasContentOrSourceParam()) { try (XContentParser parser = restRequest.contentOrSourceParamParser()) { - request = Request.fromXContent(parser, restRequest.param("index")); + return Request.fromXContent(getMasterNodeTimeout(restRequest), parser, restRequest.param("index")); } } else { - request = new Request(); + final var request = new Request(getMasterNodeTimeout(restRequest)); request.setFollowerIndex(restRequest.param("index")); + return request; } - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); - return request; } } diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestUnfollowAction.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestUnfollowAction.java index acc6ffb0a67bd..57e69b686b268 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestUnfollowAction.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/rest/RestUnfollowAction.java @@ -8,6 +8,7 @@ package org.elasticsearch.xpack.ccr.rest; import org.elasticsearch.client.internal.node.NodeClient; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestToXContentListener; @@ -33,8 +34,11 @@ public String getName() { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { - UnfollowAction.Request request = new UnfollowAction.Request(restRequest.param("index")); - request.masterNodeTimeout(getMasterNodeTimeout(restRequest)); + UnfollowAction.Request request = new UnfollowAction.Request( + getMasterNodeTimeout(restRequest), + TimeValue.THIRTY_SECONDS, + restRequest.param("index") + ); return channel -> client.execute(INSTANCE, request, new RestToXContentListener<>(channel)); } diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrIntegTestCase.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrIntegTestCase.java index 52343be3f2c23..677a82ddafa34 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrIntegTestCase.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrIntegTestCase.java @@ -484,7 +484,7 @@ protected void ensureEmptyWriteBuffers() throws Exception { protected void pauseFollow(String... indices) throws Exception { for (String index : indices) { - final PauseFollowAction.Request unfollowRequest = new PauseFollowAction.Request(index); + final PauseFollowAction.Request unfollowRequest = new PauseFollowAction.Request(TEST_REQUEST_TIMEOUT, index); assertAcked(followerClient().execute(PauseFollowAction.INSTANCE, unfollowRequest).actionGet()); } ensureNoCcrTasks(); @@ -492,8 +492,10 @@ protected void pauseFollow(String... indices) throws Exception { protected void ensureNoCcrTasks() throws Exception { assertBusy(() -> { - CcrStatsAction.Response statsResponse = followerClient().execute(CcrStatsAction.INSTANCE, new CcrStatsAction.Request()) - .actionGet(); + CcrStatsAction.Response statsResponse = followerClient().execute( + CcrStatsAction.INSTANCE, + new CcrStatsAction.Request(TEST_REQUEST_TIMEOUT) + ).actionGet(); assertThat( "Follow stats not empty: " + Strings.toString(statsResponse.getFollowStats()), statsResponse.getFollowStats().getStatsResponses(), @@ -586,7 +588,7 @@ public static PutFollowAction.Request putFollow(String leaderIndex, String follo } public static PutFollowAction.Request putFollow(String leaderIndex, String followerIndex, ActiveShardCount waitForActiveShards) { - PutFollowAction.Request request = new PutFollowAction.Request(); + PutFollowAction.Request request = new PutFollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setRemoteCluster("leader_cluster"); request.setLeaderIndex(leaderIndex); request.setFollowerIndex(followerIndex); @@ -602,7 +604,7 @@ public static PutFollowAction.Request putFollow(String leaderIndex, String follo } public static ResumeFollowAction.Request resumeFollow(String followerIndex) { - ResumeFollowAction.Request request = new ResumeFollowAction.Request(); + ResumeFollowAction.Request request = new ResumeFollowAction.Request(TEST_REQUEST_TIMEOUT); request.setFollowerIndex(followerIndex); request.getParameters().setMaxRetryDelay(TimeValue.timeValueMillis(10)); request.getParameters().setReadPollTimeout(TimeValue.timeValueMillis(10)); diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrSingleNodeTestCase.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrSingleNodeTestCase.java index efcaee96c008a..6b69c172c0df3 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrSingleNodeTestCase.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrSingleNodeTestCase.java @@ -95,11 +95,11 @@ public void removeLocalRemote() throws Exception { } protected AutoFollowStats getAutoFollowStats() { - return client().execute(CcrStatsAction.INSTANCE, new CcrStatsAction.Request()).actionGet().getAutoFollowStats(); + return client().execute(CcrStatsAction.INSTANCE, new CcrStatsAction.Request(TEST_REQUEST_TIMEOUT)).actionGet().getAutoFollowStats(); } protected ResumeFollowAction.Request getResumeFollowRequest(String followerIndex) { - ResumeFollowAction.Request request = new ResumeFollowAction.Request(); + ResumeFollowAction.Request request = new ResumeFollowAction.Request(TEST_REQUEST_TIMEOUT); request.setFollowerIndex(followerIndex); request.getParameters().setMaxRetryDelay(TimeValue.timeValueMillis(1)); request.getParameters().setReadPollTimeout(TimeValue.timeValueMillis(1)); @@ -110,7 +110,7 @@ protected ResumeFollowAction.Request getResumeFollowRequest(String followerIndex } protected PutFollowAction.Request getPutFollowRequest(String leaderIndex, String followerIndex) { - PutFollowAction.Request request = new PutFollowAction.Request(); + PutFollowAction.Request request = new PutFollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setRemoteCluster("local"); request.setLeaderIndex(leaderIndex); request.setFollowerIndex(followerIndex); diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/ActivateAutoFollowPatternActionRequestTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/ActivateAutoFollowPatternActionRequestTests.java index 03b197b629d02..f9386cf126a24 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/ActivateAutoFollowPatternActionRequestTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/ActivateAutoFollowPatternActionRequestTests.java @@ -19,7 +19,12 @@ public class ActivateAutoFollowPatternActionRequestTests extends AbstractWireSer @Override protected ActivateAutoFollowPatternAction.Request createTestInstance() { - return new ActivateAutoFollowPatternAction.Request(randomAlphaOfLength(5), randomBoolean()); + return new ActivateAutoFollowPatternAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, + randomAlphaOfLength(5), + randomBoolean() + ); } @Override @@ -33,12 +38,17 @@ protected Writeable.Reader instanceRead } public void testValidate() { - ActivateAutoFollowPatternAction.Request request = new ActivateAutoFollowPatternAction.Request(null, true); + ActivateAutoFollowPatternAction.Request request = new ActivateAutoFollowPatternAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, + null, + true + ); ActionRequestValidationException validationException = request.validate(); assertThat(validationException, notNullValue()); assertThat(validationException.getMessage(), containsString("[name] is missing")); - request = new ActivateAutoFollowPatternAction.Request("name", true); + request = new ActivateAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "name", true); validationException = request.validate(); assertThat(validationException, nullValue()); } diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinatorTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinatorTests.java index f15ca19dd590a..467ef3c68f648 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinatorTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinatorTests.java @@ -460,7 +460,10 @@ public void testAutoFollowerWithPausedActivePatterns() { final ClusterState nextLocalClusterState; if (nextClusterStateVersion == 1) { // cluster state #1 : one pattern is active - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT + ); request.setName("patternLogs"); request.setRemoteCluster(remoteCluster); request.setLeaderIndexPatterns(singletonList("patternLogs-*")); @@ -478,7 +481,10 @@ public void testAutoFollowerWithPausedActivePatterns() { } else if (nextClusterStateVersion == 3) { // cluster state #3 : add a new pattern, two patterns are active - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT + ); request.setName("patternDocs"); request.setRemoteCluster(remoteCluster); request.setLeaderIndexPatterns(singletonList("patternDocs-*")); @@ -496,12 +502,22 @@ public void testAutoFollowerWithPausedActivePatterns() { } else if (nextClusterStateVersion == 5) { // cluster state #5 : first pattern is paused, second pattern is still active - ActivateAutoFollowPatternAction.Request request = new ActivateAutoFollowPatternAction.Request("patternLogs", false); + ActivateAutoFollowPatternAction.Request request = new ActivateAutoFollowPatternAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, + "patternLogs", + false + ); nextLocalClusterState = TransportActivateAutoFollowPatternAction.innerActivate(request, currentLocalState); } else if (nextClusterStateVersion == 6) { // cluster state #5 : second pattern is paused, both patterns are inactive - ActivateAutoFollowPatternAction.Request request = new ActivateAutoFollowPatternAction.Request("patternDocs", false); + ActivateAutoFollowPatternAction.Request request = new ActivateAutoFollowPatternAction.Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, + "patternDocs", + false + ); nextLocalClusterState = TransportActivateAutoFollowPatternAction.innerActivate(request, currentLocalState); } else { diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/DeleteAutoFollowPatternRequestTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/DeleteAutoFollowPatternRequestTests.java index b4a28fd149326..1ca79401ae896 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/DeleteAutoFollowPatternRequestTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/DeleteAutoFollowPatternRequestTests.java @@ -19,7 +19,7 @@ protected Writeable.Reader instanceReader @Override protected DeleteAutoFollowPatternAction.Request createTestInstance() { - return new DeleteAutoFollowPatternAction.Request(randomAlphaOfLength(4)); + return new DeleteAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, randomAlphaOfLength(4)); } @Override diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/FollowInfoRequestTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/FollowInfoRequestTests.java index f08ab5aca1aa8..c809572195f94 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/FollowInfoRequestTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/FollowInfoRequestTests.java @@ -19,7 +19,7 @@ protected Writeable.Reader instanceReader() { @Override protected FollowInfoAction.Request createTestInstance() { - FollowInfoAction.Request request = new FollowInfoAction.Request(); + FollowInfoAction.Request request = new FollowInfoAction.Request(TEST_REQUEST_TIMEOUT); request.setFollowerIndices(generateRandomStringArray(4, 4, true, false)); return request; } diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/GetAutoFollowPatternRequestTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/GetAutoFollowPatternRequestTests.java index b451e07bd037d..d6b498e0bd3f9 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/GetAutoFollowPatternRequestTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/GetAutoFollowPatternRequestTests.java @@ -19,7 +19,7 @@ protected Writeable.Reader instanceReader() @Override protected GetAutoFollowPatternAction.Request createTestInstance() { - GetAutoFollowPatternAction.Request request = new GetAutoFollowPatternAction.Request(); + GetAutoFollowPatternAction.Request request = new GetAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT); if (randomBoolean()) { request.setName(randomAlphaOfLength(4)); } diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/PutAutoFollowPatternRequestTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/PutAutoFollowPatternRequestTests.java index 9e2ca3d8b3013..93d363251da7e 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/PutAutoFollowPatternRequestTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/PutAutoFollowPatternRequestTests.java @@ -26,7 +26,7 @@ public class PutAutoFollowPatternRequestTests extends AbstractXContentSerializin @Override protected PutAutoFollowPatternAction.Request doParseInstance(XContentParser parser) throws IOException { - return PutAutoFollowPatternAction.Request.fromXContent(parser, null); + return PutAutoFollowPatternAction.Request.fromXContent(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, parser, null); } @Override @@ -36,7 +36,7 @@ protected Writeable.Reader instanceReader() @Override protected PutAutoFollowPatternAction.Request createTestInstance() { - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setName(randomAlphaOfLength(4)); request.setRemoteCluster(randomAlphaOfLength(4)); @@ -62,7 +62,7 @@ protected PutAutoFollowPatternAction.Request mutateInstance(PutAutoFollowPattern protected PutAutoFollowPatternAction.Request createXContextTestInstance(XContentType xContentType) { // follower index parameter is not part of the request body and is provided in the url path. // So this field cannot be used for creating a test instance for xcontent testing. - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setRemoteCluster(randomAlphaOfLength(4)); request.setLeaderIndexPatterns(Arrays.asList(generateRandomStringArray(4, 4, false))); if (randomBoolean()) { @@ -78,7 +78,7 @@ protected PutAutoFollowPatternAction.Request createXContextTestInstance(XContent } public void testValidate() { - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); ActionRequestValidationException validationException = request.validate(); assertThat(validationException, notNullValue()); assertThat(validationException.getMessage(), containsString("[name] is missing")); @@ -118,7 +118,7 @@ public void testValidate() { } public void testValidateName() { - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setRemoteCluster("_alias"); request.setLeaderIndexPatterns(Collections.singletonList("logs-*")); @@ -128,7 +128,7 @@ public void testValidateName() { } public void testValidateNameComma() { - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setRemoteCluster("_alias"); request.setLeaderIndexPatterns(Collections.singletonList("logs-*")); @@ -139,7 +139,7 @@ public void testValidateNameComma() { } public void testValidateNameLeadingUnderscore() { - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setRemoteCluster("_alias"); request.setLeaderIndexPatterns(Collections.singletonList("logs-*")); @@ -150,7 +150,7 @@ public void testValidateNameLeadingUnderscore() { } public void testValidateNameUnderscores() { - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setRemoteCluster("_alias"); request.setLeaderIndexPatterns(Collections.singletonList("logs-*")); @@ -160,7 +160,7 @@ public void testValidateNameUnderscores() { } public void testValidateNameTooLong() { - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setRemoteCluster("_alias"); request.setLeaderIndexPatterns(Collections.singletonList("logs-*")); diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/PutFollowActionRequestTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/PutFollowActionRequestTests.java index 171727c3e0bc8..4fa3c0a11acb0 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/PutFollowActionRequestTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/PutFollowActionRequestTests.java @@ -27,7 +27,7 @@ protected Writeable.Reader instanceReader() { @Override protected PutFollowAction.Request createTestInstance() { - PutFollowAction.Request request = new PutFollowAction.Request(); + PutFollowAction.Request request = new PutFollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setFollowerIndex(randomAlphaOfLength(4)); request.waitForActiveShards( randomFrom(ActiveShardCount.DEFAULT, ActiveShardCount.NONE, ActiveShardCount.ONE, ActiveShardCount.ALL) @@ -47,7 +47,7 @@ protected PutFollowAction.Request createTestInstance() { protected PutFollowAction.Request createXContextTestInstance(XContentType xContentType) { // follower index parameter and wait for active shards params are not part of the request body and // are provided in the url path. So these fields cannot be used for creating a test instance for xcontent testing. - PutFollowAction.Request request = new PutFollowAction.Request(); + PutFollowAction.Request request = new PutFollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setRemoteCluster(randomAlphaOfLength(4)); request.setLeaderIndex(randomAlphaOfLength(4)); request.setSettings( @@ -61,7 +61,7 @@ protected PutFollowAction.Request createXContextTestInstance(XContentType xConte @Override protected PutFollowAction.Request doParseInstance(XContentParser parser) throws IOException { - PutFollowAction.Request request = PutFollowAction.Request.fromXContent(parser); + PutFollowAction.Request request = PutFollowAction.Request.fromXContent(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, parser); request.waitForActiveShards(ActiveShardCount.DEFAULT); request.setFollowerIndex("followerIndex"); return request; @@ -69,7 +69,7 @@ protected PutFollowAction.Request doParseInstance(XContentParser parser) throws @Override protected PutFollowAction.Request mutateInstance(PutFollowAction.Request instance) { - PutFollowAction.Request request = new PutFollowAction.Request(); + PutFollowAction.Request request = new PutFollowAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setFollowerIndex(instance.getFollowerIndex()); request.waitForActiveShards(instance.waitForActiveShards()); request.setRemoteCluster(instance.getRemoteCluster()); diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/ResumeFollowActionRequestTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/ResumeFollowActionRequestTests.java index 8a835a4d1f715..475c9135d4946 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/ResumeFollowActionRequestTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/ResumeFollowActionRequestTests.java @@ -32,7 +32,7 @@ protected Writeable.Reader instanceReader() { @Override protected ResumeFollowAction.Request createTestInstance() { - ResumeFollowAction.Request request = new ResumeFollowAction.Request(); + ResumeFollowAction.Request request = new ResumeFollowAction.Request(TEST_REQUEST_TIMEOUT); request.setFollowerIndex(randomAlphaOfLength(4)); generateFollowParameters(request.getParameters()); @@ -48,14 +48,14 @@ protected ResumeFollowAction.Request mutateInstance(ResumeFollowAction.Request i protected ResumeFollowAction.Request createXContextTestInstance(XContentType type) { // follower index parameter is not part of the request body and is provided in the url path. // So this field cannot be used for creating a test instance for xcontent testing. - ResumeFollowAction.Request request = new ResumeFollowAction.Request(); + ResumeFollowAction.Request request = new ResumeFollowAction.Request(TEST_REQUEST_TIMEOUT); generateFollowParameters(request.getParameters()); return request; } @Override protected ResumeFollowAction.Request doParseInstance(XContentParser parser) throws IOException { - return ResumeFollowAction.Request.fromXContent(parser, null); + return ResumeFollowAction.Request.fromXContent(TEST_REQUEST_TIMEOUT, parser, null); } static void generateFollowParameters(FollowParameters followParameters) { @@ -92,7 +92,7 @@ static void generateFollowParameters(FollowParameters followParameters) { } public void testValidate() { - ResumeFollowAction.Request request = new ResumeFollowAction.Request(); + ResumeFollowAction.Request request = new ResumeFollowAction.Request(TEST_REQUEST_TIMEOUT); request.setFollowerIndex("index2"); request.getParameters().setMaxRetryDelay(TimeValue.ZERO); diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportActivateAutoFollowPatternActionTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportActivateAutoFollowPatternActionTests.java index 206c71e82c52c..3a6a0d90f60ba 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportActivateAutoFollowPatternActionTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportActivateAutoFollowPatternActionTests.java @@ -33,7 +33,10 @@ public class TransportActivateAutoFollowPatternActionTests extends ESTestCase { public void testInnerActivateNoAutoFollowMetadata() { Exception e = expectThrows( ResourceNotFoundException.class, - () -> TransportActivateAutoFollowPatternAction.innerActivate(new Request("test", true), ClusterState.EMPTY_STATE) + () -> TransportActivateAutoFollowPatternAction.innerActivate( + new Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "test", true), + ClusterState.EMPTY_STATE + ) ); assertThat(e.getMessage(), equalTo("auto-follow pattern [test] is missing")); } @@ -54,7 +57,10 @@ public void testInnerActivateDoesNotExist() { .build(); Exception e = expectThrows( ResourceNotFoundException.class, - () -> TransportActivateAutoFollowPatternAction.innerActivate(new Request("does_not_exist", true), clusterState) + () -> TransportActivateAutoFollowPatternAction.innerActivate( + new Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "does_not_exist", true), + clusterState + ) ); assertThat(e.getMessage(), equalTo("auto-follow pattern [does_not_exist] is missing")); } @@ -75,12 +81,17 @@ public void testInnerActivateToggle() { ) .build(); { - Request pauseRequest = new Request("remote_cluster", autoFollowPattern.isActive()); + Request pauseRequest = new Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "remote_cluster", autoFollowPattern.isActive()); ClusterState updatedState = TransportActivateAutoFollowPatternAction.innerActivate(pauseRequest, clusterState); assertThat(updatedState, sameInstance(clusterState)); } { - Request pauseRequest = new Request("remote_cluster", autoFollowPattern.isActive() == false); + Request pauseRequest = new Request( + TEST_REQUEST_TIMEOUT, + TEST_REQUEST_TIMEOUT, + "remote_cluster", + autoFollowPattern.isActive() == false + ); ClusterState updatedState = TransportActivateAutoFollowPatternAction.innerActivate(pauseRequest, clusterState); assertThat(updatedState, not(sameInstance(clusterState))); diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportDeleteAutoFollowPatternActionTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportDeleteAutoFollowPatternActionTests.java index 470c15d86dfb1..f94f23c3695bf 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportDeleteAutoFollowPatternActionTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportDeleteAutoFollowPatternActionTests.java @@ -101,7 +101,7 @@ public void testInnerDelete() { ) .build(); - Request request = new Request("name1"); + Request request = new Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "name1"); AutoFollowMetadata result = TransportDeleteAutoFollowPatternAction.innerDelete(request, clusterState) .getMetadata() .custom(AutoFollowMetadata.TYPE); @@ -154,7 +154,7 @@ public void testInnerDeleteDoesNotExist() { ) .build(); - Request request = new Request("name2"); + Request request = new Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "name2"); Exception e = expectThrows( ResourceNotFoundException.class, () -> TransportDeleteAutoFollowPatternAction.innerDelete(request, clusterState) @@ -165,7 +165,7 @@ public void testInnerDeleteDoesNotExist() { public void testInnerDeleteNoAutoFollowMetadata() { ClusterState clusterState = ClusterState.builder(new ClusterName("us_cluster")).metadata(Metadata.builder()).build(); - Request request = new Request("name1"); + Request request = new Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, "name1"); Exception e = expectThrows( ResourceNotFoundException.class, () -> TransportDeleteAutoFollowPatternAction.innerDelete(request, clusterState) diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportPutAutoFollowPatternActionTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportPutAutoFollowPatternActionTests.java index cd2bca527bfb9..ea37cdf1aae0c 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportPutAutoFollowPatternActionTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportPutAutoFollowPatternActionTests.java @@ -31,7 +31,7 @@ public class TransportPutAutoFollowPatternActionTests extends ESTestCase { public void testInnerPut() { - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setName("name1"); request.setRemoteCluster("eu_cluster"); request.setLeaderIndexPatterns(Collections.singletonList("logs-*")); @@ -73,7 +73,7 @@ public void testInnerPut() { } public void testInnerPut_existingLeaderIndices() { - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setName("name1"); request.setRemoteCluster("eu_cluster"); request.setLeaderIndexPatterns(Collections.singletonList("logs-*")); @@ -129,7 +129,7 @@ public void testInnerPut_existingLeaderIndices() { } public void testInnerPut_existingLeaderIndicesAndAutoFollowMetadata() { - PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(); + PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT); request.setName("name1"); request.setRemoteCluster("eu_cluster"); request.setLeaderIndexPatterns(Arrays.asList("logs-*", "transactions-*")); diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportResumeFollowActionTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportResumeFollowActionTests.java index 1313e5781f122..7de0d775ba150 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportResumeFollowActionTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/TransportResumeFollowActionTests.java @@ -36,7 +36,7 @@ public class TransportResumeFollowActionTests extends ESTestCase { public static ResumeFollowAction.Request resumeFollow(String followerIndex) { - ResumeFollowAction.Request request = new ResumeFollowAction.Request(); + ResumeFollowAction.Request request = new ResumeFollowAction.Request(TEST_REQUEST_TIMEOUT); request.setFollowerIndex(followerIndex); request.getParameters().setMaxRetryDelay(TimeValue.timeValueMillis(10)); request.getParameters().setReadPollTimeout(TimeValue.timeValueMillis(10)); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/ActivateAutoFollowPatternAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/ActivateAutoFollowPatternAction.java index df917b4e97b7d..acab22f620fa0 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/ActivateAutoFollowPatternAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/ActivateAutoFollowPatternAction.java @@ -13,6 +13,7 @@ import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; import java.util.Objects; @@ -33,8 +34,8 @@ public static class Request extends AcknowledgedRequest { private final String name; private final boolean active; - public Request(final String name, final boolean active) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout, final String name, final boolean active) { + super(masterNodeTimeout, ackTimeout); this.name = name; this.active = active; } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/CcrStatsAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/CcrStatsAction.java index b187e5e39dd33..a0ecc5dd566c2 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/CcrStatsAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/CcrStatsAction.java @@ -45,8 +45,8 @@ public Request(StreamInput in) throws IOException { } } - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); + public Request(TimeValue masterNodeTimeout) { + super(masterNodeTimeout); } @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/DeleteAutoFollowPatternAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/DeleteAutoFollowPatternAction.java index e38a1cfd4a2cb..cdacb184744b2 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/DeleteAutoFollowPatternAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/DeleteAutoFollowPatternAction.java @@ -12,6 +12,7 @@ import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; import java.util.Objects; @@ -31,8 +32,8 @@ public static class Request extends AcknowledgedRequest { private final String name; - public Request(String name) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout, String name) { + super(masterNodeTimeout, ackTimeout); this.name = name; } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/FollowInfoAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/FollowInfoAction.java index d979a4cf44b9b..821559e16fa38 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/FollowInfoAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/FollowInfoAction.java @@ -16,6 +16,7 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.xcontent.ChunkedToXContentObject; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.ParseField; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.ToXContentObject; @@ -41,8 +42,8 @@ public static class Request extends MasterNodeReadRequest { private String[] followerIndices; - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); + public Request(TimeValue masterNodeTimeout) { + super(masterNodeTimeout); } public String[] getFollowerIndices() { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/GetAutoFollowPatternAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/GetAutoFollowPatternAction.java index bd6ab5bb5af44..5f08a4c253005 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/GetAutoFollowPatternAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/GetAutoFollowPatternAction.java @@ -13,6 +13,7 @@ import org.elasticsearch.action.support.master.MasterNodeReadRequest; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xpack.core.ccr.AutoFollowMetadata.AutoFollowPattern; @@ -34,8 +35,8 @@ public static class Request extends MasterNodeReadRequest { private String name; - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); + public Request(TimeValue masterNodeTimeout) { + super(masterNodeTimeout); } public Request(StreamInput in) throws IOException { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/PauseFollowAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/PauseFollowAction.java index c6905b2d06a34..54687001fbbbb 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/PauseFollowAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/PauseFollowAction.java @@ -13,6 +13,7 @@ import org.elasticsearch.action.support.master.MasterNodeRequest; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; import java.util.Objects; @@ -30,8 +31,8 @@ public static class Request extends MasterNodeRequest { private final String followIndex; - public Request(String followIndex) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); + public Request(TimeValue masterNodeTimeout, String followIndex) { + super(masterNodeTimeout); this.followIndex = Objects.requireNonNull(followIndex, "followIndex"); } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/PutAutoFollowPatternAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/PutAutoFollowPatternAction.java index 333171d864c4f..dcee7274632eb 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/PutAutoFollowPatternAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/PutAutoFollowPatternAction.java @@ -14,6 +14,7 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.ObjectParser; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; @@ -62,9 +63,10 @@ public static class Request extends AcknowledgedRequest implements ToXC FollowParameters.initParser(PARSER); } - public static Request fromXContent(XContentParser parser, String name) throws IOException { + public static Request fromXContent(TimeValue masterNodeTimeout, TimeValue ackTimeout, XContentParser parser, String name) + throws IOException { PutAutoFollowPatternParameters parameters = PARSER.parse(parser, null); - Request request = new Request(); + Request request = new Request(masterNodeTimeout, ackTimeout); request.setName(name); request.setRemoteCluster(parameters.remoteCluster); request.setLeaderIndexPatterns(parameters.leaderIndexPatterns); @@ -85,8 +87,8 @@ public static Request fromXContent(XContentParser parser, String name) throws IO private FollowParameters parameters = new FollowParameters(); private List leaderIndexExclusionPatterns = Collections.emptyList(); - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout) { + super(masterNodeTimeout, ackTimeout); } @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/PutFollowAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/PutFollowAction.java index db1e84aca9cda..82941c440484d 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/PutFollowAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/PutFollowAction.java @@ -20,6 +20,7 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.Nullable; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.ObjectParser; import org.elasticsearch.xcontent.ParseField; import org.elasticsearch.xcontent.ToXContentObject; @@ -64,10 +65,11 @@ public static final class Request extends AcknowledgedRequest implement FollowParameters.initParser(PARSER); } - public static Request fromXContent(final XContentParser parser) throws IOException { + public static Request fromXContent(TimeValue masterNodeTimeout, TimeValue ackTimeout, final XContentParser parser) + throws IOException { PutFollowParameters parameters = PARSER.parse(parser, null); - Request request = new Request(); + Request request = new Request(masterNodeTimeout, ackTimeout); request.setRemoteCluster(parameters.remoteCluster); request.setLeaderIndex(parameters.leaderIndex); request.setDataStreamName(parameters.dataStreamName); @@ -85,8 +87,8 @@ public static Request fromXContent(final XContentParser parser) throws IOExcepti private FollowParameters parameters = new FollowParameters(); private ActiveShardCount waitForActiveShards = ActiveShardCount.NONE; - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout) { + super(masterNodeTimeout, ackTimeout); } public String getFollowerIndex() { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/ResumeFollowAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/ResumeFollowAction.java index 12ddea8d99578..04c77dbbad952 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/ResumeFollowAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/ResumeFollowAction.java @@ -13,6 +13,7 @@ import org.elasticsearch.action.support.master.MasterNodeRequest; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.ObjectParser; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; @@ -43,9 +44,10 @@ public static class Request extends MasterNodeRequest implements ToXCon FollowParameters.initParser(PARSER); } - public static Request fromXContent(final XContentParser parser, final String followerIndex) throws IOException { + public static Request fromXContent(TimeValue masterNodeTimeout, final XContentParser parser, final String followerIndex) + throws IOException { FollowParameters parameters = PARSER.parse(parser, null); - Request request = new Request(); + Request request = new Request(masterNodeTimeout); request.setFollowerIndex(followerIndex); request.setParameters(parameters); return request; @@ -54,8 +56,8 @@ public static Request fromXContent(final XContentParser parser, final String fol private String followerIndex; private FollowParameters parameters = new FollowParameters(); - public Request() { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT); + public Request(TimeValue masterNodeTimeout) { + super(masterNodeTimeout); } public String getFollowerIndex() { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/UnfollowAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/UnfollowAction.java index 9a5f011f39a1b..1647b67a0e6ec 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/UnfollowAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/UnfollowAction.java @@ -15,6 +15,7 @@ import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.TimeValue; import java.io.IOException; @@ -33,8 +34,8 @@ public static class Request extends AcknowledgedRequest implements Indi private final String followerIndex; - public Request(String followerIndex) { - super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT, DEFAULT_ACK_TIMEOUT); + public Request(TimeValue masterNodeTimeout, TimeValue ackTimeout, String followerIndex) { + super(masterNodeTimeout, ackTimeout); this.followerIndex = followerIndex; } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/PauseFollowerIndexStep.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/PauseFollowerIndexStep.java index 5cecd0eb924f5..d900f168be06c 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/PauseFollowerIndexStep.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/PauseFollowerIndexStep.java @@ -52,8 +52,7 @@ void innerPerformAction(String followerIndex, ClusterState currentClusterState, return; } - PauseFollowAction.Request request = new PauseFollowAction.Request(followerIndex); - request.masterNodeTimeout(TimeValue.MAX_VALUE); + PauseFollowAction.Request request = new PauseFollowAction.Request(TimeValue.MAX_VALUE, followerIndex); getClient().execute(PauseFollowAction.INSTANCE, request, listener.delegateFailureAndWrap((l, r) -> { if (r.isAcknowledged() == false) { throw new ElasticsearchException("pause follow request failed to be acknowledged"); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/UnfollowFollowerIndexStep.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/UnfollowFollowerIndexStep.java index 8b40a23cc3c44..6e07d4e6ac823 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/UnfollowFollowerIndexStep.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/UnfollowFollowerIndexStep.java @@ -33,7 +33,7 @@ public boolean isRetryable() { @Override void innerPerformAction(String followerIndex, ClusterState currentClusterState, ActionListener listener) { - UnfollowAction.Request request = new UnfollowAction.Request(followerIndex).masterNodeTimeout(TimeValue.MAX_VALUE); + final var request = new UnfollowAction.Request(TimeValue.MAX_VALUE, TimeValue.MAX_VALUE, followerIndex); getClient().execute(UnfollowAction.INSTANCE, request, ActionListener.wrap(r -> { if (r.isAcknowledged() == false) { throw new ElasticsearchException("unfollow request failed to be acknowledged"); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ccr/action/CcrStatsActionTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ccr/action/CcrStatsActionTests.java index fab9f8de5339f..7c1e71139cb0c 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ccr/action/CcrStatsActionTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ccr/action/CcrStatsActionTests.java @@ -24,7 +24,7 @@ protected Writeable.Reader instanceReader() { @Override protected CcrStatsAction.Request createTestInstance() { - var request = new CcrStatsAction.Request(); + var request = new CcrStatsAction.Request(TEST_REQUEST_TIMEOUT); request.setTimeout(TimeValue.timeValueSeconds(randomFrom(1, 5, 10, 15))); request.masterNodeTimeout(TimeValue.timeValueSeconds(randomFrom(1, 5, 10, 15))); return request; @@ -34,13 +34,13 @@ protected CcrStatsAction.Request createTestInstance() { protected CcrStatsAction.Request mutateInstance(CcrStatsAction.Request instance) throws IOException { return switch (randomInt(1)) { case 0 -> { - var mutatedInstance = new CcrStatsAction.Request(); + var mutatedInstance = new CcrStatsAction.Request(TEST_REQUEST_TIMEOUT); mutatedInstance.setTimeout(instance.getTimeout()); mutatedInstance.masterNodeTimeout(TimeValue.timeValueSeconds(randomFrom(20, 25, 30))); yield mutatedInstance; } case 1 -> { - var mutatedInstance = new CcrStatsAction.Request(); + var mutatedInstance = new CcrStatsAction.Request(TEST_REQUEST_TIMEOUT); mutatedInstance.setTimeout(TimeValue.timeValueSeconds(randomFrom(20, 25, 30))); mutatedInstance.masterNodeTimeout(instance.masterNodeTimeout()); yield mutatedInstance; @@ -51,7 +51,7 @@ protected CcrStatsAction.Request mutateInstance(CcrStatsAction.Request instance) public void testSerializationBwc() throws IOException { // In previous version `timeout` is not set - var request = new CcrStatsAction.Request(); + var request = new CcrStatsAction.Request(TEST_REQUEST_TIMEOUT); if (randomBoolean()) { request.masterNodeTimeout(TimeValue.timeValueSeconds(randomFrom(20, 25, 30))); } diff --git a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/collector/ccr/StatsCollector.java b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/collector/ccr/StatsCollector.java index 9691756285f76..514540a85eb3b 100644 --- a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/collector/ccr/StatsCollector.java +++ b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/collector/ccr/StatsCollector.java @@ -78,7 +78,7 @@ protected Collection doCollect(final MonitoringDoc.Node node, fin final long timestamp = timestamp(); final String clusterUuid = clusterUuid(clusterState); - final CcrStatsAction.Request request = new CcrStatsAction.Request(); + final CcrStatsAction.Request request = new CcrStatsAction.Request(getCollectionTimeout()); final CcrStatsAction.Response response = client.execute(CcrStatsAction.INSTANCE, request).actionGet(getCollectionTimeout()); final AutoFollowStatsMonitoringDoc autoFollowStatsDoc = new AutoFollowStatsMonitoringDoc( From bdaaa9b838e5529f32de2261fec68102d6436769 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 29 May 2024 07:30:05 -0400 Subject: [PATCH 029/208] ESQL: Drop more "nested" query support (#109130) This was all inherited from QL, but ESQL doesn't support `nested` fields yet. And, when it does, it's not going to support nested fields in the same way as QL. And, finally, none of these methods for nested support weren't called by ESQL at all. So they were only used by a few tests. --- .../esql/core/querydsl/query/BoolQuery.java | 31 ---- .../esql/core/querydsl/query/ExistsQuery.java | 2 +- .../core/querydsl/query/GeoDistanceQuery.java | 2 +- .../esql/core/querydsl/query/LeafQuery.java | 33 ---- .../esql/core/querydsl/query/MatchAll.java | 2 +- .../esql/core/querydsl/query/MatchQuery.java | 2 +- .../core/querydsl/query/MultiMatchQuery.java | 2 +- .../esql/core/querydsl/query/NestedQuery.java | 164 ------------------ .../esql/core/querydsl/query/NotQuery.java | 20 --- .../esql/core/querydsl/query/PrefixQuery.java | 2 +- .../xpack/esql/core/querydsl/query/Query.java | 22 --- .../core/querydsl/query/QueryStringQuery.java | 2 +- .../esql/core/querydsl/query/RangeQuery.java | 2 +- .../esql/core/querydsl/query/RegexQuery.java | 2 +- .../esql/core/querydsl/query/TermQuery.java | 2 +- .../esql/core/querydsl/query/TermsQuery.java | 2 +- .../core/querydsl/query/WildcardQuery.java | 2 +- .../core/querydsl/query/BoolQueryTests.java | 90 ++-------- .../core/querydsl/query/LeafQueryTests.java | 23 +-- .../core/querydsl/query/NestedQueryTests.java | 143 --------------- .../esql/querydsl/query/SingleValueQuery.java | 16 -- .../querydsl/query/SpatialRelatesQuery.java | 16 -- 22 files changed, 27 insertions(+), 555 deletions(-) delete mode 100644 x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQuery.java delete mode 100644 x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQuery.java delete mode 100644 x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQueryTests.java diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQuery.java index 3c0723b62d711..dbd75c93ee0e7 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQuery.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQuery.java @@ -8,12 +8,10 @@ import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.search.sort.NestedSortBuilder; import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.util.CollectionUtils; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -44,35 +42,6 @@ public BoolQuery(Source source, boolean isAnd, List queries) { this.queries = queries; } - @Override - public boolean containsNestedField(String path, String field) { - for (Query query : queries) { - if (query.containsNestedField(path, field)) { - return true; - } - } - return false; - } - - @Override - public Query addNestedField(String path, String field, String format, boolean hasDocValues) { - boolean unchanged = true; - List rewritten = new ArrayList<>(queries.size()); - for (Query query : queries) { - var rewrittenQuery = query.addNestedField(path, field, format, hasDocValues); - unchanged &= rewrittenQuery == query; - rewritten.add(rewrittenQuery); - } - return unchanged ? this : new BoolQuery(source(), isAnd, rewritten); - } - - @Override - public void enrichNestedSort(NestedSortBuilder sort) { - for (Query query : queries) { - query.enrichNestedSort(sort); - } - } - @Override public QueryBuilder asBuilder() { BoolQueryBuilder boolQuery = boolQuery(); diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ExistsQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ExistsQuery.java index 7633f7f3f1e9c..be585232cf8d6 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ExistsQuery.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ExistsQuery.java @@ -11,7 +11,7 @@ import static org.elasticsearch.index.query.QueryBuilders.existsQuery; -public class ExistsQuery extends LeafQuery { +public class ExistsQuery extends Query { private final String name; diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/GeoDistanceQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/GeoDistanceQuery.java index f3c8829c2159b..f7843cec0c88c 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/GeoDistanceQuery.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/GeoDistanceQuery.java @@ -13,7 +13,7 @@ import java.util.Objects; -public class GeoDistanceQuery extends LeafQuery { +public class GeoDistanceQuery extends Query { private final String field; private final double lat; diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQuery.java deleted file mode 100644 index 786114a52c7d5..0000000000000 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQuery.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.core.querydsl.query; - -import org.elasticsearch.search.sort.NestedSortBuilder; -import org.elasticsearch.xpack.esql.core.tree.Source; - -abstract class LeafQuery extends Query { - LeafQuery(Source source) { - super(source); - } - - @Override - public final boolean containsNestedField(String path, String field) { - // No leaf queries are nested - return false; - } - - @Override - public Query addNestedField(String path, String field, String format, boolean hasDocValues) { - // No leaf queries are nested - return this; - } - - @Override - public void enrichNestedSort(NestedSortBuilder sort) { - // No leaf queries are nested - } -} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchAll.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchAll.java index 13f624a283b16..6415a69e2201d 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchAll.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchAll.java @@ -11,7 +11,7 @@ import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; -public class MatchAll extends LeafQuery { +public class MatchAll extends Query { public MatchAll(Source source) { super(source); } diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchQuery.java index 8c9934af9dfa6..3b7948d37cfad 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchQuery.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchQuery.java @@ -22,7 +22,7 @@ import static java.util.Map.entry; -public class MatchQuery extends LeafQuery { +public class MatchQuery extends Query { private static final Map> BUILDER_APPLIERS; diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MultiMatchQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MultiMatchQuery.java index 8bede4f16d00e..71e3cb9fd494a 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MultiMatchQuery.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MultiMatchQuery.java @@ -21,7 +21,7 @@ import static java.util.Map.entry; -public class MultiMatchQuery extends LeafQuery { +public class MultiMatchQuery extends Query { private static final Map> BUILDER_APPLIERS; diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQuery.java deleted file mode 100644 index 65c953cdf818d..0000000000000 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQuery.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * 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.core.querydsl.query; - -import org.apache.lucene.search.join.ScoreMode; -import org.elasticsearch.common.util.Maps; -import org.elasticsearch.index.query.InnerHitBuilder; -import org.elasticsearch.index.query.NestedQueryBuilder; -import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.search.fetch.StoredFieldsContext; -import org.elasticsearch.search.fetch.subphase.FetchSourceContext; -import org.elasticsearch.search.sort.NestedSortBuilder; -import org.elasticsearch.xpack.esql.core.tree.Source; - -import java.util.AbstractMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonList; -import static java.util.Collections.unmodifiableMap; -import static org.elasticsearch.index.query.QueryBuilders.nestedQuery; - -/** - * A query to a nested document. - */ -public class NestedQuery extends Query { - private static long COUNTER = 0; - // TODO: make this configurable - private static final int MAX_INNER_HITS = 99; - private static final List NO_STORED_FIELD = singletonList(StoredFieldsContext._NONE_); - - private final String path; - private final Map> fields; // field -> (useDocValues, format) - private final Query child; - - public NestedQuery(Source source, String path, Query child) { - this(source, path, emptyMap(), child); - } - - public NestedQuery(Source source, String path, Map> fields, Query child) { - super(source); - if (path == null) { - throw new IllegalArgumentException("path is required"); - } - if (fields == null) { - throw new IllegalArgumentException("fields is required"); - } - if (child == null) { - throw new IllegalArgumentException("child is required"); - } - this.path = path; - this.fields = fields; - this.child = child; - } - - @Override - public boolean containsNestedField(String otherPath, String field) { - boolean iContainThisField = this.path.equals(otherPath) && fields.containsKey(field); - boolean myChildContainsThisField = child.containsNestedField(otherPath, field); - return iContainThisField || myChildContainsThisField; - } - - @Override - public Query addNestedField(String otherPath, String field, String format, boolean hasDocValues) { - if (false == this.path.equals(otherPath)) { - // I'm not at the right path so let my child query have a crack at it - Query rewrittenChild = child.addNestedField(otherPath, field, format, hasDocValues); - if (rewrittenChild == child) { - return this; - } - return new NestedQuery(source(), otherPath, fields, rewrittenChild); - } - if (fields.containsKey(field)) { - // I already have the field, no rewriting needed - return this; - } - Map> newFields = Maps.newMapWithExpectedSize(fields.size() + 1); - newFields.putAll(fields); - newFields.put(field, new AbstractMap.SimpleImmutableEntry<>(hasDocValues, format)); - return new NestedQuery(source(), otherPath, unmodifiableMap(newFields), child); - } - - @Override - public void enrichNestedSort(NestedSortBuilder sort) { - child.enrichNestedSort(sort); - if (false == sort.getPath().equals(path)) { - return; - } - - // TODO: Add all filters in nested sorting when https://github.com/elastic/elasticsearch/issues/33079 is implemented - // Adding multiple filters to sort sections makes sense for nested queries where multiple conditions belong to the same - // nested query. The current functionality creates one nested query for each condition involving a nested field. - QueryBuilder childAsBuilder = child.asBuilder(); - if (sort.getFilter() != null && false == sort.getFilter().equals(childAsBuilder)) { - // throw new SqlIllegalArgumentException("nested query should have been grouped in one place"); - return; - } - sort.setFilter(childAsBuilder); - } - - @Override - public QueryBuilder asBuilder() { - // disable score - NestedQueryBuilder query = nestedQuery(path, child.asBuilder(), ScoreMode.None); - - if (fields.isEmpty() == false) { - InnerHitBuilder ihb = new InnerHitBuilder(); - ihb.setSize(0); - ihb.setSize(MAX_INNER_HITS); - ihb.setName(path + "_" + COUNTER++); - - for (Map.Entry> entry : fields.entrySet()) { - if (entry.getValue().getKey()) { - ihb.addFetchField(entry.getKey(), entry.getValue().getValue()); - } else { - ihb.addFetchField(entry.getKey()); - } - } - ihb.setFetchSourceContext(FetchSourceContext.DO_NOT_FETCH_SOURCE); - ihb.setStoredFieldNames(NO_STORED_FIELD); - - query.innerHit(ihb); - } - - return query; - } - - String path() { - return path; - } - - Map> fields() { - return fields; - } - - Query child() { - return child; - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), path, fields, child); - } - - @Override - public boolean equals(Object obj) { - if (false == super.equals(obj)) { - return false; - } - NestedQuery other = (NestedQuery) obj; - return path.equals(other.path) && fields.equals(other.fields) && child.equals(other.child); - } - - @Override - protected String innerToString() { - return path + "." + fields + "[" + child + "]"; - } -} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NotQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NotQuery.java index 4b87bbed80d71..4e36a4ee9f053 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NotQuery.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NotQuery.java @@ -7,7 +7,6 @@ package org.elasticsearch.xpack.esql.core.querydsl.query; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.search.sort.NestedSortBuilder; import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.Objects; @@ -32,25 +31,6 @@ public Query child() { return child; } - @Override - public boolean containsNestedField(String path, String field) { - return child.containsNestedField(path, field); - } - - @Override - public Query addNestedField(String path, String field, String format, boolean hasDocValues) { - Query rewrittenChild = child.addNestedField(path, field, format, hasDocValues); - if (child == rewrittenChild) { - return this; - } - return new NotQuery(source(), child); - } - - @Override - public void enrichNestedSort(NestedSortBuilder sort) { - child.enrichNestedSort(sort); - } - @Override public QueryBuilder asBuilder() { return boolQuery().mustNot(child.asBuilder()); diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/PrefixQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/PrefixQuery.java index 65dd014e72b70..1d98ff53be2f2 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/PrefixQuery.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/PrefixQuery.java @@ -13,7 +13,7 @@ import static org.elasticsearch.index.query.QueryBuilders.prefixQuery; -public class PrefixQuery extends LeafQuery { +public class PrefixQuery extends Query { private final String field, query; private final boolean caseInsensitive; diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/Query.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/Query.java index 19db6aa79846a..f3154eb6cd377 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/Query.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/Query.java @@ -7,7 +7,6 @@ package org.elasticsearch.xpack.esql.core.querydsl.query; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.search.sort.NestedSortBuilder; import org.elasticsearch.xpack.esql.core.tree.Source; /** @@ -45,27 +44,6 @@ public Source source() { return source; } - /** - * Does this query contain a particular nested field? - */ - public abstract boolean containsNestedField(String path, String field); - - /** - * Rewrite this query to one that contains the specified nested field. - *

- * Used to make sure that we fetch nested fields even if they aren't - * explicitly part of the query. - * @return a new query if we could add the nested field, the same query - * instance otherwise - */ - public abstract Query addNestedField(String path, String field, String format, boolean hasDocValues); - - /** - * Attach the one and only one matching nested query's filter to this - * sort. - */ - public abstract void enrichNestedSort(NestedSortBuilder sort); - /** * Convert to an Elasticsearch {@link QueryBuilder} all set up to execute * the query. diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQuery.java index 32cd661cab579..8ac90e6314174 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQuery.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQuery.java @@ -24,7 +24,7 @@ import static java.util.Map.entry; -public class QueryStringQuery extends LeafQuery { +public class QueryStringQuery extends Query { // TODO: it'd be great if these could be constants instead of Strings, needs a core change to make the fields public first private static final Map> BUILDER_APPLIERS = Map.ofEntries( diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RangeQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RangeQuery.java index 745e24fe52fc7..2d66ee86d0f61 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RangeQuery.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RangeQuery.java @@ -16,7 +16,7 @@ import static org.elasticsearch.index.query.QueryBuilders.rangeQuery; -public class RangeQuery extends LeafQuery { +public class RangeQuery extends Query { private final String field; private final Object lower, upper; diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RegexQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RegexQuery.java index 9117c32723d76..a8e48de654196 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RegexQuery.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RegexQuery.java @@ -13,7 +13,7 @@ import static org.elasticsearch.index.query.QueryBuilders.regexpQuery; -public class RegexQuery extends LeafQuery { +public class RegexQuery extends Query { private final String field, regex; private final boolean caseInsensitive; diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermQuery.java index b195be3741ad1..240f9f581b27e 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermQuery.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermQuery.java @@ -14,7 +14,7 @@ import static org.elasticsearch.index.query.QueryBuilders.termQuery; -public class TermQuery extends LeafQuery { +public class TermQuery extends Query { private final String term; private final Object value; diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermsQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermsQuery.java index a35a41ef09aa4..5b0920929853a 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermsQuery.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermsQuery.java @@ -14,7 +14,7 @@ import static org.elasticsearch.index.query.QueryBuilders.termsQuery; -public class TermsQuery extends LeafQuery { +public class TermsQuery extends Query { private final String term; private final Set values; diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/WildcardQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/WildcardQuery.java index be2c771ced815..9266f2b43d081 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/WildcardQuery.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/WildcardQuery.java @@ -14,7 +14,7 @@ import static org.elasticsearch.index.query.QueryBuilders.wildcardQuery; -public class WildcardQuery extends LeafQuery { +public class WildcardQuery extends Query { private final String field, query; private final boolean caseInsensitive; diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQueryTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQueryTests.java index c2f517aba4e1b..1c9d6bc54aebf 100644 --- a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQueryTests.java +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQueryTests.java @@ -6,18 +6,17 @@ */ package org.elasticsearch.xpack.esql.core.querydsl.query; -import org.elasticsearch.search.sort.NestedSortBuilder; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.tree.SourceTests; import org.elasticsearch.xpack.esql.core.util.StringUtils; -import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Function; +import java.util.function.Supplier; -import static java.util.Collections.singletonMap; import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo; @@ -25,12 +24,16 @@ public class BoolQueryTests extends ESTestCase { static BoolQuery randomBoolQuery(int depth) { - return new BoolQuery( - SourceTests.randomSource(), - randomBoolean(), - NestedQueryTests.randomQuery(depth), - NestedQueryTests.randomQuery(depth) - ); + return new BoolQuery(SourceTests.randomSource(), randomBoolean(), randomQuery(depth), randomQuery(depth)); + } + + static Query randomQuery(int depth) { + List> options = new ArrayList<>(); + options.add(MatchQueryTests::randomMatchQuery); + if (depth > 0) { + options.add(() -> BoolQueryTests.randomBoolQuery(depth - 1)); + } + return randomFrom(options).get(); } public void testEqualsAndHashCode() { @@ -45,77 +48,12 @@ private static BoolQuery mutate(BoolQuery query) { List> options = Arrays.asList( q -> new BoolQuery(SourceTests.mutate(q.source()), q.isAnd(), left(q), right(q)), q -> new BoolQuery(q.source(), false == q.isAnd(), left(q), right(q)), - q -> new BoolQuery(q.source(), q.isAnd(), randomValueOtherThan(left(q), () -> NestedQueryTests.randomQuery(5)), right(q)), - q -> new BoolQuery(q.source(), q.isAnd(), left(q), randomValueOtherThan(right(q), () -> NestedQueryTests.randomQuery(5))) + q -> new BoolQuery(q.source(), q.isAnd(), randomValueOtherThan(left(q), () -> randomQuery(5)), right(q)), + q -> new BoolQuery(q.source(), q.isAnd(), left(q), randomValueOtherThan(right(q), () -> randomQuery(5))) ); return randomFrom(options).apply(query); } - public void testContainsNestedField() { - assertFalse(boolQueryWithoutNestedChildren().containsNestedField(randomAlphaOfLength(5), randomAlphaOfLength(5))); - - String path = randomAlphaOfLength(5); - String field = randomAlphaOfLength(5); - assertTrue(boolQueryWithNestedChildren(path, field).containsNestedField(path, field)); - } - - public void testAddNestedField() { - Query q = boolQueryWithoutNestedChildren(); - assertSame(q, q.addNestedField(randomAlphaOfLength(5), randomAlphaOfLength(5), null, randomBoolean())); - - String path = randomAlphaOfLength(5); - String field = randomAlphaOfLength(5); - q = boolQueryWithNestedChildren(path, field); - String newField = randomAlphaOfLength(5); - boolean hasDocValues = randomBoolean(); - Query rewritten = q.addNestedField(path, newField, null, hasDocValues); - assertNotSame(q, rewritten); - assertTrue(rewritten.containsNestedField(path, newField)); - } - - public void testEnrichNestedSort() { - Query q = boolQueryWithoutNestedChildren(); - NestedSortBuilder sort = new NestedSortBuilder(randomAlphaOfLength(5)); - q.enrichNestedSort(sort); - assertNull(sort.getFilter()); - - String path = randomAlphaOfLength(5); - String field = randomAlphaOfLength(5); - q = boolQueryWithNestedChildren(path, field); - sort = new NestedSortBuilder(path); - q.enrichNestedSort(sort); - assertNotNull(sort.getFilter()); - } - - private Query boolQueryWithoutNestedChildren() { - return new BoolQuery( - SourceTests.randomSource(), - randomBoolean(), - new MatchAll(SourceTests.randomSource()), - new MatchAll(SourceTests.randomSource()) - ); - } - - private Query boolQueryWithNestedChildren(String path, String field) { - NestedQuery match = new NestedQuery( - SourceTests.randomSource(), - path, - singletonMap(field, new SimpleImmutableEntry<>(randomBoolean(), null)), - new MatchAll(SourceTests.randomSource()) - ); - Query matchAll = new MatchAll(SourceTests.randomSource()); - Query left; - Query right; - if (randomBoolean()) { - left = match; - right = matchAll; - } else { - left = matchAll; - right = match; - } - return new BoolQuery(SourceTests.randomSource(), randomBoolean(), left, right); - } - public void testToString() { assertEquals( "BoolQuery@1:2[ExistsQuery@1:2[f1] AND ExistsQuery@1:8[f2]]", diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQueryTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQueryTests.java index 1ac96b6d30e8c..15c49f58572cb 100644 --- a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQueryTests.java +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQueryTests.java @@ -7,7 +7,6 @@ package org.elasticsearch.xpack.esql.core.querydsl.query; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.search.sort.NestedSortBuilder; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.esql.core.tree.Location; import org.elasticsearch.xpack.esql.core.tree.Source; @@ -18,7 +17,7 @@ import static org.hamcrest.Matchers.equalTo; public class LeafQueryTests extends ESTestCase { - private static class DummyLeafQuery extends LeafQuery { + private static class DummyLeafQuery extends Query { private DummyLeafQuery(Source source) { super(source); } @@ -47,26 +46,6 @@ private static DummyLeafQuery mutate(DummyLeafQuery query) { return new DummyLeafQuery(SourceTests.mutate(query.source())); } - public void testContainsNestedField() { - Query query = new DummyLeafQuery(SourceTests.randomSource()); - // Leaf queries don't contain nested fields. - assertFalse(query.containsNestedField(randomAlphaOfLength(5), randomAlphaOfLength(5))); - } - - public void testAddNestedField() { - Query query = new DummyLeafQuery(SourceTests.randomSource()); - // Leaf queries don't contain nested fields. - assertSame(query, query.addNestedField(randomAlphaOfLength(5), randomAlphaOfLength(5), null, randomBoolean())); - } - - public void testEnrichNestedSort() { - Query query = new DummyLeafQuery(SourceTests.randomSource()); - // Leaf queries don't contain nested fields. - NestedSortBuilder sort = new NestedSortBuilder(randomAlphaOfLength(5)); - query.enrichNestedSort(sort); - assertNull(sort.getFilter()); - } - public void testNot() { var q = new LeafQueryTests.DummyLeafQuery(new Source(Location.EMPTY, "test")); assertThat(q.negate(new Source(Location.EMPTY, "not")), equalTo(new NotQuery(new Source(Location.EMPTY, "not"), q))); diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQueryTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQueryTests.java deleted file mode 100644 index 1a36531efec52..0000000000000 --- a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQueryTests.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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.core.querydsl.query; - -import org.elasticsearch.common.util.Maps; -import org.elasticsearch.search.sort.NestedSortBuilder; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.esql.core.tree.Source; -import org.elasticsearch.xpack.esql.core.tree.SourceTests; -import org.elasticsearch.xpack.esql.core.util.StringUtils; - -import java.util.AbstractMap.SimpleImmutableEntry; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.function.Supplier; - -import static java.util.Collections.singletonMap; -import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode; -import static org.hamcrest.Matchers.hasEntry; - -public class NestedQueryTests extends ESTestCase { - static Query randomQuery(int depth) { - List> options = new ArrayList<>(); - options.add(MatchQueryTests::randomMatchQuery); - if (depth > 0) { - options.add(() -> randomNestedQuery(depth - 1)); - options.add(() -> BoolQueryTests.randomBoolQuery(depth - 1)); - } - return randomFrom(options).get(); - } - - static NestedQuery randomNestedQuery(int depth) { - return new NestedQuery(SourceTests.randomSource(), randomAlphaOfLength(5), randomFields(), randomQuery(depth)); - } - - private static Map> randomFields() { - int size = between(0, 5); - Map> fields = Maps.newMapWithExpectedSize(size); - while (fields.size() < size) { - fields.put(randomAlphaOfLength(5), new SimpleImmutableEntry<>(randomBoolean(), null)); - } - return fields; - } - - public void testEqualsAndHashCode() { - checkEqualsAndHashCode(randomNestedQuery(5), NestedQueryTests::copy, NestedQueryTests::mutate); - } - - private static NestedQuery copy(NestedQuery query) { - return new NestedQuery(query.source(), query.path(), query.fields(), query.child()); - } - - private static NestedQuery mutate(NestedQuery query) { - List> options = Arrays.asList( - q -> new NestedQuery(SourceTests.mutate(q.source()), q.path(), q.fields(), q.child()), - q -> new NestedQuery(q.source(), randomValueOtherThan(q.path(), () -> randomAlphaOfLength(5)), q.fields(), q.child()), - q -> new NestedQuery(q.source(), q.path(), randomValueOtherThan(q.fields(), NestedQueryTests::randomFields), q.child()), - q -> new NestedQuery(q.source(), q.path(), q.fields(), randomValueOtherThan(q.child(), () -> randomQuery(5))) - ); - return randomFrom(options).apply(query); - } - - public void testContainsNestedField() { - NestedQuery q = randomNestedQuery(0); - for (String field : q.fields().keySet()) { - assertTrue(q.containsNestedField(q.path(), field)); - assertFalse(q.containsNestedField(randomValueOtherThan(q.path(), () -> randomAlphaOfLength(5)), field)); - } - assertFalse(q.containsNestedField(q.path(), randomValueOtherThanMany(q.fields()::containsKey, () -> randomAlphaOfLength(5)))); - } - - public void testAddNestedField() { - NestedQuery q = randomNestedQuery(0); - for (String field : q.fields().keySet()) { - // add does nothing if the field is already there - assertSame(q, q.addNestedField(q.path(), field, null, randomBoolean())); - String otherPath = randomValueOtherThan(q.path(), () -> randomAlphaOfLength(5)); - // add does nothing if the path doesn't match - assertSame(q, q.addNestedField(otherPath, randomAlphaOfLength(5), null, randomBoolean())); - } - - // if the field isn't in the list then add rewrites to a query with all the old fields and the new one - String newField = randomValueOtherThanMany(q.fields()::containsKey, () -> randomAlphaOfLength(5)); - boolean hasDocValues = randomBoolean(); - NestedQuery added = (NestedQuery) q.addNestedField(q.path(), newField, null, hasDocValues); - assertNotSame(q, added); - assertThat(added.fields(), hasEntry(newField, new SimpleImmutableEntry<>(hasDocValues, null))); - assertTrue(added.containsNestedField(q.path(), newField)); - for (Map.Entry> field : q.fields().entrySet()) { - assertThat(added.fields(), hasEntry(field.getKey(), field.getValue())); - assertTrue(added.containsNestedField(q.path(), field.getKey())); - } - } - - public void testEnrichNestedSort() { - NestedQuery q = randomNestedQuery(0); - - // enrich adds the filter if the path matches - { - NestedSortBuilder sort = new NestedSortBuilder(q.path()); - q.enrichNestedSort(sort); - assertEquals(q.child().asBuilder(), sort.getFilter()); - } - - // but doesn't if it doesn't match - { - NestedSortBuilder sort = new NestedSortBuilder(randomValueOtherThan(q.path(), () -> randomAlphaOfLength(5))); - q.enrichNestedSort(sort); - assertNull(sort.getFilter()); - } - - // enriching with the same query twice is fine - { - NestedSortBuilder sort = new NestedSortBuilder(q.path()); - q.enrichNestedSort(sort); - assertEquals(q.child().asBuilder(), sort.getFilter()); - q.enrichNestedSort(sort); - - // But enriching using another query will keep only the first query - Query originalChildQuery = randomValueOtherThan(q.child(), () -> randomQuery(0)); - NestedQuery other = new NestedQuery(SourceTests.randomSource(), q.path(), q.fields(), originalChildQuery); - other.enrichNestedSort(sort); - assertEquals(other.child().asBuilder(), originalChildQuery.asBuilder()); - } - } - - public void testToString() { - NestedQuery q = new NestedQuery( - new Source(1, 1, StringUtils.EMPTY), - "a.b", - singletonMap("f", new SimpleImmutableEntry<>(true, null)), - new MatchAll(new Source(1, 1, StringUtils.EMPTY)) - ); - assertEquals("NestedQuery@1:2[a.b.{f=true=null}[MatchAll@1:2[]]]", q.toString()); - } -} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java index 8dd1cbdef1386..6545e892741d2 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java @@ -39,7 +39,6 @@ import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryRewriteContext; import org.elasticsearch.index.query.SearchExecutionContext; -import org.elasticsearch.search.sort.NestedSortBuilder; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xpack.esql.core.querydsl.query.Query; import org.elasticsearch.xpack.esql.core.tree.Source; @@ -83,21 +82,6 @@ public SingleValueQuery(Query next, String field) { this.field = field; } - @Override - public boolean containsNestedField(String path, String field) { - return next.containsNestedField(path, field); - } - - @Override - public Query addNestedField(String path, String field, String format, boolean hasDocValues) { - return next.addNestedField(path, field, format, hasDocValues); - } - - @Override - public void enrichNestedSort(NestedSortBuilder sort) { - next.enrichNestedSort(sort); - } - @Override public Builder asBuilder() { return new Builder(next.asBuilder(), field, new Stats(), next.source()); diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SpatialRelatesQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SpatialRelatesQuery.java index c7875e79533a7..f02dd63999e27 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SpatialRelatesQuery.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SpatialRelatesQuery.java @@ -31,7 +31,6 @@ import org.elasticsearch.index.query.QueryShardException; import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.lucene.spatial.CartesianShapeDocValuesQuery; -import org.elasticsearch.search.sort.NestedSortBuilder; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xpack.esql.core.querydsl.query.Query; import org.elasticsearch.xpack.esql.core.tree.Source; @@ -57,21 +56,6 @@ public SpatialRelatesQuery(Source source, String field, ShapeField.QueryRelation this.dataType = dataType; } - @Override - public boolean containsNestedField(String path, String field) { - return false; - } - - @Override - public Query addNestedField(String path, String field, String format, boolean hasDocValues) { - return null; - } - - @Override - public void enrichNestedSort(NestedSortBuilder sort) { - - } - @Override public QueryBuilder asBuilder() { return EsqlDataTypes.isSpatialGeo(dataType) ? new GeoShapeQueryBuilder() : new CartesianShapeQueryBuilder(); From b6241711ef49deeaa2d550bd34d4838d0414301c Mon Sep 17 00:00:00 2001 From: Liam Thompson <32779855+leemthompo@users.noreply.github.com> Date: Wed, 29 May 2024 14:00:19 +0200 Subject: [PATCH 030/208] [DOCS] Update CCS matrix for 8.14 (#109142) --- .../ccs-version-compat-matrix.asciidoc | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/docs/reference/search/search-your-data/ccs-version-compat-matrix.asciidoc b/docs/reference/search/search-your-data/ccs-version-compat-matrix.asciidoc index c1d279d3163e8..4a5efe09ea5a0 100644 --- a/docs/reference/search/search-your-data/ccs-version-compat-matrix.asciidoc +++ b/docs/reference/search/search-your-data/ccs-version-compat-matrix.asciidoc @@ -1,23 +1,24 @@ -[cols="^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^"] +[cols="^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^"] |==== -| 17+^h| Remote cluster version +| 18+^h| Remote cluster version h| Local cluster version - | 6.8 | 7.1–7.16 | 7.17 | 8.0 | 8.1 | 8.2 | 8.3 | 8.4 | 8.5 |8.6 |8.7 |8.8 |8.9 |8.10 |8.11 |8.12 | 8.13 -| 6.8 | {yes-icon} | {yes-icon} | {yes-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} -| 7.1–7.16 | {yes-icon} | {yes-icon} | {yes-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} -| 7.17 | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.0 | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.1 | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.2 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.3 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon}|{yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.4 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} |{yes-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.5 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} |{yes-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.6 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.7 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon}| {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.8 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon}| {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.9 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon}| {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.10 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon}| {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.11 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon}| {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.12 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon}| {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon}| {yes-icon} | {yes-icon} -| 8.13 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon}| {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon}| {yes-icon} | {yes-icon} -|==== \ No newline at end of file + | 6.8 | 7.1–7.16 | 7.17 | 8.0 | 8.1 | 8.2 | 8.3 | 8.4 | 8.5 | 8.6 | 8.7 | 8.8 | 8.9 | 8.10 | 8.11 | 8.12 | 8.13 | 8.14 +| 6.8 | {yes-icon} | {yes-icon} | {yes-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} +| 7.1–7.16 | {yes-icon} | {yes-icon} | {yes-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} +| 7.17 | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.0 | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.1 | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.2 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon}| {yes-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.3 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon}| {yes-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.4 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon}| {yes-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.5 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon}| {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.6 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon}| {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.7 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.8 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.9 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.10 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.11 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.12 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.13 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} | {yes-icon} +| 8.14 | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {no-icon} | {yes-icon} | {yes-icon} +|==== From 849c33edeb638efb59860fe1795dc543fa7073b7 Mon Sep 17 00:00:00 2001 From: Kathleen DeRusso Date: Wed, 29 May 2024 08:02:05 -0400 Subject: [PATCH 031/208] Add SearchOrgs to changelog schema (#109135) --- .../src/main/resources/changelog-schema.json | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/build-tools-internal/src/main/resources/changelog-schema.json b/build-tools-internal/src/main/resources/changelog-schema.json index 2a0cda7fa33c9..8bdfb8d6c0b9c 100644 --- a/build-tools-internal/src/main/resources/changelog-schema.json +++ b/build-tools-internal/src/main/resources/changelog-schema.json @@ -39,6 +39,8 @@ "EQL", "ES|QL", "Engine", + "Experiences", + "Extract&Transform", "FIPS", "Features", "Geo", @@ -48,6 +50,7 @@ "ILM+SLM", "IdentityProvider", "Indices APIs", + "Inference", "Infra/CLI", "Infra/Circuit Breakers", "Infra/Core", @@ -76,6 +79,7 @@ "Ranking", "Recovery", "Reindex", + "Relevance", "Rollup", "SQL", "Search", @@ -174,7 +178,9 @@ } }, "then": { - "required": ["breaking"] + "required": [ + "breaking" + ] } }, { @@ -186,7 +192,9 @@ } }, "then": { - "required": ["breaking"] + "required": [ + "breaking" + ] } } ], @@ -198,7 +206,9 @@ } }, "then": { - "required": ["deprecation"] + "required": [ + "deprecation" + ] }, "additionalProperties": false }, From 1e58f3a48557e14c791a8f3c7c3d5329c9278cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Wed, 29 May 2024 14:56:59 +0200 Subject: [PATCH 032/208] [DOCS] Fixes sparse vector query docs. (#109153) --- docs/reference/query-dsl/sparse-vector-query.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/reference/query-dsl/sparse-vector-query.asciidoc b/docs/reference/query-dsl/sparse-vector-query.asciidoc index cb3f855afaa51..9a269ad9712a8 100644 --- a/docs/reference/query-dsl/sparse-vector-query.asciidoc +++ b/docs/reference/query-dsl/sparse-vector-query.asciidoc @@ -36,6 +36,7 @@ GET _search ---- // TEST[skip: Requires inference] +[discrete] === Example request using precomputed vectors [source,console] From 86652bde14e00b330402b2ed5366c0f3fe27300a Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 29 May 2024 09:05:00 -0400 Subject: [PATCH 033/208] ESQL: Make `Source` `Writeable` (#109137) We'd love to move all of the serialization from `PlanNamedTypes` into the the types themselves. But serialization for `Source` is in ESQL proper, not ESQL-core with all of the types that need to be serialized. This moves that serialization. It does so by making an interface in ESQL-core that contains the `query` itself which is required to serialize `Source`. This seems like the simplest way to get started moving serialization. The shim *should* be temporary, but it'll take some time to move things around. --- .../xpack/esql/core/tree/Source.java | 66 +++- .../xpack/esql/core/util/PlanStreamInput.java | 26 ++ .../xpack/esql/core/util/SourceUtils.java | 76 +--- .../xpack/esql/io/stream/PlanNamedTypes.java | 324 +++++++++--------- .../xpack/esql/io/stream/PlanStreamInput.java | 17 +- .../esql/io/stream/PlanStreamOutput.java | 12 - .../xpack/ql/util/SourceUtils.java | 93 ----- 7 files changed, 283 insertions(+), 331 deletions(-) create mode 100644 x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/PlanStreamInput.java delete mode 100644 x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/util/SourceUtils.java diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Source.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Source.java index 23d05bdf99273..2129bd8743d0f 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Source.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Source.java @@ -7,9 +7,17 @@ package org.elasticsearch.xpack.esql.core.tree; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.util.PlanStreamInput; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.io.IOException; import java.util.Objects; -public final class Source { +public final class Source implements Writeable { public static final Source EMPTY = new Source(Location.EMPTY, ""); @@ -25,6 +33,31 @@ public Source(Location location, String text) { this.text = text; } + public static Source readFrom(S in) throws IOException { + if (in.readBoolean() == false) { + return EMPTY; + } + int line = in.readInt(); + int column = in.readInt(); + int charPositionInLine = column - 1; + + int length = in.readInt(); + String text = sourceText(in.sourceText(), line, column, length); + return new Source(new Location(line, charPositionInLine), text); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + if (this == EMPTY) { + out.writeBoolean(false); + return; + } + out.writeBoolean(true); + out.writeInt(location.getLineNumber()); + out.writeInt(location.getColumnNumber()); + out.writeInt(text.length()); + } + // TODO: rename to location() public Location source() { return location; @@ -61,4 +94,35 @@ public String toString() { public static Source synthetic(String text) { return new Source(Location.EMPTY, text); } + + private static String sourceText(String query, int line, int column, int length) { + if (line <= 0 || column <= 0 || query.isEmpty()) { + return StringUtils.EMPTY; + } + int offset = textOffset(query, line, column); + if (offset + length > query.length()) { + throw new QlIllegalArgumentException( + "location [@" + line + ":" + column + "] and length [" + length + "] overrun query size [" + query.length() + "]" + ); + } + return query.substring(offset, offset + length); + } + + private static int textOffset(String query, int line, int column) { + int offset = 0; + if (line > 1) { + String[] lines = query.split("\n"); + if (line > lines.length) { + throw new QlIllegalArgumentException( + "line location [" + line + "] higher than max [" + lines.length + "] in query [" + query + "]" + ); + } + for (int i = 0; i < line - 1; i++) { + offset += lines[i].length() + 1; // +1 accounts for the removed \n + } + } + offset += column - 1; // -1 since column is 1-based indexed + return offset; + } + } diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/PlanStreamInput.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/PlanStreamInput.java new file mode 100644 index 0000000000000..51898f36d5497 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/PlanStreamInput.java @@ -0,0 +1,26 @@ +/* + * 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.core.util; + +import org.elasticsearch.xpack.esql.core.tree.Source; + +/** + * Interface for streams that can serialize plan components. This exists so + * ESQL proper can expose streaming capability to ESQL-core. If the world is kind + * and just we'll remove this when we flatten everything from ESQL-core into + * ESQL proper. + */ +public interface PlanStreamInput { + /** + * The query sent by the user to build this plan. This is used to rebuild + * {@link Source} without sending the query over the wire over and over + * and over again. + */ + String sourceText(); + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/SourceUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/SourceUtils.java index cbcb31c7a3b56..6bed7f06fa2f5 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/SourceUtils.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/SourceUtils.java @@ -9,8 +9,6 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.core.Nullable; -import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; import org.elasticsearch.xpack.esql.core.tree.Location; import org.elasticsearch.xpack.esql.core.tree.Source; @@ -20,74 +18,30 @@ public final class SourceUtils { private SourceUtils() {} + /** + * Write a {@link Source} including the text in it. + * @deprecated replace with {@link Source#writeTo}. + * That's not binary compatible so the replacement is complex. + */ + @Deprecated public static void writeSource(StreamOutput out, Source source) throws IOException { - writeSource(out, source, true); - } - - public static void writeSourceNoText(StreamOutput out, Source source) throws IOException { - writeSource(out, source, false); - } - - public static Source readSource(StreamInput in) throws IOException { - return readSource(in, null); - } - - public static Source readSourceWithText(StreamInput in, String queryText) throws IOException { - return readSource(in, queryText); - } - - private static void writeSource(StreamOutput out, Source source, boolean writeText) throws IOException { out.writeInt(source.source().getLineNumber()); out.writeInt(source.source().getColumnNumber()); - if (writeText) { - out.writeString(source.text()); - } else { - out.writeInt(source.text().length()); - } + out.writeString(source.text()); } - private static Source readSource(StreamInput in, @Nullable String queryText) throws IOException { + /** + * Read a {@link Source} including the text in it. + * @deprecated replace with {@link Source#readFrom(StreamInput)}. + * That's not binary compatible so the replacement is complex. + */ + @Deprecated + public static Source readSource(StreamInput in) throws IOException { int line = in.readInt(); int column = in.readInt(); int charPositionInLine = column - 1; - String text; - if (queryText == null) { - text = in.readString(); - } else { - int length = in.readInt(); - text = sourceText(queryText, line, column, length); - } + String text = in.readString(); return new Source(new Location(line, charPositionInLine), text); } - - private static String sourceText(String query, int line, int column, int length) { - if (line <= 0 || column <= 0 || query.isEmpty()) { - return StringUtils.EMPTY; - } - int offset = textOffset(query, line, column); - if (offset + length > query.length()) { - throw new QlIllegalArgumentException( - "location [@" + line + ":" + column + "] and length [" + length + "] overrun query size [" + query.length() + "]" - ); - } - return query.substring(offset, offset + length); - } - - private static int textOffset(String query, int line, int column) { - int offset = 0; - if (line > 1) { - String[] lines = query.split("\n"); - if (line > lines.length) { - throw new QlIllegalArgumentException( - "line location [" + line + "] higher than max [" + lines.length + "] in query [" + query + "]" - ); - } - for (int i = 0; i < line - 1; i++) { - offset += lines[i].length() + 1; // +1 accounts for the removed \n - } - } - offset += column - 1; // -1 since column is 1-based indexed - return offset; - } } 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 d64d70470c605..e846360258ebe 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 @@ -458,7 +458,7 @@ public static List namedTypeEntries() { // -- physical plan nodes static AggregateExec readAggregateExec(PlanStreamInput in) throws IOException { return new AggregateExec( - in.readSource(), + Source.readFrom(in), in.readPhysicalPlanNode(), in.readCollectionAsList(readerFromPlanReader(PlanStreamInput::readExpression)), readNamedExpressions(in), @@ -468,7 +468,7 @@ static AggregateExec readAggregateExec(PlanStreamInput in) throws IOException { } static void writeAggregateExec(PlanStreamOutput out, AggregateExec aggregateExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writePhysicalPlanNode(aggregateExec.child()); out.writeCollection(aggregateExec.groupings(), writerFromPlanWriter(PlanStreamOutput::writeExpression)); writeNamedExpressions(out, aggregateExec.aggregates()); @@ -477,11 +477,17 @@ static void writeAggregateExec(PlanStreamOutput out, AggregateExec aggregateExec } static DissectExec readDissectExec(PlanStreamInput in) throws IOException { - return new DissectExec(in.readSource(), in.readPhysicalPlanNode(), in.readExpression(), readDissectParser(in), readAttributes(in)); + return new DissectExec( + Source.readFrom(in), + in.readPhysicalPlanNode(), + in.readExpression(), + readDissectParser(in), + readAttributes(in) + ); } static void writeDissectExec(PlanStreamOutput out, DissectExec dissectExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writePhysicalPlanNode(dissectExec.child()); out.writeExpression(dissectExec.inputExpression()); writeDissectParser(out, dissectExec.parser()); @@ -490,7 +496,7 @@ static void writeDissectExec(PlanStreamOutput out, DissectExec dissectExec) thro static EsQueryExec readEsQueryExec(PlanStreamInput in) throws IOException { return new EsQueryExec( - in.readSource(), + Source.readFrom(in), readEsIndex(in), readIndexMode(in), readAttributes(in), @@ -503,7 +509,7 @@ static EsQueryExec readEsQueryExec(PlanStreamInput in) throws IOException { static void writeEsQueryExec(PlanStreamOutput out, EsQueryExec esQueryExec) throws IOException { assert esQueryExec.children().size() == 0; - out.writeNoSource(); + Source.EMPTY.writeTo(out); writeEsIndex(out, esQueryExec.index()); writeIndexMode(out, esQueryExec.indexMode()); writeAttributes(out, esQueryExec.output()); @@ -515,7 +521,7 @@ static void writeEsQueryExec(PlanStreamOutput out, EsQueryExec esQueryExec) thro static EsSourceExec readEsSourceExec(PlanStreamInput in) throws IOException { return new EsSourceExec( - in.readSource(), + Source.readFrom(in), readEsIndex(in), readAttributes(in), in.readOptionalNamedWriteable(QueryBuilder.class), @@ -524,7 +530,7 @@ static EsSourceExec readEsSourceExec(PlanStreamInput in) throws IOException { } static void writeEsSourceExec(PlanStreamOutput out, EsSourceExec esSourceExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); writeEsIndex(out, esSourceExec.index()); writeAttributes(out, esSourceExec.output()); out.writeOptionalNamedWriteable(esSourceExec.query()); @@ -548,17 +554,17 @@ static void writeIndexMode(StreamOutput out, IndexMode indexMode) throws IOExcep } static EvalExec readEvalExec(PlanStreamInput in) throws IOException { - return new EvalExec(in.readSource(), in.readPhysicalPlanNode(), readAliases(in)); + return new EvalExec(Source.readFrom(in), in.readPhysicalPlanNode(), readAliases(in)); } static void writeEvalExec(PlanStreamOutput out, EvalExec evalExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writePhysicalPlanNode(evalExec.child()); writeAliases(out, evalExec.fields()); } static EnrichExec readEnrichExec(PlanStreamInput in) throws IOException { - final Source source = in.readSource(); + final Source source = Source.readFrom(in); final PhysicalPlan child = in.readPhysicalPlanNode(); final NamedExpression matchField = in.readNamedExpression(); final String policyName = in.readString(); @@ -593,7 +599,7 @@ static EnrichExec readEnrichExec(PlanStreamInput in) throws IOException { } static void writeEnrichExec(PlanStreamOutput out, EnrichExec enrich) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writePhysicalPlanNode(enrich.child()); out.writeNamedExpression(enrich.matchField()); out.writeString(enrich.policyName()); @@ -616,29 +622,29 @@ static void writeEnrichExec(PlanStreamOutput out, EnrichExec enrich) throws IOEx } static ExchangeExec readExchangeExec(PlanStreamInput in) throws IOException { - return new ExchangeExec(in.readSource(), readAttributes(in), in.readBoolean(), in.readPhysicalPlanNode()); + return new ExchangeExec(Source.readFrom(in), readAttributes(in), in.readBoolean(), in.readPhysicalPlanNode()); } static void writeExchangeExec(PlanStreamOutput out, ExchangeExec exchangeExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); writeAttributes(out, exchangeExec.output()); out.writeBoolean(exchangeExec.isInBetweenAggs()); out.writePhysicalPlanNode(exchangeExec.child()); } static ExchangeSinkExec readExchangeSinkExec(PlanStreamInput in) throws IOException { - return new ExchangeSinkExec(in.readSource(), readAttributes(in), in.readBoolean(), in.readPhysicalPlanNode()); + return new ExchangeSinkExec(Source.readFrom(in), readAttributes(in), in.readBoolean(), in.readPhysicalPlanNode()); } static void writeExchangeSinkExec(PlanStreamOutput out, ExchangeSinkExec exchangeSinkExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); writeAttributes(out, exchangeSinkExec.output()); out.writeBoolean(exchangeSinkExec.isIntermediateAgg()); out.writePhysicalPlanNode(exchangeSinkExec.child()); } static ExchangeSourceExec readExchangeSourceExec(PlanStreamInput in) throws IOException { - return new ExchangeSourceExec(in.readSource(), readAttributes(in), in.readBoolean()); + return new ExchangeSourceExec(Source.readFrom(in), readAttributes(in), in.readBoolean()); } static void writeExchangeSourceExec(PlanStreamOutput out, ExchangeSourceExec exchangeSourceExec) throws IOException { @@ -647,28 +653,28 @@ static void writeExchangeSourceExec(PlanStreamOutput out, ExchangeSourceExec exc } static FieldExtractExec readFieldExtractExec(PlanStreamInput in) throws IOException { - return new FieldExtractExec(in.readSource(), in.readPhysicalPlanNode(), readAttributes(in)); + return new FieldExtractExec(Source.readFrom(in), in.readPhysicalPlanNode(), readAttributes(in)); } static void writeFieldExtractExec(PlanStreamOutput out, FieldExtractExec fieldExtractExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writePhysicalPlanNode(fieldExtractExec.child()); writeAttributes(out, fieldExtractExec.attributesToExtract()); } static FilterExec readFilterExec(PlanStreamInput in) throws IOException { - return new FilterExec(in.readSource(), in.readPhysicalPlanNode(), in.readExpression()); + return new FilterExec(Source.readFrom(in), in.readPhysicalPlanNode(), in.readExpression()); } static void writeFilterExec(PlanStreamOutput out, FilterExec filterExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writePhysicalPlanNode(filterExec.child()); out.writeExpression(filterExec.condition()); } static FragmentExec readFragmentExec(PlanStreamInput in) throws IOException { return new FragmentExec( - in.readSource(), + Source.readFrom(in), in.readLogicalPlanNode(), in.readOptionalNamedWriteable(QueryBuilder.class), in.readOptionalVInt(), @@ -677,7 +683,7 @@ static FragmentExec readFragmentExec(PlanStreamInput in) throws IOException { } static void writeFragmentExec(PlanStreamOutput out, FragmentExec fragmentExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeLogicalPlanNode(fragmentExec.fragment()); out.writeOptionalNamedWriteable(fragmentExec.esFilter()); out.writeOptionalVInt(fragmentExec.estimatedRowSize()); @@ -689,7 +695,7 @@ static void writeFragmentExec(PlanStreamOutput out, FragmentExec fragmentExec) t static GrokExec readGrokExec(PlanStreamInput in) throws IOException { Source source; return new GrokExec( - source = in.readSource(), + source = Source.readFrom(in), in.readPhysicalPlanNode(), in.readExpression(), Grok.pattern(source, in.readString()), @@ -698,7 +704,7 @@ static GrokExec readGrokExec(PlanStreamInput in) throws IOException { } static void writeGrokExec(PlanStreamOutput out, GrokExec grokExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writePhysicalPlanNode(grokExec.child()); out.writeExpression(grokExec.inputExpression()); out.writeString(grokExec.pattern().pattern()); @@ -706,21 +712,21 @@ static void writeGrokExec(PlanStreamOutput out, GrokExec grokExec) throws IOExce } static LimitExec readLimitExec(PlanStreamInput in) throws IOException { - return new LimitExec(in.readSource(), in.readPhysicalPlanNode(), in.readNamed(Expression.class)); + return new LimitExec(Source.readFrom(in), in.readPhysicalPlanNode(), in.readNamed(Expression.class)); } static void writeLimitExec(PlanStreamOutput out, LimitExec limitExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writePhysicalPlanNode(limitExec.child()); out.writeExpression(limitExec.limit()); } static MvExpandExec readMvExpandExec(PlanStreamInput in) throws IOException { - return new MvExpandExec(in.readSource(), in.readPhysicalPlanNode(), in.readNamedExpression(), in.readAttribute()); + return new MvExpandExec(Source.readFrom(in), in.readPhysicalPlanNode(), in.readNamedExpression(), in.readAttribute()); } static void writeMvExpandExec(PlanStreamOutput out, MvExpandExec mvExpandExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writePhysicalPlanNode(mvExpandExec.child()); out.writeNamedExpression(mvExpandExec.target()); out.writeAttribute(mvExpandExec.expanded()); @@ -728,52 +734,52 @@ static void writeMvExpandExec(PlanStreamOutput out, MvExpandExec mvExpandExec) t static OrderExec readOrderExec(PlanStreamInput in) throws IOException { return new OrderExec( - in.readSource(), + Source.readFrom(in), in.readPhysicalPlanNode(), in.readCollectionAsList(readerFromPlanReader(PlanNamedTypes::readOrder)) ); } static void writeOrderExec(PlanStreamOutput out, OrderExec orderExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writePhysicalPlanNode(orderExec.child()); out.writeCollection(orderExec.order(), writerFromPlanWriter(PlanNamedTypes::writeOrder)); } static ProjectExec readProjectExec(PlanStreamInput in) throws IOException { - return new ProjectExec(in.readSource(), in.readPhysicalPlanNode(), readNamedExpressions(in)); + return new ProjectExec(Source.readFrom(in), in.readPhysicalPlanNode(), readNamedExpressions(in)); } static void writeProjectExec(PlanStreamOutput out, ProjectExec projectExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writePhysicalPlanNode(projectExec.child()); writeNamedExpressions(out, projectExec.projections()); } static RowExec readRowExec(PlanStreamInput in) throws IOException { - return new RowExec(in.readSource(), readAliases(in)); + return new RowExec(Source.readFrom(in), readAliases(in)); } static void writeRowExec(PlanStreamOutput out, RowExec rowExec) throws IOException { assert rowExec.children().size() == 0; - out.writeNoSource(); + Source.EMPTY.writeTo(out); writeAliases(out, rowExec.fields()); } @SuppressWarnings("unchecked") static ShowExec readShowExec(PlanStreamInput in) throws IOException { - return new ShowExec(in.readSource(), readAttributes(in), (List>) in.readGenericValue()); + return new ShowExec(Source.readFrom(in), readAttributes(in), (List>) in.readGenericValue()); } static void writeShowExec(PlanStreamOutput out, ShowExec showExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); writeAttributes(out, showExec.output()); out.writeGenericValue(showExec.values()); } static TopNExec readTopNExec(PlanStreamInput in) throws IOException { return new TopNExec( - in.readSource(), + Source.readFrom(in), in.readPhysicalPlanNode(), in.readCollectionAsList(readerFromPlanReader(PlanNamedTypes::readOrder)), in.readNamed(Expression.class), @@ -782,7 +788,7 @@ static TopNExec readTopNExec(PlanStreamInput in) throws IOException { } static void writeTopNExec(PlanStreamOutput out, TopNExec topNExec) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writePhysicalPlanNode(topNExec.child()); out.writeCollection(topNExec.order(), writerFromPlanWriter(PlanNamedTypes::writeOrder)); out.writeExpression(topNExec.limit()); @@ -792,7 +798,7 @@ static void writeTopNExec(PlanStreamOutput out, TopNExec topNExec) throws IOExce // -- Logical plan nodes static Aggregate readAggregate(PlanStreamInput in) throws IOException { return new Aggregate( - in.readSource(), + Source.readFrom(in), in.readLogicalPlanNode(), in.readCollectionAsList(readerFromPlanReader(PlanStreamInput::readExpression)), readNamedExpressions(in) @@ -800,18 +806,18 @@ static Aggregate readAggregate(PlanStreamInput in) throws IOException { } static void writeAggregate(PlanStreamOutput out, Aggregate aggregate) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeLogicalPlanNode(aggregate.child()); out.writeCollection(aggregate.groupings(), writerFromPlanWriter(PlanStreamOutput::writeExpression)); writeNamedExpressions(out, aggregate.aggregates()); } static Dissect readDissect(PlanStreamInput in) throws IOException { - return new Dissect(in.readSource(), in.readLogicalPlanNode(), in.readExpression(), readDissectParser(in), readAttributes(in)); + return new Dissect(Source.readFrom(in), in.readLogicalPlanNode(), in.readExpression(), readDissectParser(in), readAttributes(in)); } static void writeDissect(PlanStreamOutput out, Dissect dissect) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeLogicalPlanNode(dissect.child()); out.writeExpression(dissect.input()); writeDissectParser(out, dissect.parser()); @@ -819,7 +825,7 @@ static void writeDissect(PlanStreamOutput out, Dissect dissect) throws IOExcepti } static EsRelation readEsRelation(PlanStreamInput in) throws IOException { - Source source = in.readSource(); + Source source = Source.readFrom(in); EsIndex esIndex = readEsIndex(in); List attributes = readAttributes(in); if (supportingEsSourceOptions(in.getTransportVersion())) { @@ -832,7 +838,7 @@ static EsRelation readEsRelation(PlanStreamInput in) throws IOException { static void writeEsRelation(PlanStreamOutput out, EsRelation relation) throws IOException { assert relation.children().size() == 0; - out.writeNoSource(); + Source.EMPTY.writeTo(out); writeEsIndex(out, relation.index()); writeAttributes(out, relation.output()); if (supportingEsSourceOptions(out.getTransportVersion())) { @@ -866,11 +872,11 @@ private static void writeEsSourceOptions(PlanStreamOutput out) throws IOExceptio } static Eval readEval(PlanStreamInput in) throws IOException { - return new Eval(in.readSource(), in.readLogicalPlanNode(), readAliases(in)); + return new Eval(Source.readFrom(in), in.readLogicalPlanNode(), readAliases(in)); } static void writeEval(PlanStreamOutput out, Eval eval) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeLogicalPlanNode(eval.child()); writeAliases(out, eval.fields()); } @@ -880,7 +886,7 @@ static Enrich readEnrich(PlanStreamInput in) throws IOException { if (in.getTransportVersion().onOrAfter(TransportVersions.V_8_13_0)) { mode = in.readEnum(Enrich.Mode.class); } - final Source source = in.readSource(); + final Source source = Source.readFrom(in); final LogicalPlan child = in.readLogicalPlanNode(); final Expression policyName = in.readExpression(); final NamedExpression matchField = in.readNamedExpression(); @@ -906,7 +912,7 @@ static void writeEnrich(PlanStreamOutput out, Enrich enrich) throws IOException out.writeEnum(enrich.mode()); } - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeLogicalPlanNode(enrich.child()); out.writeExpression(enrich.policyName()); out.writeNamedExpression(enrich.matchField()); @@ -930,21 +936,21 @@ static void writeEnrich(PlanStreamOutput out, Enrich enrich) throws IOException } static EsqlProject readEsqlProject(PlanStreamInput in) throws IOException { - return new EsqlProject(in.readSource(), in.readLogicalPlanNode(), readNamedExpressions(in)); + return new EsqlProject(Source.readFrom(in), in.readLogicalPlanNode(), readNamedExpressions(in)); } static void writeEsqlProject(PlanStreamOutput out, EsqlProject project) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeLogicalPlanNode(project.child()); writeNamedExpressions(out, project.projections()); } static Filter readFilter(PlanStreamInput in) throws IOException { - return new Filter(in.readSource(), in.readLogicalPlanNode(), in.readExpression()); + return new Filter(Source.readFrom(in), in.readLogicalPlanNode(), in.readExpression()); } static void writeFilter(PlanStreamOutput out, Filter filter) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeLogicalPlanNode(filter.child()); out.writeExpression(filter.condition()); } @@ -952,7 +958,7 @@ static void writeFilter(PlanStreamOutput out, Filter filter) throws IOException static Grok readGrok(PlanStreamInput in) throws IOException { Source source; return new Grok( - source = in.readSource(), + source = Source.readFrom(in), in.readLogicalPlanNode(), in.readExpression(), Grok.pattern(source, in.readString()), @@ -961,7 +967,7 @@ static Grok readGrok(PlanStreamInput in) throws IOException { } static void writeGrok(PlanStreamOutput out, Grok grok) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeLogicalPlanNode(grok.child()); out.writeExpression(grok.input()); out.writeString(grok.parser().pattern()); @@ -969,21 +975,21 @@ static void writeGrok(PlanStreamOutput out, Grok grok) throws IOException { } static Limit readLimit(PlanStreamInput in) throws IOException { - return new Limit(in.readSource(), in.readNamed(Expression.class), in.readLogicalPlanNode()); + return new Limit(Source.readFrom(in), in.readNamed(Expression.class), in.readLogicalPlanNode()); } static void writeLimit(PlanStreamOutput out, Limit limit) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeExpression(limit.limit()); out.writeLogicalPlanNode(limit.child()); } static MvExpand readMvExpand(PlanStreamInput in) throws IOException { - return new MvExpand(in.readSource(), in.readLogicalPlanNode(), in.readNamedExpression(), in.readAttribute()); + return new MvExpand(Source.readFrom(in), in.readLogicalPlanNode(), in.readNamedExpression(), in.readAttribute()); } static void writeMvExpand(PlanStreamOutput out, MvExpand mvExpand) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeLogicalPlanNode(mvExpand.child()); out.writeNamedExpression(mvExpand.target()); out.writeAttribute(mvExpand.expanded()); @@ -991,31 +997,31 @@ static void writeMvExpand(PlanStreamOutput out, MvExpand mvExpand) throws IOExce static OrderBy readOrderBy(PlanStreamInput in) throws IOException { return new OrderBy( - in.readSource(), + Source.readFrom(in), in.readLogicalPlanNode(), in.readCollectionAsList(readerFromPlanReader(PlanNamedTypes::readOrder)) ); } static void writeOrderBy(PlanStreamOutput out, OrderBy order) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeLogicalPlanNode(order.child()); out.writeCollection(order.order(), writerFromPlanWriter(PlanNamedTypes::writeOrder)); } static Project readProject(PlanStreamInput in) throws IOException { - return new Project(in.readSource(), in.readLogicalPlanNode(), readNamedExpressions(in)); + return new Project(Source.readFrom(in), in.readLogicalPlanNode(), readNamedExpressions(in)); } static void writeProject(PlanStreamOutput out, Project project) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeLogicalPlanNode(project.child()); writeNamedExpressions(out, project.projections()); } static TopN readTopN(PlanStreamInput in) throws IOException { return new TopN( - in.readSource(), + Source.readFrom(in), in.readLogicalPlanNode(), in.readCollectionAsList(readerFromPlanReader(PlanNamedTypes::readOrder)), in.readNamed(Expression.class) @@ -1023,7 +1029,7 @@ static TopN readTopN(PlanStreamInput in) throws IOException { } static void writeTopN(PlanStreamOutput out, TopN topN) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeLogicalPlanNode(topN.child()); out.writeCollection(topN.order(), writerFromPlanWriter(PlanNamedTypes::writeOrder)); out.writeExpression(topN.limit()); @@ -1059,7 +1065,7 @@ static void writeAliases(PlanStreamOutput out, List aliases) throws IOExc static FieldAttribute readFieldAttribute(PlanStreamInput in) throws IOException { return new FieldAttribute( - in.readSource(), + Source.readFrom(in), in.readOptionalWithReader(PlanNamedTypes::readFieldAttribute), in.readString(), in.dataTypeFromTypeName(in.readString()), @@ -1072,7 +1078,7 @@ static FieldAttribute readFieldAttribute(PlanStreamInput in) throws IOException } static void writeFieldAttribute(PlanStreamOutput out, FieldAttribute fileAttribute) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeOptionalWriteable(fileAttribute.parent() == null ? null : o -> writeFieldAttribute(out, fileAttribute.parent())); out.writeString(fileAttribute.name()); out.writeString(fileAttribute.dataType().typeName()); @@ -1085,7 +1091,7 @@ static void writeFieldAttribute(PlanStreamOutput out, FieldAttribute fileAttribu static ReferenceAttribute readReferenceAttr(PlanStreamInput in) throws IOException { return new ReferenceAttribute( - in.readSource(), + Source.readFrom(in), in.readString(), in.dataTypeFromTypeName(in.readString()), in.readOptionalString(), @@ -1096,7 +1102,7 @@ static ReferenceAttribute readReferenceAttr(PlanStreamInput in) throws IOExcepti } static void writeReferenceAttr(PlanStreamOutput out, ReferenceAttribute referenceAttribute) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeString(referenceAttribute.name()); out.writeString(referenceAttribute.dataType().typeName()); out.writeOptionalString(referenceAttribute.qualifier()); @@ -1107,7 +1113,7 @@ static void writeReferenceAttr(PlanStreamOutput out, ReferenceAttribute referenc static MetadataAttribute readMetadataAttr(PlanStreamInput in) throws IOException { return new MetadataAttribute( - in.readSource(), + Source.readFrom(in), in.readString(), in.dataTypeFromTypeName(in.readString()), in.readOptionalString(), @@ -1119,7 +1125,7 @@ static MetadataAttribute readMetadataAttr(PlanStreamInput in) throws IOException } static void writeMetadataAttr(PlanStreamOutput out, MetadataAttribute metadataAttribute) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeString(metadataAttribute.name()); out.writeString(metadataAttribute.dataType().typeName()); out.writeOptionalString(metadataAttribute.qualifier()); @@ -1131,7 +1137,7 @@ static void writeMetadataAttr(PlanStreamOutput out, MetadataAttribute metadataAt static UnsupportedAttribute readUnsupportedAttr(PlanStreamInput in) throws IOException { return new UnsupportedAttribute( - in.readSource(), + Source.readFrom(in), in.readString(), readUnsupportedEsField(in), in.readOptionalString(), @@ -1140,7 +1146,7 @@ static UnsupportedAttribute readUnsupportedAttr(PlanStreamInput in) throws IOExc } static void writeUnsupportedAttr(PlanStreamOutput out, UnsupportedAttribute unsupportedAttribute) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeString(unsupportedAttribute.name()); writeUnsupportedEsField(out, unsupportedAttribute.field()); out.writeOptionalString(unsupportedAttribute.hasCustomMessage() ? unsupportedAttribute.unresolvedMessage() : null); @@ -1250,7 +1256,7 @@ static void writeUnsupportedEsField(PlanStreamOutput out, UnsupportedEsField uns // -- BinaryComparison static EsqlBinaryComparison readBinComparison(PlanStreamInput in, String name) throws IOException { - var source = in.readSource(); + var source = Source.readFrom(in); EsqlBinaryComparison.BinaryComparisonOperation operation = EsqlBinaryComparison.BinaryComparisonOperation.readFromStream(in); var left = in.readExpression(); var right = in.readExpression(); @@ -1260,7 +1266,7 @@ static EsqlBinaryComparison readBinComparison(PlanStreamInput in, String name) t } static void writeBinComparison(PlanStreamOutput out, EsqlBinaryComparison binaryComparison) throws IOException { - out.writeSource(binaryComparison.source()); + binaryComparison.source().writeTo(out); binaryComparison.getFunctionType().writeTo(out); out.writeExpression(binaryComparison.left()); out.writeExpression(binaryComparison.right()); @@ -1269,14 +1275,14 @@ static void writeBinComparison(PlanStreamOutput out, EsqlBinaryComparison binary // -- InsensitiveEquals static InsensitiveEquals readInsensitiveEquals(PlanStreamInput in, String name) throws IOException { - var source = in.readSource(); + var source = Source.readFrom(in); var left = in.readExpression(); var right = in.readExpression(); return new InsensitiveEquals(source, left, right); } static void writeInsensitiveEquals(PlanStreamOutput out, InsensitiveEquals eq) throws IOException { - out.writeSource(eq.source()); + eq.source().writeTo(out); out.writeExpression(eq.left()); out.writeExpression(eq.right()); } @@ -1284,11 +1290,15 @@ static void writeInsensitiveEquals(PlanStreamOutput out, InsensitiveEquals eq) t // -- InComparison static In readInComparison(PlanStreamInput in) throws IOException { - return new In(in.readSource(), in.readExpression(), in.readCollectionAsList(readerFromPlanReader(PlanStreamInput::readExpression))); + return new In( + Source.readFrom(in), + in.readExpression(), + in.readCollectionAsList(readerFromPlanReader(PlanStreamInput::readExpression)) + ); } static void writeInComparison(PlanStreamOutput out, In in) throws IOException { - out.writeSource(in.source()); + in.source().writeTo(out); out.writeExpression(in.value()); out.writeCollection(in.list(), writerFromPlanWriter(PlanStreamOutput::writeExpression)); } @@ -1296,21 +1306,21 @@ static void writeInComparison(PlanStreamOutput out, In in) throws IOException { // -- RegexMatch static WildcardLike readWildcardLike(PlanStreamInput in, String name) throws IOException { - return new WildcardLike(in.readSource(), in.readExpression(), new WildcardPattern(in.readString())); + return new WildcardLike(Source.readFrom(in), in.readExpression(), new WildcardPattern(in.readString())); } static void writeWildcardLike(PlanStreamOutput out, WildcardLike like) throws IOException { - out.writeSource(like.source()); + like.source().writeTo(out); out.writeExpression(like.field()); out.writeString(like.pattern().pattern()); } static RLike readRLike(PlanStreamInput in, String name) throws IOException { - return new RLike(in.readSource(), in.readExpression(), new RLikePattern(in.readString())); + return new RLike(Source.readFrom(in), in.readExpression(), new RLikePattern(in.readString())); } static void writeRLike(PlanStreamOutput out, RLike like) throws IOException { - out.writeSource(like.source()); + like.source().writeTo(out); out.writeExpression(like.field()); out.writeString(like.pattern().asJavaRegex()); } @@ -1323,14 +1333,14 @@ static void writeRLike(PlanStreamOutput out, RLike like) throws IOException { ); static BinaryLogic readBinaryLogic(PlanStreamInput in, String name) throws IOException { - var source = in.readSource(); + var source = Source.readFrom(in); var left = in.readExpression(); var right = in.readExpression(); return BINARY_LOGIC_CTRS.get(name).apply(source, left, right); } static void writeBinaryLogic(PlanStreamOutput out, BinaryLogic binaryLogic) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeExpression(binaryLogic.left()); out.writeExpression(binaryLogic.right()); } @@ -1385,11 +1395,11 @@ static UnaryScalarFunction readESQLUnaryScalar(PlanStreamInput in, String name) if (ctr == null) { throw new IOException("Constructor for ESQLUnaryScalar not found for name:" + name); } - return ctr.apply(in.readSource(), in.readExpression()); + return ctr.apply(Source.readFrom(in), in.readExpression()); } static void writeESQLUnaryScalar(PlanStreamOutput out, UnaryScalarFunction function) throws IOException { - out.writeSource(function.source()); + function.source().writeTo(out); out.writeExpression(function.field()); } @@ -1404,11 +1414,11 @@ static ScalarFunction readNoArgScalar(PlanStreamInput in, String name) throws IO if (ctr == null) { throw new IOException("Constructor not found:" + name); } - return ctr.apply(in.readSource()); + return ctr.apply(Source.readFrom(in)); } static void writeNoArgScalar(PlanStreamOutput out, ScalarFunction function) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); } static final Map< @@ -1430,32 +1440,32 @@ static org.elasticsearch.xpack.esql.core.expression.function.scalar.UnaryScalarF if (ctr == null) { throw new IOException("Constructor for QLUnaryScalar not found for name:" + name); } - return ctr.apply(in.readSource(), in.readExpression()); + return ctr.apply(Source.readFrom(in), in.readExpression()); } static void writeQLUnaryScalar( PlanStreamOutput out, org.elasticsearch.xpack.esql.core.expression.function.scalar.UnaryScalarFunction function ) throws IOException { - out.writeSource(function.source()); + function.source().writeTo(out); out.writeExpression(function.field()); } // -- ScalarFunction static Atan2 readAtan2(PlanStreamInput in) throws IOException { - return new Atan2(in.readSource(), in.readExpression(), in.readExpression()); + return new Atan2(Source.readFrom(in), in.readExpression(), in.readExpression()); } static void writeAtan2(PlanStreamOutput out, Atan2 atan2) throws IOException { - out.writeSource(atan2.source()); + atan2.source().writeTo(out); out.writeExpression(atan2.y()); out.writeExpression(atan2.x()); } static Bucket readBucket(PlanStreamInput in) throws IOException { return new Bucket( - in.readSource(), + Source.readFrom(in), in.readExpression(), in.readExpression(), in.readOptionalNamed(Expression.class), @@ -1464,7 +1474,7 @@ static Bucket readBucket(PlanStreamInput in) throws IOException { } static void writeBucket(PlanStreamOutput out, Bucket bucket) throws IOException { - out.writeSource(bucket.source()); + bucket.source().writeTo(out); out.writeExpression(bucket.field()); out.writeExpression(bucket.buckets()); out.writeOptionalExpression(bucket.from()); @@ -1481,11 +1491,15 @@ static void writeBucket(PlanStreamOutput out, Bucket bucket) throws IOException static ScalarFunction readVarag(PlanStreamInput in, String name) throws IOException { return VARARG_CTORS.get(name) - .apply(in.readSource(), in.readExpression(), in.readCollectionAsList(readerFromPlanReader(PlanStreamInput::readExpression))); + .apply( + Source.readFrom(in), + in.readExpression(), + in.readCollectionAsList(readerFromPlanReader(PlanStreamInput::readExpression)) + ); } static void writeVararg(PlanStreamOutput out, ScalarFunction vararg) throws IOException { - out.writeSource(vararg.source()); + vararg.source().writeTo(out); out.writeExpression(vararg.children().get(0)); out.writeCollection( vararg.children().subList(1, vararg.children().size()), @@ -1494,23 +1508,23 @@ static void writeVararg(PlanStreamOutput out, ScalarFunction vararg) throws IOEx } static CountDistinct readCountDistinct(PlanStreamInput in) throws IOException { - return new CountDistinct(in.readSource(), in.readExpression(), in.readOptionalNamed(Expression.class)); + return new CountDistinct(Source.readFrom(in), in.readExpression(), in.readOptionalNamed(Expression.class)); } static void writeCountDistinct(PlanStreamOutput out, CountDistinct countDistinct) throws IOException { List fields = countDistinct.children(); assert fields.size() == 1 || fields.size() == 2; - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeExpression(fields.get(0)); out.writeOptionalWriteable(fields.size() == 2 ? o -> out.writeExpression(fields.get(1)) : null); } static DateDiff readDateDiff(PlanStreamInput in) throws IOException { - return new DateDiff(in.readSource(), in.readExpression(), in.readExpression(), in.readExpression()); + return new DateDiff(Source.readFrom(in), in.readExpression(), in.readExpression(), in.readExpression()); } static void writeDateDiff(PlanStreamOutput out, DateDiff function) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); List fields = function.children(); assert fields.size() == 3; out.writeExpression(fields.get(0)); @@ -1519,11 +1533,11 @@ static void writeDateDiff(PlanStreamOutput out, DateDiff function) throws IOExce } static DateExtract readDateExtract(PlanStreamInput in) throws IOException { - return new DateExtract(in.readSource(), in.readExpression(), in.readExpression(), in.configuration()); + return new DateExtract(Source.readFrom(in), in.readExpression(), in.readExpression(), in.configuration()); } static void writeDateExtract(PlanStreamOutput out, DateExtract function) throws IOException { - out.writeSource(function.source()); + function.source().writeTo(out); List fields = function.children(); assert fields.size() == 2; out.writeExpression(fields.get(0)); @@ -1531,11 +1545,11 @@ static void writeDateExtract(PlanStreamOutput out, DateExtract function) throws } static DateFormat readDateFormat(PlanStreamInput in) throws IOException { - return new DateFormat(in.readSource(), in.readExpression(), in.readOptionalNamed(Expression.class), in.configuration()); + return new DateFormat(Source.readFrom(in), in.readExpression(), in.readOptionalNamed(Expression.class), in.configuration()); } static void writeDateFormat(PlanStreamOutput out, DateFormat dateFormat) throws IOException { - out.writeSource(dateFormat.source()); + dateFormat.source().writeTo(out); List fields = dateFormat.children(); assert fields.size() == 1 || fields.size() == 2; out.writeExpression(fields.get(0)); @@ -1543,11 +1557,11 @@ static void writeDateFormat(PlanStreamOutput out, DateFormat dateFormat) throws } static DateParse readDateTimeParse(PlanStreamInput in) throws IOException { - return new DateParse(in.readSource(), in.readExpression(), in.readOptionalNamed(Expression.class)); + return new DateParse(Source.readFrom(in), in.readExpression(), in.readOptionalNamed(Expression.class)); } static void writeDateTimeParse(PlanStreamOutput out, DateParse function) throws IOException { - out.writeSource(function.source()); + function.source().writeTo(out); List fields = function.children(); assert fields.size() == 1 || fields.size() == 2; out.writeExpression(fields.get(0)); @@ -1555,11 +1569,11 @@ static void writeDateTimeParse(PlanStreamOutput out, DateParse function) throws } static DateTrunc readDateTrunc(PlanStreamInput in) throws IOException { - return new DateTrunc(in.readSource(), in.readExpression(), in.readExpression()); + return new DateTrunc(Source.readFrom(in), in.readExpression(), in.readExpression()); } static void writeDateTrunc(PlanStreamOutput out, DateTrunc dateTrunc) throws IOException { - out.writeSource(dateTrunc.source()); + dateTrunc.source().writeTo(out); List fields = dateTrunc.children(); assert fields.size() == 2; out.writeExpression(fields.get(0)); @@ -1588,51 +1602,51 @@ static void writeSpatialRelatesFunction(PlanStreamOutput out, SpatialRelatesFunc } static Now readNow(PlanStreamInput in) throws IOException { - return new Now(in.readSource(), in.configuration()); + return new Now(Source.readFrom(in), in.configuration()); } static void writeNow(PlanStreamOutput out, Now function) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); } static Round readRound(PlanStreamInput in) throws IOException { - return new Round(in.readSource(), in.readExpression(), in.readOptionalNamed(Expression.class)); + return new Round(Source.readFrom(in), in.readExpression(), in.readOptionalNamed(Expression.class)); } static void writeRound(PlanStreamOutput out, Round round) throws IOException { - out.writeSource(round.source()); + round.source().writeTo(out); out.writeExpression(round.field()); out.writeOptionalExpression(round.decimals()); } static Pow readPow(PlanStreamInput in) throws IOException { - return new Pow(in.readSource(), in.readExpression(), in.readExpression()); + return new Pow(Source.readFrom(in), in.readExpression(), in.readExpression()); } static void writePow(PlanStreamOutput out, Pow pow) throws IOException { - out.writeSource(pow.source()); + pow.source().writeTo(out); out.writeExpression(pow.base()); out.writeExpression(pow.exponent()); } static Percentile readPercentile(PlanStreamInput in) throws IOException { - return new Percentile(in.readSource(), in.readExpression(), in.readExpression()); + return new Percentile(Source.readFrom(in), in.readExpression(), in.readExpression()); } static void writePercentile(PlanStreamOutput out, Percentile percentile) throws IOException { List fields = percentile.children(); assert fields.size() == 2 : "percentile() aggregation must have two arguments"; - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeExpression(fields.get(0)); out.writeExpression(fields.get(1)); } static StartsWith readStartsWith(PlanStreamInput in) throws IOException { - return new StartsWith(in.readSource(), in.readExpression(), in.readExpression()); + return new StartsWith(Source.readFrom(in), in.readExpression(), in.readExpression()); } static void writeStartsWith(PlanStreamOutput out, StartsWith startsWith) throws IOException { - out.writeSource(startsWith.source()); + startsWith.source().writeTo(out); List fields = startsWith.children(); assert fields.size() == 2; out.writeExpression(fields.get(0)); @@ -1640,23 +1654,23 @@ static void writeStartsWith(PlanStreamOutput out, StartsWith startsWith) throws } static EndsWith readEndsWith(PlanStreamInput in) throws IOException { - return new EndsWith(in.readSource(), in.readExpression(), in.readExpression()); + return new EndsWith(Source.readFrom(in), in.readExpression(), in.readExpression()); } static void writeEndsWith(PlanStreamOutput out, EndsWith endsWith) throws IOException { List fields = endsWith.children(); assert fields.size() == 2; - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeExpression(fields.get(0)); out.writeExpression(fields.get(1)); } static Substring readSubstring(PlanStreamInput in) throws IOException { - return new Substring(in.readSource(), in.readExpression(), in.readExpression(), in.readOptionalNamed(Expression.class)); + return new Substring(Source.readFrom(in), in.readExpression(), in.readExpression(), in.readOptionalNamed(Expression.class)); } static void writeSubstring(PlanStreamOutput out, Substring substring) throws IOException { - out.writeSource(substring.source()); + substring.source().writeTo(out); List fields = substring.children(); assert fields.size() == 2 || fields.size() == 3; out.writeExpression(fields.get(0)); @@ -1665,11 +1679,11 @@ static void writeSubstring(PlanStreamOutput out, Substring substring) throws IOE } static Locate readLocate(PlanStreamInput in) throws IOException { - return new Locate(in.readSource(), in.readExpression(), in.readExpression(), in.readOptionalNamed(Expression.class)); + return new Locate(Source.readFrom(in), in.readExpression(), in.readExpression(), in.readOptionalNamed(Expression.class)); } static void writeLocate(PlanStreamOutput out, Locate locate) throws IOException { - out.writeSource(locate.source()); + locate.source().writeTo(out); List fields = locate.children(); assert fields.size() == 2 || fields.size() == 3; out.writeExpression(fields.get(0)); @@ -1706,11 +1720,11 @@ static void writeToUpper(PlanStreamOutput out, ToUpper toUpper) throws IOExcepti } static Left readLeft(PlanStreamInput in) throws IOException { - return new Left(in.readSource(), in.readExpression(), in.readExpression()); + return new Left(Source.readFrom(in), in.readExpression(), in.readExpression()); } static void writeLeft(PlanStreamOutput out, Left left) throws IOException { - out.writeSource(left.source()); + left.source().writeTo(out); List fields = left.children(); assert fields.size() == 2; out.writeExpression(fields.get(0)); @@ -1718,11 +1732,11 @@ static void writeLeft(PlanStreamOutput out, Left left) throws IOException { } static Right readRight(PlanStreamInput in) throws IOException { - return new Right(in.readSource(), in.readExpression(), in.readExpression()); + return new Right(Source.readFrom(in), in.readExpression(), in.readExpression()); } static void writeRight(PlanStreamOutput out, Right right) throws IOException { - out.writeSource(right.source()); + right.source().writeTo(out); List fields = right.children(); assert fields.size() == 2; out.writeExpression(fields.get(0)); @@ -1730,25 +1744,25 @@ static void writeRight(PlanStreamOutput out, Right right) throws IOException { } static Split readSplit(PlanStreamInput in) throws IOException { - return new Split(in.readSource(), in.readExpression(), in.readExpression()); + return new Split(Source.readFrom(in), in.readExpression(), in.readExpression()); } static void writeSplit(PlanStreamOutput out, Split split) throws IOException { - out.writeSource(split.source()); + split.source().writeTo(out); out.writeExpression(split.left()); out.writeExpression(split.right()); } static CIDRMatch readCIDRMatch(PlanStreamInput in) throws IOException { return new CIDRMatch( - in.readSource(), + Source.readFrom(in), in.readExpression(), in.readCollectionAsList(readerFromPlanReader(PlanStreamInput::readExpression)) ); } static void writeCIDRMatch(PlanStreamOutput out, CIDRMatch cidrMatch) throws IOException { - out.writeSource(cidrMatch.source()); + cidrMatch.source().writeTo(out); List children = cidrMatch.children(); assert children.size() > 1; out.writeExpression(children.get(0)); @@ -1766,14 +1780,14 @@ static void writeCIDRMatch(PlanStreamOutput out, CIDRMatch cidrMatch) throws IOE ); static ArithmeticOperation readArithmeticOperation(PlanStreamInput in, String name) throws IOException { - var source = in.readSource(); + var source = Source.readFrom(in); var left = in.readExpression(); var right = in.readExpression(); return ARITHMETIC_CTRS.get(name).apply(source, left, right); } static void writeArithmeticOperation(PlanStreamOutput out, ArithmeticOperation arithmeticOperation) throws IOException { - out.writeSource(arithmeticOperation.source()); + arithmeticOperation.source().writeTo(out); out.writeExpression(arithmeticOperation.left()); out.writeExpression(arithmeticOperation.right()); } @@ -1792,11 +1806,11 @@ static void writeArithmeticOperation(PlanStreamOutput out, ArithmeticOperation a ); static AggregateFunction readAggFunction(PlanStreamInput in, String name) throws IOException { - return AGG_CTRS.get(name).apply(in.readSource(), in.readExpression()); + return AGG_CTRS.get(name).apply(Source.readFrom(in), in.readExpression()); } static void writeAggFunction(PlanStreamOutput out, AggregateFunction aggregateFunction) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeExpression(aggregateFunction.field()); } @@ -1814,20 +1828,20 @@ static void writeAggFunction(PlanStreamOutput out, AggregateFunction aggregateFu ); static AbstractMultivalueFunction readMvFunction(PlanStreamInput in, String name) throws IOException { - return MV_CTRS.get(name).apply(in.readSource(), in.readExpression()); + return MV_CTRS.get(name).apply(Source.readFrom(in), in.readExpression()); } static void writeMvFunction(PlanStreamOutput out, AbstractMultivalueFunction fn) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeExpression(fn.field()); } static MvConcat readMvConcat(PlanStreamInput in) throws IOException { - return new MvConcat(in.readSource(), in.readExpression(), in.readExpression()); + return new MvConcat(Source.readFrom(in), in.readExpression(), in.readExpression()); } static void writeMvConcat(PlanStreamOutput out, MvConcat fn) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeExpression(fn.left()); out.writeExpression(fn.right()); } @@ -1836,7 +1850,7 @@ static void writeMvConcat(PlanStreamOutput out, MvConcat fn) throws IOException static Alias readAlias(PlanStreamInput in) throws IOException { return new Alias( - in.readSource(), + Source.readFrom(in), in.readString(), in.readOptionalString(), in.readNamed(Expression.class), @@ -1846,7 +1860,7 @@ static Alias readAlias(PlanStreamInput in) throws IOException { } static void writeAlias(PlanStreamOutput out, Alias alias) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeString(alias.name()); out.writeOptionalString(alias.qualifier()); out.writeExpression(alias.child()); @@ -1857,14 +1871,14 @@ static void writeAlias(PlanStreamOutput out, Alias alias) throws IOException { // -- Expressions (other) static Literal readLiteral(PlanStreamInput in) throws IOException { - Source source = in.readSource(); + Source source = Source.readFrom(in); Object value = in.readGenericValue(); DataType dataType = in.dataTypeFromTypeName(in.readString()); return new Literal(source, mapToLiteralValue(in, dataType, value), dataType); } static void writeLiteral(PlanStreamOutput out, Literal literal) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeGenericValue(mapFromLiteralValue(out, literal.dataType(), literal.value())); out.writeString(literal.dataType().typeName()); } @@ -1917,7 +1931,7 @@ private static long wkbAsLong(DataType dataType, BytesRef wkb) { static Order readOrder(PlanStreamInput in) throws IOException { return new org.elasticsearch.xpack.esql.expression.Order( - in.readSource(), + Source.readFrom(in), in.readNamed(Expression.class), in.readEnum(Order.OrderDirection.class), in.readEnum(Order.NullsPosition.class) @@ -1925,7 +1939,7 @@ static Order readOrder(PlanStreamInput in) throws IOException { } static void writeOrder(PlanStreamOutput out, Order order) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); out.writeExpression(order.child()); out.writeEnum(order.direction()); out.writeEnum(order.nullsPosition()); @@ -1974,11 +1988,11 @@ static void writeDissectParser(PlanStreamOutput out, Parser dissectParser) throw } static Log readLog(PlanStreamInput in) throws IOException { - return new Log(in.readSource(), in.readExpression(), in.readOptionalNamed(Expression.class)); + return new Log(Source.readFrom(in), in.readExpression(), in.readOptionalNamed(Expression.class)); } static void writeLog(PlanStreamOutput out, Log log) throws IOException { - out.writeSource(log.source()); + log.source().writeTo(out); List fields = log.children(); assert fields.size() == 1 || fields.size() == 2; out.writeExpression(fields.get(0)); @@ -1986,11 +2000,11 @@ static void writeLog(PlanStreamOutput out, Log log) throws IOException { } static MvSort readMvSort(PlanStreamInput in) throws IOException { - return new MvSort(in.readSource(), in.readExpression(), in.readOptionalNamed(Expression.class)); + return new MvSort(Source.readFrom(in), in.readExpression(), in.readOptionalNamed(Expression.class)); } static void writeMvSort(PlanStreamOutput out, MvSort mvSort) throws IOException { - out.writeSource(mvSort.source()); + mvSort.source().writeTo(out); List fields = mvSort.children(); assert fields.size() == 1 || fields.size() == 2; out.writeExpression(fields.get(0)); @@ -1998,11 +2012,11 @@ static void writeMvSort(PlanStreamOutput out, MvSort mvSort) throws IOException } static MvSlice readMvSlice(PlanStreamInput in) throws IOException { - return new MvSlice(in.readSource(), in.readExpression(), in.readExpression(), in.readOptionalNamed(Expression.class)); + return new MvSlice(Source.readFrom(in), in.readExpression(), in.readExpression(), in.readOptionalNamed(Expression.class)); } static void writeMvSlice(PlanStreamOutput out, MvSlice fn) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); List fields = fn.children(); assert fields.size() == 2 || fields.size() == 3; out.writeExpression(fields.get(0)); @@ -2011,11 +2025,11 @@ static void writeMvSlice(PlanStreamOutput out, MvSlice fn) throws IOException { } static MvZip readMvZip(PlanStreamInput in) throws IOException { - return new MvZip(in.readSource(), in.readExpression(), in.readExpression(), in.readOptionalNamed(Expression.class)); + return new MvZip(Source.readFrom(in), in.readExpression(), in.readExpression(), in.readOptionalNamed(Expression.class)); } static void writeMvZip(PlanStreamOutput out, MvZip fn) throws IOException { - out.writeNoSource(); + Source.EMPTY.writeTo(out); List fields = fn.children(); assert fields.size() == 2 || fields.size() == 3; out.writeExpression(fields.get(0)); diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInput.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInput.java index 3faf85b989c09..c8dc24e4c2208 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInput.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInput.java @@ -30,7 +30,6 @@ import org.elasticsearch.xpack.esql.core.expression.NameId; import org.elasticsearch.xpack.esql.core.expression.NamedExpression; import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.core.type.EsField; import org.elasticsearch.xpack.esql.io.stream.PlanNameRegistry.PlanNamedReader; @@ -48,13 +47,13 @@ import java.util.function.LongFunction; import java.util.function.Supplier; -import static org.elasticsearch.xpack.esql.core.util.SourceUtils.readSourceWithText; - /** * A customized stream input used to deserialize ESQL physical plan fragments. Complements stream * input with methods that read plan nodes, Attributes, Expressions, etc. */ -public final class PlanStreamInput extends NamedWriteableAwareStreamInput { +public final class PlanStreamInput extends NamedWriteableAwareStreamInput + implements + org.elasticsearch.xpack.esql.core.util.PlanStreamInput { /** * A Mapper of stream named id, represented as a primitive long value, to NameId instance. @@ -123,11 +122,6 @@ public PhysicalPlan readOptionalPhysicalPlanNode() throws IOException { return readOptionalNamed(PhysicalPlan.class); } - public Source readSource() throws IOException { - boolean hasSource = readBoolean(); - return hasSource ? readSourceWithText(this, configuration.query()) : Source.EMPTY; - } - public Expression readExpression() throws IOException { return readNamed(Expression.class); } @@ -268,6 +262,11 @@ public Block[] readCachedBlockArray() throws IOException { } } + @Override + public String sourceText() { + return configuration.query(); + } + static void throwOnNullOptionalRead(Class type) throws IOException { final IOException e = new IOException("read optional named returned null which is not allowed, type:" + type); assert false : e; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamOutput.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamOutput.java index 6cf64de339383..351918699aac4 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamOutput.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamOutput.java @@ -23,7 +23,6 @@ import org.elasticsearch.xpack.esql.core.expression.Expression; import org.elasticsearch.xpack.esql.core.expression.NamedExpression; import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.io.stream.PlanNameRegistry.PlanWriter; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; @@ -33,8 +32,6 @@ import java.util.Map; import java.util.function.Function; -import static org.elasticsearch.xpack.esql.core.util.SourceUtils.writeSourceNoText; - /** * A customized stream output used to serialize ESQL physical plan fragments. Complements stream * output with methods that write plan nodes, Attributes, Expressions, etc. @@ -98,15 +95,6 @@ public void writeOptionalPhysicalPlanNode(PhysicalPlan physicalPlan) throws IOEx } } - public void writeSource(Source source) throws IOException { - writeBoolean(true); - writeSourceNoText(this, source); - } - - public void writeNoSource() throws IOException { - writeBoolean(false); - } - public void writeExpression(Expression expression) throws IOException { writeNamed(Expression.class, expression); } diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/util/SourceUtils.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/util/SourceUtils.java deleted file mode 100644 index afba73373df92..0000000000000 --- a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/util/SourceUtils.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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.ql.util; - -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.core.Nullable; -import org.elasticsearch.xpack.ql.QlIllegalArgumentException; -import org.elasticsearch.xpack.ql.tree.Location; -import org.elasticsearch.xpack.ql.tree.Source; - -import java.io.IOException; - -public final class SourceUtils { - - private SourceUtils() {} - - public static void writeSource(StreamOutput out, Source source) throws IOException { - writeSource(out, source, true); - } - - public static void writeSourceNoText(StreamOutput out, Source source) throws IOException { - writeSource(out, source, false); - } - - public static Source readSource(StreamInput in) throws IOException { - return readSource(in, null); - } - - public static Source readSourceWithText(StreamInput in, String queryText) throws IOException { - return readSource(in, queryText); - } - - private static void writeSource(StreamOutput out, Source source, boolean writeText) throws IOException { - out.writeInt(source.source().getLineNumber()); - out.writeInt(source.source().getColumnNumber()); - if (writeText) { - out.writeString(source.text()); - } else { - out.writeInt(source.text().length()); - } - } - - private static Source readSource(StreamInput in, @Nullable String queryText) throws IOException { - int line = in.readInt(); - int column = in.readInt(); - int charPositionInLine = column - 1; - - String text; - if (queryText == null) { - text = in.readString(); - } else { - int length = in.readInt(); - text = sourceText(queryText, line, column, length); - } - return new Source(new Location(line, charPositionInLine), text); - } - - private static String sourceText(String query, int line, int column, int length) { - if (line <= 0 || column <= 0 || query.isEmpty()) { - return StringUtils.EMPTY; - } - int offset = textOffset(query, line, column); - if (offset + length > query.length()) { - throw new QlIllegalArgumentException( - "location [@" + line + ":" + column + "] and length [" + length + "] overrun query size [" + query.length() + "]" - ); - } - return query.substring(offset, offset + length); - } - - private static int textOffset(String query, int line, int column) { - int offset = 0; - if (line > 1) { - String[] lines = query.split("\n"); - if (line > lines.length) { - throw new QlIllegalArgumentException( - "line location [" + line + "] higher than max [" + lines.length + "] in query [" + query + "]" - ); - } - for (int i = 0; i < line - 1; i++) { - offset += lines[i].length() + 1; // +1 accounts for the removed \n - } - } - offset += column - 1; // -1 since column is 1-based indexed - return offset; - } -} From da9282e3f571e5af834953db679763bde8d1530d Mon Sep 17 00:00:00 2001 From: Henning Andersen <33268011+henningandersen@users.noreply.github.com> Date: Wed, 29 May 2024 16:23:22 +0200 Subject: [PATCH 034/208] Longer timeout for local node startup during CI (#109141) Sometimes CI is slow enough that the 2 min timeout fails. Extending it. Seen in CI failure from #109139 --- .../test/cluster/local/AbstractLocalClusterFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/local/AbstractLocalClusterFactory.java b/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/local/AbstractLocalClusterFactory.java index 9bd3403060b2a..0101c76b21f76 100644 --- a/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/local/AbstractLocalClusterFactory.java +++ b/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/local/AbstractLocalClusterFactory.java @@ -64,7 +64,7 @@ public abstract class AbstractLocalClusterFactory { private static final Logger LOGGER = LogManager.getLogger(AbstractLocalClusterFactory.class); - private static final Duration NODE_UP_TIMEOUT = Duration.ofMinutes(2); + private static final Duration NODE_UP_TIMEOUT = Duration.ofMinutes(3); private static final Map, DistributionDescriptor> TEST_DISTRIBUTIONS = new ConcurrentHashMap<>(); private static final String TESTS_CLUSTER_MODULES_PATH_SYSPROP = "tests.cluster.modules.path"; private static final String TESTS_CLUSTER_PLUGINS_PATH_SYSPROP = "tests.cluster.plugins.path"; From f16f71e2a2bd025cb2bc63cad0670deb91017818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Cea=20Fontenla?= Date: Wed, 29 May 2024 16:23:45 +0200 Subject: [PATCH 035/208] ESQL: Add ip_prefix function (#109070) Added ESQL function to get the prefix of an IP. It works now with both IPv4 and IPv6. For users planning to use it with mixed IPs, we may need to add a function like "is_ipv4()" first. **About the skipped test:** There's currently a "bug" in the evaluators//functions that return null. Evaluators can't handle them. We'll work on support for that in another PR. It affects other functions, like `substring()`. In this function, however, it only affects in "wrong" cases (Like an invalid prefix), so it has no impact. Fixes https://github.com/elastic/elasticsearch/issues/99064 --- .gitattributes | 5 + docs/changelog/109070.yaml | 6 + .../functions/description/ip_prefix.asciidoc | 5 + .../functions/examples/ip_prefix.asciidoc | 13 ++ .../kibana/definition/ip_prefix.json | 35 ++++ .../esql/functions/kibana/docs/ip_prefix.md | 11 + .../esql/functions/layout/ip_prefix.asciidoc | 15 ++ .../functions/parameters/ip_prefix.asciidoc | 12 ++ .../esql/functions/signature/ip_prefix.svg | 1 + .../esql/functions/types/ip_prefix.asciidoc | 9 + .../xpack/esql/CsvTestUtils.java | 2 +- .../src/main/resources/ip.csv-spec | 105 ++++++++++ .../src/main/resources/meta.csv-spec | 6 +- .../function/scalar/ip/IpPrefixEvaluator.java | 183 +++++++++++++++++ .../scalar/ip/IpPrefixOnlyV4Evaluator.java | 148 ++++++++++++++ .../xpack/esql/action/EsqlCapabilities.java | 6 + .../function/EsqlFunctionRegistry.java | 2 + .../function/scalar/ip/IpPrefix.java | 191 ++++++++++++++++++ .../xpack/esql/io/stream/PlanNamedTypes.java | 2 + .../function/scalar/ip/IpPrefixTests.java | 116 +++++++++++ 20 files changed, 871 insertions(+), 2 deletions(-) create mode 100644 docs/changelog/109070.yaml create mode 100644 docs/reference/esql/functions/description/ip_prefix.asciidoc create mode 100644 docs/reference/esql/functions/examples/ip_prefix.asciidoc create mode 100644 docs/reference/esql/functions/kibana/definition/ip_prefix.json create mode 100644 docs/reference/esql/functions/kibana/docs/ip_prefix.md create mode 100644 docs/reference/esql/functions/layout/ip_prefix.asciidoc create mode 100644 docs/reference/esql/functions/parameters/ip_prefix.asciidoc create mode 100644 docs/reference/esql/functions/signature/ip_prefix.svg create mode 100644 docs/reference/esql/functions/types/ip_prefix.asciidoc create mode 100644 x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefixEvaluator.java create mode 100644 x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefixOnlyV4Evaluator.java create mode 100644 x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefix.java create mode 100644 x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefixTests.java diff --git a/.gitattributes b/.gitattributes index ebe1a34db3479..6a8de5462ec3f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,3 +8,8 @@ x-pack/plugin/esql/src/main/antlr/*.tokens linguist-generated=true x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/*.interp linguist-generated=true x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer*.java linguist-generated=true x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser*.java linguist-generated=true +x-pack/plugin/esql/src/main/generated/** linguist-generated=true + +# ESQL functions docs are autogenerated. More information at `docs/reference/esql/functions/README.md` +docs/reference/esql/functions/*/** linguist-generated=true + diff --git a/docs/changelog/109070.yaml b/docs/changelog/109070.yaml new file mode 100644 index 0000000000000..8dbc0ec1c6cf2 --- /dev/null +++ b/docs/changelog/109070.yaml @@ -0,0 +1,6 @@ +pr: 109070 +summary: "ESQL: Add `ip_prefix` function" +area: ES|QL +type: feature +issues: + - 99064 diff --git a/docs/reference/esql/functions/description/ip_prefix.asciidoc b/docs/reference/esql/functions/description/ip_prefix.asciidoc new file mode 100644 index 0000000000000..4b7a88486dea2 --- /dev/null +++ b/docs/reference/esql/functions/description/ip_prefix.asciidoc @@ -0,0 +1,5 @@ +// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it. + +*Description* + +Truncates an IP to a given prefix length. diff --git a/docs/reference/esql/functions/examples/ip_prefix.asciidoc b/docs/reference/esql/functions/examples/ip_prefix.asciidoc new file mode 100644 index 0000000000000..19f0ed266afb5 --- /dev/null +++ b/docs/reference/esql/functions/examples/ip_prefix.asciidoc @@ -0,0 +1,13 @@ +// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it. + +*Example* + +[source.merge.styled,esql] +---- +include::{esql-specs}/ip.csv-spec[tag=ipPrefix] +---- +[%header.monospaced.styled,format=dsv,separator=|] +|=== +include::{esql-specs}/ip.csv-spec[tag=ipPrefix-result] +|=== + diff --git a/docs/reference/esql/functions/kibana/definition/ip_prefix.json b/docs/reference/esql/functions/kibana/definition/ip_prefix.json new file mode 100644 index 0000000000000..00c3cf75a949e --- /dev/null +++ b/docs/reference/esql/functions/kibana/definition/ip_prefix.json @@ -0,0 +1,35 @@ +{ + "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", + "type" : "eval", + "name" : "ip_prefix", + "description" : "Truncates an IP to a given prefix length.", + "signatures" : [ + { + "params" : [ + { + "name" : "ip", + "type" : "ip", + "optional" : false, + "description" : "IP address of type `ip` (both IPv4 and IPv6 are supported)." + }, + { + "name" : "prefixLengthV4", + "type" : "integer", + "optional" : false, + "description" : "Prefix length for IPv4 addresses." + }, + { + "name" : "prefixLengthV6", + "type" : "integer", + "optional" : false, + "description" : "Prefix length for IPv6 addresses." + } + ], + "variadic" : false, + "returnType" : "ip" + } + ], + "examples" : [ + "row ip4 = to_ip(\"1.2.3.4\"), ip6 = to_ip(\"fe80::cae2:65ff:fece:feb9\")\n| eval ip4_prefix = ip_prefix(ip4, 24, 0), ip6_prefix = ip_prefix(ip6, 0, 112);" + ] +} diff --git a/docs/reference/esql/functions/kibana/docs/ip_prefix.md b/docs/reference/esql/functions/kibana/docs/ip_prefix.md new file mode 100644 index 0000000000000..5c0009528bb68 --- /dev/null +++ b/docs/reference/esql/functions/kibana/docs/ip_prefix.md @@ -0,0 +1,11 @@ + + +### IP_PREFIX +Truncates an IP to a given prefix length. + +``` +row ip4 = to_ip("1.2.3.4"), ip6 = to_ip("fe80::cae2:65ff:fece:feb9") +| eval ip4_prefix = ip_prefix(ip4, 24, 0), ip6_prefix = ip_prefix(ip6, 0, 112); +``` diff --git a/docs/reference/esql/functions/layout/ip_prefix.asciidoc b/docs/reference/esql/functions/layout/ip_prefix.asciidoc new file mode 100644 index 0000000000000..ca51c871daf7f --- /dev/null +++ b/docs/reference/esql/functions/layout/ip_prefix.asciidoc @@ -0,0 +1,15 @@ +// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it. + +[discrete] +[[esql-ip_prefix]] +=== `IP_PREFIX` + +*Syntax* + +[.text-center] +image::esql/functions/signature/ip_prefix.svg[Embedded,opts=inline] + +include::../parameters/ip_prefix.asciidoc[] +include::../description/ip_prefix.asciidoc[] +include::../types/ip_prefix.asciidoc[] +include::../examples/ip_prefix.asciidoc[] diff --git a/docs/reference/esql/functions/parameters/ip_prefix.asciidoc b/docs/reference/esql/functions/parameters/ip_prefix.asciidoc new file mode 100644 index 0000000000000..945601c2476e6 --- /dev/null +++ b/docs/reference/esql/functions/parameters/ip_prefix.asciidoc @@ -0,0 +1,12 @@ +// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it. + +*Parameters* + +`ip`:: +IP address of type `ip` (both IPv4 and IPv6 are supported). + +`prefixLengthV4`:: +Prefix length for IPv4 addresses. + +`prefixLengthV6`:: +Prefix length for IPv6 addresses. diff --git a/docs/reference/esql/functions/signature/ip_prefix.svg b/docs/reference/esql/functions/signature/ip_prefix.svg new file mode 100644 index 0000000000000..4699c23357460 --- /dev/null +++ b/docs/reference/esql/functions/signature/ip_prefix.svg @@ -0,0 +1 @@ +IP_PREFIX(ip,prefixLengthV4,prefixLengthV6) \ No newline at end of file diff --git a/docs/reference/esql/functions/types/ip_prefix.asciidoc b/docs/reference/esql/functions/types/ip_prefix.asciidoc new file mode 100644 index 0000000000000..786d99d45d327 --- /dev/null +++ b/docs/reference/esql/functions/types/ip_prefix.asciidoc @@ -0,0 +1,9 @@ +// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it. + +*Supported types* + +[%header.monospaced.styled,format=dsv,separator=|] +|=== +ip | prefixLengthV4 | prefixLengthV6 | result +ip | integer | integer | ip +|=== diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestUtils.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestUtils.java index 1927cfd03ac06..7d1c168bd203f 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestUtils.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestUtils.java @@ -101,7 +101,7 @@ public static Tuple skipVersionRange(String testName) { Map pairs = extractInstructions(testName); String versionRange = pairs.get("skip"); if (versionRange != null) { - String[] skipVersions = versionRange.split("-"); + String[] skipVersions = versionRange.split("-", Integer.MAX_VALUE); if (skipVersions.length != 2) { throw new IllegalArgumentException("malformed version range : " + versionRange); } diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ip.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ip.csv-spec index ae683acbb2c3a..0de64d3e2d9d4 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ip.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ip.csv-spec @@ -485,3 +485,108 @@ beta | 127.0.0.1 beta | 127.0.0.1 beta | 127.0.0.1 ; + +ipPrefix +required_capability: fn_ip_prefix +//tag::ipPrefix[] +row ip4 = to_ip("1.2.3.4"), ip6 = to_ip("fe80::cae2:65ff:fece:feb9") +| eval ip4_prefix = ip_prefix(ip4, 24, 0), ip6_prefix = ip_prefix(ip6, 0, 112); +//end::ipPrefix[] + +//tag::ipPrefix-result[] +ip4:ip | ip6:ip | ip4_prefix:ip | ip6_prefix:ip +1.2.3.4 | fe80::cae2:65ff:fece:feb9 | 1.2.3.0 | fe80::cae2:65ff:fece:0000 +//end::ipPrefix-result[] +; + +ipPrefixCompleteIp +required_capability: fn_ip_prefix +row ip4 = to_ip("1.2.3.4"), ip6 = to_ip("fe80::cae2:65ff:fece:feb9") +| eval ip4_prefix = ip_prefix(ip4, 32, 0), ip6_prefix = ip_prefix(ip6, 0, 128); + +ip4:ip | ip6:ip | ip4_prefix:ip | ip6_prefix:ip +1.2.3.4 | fe80::cae2:65ff:fece:feb9 | 1.2.3.4 | fe80::cae2:65ff:fece:feb9 +; + +ipPrefixZeroBits +required_capability: fn_ip_prefix +row ip4 = to_ip("1.2.3.4"), ip6 = to_ip("fe80::cae2:65ff:fece:feb9") +| eval ip4_prefix = ip_prefix(ip4, 0, 128), ip6_prefix = ip_prefix(ip6, 32, 0); + +ip4:ip | ip6:ip | ip4_prefix:ip | ip6_prefix:ip +1.2.3.4 | fe80::cae2:65ff:fece:feb9 | 0.0.0.0 | ::0 +; + +ipPrefixWithBits +required_capability: fn_ip_prefix +row ip4 = to_ip("1.2.3.255"), ip6 = to_ip("fe80::cae2:65ff:fece:feff") +| eval ip4_prefix = ip_prefix(ip4, 25, 0), ip6_prefix = ip_prefix(ip6, 0, 121); + +ip4:ip | ip6:ip | ip4_prefix:ip | ip6_prefix:ip +1.2.3.255 | fe80::cae2:65ff:fece:feff | 1.2.3.128 | fe80::cae2:65ff:fece:fe80 +; + +ipPrefixLengthFromColumn +required_capability: fn_ip_prefix +from hosts +| where host == "alpha" +| sort card +| eval prefix = ip_prefix(ip0, 24, 128) +| keep card, ip0, prefix; + +card:keyword | ip0:ip | prefix:ip +eth0 | 127.0.0.1 | 127.0.0.0 +eth1 | ::1 | ::0 +; + +ipPrefixLengthFromExpression +required_capability: fn_ip_prefix +row ip4 = to_ip("1.2.3.4"), ip6 = to_ip("fe80::cae2:65ff:fece:feb9"), bits_per_byte = 8 +| eval ip4_length = 3 * bits_per_byte, ip4_prefix = ip_prefix(ip4, ip4_length, 0), ip6_prefix = ip_prefix(ip6, 0, 12 * 10); + +ip4:ip | ip6:ip | bits_per_byte:integer | ip4_length:integer | ip4_prefix:ip | ip6_prefix:ip +1.2.3.4 | fe80::cae2:65ff:fece:feb9 | 8 | 24 | 1.2.3.0 | fe80::cae2:65ff:fece:fe00 +; + +ipPrefixAsGroup +required_capability: fn_ip_prefix +from hosts +| stats count(*) by ip_prefix(ip1, 24, 120) +| sort `ip_prefix(ip1, 24, 120)`; +warning:Line 2:21: evaluation of [ip_prefix(ip1, 24, 120)] failed, treating result as null. Only first 20 failures recorded. +warning:Line 2:21: java.lang.IllegalArgumentException: single-value function encountered multi-value + +count(*):long | ip_prefix(ip1, 24, 120):ip +2 | ::0 +3 | 127.0.0.0 +1 | 128.0.0.0 +1 | fe80::cae2:65ff:fece:fe00 +1 | fe81::cae2:65ff:fece:fe00 +2 | null +; + +ipPrefixWithWrongLengths +required_capability: fn_ip_prefix +row ip4 = to_ip("1.2.3.4") +| eval a = ip_prefix(ip4, -1, 128), b = ip_prefix(ip4, 32, -1), c = ip_prefix(ip4, 33, 0), d = ip_prefix(ip4, 32, 129); +warning:Line 2:12: evaluation of [ip_prefix(ip4, -1, 128)] failed, treating result as null. Only first 20 failures recorded. +warning:Line 2:12: java.lang.IllegalArgumentException: Prefix length v4 must be in range [0, 32], found -1 +warning:Line 2:41: evaluation of [ip_prefix(ip4, 32, -1)] failed, treating result as null. Only first 20 failures recorded. +warning:Line 2:41: java.lang.IllegalArgumentException: Prefix length v6 must be in range [0, 128], found -1 +warning:Line 2:69: evaluation of [ip_prefix(ip4, 33, 0)] failed, treating result as null. Only first 20 failures recorded. +warning:Line 2:69: java.lang.IllegalArgumentException: Prefix length v4 must be in range [0, 32], found 33 +warning:Line 2:96: evaluation of [ip_prefix(ip4, 32, 129)] failed, treating result as null. Only first 20 failures recorded. +warning:Line 2:96: java.lang.IllegalArgumentException: Prefix length v6 must be in range [0, 128], found 129 + +ip4:ip | a:ip | b:ip | c:ip | d:ip +1.2.3.4 | null | null | null | null +; + +ipPrefixWithNullArguments +required_capability: fn_ip_prefix +row ip4 = to_ip("1.2.3.4") +| eval a = ip_prefix(null, 32, 128), b = ip_prefix(ip4, null, 128), c = ip_prefix(ip4, 32, null); + +ip4:ip | a:ip | b:ip | c:ip +1.2.3.4 | null | null | null +; diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/meta.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/meta.csv-spec index f68dd15e9c516..eff4cb05bd8c0 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/meta.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/meta.csv-spec @@ -30,6 +30,7 @@ double e() "double|integer|long|unsigned_long floor(number:double|integer|long|unsigned_long)" "keyword from_base64(string:keyword|text)" "boolean|double|integer|ip|keyword|long|text|version greatest(first:boolean|double|integer|ip|keyword|long|text|version, ?rest...:boolean|double|integer|ip|keyword|long|text|version)" +"ip ip_prefix(ip:ip, prefixLengthV4:integer, prefixLengthV6:integer)" "boolean|double|integer|ip|keyword|long|text|version least(first:boolean|double|integer|ip|keyword|long|text|version, ?rest...:boolean|double|integer|ip|keyword|long|text|version)" "keyword left(string:keyword|text, length:integer)" "integer length(string:keyword|text)" @@ -144,6 +145,7 @@ ends_with |[str, suffix] |["keyword|text", "keyword|te floor |number |"double|integer|long|unsigned_long" |Numeric expression. If `null`, the function returns `null`. from_base64 |string |"keyword|text" |A base64 string. greatest |first |"boolean|double|integer|ip|keyword|long|text|version" |First of the columns to evaluate. +ip_prefix |[ip, prefixLengthV4, prefixLengthV6]|[ip, integer, integer] |[IP address of type `ip` (both IPv4 and IPv6 are supported)., Prefix length for IPv4 addresses., Prefix length for IPv6 addresses.] least |first |"boolean|double|integer|ip|keyword|long|text|version" |First of the columns to evaluate. left |[string, length] |["keyword|text", integer] |[The string from which to return a substring., The number of characters to return.] length |string |"keyword|text" |String expression. If `null`, the function returns `null`. @@ -259,6 +261,7 @@ ends_with |Returns a boolean that indicates whether a keyword string ends wi floor |Round a number down to the nearest integer. from_base64 |Decode a base64 string. greatest |Returns the maximum value from multiple columns. This is similar to <> except it is intended to run on multiple columns at once. +ip_prefix |Truncates an IP to a given prefix length. least |Returns the minimum value from multiple columns. This is similar to <> except it is intended to run on multiple columns at once. left |Returns the substring that extracts 'length' chars from 'string' starting from the left. length |Returns the character length of a string. @@ -375,6 +378,7 @@ ends_with |boolean floor |"double|integer|long|unsigned_long" |false |false |false from_base64 |keyword |false |false |false greatest |"boolean|double|integer|ip|keyword|long|text|version" |false |true |false +ip_prefix |ip |[false, false, false] |false |false least |"boolean|double|integer|ip|keyword|long|text|version" |false |true |false left |keyword |[false, false] |false |false length |integer |false |false |false @@ -471,5 +475,5 @@ countFunctions#[skip:-8.14.99, reason:BIN added] meta functions | stats a = count(*), b = count(*), c = count(*) | mv_expand c; a:long | b:long | c:long -106 | 106 | 106 +107 | 107 | 107 ; diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefixEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefixEvaluator.java new file mode 100644 index 0000000000000..174df48d5ce62 --- /dev/null +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefixEvaluator.java @@ -0,0 +1,183 @@ +// 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.expression.function.scalar.ip; + +import java.lang.IllegalArgumentException; +import java.lang.Override; +import java.lang.String; +import java.util.function.Function; +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.compute.data.Block; +import org.elasticsearch.compute.data.BytesRefBlock; +import org.elasticsearch.compute.data.BytesRefVector; +import org.elasticsearch.compute.data.IntBlock; +import org.elasticsearch.compute.data.IntVector; +import org.elasticsearch.compute.data.Page; +import org.elasticsearch.compute.operator.DriverContext; +import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.expression.function.Warnings; + +/** + * {@link EvalOperator.ExpressionEvaluator} implementation for {@link IpPrefix}. + * This class is generated. Do not edit it. + */ +public final class IpPrefixEvaluator implements EvalOperator.ExpressionEvaluator { + private final Warnings warnings; + + private final EvalOperator.ExpressionEvaluator ip; + + private final EvalOperator.ExpressionEvaluator prefixLengthV4; + + private final EvalOperator.ExpressionEvaluator prefixLengthV6; + + private final BytesRef scratch; + + private final DriverContext driverContext; + + public IpPrefixEvaluator(Source source, EvalOperator.ExpressionEvaluator ip, + EvalOperator.ExpressionEvaluator prefixLengthV4, + EvalOperator.ExpressionEvaluator prefixLengthV6, BytesRef scratch, + DriverContext driverContext) { + this.warnings = new Warnings(source); + this.ip = ip; + this.prefixLengthV4 = prefixLengthV4; + this.prefixLengthV6 = prefixLengthV6; + this.scratch = scratch; + this.driverContext = driverContext; + } + + @Override + public Block eval(Page page) { + try (BytesRefBlock ipBlock = (BytesRefBlock) ip.eval(page)) { + try (IntBlock prefixLengthV4Block = (IntBlock) prefixLengthV4.eval(page)) { + try (IntBlock prefixLengthV6Block = (IntBlock) prefixLengthV6.eval(page)) { + BytesRefVector ipVector = ipBlock.asVector(); + if (ipVector == null) { + return eval(page.getPositionCount(), ipBlock, prefixLengthV4Block, prefixLengthV6Block); + } + IntVector prefixLengthV4Vector = prefixLengthV4Block.asVector(); + if (prefixLengthV4Vector == null) { + return eval(page.getPositionCount(), ipBlock, prefixLengthV4Block, prefixLengthV6Block); + } + IntVector prefixLengthV6Vector = prefixLengthV6Block.asVector(); + if (prefixLengthV6Vector == null) { + return eval(page.getPositionCount(), ipBlock, prefixLengthV4Block, prefixLengthV6Block); + } + return eval(page.getPositionCount(), ipVector, prefixLengthV4Vector, prefixLengthV6Vector); + } + } + } + } + + public BytesRefBlock eval(int positionCount, BytesRefBlock ipBlock, IntBlock prefixLengthV4Block, + IntBlock prefixLengthV6Block) { + try(BytesRefBlock.Builder result = driverContext.blockFactory().newBytesRefBlockBuilder(positionCount)) { + BytesRef ipScratch = new BytesRef(); + position: for (int p = 0; p < positionCount; p++) { + if (ipBlock.isNull(p)) { + result.appendNull(); + continue position; + } + if (ipBlock.getValueCount(p) != 1) { + if (ipBlock.getValueCount(p) > 1) { + warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); + } + result.appendNull(); + continue position; + } + if (prefixLengthV4Block.isNull(p)) { + result.appendNull(); + continue position; + } + if (prefixLengthV4Block.getValueCount(p) != 1) { + if (prefixLengthV4Block.getValueCount(p) > 1) { + warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); + } + result.appendNull(); + continue position; + } + if (prefixLengthV6Block.isNull(p)) { + result.appendNull(); + continue position; + } + if (prefixLengthV6Block.getValueCount(p) != 1) { + if (prefixLengthV6Block.getValueCount(p) > 1) { + warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); + } + result.appendNull(); + continue position; + } + try { + result.appendBytesRef(IpPrefix.process(ipBlock.getBytesRef(ipBlock.getFirstValueIndex(p), ipScratch), prefixLengthV4Block.getInt(prefixLengthV4Block.getFirstValueIndex(p)), prefixLengthV6Block.getInt(prefixLengthV6Block.getFirstValueIndex(p)), scratch)); + } catch (IllegalArgumentException e) { + warnings.registerException(e); + result.appendNull(); + } + } + return result.build(); + } + } + + public BytesRefBlock eval(int positionCount, BytesRefVector ipVector, + IntVector prefixLengthV4Vector, IntVector prefixLengthV6Vector) { + try(BytesRefBlock.Builder result = driverContext.blockFactory().newBytesRefBlockBuilder(positionCount)) { + BytesRef ipScratch = new BytesRef(); + position: for (int p = 0; p < positionCount; p++) { + try { + result.appendBytesRef(IpPrefix.process(ipVector.getBytesRef(p, ipScratch), prefixLengthV4Vector.getInt(p), prefixLengthV6Vector.getInt(p), scratch)); + } catch (IllegalArgumentException e) { + warnings.registerException(e); + result.appendNull(); + } + } + return result.build(); + } + } + + @Override + public String toString() { + return "IpPrefixEvaluator[" + "ip=" + ip + ", prefixLengthV4=" + prefixLengthV4 + ", prefixLengthV6=" + prefixLengthV6 + "]"; + } + + @Override + public void close() { + Releasables.closeExpectNoException(ip, prefixLengthV4, prefixLengthV6); + } + + static class Factory implements EvalOperator.ExpressionEvaluator.Factory { + private final Source source; + + private final EvalOperator.ExpressionEvaluator.Factory ip; + + private final EvalOperator.ExpressionEvaluator.Factory prefixLengthV4; + + private final EvalOperator.ExpressionEvaluator.Factory prefixLengthV6; + + private final Function scratch; + + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory ip, + EvalOperator.ExpressionEvaluator.Factory prefixLengthV4, + EvalOperator.ExpressionEvaluator.Factory prefixLengthV6, + Function scratch) { + this.source = source; + this.ip = ip; + this.prefixLengthV4 = prefixLengthV4; + this.prefixLengthV6 = prefixLengthV6; + this.scratch = scratch; + } + + @Override + public IpPrefixEvaluator get(DriverContext context) { + return new IpPrefixEvaluator(source, ip.get(context), prefixLengthV4.get(context), prefixLengthV6.get(context), scratch.apply(context), context); + } + + @Override + public String toString() { + return "IpPrefixEvaluator[" + "ip=" + ip + ", prefixLengthV4=" + prefixLengthV4 + ", prefixLengthV6=" + prefixLengthV6 + "]"; + } + } +} diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefixOnlyV4Evaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefixOnlyV4Evaluator.java new file mode 100644 index 0000000000000..a6cb7c7f9b687 --- /dev/null +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefixOnlyV4Evaluator.java @@ -0,0 +1,148 @@ +// 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.expression.function.scalar.ip; + +import java.lang.IllegalArgumentException; +import java.lang.Override; +import java.lang.String; +import java.util.function.Function; +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.compute.data.Block; +import org.elasticsearch.compute.data.BytesRefBlock; +import org.elasticsearch.compute.data.BytesRefVector; +import org.elasticsearch.compute.data.IntBlock; +import org.elasticsearch.compute.data.IntVector; +import org.elasticsearch.compute.data.Page; +import org.elasticsearch.compute.operator.DriverContext; +import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.expression.function.Warnings; + +/** + * {@link EvalOperator.ExpressionEvaluator} implementation for {@link IpPrefix}. + * This class is generated. Do not edit it. + */ +public final class IpPrefixOnlyV4Evaluator implements EvalOperator.ExpressionEvaluator { + private final Warnings warnings; + + private final EvalOperator.ExpressionEvaluator ip; + + private final EvalOperator.ExpressionEvaluator prefixLengthV4; + + private final BytesRef scratch; + + private final DriverContext driverContext; + + public IpPrefixOnlyV4Evaluator(Source source, EvalOperator.ExpressionEvaluator ip, + EvalOperator.ExpressionEvaluator prefixLengthV4, BytesRef scratch, + DriverContext driverContext) { + this.warnings = new Warnings(source); + this.ip = ip; + this.prefixLengthV4 = prefixLengthV4; + this.scratch = scratch; + this.driverContext = driverContext; + } + + @Override + public Block eval(Page page) { + try (BytesRefBlock ipBlock = (BytesRefBlock) ip.eval(page)) { + try (IntBlock prefixLengthV4Block = (IntBlock) prefixLengthV4.eval(page)) { + BytesRefVector ipVector = ipBlock.asVector(); + if (ipVector == null) { + return eval(page.getPositionCount(), ipBlock, prefixLengthV4Block); + } + IntVector prefixLengthV4Vector = prefixLengthV4Block.asVector(); + if (prefixLengthV4Vector == null) { + return eval(page.getPositionCount(), ipBlock, prefixLengthV4Block); + } + return eval(page.getPositionCount(), ipVector, prefixLengthV4Vector).asBlock(); + } + } + } + + public BytesRefBlock eval(int positionCount, BytesRefBlock ipBlock, + IntBlock prefixLengthV4Block) { + try(BytesRefBlock.Builder result = driverContext.blockFactory().newBytesRefBlockBuilder(positionCount)) { + BytesRef ipScratch = new BytesRef(); + position: for (int p = 0; p < positionCount; p++) { + if (ipBlock.isNull(p)) { + result.appendNull(); + continue position; + } + if (ipBlock.getValueCount(p) != 1) { + if (ipBlock.getValueCount(p) > 1) { + warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); + } + result.appendNull(); + continue position; + } + if (prefixLengthV4Block.isNull(p)) { + result.appendNull(); + continue position; + } + if (prefixLengthV4Block.getValueCount(p) != 1) { + if (prefixLengthV4Block.getValueCount(p) > 1) { + warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); + } + result.appendNull(); + continue position; + } + result.appendBytesRef(IpPrefix.process(ipBlock.getBytesRef(ipBlock.getFirstValueIndex(p), ipScratch), prefixLengthV4Block.getInt(prefixLengthV4Block.getFirstValueIndex(p)), scratch)); + } + return result.build(); + } + } + + public BytesRefVector eval(int positionCount, BytesRefVector ipVector, + IntVector prefixLengthV4Vector) { + try(BytesRefVector.Builder result = driverContext.blockFactory().newBytesRefVectorBuilder(positionCount)) { + BytesRef ipScratch = new BytesRef(); + position: for (int p = 0; p < positionCount; p++) { + result.appendBytesRef(IpPrefix.process(ipVector.getBytesRef(p, ipScratch), prefixLengthV4Vector.getInt(p), scratch)); + } + return result.build(); + } + } + + @Override + public String toString() { + return "IpPrefixOnlyV4Evaluator[" + "ip=" + ip + ", prefixLengthV4=" + prefixLengthV4 + "]"; + } + + @Override + public void close() { + Releasables.closeExpectNoException(ip, prefixLengthV4); + } + + static class Factory implements EvalOperator.ExpressionEvaluator.Factory { + private final Source source; + + private final EvalOperator.ExpressionEvaluator.Factory ip; + + private final EvalOperator.ExpressionEvaluator.Factory prefixLengthV4; + + private final Function scratch; + + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory ip, + EvalOperator.ExpressionEvaluator.Factory prefixLengthV4, + Function scratch) { + this.source = source; + this.ip = ip; + this.prefixLengthV4 = prefixLengthV4; + this.scratch = scratch; + } + + @Override + public IpPrefixOnlyV4Evaluator get(DriverContext context) { + return new IpPrefixOnlyV4Evaluator(source, ip.get(context), prefixLengthV4.get(context), scratch.apply(context), context); + } + + @Override + public String toString() { + return "IpPrefixOnlyV4Evaluator[" + "ip=" + ip + ", prefixLengthV4=" + prefixLengthV4 + "]"; + } + } +} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java index ca90b9e1e3f2e..e8f136c297ce0 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java @@ -27,6 +27,11 @@ public class EsqlCapabilities { */ private static final String FN_CBRT = "fn_cbrt"; + /** + * Support for function {@code IP_PREFIX}. + */ + private static final String FN_IP_PREFIX = "fn_ip_prefix"; + /** * Optimization for ST_CENTROID changed some results in cartesian data. #108713 */ @@ -47,6 +52,7 @@ public class EsqlCapabilities { private static Set capabilities() { List caps = new ArrayList<>(); caps.add(FN_CBRT); + caps.add(FN_IP_PREFIX); caps.add(ST_CENTROID_AGG_OPTIMIZED); caps.add(METADATA_IGNORED_FIELD); diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java index 90f28b263f07a..382b02d2f9b35 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java @@ -52,6 +52,7 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.date.DateTrunc; import org.elasticsearch.xpack.esql.expression.function.scalar.date.Now; import org.elasticsearch.xpack.esql.expression.function.scalar.ip.CIDRMatch; +import org.elasticsearch.xpack.esql.expression.function.scalar.ip.IpPrefix; import org.elasticsearch.xpack.esql.expression.function.scalar.math.Abs; import org.elasticsearch.xpack.esql.expression.function.scalar.math.Acos; import org.elasticsearch.xpack.esql.expression.function.scalar.math.Asin; @@ -257,6 +258,7 @@ private FunctionDefinition[][] functions() { new FunctionDefinition[] { def(Coalesce.class, Coalesce::new, "coalesce"), }, // IP new FunctionDefinition[] { def(CIDRMatch.class, CIDRMatch::new, "cidr_match") }, + new FunctionDefinition[] { def(IpPrefix.class, IpPrefix::new, "ip_prefix") }, // conversion functions new FunctionDefinition[] { def(FromBase64.class, FromBase64::new, "from_base64"), diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefix.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefix.java new file mode 100644 index 0000000000000..d271742aef82d --- /dev/null +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefix.java @@ -0,0 +1,191 @@ +/* + * 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.expression.function.scalar.ip; + +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.compute.ann.Evaluator; +import org.elasticsearch.compute.ann.Fixed; +import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.expression.function.Example; +import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.Param; +import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; +import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput; +import org.elasticsearch.xpack.esql.io.stream.PlanStreamOutput; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.THIRD; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isIPAndExact; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; + +/** + * Truncates an IP value to a given prefix length. + */ +public class IpPrefix extends EsqlScalarFunction implements OptionalArgument { + // Borrowed from Lucene, rfc4291 prefix + private static final byte[] IPV4_PREFIX = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1 }; + + private final Expression ipField; + private final Expression prefixLengthV4Field; + private final Expression prefixLengthV6Field; + + @FunctionInfo( + returnType = "ip", + description = "Truncates an IP to a given prefix length.", + examples = @Example(file = "ip", tag = "ipPrefix") + ) + public IpPrefix( + Source source, + @Param( + name = "ip", + type = { "ip" }, + description = "IP address of type `ip` (both IPv4 and IPv6 are supported)." + ) Expression ipField, + @Param( + name = "prefixLengthV4", + type = { "integer" }, + description = "Prefix length for IPv4 addresses." + ) Expression prefixLengthV4Field, + @Param( + name = "prefixLengthV6", + type = { "integer" }, + description = "Prefix length for IPv6 addresses." + ) Expression prefixLengthV6Field + ) { + super(source, Arrays.asList(ipField, prefixLengthV4Field, prefixLengthV6Field)); + this.ipField = ipField; + this.prefixLengthV4Field = prefixLengthV4Field; + this.prefixLengthV6Field = prefixLengthV6Field; + } + + public static IpPrefix readFrom(PlanStreamInput in) throws IOException { + return new IpPrefix(in.readSource(), in.readExpression(), in.readExpression(), in.readExpression()); + } + + public static void writeTo(PlanStreamOutput out, IpPrefix ipPrefix) throws IOException { + out.writeSource(ipPrefix.source()); + List fields = ipPrefix.children(); + assert fields.size() == 3; + out.writeExpression(fields.get(0)); + out.writeExpression(fields.get(1)); + out.writeExpression(fields.get(2)); + } + + public Expression ipField() { + return ipField; + } + + public Expression prefixLengthV4Field() { + return prefixLengthV4Field; + } + + public Expression prefixLengthV6Field() { + return prefixLengthV6Field; + } + + @Override + public boolean foldable() { + return Expressions.foldable(children()); + } + + @Override + public ExpressionEvaluator.Factory toEvaluator(Function toEvaluator) { + var ipEvaluatorSupplier = toEvaluator.apply(ipField); + var prefixLengthV4EvaluatorSupplier = toEvaluator.apply(prefixLengthV4Field); + var prefixLengthV6EvaluatorSupplier = toEvaluator.apply(prefixLengthV6Field); + + return new IpPrefixEvaluator.Factory( + source(), + ipEvaluatorSupplier, + prefixLengthV4EvaluatorSupplier, + prefixLengthV6EvaluatorSupplier, + context -> new BytesRef(new byte[16]) + ); + } + + @Evaluator(warnExceptions = IllegalArgumentException.class) + static BytesRef process( + BytesRef ip, + int prefixLengthV4, + int prefixLengthV6, + @Fixed(includeInToString = false, build = true) BytesRef scratch + ) { + if (prefixLengthV4 < 0 || prefixLengthV4 > 32) { + throw new IllegalArgumentException("Prefix length v4 must be in range [0, 32], found " + prefixLengthV4); + } + if (prefixLengthV6 < 0 || prefixLengthV6 > 128) { + throw new IllegalArgumentException("Prefix length v6 must be in range [0, 128], found " + prefixLengthV6); + } + + boolean isIpv4 = Arrays.compareUnsigned(ip.bytes, 0, IPV4_PREFIX.length, IPV4_PREFIX, 0, IPV4_PREFIX.length) == 0; + + if (isIpv4) { + makePrefix(ip, scratch, 12 + prefixLengthV4 / 8, prefixLengthV4 % 8); + } else { + makePrefix(ip, scratch, prefixLengthV6 / 8, prefixLengthV6 % 8); + } + + return scratch; + } + + private static void makePrefix(BytesRef ip, BytesRef scratch, int fullBytes, int remainingBits) { + // Copy the first full bytes + System.arraycopy(ip.bytes, ip.offset, scratch.bytes, 0, fullBytes); + + // Copy the last byte ignoring the trailing bits + if (remainingBits > 0) { + byte lastByteMask = (byte) (0xFF << (8 - remainingBits)); + scratch.bytes[fullBytes] = (byte) (ip.bytes[fullBytes] & lastByteMask); + } + + // Copy the last empty bytes + if (fullBytes < 16) { + Arrays.fill(scratch.bytes, fullBytes + 1, 16, (byte) 0); + } + } + + @Override + public DataType dataType() { + return DataTypes.IP; + } + + @Override + protected TypeResolution resolveType() { + if (childrenResolved() == false) { + return new TypeResolution("Unresolved children"); + } + + return isIPAndExact(ipField, sourceText(), FIRST).and( + isType(prefixLengthV4Field, dt -> dt == INTEGER, sourceText(), SECOND, "integer") + ).and(isType(prefixLengthV6Field, dt -> dt == INTEGER, sourceText(), THIRD, "integer")); + } + + @Override + public Expression replaceChildren(List newChildren) { + return new IpPrefix(source(), newChildren.get(0), newChildren.get(1), newChildren.get(2)); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, IpPrefix::new, ipField, prefixLengthV4Field, prefixLengthV6Field); + } +} 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 e846360258ebe..67a6a5d4bb98d 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 @@ -98,6 +98,7 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.date.DateTrunc; import org.elasticsearch.xpack.esql.expression.function.scalar.date.Now; import org.elasticsearch.xpack.esql.expression.function.scalar.ip.CIDRMatch; +import org.elasticsearch.xpack.esql.expression.function.scalar.ip.IpPrefix; import org.elasticsearch.xpack.esql.expression.function.scalar.math.Abs; import org.elasticsearch.xpack.esql.expression.function.scalar.math.Acos; import org.elasticsearch.xpack.esql.expression.function.scalar.math.Asin; @@ -394,6 +395,7 @@ public static List namedTypeEntries() { of(ScalarFunction.class, DateTrunc.class, PlanNamedTypes::writeDateTrunc, PlanNamedTypes::readDateTrunc), of(ScalarFunction.class, E.class, PlanNamedTypes::writeNoArgScalar, PlanNamedTypes::readNoArgScalar), of(ScalarFunction.class, Greatest.class, PlanNamedTypes::writeVararg, PlanNamedTypes::readVarag), + of(ScalarFunction.class, IpPrefix.class, IpPrefix::writeTo, IpPrefix::readFrom), of(ScalarFunction.class, Least.class, PlanNamedTypes::writeVararg, PlanNamedTypes::readVarag), of(ScalarFunction.class, Log.class, PlanNamedTypes::writeLog, PlanNamedTypes::readLog), of(ScalarFunction.class, Now.class, PlanNamedTypes::writeNow, PlanNamedTypes::readNow), diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefixTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefixTests.java new file mode 100644 index 0000000000000..e46eaea849bb5 --- /dev/null +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefixTests.java @@ -0,0 +1,116 @@ +/* + * 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.expression.function.scalar.ip; + +import com.carrotsearch.randomizedtesting.annotations.Name; +import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + +import org.elasticsearch.common.network.InetAddresses; +import org.elasticsearch.common.network.NetworkAddress; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; +import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; +import org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter; + +import java.util.List; +import java.util.function.Supplier; + +import static org.hamcrest.Matchers.equalTo; + +public class IpPrefixTests extends AbstractFunctionTestCase { + public IpPrefixTests(@Name("TestCase") Supplier testCaseSupplier) { + this.testCase = testCaseSupplier.get(); + } + + @ParametersFactory + public static Iterable parameters() { + var suppliers = List.of( + // V4 + new TestCaseSupplier( + List.of(DataTypes.IP, DataTypes.INTEGER, DataTypes.INTEGER), + () -> new TestCaseSupplier.TestCase( + List.of( + new TestCaseSupplier.TypedData(EsqlDataTypeConverter.stringToIP("1.2.3.4"), DataTypes.IP, "ip"), + new TestCaseSupplier.TypedData(24, DataTypes.INTEGER, "prefixLengthV4"), + new TestCaseSupplier.TypedData(ESTestCase.randomIntBetween(0, 128), DataTypes.INTEGER, "prefixLengthV6") + ), + "IpPrefixEvaluator[ip=Attribute[channel=0], prefixLengthV4=Attribute[channel=1], prefixLengthV6=Attribute[channel=2]]", + DataTypes.IP, + equalTo(EsqlDataTypeConverter.stringToIP("1.2.3.0")) + ) + ), + new TestCaseSupplier(List.of(DataTypes.IP, DataTypes.INTEGER, DataTypes.INTEGER), () -> { + var randomIp = randomIp(true); + var randomPrefix = randomIntBetween(0, 32); + var cidrString = InetAddresses.toCidrString(randomIp, randomPrefix); + + var ipParameter = EsqlDataTypeConverter.stringToIP(NetworkAddress.format(randomIp)); + var expectedPrefix = EsqlDataTypeConverter.stringToIP( + NetworkAddress.format(InetAddresses.parseIpRangeFromCidr(cidrString).lowerBound()) + ); + + return new TestCaseSupplier.TestCase( + List.of( + new TestCaseSupplier.TypedData(ipParameter, DataTypes.IP, "ip"), + new TestCaseSupplier.TypedData(randomPrefix, DataTypes.INTEGER, "prefixLengthV4"), + new TestCaseSupplier.TypedData(ESTestCase.randomIntBetween(0, 128), DataTypes.INTEGER, "prefixLengthV6") + ), + "IpPrefixEvaluator[ip=Attribute[channel=0], prefixLengthV4=Attribute[channel=1], prefixLengthV6=Attribute[channel=2]]", + DataTypes.IP, + equalTo(expectedPrefix) + ); + }), + + // V6 + new TestCaseSupplier( + List.of(DataTypes.IP, DataTypes.INTEGER, DataTypes.INTEGER), + () -> new TestCaseSupplier.TestCase( + List.of( + new TestCaseSupplier.TypedData(EsqlDataTypeConverter.stringToIP("::ff"), DataTypes.IP, "ip"), + new TestCaseSupplier.TypedData(ESTestCase.randomIntBetween(0, 32), DataTypes.INTEGER, "prefixLengthV4"), + new TestCaseSupplier.TypedData(127, DataTypes.INTEGER, "prefixLengthV6") + ), + "IpPrefixEvaluator[ip=Attribute[channel=0], prefixLengthV4=Attribute[channel=1], prefixLengthV6=Attribute[channel=2]]", + DataTypes.IP, + equalTo(EsqlDataTypeConverter.stringToIP("::fe")) + ) + ), + new TestCaseSupplier(List.of(DataTypes.IP, DataTypes.INTEGER, DataTypes.INTEGER), () -> { + var randomIp = randomIp(false); + var randomPrefix = randomIntBetween(0, 128); + var cidrString = InetAddresses.toCidrString(randomIp, randomPrefix); + + var ipParameter = EsqlDataTypeConverter.stringToIP(NetworkAddress.format(randomIp)); + var expectedPrefix = EsqlDataTypeConverter.stringToIP( + NetworkAddress.format(InetAddresses.parseIpRangeFromCidr(cidrString).lowerBound()) + ); + + return new TestCaseSupplier.TestCase( + List.of( + new TestCaseSupplier.TypedData(ipParameter, DataTypes.IP, "ip"), + new TestCaseSupplier.TypedData(ESTestCase.randomIntBetween(0, 32), DataTypes.INTEGER, "prefixLengthV4"), + new TestCaseSupplier.TypedData(randomPrefix, DataTypes.INTEGER, "prefixLengthV6") + ), + "IpPrefixEvaluator[ip=Attribute[channel=0], prefixLengthV4=Attribute[channel=1], prefixLengthV6=Attribute[channel=2]]", + DataTypes.IP, + equalTo(expectedPrefix) + ); + }) + ); + + return parameterSuppliersFromTypedData(errorsForCasesWithoutExamples(anyNullIsNull(true, suppliers))); + } + + @Override + protected Expression build(Source source, List args) { + return new IpPrefix(source, args.get(0), args.get(1), args.size() == 3 ? args.get(2) : null); + } +} From 829070dfea109f73f3a04f42c0e71e3f37e90f53 Mon Sep 17 00:00:00 2001 From: Andrei Dan Date: Wed, 29 May 2024 16:20:44 +0100 Subject: [PATCH 036/208] Install the apm templates only if DSL available (#109166) The APM module installs component and index templates that make use of data stream lifecycle. This makes sure the templates are installed only once the cluster has the data stream lifecycle feature. Follow-up to https://github.com/elastic/elasticsearch/pull/108860 Fixes #106461 --- x-pack/plugin/apm-data/build.gradle | 1 + .../apmdata/APMIndexTemplateRegistry.java | 19 ++++++++++++-- .../xpack/apmdata/APMPlugin.java | 9 ++++++- .../APMIndexTemplateRegistryTests.java | 26 +++++++++++++++++-- 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/x-pack/plugin/apm-data/build.gradle b/x-pack/plugin/apm-data/build.gradle index cbd843d227ff4..354be306a0ddd 100644 --- a/x-pack/plugin/apm-data/build.gradle +++ b/x-pack/plugin/apm-data/build.gradle @@ -20,6 +20,7 @@ dependencies { compileOnly project(path: xpackModule('core')) testImplementation project(path: ':x-pack:plugin:stack') testImplementation(testArtifact(project(xpackModule('core')))) + testImplementation project(':modules:data-streams') clusterModules project(':modules:data-streams') clusterModules project(':modules:ingest-common') clusterModules project(':modules:ingest-geoip') diff --git a/x-pack/plugin/apm-data/src/main/java/org/elasticsearch/xpack/apmdata/APMIndexTemplateRegistry.java b/x-pack/plugin/apm-data/src/main/java/org/elasticsearch/xpack/apmdata/APMIndexTemplateRegistry.java index 6ec287fe2b980..04b0257f4180a 100644 --- a/x-pack/plugin/apm-data/src/main/java/org/elasticsearch/xpack/apmdata/APMIndexTemplateRegistry.java +++ b/x-pack/plugin/apm-data/src/main/java/org/elasticsearch/xpack/apmdata/APMIndexTemplateRegistry.java @@ -10,12 +10,15 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.elasticsearch.client.internal.Client; +import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.metadata.ComponentTemplate; import org.elasticsearch.cluster.metadata.ComposableIndexTemplate; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.core.Nullable; +import org.elasticsearch.features.FeatureService; +import org.elasticsearch.features.NodeFeature; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xcontent.NamedXContentRegistry; import org.elasticsearch.xcontent.XContentParserConfiguration; @@ -39,12 +42,15 @@ */ public class APMIndexTemplateRegistry extends IndexTemplateRegistry { private static final Logger logger = LogManager.getLogger(APMIndexTemplateRegistry.class); - + // this node feature is a redefinition of {@link DataStreamFeatures#DATA_STREAM_LIFECYCLE} and it's meant to avoid adding a + // dependency to the data-streams module just for this + public static final NodeFeature DATA_STREAM_LIFECYCLE = new NodeFeature("data_stream.lifecycle"); private final int version; private final Map componentTemplates; private final Map composableIndexTemplates; private final List ingestPipelines; + private final FeatureService featureService; private volatile boolean enabled; @SuppressWarnings("unchecked") @@ -53,7 +59,8 @@ public APMIndexTemplateRegistry( ClusterService clusterService, ThreadPool threadPool, Client client, - NamedXContentRegistry xContentRegistry + NamedXContentRegistry xContentRegistry, + FeatureService featureService ) { super(nodeSettings, clusterService, threadPool, client, xContentRegistry); @@ -78,6 +85,7 @@ public APMIndexTemplateRegistry( Map.Entry> pipelineConfig = map.entrySet().iterator().next(); return loadIngestPipeline(pipelineConfig.getKey(), version, (List) pipelineConfig.getValue().get("dependencies")); }).collect(Collectors.toList()); + this.featureService = featureService; } catch (IOException e) { throw new RuntimeException(e); } @@ -105,6 +113,13 @@ protected String getOrigin() { return ClientHelper.APM_ORIGIN; } + @Override + protected boolean isClusterReady(ClusterChangedEvent event) { + // Ensure current version of the components are installed only after versions that support data stream lifecycle + // due to the use of the feature in all the `@lifecycle` component templates + return featureService.clusterHasFeature(event.state(), DATA_STREAM_LIFECYCLE); + } + @Override protected boolean requiresMasterNode() { return true; diff --git a/x-pack/plugin/apm-data/src/main/java/org/elasticsearch/xpack/apmdata/APMPlugin.java b/x-pack/plugin/apm-data/src/main/java/org/elasticsearch/xpack/apmdata/APMPlugin.java index f905c17c04b4c..102b0d38461c3 100644 --- a/x-pack/plugin/apm-data/src/main/java/org/elasticsearch/xpack/apmdata/APMPlugin.java +++ b/x-pack/plugin/apm-data/src/main/java/org/elasticsearch/xpack/apmdata/APMPlugin.java @@ -48,7 +48,14 @@ public Collection createComponents(PluginServices services) { Settings settings = services.environment().settings(); ClusterService clusterService = services.clusterService(); registry.set( - new APMIndexTemplateRegistry(settings, clusterService, services.threadPool(), services.client(), services.xContentRegistry()) + new APMIndexTemplateRegistry( + settings, + clusterService, + services.threadPool(), + services.client(), + services.xContentRegistry(), + services.featureService() + ) ); if (enabled) { APMIndexTemplateRegistry registryInstance = registry.get(); diff --git a/x-pack/plugin/apm-data/src/test/java/org/elasticsearch/xpack/apmdata/APMIndexTemplateRegistryTests.java b/x-pack/plugin/apm-data/src/test/java/org/elasticsearch/xpack/apmdata/APMIndexTemplateRegistryTests.java index 8228d7011c9c1..e9f0775836c71 100644 --- a/x-pack/plugin/apm-data/src/test/java/org/elasticsearch/xpack/apmdata/APMIndexTemplateRegistryTests.java +++ b/x-pack/plugin/apm-data/src/test/java/org/elasticsearch/xpack/apmdata/APMIndexTemplateRegistryTests.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.apmdata; +import org.elasticsearch.Version; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionResponse; @@ -29,6 +30,7 @@ import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.datastreams.DataStreamFeatures; import org.elasticsearch.features.FeatureService; import org.elasticsearch.ingest.IngestMetadata; import org.elasticsearch.ingest.PipelineConfiguration; @@ -88,7 +90,7 @@ public void createRegistryAndClient() { threadPool = new TestThreadPool(this.getClass().getName()); client = new VerifyingClient(threadPool); clusterService = ClusterServiceUtils.createClusterService(threadPool, clusterSettings); - FeatureService featureService = new FeatureService(List.of()); + FeatureService featureService = new FeatureService(List.of(new DataStreamFeatures())); stackTemplateRegistryAccessor = new StackTemplateRegistryAccessor( new StackTemplateRegistry(Settings.EMPTY, clusterService, threadPool, client, NamedXContentRegistry.EMPTY, featureService) ); @@ -98,7 +100,8 @@ public void createRegistryAndClient() { clusterService, threadPool, client, - NamedXContentRegistry.EMPTY + NamedXContentRegistry.EMPTY, + featureService ); apmIndexTemplateRegistry.setEnabled(true); } @@ -355,6 +358,25 @@ public void testIndexTemplateConventions() throws Exception { } } + public void testThatNothingIsInstalledWhenAllNodesAreNotUpdated() { + DiscoveryNode updatedNode = DiscoveryNodeUtils.create("updatedNode"); + DiscoveryNode outdatedNode = DiscoveryNodeUtils.create("outdatedNode", ESTestCase.buildNewFakeTransportAddress(), Version.V_8_10_0); + DiscoveryNodes nodes = DiscoveryNodes.builder() + .localNodeId("updatedNode") + .masterNodeId("updatedNode") + .add(updatedNode) + .add(outdatedNode) + .build(); + + client.setVerifier((a, r, l) -> { + fail("if some cluster mode are not updated to at least v.8.11.0 nothing should happen"); + return null; + }); + + ClusterChangedEvent event = createClusterChangedEvent(Map.of(), Map.of(), nodes); + apmIndexTemplateRegistry.clusterChanged(event); + } + private Map getIndependentComponentTemplateConfigs() { return apmIndexTemplateRegistry.getComponentTemplateConfigs().entrySet().stream().filter(template -> { Settings settings = template.getValue().template().settings(); From 0f8c375bc826e61ed916db457f6a208d148dbd41 Mon Sep 17 00:00:00 2001 From: elasticsearchmachine <58790826+elasticsearchmachine@users.noreply.github.com> Date: Wed, 29 May 2024 11:22:04 -0400 Subject: [PATCH 037/208] Forward port release notes for v8.13.4 (#108527) --- docs/reference/release-notes.asciidoc | 2 ++ docs/reference/release-notes/8.13.4.asciidoc | 22 ++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 docs/reference/release-notes/8.13.4.asciidoc diff --git a/docs/reference/release-notes.asciidoc b/docs/reference/release-notes.asciidoc index 9fb5bd70e4d29..9b1257e9054c9 100644 --- a/docs/reference/release-notes.asciidoc +++ b/docs/reference/release-notes.asciidoc @@ -8,6 +8,7 @@ This section summarizes the changes in each release. * <> * <> +* <> * <> * <> * <> @@ -68,6 +69,7 @@ This section summarizes the changes in each release. include::release-notes/8.15.0.asciidoc[] include::release-notes/8.14.0.asciidoc[] +include::release-notes/8.13.4.asciidoc[] include::release-notes/8.13.3.asciidoc[] include::release-notes/8.13.2.asciidoc[] include::release-notes/8.13.1.asciidoc[] diff --git a/docs/reference/release-notes/8.13.4.asciidoc b/docs/reference/release-notes/8.13.4.asciidoc new file mode 100644 index 0000000000000..bf3f2f497d8fc --- /dev/null +++ b/docs/reference/release-notes/8.13.4.asciidoc @@ -0,0 +1,22 @@ +[[release-notes-8.13.4]] +== {es} version 8.13.4 + +Also see <>. + +[[bug-8.13.4]] +[float] +=== Bug fixes + +Aggregations:: +* Fix Bucket ordering for partial reduction in date histogram and histogram aggregation {es-pull}108184[#108184] (issue: {es-issue}108181[#108181]) + +ES|QL:: +* Fix `BlockHash` `DirectEncoder` {es-pull}108283[#108283] (issue: {es-issue}108268[#108268]) + +Snapshot/Restore:: +* Ensure necessary security context for s3 bulk deletions {es-pull}108280[#108280] (issue: {es-issue}108049[#108049]) + +TSDB:: +* Fix tsdb codec when doc-values spread in two blocks {es-pull}108276[#108276] + + From aed23cd6af7f836f08caedb9dc321fbed4ea8fad Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 29 May 2024 11:30:30 -0400 Subject: [PATCH 038/208] ESQL: Fix compilation Two PR passing in the night, break each other. --- .../esql/expression/function/scalar/ip/IpPrefix.java | 8 ++++---- .../xpack/esql/io/stream/PlanNamedTypes.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefix.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefix.java index d271742aef82d..5c576101668b3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefix.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/IpPrefix.java @@ -78,12 +78,12 @@ public IpPrefix( } public static IpPrefix readFrom(PlanStreamInput in) throws IOException { - return new IpPrefix(in.readSource(), in.readExpression(), in.readExpression(), in.readExpression()); + return new IpPrefix(Source.readFrom(in), in.readExpression(), in.readExpression(), in.readExpression()); } - public static void writeTo(PlanStreamOutput out, IpPrefix ipPrefix) throws IOException { - out.writeSource(ipPrefix.source()); - List fields = ipPrefix.children(); + public void writeTo(PlanStreamOutput out) throws IOException { + source().writeTo(out); + List fields = children(); assert fields.size() == 3; out.writeExpression(fields.get(0)); out.writeExpression(fields.get(1)); 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 67a6a5d4bb98d..d941b4ef3f40b 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 @@ -395,7 +395,7 @@ public static List namedTypeEntries() { of(ScalarFunction.class, DateTrunc.class, PlanNamedTypes::writeDateTrunc, PlanNamedTypes::readDateTrunc), of(ScalarFunction.class, E.class, PlanNamedTypes::writeNoArgScalar, PlanNamedTypes::readNoArgScalar), of(ScalarFunction.class, Greatest.class, PlanNamedTypes::writeVararg, PlanNamedTypes::readVarag), - of(ScalarFunction.class, IpPrefix.class, IpPrefix::writeTo, IpPrefix::readFrom), + of(ScalarFunction.class, IpPrefix.class, (out, prefix) -> prefix.writeTo(out), IpPrefix::readFrom), of(ScalarFunction.class, Least.class, PlanNamedTypes::writeVararg, PlanNamedTypes::readVarag), of(ScalarFunction.class, Log.class, PlanNamedTypes::writeLog, PlanNamedTypes::readLog), of(ScalarFunction.class, Now.class, PlanNamedTypes::writeNow, PlanNamedTypes::readNow), From 6bb687bfb25bbbc8cfac50cf5834b20b03dc575a Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 29 May 2024 11:34:43 -0400 Subject: [PATCH 039/208] ESQL: Drop unused wrapper (#109125) This isn't used any more. --- .../planner/EsqlExpressionTranslators.java | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java index d78d2d7f79d80..8873bd770a84e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java @@ -53,7 +53,6 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import java.util.function.Supplier; import static org.elasticsearch.xpack.esql.core.type.DataTypes.IP; import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; @@ -376,26 +375,13 @@ public static void checkSpatialRelatesFunction(Expression constantExpression, Sh ); } - /** - * We should normally be using the real `wrapFunctionQuery` above, so we get the benefits of `SingleValueQuery`, - * but at the moment `SingleValueQuery` makes use of `SortDocValues` to determine if the results are single or multi-valued, - * and LeafShapeFieldData does not support `SortedBinaryDocValues getBytesValues()`. - * Skipping this code path entirely is a temporary workaround while separate work is being done to simplify `SingleValueQuery` - * to rather rely on a new method on `LeafFieldData`. This is both for the benefit of the spatial queries, as well as an - * improvement overall. - * TODO: Remove this method and call the parent method once the SingleValueQuery improvements have been made - */ - public static Query wrapFunctionQuery(Supplier querySupplier) { - return querySupplier.get(); - } - public static Query doTranslate(SpatialRelatesFunction bc, TranslatorHandler handler) { if (bc.left().foldable()) { checkSpatialRelatesFunction(bc.left(), bc.queryRelation()); - return wrapFunctionQuery(() -> translate(bc, handler, bc.right(), bc.left())); + return translate(bc, handler, bc.right(), bc.left()); } else { checkSpatialRelatesFunction(bc.right(), bc.queryRelation()); - return wrapFunctionQuery(() -> translate(bc, handler, bc.left(), bc.right())); + return translate(bc, handler, bc.left(), bc.right()); } } From 1582c645bf5e89c4271acec6cb7db886a0ca8fb4 Mon Sep 17 00:00:00 2001 From: Pat Whelan Date: Wed, 29 May 2024 11:40:46 -0400 Subject: [PATCH 040/208] [ML] Offload request to generic threadpool (#109104) buildTextStructureResponse can take a long time, presumably up to 25s, and is currently blocking the transport thread for that amount of time. Offloading the request to the generic threadpool will at least let the transport thread handle other requests concurrently. Co-authored-by: David Turner --- docs/changelog/109104.yaml | 6 +++ .../transport/TextStructExecutor.java | 47 +++++++++++++++++++ .../TransportFindFieldStructureAction.java | 21 +++++---- .../TransportFindMessageStructureAction.java | 20 +++++--- .../TransportFindStructureAction.java | 26 +++++++--- 5 files changed, 96 insertions(+), 24 deletions(-) create mode 100644 docs/changelog/109104.yaml create mode 100644 x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TextStructExecutor.java diff --git a/docs/changelog/109104.yaml b/docs/changelog/109104.yaml new file mode 100644 index 0000000000000..985cf14bc5952 --- /dev/null +++ b/docs/changelog/109104.yaml @@ -0,0 +1,6 @@ +pr: 109104 +summary: Offload request to generic threadpool +area: Machine Learning +type: bug +issues: + - 109100 diff --git a/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TextStructExecutor.java b/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TextStructExecutor.java new file mode 100644 index 0000000000000..89b21c8dfbcf5 --- /dev/null +++ b/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TextStructExecutor.java @@ -0,0 +1,47 @@ +/* + * 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.textstructure.transport; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRunnable; +import org.elasticsearch.common.CheckedSupplier; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.threadpool.ThreadPool; + +import java.util.concurrent.ExecutorService; + +import static org.elasticsearch.common.util.concurrent.EsExecutors.DIRECT_EXECUTOR_SERVICE; + +/** + * workaround for https://github.com/elastic/elasticsearch/issues/97916 + * TODO delete this entire class when we can + */ +public class TextStructExecutor { + private final ThreadPool threadPool; + + @Inject + public TextStructExecutor(ThreadPool threadPool) { + this.threadPool = threadPool; + } + + /** + * when the workaround is removed, change the value in each consuming class's constructor passes to the super constructor from + * DIRECT_EXECUTOR_SERVICE back to threadpool.generic() so that we continue to fork off of the transport thread. + */ + ExecutorService handledTransportActionExecutorService() { + return DIRECT_EXECUTOR_SERVICE; + } + + /** + * when the workaround is removed, change the callers of this function to + * {@link ActionListener#completeWith(ActionListener, CheckedSupplier)}. + */ + void execute(ActionListener listener, CheckedSupplier supplier) { + threadPool.generic().execute(ActionRunnable.supply(listener, supplier)); + } +} diff --git a/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TransportFindFieldStructureAction.java b/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TransportFindFieldStructureAction.java index 43a990f6f565b..88e60dc3ffd9f 100644 --- a/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TransportFindFieldStructureAction.java +++ b/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TransportFindFieldStructureAction.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.textstructure.transport; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRunnable; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.HandledTransportAction; @@ -31,6 +32,8 @@ import java.util.Objects; import java.util.stream.Collectors; +import static org.elasticsearch.threadpool.ThreadPool.Names.GENERIC; + public class TransportFindFieldStructureAction extends HandledTransportAction { private final Client client; @@ -58,21 +61,18 @@ protected void doExecute(Task task, FindFieldStructureAction.Request request, Ac .setFetchSource(true) .setQuery(QueryBuilders.existsQuery(request.getField())) .setFetchSource(new String[] { request.getField() }, null) - .execute(ActionListener.wrap(searchResponse -> { - long hitCount = searchResponse.getHits().getHits().length; + .execute(listener.delegateFailureAndWrap((delegate, searchResponse) -> { + var hitCount = searchResponse.getHits().getHits().length; if (hitCount < AbstractFindStructureRequest.MIN_SAMPLE_LINE_COUNT) { - listener.onFailure( + delegate.onFailure( new IllegalArgumentException("Input contained too few lines [" + hitCount + "] to obtain a meaningful sample") ); return; } - List messages = getMessages(searchResponse, request.getField()); - try { - listener.onResponse(buildTextStructureResponse(messages, request)); - } catch (Exception e) { - listener.onFailure(e); - } - }, listener::onFailure)); + var messages = getMessages(searchResponse, request.getField()); + // As matching a regular expression might take a while, we run in a different thread to avoid blocking the network thread. + threadPool.generic().execute(ActionRunnable.supply(delegate, () -> buildTextStructureResponse(messages, request))); + })); } private List getMessages(SearchResponse searchResponse, String field) { @@ -83,6 +83,7 @@ private List getMessages(SearchResponse searchResponse, String field) { private FindStructureResponse buildTextStructureResponse(List messages, FindFieldStructureAction.Request request) throws Exception { + assert ThreadPool.assertCurrentThreadPool(GENERIC); TextStructureFinderManager structureFinderManager = new TextStructureFinderManager(threadPool.scheduler()); TextStructureFinder textStructureFinder = structureFinderManager.findTextStructure( messages, diff --git a/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TransportFindMessageStructureAction.java b/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TransportFindMessageStructureAction.java index 79c21b3cea306..d915a7babcbfe 100644 --- a/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TransportFindMessageStructureAction.java +++ b/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TransportFindMessageStructureAction.java @@ -19,32 +19,38 @@ import org.elasticsearch.xpack.textstructure.structurefinder.TextStructureFinderManager; import org.elasticsearch.xpack.textstructure.structurefinder.TextStructureOverrides; +import static org.elasticsearch.threadpool.ThreadPool.Names.GENERIC; + public class TransportFindMessageStructureAction extends HandledTransportAction { private final ThreadPool threadPool; + private final TextStructExecutor executor; @Inject - public TransportFindMessageStructureAction(TransportService transportService, ActionFilters actionFilters, ThreadPool threadPool) { + public TransportFindMessageStructureAction( + TransportService transportService, + ActionFilters actionFilters, + ThreadPool threadPool, + TextStructExecutor executor + ) { super( FindMessageStructureAction.NAME, transportService, actionFilters, FindMessageStructureAction.Request::new, - threadPool.generic() + executor.handledTransportActionExecutorService() ); this.threadPool = threadPool; + this.executor = executor; } @Override protected void doExecute(Task task, FindMessageStructureAction.Request request, ActionListener listener) { - try { - listener.onResponse(buildTextStructureResponse(request)); - } catch (Exception e) { - listener.onFailure(e); - } + executor.execute(listener, () -> buildTextStructureResponse(request)); } private FindStructureResponse buildTextStructureResponse(FindMessageStructureAction.Request request) throws Exception { + assert ThreadPool.assertCurrentThreadPool(GENERIC); TextStructureFinderManager structureFinderManager = new TextStructureFinderManager(threadPool.scheduler()); TextStructureFinder textStructureFinder = structureFinderManager.findTextStructure( request.getMessages(), diff --git a/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TransportFindStructureAction.java b/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TransportFindStructureAction.java index 4257a36bc150a..aa546e1747ba4 100644 --- a/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TransportFindStructureAction.java +++ b/x-pack/plugin/text-structure/src/main/java/org/elasticsearch/xpack/textstructure/transport/TransportFindStructureAction.java @@ -21,26 +21,38 @@ import java.io.InputStream; +import static org.elasticsearch.threadpool.ThreadPool.Names.GENERIC; + public class TransportFindStructureAction extends HandledTransportAction { private final ThreadPool threadPool; + private final TextStructExecutor executor; @Inject - public TransportFindStructureAction(TransportService transportService, ActionFilters actionFilters, ThreadPool threadPool) { - super(FindStructureAction.NAME, transportService, actionFilters, FindStructureAction.Request::new, threadPool.generic()); + public TransportFindStructureAction( + TransportService transportService, + ActionFilters actionFilters, + ThreadPool threadPool, + TextStructExecutor executor + ) { + super( + FindStructureAction.NAME, + transportService, + actionFilters, + FindStructureAction.Request::new, + executor.handledTransportActionExecutorService() + ); this.threadPool = threadPool; + this.executor = executor; } @Override protected void doExecute(Task task, FindStructureAction.Request request, ActionListener listener) { - try { - listener.onResponse(buildTextStructureResponse(request)); - } catch (Exception e) { - listener.onFailure(e); - } + executor.execute(listener, () -> buildTextStructureResponse(request)); } private FindStructureResponse buildTextStructureResponse(FindStructureAction.Request request) throws Exception { + assert ThreadPool.assertCurrentThreadPool(GENERIC); TextStructureFinderManager structureFinderManager = new TextStructureFinderManager(threadPool.scheduler()); try (InputStream sampleStream = request.getSample().streamInput()) { TextStructureFinder textStructureFinder = structureFinderManager.findTextStructure( From 1413c67d99e25a35dd7f5a17f86281b8f1dca750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Wed, 29 May 2024 17:43:10 +0200 Subject: [PATCH 041/208] [DOCS] Amends inference reference docs and tutorials (#109159) * [DOCS] Fixes inference tutorial widgets. * [DOCS] Adds link to notebooks, rearranges sections in PUT inference API docs. --- .../inference/put-inference.asciidoc | 552 +++++++++--------- .../semantic-search-inference.asciidoc | 12 +- .../infer-api-ingest-pipeline-widget.asciidoc | 2 +- .../infer-api-reindex-widget.asciidoc | 2 +- .../infer-api-search-widget.asciidoc | 2 +- 5 files changed, 294 insertions(+), 276 deletions(-) diff --git a/docs/reference/inference/put-inference.asciidoc b/docs/reference/inference/put-inference.asciidoc index cac03afd29562..354cee3f6a990 100644 --- a/docs/reference/inference/put-inference.asciidoc +++ b/docs/reference/inference/put-inference.asciidoc @@ -8,10 +8,11 @@ Creates an {infer} endpoint to perform an {infer} task. IMPORTANT: The {infer} APIs enable you to use certain services, such as built-in {ml} models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure -OpenAI, Google AI Studio or Hugging Face. For built-in models and models uploaded though -Eland, the {infer} APIs offer an alternative way to use and manage trained -models. However, if you do not plan to use the {infer} APIs to use these models -or if you want to use non-NLP models, use the <>. +OpenAI, Google AI Studio or Hugging Face. For built-in models and models +uploaded though Eland, the {infer} APIs offer an alternative way to use and +manage trained models. However, if you do not plan to use the {infer} APIs to +use these models or if you want to use non-NLP models, use the +<>. [discrete] @@ -38,14 +39,14 @@ The create {infer} API enables you to create an {infer} endpoint and configure a The following services are available through the {infer} API: +* Azure AI Studio +* Azure OpenAI * Cohere +* Elasticsearch (for built-in models and models uploaded through Eland) * ELSER +* Google AI Studio * Hugging Face * OpenAI -* Azure OpenAI -* Azure AI Studio -* Elasticsearch (for built-in models and models uploaded through Eland) -* Google AI Studio [discrete] @@ -74,82 +75,34 @@ The type of the {infer} task that the model will perform. Available task types: (Required, string) The type of service supported for the specified task type. Available services: + +* `azureopenai`: specify the `completion` or `text_embedding` task type to use the Azure OpenAI service. +* `azureaistudio`: specify the `completion` or `text_embedding` task type to use the Azure AI Studio service. * `cohere`: specify the `completion`, `text_embedding` or the `rerank` task type to use the Cohere service. +* `elasticsearch`: specify the `text_embedding` task type to use the E5 +built-in model or text embedding models uploaded by Eland. * `elser`: specify the `sparse_embedding` task type to use the ELSER service. +* `googleaistudio`: specify the `completion` task to use the Google AI Studio service. * `hugging_face`: specify the `text_embedding` task type to use the Hugging Face service. * `openai`: specify the `completion` or `text_embedding` task type to use the OpenAI service. -* `azureopenai`: specify the `completion` or `text_embedding` task type to use the Azure OpenAI service. -* `azureaistudio`: specify the `completion` or `text_embedding` task type to use the Azure AI Studio service. -* `elasticsearch`: specify the `text_embedding` task type to use the E5 -built-in model or text embedding models uploaded by Eland. -* `googleaistudio`: specify the `completion` task to use the Google AI Studio service. + `service_settings`:: (Required, object) Settings used to install the {infer} model. These settings are specific to the `service` you specified. + -.`service_settings` for the `cohere` service -[%collapsible%closed] -===== -`api_key`::: -(Required, string) -A valid API key of your Cohere account. You can find your Cohere API keys or you -can create a new one -https://dashboard.cohere.com/api-keys[on the API keys settings page]. - -IMPORTANT: You need to provide the API key only once, during the {infer} model -creation. The <> does not retrieve your API key. After -creating the {infer} model, you cannot change the associated API key. If you -want to use a different API key, delete the {infer} model and recreate it with -the same name and the updated API key. - -`embedding_type`:: -(Optional, string) -Only for `text_embedding`. Specifies the types of embeddings you want to get -back. Defaults to `float`. -Valid values are: - * `byte`: use it for signed int8 embeddings (this is a synonym of `int8`). - * `float`: use it for the default float embeddings. - * `int8`: use it for signed int8 embeddings. - -`model_id`:: -(Optional, string) -The name of the model to use for the {infer} task. -To review the available `rerank` models, refer to the -https://docs.cohere.com/reference/rerank-1[Cohere docs]. - -To review the available `text_embedding` models, refer to the -https://docs.cohere.com/reference/embed[Cohere docs]. The default value for -`text_embedding` is `embed-english-v2.0`. -===== -+ -.`service_settings` for the `elser` service +.`service_settings` for the `azureaistudio` service [%collapsible%closed] ===== -`num_allocations`::: -(Required, integer) -The number of model allocations to create. `num_allocations` must not exceed the -number of available processors per node divided by the `num_threads`. -`num_threads`::: -(Required, integer) -The number of threads to use by each model allocation. `num_threads` must not -exceed the number of available processors per node divided by the number of -allocations. Must be a power of 2. Max allowed value is 32. -===== -+ -.`service_settings` for the `hugging_face` service -[%collapsible%closed] -===== `api_key`::: (Required, string) -A valid access token of your Hugging Face account. You can find your Hugging -Face access tokens or you can create a new one -https://huggingface.co/settings/tokens[on the settings page]. +A valid API key of your Azure AI Studio model deployment. +This key can be found on the overview page for your deployment in the management section of your https://ai.azure.com/[Azure AI Studio] account. IMPORTANT: You need to provide the API key only once, during the {infer} model creation. The <> does not retrieve your API key. After @@ -157,43 +110,43 @@ creating the {infer} model, you cannot change the associated API key. If you want to use a different API key, delete the {infer} model and recreate it with the same name and the updated API key. -`url`::: -(Required, string) -The URL endpoint to use for the requests. -===== -+ -.`service_settings` for the `openai` service -[%collapsible%closed] -===== -`api_key`::: +`target`::: (Required, string) -A valid API key of your OpenAI account. You can find your OpenAI API keys in -your OpenAI account under the -https://platform.openai.com/api-keys[API keys section]. - -IMPORTANT: You need to provide the API key only once, during the {infer} model -creation. The <> does not retrieve your API key. After -creating the {infer} model, you cannot change the associated API key. If you -want to use a different API key, delete the {infer} model and recreate it with -the same name and the updated API key. +The target URL of your Azure AI Studio model deployment. +This can be found on the overview page for your deployment in the management section of your https://ai.azure.com/[Azure AI Studio] account. -`model_id`::: +`provider`::: (Required, string) -The name of the model to use for the {infer} task. Refer to the -https://platform.openai.com/docs/guides/embeddings/what-are-embeddings[OpenAI documentation] -for the list of available text embedding models. +The model provider for your deployment. +Note that some providers may support only certain task types. +Supported providers include: -`organization_id`::: -(Optional, string) -The unique identifier of your organization. You can find the Organization ID in -your OpenAI account under -https://platform.openai.com/account/organization[**Settings** > **Organizations**]. +* `cohere` - available for `text_embedding` and `completion` task types +* `databricks` - available for `completion` task type only +* `meta` - available for `completion` task type only +* `microsoft_phi` - available for `completion` task type only +* `mistral` - available for `completion` task type only +* `openai` - available for `text_embedding` and `completion` task types -`url`::: -(Optional, string) -The URL endpoint to use for the requests. Can be changed for testing purposes. -Defaults to `https://api.openai.com/v1/embeddings`. +`endpoint_type`::: +(Required, string) +One of `token` or `realtime`. +Specifies the type of endpoint that is used in your model deployment. +There are https://learn.microsoft.com/en-us/azure/ai-studio/concepts/deployments-overview#billing-for-deploying-and-inferencing-llms-in-azure-ai-studio[two endpoint types available] for deployment through Azure AI Studio. +"Pay as you go" endpoints are billed per token. +For these, you must specify `token` for your `endpoint_type`. +For "real-time" endpoints which are billed per hour of usage, specify `realtime`. +`rate_limit`::: +(Optional, object) +By default, the `azureaistudio` service sets the number of requests allowed per minute to `240`. +This helps to minimize the number of rate limit errors returned from Azure AI Studio. +To modify this, set the `requests_per_minute` setting of this object in your service settings: +``` +"rate_limit": { + "requests_per_minute": <> +} +``` ===== + .`service_settings` for the `azureopenai` service @@ -230,14 +183,14 @@ We recommend using the https://learn.microsoft.com/en-us/azure/ai-services/opena ===== + -.`service_settings` for the `azureaistudio` service +.`service_settings` for the `cohere` service [%collapsible%closed] ===== - `api_key`::: (Required, string) -A valid API key of your Azure AI Studio model deployment. -This key can be found on the overview page for your deployment in the management section of your https://ai.azure.com/[Azure AI Studio] account. +A valid API key of your Cohere account. You can find your Cohere API keys or you +can create a new one +https://dashboard.cohere.com/api-keys[on the API keys settings page]. IMPORTANT: You need to provide the API key only once, during the {infer} model creation. The <> does not retrieve your API key. After @@ -245,43 +198,61 @@ creating the {infer} model, you cannot change the associated API key. If you want to use a different API key, delete the {infer} model and recreate it with the same name and the updated API key. -`target`::: -(Required, string) -The target URL of your Azure AI Studio model deployment. -This can be found on the overview page for your deployment in the management section of your https://ai.azure.com/[Azure AI Studio] account. +`embedding_type`:: +(Optional, string) +Only for `text_embedding`. Specifies the types of embeddings you want to get +back. Defaults to `float`. +Valid values are: + * `byte`: use it for signed int8 embeddings (this is a synonym of `int8`). + * `float`: use it for the default float embeddings. + * `int8`: use it for signed int8 embeddings. -`provider`::: +`model_id`:: +(Optional, string) +The name of the model to use for the {infer} task. +To review the available `rerank` models, refer to the +https://docs.cohere.com/reference/rerank-1[Cohere docs]. + +To review the available `text_embedding` models, refer to the +https://docs.cohere.com/reference/embed[Cohere docs]. The default value for +`text_embedding` is `embed-english-v2.0`. +===== ++ +.`service_settings` for the `elasticsearch` service +[%collapsible%closed] +===== +`model_id`::: (Required, string) -The model provider for your deployment. -Note that some providers may support only certain task types. -Supported providers include: +The name of the model to use for the {infer} task. It can be the +ID of either a built-in model (for example, `.multilingual-e5-small` for E5) or +a text embedding model already +{ml-docs}/ml-nlp-import-model.html#ml-nlp-import-script[uploaded through Eland]. -* `openai` - available for `text_embedding` and `completion` task types -* `mistral` - available for `completion` task type only -* `meta` - available for `completion` task type only -* `microsoft_phi` - available for `completion` task type only -* `cohere` - available for `text_embedding` and `completion` task types -* `databricks` - available for `completion` task type only +`num_allocations`::: +(Required, integer) +The number of model allocations to create. `num_allocations` must not exceed the +number of available processors per node divided by the `num_threads`. -`endpoint_type`::: -(Required, string) -One of `token` or `realtime`. -Specifies the type of endpoint that is used in your model deployment. -There are https://learn.microsoft.com/en-us/azure/ai-studio/concepts/deployments-overview#billing-for-deploying-and-inferencing-llms-in-azure-ai-studio[two endpoint types available] for deployment through Azure AI Studio. -"Pay as you go" endpoints are billed per token. -For these, you must specify `token` for your `endpoint_type`. -For "real-time" endpoints which are billed per hour of usage, specify `realtime`. +`num_threads`::: +(Required, integer) +The number of threads to use by each model allocation. `num_threads` must not +exceed the number of available processors per node divided by the number of +allocations. Must be a power of 2. Max allowed value is 32. +===== ++ +.`service_settings` for the `elser` service +[%collapsible%closed] +===== +`num_allocations`::: +(Required, integer) +The number of model allocations to create. `num_allocations` must not exceed the +number of available processors per node divided by the `num_threads`. -`rate_limit`::: -(Optional, object) -By default, the `azureaistudio` service sets the number of requests allowed per minute to `240`. -This helps to minimize the number of rate limit errors returned from Azure AI Studio. -To modify this, set the `requests_per_minute` setting of this object in your service settings: -``` -"rate_limit": { - "requests_per_minute": <> -} -``` +`num_threads`::: +(Required, integer) +The number of threads to use by each model allocation. `num_threads` must not +exceed the number of available processors per node divided by the number of +allocations. Must be a power of 2. Max allowed value is 32. ===== + .`service_settings` for the `googleiastudio` service @@ -311,26 +282,58 @@ To modify this, set the `requests_per_minute` setting of this object in your ser -- ===== + -.`service_settings` for the `elasticsearch` service +.`service_settings` for the `hugging_face` service +[%collapsible%closed] +===== +`api_key`::: +(Required, string) +A valid access token of your Hugging Face account. You can find your Hugging +Face access tokens or you can create a new one +https://huggingface.co/settings/tokens[on the settings page]. + +IMPORTANT: You need to provide the API key only once, during the {infer} model +creation. The <> does not retrieve your API key. After +creating the {infer} model, you cannot change the associated API key. If you +want to use a different API key, delete the {infer} model and recreate it with +the same name and the updated API key. + +`url`::: +(Required, string) +The URL endpoint to use for the requests. +===== ++ +.`service_settings` for the `openai` service [%collapsible%closed] ===== +`api_key`::: +(Required, string) +A valid API key of your OpenAI account. You can find your OpenAI API keys in +your OpenAI account under the +https://platform.openai.com/api-keys[API keys section]. + +IMPORTANT: You need to provide the API key only once, during the {infer} model +creation. The <> does not retrieve your API key. After +creating the {infer} model, you cannot change the associated API key. If you +want to use a different API key, delete the {infer} model and recreate it with +the same name and the updated API key. + `model_id`::: (Required, string) -The name of the model to use for the {infer} task. It can be the -ID of either a built-in model (for example, `.multilingual-e5-small` for E5) or -a text embedding model already -{ml-docs}/ml-nlp-import-model.html#ml-nlp-import-script[uploaded through Eland]. +The name of the model to use for the {infer} task. Refer to the +https://platform.openai.com/docs/guides/embeddings/what-are-embeddings[OpenAI documentation] +for the list of available text embedding models. -`num_allocations`::: -(Required, integer) -The number of model allocations to create. `num_allocations` must not exceed the -number of available processors per node divided by the `num_threads`. +`organization_id`::: +(Optional, string) +The unique identifier of your organization. You can find the Organization ID in +your OpenAI account under +https://platform.openai.com/account/organization[**Settings** > **Organizations**]. + +`url`::: +(Optional, string) +The URL endpoint to use for the requests. Can be changed for testing purposes. +Defaults to `https://api.openai.com/v1/embeddings`. -`num_threads`::: -(Required, integer) -The number of threads to use by each model allocation. `num_threads` must not -exceed the number of available processors per node divided by the number of -allocations. Must be a power of 2. Max allowed value is 32. ===== `task_settings`:: @@ -341,6 +344,18 @@ Settings to configure the {infer} task. These settings are specific to the .`task_settings` for the `completion` task type [%collapsible%closed] ===== +`do_sample`::: +(Optional, float) +For the `azureaistudio` service only. +Instructs the inference process to perform sampling or not. +Has not affect unless `temperature` or `top_p` is specified. + +`max_new_tokens`::: +(Optional, integer) +For the `azureaistudio` service only. +Provides a hint for the maximum number of output tokens to be generated. +Defaults to 64. + `user`::: (Optional, string) For `openai` service only. Specifies the user issuing the request, which can be @@ -358,18 +373,6 @@ For the `azureaistudio` service only. A number in the range of 0.0 to 2.0 that is an alternative value to temperature that causes the model to consider the results of the tokens with nucleus sampling probability. Should not be used if `temperature` is specified. -`do_sample`::: -(Optional, float) -For the `azureaistudio` service only. -Instructs the inference process to perform sampling or not. -Has not affect unless `temperature` or `top_p` is specified. - -`max_new_tokens`::: -(Optional, integer) -For the `azureaistudio` service only. -Provides a hint for the maximum number of output tokens to be generated. -Defaults to 64. - ===== + .`task_settings` for the `rerank` task type @@ -422,6 +425,100 @@ request, which can be used for abuse detection. This section contains example API calls for every service type. +[discrete] +[[inference-example-azureaistudio]] +===== Azure AI Studio service + +The following example shows how to create an {infer} endpoint called +`azure_ai_studio_embeddings` to perform a `text_embedding` task type. +Note that we do not specify a model here, as it is defined already via our Azure AI Studio deployment. + +The list of embeddings models that you can choose from in your deployment can be found in the https://ai.azure.com/explore/models?selectedTask=embeddings[Azure AI Studio model explorer]. + +[source,console] +------------------------------------------------------------ +PUT _inference/text_embedding/azure_ai_studio_embeddings +{ + "service": "azureaistudio", + "service_settings": { + "api_key": "", + "target": "", + "provider": "", + "endpoint_type": "" + } +} +------------------------------------------------------------ +// TEST[skip:TBD] + +The next example shows how to create an {infer} endpoint called +`azure_ai_studio_completion` to perform a `completion` task type. + +[source,console] +------------------------------------------------------------ +PUT _inference/completion/azure_ai_studio_completion +{ + "service": "azureaistudio", + "service_settings": { + "api_key": "", + "target": "", + "provider": "", + "endpoint_type": "" + } +} +------------------------------------------------------------ +// TEST[skip:TBD] + +The list of chat completion models that you can choose from in your deployment can be found in the https://ai.azure.com/explore/models?selectedTask=chat-completion[Azure AI Studio model explorer]. + + +[discrete] +[[inference-example-azureopenai]] +===== Azure OpenAI service + +The following example shows how to create an {infer} endpoint called +`azure_openai_embeddings` to perform a `text_embedding` task type. +Note that we do not specify a model here, as it is defined already via our Azure OpenAI deployment. + +The list of embeddings models that you can choose from in your deployment can be found in the https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#embeddings[Azure models documentation]. + +[source,console] +------------------------------------------------------------ +PUT _inference/text_embedding/azure_openai_embeddings +{ + "service": "azureopenai", + "service_settings": { + "api_key": "", + "resource_name": "", + "deployment_id": "", + "api_version": "2024-02-01" + } +} +------------------------------------------------------------ +// TEST[skip:TBD] + +The next example shows how to create an {infer} endpoint called +`azure_openai_completion` to perform a `completion` task type. + +[source,console] +------------------------------------------------------------ +PUT _inference/completion/azure_openai_completion +{ + "service": "azureopenai", + "service_settings": { + "api_key": "", + "resource_name": "", + "deployment_id": "", + "api_version": "2024-02-01" + } +} +------------------------------------------------------------ +// TEST[skip:TBD] + +The list of chat completion models that you can choose from in your Azure OpenAI deployment can be found at the following places: + +* https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#gpt-4-and-gpt-4-turbo-models[GPT-4 and GPT-4 Turbo models] +* https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#gpt-35[GPT-3.5] + [discrete] [[inference-example-cohere]] @@ -471,7 +568,7 @@ https://docs.cohere.com/docs/elasticsearch-and-cohere#rerank-search-results-with [discrete] [[inference-example-e5]] -===== E5 via the elasticsearch service +===== E5 via the `elasticsearch` service The following example shows how to create an {infer} endpoint called `my-e5-model` to perform a `text_embedding` task type. @@ -500,6 +597,8 @@ further details, refer to the {ml-docs}/ml-nlp-e5.html[E5 model documentation]. The following example shows how to create an {infer} endpoint called `my-elser-model` to perform a `sparse_embedding` task type. +Refer to the {ml-docs}/ml-nlp-elser.html[ELSER model documentation] for more +info. [source,console] ------------------------------------------------------------ @@ -533,6 +632,27 @@ Example response: // NOTCONSOLE +[discrete] +[[inference-example-googleaistudio]] +===== Google AI Studio service + +The following example shows how to create an {infer} endpoint called +`google_ai_studio_completion` to perform a `completion` task type. + +[source,console] +------------------------------------------------------------ +PUT _inference/completion/google_ai_studio_completion +{ + "service": "googleaistudio", + "service_settings": { + "api_key": "", + "model_id": "" + } +} +------------------------------------------------------------ +// TEST[skip:TBD] + + [discrete] [[inference-example-hugging-face]] ===== Hugging Face service @@ -637,115 +757,3 @@ PUT _inference/completion/openai-completion ------------------------------------------------------------ // TEST[skip:TBD] -[discrete] -[[inference-example-azureopenai]] -===== Azure OpenAI service - -The following example shows how to create an {infer} endpoint called -`azure_openai_embeddings` to perform a `text_embedding` task type. -Note that we do not specify a model here, as it is defined already via our Azure OpenAI deployment. - -The list of embeddings models that you can choose from in your deployment can be found in the https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#embeddings[Azure models documentation]. - -[source,console] ------------------------------------------------------------- -PUT _inference/text_embedding/azure_openai_embeddings -{ - "service": "azureopenai", - "service_settings": { - "api_key": "", - "resource_name": "", - "deployment_id": "", - "api_version": "2024-02-01" - } -} ------------------------------------------------------------- -// TEST[skip:TBD] - -The next example shows how to create an {infer} endpoint called -`azure_openai_completion` to perform a `completion` task type. - -[source,console] ------------------------------------------------------------- -PUT _inference/completion/azure_openai_completion -{ - "service": "azureopenai", - "service_settings": { - "api_key": "", - "resource_name": "", - "deployment_id": "", - "api_version": "2024-02-01" - } -} ------------------------------------------------------------- -// TEST[skip:TBD] - -The list of chat completion models that you can choose from in your Azure OpenAI deployment can be found at the following places: - -* https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#gpt-4-and-gpt-4-turbo-models[GPT-4 and GPT-4 Turbo models] -* https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#gpt-35[GPT-3.5] - -[discrete] -[[inference-example-azureaistudio]] -===== Azure AI Studio service - -The following example shows how to create an {infer} endpoint called -`azure_ai_studio_embeddings` to perform a `text_embedding` task type. -Note that we do not specify a model here, as it is defined already via our Azure AI Studio deployment. - -The list of embeddings models that you can choose from in your deployment can be found in the https://ai.azure.com/explore/models?selectedTask=embeddings[Azure AI Studio model explorer]. - -[source,console] ------------------------------------------------------------- -PUT _inference/text_embedding/azure_ai_studio_embeddings -{ - "service": "azureaistudio", - "service_settings": { - "api_key": "", - "target": "", - "provider": "", - "endpoint_type": "" - } -} ------------------------------------------------------------- -// TEST[skip:TBD] - -The next example shows how to create an {infer} endpoint called -`azure_ai_studio_completion` to perform a `completion` task type. - -[source,console] ------------------------------------------------------------- -PUT _inference/completion/azure_ai_studio_completion -{ - "service": "azureaistudio", - "service_settings": { - "api_key": "", - "target": "", - "provider": "", - "endpoint_type": "" - } -} ------------------------------------------------------------- -// TEST[skip:TBD] - -The list of chat completion models that you can choose from in your deployment can be found in the https://ai.azure.com/explore/models?selectedTask=chat-completion[Azure AI Studio model explorer]. - -[discrete] -[[inference-example-googleaistudio]] -===== Google AI Studio service - -The following example shows how to create an {infer} endpoint called -`google_ai_studio_completion` to perform a `completion` task type. - -[source,console] ------------------------------------------------------------- -PUT _inference/completion/google_ai_studio_completion -{ - "service": "googleaistudio", - "service_settings": { - "api_key": ">", - "model_id": "" - } -} ------------------------------------------------------------- -// TEST[skip:TBD] diff --git a/docs/reference/search/search-your-data/semantic-search-inference.asciidoc b/docs/reference/search/search-your-data/semantic-search-inference.asciidoc index e7e16d74764fa..89464d46744b2 100644 --- a/docs/reference/search/search-your-data/semantic-search-inference.asciidoc +++ b/docs/reference/search/search-your-data/semantic-search-inference.asciidoc @@ -114,4 +114,14 @@ provide the query text and the model you have used to create the embeddings. NOTE: If you cancelled the reindexing process, you run the query only a part of the data which affects the quality of your results. -include::{es-ref-dir}/tab-widgets/inference-api/infer-api-search-widget.asciidoc[] \ No newline at end of file +include::{es-ref-dir}/tab-widgets/inference-api/infer-api-search-widget.asciidoc[] + + +[discrete] +[[infer-interactive-tutorials]] +==== Interactive tutorials + +You can also find tutorials in an interactive Colab notebook format using the +{es} Python client: +* https://colab.research.google.com/github/elastic/elasticsearch-labs/blob/main/notebooks/integrations/cohere/inference-cohere.ipynb[Cohere {infer} tutorial notebook] +* https://colab.research.google.com/github/elastic/elasticsearch-labs/blob/main/notebooks/search/07-inference.ipynb[OpenAI {infer} tutorial notebook] \ No newline at end of file diff --git a/docs/reference/tab-widgets/inference-api/infer-api-ingest-pipeline-widget.asciidoc b/docs/reference/tab-widgets/inference-api/infer-api-ingest-pipeline-widget.asciidoc index ce0f41524c1a0..80f6da2cf602a 100644 --- a/docs/reference/tab-widgets/inference-api/infer-api-ingest-pipeline-widget.asciidoc +++ b/docs/reference/tab-widgets/inference-api/infer-api-ingest-pipeline-widget.asciidoc @@ -8,7 +8,7 @@ Cohere