diff --git a/.buildkite/pipelines/intake.yml b/.buildkite/pipelines/intake.yml index 2633dee0a7ea..3cc525b36f94 100644 --- a/.buildkite/pipelines/intake.yml +++ b/.buildkite/pipelines/intake.yml @@ -56,7 +56,7 @@ steps: timeout_in_minutes: 300 matrix: setup: - BWC_VERSION: ["8.16.4", "8.17.2", "8.18.0", "8.19.0", "9.0.0", "9.1.0"] + BWC_VERSION: ["8.16.5", "8.17.3", "8.18.0", "8.19.0", "9.0.0", "9.1.0"] agents: provider: gcp image: family/elasticsearch-ubuntu-2004 diff --git a/.buildkite/pipelines/periodic-packaging.yml b/.buildkite/pipelines/periodic-packaging.yml index 99ff9ec9ecf2..e2db7579724b 100644 --- a/.buildkite/pipelines/periodic-packaging.yml +++ b/.buildkite/pipelines/periodic-packaging.yml @@ -287,8 +287,8 @@ steps: env: BWC_VERSION: 8.15.5 - - label: "{{matrix.image}} / 8.16.4 / packaging-tests-upgrade" - command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.16.4 + - label: "{{matrix.image}} / 8.16.5 / packaging-tests-upgrade" + command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.16.5 timeout_in_minutes: 300 matrix: setup: @@ -301,10 +301,10 @@ steps: machineType: custom-16-32768 buildDirectory: /dev/shm/bk env: - BWC_VERSION: 8.16.4 + BWC_VERSION: 8.16.5 - - label: "{{matrix.image}} / 8.17.2 / packaging-tests-upgrade" - command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.17.2 + - label: "{{matrix.image}} / 8.17.3 / packaging-tests-upgrade" + command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.17.3 timeout_in_minutes: 300 matrix: setup: @@ -317,7 +317,7 @@ steps: machineType: custom-16-32768 buildDirectory: /dev/shm/bk env: - BWC_VERSION: 8.17.2 + BWC_VERSION: 8.17.3 - label: "{{matrix.image}} / 8.18.0 / packaging-tests-upgrade" command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.18.0 diff --git a/.buildkite/pipelines/periodic.template.yml b/.buildkite/pipelines/periodic.template.yml index 4ebe8460c72d..cf14bcdb3c5d 100644 --- a/.buildkite/pipelines/periodic.template.yml +++ b/.buildkite/pipelines/periodic.template.yml @@ -78,8 +78,8 @@ steps: BWC_VERSION: "{{matrix.BWC_VERSION}}" - group: java-matrix steps: - - label: "{{matrix.ES_RUNTIME_JAVA}} / {{matrix.GRADLE_TASK}} / java-matrix" - command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true $$GRADLE_TASK + - label: "{{matrix.ES_RUNTIME_JAVA}} / entitlements={{matrix.ENTITLEMENTS_ENABLED}} / {{matrix.GRADLE_TASK}} / java-matrix" + command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true -Dtests.jvm.argline="-Des.entitlements.enabled=$$ENTITLEMENTS_ENABLED" $$GRADLE_TASK timeout_in_minutes: 300 matrix: setup: @@ -94,6 +94,9 @@ steps: - checkPart4 - checkPart5 - checkRestCompat + ENTITLEMENTS_ENABLED: + - "true" + - "false" agents: provider: gcp image: family/elasticsearch-ubuntu-2004 @@ -102,6 +105,7 @@ steps: env: ES_RUNTIME_JAVA: "{{matrix.ES_RUNTIME_JAVA}}" GRADLE_TASK: "{{matrix.GRADLE_TASK}}" + ENTITLEMENTS_ENABLED: "{{matrix.ENTITLEMENTS_ENABLED}}" - label: "{{matrix.ES_RUNTIME_JAVA}} / {{matrix.BWC_VERSION}} / java-matrix-bwc" command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v$$BWC_VERSION#bwcTest timeout_in_minutes: 300 diff --git a/.buildkite/pipelines/periodic.yml b/.buildkite/pipelines/periodic.yml index ff771061950e..90ab4d31f1c3 100644 --- a/.buildkite/pipelines/periodic.yml +++ b/.buildkite/pipelines/periodic.yml @@ -306,8 +306,8 @@ steps: - signal_reason: agent_stop limit: 3 - - label: 8.16.4 / bwc - command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.16.4#bwcTest + - label: 8.16.5 / bwc + command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.16.5#bwcTest timeout_in_minutes: 300 agents: provider: gcp @@ -316,7 +316,7 @@ steps: buildDirectory: /dev/shm/bk preemptible: true env: - BWC_VERSION: 8.16.4 + BWC_VERSION: 8.16.5 retry: automatic: - exit_status: "-1" @@ -325,8 +325,8 @@ steps: - signal_reason: agent_stop limit: 3 - - label: 8.17.2 / bwc - command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.17.2#bwcTest + - label: 8.17.3 / bwc + command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.17.3#bwcTest timeout_in_minutes: 300 agents: provider: gcp @@ -335,7 +335,7 @@ steps: buildDirectory: /dev/shm/bk preemptible: true env: - BWC_VERSION: 8.17.2 + BWC_VERSION: 8.17.3 retry: automatic: - exit_status: "-1" @@ -486,7 +486,7 @@ steps: setup: ES_RUNTIME_JAVA: - openjdk21 - BWC_VERSION: ["8.16.4", "8.17.2", "8.18.0", "8.19.0", "9.0.0", "9.1.0"] + BWC_VERSION: ["8.16.5", "8.17.3", "8.18.0", "8.19.0", "9.0.0", "9.1.0"] agents: provider: gcp image: family/elasticsearch-ubuntu-2004 @@ -497,8 +497,8 @@ steps: BWC_VERSION: "{{matrix.BWC_VERSION}}" - group: java-matrix steps: - - label: "{{matrix.ES_RUNTIME_JAVA}} / {{matrix.GRADLE_TASK}} / java-matrix" - command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true $$GRADLE_TASK + - label: "{{matrix.ES_RUNTIME_JAVA}} / entitlements={{matrix.ENTITLEMENTS_ENABLED}} / {{matrix.GRADLE_TASK}} / java-matrix" + command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true -Dtests.jvm.argline="-Des.entitlements.enabled=$$ENTITLEMENTS_ENABLED" $$GRADLE_TASK timeout_in_minutes: 300 matrix: setup: @@ -513,6 +513,9 @@ steps: - checkPart4 - checkPart5 - checkRestCompat + ENTITLEMENTS_ENABLED: + - "true" + - "false" agents: provider: gcp image: family/elasticsearch-ubuntu-2004 @@ -521,6 +524,7 @@ steps: env: ES_RUNTIME_JAVA: "{{matrix.ES_RUNTIME_JAVA}}" GRADLE_TASK: "{{matrix.GRADLE_TASK}}" + ENTITLEMENTS_ENABLED: "{{matrix.ENTITLEMENTS_ENABLED}}" - label: "{{matrix.ES_RUNTIME_JAVA}} / {{matrix.BWC_VERSION}} / java-matrix-bwc" command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v$$BWC_VERSION#bwcTest timeout_in_minutes: 300 @@ -529,7 +533,7 @@ steps: ES_RUNTIME_JAVA: - openjdk21 - openjdk23 - BWC_VERSION: ["8.16.4", "8.17.2", "8.18.0", "8.19.0", "9.0.0", "9.1.0"] + BWC_VERSION: ["8.16.5", "8.17.3", "8.18.0", "8.19.0", "9.0.0", "9.1.0"] agents: provider: gcp image: family/elasticsearch-ubuntu-2004 diff --git a/.buildkite/scripts/dra-update-staging.sh b/.buildkite/scripts/dra-update-staging.sh index 676361bf1cfc..e168dbf733ea 100755 --- a/.buildkite/scripts/dra-update-staging.sh +++ b/.buildkite/scripts/dra-update-staging.sh @@ -36,6 +36,9 @@ for BRANCH in "${BRANCHES[@]}"; do fi if [[ "$SHOULD_TRIGGER" == "true" ]]; then + if [[ "$BRANCH" == "9.0" ]]; then + export VERSION_QUALIFIER="beta1" + fi echo "Triggering DRA staging workflow for $BRANCH" cat << EOF | buildkite-agent pipeline upload steps: @@ -46,6 +49,7 @@ steps: branch: "$BRANCH" env: DRA_WORKFLOW: staging + VERSION_QUALIFIER: ${VERSION_QUALIFIER:-} EOF fi done diff --git a/.ci/bwcVersions b/.ci/bwcVersions index e80e036907a0..4d27c647bc40 100644 --- a/.ci/bwcVersions +++ b/.ci/bwcVersions @@ -15,8 +15,8 @@ BWC_VERSION: - "8.13.4" - "8.14.3" - "8.15.5" - - "8.16.4" - - "8.17.2" + - "8.16.5" + - "8.17.3" - "8.18.0" - "8.19.0" - "9.0.0" diff --git a/.ci/snapshotBwcVersions b/.ci/snapshotBwcVersions index 68663fdfb178..9920160e4df8 100644 --- a/.ci/snapshotBwcVersions +++ b/.ci/snapshotBwcVersions @@ -1,6 +1,6 @@ BWC_VERSION: - - "8.16.4" - - "8.17.2" + - "8.16.5" + - "8.17.3" - "8.18.0" - "8.19.0" - "9.0.0" diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/AggregatorBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/AggregatorBenchmark.java index 652defa7b39c..77c70bc3a10f 100644 --- a/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/AggregatorBenchmark.java +++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/AggregatorBenchmark.java @@ -155,7 +155,7 @@ public class AggregatorBenchmark { if (grouping.equals("none")) { return new AggregationOperator( - List.of(supplier(op, dataType, filter, 0).aggregatorFactory(AggregatorMode.SINGLE).apply(driverContext)), + List.of(supplier(op, dataType, filter).aggregatorFactory(AggregatorMode.SINGLE, List.of(0)).apply(driverContext)), driverContext ); } @@ -182,33 +182,33 @@ public class AggregatorBenchmark { default -> throw new IllegalArgumentException("unsupported grouping [" + grouping + "]"); }; return new HashAggregationOperator( - List.of(supplier(op, dataType, filter, groups.size()).groupingAggregatorFactory(AggregatorMode.SINGLE)), + List.of(supplier(op, dataType, filter).groupingAggregatorFactory(AggregatorMode.SINGLE, List.of(groups.size()))), () -> BlockHash.build(groups, driverContext.blockFactory(), 16 * 1024, false), driverContext ); } - private static AggregatorFunctionSupplier supplier(String op, String dataType, String filter, int dataChannel) { + private static AggregatorFunctionSupplier supplier(String op, String dataType, String filter) { return filtered(switch (op) { - case COUNT -> CountAggregatorFunction.supplier(List.of(dataChannel)); + case COUNT -> CountAggregatorFunction.supplier(); case COUNT_DISTINCT -> switch (dataType) { - case LONGS -> new CountDistinctLongAggregatorFunctionSupplier(List.of(dataChannel), 3000); - case DOUBLES -> new CountDistinctDoubleAggregatorFunctionSupplier(List.of(dataChannel), 3000); + case LONGS -> new CountDistinctLongAggregatorFunctionSupplier(3000); + case DOUBLES -> new CountDistinctDoubleAggregatorFunctionSupplier(3000); default -> throw new IllegalArgumentException("unsupported data type [" + dataType + "]"); }; case MAX -> switch (dataType) { - case LONGS -> new MaxLongAggregatorFunctionSupplier(List.of(dataChannel)); - case DOUBLES -> new MaxDoubleAggregatorFunctionSupplier(List.of(dataChannel)); + case LONGS -> new MaxLongAggregatorFunctionSupplier(); + case DOUBLES -> new MaxDoubleAggregatorFunctionSupplier(); default -> throw new IllegalArgumentException("unsupported data type [" + dataType + "]"); }; case MIN -> switch (dataType) { - case LONGS -> new MinLongAggregatorFunctionSupplier(List.of(dataChannel)); - case DOUBLES -> new MinDoubleAggregatorFunctionSupplier(List.of(dataChannel)); + case LONGS -> new MinLongAggregatorFunctionSupplier(); + case DOUBLES -> new MinDoubleAggregatorFunctionSupplier(); default -> throw new IllegalArgumentException("unsupported data type [" + dataType + "]"); }; case SUM -> switch (dataType) { - case LONGS -> new SumLongAggregatorFunctionSupplier(List.of(dataChannel)); - case DOUBLES -> new SumDoubleAggregatorFunctionSupplier(List.of(dataChannel)); + case LONGS -> new SumLongAggregatorFunctionSupplier(); + case DOUBLES -> new SumDoubleAggregatorFunctionSupplier(); default -> throw new IllegalArgumentException("unsupported data type [" + dataType + "]"); }; default -> throw new IllegalArgumentException("unsupported op [" + op + "]"); diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DockerBase.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DockerBase.java index 59723823e925..d461a1bfae61 100644 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DockerBase.java +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DockerBase.java @@ -22,7 +22,7 @@ public enum DockerBase { // Chainguard based wolfi image with latest jdk // This is usually updated via renovatebot // spotless:off - WOLFI("docker.elastic.co/wolfi/chainguard-base:latest@sha256:bd401704a162a7937cd1015f755ca9da9aba0fdf967fc6bf90bf8d3f6b2eb557", + WOLFI("docker.elastic.co/wolfi/chainguard-base:latest@sha256:ecd940be9f342ee6173397c48f3df5bb410e95000f8726fd01759b6c39b0beda", "-wolfi", "apk" ), diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchJavaBasePlugin.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchJavaBasePlugin.java index ee0eb3f6eb2b..ce779343dfea 100644 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchJavaBasePlugin.java +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchJavaBasePlugin.java @@ -58,7 +58,6 @@ public class ElasticsearchJavaBasePlugin implements Plugin { @Override public void apply(Project project) { - project.getRootProject().getPlugins().apply(GlobalBuildInfoPlugin.class); // make sure the global build info plugin is applied to the root project project.getRootProject().getPluginManager().apply(GlobalBuildInfoPlugin.class); buildParams = project.getRootProject().getExtensions().getByType(BuildParameterExtension.class); diff --git a/client/test/build.gradle b/client/test/build.gradle index e39b7587b69d..3b7f62fd8ef5 100644 --- a/client/test/build.gradle +++ b/client/test/build.gradle @@ -28,9 +28,9 @@ dependencies { api "org.hamcrest:hamcrest:${versions.hamcrest}" // mockito - api 'org.mockito:mockito-core:5.11.0' - api 'org.mockito:mockito-subclass:5.11.0' - api 'net.bytebuddy:byte-buddy:1.14.12' + api 'org.mockito:mockito-core:5.15.2' + api 'org.mockito:mockito-subclass:5.15.2' + api 'net.bytebuddy:byte-buddy:1.15.11' api 'org.objenesis:objenesis:3.3' } diff --git a/docs/changelog/117201.yaml b/docs/changelog/117201.yaml deleted file mode 100644 index f8a2be35c70a..000000000000 --- a/docs/changelog/117201.yaml +++ /dev/null @@ -1,6 +0,0 @@ -pr: 117201 -summary: "Use `field_caps` native nested fields filtering" -area: ES|QL -type: bug -issues: - - 117054 diff --git a/docs/changelog/117504.yaml b/docs/changelog/117504.yaml deleted file mode 100644 index 91a62c61b88f..000000000000 --- a/docs/changelog/117504.yaml +++ /dev/null @@ -1,6 +0,0 @@ -pr: 117504 -summary: Fix NPE caused by race condition in async search when minimise round trips - is true -area: Search -type: bug -issues: [] diff --git a/docs/changelog/119748.yaml b/docs/changelog/119748.yaml deleted file mode 100644 index 8b29fb7c1a64..000000000000 --- a/docs/changelog/119748.yaml +++ /dev/null @@ -1,6 +0,0 @@ -pr: 119748 -summary: Issue S3 web identity token refresh call with sufficient permissions -area: Snapshot/Restore -type: bug -issues: - - 119747 diff --git a/docs/changelog/120014.yaml b/docs/changelog/120014.yaml deleted file mode 100644 index bef1f3ba4993..000000000000 --- a/docs/changelog/120014.yaml +++ /dev/null @@ -1,6 +0,0 @@ -pr: 120014 -summary: Fix potential file leak in ES816BinaryQuantizedVectorsWriter -area: Search -type: bug -issues: - - 119981 diff --git a/docs/changelog/120062.yaml b/docs/changelog/120062.yaml deleted file mode 100644 index 42e8d97f1744..000000000000 --- a/docs/changelog/120062.yaml +++ /dev/null @@ -1,6 +0,0 @@ -pr: 120062 -summary: Update Text Similarity Reranker to Properly Handle Aliases -area: Ranking -type: bug -issues: - - 119617 diff --git a/docs/changelog/120133.yaml b/docs/changelog/120133.yaml deleted file mode 100644 index 4ec88267a1bf..000000000000 --- a/docs/changelog/120133.yaml +++ /dev/null @@ -1,6 +0,0 @@ -pr: 120133 -summary: Use approximation to advance matched queries -area: Search -type: bug -issues: - - 120130 diff --git a/docs/changelog/120256.yaml b/docs/changelog/120256.yaml deleted file mode 100644 index c4ee5ab1705c..000000000000 --- a/docs/changelog/120256.yaml +++ /dev/null @@ -1,7 +0,0 @@ -pr: 120256 -summary: Improve memory aspects of enrich cache -area: Ingest Node -type: enhancement -issues: - - 96050 - - 120021 diff --git a/docs/changelog/120355.yaml b/docs/changelog/120355.yaml new file mode 100644 index 000000000000..fd335fe1f589 --- /dev/null +++ b/docs/changelog/120355.yaml @@ -0,0 +1,5 @@ +pr: 120355 +summary: Ensure cluster string could be quoted +area: ES|QL +type: enhancement +issues: [] diff --git a/docs/changelog/120483.yaml b/docs/changelog/120483.yaml deleted file mode 100644 index 20da3b9ab4e8..000000000000 --- a/docs/changelog/120483.yaml +++ /dev/null @@ -1,5 +0,0 @@ -pr: 120483 -summary: Fix NPE on disabled API auth key cache -area: Authentication -type: bug -issues: [] diff --git a/docs/changelog/120590.yaml b/docs/changelog/120590.yaml deleted file mode 100644 index 56abe44fbce1..000000000000 --- a/docs/changelog/120590.yaml +++ /dev/null @@ -1,5 +0,0 @@ -pr: 120590 -summary: Map `scope.name` as a dimension -area: Data streams -type: bug -issues: [] diff --git a/docs/changelog/120717.yaml b/docs/changelog/120717.yaml deleted file mode 100644 index c5609e7e3df5..000000000000 --- a/docs/changelog/120717.yaml +++ /dev/null @@ -1,6 +0,0 @@ -pr: 120717 -summary: Fix LTR rescorer throws 'local model reference is null' on multi-shards index when explained is enabled -area: Ranking -type: bug -issues: - - 120739 diff --git a/docs/changelog/120781.yaml b/docs/changelog/120781.yaml deleted file mode 100644 index 67c7d90528d6..000000000000 --- a/docs/changelog/120781.yaml +++ /dev/null @@ -1,5 +0,0 @@ -pr: 120781 -summary: Add back `keep_alive` to `async_search.submit` rest-api-spec -area: Search -type: bug -issues: [] diff --git a/docs/changelog/120809.yaml b/docs/changelog/120809.yaml deleted file mode 100644 index 30a3736dc93a..000000000000 --- a/docs/changelog/120809.yaml +++ /dev/null @@ -1,6 +0,0 @@ -pr: 120809 -summary: LTR sometines throw `NullPointerException:` Cannot read field "approximation" - because "top" is null -area: Ranking -type: bug -issues: [] diff --git a/docs/changelog/120930.yaml b/docs/changelog/120930.yaml deleted file mode 100644 index 376edb7632a0..000000000000 --- a/docs/changelog/120930.yaml +++ /dev/null @@ -1,6 +0,0 @@ -pr: 120930 -summary: Normalize negative scores for `text_similarity_reranker` retriever -area: Ranking -type: bug -issues: - - 120201 diff --git a/docs/changelog/120998.yaml b/docs/changelog/120998.yaml new file mode 100644 index 000000000000..4d9a3aa3eb1c --- /dev/null +++ b/docs/changelog/120998.yaml @@ -0,0 +1,5 @@ +pr: 120998 +summary: ES|QL `change_point` processing command +area: Machine Learning +type: feature +issues: [] diff --git a/docs/changelog/121119.yaml b/docs/changelog/121119.yaml deleted file mode 100644 index ad05011affbb..000000000000 --- a/docs/changelog/121119.yaml +++ /dev/null @@ -1,5 +0,0 @@ -pr: 121119 -summary: Revert "Reduce Data Loss in System Indices Migration" -area: Infra/Core -type: bug -issues: [] diff --git a/docs/changelog/121156.yaml b/docs/changelog/121156.yaml new file mode 100644 index 000000000000..8f9c5ccdb38c --- /dev/null +++ b/docs/changelog/121156.yaml @@ -0,0 +1,5 @@ +pr: 121156 +summary: Remove redundant sorts from execution plan +area: ES|QL +type: bug +issues: [] diff --git a/docs/changelog/121196.yaml b/docs/changelog/121196.yaml new file mode 100644 index 000000000000..f5168b1ea436 --- /dev/null +++ b/docs/changelog/121196.yaml @@ -0,0 +1,5 @@ +pr: 121196 +summary: Fix geoip databases index access after system feature migration +area: Ingest Node +type: bug +issues: [] diff --git a/docs/changelog/121231.yaml b/docs/changelog/121231.yaml deleted file mode 100644 index bd9eb934c8d0..000000000000 --- a/docs/changelog/121231.yaml +++ /dev/null @@ -1,6 +0,0 @@ -pr: 121231 -summary: Fix inference update API calls with `task_type` in body or `deployment_id` - defined -area: Machine Learning -type: bug -issues: [] diff --git a/docs/changelog/121283.yaml b/docs/changelog/121283.yaml deleted file mode 100644 index 56fb62acdb5f..000000000000 --- a/docs/changelog/121283.yaml +++ /dev/null @@ -1,5 +0,0 @@ -pr: 121283 -summary: Cheaper snapshot-related `toString()` impls -area: Snapshot/Restore -type: bug -issues: [] diff --git a/docs/changelog/121327.yaml b/docs/changelog/121327.yaml new file mode 100644 index 000000000000..fc684ea504f3 --- /dev/null +++ b/docs/changelog/121327.yaml @@ -0,0 +1,5 @@ +pr: 121327 +summary: Reduce Data Loss in System Indices Migration +area: Infra/Core +type: bug +issues: [] diff --git a/docs/changelog/121428.yaml b/docs/changelog/121428.yaml deleted file mode 100644 index b0a31b239961..000000000000 --- a/docs/changelog/121428.yaml +++ /dev/null @@ -1,6 +0,0 @@ -pr: 121428 -summary: Fix infer on and elasticsearch service endpoint created with a deployment - id -area: Machine Learning -type: bug -issues: [] diff --git a/docs/changelog/121559.yaml b/docs/changelog/121559.yaml deleted file mode 100644 index e3870609a454..000000000000 --- a/docs/changelog/121559.yaml +++ /dev/null @@ -1,6 +0,0 @@ -pr: 121559 -summary: Skip Usage stats update when ML is disabled -area: Machine Learning -type: bug -issues: - - 121532 diff --git a/docs/changelog/121667.yaml b/docs/changelog/121667.yaml new file mode 100644 index 000000000000..2467036832a3 --- /dev/null +++ b/docs/changelog/121667.yaml @@ -0,0 +1,11 @@ +pr: 121667 +summary: Add deprecation warning for flush API +area: Machine Learning +type: deprecation +issues: + - 121506 +deprecation: + title: Add deprecation warning for flush API + area: REST API + details: The anomaly detection job flush API is deprecated since it is only required for the post data API, which was deprecated since 7.11.0. + impact: This should have a minimal impact on users as the flush API is only required for the post data API, which was deprecated since 7.11.0. diff --git a/docs/changelog/121715.yaml b/docs/changelog/121715.yaml deleted file mode 100644 index 837bae57b4c9..000000000000 --- a/docs/changelog/121715.yaml +++ /dev/null @@ -1,5 +0,0 @@ -pr: 121715 -summary: Fix synthetic source issue with deeply nested ignored source fields -area: Mapping -type: bug -issues: [] diff --git a/docs/changelog/121720.yaml b/docs/changelog/121720.yaml new file mode 100644 index 000000000000..40dcfaeb770d --- /dev/null +++ b/docs/changelog/121720.yaml @@ -0,0 +1,5 @@ +pr: 121720 +summary: Skip fetching _inference_fields field in legacy semantic_text format +area: Search +type: bug +issues: [] diff --git a/docs/changelog/121731.yaml b/docs/changelog/121731.yaml new file mode 100644 index 000000000000..9fc117610a49 --- /dev/null +++ b/docs/changelog/121731.yaml @@ -0,0 +1,21 @@ +pr: 121731 +summary: Remove TLSv1.1 from default protocols +area: TLS +type: breaking +issues: [] +breaking: + title: Remove TLSv1.1 from default protocols + area: Cluster and node setting + details: "TLSv1.1 is no longer enabled by default. Prior to version 9.0, Elasticsearch\ + \ would attempt to enable TLSv1.1 if the JDK supported it. In most cases, including\ + \ all cases where Elasticsearch 8 was running with the bundled JDK, the JDK would\ + \ not support TLSv1.1, so that protocol would not be available in Elasticsearch.\ + \ However, if Elasticsearch was running on an old JDK or a JDK that have been\ + \ reconfigured to support TLSv1.1, then the protocol would automatically be available\ + \ within Elasticsearch. As of Elasticsearch 9.0, this is no longer true. If you\ + \ wish to enable TLSv1.1 then you must enable it within the JDK and also enable\ + \ it within Elasticsearch by using the `ssl.supported_protocols` setting." + impact: "Most users will not be impacted. If your Elastisearch 8 cluster was using\ + \ a custom JDK and you relied on TLSv1.1, then you will need to explicitly enable\ + \ TLSv1.1 within Elasticsearch (as well as enabling it within your JDK)" + notable: false diff --git a/docs/changelog/121805.yaml b/docs/changelog/121805.yaml new file mode 100644 index 000000000000..7d0f3a96221a --- /dev/null +++ b/docs/changelog/121805.yaml @@ -0,0 +1,5 @@ +pr: 121805 +summary: Support subset of metrics in aggregate metric double +area: "ES|QL" +type: enhancement +issues: [] diff --git a/docs/changelog/121821.yaml b/docs/changelog/121821.yaml new file mode 100644 index 000000000000..1e8edd09dcd9 --- /dev/null +++ b/docs/changelog/121821.yaml @@ -0,0 +1,6 @@ +pr: 121821 +summary: Fix get all inference endponts not returning multiple endpoints sharing model + deployment +area: Machine Learning +type: bug +issues: [] diff --git a/docs/changelog/121843.yaml b/docs/changelog/121843.yaml new file mode 100644 index 000000000000..85b19e317a09 --- /dev/null +++ b/docs/changelog/121843.yaml @@ -0,0 +1,6 @@ +pr: 121843 +summary: Fix async stop sometimes not properly collecting result +area: ES|QL +type: bug +issues: + - 121249 diff --git a/docs/changelog/121850.yaml b/docs/changelog/121850.yaml new file mode 100644 index 000000000000..b6c5ba2e03fe --- /dev/null +++ b/docs/changelog/121850.yaml @@ -0,0 +1,5 @@ +pr: 121850 +summary: Take named parameters for identifier and pattern out of snapshot +area: ES|QL +type: enhancement +issues: [] diff --git a/docs/changelog/121911.yaml b/docs/changelog/121911.yaml new file mode 100644 index 000000000000..d30e96abc21c --- /dev/null +++ b/docs/changelog/121911.yaml @@ -0,0 +1,5 @@ +pr: 121911 +summary: Fix ENRICH validation for use of wildcards +area: ES|QL +type: bug +issues: [] diff --git a/docs/changelog/122011.yaml b/docs/changelog/122011.yaml new file mode 100644 index 000000000000..2cc9a37b0161 --- /dev/null +++ b/docs/changelog/122011.yaml @@ -0,0 +1,5 @@ +pr: 122011 +summary: Fix JOIN command validation (not supported) +area: EQL +type: bug +issues: [] diff --git a/docs/changelog/122246.yaml b/docs/changelog/122246.yaml new file mode 100644 index 000000000000..c1e90f342311 --- /dev/null +++ b/docs/changelog/122246.yaml @@ -0,0 +1,5 @@ +pr: 122246 +summary: Ensure removal of index blocks does not leave key with null value +area: Data streams +type: bug +issues: [] diff --git a/docs/changelog/122278.yaml b/docs/changelog/122278.yaml new file mode 100644 index 000000000000..529d17c729c7 --- /dev/null +++ b/docs/changelog/122278.yaml @@ -0,0 +1,5 @@ +pr: 122278 +summary: Fix serialising the inference update request +area: Machine Learning +type: bug +issues: [] diff --git a/docs/reference/esql/functions/kibana/definition/abs.json b/docs/reference/esql/functions/kibana/definition/abs.json index e875d8200715..888ebf638640 100644 --- a/docs/reference/esql/functions/kibana/definition/abs.json +++ b/docs/reference/esql/functions/kibana/definition/abs.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "abs", "description" : "Returns the absolute value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/acos.json b/docs/reference/esql/functions/kibana/definition/acos.json index f86b1a5552a6..5b6a5b023f48 100644 --- a/docs/reference/esql/functions/kibana/definition/acos.json +++ b/docs/reference/esql/functions/kibana/definition/acos.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "acos", "description" : "Returns the arccosine of `n` as an angle, expressed in radians.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/asin.json b/docs/reference/esql/functions/kibana/definition/asin.json index 4063ffcba614..293a66a21ab2 100644 --- a/docs/reference/esql/functions/kibana/definition/asin.json +++ b/docs/reference/esql/functions/kibana/definition/asin.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "asin", "description" : "Returns the arcsine of the input\nnumeric expression as an angle, expressed in radians.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/atan.json b/docs/reference/esql/functions/kibana/definition/atan.json index 1b2a3a1860bc..afa380ca1d7f 100644 --- a/docs/reference/esql/functions/kibana/definition/atan.json +++ b/docs/reference/esql/functions/kibana/definition/atan.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "atan", "description" : "Returns the arctangent of the input\nnumeric expression as an angle, expressed in radians.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/atan2.json b/docs/reference/esql/functions/kibana/definition/atan2.json index 9b67c07d8d73..8e12198cb60e 100644 --- a/docs/reference/esql/functions/kibana/definition/atan2.json +++ b/docs/reference/esql/functions/kibana/definition/atan2.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "atan2", "description" : "The angle between the positive x-axis and the ray from the\norigin to the point (x , y) in the Cartesian plane, expressed in radians.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/bit_length.json b/docs/reference/esql/functions/kibana/definition/bit_length.json index 0c75b76cdbbf..25a032044ec9 100644 --- a/docs/reference/esql/functions/kibana/definition/bit_length.json +++ b/docs/reference/esql/functions/kibana/definition/bit_length.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "bit_length", "description" : "Returns the bit length of a string.", "note" : "All strings are in UTF-8, so a single character can use multiple bytes.", diff --git a/docs/reference/esql/functions/kibana/definition/bucket.json b/docs/reference/esql/functions/kibana/definition/bucket.json index f9c7f2f27d6f..990f102bac16 100644 --- a/docs/reference/esql/functions/kibana/definition/bucket.json +++ b/docs/reference/esql/functions/kibana/definition/bucket.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "grouping", "name" : "bucket", "description" : "Creates groups of values - buckets - out of a datetime or numeric input.\nThe size of the buckets can either be provided directly, or chosen based on a recommended count and values range.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/byte_length.json b/docs/reference/esql/functions/kibana/definition/byte_length.json index 60f439b9d813..6d1a91813221 100644 --- a/docs/reference/esql/functions/kibana/definition/byte_length.json +++ b/docs/reference/esql/functions/kibana/definition/byte_length.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "byte_length", "description" : "Returns the byte length of a string.", "note" : "All strings are in UTF-8, so a single character can use multiple bytes.", diff --git a/docs/reference/esql/functions/kibana/definition/case.json b/docs/reference/esql/functions/kibana/definition/case.json index 51693d9d3066..4e2d4187712e 100644 --- a/docs/reference/esql/functions/kibana/definition/case.json +++ b/docs/reference/esql/functions/kibana/definition/case.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "case", "description" : "Accepts pairs of conditions and values. The function returns the value that\nbelongs to the first condition that evaluates to `true`.\n\nIf the number of arguments is odd, the last argument is the default value which\nis returned when no condition matches. If the number of arguments is even, and\nno condition matches, the function returns `null`.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/categorize.json b/docs/reference/esql/functions/kibana/definition/categorize.json index ed5fa15232b8..1b7f20405756 100644 --- a/docs/reference/esql/functions/kibana/definition/categorize.json +++ b/docs/reference/esql/functions/kibana/definition/categorize.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "grouping", "name" : "categorize", "description" : "Groups text messages into categories of similarly formatted text values.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/cbrt.json b/docs/reference/esql/functions/kibana/definition/cbrt.json index ce23551f75e5..f146a864929a 100644 --- a/docs/reference/esql/functions/kibana/definition/cbrt.json +++ b/docs/reference/esql/functions/kibana/definition/cbrt.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "cbrt", "description" : "Returns the cube root of a number. The input can be any numeric value, the return value is always a double.\nCube roots of infinities are null.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/ceil.json b/docs/reference/esql/functions/kibana/definition/ceil.json index 15e7bafd1fa5..4a9e24e9094e 100644 --- a/docs/reference/esql/functions/kibana/definition/ceil.json +++ b/docs/reference/esql/functions/kibana/definition/ceil.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "ceil", "description" : "Round a number up to the nearest integer.", "note" : "This is a noop for `long` (including unsigned) and `integer`. For `double` this picks the closest `double` value to the integer similar to Math.ceil.", diff --git a/docs/reference/esql/functions/kibana/definition/cidr_match.json b/docs/reference/esql/functions/kibana/definition/cidr_match.json index dc5d6773f69e..9e988623c0fd 100644 --- a/docs/reference/esql/functions/kibana/definition/cidr_match.json +++ b/docs/reference/esql/functions/kibana/definition/cidr_match.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "cidr_match", "description" : "Returns true if the provided IP is contained in one of the provided CIDR blocks.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/coalesce.json b/docs/reference/esql/functions/kibana/definition/coalesce.json index c929323397c9..a507aea3fd0d 100644 --- a/docs/reference/esql/functions/kibana/definition/coalesce.json +++ b/docs/reference/esql/functions/kibana/definition/coalesce.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "coalesce", "description" : "Returns the first of its arguments that is not null. If all arguments are null, it returns `null`.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/concat.json b/docs/reference/esql/functions/kibana/definition/concat.json index d3e9f0852bc1..b41ebba40b58 100644 --- a/docs/reference/esql/functions/kibana/definition/concat.json +++ b/docs/reference/esql/functions/kibana/definition/concat.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "concat", "description" : "Concatenates two or more strings.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/cos.json b/docs/reference/esql/functions/kibana/definition/cos.json index 1b9ca2f1d486..8922dd6db555 100644 --- a/docs/reference/esql/functions/kibana/definition/cos.json +++ b/docs/reference/esql/functions/kibana/definition/cos.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "cos", "description" : "Returns the cosine of an angle.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/cosh.json b/docs/reference/esql/functions/kibana/definition/cosh.json index 77d9853d34e4..458f4ecf0455 100644 --- a/docs/reference/esql/functions/kibana/definition/cosh.json +++ b/docs/reference/esql/functions/kibana/definition/cosh.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "cosh", "description" : "Returns the hyperbolic cosine of a number.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/date_diff.json b/docs/reference/esql/functions/kibana/definition/date_diff.json index 2738ec839022..dab7f7e0ef2e 100644 --- a/docs/reference/esql/functions/kibana/definition/date_diff.json +++ b/docs/reference/esql/functions/kibana/definition/date_diff.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "date_diff", "description" : "Subtracts the `startTimestamp` from the `endTimestamp` and returns the difference in multiples of `unit`.\nIf `startTimestamp` is later than the `endTimestamp`, negative values are returned.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/date_extract.json b/docs/reference/esql/functions/kibana/definition/date_extract.json index 0ababf80d913..1778d99dcf34 100644 --- a/docs/reference/esql/functions/kibana/definition/date_extract.json +++ b/docs/reference/esql/functions/kibana/definition/date_extract.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "date_extract", "description" : "Extracts parts of a date, like year, month, day, hour.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/date_format.json b/docs/reference/esql/functions/kibana/definition/date_format.json index f6f48e9df82b..633e20444d77 100644 --- a/docs/reference/esql/functions/kibana/definition/date_format.json +++ b/docs/reference/esql/functions/kibana/definition/date_format.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "date_format", "description" : "Returns a string representation of a date, in the provided format.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/date_parse.json b/docs/reference/esql/functions/kibana/definition/date_parse.json index 77247b332c6f..8e2f15efce82 100644 --- a/docs/reference/esql/functions/kibana/definition/date_parse.json +++ b/docs/reference/esql/functions/kibana/definition/date_parse.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "date_parse", "description" : "Returns a date by parsing the second argument using the format specified in the first argument.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/date_trunc.json b/docs/reference/esql/functions/kibana/definition/date_trunc.json index cdda984a0ce7..023298d0f8b5 100644 --- a/docs/reference/esql/functions/kibana/definition/date_trunc.json +++ b/docs/reference/esql/functions/kibana/definition/date_trunc.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "date_trunc", "description" : "Rounds down a date to the closest interval.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/e.json b/docs/reference/esql/functions/kibana/definition/e.json index e5941b50c00a..15bcb0572e2a 100644 --- a/docs/reference/esql/functions/kibana/definition/e.json +++ b/docs/reference/esql/functions/kibana/definition/e.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "e", "description" : "Returns Euler's number.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/ends_with.json b/docs/reference/esql/functions/kibana/definition/ends_with.json index 5c2f721c3344..eb2e0268214a 100644 --- a/docs/reference/esql/functions/kibana/definition/ends_with.json +++ b/docs/reference/esql/functions/kibana/definition/ends_with.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "ends_with", "description" : "Returns a boolean that indicates whether a keyword string ends with another string.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/exp.json b/docs/reference/esql/functions/kibana/definition/exp.json index 4df40ce467d8..186cde72c799 100644 --- a/docs/reference/esql/functions/kibana/definition/exp.json +++ b/docs/reference/esql/functions/kibana/definition/exp.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "exp", "description" : "Returns the value of e raised to the power of the given number.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/floor.json b/docs/reference/esql/functions/kibana/definition/floor.json index 1d1c961bfe2b..6e2deb3dce56 100644 --- a/docs/reference/esql/functions/kibana/definition/floor.json +++ b/docs/reference/esql/functions/kibana/definition/floor.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "floor", "description" : "Round a number down to the nearest integer.", "note" : "This is a noop for `long` (including unsigned) and `integer`.\nFor `double` this picks the closest `double` value to the integer\nsimilar to Math.floor.", diff --git a/docs/reference/esql/functions/kibana/definition/from_base64.json b/docs/reference/esql/functions/kibana/definition/from_base64.json index 7580b817031a..a94f4a338cb0 100644 --- a/docs/reference/esql/functions/kibana/definition/from_base64.json +++ b/docs/reference/esql/functions/kibana/definition/from_base64.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "from_base64", "description" : "Decode a base64 string.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/greatest.json b/docs/reference/esql/functions/kibana/definition/greatest.json index 077100317dfc..af78ca3d02b5 100644 --- a/docs/reference/esql/functions/kibana/definition/greatest.json +++ b/docs/reference/esql/functions/kibana/definition/greatest.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "greatest", "description" : "Returns the maximum value from multiple columns. This is similar to <>\nexcept it is intended to run on multiple columns at once.", "note" : "When run on `keyword` or `text` fields, this returns the last string in alphabetical order. When run on `boolean` columns this will return `true` if any values are `true`.", diff --git a/docs/reference/esql/functions/kibana/definition/hash.json b/docs/reference/esql/functions/kibana/definition/hash.json index dbf4a2542afc..93ee99bf3e9c 100644 --- a/docs/reference/esql/functions/kibana/definition/hash.json +++ b/docs/reference/esql/functions/kibana/definition/hash.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "hash", "description" : "Computes the hash of the input using various algorithms such as MD5, SHA, SHA-224, SHA-256, SHA-384, SHA-512.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/hypot.json b/docs/reference/esql/functions/kibana/definition/hypot.json index 06971f07a358..a71f318a286b 100644 --- a/docs/reference/esql/functions/kibana/definition/hypot.json +++ b/docs/reference/esql/functions/kibana/definition/hypot.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "hypot", "description" : "Returns the hypotenuse of two numbers. The input can be any numeric values, the return value is always a double.\nHypotenuses of infinities are null.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/ip_prefix.json b/docs/reference/esql/functions/kibana/definition/ip_prefix.json index bbf0702b325e..0d039a784a7b 100644 --- a/docs/reference/esql/functions/kibana/definition/ip_prefix.json +++ b/docs/reference/esql/functions/kibana/definition/ip_prefix.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "ip_prefix", "description" : "Truncates an IP to a given prefix length.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/kql.json b/docs/reference/esql/functions/kibana/definition/kql.json index f10a06b91600..ff0f854f20fa 100644 --- a/docs/reference/esql/functions/kibana/definition/kql.json +++ b/docs/reference/esql/functions/kibana/definition/kql.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "kql", "description" : "Performs a KQL query. Returns true if the provided KQL query string matches the row.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/least.json b/docs/reference/esql/functions/kibana/definition/least.json index 18ec65c60f47..30f27b9be0b0 100644 --- a/docs/reference/esql/functions/kibana/definition/least.json +++ b/docs/reference/esql/functions/kibana/definition/least.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "least", "description" : "Returns the minimum value from multiple columns. This is similar to <> except it is intended to run on multiple columns at once.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/left.json b/docs/reference/esql/functions/kibana/definition/left.json index 9e226d6cde59..b367dc9655ec 100644 --- a/docs/reference/esql/functions/kibana/definition/left.json +++ b/docs/reference/esql/functions/kibana/definition/left.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "left", "description" : "Returns the substring that extracts 'length' chars from 'string' starting from the left.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/length.json b/docs/reference/esql/functions/kibana/definition/length.json index bc26acde744f..c2eca63e4e1d 100644 --- a/docs/reference/esql/functions/kibana/definition/length.json +++ b/docs/reference/esql/functions/kibana/definition/length.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "length", "description" : "Returns the character length of a string.", "note" : "All strings are in UTF-8, so a single character can use multiple bytes.", diff --git a/docs/reference/esql/functions/kibana/definition/locate.json b/docs/reference/esql/functions/kibana/definition/locate.json index 6278cb5e33a0..0322ec1945aa 100644 --- a/docs/reference/esql/functions/kibana/definition/locate.json +++ b/docs/reference/esql/functions/kibana/definition/locate.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "locate", "description" : "Returns an integer that indicates the position of a keyword substring within another string.\nReturns `0` if the substring cannot be found.\nNote that string positions start from `1`.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/log.json b/docs/reference/esql/functions/kibana/definition/log.json index 369503c1b8e4..c75349a89630 100644 --- a/docs/reference/esql/functions/kibana/definition/log.json +++ b/docs/reference/esql/functions/kibana/definition/log.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "log", "description" : "Returns the logarithm of a value to a base. The input can be any numeric value, the return value is always a double.\n\nLogs of zero, negative numbers, and base of one return `null` as well as a warning.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/log10.json b/docs/reference/esql/functions/kibana/definition/log10.json index a958e5caec8a..6cc089ae49c4 100644 --- a/docs/reference/esql/functions/kibana/definition/log10.json +++ b/docs/reference/esql/functions/kibana/definition/log10.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "log10", "description" : "Returns the logarithm of a value to base 10. The input can be any numeric value, the return value is always a double.\n\nLogs of 0 and negative numbers return `null` as well as a warning.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/ltrim.json b/docs/reference/esql/functions/kibana/definition/ltrim.json index 6d992b9db7b2..f0a58dd4f9ae 100644 --- a/docs/reference/esql/functions/kibana/definition/ltrim.json +++ b/docs/reference/esql/functions/kibana/definition/ltrim.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "ltrim", "description" : "Removes leading whitespaces from a string.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/match.json b/docs/reference/esql/functions/kibana/definition/match.json index 730588038ec5..4844382fe04c 100644 --- a/docs/reference/esql/functions/kibana/definition/match.json +++ b/docs/reference/esql/functions/kibana/definition/match.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "match", "description" : "Use `MATCH` to perform a <> on the specified field.\nUsing `MATCH` is equivalent to using the `match` query in the Elasticsearch Query DSL.\n\nMatch can be used on fields from the text family like <> and <>,\nas well as other field types like keyword, boolean, dates, and numeric types.\n\nMatch can use <> to specify additional options for the match query.\nAll <> are supported.\n\nFor a simplified syntax, you can use the <> `:` operator instead of `MATCH`.\n\n`MATCH` returns true if the provided query matches the row.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/md5.json b/docs/reference/esql/functions/kibana/definition/md5.json index 4d3a88e123ff..b631f7816cb5 100644 --- a/docs/reference/esql/functions/kibana/definition/md5.json +++ b/docs/reference/esql/functions/kibana/definition/md5.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "md5", "description" : "Computes the MD5 hash of the input.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_append.json b/docs/reference/esql/functions/kibana/definition/mv_append.json index 043625d9ea1e..7cbcc678464c 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_append.json +++ b/docs/reference/esql/functions/kibana/definition/mv_append.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_append", "description" : "Concatenates values of two multi-value fields.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_avg.json b/docs/reference/esql/functions/kibana/definition/mv_avg.json index a25d38c909e6..65a32cba133e 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_avg.json +++ b/docs/reference/esql/functions/kibana/definition/mv_avg.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_avg", "description" : "Converts a multivalued field into a single valued field containing the average of all of the values.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_concat.json b/docs/reference/esql/functions/kibana/definition/mv_concat.json index 88b1107a9f40..6855525abfba 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_concat.json +++ b/docs/reference/esql/functions/kibana/definition/mv_concat.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_concat", "description" : "Converts a multivalued string expression into a single valued column containing the concatenation of all values separated by a delimiter.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_count.json b/docs/reference/esql/functions/kibana/definition/mv_count.json index 90ace2525f71..b82b7b382409 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_count.json +++ b/docs/reference/esql/functions/kibana/definition/mv_count.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_count", "description" : "Converts a multivalued expression into a single valued column containing a count of the number of values.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_dedupe.json b/docs/reference/esql/functions/kibana/definition/mv_dedupe.json index 2fb5b9c61727..fbce83189ef2 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_dedupe.json +++ b/docs/reference/esql/functions/kibana/definition/mv_dedupe.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_dedupe", "description" : "Remove duplicate values from a multivalued field.", "note" : "`MV_DEDUPE` may, but won't always, sort the values in the column.", diff --git a/docs/reference/esql/functions/kibana/definition/mv_first.json b/docs/reference/esql/functions/kibana/definition/mv_first.json index 552f568c9b17..32525a7c124f 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_first.json +++ b/docs/reference/esql/functions/kibana/definition/mv_first.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_first", "description" : "Converts a multivalued expression into a single valued column containing the\nfirst value. This is most useful when reading from a function that emits\nmultivalued columns in a known order like <>.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_last.json b/docs/reference/esql/functions/kibana/definition/mv_last.json index 78d7b348a604..f11482b69824 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_last.json +++ b/docs/reference/esql/functions/kibana/definition/mv_last.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_last", "description" : "Converts a multivalue expression into a single valued column containing the last\nvalue. This is most useful when reading from a function that emits multivalued\ncolumns in a known order like <>.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_max.json b/docs/reference/esql/functions/kibana/definition/mv_max.json index a1e55c58cff7..65b8d801edab 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_max.json +++ b/docs/reference/esql/functions/kibana/definition/mv_max.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_max", "description" : "Converts a multivalued expression into a single valued column containing the maximum value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_median.json b/docs/reference/esql/functions/kibana/definition/mv_median.json index fe95e1999f6a..3ba870023cb4 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_median.json +++ b/docs/reference/esql/functions/kibana/definition/mv_median.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_median", "description" : "Converts a multivalued field into a single valued field containing the median value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_median_absolute_deviation.json b/docs/reference/esql/functions/kibana/definition/mv_median_absolute_deviation.json index af16e9ab0d3b..e4beb343cd20 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_median_absolute_deviation.json +++ b/docs/reference/esql/functions/kibana/definition/mv_median_absolute_deviation.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_median_absolute_deviation", "description" : "Converts a multivalued field into a single valued field containing the median absolute deviation.\n\nIt is calculated as the median of each data point's deviation from the median of the entire sample. That is, for a random variable `X`, the median absolute deviation is `median(|median(X) - X|)`.", "note" : "If the field has an even number of values, the medians will be calculated as the average of the middle two values. If the value is not a floating point number, the averages are rounded towards 0.", diff --git a/docs/reference/esql/functions/kibana/definition/mv_min.json b/docs/reference/esql/functions/kibana/definition/mv_min.json index 7998ca4eda94..ef36cee912d5 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_min.json +++ b/docs/reference/esql/functions/kibana/definition/mv_min.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_min", "description" : "Converts a multivalued expression into a single valued column containing the minimum value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_percentile.json b/docs/reference/esql/functions/kibana/definition/mv_percentile.json index 8e4cec705f48..7835241ed68b 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_percentile.json +++ b/docs/reference/esql/functions/kibana/definition/mv_percentile.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_percentile", "description" : "Converts a multivalued field into a single valued field containing the value at which a certain percentage of observed values occur.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_pseries_weighted_sum.json b/docs/reference/esql/functions/kibana/definition/mv_pseries_weighted_sum.json index f96a6dfb5a43..7935afe3338e 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_pseries_weighted_sum.json +++ b/docs/reference/esql/functions/kibana/definition/mv_pseries_weighted_sum.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_pseries_weighted_sum", "description" : "Converts a multivalued expression into a single-valued column by multiplying every element on the input list by its corresponding term in P-Series and computing the sum.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_slice.json b/docs/reference/esql/functions/kibana/definition/mv_slice.json index 5ad8f588cdc2..f23c0d089d93 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_slice.json +++ b/docs/reference/esql/functions/kibana/definition/mv_slice.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_slice", "description" : "Returns a subset of the multivalued field using the start and end index values.\nThis is most useful when reading from a function that emits multivalued columns\nin a known order like <> or <>.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_sort.json b/docs/reference/esql/functions/kibana/definition/mv_sort.json index 072c05743af3..17a8fb426755 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_sort.json +++ b/docs/reference/esql/functions/kibana/definition/mv_sort.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_sort", "description" : "Sorts a multivalued field in lexicographical order.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_sum.json b/docs/reference/esql/functions/kibana/definition/mv_sum.json index 6ccbcec3c61b..31b0e5e420b7 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_sum.json +++ b/docs/reference/esql/functions/kibana/definition/mv_sum.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_sum", "description" : "Converts a multivalued field into a single valued field containing the sum of all of the values.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/mv_zip.json b/docs/reference/esql/functions/kibana/definition/mv_zip.json index e292cd27ee73..fc573834054b 100644 --- a/docs/reference/esql/functions/kibana/definition/mv_zip.json +++ b/docs/reference/esql/functions/kibana/definition/mv_zip.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "mv_zip", "description" : "Combines the values from two multivalued fields with a delimiter that joins them together.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/now.json b/docs/reference/esql/functions/kibana/definition/now.json index 26ef36299518..42831c2faf49 100644 --- a/docs/reference/esql/functions/kibana/definition/now.json +++ b/docs/reference/esql/functions/kibana/definition/now.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "now", "description" : "Returns current date and time.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/pi.json b/docs/reference/esql/functions/kibana/definition/pi.json index 98d9451a2b92..0dd720dd69cb 100644 --- a/docs/reference/esql/functions/kibana/definition/pi.json +++ b/docs/reference/esql/functions/kibana/definition/pi.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "pi", "description" : "Returns Pi, the ratio of a circle's circumference to its diameter.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/pow.json b/docs/reference/esql/functions/kibana/definition/pow.json index 35fe080d82f7..93dda492f087 100644 --- a/docs/reference/esql/functions/kibana/definition/pow.json +++ b/docs/reference/esql/functions/kibana/definition/pow.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "pow", "description" : "Returns the value of `base` raised to the power of `exponent`.", "note" : "It is still possible to overflow a double result here; in that case, null will be returned.", diff --git a/docs/reference/esql/functions/kibana/definition/qstr.json b/docs/reference/esql/functions/kibana/definition/qstr.json index 3758ff693b3a..b617f9f9246c 100644 --- a/docs/reference/esql/functions/kibana/definition/qstr.json +++ b/docs/reference/esql/functions/kibana/definition/qstr.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "qstr", "description" : "Performs a <>. Returns true if the provided query string matches the row.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/repeat.json b/docs/reference/esql/functions/kibana/definition/repeat.json index 201484cf7aa6..2eb739f0d0bc 100644 --- a/docs/reference/esql/functions/kibana/definition/repeat.json +++ b/docs/reference/esql/functions/kibana/definition/repeat.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "repeat", "description" : "Returns a string constructed by concatenating `string` with itself the specified `number` of times.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/replace.json b/docs/reference/esql/functions/kibana/definition/replace.json index b5d1a1af7e8f..b512019a9951 100644 --- a/docs/reference/esql/functions/kibana/definition/replace.json +++ b/docs/reference/esql/functions/kibana/definition/replace.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "replace", "description" : "The function substitutes in the string `str` any match of the regular expression `regex`\nwith the replacement string `newStr`.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/reverse.json b/docs/reference/esql/functions/kibana/definition/reverse.json index 0652d9cfa6b1..2ebf63fa5787 100644 --- a/docs/reference/esql/functions/kibana/definition/reverse.json +++ b/docs/reference/esql/functions/kibana/definition/reverse.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "reverse", "description" : "Returns a new string representing the input string in reverse order.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/right.json b/docs/reference/esql/functions/kibana/definition/right.json index 1211877a2f90..84408f082db5 100644 --- a/docs/reference/esql/functions/kibana/definition/right.json +++ b/docs/reference/esql/functions/kibana/definition/right.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "right", "description" : "Return the substring that extracts 'length' chars from 'str' starting from the right.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/round.json b/docs/reference/esql/functions/kibana/definition/round.json index 4ef20aa162b4..a364dbbed0b5 100644 --- a/docs/reference/esql/functions/kibana/definition/round.json +++ b/docs/reference/esql/functions/kibana/definition/round.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "round", "description" : "Rounds a number to the specified number of decimal places.\nDefaults to 0, which returns the nearest integer. If the\nprecision is a negative number, rounds to the number of digits left\nof the decimal point.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/rtrim.json b/docs/reference/esql/functions/kibana/definition/rtrim.json index 9c8a7578ed78..ef6c93f9fa17 100644 --- a/docs/reference/esql/functions/kibana/definition/rtrim.json +++ b/docs/reference/esql/functions/kibana/definition/rtrim.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "rtrim", "description" : "Removes trailing whitespaces from a string.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/sha1.json b/docs/reference/esql/functions/kibana/definition/sha1.json index a6abb31368bb..18fa2c33ae0d 100644 --- a/docs/reference/esql/functions/kibana/definition/sha1.json +++ b/docs/reference/esql/functions/kibana/definition/sha1.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "sha1", "description" : "Computes the SHA1 hash of the input.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/sha256.json b/docs/reference/esql/functions/kibana/definition/sha256.json index 700425d485b6..7ad0e2c5500d 100644 --- a/docs/reference/esql/functions/kibana/definition/sha256.json +++ b/docs/reference/esql/functions/kibana/definition/sha256.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "sha256", "description" : "Computes the SHA256 hash of the input.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/signum.json b/docs/reference/esql/functions/kibana/definition/signum.json index 0902826651ef..20667b8cb683 100644 --- a/docs/reference/esql/functions/kibana/definition/signum.json +++ b/docs/reference/esql/functions/kibana/definition/signum.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "signum", "description" : "Returns the sign of the given number.\nIt returns `-1` for negative numbers, `0` for `0` and `1` for positive numbers.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/sin.json b/docs/reference/esql/functions/kibana/definition/sin.json index 0d4f4e5c5cf1..efdf96a3b8d3 100644 --- a/docs/reference/esql/functions/kibana/definition/sin.json +++ b/docs/reference/esql/functions/kibana/definition/sin.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "sin", "description" : "Returns the sine of an angle.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/sinh.json b/docs/reference/esql/functions/kibana/definition/sinh.json index b20db3328775..3ed3eaa23c9c 100644 --- a/docs/reference/esql/functions/kibana/definition/sinh.json +++ b/docs/reference/esql/functions/kibana/definition/sinh.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "sinh", "description" : "Returns the hyperbolic sine of a number.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/space.json b/docs/reference/esql/functions/kibana/definition/space.json index 7a819d3ccd21..cc1223de2cdf 100644 --- a/docs/reference/esql/functions/kibana/definition/space.json +++ b/docs/reference/esql/functions/kibana/definition/space.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "space", "description" : "Returns a string made of `number` spaces.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/split.json b/docs/reference/esql/functions/kibana/definition/split.json index 862cf7a09f19..87a7b0a0f87c 100644 --- a/docs/reference/esql/functions/kibana/definition/split.json +++ b/docs/reference/esql/functions/kibana/definition/split.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "split", "description" : "Split a single valued string into multiple strings.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/sqrt.json b/docs/reference/esql/functions/kibana/definition/sqrt.json index 11620a465c45..6985cb20043c 100644 --- a/docs/reference/esql/functions/kibana/definition/sqrt.json +++ b/docs/reference/esql/functions/kibana/definition/sqrt.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "sqrt", "description" : "Returns the square root of a number. The input can be any numeric value, the return value is always a double.\nSquare roots of negative numbers and infinities are null.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/st_contains.json b/docs/reference/esql/functions/kibana/definition/st_contains.json index 0c1b61c56340..7d78518f91da 100644 --- a/docs/reference/esql/functions/kibana/definition/st_contains.json +++ b/docs/reference/esql/functions/kibana/definition/st_contains.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "st_contains", "description" : "Returns whether the first geometry contains the second geometry.\nThis is the inverse of the <> function.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/st_disjoint.json b/docs/reference/esql/functions/kibana/definition/st_disjoint.json index 0c4f6e7c36f5..f0da69103ea6 100644 --- a/docs/reference/esql/functions/kibana/definition/st_disjoint.json +++ b/docs/reference/esql/functions/kibana/definition/st_disjoint.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "st_disjoint", "description" : "Returns whether the two geometries or geometry columns are disjoint.\nThis is the inverse of the <> function.\nIn mathematical terms: ST_Disjoint(A, B) ⇔ A ⋂ B = ∅", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/st_distance.json b/docs/reference/esql/functions/kibana/definition/st_distance.json index 2fb8f341d12f..74492b6e3074 100644 --- a/docs/reference/esql/functions/kibana/definition/st_distance.json +++ b/docs/reference/esql/functions/kibana/definition/st_distance.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "st_distance", "description" : "Computes the distance between two points.\nFor cartesian geometries, this is the pythagorean distance in the same units as the original coordinates.\nFor geographic geometries, this is the circular distance along the great circle in meters.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/st_envelope.json b/docs/reference/esql/functions/kibana/definition/st_envelope.json index 6c00dda265ac..83f4bad5b826 100644 --- a/docs/reference/esql/functions/kibana/definition/st_envelope.json +++ b/docs/reference/esql/functions/kibana/definition/st_envelope.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "st_envelope", "description" : "Determines the minimum bounding box of the supplied geometry.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/st_intersects.json b/docs/reference/esql/functions/kibana/definition/st_intersects.json index 51237a0b1cee..b35df6711b33 100644 --- a/docs/reference/esql/functions/kibana/definition/st_intersects.json +++ b/docs/reference/esql/functions/kibana/definition/st_intersects.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "st_intersects", "description" : "Returns true if two geometries intersect.\nThey intersect if they have any point in common, including their interior points\n(points along lines or within polygons).\nThis is the inverse of the <> function.\nIn mathematical terms: ST_Intersects(A, B) ⇔ A ⋂ B ≠ ∅", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/st_within.json b/docs/reference/esql/functions/kibana/definition/st_within.json index d877cf4e8dfb..3ab419683f02 100644 --- a/docs/reference/esql/functions/kibana/definition/st_within.json +++ b/docs/reference/esql/functions/kibana/definition/st_within.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "st_within", "description" : "Returns whether the first geometry is within the second geometry.\nThis is the inverse of the <> function.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/st_x.json b/docs/reference/esql/functions/kibana/definition/st_x.json index f434f1467c0b..27378edd25ff 100644 --- a/docs/reference/esql/functions/kibana/definition/st_x.json +++ b/docs/reference/esql/functions/kibana/definition/st_x.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "st_x", "description" : "Extracts the `x` coordinate from the supplied point.\nIf the points is of type `geo_point` this is equivalent to extracting the `longitude` value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/st_xmax.json b/docs/reference/esql/functions/kibana/definition/st_xmax.json index 7be22617c099..c1223ecae734 100644 --- a/docs/reference/esql/functions/kibana/definition/st_xmax.json +++ b/docs/reference/esql/functions/kibana/definition/st_xmax.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "st_xmax", "description" : "Extracts the maximum value of the `x` coordinates from the supplied geometry.\nIf the geometry is of type `geo_point` or `geo_shape` this is equivalent to extracting the maximum `longitude` value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/st_xmin.json b/docs/reference/esql/functions/kibana/definition/st_xmin.json index 8052fdb861ce..20c4bd8cca79 100644 --- a/docs/reference/esql/functions/kibana/definition/st_xmin.json +++ b/docs/reference/esql/functions/kibana/definition/st_xmin.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "st_xmin", "description" : "Extracts the minimum value of the `x` coordinates from the supplied geometry.\nIf the geometry is of type `geo_point` or `geo_shape` this is equivalent to extracting the minimum `longitude` value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/st_y.json b/docs/reference/esql/functions/kibana/definition/st_y.json index ca7d817a36ff..42f37d0346b1 100644 --- a/docs/reference/esql/functions/kibana/definition/st_y.json +++ b/docs/reference/esql/functions/kibana/definition/st_y.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "st_y", "description" : "Extracts the `y` coordinate from the supplied point.\nIf the points is of type `geo_point` this is equivalent to extracting the `latitude` value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/st_ymax.json b/docs/reference/esql/functions/kibana/definition/st_ymax.json index 1a53f7388ea5..83a8070834e1 100644 --- a/docs/reference/esql/functions/kibana/definition/st_ymax.json +++ b/docs/reference/esql/functions/kibana/definition/st_ymax.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "st_ymax", "description" : "Extracts the maximum value of the `y` coordinates from the supplied geometry.\nIf the geometry is of type `geo_point` or `geo_shape` this is equivalent to extracting the maximum `latitude` value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/st_ymin.json b/docs/reference/esql/functions/kibana/definition/st_ymin.json index e11722a8f9c0..21051d02cb6d 100644 --- a/docs/reference/esql/functions/kibana/definition/st_ymin.json +++ b/docs/reference/esql/functions/kibana/definition/st_ymin.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "st_ymin", "description" : "Extracts the minimum value of the `y` coordinates from the supplied geometry.\nIf the geometry is of type `geo_point` or `geo_shape` this is equivalent to extracting the minimum `latitude` value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/starts_with.json b/docs/reference/esql/functions/kibana/definition/starts_with.json index 0e5dc076a568..bad7fa1d34b6 100644 --- a/docs/reference/esql/functions/kibana/definition/starts_with.json +++ b/docs/reference/esql/functions/kibana/definition/starts_with.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "starts_with", "description" : "Returns a boolean that indicates whether a keyword string starts with another string.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/substring.json b/docs/reference/esql/functions/kibana/definition/substring.json index 1998eb042848..c6260c5040e5 100644 --- a/docs/reference/esql/functions/kibana/definition/substring.json +++ b/docs/reference/esql/functions/kibana/definition/substring.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "substring", "description" : "Returns a substring of a string, specified by a start position and an optional length.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/tan.json b/docs/reference/esql/functions/kibana/definition/tan.json index 76fab2ff6ab1..af28eace4c59 100644 --- a/docs/reference/esql/functions/kibana/definition/tan.json +++ b/docs/reference/esql/functions/kibana/definition/tan.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "tan", "description" : "Returns the tangent of an angle.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/tanh.json b/docs/reference/esql/functions/kibana/definition/tanh.json index f56e053a3d4e..a36edcc1e88f 100644 --- a/docs/reference/esql/functions/kibana/definition/tanh.json +++ b/docs/reference/esql/functions/kibana/definition/tanh.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "tanh", "description" : "Returns the hyperbolic tangent of a number.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/tau.json b/docs/reference/esql/functions/kibana/definition/tau.json index 1dbb2e892ee6..b5090e8a39a8 100644 --- a/docs/reference/esql/functions/kibana/definition/tau.json +++ b/docs/reference/esql/functions/kibana/definition/tau.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "tau", "description" : "Returns the ratio of a circle's circumference to its radius.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/term.json b/docs/reference/esql/functions/kibana/definition/term.json index b0f129afd239..1a0ea7bf8a4e 100644 --- a/docs/reference/esql/functions/kibana/definition/term.json +++ b/docs/reference/esql/functions/kibana/definition/term.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "term", "description" : "Performs a Term query on the specified field. Returns true if the provided term matches the row.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_base64.json b/docs/reference/esql/functions/kibana/definition/to_base64.json index 84ace22073ab..39014ceb9a5c 100644 --- a/docs/reference/esql/functions/kibana/definition/to_base64.json +++ b/docs/reference/esql/functions/kibana/definition/to_base64.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_base64", "description" : "Encode a string to a base64 string.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_boolean.json b/docs/reference/esql/functions/kibana/definition/to_boolean.json index 3a403caaace6..d295c826f576 100644 --- a/docs/reference/esql/functions/kibana/definition/to_boolean.json +++ b/docs/reference/esql/functions/kibana/definition/to_boolean.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_boolean", "description" : "Converts an input value to a boolean value.\nA string value of *true* will be case-insensitive converted to the Boolean *true*.\nFor anything else, including the empty string, the function will return *false*.\nThe numerical value of *0* will be converted to *false*, anything else will be converted to *true*.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_cartesianpoint.json b/docs/reference/esql/functions/kibana/definition/to_cartesianpoint.json index 7f6e99f88b77..f7303457120f 100644 --- a/docs/reference/esql/functions/kibana/definition/to_cartesianpoint.json +++ b/docs/reference/esql/functions/kibana/definition/to_cartesianpoint.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_cartesianpoint", "description" : "Converts an input value to a `cartesian_point` value.\nA string will only be successfully converted if it respects WKT Point format.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_cartesianshape.json b/docs/reference/esql/functions/kibana/definition/to_cartesianshape.json index 284288068b41..6a08d531523a 100644 --- a/docs/reference/esql/functions/kibana/definition/to_cartesianshape.json +++ b/docs/reference/esql/functions/kibana/definition/to_cartesianshape.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_cartesianshape", "description" : "Converts an input value to a `cartesian_shape` value.\nA string will only be successfully converted if it respects WKT format.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_date_nanos.json b/docs/reference/esql/functions/kibana/definition/to_date_nanos.json index 210b9608f9ef..bc74476a4867 100644 --- a/docs/reference/esql/functions/kibana/definition/to_date_nanos.json +++ b/docs/reference/esql/functions/kibana/definition/to_date_nanos.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_date_nanos", "description" : "Converts an input to a nanosecond-resolution date value (aka date_nanos).", "note" : "The range for date nanos is 1970-01-01T00:00:00.000000000Z to 2262-04-11T23:47:16.854775807Z, attepting to convertvalues outside of that range will result in null with a warning.. Additionally, integers cannot be converted into date nanos, as the range of integer nanoseconds only covers about 2 seconds after epoch.", diff --git a/docs/reference/esql/functions/kibana/definition/to_dateperiod.json b/docs/reference/esql/functions/kibana/definition/to_dateperiod.json index 2940a08a7a10..790c7ec92401 100644 --- a/docs/reference/esql/functions/kibana/definition/to_dateperiod.json +++ b/docs/reference/esql/functions/kibana/definition/to_dateperiod.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_dateperiod", "description" : "Converts an input value into a `date_period` value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_datetime.json b/docs/reference/esql/functions/kibana/definition/to_datetime.json index 8f9ecbd139d3..90c683cf3767 100644 --- a/docs/reference/esql/functions/kibana/definition/to_datetime.json +++ b/docs/reference/esql/functions/kibana/definition/to_datetime.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_datetime", "description" : "Converts an input value to a date value.\nA string will only be successfully converted if it's respecting the format `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'`.\nTo convert dates in other formats, use <>.", "note" : "Note that when converting from nanosecond resolution to millisecond resolution with this function, the nanosecond date is truncated, not rounded.", diff --git a/docs/reference/esql/functions/kibana/definition/to_degrees.json b/docs/reference/esql/functions/kibana/definition/to_degrees.json index 6aefca5c5d4b..7b1cc5180970 100644 --- a/docs/reference/esql/functions/kibana/definition/to_degrees.json +++ b/docs/reference/esql/functions/kibana/definition/to_degrees.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_degrees", "description" : "Converts a number in radians to degrees.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_double.json b/docs/reference/esql/functions/kibana/definition/to_double.json index 27565e616d6e..09d5341a62a1 100644 --- a/docs/reference/esql/functions/kibana/definition/to_double.json +++ b/docs/reference/esql/functions/kibana/definition/to_double.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_double", "description" : "Converts an input value to a double value. If the input parameter is of a date type,\nits value will be interpreted as milliseconds since the Unix epoch,\nconverted to double. Boolean *true* will be converted to double *1.0*, *false* to *0.0*.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_geopoint.json b/docs/reference/esql/functions/kibana/definition/to_geopoint.json index e2ba492e39e9..2c465fcfc2f8 100644 --- a/docs/reference/esql/functions/kibana/definition/to_geopoint.json +++ b/docs/reference/esql/functions/kibana/definition/to_geopoint.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_geopoint", "description" : "Converts an input value to a `geo_point` value.\nA string will only be successfully converted if it respects WKT Point format.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_geoshape.json b/docs/reference/esql/functions/kibana/definition/to_geoshape.json index 53316cc0f7b8..dc05f12e6ee3 100644 --- a/docs/reference/esql/functions/kibana/definition/to_geoshape.json +++ b/docs/reference/esql/functions/kibana/definition/to_geoshape.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_geoshape", "description" : "Converts an input value to a `geo_shape` value.\nA string will only be successfully converted if it respects WKT format.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_integer.json b/docs/reference/esql/functions/kibana/definition/to_integer.json index 93691ac4e94e..0228d6baaf50 100644 --- a/docs/reference/esql/functions/kibana/definition/to_integer.json +++ b/docs/reference/esql/functions/kibana/definition/to_integer.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_integer", "description" : "Converts an input value to an integer value.\nIf the input parameter is of a date type, its value will be interpreted as milliseconds\nsince the Unix epoch, converted to integer.\nBoolean *true* will be converted to integer *1*, *false* to *0*.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_ip.json b/docs/reference/esql/functions/kibana/definition/to_ip.json index dfc8e97d283f..4ec424442c2c 100644 --- a/docs/reference/esql/functions/kibana/definition/to_ip.json +++ b/docs/reference/esql/functions/kibana/definition/to_ip.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_ip", "description" : "Converts an input string to an IP value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_long.json b/docs/reference/esql/functions/kibana/definition/to_long.json index eb1ce7220c3f..5cd920092473 100644 --- a/docs/reference/esql/functions/kibana/definition/to_long.json +++ b/docs/reference/esql/functions/kibana/definition/to_long.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_long", "description" : "Converts an input value to a long value. If the input parameter is of a date type,\nits value will be interpreted as milliseconds since the Unix epoch, converted to long.\nBoolean *true* will be converted to long *1*, *false* to *0*.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_lower.json b/docs/reference/esql/functions/kibana/definition/to_lower.json index 07bb057fe080..22fd8f4fc1b1 100644 --- a/docs/reference/esql/functions/kibana/definition/to_lower.json +++ b/docs/reference/esql/functions/kibana/definition/to_lower.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_lower", "description" : "Returns a new string representing the input string converted to lower case.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_radians.json b/docs/reference/esql/functions/kibana/definition/to_radians.json index 1b13ef22e23f..638ef8ec13e8 100644 --- a/docs/reference/esql/functions/kibana/definition/to_radians.json +++ b/docs/reference/esql/functions/kibana/definition/to_radians.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_radians", "description" : "Converts a number in degrees to radians.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_string.json b/docs/reference/esql/functions/kibana/definition/to_string.json index 1c86e81b3113..40e9588b03f8 100644 --- a/docs/reference/esql/functions/kibana/definition/to_string.json +++ b/docs/reference/esql/functions/kibana/definition/to_string.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_string", "description" : "Converts an input value into a string.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_timeduration.json b/docs/reference/esql/functions/kibana/definition/to_timeduration.json index eb7d4e0d5cce..923aa2024f33 100644 --- a/docs/reference/esql/functions/kibana/definition/to_timeduration.json +++ b/docs/reference/esql/functions/kibana/definition/to_timeduration.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_timeduration", "description" : "Converts an input value into a `time_duration` value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_unsigned_long.json b/docs/reference/esql/functions/kibana/definition/to_unsigned_long.json index 4a215b1ea97f..f7725311b298 100644 --- a/docs/reference/esql/functions/kibana/definition/to_unsigned_long.json +++ b/docs/reference/esql/functions/kibana/definition/to_unsigned_long.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_unsigned_long", "description" : "Converts an input value to an unsigned long value. If the input parameter is of a date type,\nits value will be interpreted as milliseconds since the Unix epoch, converted to unsigned long.\nBoolean *true* will be converted to unsigned long *1*, *false* to *0*.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_upper.json b/docs/reference/esql/functions/kibana/definition/to_upper.json index caa9d563b08b..ac0494b1fb9e 100644 --- a/docs/reference/esql/functions/kibana/definition/to_upper.json +++ b/docs/reference/esql/functions/kibana/definition/to_upper.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_upper", "description" : "Returns a new string representing the input string converted to upper case.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/to_version.json b/docs/reference/esql/functions/kibana/definition/to_version.json index a77fc250c3a3..41ad00dc20c9 100644 --- a/docs/reference/esql/functions/kibana/definition/to_version.json +++ b/docs/reference/esql/functions/kibana/definition/to_version.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "to_version", "description" : "Converts an input string to a version value.", "signatures" : [ diff --git a/docs/reference/esql/functions/kibana/definition/trim.json b/docs/reference/esql/functions/kibana/definition/trim.json index 45805b3bfb05..eb72d5d041d0 100644 --- a/docs/reference/esql/functions/kibana/definition/trim.json +++ b/docs/reference/esql/functions/kibana/definition/trim.json @@ -1,6 +1,6 @@ { "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "eval", + "type" : "scalar", "name" : "trim", "description" : "Removes leading and trailing whitespaces from a string.", "signatures" : [ diff --git a/docs/src/yamlRestTest/resources/GeoLite2-City.mmdb b/docs/src/yamlRestTest/resources/GeoLite2-City.mmdb index 0809201619b5..67dcd4a8e5a1 100644 Binary files a/docs/src/yamlRestTest/resources/GeoLite2-City.mmdb and b/docs/src/yamlRestTest/resources/GeoLite2-City.mmdb differ diff --git a/docs/src/yamlRestTest/resources/GeoLite2-Country.mmdb b/docs/src/yamlRestTest/resources/GeoLite2-Country.mmdb index aa81cbe8a2f0..8b1436b0c387 100644 Binary files a/docs/src/yamlRestTest/resources/GeoLite2-Country.mmdb and b/docs/src/yamlRestTest/resources/GeoLite2-Country.mmdb differ diff --git a/gradle/build.versions.toml b/gradle/build.versions.toml index 05fda8e0244d..1aed327c4579 100644 --- a/gradle/build.versions.toml +++ b/gradle/build.versions.toml @@ -11,7 +11,7 @@ apache-compress = "org.apache.commons:commons-compress:1.26.1" apache-rat = "org.apache.rat:apache-rat:0.11" asm = { group = "org.ow2.asm", name="asm", version.ref="asm" } asm-tree = { group = "org.ow2.asm", name="asm-tree", version.ref="asm" } -bytebuddy = "net.bytebuddy:byte-buddy:1.14.12" +bytebuddy = "net.bytebuddy:byte-buddy:1.15.11" checkstyle = "com.puppycrawl.tools:checkstyle:10.3" commons-codec = "commons-codec:commons-codec:1.11" commmons-io = "commons-io:commons-io:2.2" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index b1db86f3a7b2..64efd8e439df 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -904,14 +904,14 @@ - - - + + + - - - + + + @@ -1724,9 +1724,9 @@ - - - + + + @@ -4118,14 +4118,14 @@ - - - + + + - - - + + + diff --git a/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumentationServiceImpl.java b/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumentationServiceImpl.java index 46b2139c79db..05a5af374e5d 100644 --- a/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumentationServiceImpl.java +++ b/libs/entitlement/asm-provider/src/main/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumentationServiceImpl.java @@ -118,7 +118,8 @@ public class InstrumentationServiceImpl implements InstrumentationService { ) throws NoSuchMethodException, ClassNotFoundException { var targetMethod = targetSuperclass.getDeclaredMethod(methodName, parameterTypes); - validateTargetMethod(implementationClass, targetMethod); + var implementationMethod = implementationClass.getMethod(targetMethod.getName(), targetMethod.getParameterTypes()); + validateTargetMethod(implementationClass, targetMethod, implementationMethod); var checkerAdditionalArguments = Stream.of(Class.class, targetSuperclass); var checkMethodArgumentTypes = Stream.concat(checkerAdditionalArguments, Arrays.stream(parameterTypes)) @@ -169,15 +170,15 @@ public class InstrumentationServiceImpl implements InstrumentationService { return new InstrumentationInfo( new MethodKey( - Type.getInternalName(implementationClass), - targetMethod.getName(), + Type.getInternalName(implementationMethod.getDeclaringClass()), + implementationMethod.getName(), Arrays.stream(parameterTypes).map(c -> Type.getType(c).getInternalName()).toList() ), checkMethod[0] ); } - private static void validateTargetMethod(Class implementationClass, Method targetMethod) { + private static void validateTargetMethod(Class implementationClass, Method targetMethod, Method implementationMethod) { if (targetMethod.getDeclaringClass().isAssignableFrom(implementationClass) == false) { throw new IllegalArgumentException( String.format( @@ -209,37 +210,26 @@ public class InstrumentationServiceImpl implements InstrumentationService { ) ); } - try { - var implementationMethod = implementationClass.getMethod(targetMethod.getName(), targetMethod.getParameterTypes()); - var methodModifiers = implementationMethod.getModifiers(); - if (Modifier.isAbstract(methodModifiers)) { - throw new IllegalArgumentException( - String.format( - Locale.ROOT, - "Not a valid instrumentation method: %s is abstract in %s", - targetMethod.getName(), - implementationClass.getName() - ) - ); - } - if (Modifier.isPublic(methodModifiers) == false) { - throw new IllegalArgumentException( - String.format( - Locale.ROOT, - "Not a valid instrumentation method: %s is not public in %s", - targetMethod.getName(), - implementationClass.getName() - ) - ); - } - } catch (NoSuchMethodException e) { - assert false - : String.format( + var methodModifiers = implementationMethod.getModifiers(); + if (Modifier.isAbstract(methodModifiers)) { + throw new IllegalArgumentException( + String.format( Locale.ROOT, - "Not a valid instrumentation method: %s cannot be found in %s", + "Not a valid instrumentation method: %s is abstract in %s", targetMethod.getName(), implementationClass.getName() - ); + ) + ); + } + if (Modifier.isPublic(methodModifiers) == false) { + throw new IllegalArgumentException( + String.format( + Locale.ROOT, + "Not a valid instrumentation method: %s is not public in %s", + targetMethod.getName(), + implementationClass.getName() + ) + ); } } diff --git a/libs/entitlement/asm-provider/src/test/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumentationServiceImplTests.java b/libs/entitlement/asm-provider/src/test/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumentationServiceImplTests.java index 3c1eacdc9063..2b9b70d46c0e 100644 --- a/libs/entitlement/asm-provider/src/test/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumentationServiceImplTests.java +++ b/libs/entitlement/asm-provider/src/test/java/org/elasticsearch/entitlement/instrumentation/impl/InstrumentationServiceImplTests.java @@ -40,9 +40,16 @@ public class InstrumentationServiceImplTests extends ESTestCase { abstract static class TestTargetBaseClass { abstract void instanceMethod(int x, String y); + + abstract void instanceMethod2(int x, String y); } - static class TestTargetImplementationClass extends TestTargetBaseClass { + abstract static class TestTargetIntermediateClass extends TestTargetBaseClass { + @Override + public void instanceMethod2(int x, String y) {} + } + + static class TestTargetImplementationClass extends TestTargetIntermediateClass { @Override public void instanceMethod(int x, String y) {} } @@ -364,6 +371,44 @@ public class InstrumentationServiceImplTests extends ESTestCase { ); } + public void testLookupImplementationMethodWithInheritance() throws ClassNotFoundException, NoSuchMethodException { + var info = instrumentationService.lookupImplementationMethod( + TestTargetBaseClass.class, + "instanceMethod2", + TestTargetImplementationClass.class, + TestCheckerMixed.class, + "checkInstanceMethodManual", + int.class, + String.class + ); + + assertThat( + info.targetMethod(), + equalTo( + new MethodKey( + "org/elasticsearch/entitlement/instrumentation/impl/InstrumentationServiceImplTests$TestTargetIntermediateClass", + "instanceMethod2", + List.of("I", "java/lang/String") + ) + ) + ); + assertThat( + info.checkMethod(), + equalTo( + new CheckMethod( + "org/elasticsearch/entitlement/instrumentation/impl/InstrumentationServiceImplTests$TestCheckerMixed", + "checkInstanceMethodManual", + List.of( + "Ljava/lang/Class;", + "Lorg/elasticsearch/entitlement/instrumentation/impl/InstrumentationServiceImplTests$TestTargetBaseClass;", + "I", + "Ljava/lang/String;" + ) + ) + ) + ); + } + public void testParseCheckerMethodSignatureStaticMethod() { var methodKey = InstrumentationServiceImpl.parseCheckerMethodSignature( "check$org_example_TestClass$$staticMethod", diff --git a/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java b/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java index e54ccd675b5f..28306cc0e660 100644 --- a/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java +++ b/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java @@ -48,7 +48,9 @@ import java.nio.channels.CompletionHandler; import java.nio.channels.DatagramChannel; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; +import java.nio.channels.spi.SelectorProvider; import java.nio.charset.Charset; +import java.nio.file.LinkOption; import java.nio.file.OpenOption; import java.nio.file.Path; import java.nio.file.attribute.UserPrincipal; @@ -214,6 +216,8 @@ public interface EntitlementChecker { void check$jdk_vm_ci_services_Services$$loadSingle(Class callerClass, Class service, boolean required); + void check$java_nio_charset_spi_CharsetProvider$(Class callerClass); + /// ///////////////// // // Network access @@ -411,6 +415,16 @@ public interface EntitlementChecker { void check$sun_nio_ch_DatagramChannelImpl$receive(Class callerClass, DatagramChannel that, ByteBuffer dst); + // providers (SPI) + + // protected constructors + void check$java_nio_channels_spi_SelectorProvider$(Class callerClass); + + void check$java_nio_channels_spi_AsynchronousChannelProvider$(Class callerClass); + + // provider methods (dynamic) + void checkSelectorProviderInheritedChannel(Class callerClass, SelectorProvider that); + /// ///////////////// // // Load native libraries @@ -501,6 +515,8 @@ public interface EntitlementChecker { void check$java_util_Scanner$(Class callerClass, File source, Charset charset); // nio + void check$java_nio_file_Files$$getOwner(Class callerClass, Path path, LinkOption... options); + void check$java_nio_file_Files$$probeContentType(Class callerClass, Path path); void check$java_nio_file_Files$$setOwner(Class callerClass, Path path, UserPrincipal principal); diff --git a/libs/entitlement/qa/entitled-plugin/src/main/plugin-metadata/entitlement-policy.yaml b/libs/entitlement/qa/entitled-plugin/src/main/plugin-metadata/entitlement-policy.yaml deleted file mode 100644 index 81acd4c467f9..000000000000 --- a/libs/entitlement/qa/entitled-plugin/src/main/plugin-metadata/entitlement-policy.yaml +++ /dev/null @@ -1,4 +0,0 @@ -org.elasticsearch.entitlement.qa.entitled: - - write_system_properties: - properties: - - org.elasticsearch.entitlement.qa.selfTest diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/DummyImplementations.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/DummyImplementations.java index 6564e0eed41e..67e06c836f7b 100644 --- a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/DummyImplementations.java +++ b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/DummyImplementations.java @@ -17,11 +17,24 @@ import java.net.DatagramSocket; import java.net.DatagramSocketImpl; import java.net.InetAddress; import java.net.NetworkInterface; +import java.net.ProtocolFamily; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketException; import java.net.SocketImpl; +import java.nio.channels.AsynchronousChannelGroup; +import java.nio.channels.AsynchronousServerSocketChannel; +import java.nio.channels.AsynchronousSocketChannel; +import java.nio.channels.DatagramChannel; +import java.nio.channels.Pipe; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.channels.spi.AbstractSelector; +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.nio.channels.spi.SelectorProvider; +import java.nio.charset.Charset; +import java.nio.charset.spi.CharsetProvider; import java.security.cert.Certificate; import java.text.BreakIterator; import java.text.Collator; @@ -35,8 +48,11 @@ import java.text.spi.DateFormatProvider; import java.text.spi.DateFormatSymbolsProvider; import java.text.spi.DecimalFormatSymbolsProvider; import java.text.spi.NumberFormatProvider; +import java.util.Iterator; import java.util.Locale; import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadFactory; import java.util.spi.CalendarDataProvider; import java.util.spi.CalendarNameProvider; import java.util.spi.CurrencyNameProvider; @@ -486,4 +502,70 @@ class DummyImplementations { private static RuntimeException unexpected() { return new IllegalStateException("This method isn't supposed to be called"); } + + static class DummySelectorProvider extends SelectorProvider { + @Override + public DatagramChannel openDatagramChannel() throws IOException { + return null; + } + + @Override + public DatagramChannel openDatagramChannel(ProtocolFamily family) throws IOException { + return null; + } + + @Override + public Pipe openPipe() throws IOException { + return null; + } + + @Override + public AbstractSelector openSelector() throws IOException { + return null; + } + + @Override + public ServerSocketChannel openServerSocketChannel() throws IOException { + return null; + } + + @Override + public SocketChannel openSocketChannel() throws IOException { + return null; + } + } + + static class DummyAsynchronousChannelProvider extends AsynchronousChannelProvider { + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory threadFactory) throws IOException { + return null; + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize) throws IOException { + return null; + } + + @Override + public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group) throws IOException { + return null; + } + + @Override + public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group) throws IOException { + return null; + } + } + + static class DummyCharsetProvider extends CharsetProvider { + @Override + public Iterator charsets() { + return null; + } + + @Override + public Charset charsetForName(String charsetName) { + return null; + } + } } diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java index 6d43f58c532c..c62f6c003fe7 100644 --- a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java +++ b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java @@ -80,6 +80,11 @@ class FileCheckActions { new FileOutputStream(readWriteFile().toFile(), false).close(); } + @EntitlementTest(expectedAccess = PLUGINS) + static void filesGetOwner() throws IOException { + Files.getOwner(readFile()); + } + @EntitlementTest(expectedAccess = PLUGINS) static void filesProbeContentType() throws IOException { Files.probeContentType(readFile()); diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main22/java/org/elasticsearch/entitlement/qa/test/VersionSpecificNativeChecks.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/NativeActions.java similarity index 85% rename from libs/entitlement/qa/entitlement-test-plugin/src/main22/java/org/elasticsearch/entitlement/qa/test/VersionSpecificNativeChecks.java rename to libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/NativeActions.java index 0a69f7255a20..5079e0d38a00 100644 --- a/libs/entitlement/qa/entitlement-test-plugin/src/main22/java/org/elasticsearch/entitlement/qa/test/VersionSpecificNativeChecks.java +++ b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/NativeActions.java @@ -30,9 +30,12 @@ import java.util.Set; import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS; +import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.SERVER_ONLY; -class VersionSpecificNativeChecks { +class NativeActions { + @EntitlementTest(expectedAccess = SERVER_ONLY) static void enableNativeAccess() throws Exception { ModuleLayer parent = ModuleLayer.boot(); @@ -49,16 +52,19 @@ class VersionSpecificNativeChecks { controller.enableNativeAccess(targetModule.get()); } + @EntitlementTest(expectedAccess = PLUGINS) static void addressLayoutWithTargetLayout() { AddressLayout addressLayout = ADDRESS.withoutTargetLayout(); addressLayout.withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, ValueLayout.JAVA_BYTE)); } + @EntitlementTest(expectedAccess = PLUGINS) static void linkerDowncallHandle() { Linker linker = Linker.nativeLinker(); linker.downcallHandle(FunctionDescriptor.of(JAVA_LONG, ADDRESS)); } + @EntitlementTest(expectedAccess = PLUGINS) static void linkerDowncallHandleWithAddress() { Linker linker = Linker.nativeLinker(); linker.downcallHandle(linker.defaultLookup().find("strlen").get(), FunctionDescriptor.of(JAVA_LONG, ADDRESS)); @@ -68,12 +74,13 @@ class VersionSpecificNativeChecks { return 0; } + @EntitlementTest(expectedAccess = PLUGINS) static void linkerUpcallStub() throws NoSuchMethodException { Linker linker = Linker.nativeLinker(); MethodHandle mh = null; try { - mh = MethodHandles.lookup().findStatic(VersionSpecificNativeChecks.class, "callback", MethodType.methodType(int.class)); + mh = MethodHandles.lookup().findStatic(NativeActions.class, "callback", MethodType.methodType(int.class)); } catch (IllegalAccessException e) { assert false; } @@ -82,24 +89,28 @@ class VersionSpecificNativeChecks { linker.upcallStub(mh, callbackDescriptor, Arena.ofAuto()); } + @EntitlementTest(expectedAccess = PLUGINS) static void memorySegmentReinterpret() { Arena arena = Arena.ofAuto(); MemorySegment segment = arena.allocate(100); segment.reinterpret(50); } + @EntitlementTest(expectedAccess = PLUGINS) static void memorySegmentReinterpretWithCleanup() { Arena arena = Arena.ofAuto(); MemorySegment segment = arena.allocate(100); segment.reinterpret(Arena.ofAuto(), s -> {}); } + @EntitlementTest(expectedAccess = PLUGINS) static void memorySegmentReinterpretWithSizeAndCleanup() { Arena arena = Arena.ofAuto(); MemorySegment segment = arena.allocate(100); segment.reinterpret(50, Arena.ofAuto(), s -> {}); } + @EntitlementTest(expectedAccess = PLUGINS) static void symbolLookupWithPath() { try { SymbolLookup.libraryLookup(Path.of("/foo/bar/libFoo.so"), Arena.ofAuto()); @@ -108,6 +119,7 @@ class VersionSpecificNativeChecks { } } + @EntitlementTest(expectedAccess = PLUGINS) static void symbolLookupWithName() { try { SymbolLookup.libraryLookup("foo", Arena.ofAuto()); diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java index f2f6bd721e88..dbc9a7692b70 100644 --- a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java +++ b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java @@ -180,27 +180,12 @@ public class RestEntitlementsCheckAction extends BaseRestHandler { entry("runtime_load", forPlugins(LoadNativeLibrariesCheckActions::runtimeLoad)), entry("runtime_load_library", forPlugins(LoadNativeLibrariesCheckActions::runtimeLoadLibrary)), entry("system_load", forPlugins(LoadNativeLibrariesCheckActions::systemLoad)), - entry("system_load_library", forPlugins(LoadNativeLibrariesCheckActions::systemLoadLibrary)), - entry("enable_native_access", new CheckAction(VersionSpecificNativeChecks::enableNativeAccess, false, 22)), - entry("address_target_layout", new CheckAction(VersionSpecificNativeChecks::addressLayoutWithTargetLayout, false, 22)), - entry("donwncall_handle", new CheckAction(VersionSpecificNativeChecks::linkerDowncallHandle, false, 22)), - entry( - "donwncall_handle_with_address", - new CheckAction(VersionSpecificNativeChecks::linkerDowncallHandleWithAddress, false, 22) - ), - entry("upcall_stub", new CheckAction(VersionSpecificNativeChecks::linkerUpcallStub, false, 22)), - entry("reinterpret", new CheckAction(VersionSpecificNativeChecks::memorySegmentReinterpret, false, 22)), - entry("reinterpret_cleanup", new CheckAction(VersionSpecificNativeChecks::memorySegmentReinterpretWithCleanup, false, 22)), - entry( - "reinterpret_size_cleanup", - new CheckAction(VersionSpecificNativeChecks::memorySegmentReinterpretWithSizeAndCleanup, false, 22) - ), - entry("symbol_lookup_name", new CheckAction(VersionSpecificNativeChecks::symbolLookupWithName, false, 22)), - entry("symbol_lookup_path", new CheckAction(VersionSpecificNativeChecks::symbolLookupWithPath, false, 22)) + entry("system_load_library", forPlugins(LoadNativeLibrariesCheckActions::systemLoadLibrary)) ), getTestEntries(FileCheckActions.class), getTestEntries(SpiActions.class), - getTestEntries(SystemActions.class) + getTestEntries(SystemActions.class), + getTestEntries(NativeActions.class) ) .flatMap(Function.identity()) .filter(entry -> entry.getValue().fromJavaVersion() == null || Runtime.version().feature() >= entry.getValue().fromJavaVersion()) diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/SpiActions.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/SpiActions.java index d9ebd1705cb4..a335964c6fa8 100644 --- a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/SpiActions.java +++ b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/SpiActions.java @@ -9,6 +9,10 @@ package org.elasticsearch.entitlement.qa.test; +import java.io.IOException; +import java.nio.channels.Channel; +import java.nio.channels.spi.SelectorProvider; + import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.ALWAYS_DENIED; class SpiActions { @@ -72,5 +76,32 @@ class SpiActions { new DummyImplementations.DummyLocaleServiceProvider(); } + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void getInheritedChannel() throws IOException { + Channel channel = null; + try { + channel = SelectorProvider.provider().inheritedChannel(); + } finally { + if (channel != null) { + channel.close(); + } + } + } + + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void createSelectorProvider() { + new DummyImplementations.DummySelectorProvider(); + } + + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void createAsynchronousChannelProvider() { + new DummyImplementations.DummyAsynchronousChannelProvider(); + } + + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void createCharsetProvider() { + new DummyImplementations.DummyCharsetProvider(); + } + private SpiActions() {} } diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/VersionSpecificNativeChecks.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/VersionSpecificNativeChecks.java deleted file mode 100644 index cb84c9bd9042..000000000000 --- a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/VersionSpecificNativeChecks.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -package org.elasticsearch.entitlement.qa.test; - -class VersionSpecificNativeChecks { - - static void enableNativeAccess() throws Exception {} - - static void addressLayoutWithTargetLayout() {} - - static void linkerDowncallHandle() {} - - static void linkerDowncallHandleWithAddress() {} - - static void linkerUpcallStub() throws NoSuchMethodException {} - - static void memorySegmentReinterpret() {} - - static void memorySegmentReinterpretWithCleanup() {} - - static void memorySegmentReinterpretWithSizeAndCleanup() {} - - static void symbolLookupWithPath() {} - - static void symbolLookupWithName() {} -} diff --git a/libs/entitlement/qa/src/javaRestTest/java/org/elasticsearch/entitlement/qa/AbstractEntitlementsIT.java b/libs/entitlement/qa/src/javaRestTest/java/org/elasticsearch/entitlement/qa/AbstractEntitlementsIT.java index 487f692ef448..29e616855f27 100644 --- a/libs/entitlement/qa/src/javaRestTest/java/org/elasticsearch/entitlement/qa/AbstractEntitlementsIT.java +++ b/libs/entitlement/qa/src/javaRestTest/java/org/elasticsearch/entitlement/qa/AbstractEntitlementsIT.java @@ -11,6 +11,7 @@ package org.elasticsearch.entitlement.qa; import org.elasticsearch.client.Request; import org.elasticsearch.client.Response; +import org.elasticsearch.entitlement.qa.EntitlementsTestRule.PolicyBuilder; import org.elasticsearch.test.rest.ESRestTestCase; import java.io.IOException; @@ -22,7 +23,7 @@ import static org.hamcrest.Matchers.equalTo; public abstract class AbstractEntitlementsIT extends ESRestTestCase { - static final EntitlementsTestRule.PolicyBuilder ALLOWED_TEST_ENTITLEMENTS = (builder, tempDir) -> { + static final PolicyBuilder ALLOWED_TEST_ENTITLEMENTS = (builder, tempDir) -> { builder.value("create_class_loader"); builder.value("set_https_connection_properties"); builder.value("inbound_network"); @@ -34,11 +35,17 @@ public abstract class AbstractEntitlementsIT extends ESRestTestCase { Map.of("properties", List.of("es.entitlements.checkSetSystemProperty", "es.entitlements.checkClearSystemProperty")) ) ); - - builder.value(Map.of("file", Map.of("path", tempDir.resolve("read_dir"), "mode", "read"))); - builder.value(Map.of("file", Map.of("path", tempDir.resolve("read_write_dir"), "mode", "read_write"))); - builder.value(Map.of("file", Map.of("path", tempDir.resolve("read_file"), "mode", "read"))); - builder.value(Map.of("file", Map.of("path", tempDir.resolve("read_write_file"), "mode", "read_write"))); + builder.value( + Map.of( + "files", + List.of( + Map.of("path", tempDir.resolve("read_dir"), "mode", "read"), + Map.of("path", tempDir.resolve("read_write_dir"), "mode", "read_write"), + Map.of("path", tempDir.resolve("read_file"), "mode", "read"), + Map.of("path", tempDir.resolve("read_write_file"), "mode", "read_write") + ) + ) + ); }; private final String actionName; diff --git a/libs/entitlement/qa/src/javaRestTest/java/org/elasticsearch/entitlement/qa/EntitlementsTestRule.java b/libs/entitlement/qa/src/javaRestTest/java/org/elasticsearch/entitlement/qa/EntitlementsTestRule.java index 33d5eeca595a..fd702d60e723 100644 --- a/libs/entitlement/qa/src/javaRestTest/java/org/elasticsearch/entitlement/qa/EntitlementsTestRule.java +++ b/libs/entitlement/qa/src/javaRestTest/java/org/elasticsearch/entitlement/qa/EntitlementsTestRule.java @@ -26,9 +26,27 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; +import java.util.Map; class EntitlementsTestRule implements TestRule { + // entitlements that test methods may use, see EntitledActions + private static final PolicyBuilder ENTITLED_POLICY = (builder, tempDir) -> { + builder.value(Map.of("write_system_properties", Map.of("properties", List.of("org.elasticsearch.entitlement.qa.selfTest")))); + builder.value( + Map.of( + "files", + List.of( + Map.of("path", tempDir.resolve("read_dir"), "mode", "read"), + Map.of("path", tempDir.resolve("read_write_dir"), "mode", "read_write"), + Map.of("path", tempDir.resolve("read_file"), "mode", "read"), + Map.of("path", tempDir.resolve("read_write_file"), "mode", "read_write") + ) + ) + ); + }; + interface PolicyBuilder { void build(XContentBuilder builder, Path tempDir) throws IOException; } @@ -51,7 +69,7 @@ class EntitlementsTestRule implements TestRule { } }; cluster = ElasticsearchCluster.local() - .module("entitled") + .module("entitled", spec -> buildEntitlements(spec, "org.elasticsearch.entitlement.qa.entitled", ENTITLED_POLICY)) .module("entitlement-test-plugin", spec -> setupEntitlements(spec, modular, policyBuilder)) .systemProperty("es.entitlements.enabled", "true") .systemProperty("es.entitlements.testdir", () -> testDir.getRoot().getAbsolutePath()) @@ -65,29 +83,30 @@ class EntitlementsTestRule implements TestRule { return ruleChain.apply(statement, description); } + private void buildEntitlements(PluginInstallSpec spec, String moduleName, PolicyBuilder policyBuilder) { + spec.withEntitlementsOverride(old -> { + try (var builder = YamlXContent.contentBuilder()) { + builder.startObject(); + builder.field(moduleName); + builder.startArray(); + + policyBuilder.build(builder, testDir.getRoot().toPath()); + builder.endArray(); + builder.endObject(); + + String policy = Strings.toString(builder); + System.out.println("Using entitlement policy for module " + moduleName + ":\n" + policy); + return Resource.fromString(policy); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + private void setupEntitlements(PluginInstallSpec spec, boolean modular, PolicyBuilder policyBuilder) { String moduleName = modular ? "org.elasticsearch.entitlement.qa.test" : "ALL-UNNAMED"; if (policyBuilder != null) { - spec.withEntitlementsOverride(old -> { - try { - try (var builder = YamlXContent.contentBuilder()) { - builder.startObject(); - builder.field(moduleName); - builder.startArray(); - - policyBuilder.build(builder, testDir.getRoot().toPath()); - builder.endArray(); - builder.endObject(); - - String policy = Strings.toString(builder); - System.out.println("Using entitlement policy:\n" + policy); - return Resource.fromString(policy); - } - - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }); + buildEntitlements(spec, moduleName, policyBuilder); } if (modular == false) { diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/EntitlementInitialization.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/EntitlementInitialization.java index 4e46e307f3c7..8935d718b830 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/EntitlementInitialization.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/EntitlementInitialization.java @@ -31,6 +31,7 @@ import org.elasticsearch.entitlement.runtime.policy.entitlements.OutboundNetwork import java.lang.instrument.Instrumentation; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.nio.channels.spi.SelectorProvider; import java.nio.file.FileSystems; import java.nio.file.OpenOption; import java.nio.file.Path; @@ -79,6 +80,13 @@ public class EntitlementInitialization { "checkNewInputStream", Path.class, OpenOption[].class + ), + INSTRUMENTATION_SERVICE.lookupImplementationMethod( + SelectorProvider.class, + "inheritedChannel", + SelectorProvider.provider().getClass(), + EntitlementChecker.class, + "checkSelectorProviderInheritedChannel" ) ).forEach(instrumentation -> checkMethods.put(instrumentation.targetMethod(), instrumentation.checkMethod())); diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java index bf9c2fad4df9..50e3e6d9c55e 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java @@ -53,7 +53,9 @@ import java.nio.channels.CompletionHandler; import java.nio.channels.DatagramChannel; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; +import java.nio.channels.spi.SelectorProvider; import java.nio.charset.Charset; +import java.nio.file.LinkOption; import java.nio.file.OpenOption; import java.nio.file.Path; import java.nio.file.attribute.UserPrincipal; @@ -289,6 +291,11 @@ public class ElasticsearchEntitlementChecker implements EntitlementChecker { policyManager.checkChangeJVMGlobalState(callerClass); } + @Override + public void check$java_nio_charset_spi_CharsetProvider$(Class callerClass) { + policyManager.checkChangeJVMGlobalState(callerClass); + } + @Override public void check$com_sun_tools_jdi_VirtualMachineManagerImpl$$virtualMachineManager(Class callerClass) { policyManager.checkChangeJVMGlobalState(callerClass); @@ -801,6 +808,21 @@ public class ElasticsearchEntitlementChecker implements EntitlementChecker { policyManager.checkInboundNetworkAccess(callerClass); } + @Override + public void check$java_nio_channels_spi_SelectorProvider$(Class callerClass) { + policyManager.checkChangeNetworkHandling(callerClass); + } + + @Override + public void check$java_nio_channels_spi_AsynchronousChannelProvider$(Class callerClass) { + policyManager.checkChangeNetworkHandling(callerClass); + } + + @Override + public void checkSelectorProviderInheritedChannel(Class callerClass, SelectorProvider that) { + policyManager.checkChangeNetworkHandling(callerClass); + } + @Override public void check$java_lang_Runtime$load(Class callerClass, Runtime that, String filename) { // TODO: check filesystem entitlement READ @@ -908,7 +930,7 @@ public class ElasticsearchEntitlementChecker implements EntitlementChecker { ModuleLayer.Controller that, Module target ) { - policyManager.checkLoadingNativeLibraries(callerClass); + policyManager.checkChangeJVMGlobalState(callerClass); } /// ///////////////// @@ -955,6 +977,11 @@ public class ElasticsearchEntitlementChecker implements EntitlementChecker { // nio + @Override + public void check$java_nio_file_Files$$getOwner(Class callerClass, Path path, LinkOption... options) { + policyManager.checkFileRead(callerClass, path); + } + @Override public void check$java_nio_file_Files$$probeContentType(Class callerClass, Path path) { policyManager.checkFileRead(callerClass, path); diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTree.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTree.java index 3333eefa4f71..c69244d7e8a9 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTree.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTree.java @@ -9,7 +9,7 @@ package org.elasticsearch.entitlement.runtime.policy; -import org.elasticsearch.entitlement.runtime.policy.entitlements.FileEntitlement; +import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement; import java.nio.file.Path; import java.util.ArrayList; @@ -20,18 +20,19 @@ import java.util.Objects; import static org.elasticsearch.core.PathUtils.getDefaultFileSystem; public final class FileAccessTree { - public static final FileAccessTree EMPTY = new FileAccessTree(List.of()); + public static final FileAccessTree EMPTY = new FileAccessTree(FilesEntitlement.EMPTY); private static final String FILE_SEPARATOR = getDefaultFileSystem().getSeparator(); private final String[] readPaths; private final String[] writePaths; - private FileAccessTree(List fileEntitlements) { + private FileAccessTree(FilesEntitlement filesEntitlement) { List readPaths = new ArrayList<>(); List writePaths = new ArrayList<>(); - for (FileEntitlement fileEntitlement : fileEntitlements) { - String path = normalizePath(Path.of(fileEntitlement.path())); - if (fileEntitlement.mode() == FileEntitlement.Mode.READ_WRITE) { + for (FilesEntitlement.FileData fileData : filesEntitlement.filesData()) { + var path = normalizePath(Path.of(fileData.path())); + var mode = fileData.mode(); + if (mode == FilesEntitlement.Mode.READ_WRITE) { writePaths.add(path); } readPaths.add(path); @@ -44,8 +45,8 @@ public final class FileAccessTree { this.writePaths = writePaths.toArray(new String[0]); } - public static FileAccessTree of(List fileEntitlements) { - return new FileAccessTree(fileEntitlements); + public static FileAccessTree of(FilesEntitlement filesEntitlement) { + return new FileAccessTree(filesEntitlement); } boolean canRead(Path path) { diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java index 77894aff610c..393eb93478e6 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java @@ -16,7 +16,7 @@ import org.elasticsearch.entitlement.runtime.api.NotEntitledException; import org.elasticsearch.entitlement.runtime.policy.entitlements.CreateClassLoaderEntitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.Entitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.ExitVMEntitlement; -import org.elasticsearch.entitlement.runtime.policy.entitlements.FileEntitlement; +import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.InboundNetworkEntitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.LoadNativeLibrariesEntitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.OutboundNetworkEntitlement; @@ -73,14 +73,16 @@ public class PolicyManager { } public static ModuleEntitlements from(String componentName, List entitlements) { - var fileEntitlements = entitlements.stream() - .filter(e -> e.getClass().equals(FileEntitlement.class)) - .map(e -> (FileEntitlement) e) - .toList(); + FilesEntitlement filesEntitlement = FilesEntitlement.EMPTY; + for (Entitlement entitlement : entitlements) { + if (entitlement instanceof FilesEntitlement) { + filesEntitlement = (FilesEntitlement) entitlement; + } + } return new ModuleEntitlements( componentName, entitlements.stream().collect(groupingBy(Entitlement::getClass)), - FileAccessTree.of(fileEntitlements) + FileAccessTree.of(filesEntitlement) ); } @@ -164,23 +166,14 @@ public class PolicyManager { } private static void validateEntitlementsPerModule(String componentName, String moduleName, List entitlements) { - Set> flagEntitlements = new HashSet<>(); + Set> found = new HashSet<>(); for (var e : entitlements) { - if (e instanceof FileEntitlement) { - continue; - } - if (flagEntitlements.contains(e.getClass())) { + if (found.contains(e.getClass())) { throw new IllegalArgumentException( - "[" - + componentName - + "] using module [" - + moduleName - + "] found duplicate flag entitlements [" - + e.getClass().getName() - + "]" + "[" + componentName + "] using module [" + moduleName + "] found duplicate entitlement [" + e.getClass().getName() + "]" ); } - flagEntitlements.add(e.getClass()); + found.add(e.getClass()); } } diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyParser.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyParser.java index 2d3468165a59..fead4fc1f629 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyParser.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyParser.java @@ -11,7 +11,7 @@ package org.elasticsearch.entitlement.runtime.policy; import org.elasticsearch.entitlement.runtime.policy.entitlements.CreateClassLoaderEntitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.Entitlement; -import org.elasticsearch.entitlement.runtime.policy.entitlements.FileEntitlement; +import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.InboundNetworkEntitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.LoadNativeLibrariesEntitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.OutboundNetworkEntitlement; @@ -46,7 +46,7 @@ import java.util.stream.Stream; public class PolicyParser { private static final Map> EXTERNAL_ENTITLEMENTS = Stream.of( - FileEntitlement.class, + FilesEntitlement.class, CreateClassLoaderEntitlement.class, SetHttpsConnectionPropertiesEntitlement.class, OutboundNetworkEntitlement.class, @@ -197,36 +197,43 @@ public class PolicyParser { ? entitlementConstructor.getParameterTypes() : entitlementMethod.getParameterTypes(); String[] parametersNames = entitlementMetadata.parameterNames(); + Object[] parameterValues = new Object[parameterTypes.length]; if (parameterTypes.length != 0 || parametersNames.length != 0) { - if (policyParser.nextToken() != XContentParser.Token.START_OBJECT) { + if (policyParser.nextToken() == XContentParser.Token.START_OBJECT) { + Map parsedValues = policyParser.map(); + + for (int parameterIndex = 0; parameterIndex < parameterTypes.length; ++parameterIndex) { + String parameterName = parametersNames[parameterIndex]; + Object parameterValue = parsedValues.remove(parameterName); + if (parameterValue == null) { + throw newPolicyParserException(scopeName, entitlementType, "missing entitlement parameter [" + parameterName + "]"); + } + Class parameterType = parameterTypes[parameterIndex]; + if (parameterType.isAssignableFrom(parameterValue.getClass()) == false) { + throw newPolicyParserException( + scopeName, + entitlementType, + "unexpected parameter type [" + + parameterType.getSimpleName() + + "] for entitlement parameter [" + + parameterName + + "]" + ); + } + parameterValues[parameterIndex] = parameterValue; + } + if (parsedValues.isEmpty() == false) { + throw newPolicyParserException(scopeName, entitlementType, "extraneous entitlement parameter(s) " + parsedValues); + } + } else if (policyParser.currentToken() == XContentParser.Token.START_ARRAY) { + List parsedValues = policyParser.list(); + parameterValues[0] = parsedValues; + } else { throw newPolicyParserException(scopeName, entitlementType, "expected entitlement parameters"); } } - Map parsedValues = policyParser.map(); - - Object[] parameterValues = new Object[parameterTypes.length]; - for (int parameterIndex = 0; parameterIndex < parameterTypes.length; ++parameterIndex) { - String parameterName = parametersNames[parameterIndex]; - Object parameterValue = parsedValues.remove(parameterName); - if (parameterValue == null) { - throw newPolicyParserException(scopeName, entitlementType, "missing entitlement parameter [" + parameterName + "]"); - } - Class parameterType = parameterTypes[parameterIndex]; - if (parameterType.isAssignableFrom(parameterValue.getClass()) == false) { - throw newPolicyParserException( - scopeName, - entitlementType, - "unexpected parameter type [" + parameterType.getSimpleName() + "] for entitlement parameter [" + parameterName + "]" - ); - } - parameterValues[parameterIndex] = parameterValue; - } - if (parsedValues.isEmpty() == false) { - throw newPolicyParserException(scopeName, entitlementType, "extraneous entitlement parameter(s) " + parsedValues); - } - try { if (entitlementConstructor != null) { return (Entitlement) entitlementConstructor.newInstance(parameterValues); diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java new file mode 100644 index 000000000000..953954ec3769 --- /dev/null +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.entitlement.runtime.policy.entitlements; + +import org.elasticsearch.entitlement.runtime.policy.ExternalEntitlement; +import org.elasticsearch.entitlement.runtime.policy.PolicyValidationException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Describes a file entitlement with a path and mode. + */ +public record FilesEntitlement(List filesData) implements Entitlement { + + public static final FilesEntitlement EMPTY = new FilesEntitlement(List.of()); + + public enum Mode { + READ, + READ_WRITE + } + + public record FileData(String path, Mode mode) { + + } + + private static Mode parseMode(String mode) { + if (mode.equals("read")) { + return Mode.READ; + } else if (mode.equals("read_write")) { + return Mode.READ_WRITE; + } else { + throw new PolicyValidationException("invalid mode: " + mode + ", valid values: [read, read_write]"); + } + } + + @ExternalEntitlement(parameterNames = { "paths" }, esModulesOnly = false) + @SuppressWarnings("unchecked") + public static FilesEntitlement build(List paths) { + if (paths == null || paths.isEmpty()) { + throw new PolicyValidationException("must specify at least one path"); + } + List filesData = new ArrayList<>(); + for (Object object : paths) { + Map file = new HashMap<>((Map) object); + String path = file.remove("path"); + if (path == null) { + throw new PolicyValidationException("files entitlement must contain path for every listed file"); + } + String mode = file.remove("mode"); + if (mode == null) { + throw new PolicyValidationException("files entitlement must contain mode for every listed file"); + } + if (file.isEmpty() == false) { + throw new PolicyValidationException("unknown key(s) " + file + " in a listed file for files entitlement"); + } + filesData.add(new FileData(path, parseMode(mode))); + } + return new FilesEntitlement(filesData); + } +} diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java index 48c03cfd2f9b..de3e2eafb756 100644 --- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java +++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java @@ -9,12 +9,15 @@ package org.elasticsearch.entitlement.runtime.policy; -import org.elasticsearch.entitlement.runtime.policy.entitlements.FileEntitlement; +import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement; import org.elasticsearch.test.ESTestCase; import org.junit.BeforeClass; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static org.elasticsearch.core.PathUtils.getDefaultFileSystem; import static org.hamcrest.Matchers.is; @@ -33,13 +36,13 @@ public class FileAccessTreeTests extends ESTestCase { } public void testEmpty() { - var tree = FileAccessTree.of(List.of()); + var tree = FileAccessTree.of(FilesEntitlement.EMPTY); assertThat(tree.canRead(path("path")), is(false)); assertThat(tree.canWrite(path("path")), is(false)); } public void testRead() { - var tree = FileAccessTree.of(List.of(entitlement("foo", "read"))); + var tree = FileAccessTree.of(entitlement("foo", "read")); assertThat(tree.canRead(path("foo")), is(true)); assertThat(tree.canRead(path("foo/subdir")), is(true)); assertThat(tree.canRead(path("food")), is(false)); @@ -51,7 +54,7 @@ public class FileAccessTreeTests extends ESTestCase { } public void testWrite() { - var tree = FileAccessTree.of(List.of(entitlement("foo", "read_write"))); + var tree = FileAccessTree.of(entitlement("foo", "read_write")); assertThat(tree.canWrite(path("foo")), is(true)); assertThat(tree.canWrite(path("foo/subdir")), is(true)); assertThat(tree.canWrite(path("food")), is(false)); @@ -63,7 +66,7 @@ public class FileAccessTreeTests extends ESTestCase { } public void testTwoPaths() { - var tree = FileAccessTree.of(List.of(entitlement("foo", "read"), entitlement("bar", "read"))); + var tree = FileAccessTree.of(entitlement("foo", "read", "bar", "read")); assertThat(tree.canRead(path("a")), is(false)); assertThat(tree.canRead(path("bar")), is(true)); assertThat(tree.canRead(path("bar/subdir")), is(true)); @@ -74,7 +77,7 @@ public class FileAccessTreeTests extends ESTestCase { } public void testReadWriteUnderRead() { - var tree = FileAccessTree.of(List.of(entitlement("foo", "read"), entitlement("foo/bar", "read_write"))); + var tree = FileAccessTree.of(entitlement("foo", "read", "foo/bar", "read_write")); assertThat(tree.canRead(path("foo")), is(true)); assertThat(tree.canWrite(path("foo")), is(false)); assertThat(tree.canRead(path("foo/bar")), is(true)); @@ -82,7 +85,7 @@ public class FileAccessTreeTests extends ESTestCase { } public void testNormalizePath() { - var tree = FileAccessTree.of(List.of(entitlement("foo/../bar", "read"))); + var tree = FileAccessTree.of(entitlement("foo/../bar", "read")); assertThat(tree.canRead(path("foo/../bar")), is(true)); assertThat(tree.canRead(path("foo")), is(false)); assertThat(tree.canRead(path("")), is(false)); @@ -90,7 +93,7 @@ public class FileAccessTreeTests extends ESTestCase { public void testForwardSlashes() { String sep = getDefaultFileSystem().getSeparator(); - var tree = FileAccessTree.of(List.of(entitlement("a/b", "read"), entitlement("m" + sep + "n", "read"))); + var tree = FileAccessTree.of(entitlement("a/b", "read", "m" + sep + "n", "read")); // Native separators work assertThat(tree.canRead(path("a" + sep + "b")), is(true)); @@ -99,13 +102,16 @@ public class FileAccessTreeTests extends ESTestCase { // Forward slashes also work assertThat(tree.canRead(path("a/b")), is(true)); assertThat(tree.canRead(path("m/n")), is(true)); - - // In case the native separator is a backslash, don't treat that as an escape - assertThat(tree.canRead(path("m\n")), is(false)); } - FileEntitlement entitlement(String path, String mode) { - Path p = path(path); - return FileEntitlement.create(p.toString(), mode); + FilesEntitlement entitlement(String... values) { + List filesData = new ArrayList<>(); + for (int i = 0; i < values.length; i += 2) { + Map fileData = new HashMap<>(); + fileData.put("path", path(values[i]).toString()); + fileData.put("mode", values[i + 1]); + filesData.add(fileData); + } + return FilesEntitlement.build(filesData); } } diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java index 12e3bf397a8a..34d069c98c7a 100644 --- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java +++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java @@ -14,7 +14,7 @@ import org.elasticsearch.entitlement.runtime.policy.agent.TestAgent; import org.elasticsearch.entitlement.runtime.policy.agent.inner.TestInnerAgent; import org.elasticsearch.entitlement.runtime.policy.entitlements.CreateClassLoaderEntitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.ExitVMEntitlement; -import org.elasticsearch.entitlement.runtime.policy.entitlements.FileEntitlement; +import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.compiler.InMemoryJavaCompiler; import org.elasticsearch.test.jar.JarUtils; @@ -293,7 +293,7 @@ public class PolicyManagerTests extends ESTestCase { } } - public void testDuplicateFlagEntitlements() { + public void testDuplicateEntitlements() { IllegalArgumentException iae = expectThrows( IllegalArgumentException.class, () -> new PolicyManager( @@ -309,7 +309,7 @@ public class PolicyManagerTests extends ESTestCase { ) ); assertEquals( - "[(server)] using module [test] found duplicate flag entitlements " + "[" + CreateClassLoaderEntitlement.class.getName() + "]", + "[(server)] using module [test] found duplicate entitlement " + "[" + CreateClassLoaderEntitlement.class.getName() + "]", iae.getMessage() ); @@ -325,10 +325,7 @@ public class PolicyManagerTests extends ESTestCase { ) ); assertEquals( - "[(APM agent)] using module [unnamed] found duplicate flag entitlements " - + "[" - + CreateClassLoaderEntitlement.class.getName() - + "]", + "[(APM agent)] using module [unnamed] found duplicate entitlement " + "[" + CreateClassLoaderEntitlement.class.getName() + "]", iae.getMessage() ); @@ -345,10 +342,9 @@ public class PolicyManagerTests extends ESTestCase { new Scope( "test", List.of( - new FileEntitlement("/test/path", FileEntitlement.Mode.READ), + FilesEntitlement.EMPTY, new CreateClassLoaderEntitlement(), - new FileEntitlement("/test/test", FileEntitlement.Mode.READ), - new CreateClassLoaderEntitlement() + new FilesEntitlement(List.of(new FilesEntitlement.FileData("test", FilesEntitlement.Mode.READ))) ) ) ) @@ -360,7 +356,7 @@ public class PolicyManagerTests extends ESTestCase { ) ); assertEquals( - "[plugin1] using module [test] found duplicate flag entitlements " + "[" + CreateClassLoaderEntitlement.class.getName() + "]", + "[plugin1] using module [test] found duplicate entitlement " + "[" + FilesEntitlement.class.getName() + "]", iae.getMessage() ); } @@ -407,7 +403,10 @@ public class PolicyManagerTests extends ESTestCase { .map( name -> new Scope( name, - List.of(new FileEntitlement("/test/path", FileEntitlement.Mode.READ), new CreateClassLoaderEntitlement()) + List.of( + new FilesEntitlement(List.of(new FilesEntitlement.FileData("/test/path", FilesEntitlement.Mode.READ))), + new CreateClassLoaderEntitlement() + ) ) ) .toList() diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyParserFailureTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyParserFailureTests.java index cc8043990930..4f479a9bf59a 100644 --- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyParserFailureTests.java +++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyParserFailureTests.java @@ -40,22 +40,12 @@ public class PolicyParserFailureTests extends ESTestCase { public void testEntitlementMissingParameter() { PolicyParserException ppe = expectThrows(PolicyParserException.class, () -> new PolicyParser(new ByteArrayInputStream(""" entitlement-module-name: - - file: {} + - files: + - path: test-path """.getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml", false).parsePolicy()); assertEquals( - "[2:12] policy parsing error for [test-failure-policy.yaml] in scope [entitlement-module-name] " - + "for entitlement type [file]: missing entitlement parameter [path]", - ppe.getMessage() - ); - - ppe = expectThrows(PolicyParserException.class, () -> new PolicyParser(new ByteArrayInputStream(""" - entitlement-module-name: - - file: - path: test-path - """.getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml", false).parsePolicy()); - assertEquals( - "[4:1] policy parsing error for [test-failure-policy.yaml] in scope [entitlement-module-name] " - + "for entitlement type [file]: missing entitlement parameter [mode]", + "[2:5] policy parsing error for [test-failure-policy.yaml] in scope [entitlement-module-name] " + + "for entitlement type [files]: files entitlement must contain mode for every listed file", ppe.getMessage() ); } @@ -63,14 +53,14 @@ public class PolicyParserFailureTests extends ESTestCase { public void testEntitlementExtraneousParameter() { PolicyParserException ppe = expectThrows(PolicyParserException.class, () -> new PolicyParser(new ByteArrayInputStream(""" entitlement-module-name: - - file: - path: test-path - mode: read - extra: test + - files: + - path: test-path + mode: read + extra: test """.getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml", false).parsePolicy()); assertEquals( - "[6:1] policy parsing error for [test-failure-policy.yaml] in scope [entitlement-module-name] " - + "for entitlement type [file]: extraneous entitlement parameter(s) {extra=test}", + "[2:5] policy parsing error for [test-failure-policy.yaml] in scope [entitlement-module-name] " + + "for entitlement type [files]: unknown key(s) {extra=test} in a listed file for files entitlement", ppe.getMessage() ); } diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyParserTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyParserTests.java index 85bffda369f3..e84c8ad2a83c 100644 --- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyParserTests.java +++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyParserTests.java @@ -11,7 +11,7 @@ package org.elasticsearch.entitlement.runtime.policy; import org.elasticsearch.entitlement.runtime.policy.entitlements.CreateClassLoaderEntitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.Entitlement; -import org.elasticsearch.entitlement.runtime.policy.entitlements.FileEntitlement; +import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.InboundNetworkEntitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.LoadNativeLibrariesEntitlement; import org.elasticsearch.entitlement.runtime.policy.entitlements.OutboundNetworkEntitlement; @@ -84,7 +84,12 @@ public class PolicyParserTests extends ESTestCase { .parsePolicy(); Policy expected = new Policy( "test-policy.yaml", - List.of(new Scope("entitlement-module-name", List.of(FileEntitlement.create("test/path/to/file", "read_write")))) + List.of( + new Scope( + "entitlement-module-name", + List.of(FilesEntitlement.build(List.of(Map.of("path", "test/path/to/file", "mode", "read_write")))) + ) + ) ); assertEquals(expected, parsedPolicy); } @@ -94,7 +99,12 @@ public class PolicyParserTests extends ESTestCase { .parsePolicy(); Policy expected = new Policy( "test-policy.yaml", - List.of(new Scope("entitlement-module-name", List.of(FileEntitlement.create("test/path/to/file", "read_write")))) + List.of( + new Scope( + "entitlement-module-name", + List.of(FilesEntitlement.build(List.of(Map.of("path", "test/path/to/file", "mode", "read_write")))) + ) + ) ); assertEquals(expected, parsedPolicy); } diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlementTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlementTests.java new file mode 100644 index 000000000000..5011fe2be462 --- /dev/null +++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlementTests.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.entitlement.runtime.policy.entitlements; + +import org.elasticsearch.entitlement.runtime.policy.PolicyValidationException; +import org.elasticsearch.test.ESTestCase; + +import java.util.List; + +public class FilesEntitlementTests extends ESTestCase { + + public void testEmptyBuild() { + PolicyValidationException pve = expectThrows(PolicyValidationException.class, () -> FilesEntitlement.build(List.of())); + assertEquals(pve.getMessage(), "must specify at least one path"); + pve = expectThrows(PolicyValidationException.class, () -> FilesEntitlement.build(null)); + assertEquals(pve.getMessage(), "must specify at least one path"); + } +} diff --git a/libs/entitlement/src/test/resources/org/elasticsearch/entitlement/runtime/policy/test-policy.yaml b/libs/entitlement/src/test/resources/org/elasticsearch/entitlement/runtime/policy/test-policy.yaml index bbb926ccdd37..6b1a5c22993f 100644 --- a/libs/entitlement/src/test/resources/org/elasticsearch/entitlement/runtime/policy/test-policy.yaml +++ b/libs/entitlement/src/test/resources/org/elasticsearch/entitlement/runtime/policy/test-policy.yaml @@ -1,4 +1,4 @@ entitlement-module-name: - - file: - path: "test/path/to/file" - mode: "read_write" + - files: + - path: "test/path/to/file" + mode: "read_write" diff --git a/libs/native/src/main/java/org/elasticsearch/nativeaccess/NativeAccessUtil.java b/libs/native/src/main/java/org/elasticsearch/nativeaccess/NativeAccessUtil.java index 5c1789f3aa66..c83c9a6234a7 100644 --- a/libs/native/src/main/java/org/elasticsearch/nativeaccess/NativeAccessUtil.java +++ b/libs/native/src/main/java/org/elasticsearch/nativeaccess/NativeAccessUtil.java @@ -11,11 +11,15 @@ package org.elasticsearch.nativeaccess; public class NativeAccessUtil { /** - * Enables native access for the provided module. No-op for JDK 21 or before. + * Enables native access for the provided module. + * We need to have this adapter even if the method is available in JDK 21, as it was in preview. + * Available to JDK 22+, required for JDK 24+ when using --illegal-native-access=deny */ - public static void enableNativeAccess(ModuleLayer.Controller controller, Module module) {} + public static void enableNativeAccess(ModuleLayer.Controller controller, Module module) { + controller.enableNativeAccess(module); + } public static boolean isNativeAccessEnabled(Module module) { - return true; + return module.isNativeAccessEnabled(); } } diff --git a/libs/native/src/main22/java/org/elasticsearch/nativeaccess/NativeAccessUtil.java b/libs/native/src/main22/java/org/elasticsearch/nativeaccess/NativeAccessUtil.java deleted file mode 100644 index 34776407f759..000000000000 --- a/libs/native/src/main22/java/org/elasticsearch/nativeaccess/NativeAccessUtil.java +++ /dev/null @@ -1,23 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -package org.elasticsearch.nativeaccess; - -public class NativeAccessUtil { - /** - * Enables native access for the provided module. Available to JDK 22+, required for JDK 24+ when using --illegal-native-access=deny - */ - public static void enableNativeAccess(ModuleLayer.Controller controller, Module module) { - controller.enableNativeAccess(module); - } - - public static boolean isNativeAccessEnabled(Module module) { - return module.isNativeAccessEnabled(); - } -} diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java index 79bfaec6a6d1..3e1815a74fbf 100644 --- a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java @@ -13,8 +13,6 @@ import org.elasticsearch.core.Nullable; import java.nio.file.Path; import java.security.KeyStore; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Set; @@ -25,7 +23,6 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; import static org.elasticsearch.common.ssl.KeyStoreUtil.inferKeyStoreType; -import static org.elasticsearch.common.ssl.SslConfiguration.ORDERED_PROTOCOL_ALGORITHM_MAP; import static org.elasticsearch.common.ssl.SslConfigurationKeys.CERTIFICATE; import static org.elasticsearch.common.ssl.SslConfigurationKeys.CERTIFICATE_AUTHORITIES; import static org.elasticsearch.common.ssl.SslConfigurationKeys.CIPHERS; @@ -63,11 +60,7 @@ import static org.elasticsearch.common.ssl.SslConfigurationKeys.VERIFICATION_MOD */ public abstract class SslConfigurationLoader { - static final List DEFAULT_PROTOCOLS = Collections.unmodifiableList( - ORDERED_PROTOCOL_ALGORITHM_MAP.containsKey("TLSv1.3") - ? Arrays.asList("TLSv1.3", "TLSv1.2", "TLSv1.1") - : Arrays.asList("TLSv1.2", "TLSv1.1") - ); + static final List DEFAULT_PROTOCOLS = List.of("TLSv1.3", "TLSv1.2"); private static final List JDK12_CIPHERS = List.of( // TLSv1.3 cipher has PFS, AEAD, hardware support diff --git a/modules/aggregations/src/main/java/org/elasticsearch/aggregations/bucket/histogram/AutoDateHistogramAggregator.java b/modules/aggregations/src/main/java/org/elasticsearch/aggregations/bucket/histogram/AutoDateHistogramAggregator.java index 6add1b0ac4a1..abd482d8298e 100644 --- a/modules/aggregations/src/main/java/org/elasticsearch/aggregations/bucket/histogram/AutoDateHistogramAggregator.java +++ b/modules/aggregations/src/main/java/org/elasticsearch/aggregations/bucket/histogram/AutoDateHistogramAggregator.java @@ -35,6 +35,7 @@ import org.elasticsearch.search.aggregations.bucket.terms.LongKeyedBucketOrds; import org.elasticsearch.search.aggregations.support.AggregationContext; import org.elasticsearch.search.aggregations.support.ValuesSource; import org.elasticsearch.search.aggregations.support.ValuesSourceConfig; +import org.elasticsearch.tasks.TaskCancelledException; import java.io.IOException; import java.util.Collections; @@ -573,7 +574,15 @@ abstract class AutoDateHistogramAggregator extends DeferableBucketAggregator { long[] mergeMap = new long[Math.toIntExact(oldOrds.size())]; bucketOrds = new LongKeyedBucketOrds.FromMany(bigArrays()); success = true; - for (long owningBucketOrd = 0; owningBucketOrd <= oldOrds.maxOwningBucketOrd(); owningBucketOrd++) { + long maxOwning = oldOrds.maxOwningBucketOrd(); + for (long owningBucketOrd = 0; owningBucketOrd <= maxOwning; owningBucketOrd++) { + /* + * Check for cancelation during this tight loop as it can take a while and the standard + * cancelation checks don't run during the loop. Becuase it's a tight loop. + */ + if (context.isCancelled()) { + throw new TaskCancelledException("cancelled"); + } LongKeyedBucketOrds.BucketOrdsEnum ordsEnum = oldOrds.ordsEnum(owningBucketOrd); Rounding.Prepared preparedRounding = preparedRoundings[roundingIndexFor(owningBucketOrd)]; while (ordsEnum.next()) { diff --git a/modules/aggregations/src/test/java/org/elasticsearch/aggregations/metric/MatrixStatsAggregatorTests.java b/modules/aggregations/src/test/java/org/elasticsearch/aggregations/metric/MatrixStatsAggregatorTests.java index 74c1f3c16278..2eb21cfc0965 100644 --- a/modules/aggregations/src/test/java/org/elasticsearch/aggregations/metric/MatrixStatsAggregatorTests.java +++ b/modules/aggregations/src/test/java/org/elasticsearch/aggregations/metric/MatrixStatsAggregatorTests.java @@ -36,7 +36,7 @@ public class MatrixStatsAggregatorTests extends AggregationTestCase { MatrixStatsAggregationBuilder aggBuilder = new MatrixStatsAggregationBuilder("my_agg").fields( Collections.singletonList("field") ); - InternalMatrixStats stats = searchAndReduce(reader, new AggTestConfig(aggBuilder, ft)); + InternalMatrixStats stats = searchAndReduce(reader, new AggTestConfig(aggBuilder, ft).noReductionCancellation()); assertNull(stats.getStats()); assertEquals(0L, stats.getDocCount()); } @@ -54,7 +54,7 @@ public class MatrixStatsAggregatorTests extends AggregationTestCase { MatrixStatsAggregationBuilder aggBuilder = new MatrixStatsAggregationBuilder("my_agg").fields( Collections.singletonList("bogus") ); - InternalMatrixStats stats = searchAndReduce(reader, new AggTestConfig(aggBuilder, ft)); + InternalMatrixStats stats = searchAndReduce(reader, new AggTestConfig(aggBuilder, ft).noReductionCancellation()); assertNull(stats.getStats()); assertEquals(0L, stats.getDocCount()); } @@ -88,7 +88,7 @@ public class MatrixStatsAggregatorTests extends AggregationTestCase { MatrixStatsAggregationBuilder aggBuilder = new MatrixStatsAggregationBuilder("my_agg").fields( Arrays.asList(fieldA, fieldB) ); - InternalMatrixStats stats = searchAndReduce(reader, new AggTestConfig(aggBuilder, ftA, ftB)); + InternalMatrixStats stats = searchAndReduce(reader, new AggTestConfig(aggBuilder, ftA, ftB).noReductionCancellation()); multiPassStats.assertNearlyEqual(stats); assertTrue(MatrixAggregationInspectionHelper.hasValue(stats)); } diff --git a/modules/ingest-geoip/build.gradle b/modules/ingest-geoip/build.gradle index 988ca317b473..bdda4872fb4d 100644 --- a/modules/ingest-geoip/build.gradle +++ b/modules/ingest-geoip/build.gradle @@ -28,12 +28,12 @@ tasks.named('internalClusterTestTestingConventions').configure { } dependencies { - implementation('com.maxmind.geoip2:geoip2:4.2.0') + implementation('com.maxmind.geoip2:geoip2:4.2.1') // geoip2 dependencies: runtimeOnly("com.fasterxml.jackson.core:jackson-annotations:${versions.jackson}") runtimeOnly("com.fasterxml.jackson.core:jackson-databind:${versions.jackson}") runtimeOnly("com.fasterxml.jackson.core:jackson-core:${versions.jackson}") - implementation('com.maxmind.db:maxmind-db:3.1.0') + implementation('com.maxmind.db:maxmind-db:3.1.1') testImplementation 'org.elasticsearch:geolite2-databases:20191119' internalClusterTestImplementation project(':modules:reindex') diff --git a/modules/ingest-geoip/qa/file-based-update/src/javaRestTest/resources/GeoLite2-City-Test.mmdb b/modules/ingest-geoip/qa/file-based-update/src/javaRestTest/resources/GeoLite2-City-Test.mmdb index 0809201619b5..40c7eb0c47f9 100644 Binary files a/modules/ingest-geoip/qa/file-based-update/src/javaRestTest/resources/GeoLite2-City-Test.mmdb and b/modules/ingest-geoip/qa/file-based-update/src/javaRestTest/resources/GeoLite2-City-Test.mmdb differ diff --git a/modules/ingest-geoip/qa/full-cluster-restart/src/javaRestTest/java/org/elasticsearch/ingest/geoip/FullClusterRestartIT.java b/modules/ingest-geoip/qa/full-cluster-restart/src/javaRestTest/java/org/elasticsearch/ingest/geoip/FullClusterRestartIT.java index 6a28a09dc7c6..9525eed7f2eb 100644 --- a/modules/ingest-geoip/qa/full-cluster-restart/src/javaRestTest/java/org/elasticsearch/ingest/geoip/FullClusterRestartIT.java +++ b/modules/ingest-geoip/qa/full-cluster-restart/src/javaRestTest/java/org/elasticsearch/ingest/geoip/FullClusterRestartIT.java @@ -119,10 +119,16 @@ public class FullClusterRestartIT extends ParameterizedFullClusterRestartTestCas // before the upgrade, Kibana should work assertBusy(() -> testGetStarAsKibana(List.of("my-index-00001"), maybeSecurityIndex)); + + // as should a normal get * + assertBusy(() -> testGetStar(List.of("my-index-00001"), maybeSecurityIndex)); } else { // after the upgrade, but before the migration, Kibana should work assertBusy(() -> testGetStarAsKibana(List.of("my-index-00001"), maybeSecurityIndex)); + // as should a normal get * + assertBusy(() -> testGetStar(List.of("my-index-00001"), maybeSecurityIndex)); + // migrate the system features and give the cluster a moment to settle Request migrateSystemFeatures = new Request("POST", "/_migration/system_features"); assertOK(client().performRequest(migrateSystemFeatures)); @@ -132,9 +138,10 @@ public class FullClusterRestartIT extends ParameterizedFullClusterRestartTestCas assertBusy(() -> testIndexGeoDoc()); // after the migration, Kibana should work - if (useSecurity == false) { // BUT IT DOESN'T if security is enabled - assertBusy(() -> testGetStarAsKibana(List.of("my-index-00001"), maybeSecurityIndexReindexed)); - } + assertBusy(() -> testGetStarAsKibana(List.of("my-index-00001"), maybeSecurityIndexReindexed)); + + // as should a normal get * + assertBusy(() -> testGetStar(List.of("my-index-00001"), maybeSecurityIndexReindexed)); Request disableDownloader = new Request("PUT", "/_cluster/settings"); disableDownloader.setJsonEntity(""" @@ -213,6 +220,23 @@ public class FullClusterRestartIT extends ParameterizedFullClusterRestartTestCas assertEquals("Sweden", doc.evaluate("_source.geo.country_name")); } + private void testGetStar(List indexNames, @Nullable List additionalIndexNames) throws IOException { + Request getStar = new Request("GET", "*?expand_wildcards=all"); + getStar.setOptions( + RequestOptions.DEFAULT.toBuilder().setWarningsHandler(WarningsHandler.PERMISSIVE) // we don't care about warnings, just errors + ); + Response response = client().performRequest(getStar); + assertOK(response); + + if (additionalIndexNames != null && additionalIndexNames.isEmpty() == false) { + indexNames = new ArrayList<>(indexNames); // recopy into a mutable list + indexNames.addAll(additionalIndexNames); + } + + Map map = responseAsMap(response); + assertThat(map.keySet(), is(new HashSet<>(indexNames))); + } + private void testGetStarAsKibana(List indexNames, @Nullable List additionalIndexNames) throws IOException { Request getStar = new Request("GET", "*?expand_wildcards=all"); getStar.setOptions( diff --git a/modules/ingest-geoip/src/internalClusterTest/java/org/elasticsearch/ingest/geoip/GeoIpDownloaderIT.java b/modules/ingest-geoip/src/internalClusterTest/java/org/elasticsearch/ingest/geoip/GeoIpDownloaderIT.java index 3bcc9f435534..daba9c4e5e15 100644 --- a/modules/ingest-geoip/src/internalClusterTest/java/org/elasticsearch/ingest/geoip/GeoIpDownloaderIT.java +++ b/modules/ingest-geoip/src/internalClusterTest/java/org/elasticsearch/ingest/geoip/GeoIpDownloaderIT.java @@ -391,18 +391,18 @@ public class GeoIpDownloaderIT extends AbstractGeoIpIT { assertThat( files, containsInAnyOrder( - "GeoLite2-City.mmdb", - "GeoLite2-Country.mmdb", "GeoLite2-ASN.mmdb", - "MyCustomGeoLite2-City.mmdb", - "GeoLite2-City.mmdb_COPYRIGHT.txt", - "GeoLite2-Country.mmdb_COPYRIGHT.txt", "GeoLite2-ASN.mmdb_COPYRIGHT.txt", - "MyCustomGeoLite2-City.mmdb_COPYRIGHT.txt", - "GeoLite2-City.mmdb_LICENSE.txt", - "GeoLite2-Country.mmdb_LICENSE.txt", "GeoLite2-ASN.mmdb_LICENSE.txt", - "GeoLite2-ASN.mmdb_README.txt", + "GeoLite2-City.mmdb", + "GeoLite2-City.mmdb_COPYRIGHT.txt", + "GeoLite2-City.mmdb_LICENSE.txt", + "GeoLite2-City.mmdb_README.txt", + "GeoLite2-Country.mmdb", + "GeoLite2-Country.mmdb_COPYRIGHT.txt", + "GeoLite2-Country.mmdb_LICENSE.txt", + "MyCustomGeoLite2-City.mmdb", + "MyCustomGeoLite2-City.mmdb_COPYRIGHT.txt", "MyCustomGeoLite2-City.mmdb_LICENSE.txt" ) ); diff --git a/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/IpinfoIpDataLookupsTests.java b/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/IpinfoIpDataLookupsTests.java index 11aa123824d1..5d45ff5d5585 100644 --- a/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/IpinfoIpDataLookupsTests.java +++ b/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/IpinfoIpDataLookupsTests.java @@ -104,16 +104,16 @@ public class IpinfoIpDataLookupsTests extends ESTestCase { public void testAsnFree() { assumeFalse("https://github.com/elastic/elasticsearch/issues/114266", Constants.WINDOWS); String databaseName = "ip_asn_sample.mmdb"; - String ip = "23.32.184.0"; + String ip = "23.200.217.1"; assertExpectedLookupResults( databaseName, ip, new IpinfoIpDataLookups.Asn(Database.AsnV2.properties()), Map.ofEntries( entry("ip", ip), - entry("organization_name", "Akamai Technologies, Inc."), - entry("asn", 16625L), - entry("network", "23.32.184.0/21"), + entry("organization_name", "Akamai Technologies Tokyo ASN"), + entry("asn", 24319L), + entry("network", "23.200.217.0/24"), entry("domain", "akamai.com") ), Map.ofEntries(entry("name", "organization_name"), entry("asn", "asn"), entry("network", "network"), entry("domain", "domain")), @@ -125,17 +125,17 @@ public class IpinfoIpDataLookupsTests extends ESTestCase { public void testAsnStandard() { assumeFalse("https://github.com/elastic/elasticsearch/issues/114266", Constants.WINDOWS); String databaseName = "asn_sample.mmdb"; - String ip = "69.19.224.0"; + String ip = "207.244.150.1"; assertExpectedLookupResults( databaseName, ip, new IpinfoIpDataLookups.Asn(Database.AsnV2.properties()), Map.ofEntries( entry("ip", ip), - entry("organization_name", "TPx Communications"), - entry("asn", 14265L), - entry("network", "69.19.224.0/22"), - entry("domain", "tpx.com"), + entry("organization_name", "Wowrack.com"), + entry("asn", 23033L), + entry("network", "207.244.150.0/23"), + entry("domain", "wowrack.com"), entry("type", "hosting"), entry("country_iso_code", "US") ), @@ -192,15 +192,15 @@ public class IpinfoIpDataLookupsTests extends ESTestCase { public void testCountryFree() { assumeFalse("https://github.com/elastic/elasticsearch/issues/114266", Constants.WINDOWS); String databaseName = "ip_country_sample.mmdb"; - String ip = "20.33.76.0"; + String ip = "149.7.32.1"; assertExpectedLookupResults( databaseName, ip, new IpinfoIpDataLookups.Country(Database.CountryV2.properties()), Map.ofEntries( entry("ip", ip), - entry("country_name", "Ireland"), - entry("country_iso_code", "IE"), + entry("country_name", "United Kingdom"), + entry("country_iso_code", "GB"), entry("continent_name", "Europe"), entry("continent_code", "EU") ), @@ -289,14 +289,14 @@ public class IpinfoIpDataLookupsTests extends ESTestCase { public void testPrivacyDetectionStandard() { assumeFalse("https://github.com/elastic/elasticsearch/issues/114266", Constants.WINDOWS); String databaseName = "privacy_detection_sample.mmdb"; - String ip = "2.57.109.154"; + String ip = "20.102.24.249"; assertExpectedLookupResults( databaseName, ip, new IpinfoIpDataLookups.PrivacyDetection(Database.PrivacyDetection.properties()), Map.ofEntries( entry("ip", ip), - entry("hosting", false), + entry("hosting", true), entry("proxy", false), entry("relay", false), entry("tor", false), @@ -317,7 +317,7 @@ public class IpinfoIpDataLookupsTests extends ESTestCase { public void testPrivacyDetectionStandardNonEmptyService() { assumeFalse("https://github.com/elastic/elasticsearch/issues/114266", Constants.WINDOWS); String databaseName = "privacy_detection_sample.mmdb"; - String ip = "59.29.201.246"; + String ip = "14.52.64.231"; assertExpectedLookupResults( databaseName, ip, diff --git a/modules/ingest-geoip/src/test/resources/GeoIP2-Anonymous-IP-Test.mmdb b/modules/ingest-geoip/src/test/resources/GeoIP2-Anonymous-IP-Test.mmdb index 1b142d0001b9..460e58ee5659 100644 Binary files a/modules/ingest-geoip/src/test/resources/GeoIP2-Anonymous-IP-Test.mmdb and b/modules/ingest-geoip/src/test/resources/GeoIP2-Anonymous-IP-Test.mmdb differ diff --git a/modules/ingest-geoip/src/test/resources/GeoIP2-City-Test.mmdb b/modules/ingest-geoip/src/test/resources/GeoIP2-City-Test.mmdb index 04220ff4b641..67dcd4a8e5a1 100644 Binary files a/modules/ingest-geoip/src/test/resources/GeoIP2-City-Test.mmdb and b/modules/ingest-geoip/src/test/resources/GeoIP2-City-Test.mmdb differ diff --git a/modules/ingest-geoip/src/test/resources/GeoIP2-Connection-Type-Test.mmdb b/modules/ingest-geoip/src/test/resources/GeoIP2-Connection-Type-Test.mmdb index c49ca3ad48f3..4d0a477a623a 100644 Binary files a/modules/ingest-geoip/src/test/resources/GeoIP2-Connection-Type-Test.mmdb and b/modules/ingest-geoip/src/test/resources/GeoIP2-Connection-Type-Test.mmdb differ diff --git a/modules/ingest-geoip/src/test/resources/GeoIP2-Country-Test.mmdb b/modules/ingest-geoip/src/test/resources/GeoIP2-Country-Test.mmdb index 0b1f6cf50b2a..8b1436b0c387 100644 Binary files a/modules/ingest-geoip/src/test/resources/GeoIP2-Country-Test.mmdb and b/modules/ingest-geoip/src/test/resources/GeoIP2-Country-Test.mmdb differ diff --git a/modules/ingest-geoip/src/test/resources/GeoIP2-Domain-Test.mmdb b/modules/ingest-geoip/src/test/resources/GeoIP2-Domain-Test.mmdb index 596a96617f24..0aaccefa7fec 100644 Binary files a/modules/ingest-geoip/src/test/resources/GeoIP2-Domain-Test.mmdb and b/modules/ingest-geoip/src/test/resources/GeoIP2-Domain-Test.mmdb differ diff --git a/modules/ingest-geoip/src/test/resources/GeoIP2-Enterprise-Test.mmdb b/modules/ingest-geoip/src/test/resources/GeoIP2-Enterprise-Test.mmdb index 16c1acf80026..e0a99f6ba94e 100644 Binary files a/modules/ingest-geoip/src/test/resources/GeoIP2-Enterprise-Test.mmdb and b/modules/ingest-geoip/src/test/resources/GeoIP2-Enterprise-Test.mmdb differ diff --git a/modules/ingest-geoip/src/test/resources/GeoIP2-ISP-Test.mmdb b/modules/ingest-geoip/src/test/resources/GeoIP2-ISP-Test.mmdb index a4277d0a55c4..f9eaa14cee3a 100644 Binary files a/modules/ingest-geoip/src/test/resources/GeoIP2-ISP-Test.mmdb and b/modules/ingest-geoip/src/test/resources/GeoIP2-ISP-Test.mmdb differ diff --git a/modules/ingest-geoip/src/test/resources/GeoLite2-ASN-Test.mmdb b/modules/ingest-geoip/src/test/resources/GeoLite2-ASN-Test.mmdb index 2614d1a7aa23..af37b8ae278f 100644 Binary files a/modules/ingest-geoip/src/test/resources/GeoLite2-ASN-Test.mmdb and b/modules/ingest-geoip/src/test/resources/GeoLite2-ASN-Test.mmdb differ diff --git a/modules/ingest-geoip/src/test/resources/GeoLite2-City-Test.mmdb b/modules/ingest-geoip/src/test/resources/GeoLite2-City-Test.mmdb index 393efe464b61..40c7eb0c47f9 100644 Binary files a/modules/ingest-geoip/src/test/resources/GeoLite2-City-Test.mmdb and b/modules/ingest-geoip/src/test/resources/GeoLite2-City-Test.mmdb differ diff --git a/modules/ingest-geoip/src/test/resources/GeoLite2-Country-Test.mmdb b/modules/ingest-geoip/src/test/resources/GeoLite2-Country-Test.mmdb index 44b5ff1a3f1b..ef614ec16c3f 100644 Binary files a/modules/ingest-geoip/src/test/resources/GeoLite2-Country-Test.mmdb and b/modules/ingest-geoip/src/test/resources/GeoLite2-Country-Test.mmdb differ diff --git a/modules/ingest-geoip/src/test/resources/ipinfo/asn_sample.mmdb b/modules/ingest-geoip/src/test/resources/ipinfo/asn_sample.mmdb index 289318a124d7..6f93d59731f1 100644 Binary files a/modules/ingest-geoip/src/test/resources/ipinfo/asn_sample.mmdb and b/modules/ingest-geoip/src/test/resources/ipinfo/asn_sample.mmdb differ diff --git a/modules/ingest-geoip/src/test/resources/ipinfo/ip_asn_sample.mmdb b/modules/ingest-geoip/src/test/resources/ipinfo/ip_asn_sample.mmdb index d2bac8452a0f..fb52368827f6 100644 Binary files a/modules/ingest-geoip/src/test/resources/ipinfo/ip_asn_sample.mmdb and b/modules/ingest-geoip/src/test/resources/ipinfo/ip_asn_sample.mmdb differ diff --git a/modules/ingest-geoip/src/test/resources/ipinfo/ip_country_sample.mmdb b/modules/ingest-geoip/src/test/resources/ipinfo/ip_country_sample.mmdb index caa218f02770..507ac2b5eac2 100644 Binary files a/modules/ingest-geoip/src/test/resources/ipinfo/ip_country_sample.mmdb and b/modules/ingest-geoip/src/test/resources/ipinfo/ip_country_sample.mmdb differ diff --git a/modules/ingest-geoip/src/test/resources/ipinfo/privacy_detection_sample.mmdb b/modules/ingest-geoip/src/test/resources/ipinfo/privacy_detection_sample.mmdb index 4f2fca5559e1..9ab67cc88ba2 100644 Binary files a/modules/ingest-geoip/src/test/resources/ipinfo/privacy_detection_sample.mmdb and b/modules/ingest-geoip/src/test/resources/ipinfo/privacy_detection_sample.mmdb differ diff --git a/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/AbstractFeatureMigrationIntegTest.java b/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/AbstractFeatureMigrationIntegTest.java index d079b2daad38..314d41a6c75e 100644 --- a/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/AbstractFeatureMigrationIntegTest.java +++ b/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/AbstractFeatureMigrationIntegTest.java @@ -9,14 +9,17 @@ package org.elasticsearch.migration; +import org.elasticsearch.ElasticsearchException; import org.elasticsearch.Version; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.admin.cluster.migration.TransportGetFeatureUpgradeStatusAction; import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.stats.IndexStats; import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; import org.elasticsearch.action.index.IndexRequestBuilder; +import org.elasticsearch.action.support.ActionFilter; import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.client.internal.Client; import org.elasticsearch.cluster.ClusterState; @@ -28,6 +31,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.IndexVersion; import org.elasticsearch.indices.AssociatedIndexDescriptor; import org.elasticsearch.indices.SystemIndexDescriptor; +import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.PluginsService; import org.elasticsearch.plugins.SystemIndexPlugin; @@ -50,6 +54,10 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.function.Function; +import static java.util.Collections.emptySet; +import static java.util.Collections.singletonList; +import static java.util.Collections.unmodifiableSet; +import static org.elasticsearch.common.util.set.Sets.newHashSet; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.equalTo; @@ -255,12 +263,18 @@ public abstract class AbstractFeatureMigrationIntegTest extends ESIntegTestCase assertThat(thisIndexStats.getTotal().getDocs().getCount(), is((long) INDEX_DOC_COUNT)); } - public static class TestPlugin extends Plugin implements SystemIndexPlugin { + public static class TestPlugin extends Plugin implements SystemIndexPlugin, ActionPlugin { public final AtomicReference>> preMigrationHook = new AtomicReference<>(); public final AtomicReference>> postMigrationHook = new AtomicReference<>(); + private final BlockingActionFilter blockingActionFilter; public TestPlugin() { + blockingActionFilter = new BlockingActionFilter(); + } + @Override + public List getActionFilters() { + return singletonList(blockingActionFilter); } @Override @@ -299,5 +313,26 @@ public abstract class AbstractFeatureMigrationIntegTest extends ESIntegTestCase postMigrationHook.get().accept(clusterService.state(), preUpgradeMetadata); listener.onResponse(true); } + + public static class BlockingActionFilter extends org.elasticsearch.action.support.ActionFilter.Simple { + private Set blockedActions = emptySet(); + + @Override + protected boolean apply(String action, ActionRequest request, ActionListener listener) { + if (blockedActions.contains(action)) { + throw new ElasticsearchException("force exception on [" + action + "]"); + } + return true; + } + + @Override + public int order() { + return 0; + } + + public void blockActions(String... actions) { + blockedActions = unmodifiableSet(newHashSet(actions)); + } + } } } diff --git a/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/FeatureMigrationIT.java b/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/FeatureMigrationIT.java index a5b9d437bc76..aa412ef81e1d 100644 --- a/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/FeatureMigrationIT.java +++ b/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/FeatureMigrationIT.java @@ -17,11 +17,14 @@ import org.elasticsearch.action.admin.cluster.migration.PostFeatureUpgradeAction import org.elasticsearch.action.admin.cluster.migration.PostFeatureUpgradeRequest; import org.elasticsearch.action.admin.cluster.migration.PostFeatureUpgradeResponse; import org.elasticsearch.action.admin.indices.alias.Alias; +import org.elasticsearch.action.admin.indices.alias.TransportIndicesAliasesAction; import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.template.put.PutComponentTemplateAction; import org.elasticsearch.action.admin.indices.template.put.TransportPutComposableIndexTemplateAction; import org.elasticsearch.action.search.SearchRequestBuilder; +import org.elasticsearch.action.support.ActionFilter; +import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterStateUpdateTask; @@ -36,10 +39,12 @@ import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.indices.SystemIndexDescriptor; +import org.elasticsearch.migration.AbstractFeatureMigrationIntegTest.TestPlugin.BlockingActionFilter; import org.elasticsearch.painless.PainlessPlugin; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.SystemIndexPlugin; import org.elasticsearch.reindex.ReindexPlugin; +import org.elasticsearch.test.InternalTestCluster; import org.elasticsearch.upgrades.FeatureMigrationResults; import org.elasticsearch.upgrades.SingleFeatureMigrationResult; @@ -272,6 +277,60 @@ public class FeatureMigrationIT extends AbstractFeatureMigrationIntegTest { }); } + @AwaitsFix(bugUrl = "ES-10666") // This test uncovered an existing issue + public void testIndexBlockIsRemovedWhenAliasRequestFails() throws Exception { + createSystemIndexForDescriptor(INTERNAL_UNMANAGED); + ensureGreen(); + + // Block the alias request to simulate a failure + InternalTestCluster internalTestCluster = internalCluster(); + ActionFilters actionFilters = internalTestCluster.getInstance(ActionFilters.class, internalTestCluster.getMasterName()); + BlockingActionFilter blockingActionFilter = null; + for (ActionFilter filter : actionFilters.filters()) { + if (filter instanceof BlockingActionFilter) { + blockingActionFilter = (BlockingActionFilter) filter; + break; + } + } + assertNotNull("BlockingActionFilter should exist", blockingActionFilter); + blockingActionFilter.blockActions(TransportIndicesAliasesAction.NAME); + + // Start the migration + client().execute(PostFeatureUpgradeAction.INSTANCE, new PostFeatureUpgradeRequest(TEST_REQUEST_TIMEOUT)).get(); + + // Wait till the migration fails + assertBusy(() -> { + GetFeatureUpgradeStatusResponse statusResp = client().execute( + GetFeatureUpgradeStatusAction.INSTANCE, + new GetFeatureUpgradeStatusRequest(TEST_REQUEST_TIMEOUT) + ).get(); + logger.info(Strings.toString(statusResp)); + assertThat(statusResp.getUpgradeStatus(), equalTo(GetFeatureUpgradeStatusResponse.UpgradeStatus.ERROR)); + }); + + // Get the settings to see if the write block was removed + var allsettings = client().admin().indices().prepareGetSettings(INTERNAL_UNMANAGED.getIndexPattern()).get().getIndexToSettings(); + var internalUnmanagedOldIndexSettings = allsettings.get(".int-unman-old"); + var writeBlock = internalUnmanagedOldIndexSettings.get(IndexMetadata.INDEX_BLOCKS_WRITE_SETTING.getKey()); + assertThat("Write block on old index should be removed on migration ERROR status", writeBlock, equalTo("false")); + + // Unblock the alias request + blockingActionFilter.blockActions(); + + // Retry the migration + client().execute(PostFeatureUpgradeAction.INSTANCE, new PostFeatureUpgradeRequest(TEST_REQUEST_TIMEOUT)).get(); + + // Ensure that the migration is successful after the alias request is unblocked + assertBusy(() -> { + GetFeatureUpgradeStatusResponse statusResp = client().execute( + GetFeatureUpgradeStatusAction.INSTANCE, + new GetFeatureUpgradeStatusRequest(TEST_REQUEST_TIMEOUT) + ).get(); + logger.info(Strings.toString(statusResp)); + assertThat(statusResp.getUpgradeStatus(), equalTo(GetFeatureUpgradeStatusResponse.UpgradeStatus.NO_MIGRATION_NEEDED)); + }); + } + public void testMigrationWillRunAfterError() throws Exception { createSystemIndexForDescriptor(INTERNAL_MANAGED); diff --git a/muted-tests.yml b/muted-tests.yml index 7ab855ac5c29..06e913bd8631 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -104,9 +104,6 @@ tests: - class: org.elasticsearch.discovery.ClusterDisruptionIT method: testAckedIndexing issue: https://github.com/elastic/elasticsearch/issues/117024 -- class: org.elasticsearch.xpack.test.rest.XPackRestIT - method: test {p0=snapshot/10_basic/Create a source only snapshot and then restore it} - issue: https://github.com/elastic/elasticsearch/issues/117295 - class: org.elasticsearch.xpack.inference.InferenceRestIT method: test {p0=inference/40_semantic_text_query/Query a field that uses the default ELSER 2 endpoint} issue: https://github.com/elastic/elasticsearch/issues/117027 @@ -134,17 +131,9 @@ tests: - class: org.elasticsearch.datastreams.DataStreamsClientYamlTestSuiteIT method: test {p0=data_stream/120_data_streams_stats/Multiple data stream} issue: https://github.com/elastic/elasticsearch/issues/118217 - # TODO: re-enable after backporting https://github.com/elastic/elasticsearch/pull/119110 -- class: org.elasticsearch.test.rest.ClientYamlTestSuiteIT - method: test {yaml=update/100_synthetic_source/keyword} - # TODO: re-enable after backporting https://github.com/elastic/elasticsearch/pull/119110 -- class: org.elasticsearch.test.rest.ClientYamlTestSuiteIT - method: test {yaml=update/100_synthetic_source/stored text} - class: org.elasticsearch.xpack.searchablesnapshots.RetrySearchIntegTests method: testSearcherId issue: https://github.com/elastic/elasticsearch/issues/118374 -- class: org.elasticsearch.xpack.esql.action.EsqlActionBreakerIT - issue: https://github.com/elastic/elasticsearch/issues/118238 - class: org.elasticsearch.xpack.ccr.rest.ShardChangesRestIT method: testShardChangesNoOperation issue: https://github.com/elastic/elasticsearch/issues/118800 @@ -209,9 +198,6 @@ tests: issue: https://github.com/elastic/elasticsearch/issues/120668 - class: org.elasticsearch.xpack.security.authc.ldap.ADLdapUserSearchSessionFactoryTests issue: https://github.com/elastic/elasticsearch/issues/119882 -- class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncEnrichStopIT - method: testEnrichAfterStop - issue: https://github.com/elastic/elasticsearch/issues/120757 - class: org.elasticsearch.xpack.test.rest.XPackRestIT method: test {p0=ml/3rd_party_deployment/Test start deployment fails while model download in progress} issue: https://github.com/elastic/elasticsearch/issues/120810 @@ -282,9 +268,6 @@ tests: - class: org.elasticsearch.xpack.ml.integration.ClassificationIT method: testWithDatastreams issue: https://github.com/elastic/elasticsearch/issues/121236 -- class: org.elasticsearch.xpack.remotecluster.RemoteClusterSecurityEsqlIT - method: testCrossClusterAsyncQueryStop - issue: https://github.com/elastic/elasticsearch/issues/121249 - class: org.elasticsearch.xpack.test.rest.XPackRestIT method: test {p0=transform/*} issue: https://github.com/elastic/elasticsearch/issues/120816 @@ -367,32 +350,74 @@ tests: - class: org.elasticsearch.xpack.ml.integration.ClassificationIT method: testDependentVariableIsAliasToKeyword issue: https://github.com/elastic/elasticsearch/issues/121492 -- class: org.elasticsearch.xpack.esql.action.CrossClusterQueryUnavailableRemotesIT - method: testRemoteOnlyCCSAgainstDisconnectedRemoteWithSkipUnavailableTrue - issue: https://github.com/elastic/elasticsearch/issues/121578 -- class: org.elasticsearch.xpack.esql.action.CrossClustersCancellationIT - method: testTasks - issue: https://github.com/elastic/elasticsearch/issues/121626 -- class: org.elasticsearch.xpack.esql.action.CrossClustersCancellationIT - method: testCloseSkipUnavailable - issue: https://github.com/elastic/elasticsearch/issues/121627 -- class: org.elasticsearch.xpack.esql.action.CrossClustersCancellationIT - method: testCancel - issue: https://github.com/elastic/elasticsearch/issues/121632 -- class: org.elasticsearch.xpack.esql.action.CrossClustersCancellationIT - method: testCancelSkipUnavailable - issue: https://github.com/elastic/elasticsearch/issues/121631 - class: org.elasticsearch.search.CrossClusterSearchUnavailableClusterIT method: testSearchSkipUnavailable issue: https://github.com/elastic/elasticsearch/issues/121497 +- class: org.elasticsearch.smoketest.DocsClientYamlTestSuiteIT + method: test {yaml=reference/cat/health/cat-health-no-timestamp-example} + issue: https://github.com/elastic/elasticsearch/issues/121867 +- class: org.elasticsearch.analysis.common.CommonAnalysisClientYamlTestSuiteIT + method: test {yaml=analysis-common/40_token_filters/stemmer_override file access} + issue: https://github.com/elastic/elasticsearch/issues/121625 +- class: org.elasticsearch.xpack.searchablesnapshots.hdfs.SecureHdfsSearchableSnapshotsIT + issue: https://github.com/elastic/elasticsearch/issues/121967 +- class: org.elasticsearch.action.search.SearchQueryThenFetchAsyncActionTests + method: testBottomFieldSort + issue: https://github.com/elastic/elasticsearch/issues/121503 +- class: org.elasticsearch.xpack.application.CohereServiceUpgradeIT + issue: https://github.com/elastic/elasticsearch/issues/121537 +- class: org.elasticsearch.xpack.restart.FullClusterRestartIT + method: testWatcherWithApiKey {cluster=UPGRADED} + issue: https://github.com/elastic/elasticsearch/issues/122061 +- class: org.elasticsearch.test.rest.ClientYamlTestSuiteIT + method: test {yaml=snapshot.delete/10_basic/Delete a snapshot asynchronously} + issue: https://github.com/elastic/elasticsearch/issues/122102 +- class: org.elasticsearch.test.rest.ClientYamlTestSuiteIT + method: test {yaml=search/180_locale_dependent_mapping/Test Index and Search locale dependent mappings / dates} + issue: https://github.com/elastic/elasticsearch/issues/122103 +- class: org.elasticsearch.xpack.security.CoreWithSecurityClientYamlTestSuiteIT + method: test {yaml=snapshot.delete/10_basic/Delete a snapshot asynchronously} + issue: https://github.com/elastic/elasticsearch/issues/122104 +- class: org.elasticsearch.xpack.ml.integration.ClassificationIT + method: testWithOnlyTrainingRowsAndTrainingPercentIsFifty_DependentVariableIsBoolean + issue: https://github.com/elastic/elasticsearch/issues/121680 +- class: org.elasticsearch.xpack.downsample.DownsampleActionSingleNodeTests + method: testDuplicateDownsampleRequest + issue: https://github.com/elastic/elasticsearch/issues/122158 +- class: org.elasticsearch.search.SearchCancellationIT + method: testCancelFailedSearchWhenPartialResultDisallowed + issue: https://github.com/elastic/elasticsearch/issues/121719 +- class: org.elasticsearch.xpack.esql.analysis.VerifierTests + method: testChangePoint + issue: https://github.com/elastic/elasticsearch/issues/122179 +- class: org.elasticsearch.xpack.esql.analysis.VerifierTests + method: testChangePoint_keySortable + issue: https://github.com/elastic/elasticsearch/issues/122180 +- class: org.elasticsearch.xpack.esql.analysis.VerifierTests + method: testChangePoint_valueNumeric + issue: https://github.com/elastic/elasticsearch/issues/122181 +- class: org.elasticsearch.datastreams.TSDBPassthroughIndexingIT + issue: https://github.com/elastic/elasticsearch/issues/121716 +- class: org.elasticsearch.smoketest.SmokeTestMonitoringWithSecurityIT + method: testHTTPExporterWithSSL + issue: https://github.com/elastic/elasticsearch/issues/122220 - class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT method: testStopQueryLocal issue: https://github.com/elastic/elasticsearch/issues/121672 -- class: org.elasticsearch.xpack.esql.qa.multi_node.EsqlSpecIT - issue: https://github.com/elastic/elasticsearch/issues/121411 -- class: org.elasticsearch.transport.InboundHandlerTests - method: testLogsSlowInboundProcessing - issue: https://github.com/elastic/elasticsearch/issues/121816 +- class: org.elasticsearch.xpack.security.authz.IndexAliasesTests + method: testRemoveIndex + issue: https://github.com/elastic/elasticsearch/issues/122221 +- class: org.elasticsearch.xpack.migrate.action.ReindexDatastreamIndexTransportActionIT + issue: https://github.com/elastic/elasticsearch/issues/121737 +- class: org.elasticsearch.xpack.esql.action.EsqlActionBreakerIT + method: testGroupingMultiValueByOrdinals + issue: https://github.com/elastic/elasticsearch/issues/122228 +- class: org.elasticsearch.xpack.esql.action.EsqlNodeFailureIT + method: testFailureLoadingFields + issue: https://github.com/elastic/elasticsearch/issues/122132 +- class: org.elasticsearch.blocks.SimpleBlocksIT + method: testConcurrentAddBlock + issue: https://github.com/elastic/elasticsearch/issues/122324 # Examples: # diff --git a/plugins/examples/custom-settings/src/main/java/org/elasticsearch/example/customsettings/ExampleCustomSettingsConfig.java b/plugins/examples/custom-settings/src/main/java/org/elasticsearch/example/customsettings/ExampleCustomSettingsConfig.java index 243201f632c8..a085973e82b0 100644 --- a/plugins/examples/custom-settings/src/main/java/org/elasticsearch/example/customsettings/ExampleCustomSettingsConfig.java +++ b/plugins/examples/custom-settings/src/main/java/org/elasticsearch/example/customsettings/ExampleCustomSettingsConfig.java @@ -70,7 +70,7 @@ public class ExampleCustomSettingsConfig { public ExampleCustomSettingsConfig(final Environment environment) { // Elasticsearch config directory - final Path configDir = environment.configFile(); + final Path configDir = environment.configDir(); // Resolve the plugin's custom settings file final Path customSettingsYamlFile = configDir.resolve("custom-settings/custom.yml"); diff --git a/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/SourceModeRollingUpgradeIT.java b/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/SourceModeRollingUpgradeIT.java index 8bf870edc5ec..55a03da7c9e9 100644 --- a/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/SourceModeRollingUpgradeIT.java +++ b/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/SourceModeRollingUpgradeIT.java @@ -85,7 +85,13 @@ public class SourceModeRollingUpgradeIT extends AbstractRollingUpgradeTestCase { assertThat(response.containsKey("templates"), equalTo(true)); Map issuesByTemplate = (Map) response.get("templates"); assertThat(issuesByTemplate.containsKey(templateName), equalTo(true)); - var templateIssues = (List) issuesByTemplate.get(templateName); - assertThat(((Map) templateIssues.getFirst()).get("message"), equalTo(SourceFieldMapper.DEPRECATION_WARNING)); + var templateIssue = (Map) ((List) issuesByTemplate.get(templateName)).getFirst(); + // Bwc compatible logic until backports are complete. + if (templateIssue.containsKey("details")) { + assertThat(templateIssue.get("message"), equalTo(SourceFieldMapper.DEPRECATION_WARNING_TITLE)); + assertThat(templateIssue.get("details"), equalTo(SourceFieldMapper.DEPRECATION_WARNING)); + } else { + assertThat(templateIssue.get("message"), equalTo(SourceFieldMapper.DEPRECATION_WARNING)); + } } } diff --git a/qa/smoke-test-http/src/javaRestTest/java/org/elasticsearch/http/SearchErrorTraceIT.java b/qa/smoke-test-http/src/javaRestTest/java/org/elasticsearch/http/SearchErrorTraceIT.java index 6f9ab8ccdfde..99e89f0e31cc 100644 --- a/qa/smoke-test-http/src/javaRestTest/java/org/elasticsearch/http/SearchErrorTraceIT.java +++ b/qa/smoke-test-http/src/javaRestTest/java/org/elasticsearch/http/SearchErrorTraceIT.java @@ -11,43 +11,26 @@ package org.elasticsearch.http; import org.apache.http.entity.ContentType; import org.apache.http.nio.entity.NByteArrayEntity; -import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.action.search.MultiSearchRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.client.Request; +import org.elasticsearch.search.ErrorTraceHelper; import org.elasticsearch.search.builder.SearchSourceBuilder; -import org.elasticsearch.transport.TransportMessageListener; -import org.elasticsearch.transport.TransportService; import org.elasticsearch.xcontent.XContentType; import org.junit.Before; import java.io.IOException; import java.nio.charset.Charset; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BooleanSupplier; import static org.elasticsearch.index.query.QueryBuilders.simpleQueryStringQuery; public class SearchErrorTraceIT extends HttpSmokeTestCase { - private AtomicBoolean hasStackTrace; + private BooleanSupplier hasStackTrace; @Before - private void setupMessageListener() { - internalCluster().getDataNodeInstances(TransportService.class).forEach(ts -> { - ts.addMessageListener(new TransportMessageListener() { - @Override - public void onResponseSent(long requestId, String action, Exception error) { - TransportMessageListener.super.onResponseSent(requestId, action, error); - if (action.startsWith("indices:data/read/search")) { - Optional throwable = ExceptionsHelper.unwrapCausesAndSuppressed( - error, - t -> t.getStackTrace().length > 0 - ); - hasStackTrace.set(throwable.isPresent()); - } - } - }); - }); + public void setupMessageListener() { + hasStackTrace = ErrorTraceHelper.setupErrorTraceListener(internalCluster()); } private void setupIndexWithDocs() { @@ -61,7 +44,6 @@ public class SearchErrorTraceIT extends HttpSmokeTestCase { } public void testSearchFailingQueryErrorTraceDefault() throws IOException { - hasStackTrace = new AtomicBoolean(); setupIndexWithDocs(); Request searchRequest = new Request("POST", "/_search"); @@ -76,11 +58,10 @@ public class SearchErrorTraceIT extends HttpSmokeTestCase { } """); getRestClient().performRequest(searchRequest); - assertFalse(hasStackTrace.get()); + assertFalse(hasStackTrace.getAsBoolean()); } public void testSearchFailingQueryErrorTraceTrue() throws IOException { - hasStackTrace = new AtomicBoolean(); setupIndexWithDocs(); Request searchRequest = new Request("POST", "/_search"); @@ -96,11 +77,10 @@ public class SearchErrorTraceIT extends HttpSmokeTestCase { """); searchRequest.addParameter("error_trace", "true"); getRestClient().performRequest(searchRequest); - assertTrue(hasStackTrace.get()); + assertTrue(hasStackTrace.getAsBoolean()); } public void testSearchFailingQueryErrorTraceFalse() throws IOException { - hasStackTrace = new AtomicBoolean(); setupIndexWithDocs(); Request searchRequest = new Request("POST", "/_search"); @@ -116,11 +96,10 @@ public class SearchErrorTraceIT extends HttpSmokeTestCase { """); searchRequest.addParameter("error_trace", "false"); getRestClient().performRequest(searchRequest); - assertFalse(hasStackTrace.get()); + assertFalse(hasStackTrace.getAsBoolean()); } public void testMultiSearchFailingQueryErrorTraceDefault() throws IOException { - hasStackTrace = new AtomicBoolean(); setupIndexWithDocs(); XContentType contentType = XContentType.JSON; @@ -133,11 +112,10 @@ public class SearchErrorTraceIT extends HttpSmokeTestCase { new NByteArrayEntity(requestBody, ContentType.create(contentType.mediaTypeWithoutParameters(), (Charset) null)) ); getRestClient().performRequest(searchRequest); - assertFalse(hasStackTrace.get()); + assertFalse(hasStackTrace.getAsBoolean()); } public void testMultiSearchFailingQueryErrorTraceTrue() throws IOException { - hasStackTrace = new AtomicBoolean(); setupIndexWithDocs(); XContentType contentType = XContentType.JSON; @@ -151,11 +129,10 @@ public class SearchErrorTraceIT extends HttpSmokeTestCase { ); searchRequest.addParameter("error_trace", "true"); getRestClient().performRequest(searchRequest); - assertTrue(hasStackTrace.get()); + assertTrue(hasStackTrace.getAsBoolean()); } public void testMultiSearchFailingQueryErrorTraceFalse() throws IOException { - hasStackTrace = new AtomicBoolean(); setupIndexWithDocs(); XContentType contentType = XContentType.JSON; @@ -170,6 +147,6 @@ public class SearchErrorTraceIT extends HttpSmokeTestCase { searchRequest.addParameter("error_trace", "false"); getRestClient().performRequest(searchRequest); - assertFalse(hasStackTrace.get()); + assertFalse(hasStackTrace.getAsBoolean()); } } diff --git a/qa/smoke-test-ingest-with-all-dependencies/src/yamlRestTest/resources/GeoLite2-City.mmdb b/qa/smoke-test-ingest-with-all-dependencies/src/yamlRestTest/resources/GeoLite2-City.mmdb index 0809201619b5..67dcd4a8e5a1 100644 Binary files a/qa/smoke-test-ingest-with-all-dependencies/src/yamlRestTest/resources/GeoLite2-City.mmdb and b/qa/smoke-test-ingest-with-all-dependencies/src/yamlRestTest/resources/GeoLite2-City.mmdb differ diff --git a/qa/smoke-test-multinode/build.gradle b/qa/smoke-test-multinode/build.gradle index 14e102025cac..cc71a99562eb 100644 --- a/qa/smoke-test-multinode/build.gradle +++ b/qa/smoke-test-multinode/build.gradle @@ -28,7 +28,5 @@ tasks.named("yamlRestTest").configure { 'cat.templates/10_basic/No templates', 'cat.templates/10_basic/Sort templates', 'cat.templates/10_basic/Multiple template', - 'update/100_synthetic_source/keyword', - 'update/100_synthetic_source/stored text' ].join(',') } diff --git a/qa/smoke-test-multinode/src/yamlRestTest/java/org/elasticsearch/smoketest/SmokeTestMultiNodeClientYamlTestSuiteIT.java b/qa/smoke-test-multinode/src/yamlRestTest/java/org/elasticsearch/smoketest/SmokeTestMultiNodeClientYamlTestSuiteIT.java index e53c0564be29..5943d4a86ab9 100644 --- a/qa/smoke-test-multinode/src/yamlRestTest/java/org/elasticsearch/smoketest/SmokeTestMultiNodeClientYamlTestSuiteIT.java +++ b/qa/smoke-test-multinode/src/yamlRestTest/java/org/elasticsearch/smoketest/SmokeTestMultiNodeClientYamlTestSuiteIT.java @@ -36,6 +36,7 @@ public class SmokeTestMultiNodeClientYamlTestSuiteIT extends ESClientYamlSuiteTe .node(0, n -> n.setting("node.roles", "[master,data,ml,remote_cluster_client,transform]")) .feature(FeatureFlag.TIME_SERIES_MODE) .feature(FeatureFlag.SUB_OBJECTS_AUTO_ENABLED) + .feature(FeatureFlag.INDEX_RECOVERY_USE_SYNTHETIC_SOURCE) .build(); public SmokeTestMultiNodeClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) { diff --git a/rest-api-spec/src/yamlRestTest/java/org/elasticsearch/test/rest/ClientYamlTestSuiteIT.java b/rest-api-spec/src/yamlRestTest/java/org/elasticsearch/test/rest/ClientYamlTestSuiteIT.java index 675092bffe8d..e59d8a452b6c 100644 --- a/rest-api-spec/src/yamlRestTest/java/org/elasticsearch/test/rest/ClientYamlTestSuiteIT.java +++ b/rest-api-spec/src/yamlRestTest/java/org/elasticsearch/test/rest/ClientYamlTestSuiteIT.java @@ -36,6 +36,7 @@ public class ClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase { .module("data-streams") .feature(FeatureFlag.TIME_SERIES_MODE) .feature(FeatureFlag.SUB_OBJECTS_AUTO_ENABLED) + .feature(FeatureFlag.INDEX_RECOVERY_USE_SYNTHETIC_SOURCE) .build(); public ClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) { diff --git a/server/src/internalClusterTest/java/org/elasticsearch/rest/RestControllerIT.java b/server/src/internalClusterTest/java/org/elasticsearch/rest/RestControllerIT.java index d3d46a87b920..564d18ef4a61 100644 --- a/server/src/internalClusterTest/java/org/elasticsearch/rest/RestControllerIT.java +++ b/server/src/internalClusterTest/java/org/elasticsearch/rest/RestControllerIT.java @@ -10,6 +10,7 @@ package org.elasticsearch.rest; import org.elasticsearch.client.Request; +import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.ResponseException; import org.elasticsearch.client.internal.node.NodeClient; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; @@ -20,6 +21,7 @@ import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.IndexScopedSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsFilter; +import org.elasticsearch.common.xcontent.ChunkedToXContentHelper; import org.elasticsearch.features.NodeFeature; import org.elasticsearch.logging.LogManager; import org.elasticsearch.logging.Logger; @@ -30,15 +32,21 @@ import org.elasticsearch.plugins.TelemetryPlugin; import org.elasticsearch.telemetry.Measurement; import org.elasticsearch.telemetry.TestTelemetryPlugin; import org.elasticsearch.test.ESIntegTestCase; +import org.elasticsearch.xcontent.XContentParser; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; +import static org.elasticsearch.test.rest.ESRestTestCase.responseAsParser; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; @@ -58,6 +66,49 @@ public class RestControllerIT extends ESIntegTestCase { assertEquals(ChunkedResponseWithHeadersPlugin.HEADER_VALUE, response.getHeader(ChunkedResponseWithHeadersPlugin.HEADER_NAME)); } + public void testHeadersAreCollapsed() throws IOException { + final var client = getRestClient(); + final var request = new Request("GET", TestEchoHeadersPlugin.ROUTE); + request.setOptions(RequestOptions.DEFAULT.toBuilder().addHeader("X-Foo", "1").addHeader("X-Foo", "2").build()); + final var response = client.performRequest(request); + var responseMap = responseAsParser(response).map(HashMap::new, XContentParser::list); + assertThat(responseMap, hasEntry(equalTo("X-Foo"), containsInAnyOrder("1", "2"))); + } + + public void testHeadersTreatedCaseInsensitive() throws IOException { + final var client = getRestClient(); + final var request = new Request("GET", TestEchoHeadersPlugin.ROUTE); + request.setOptions(RequestOptions.DEFAULT.toBuilder().addHeader("X-Foo", "1").addHeader("x-foo", "2").build()); + final var response = client.performRequest(request); + var responseMap = responseAsParser(response).map(HashMap::new, XContentParser::list); + assertThat(responseMap, hasEntry(equalTo("x-foo"), containsInAnyOrder("1", "2"))); + assertThat(responseMap, hasEntry(equalTo("X-Foo"), containsInAnyOrder("1", "2"))); + } + + public void testThreadContextPopulationFromMultipleHeadersFailsWithCorrectError() { + final var client = getRestClient(); + final var sameCaseRequest = new Request("GET", TestEchoHeadersPlugin.ROUTE); + sameCaseRequest.setOptions( + RequestOptions.DEFAULT.toBuilder() + .addHeader("x-elastic-product-origin", "elastic") + .addHeader("x-elastic-product-origin", "other") + ); + var exception1 = expectThrows(ResponseException.class, () -> client.performRequest(sameCaseRequest)); + assertThat(exception1.getMessage(), containsString("multiple values for single-valued header [X-elastic-product-origin]")); + } + + public void testMultipleProductOriginHeadersWithDifferentCaseFailsWithCorrectError() { + final var client = getRestClient(); + final var differentCaseRequest = new Request("GET", TestEchoHeadersPlugin.ROUTE); + differentCaseRequest.setOptions( + RequestOptions.DEFAULT.toBuilder() + .addHeader("X-elastic-product-origin", "elastic") + .addHeader("x-elastic-product-origin", "other") + ); + var exception2 = expectThrows(ResponseException.class, () -> client.performRequest(differentCaseRequest)); + assertThat(exception2.getMessage(), containsString("multiple values for single-valued header [X-elastic-product-origin]")); + } + public void testMetricsEmittedOnSuccess() throws Exception { final var client = getRestClient(); final var request = new Request("GET", TestEchoStatusCodePlugin.ROUTE); @@ -125,7 +176,12 @@ public class RestControllerIT extends ESIntegTestCase { @Override protected Collection> nodePlugins() { - return List.of(ChunkedResponseWithHeadersPlugin.class, TestEchoStatusCodePlugin.class, TestTelemetryPlugin.class); + return List.of( + ChunkedResponseWithHeadersPlugin.class, + TestEchoStatusCodePlugin.class, + TestEchoHeadersPlugin.class, + TestTelemetryPlugin.class + ); } public static class TestEchoStatusCodePlugin extends Plugin implements ActionPlugin { @@ -181,6 +237,62 @@ public class RestControllerIT extends ESIntegTestCase { } } + public static class TestEchoHeadersPlugin extends Plugin implements ActionPlugin { + static final String ROUTE = "/_test/echo_headers"; + static final String NAME = "test_echo_headers"; + + private static final Logger logger = LogManager.getLogger(TestEchoStatusCodePlugin.class); + + @Override + public Collection getRestHandlers( + Settings settings, + NamedWriteableRegistry namedWriteableRegistry, + RestController restController, + ClusterSettings clusterSettings, + IndexScopedSettings indexScopedSettings, + SettingsFilter settingsFilter, + IndexNameExpressionResolver indexNameExpressionResolver, + Supplier nodesInCluster, + Predicate clusterSupportsFeature + ) { + return List.of(new BaseRestHandler() { + @Override + public String getName() { + return NAME; + } + + @Override + public List routes() { + return List.of(new Route(RestRequest.Method.GET, ROUTE), new Route(RestRequest.Method.POST, ROUTE)); + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { + var headers = request.getHeaders(); + logger.info("received header echo request for [{}]", String.join(",", headers.keySet())); + + return channel -> { + final var response = RestResponse.chunked( + RestStatus.OK, + ChunkedRestResponseBodyPart.fromXContent( + params -> Iterators.concat( + ChunkedToXContentHelper.startObject(), + Iterators.map(headers.entrySet().iterator(), e -> (b, p) -> b.field(e.getKey(), e.getValue())), + ChunkedToXContentHelper.endObject() + ), + request, + channel + ), + null + ); + channel.sendResponse(response); + logger.info("sent response"); + }; + } + }); + } + } + public static class ChunkedResponseWithHeadersPlugin extends Plugin implements ActionPlugin { static final String ROUTE = "/_test/chunked_response_with_headers"; diff --git a/server/src/internalClusterTest/java/org/elasticsearch/search/SearchTimeoutIT.java b/server/src/internalClusterTest/java/org/elasticsearch/search/SearchTimeoutIT.java index f63f09764621..f45c37715f7c 100644 --- a/server/src/internalClusterTest/java/org/elasticsearch/search/SearchTimeoutIT.java +++ b/server/src/internalClusterTest/java/org/elasticsearch/search/SearchTimeoutIT.java @@ -9,36 +9,56 @@ package org.elasticsearch.search; +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.search.BulkScorer; +import org.apache.lucene.search.ConstantScoreScorer; +import org.apache.lucene.search.ConstantScoreWeight; +import org.apache.lucene.search.DocIdSetIterator; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.LeafCollector; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; +import org.apache.lucene.search.Scorable; +import org.apache.lucene.search.ScoreMode; +import org.apache.lucene.search.Scorer; +import org.apache.lucene.search.ScorerSupplier; +import org.apache.lucene.search.Weight; +import org.apache.lucene.util.Bits; import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.TransportVersion; +import org.elasticsearch.action.search.SearchRequestBuilder; +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.index.query.AbstractQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.script.MockScriptPlugin; -import org.elasticsearch.script.Script; -import org.elasticsearch.script.ScriptType; +import org.elasticsearch.plugins.SearchPlugin; import org.elasticsearch.search.aggregations.bucket.terms.StringTerms; import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; +import org.elasticsearch.search.internal.ContextIndexSearcher; import org.elasticsearch.test.ESIntegTestCase; +import org.elasticsearch.test.hamcrest.ElasticsearchAssertions; +import org.elasticsearch.xcontent.XContentBuilder; +import java.io.IOException; import java.util.Collection; import java.util.Collections; -import java.util.Map; +import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; -import static org.elasticsearch.index.query.QueryBuilders.scriptQuery; -import static org.elasticsearch.search.SearchTimeoutIT.ScriptedTimeoutPlugin.SCRIPT_NAME; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; @ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.SUITE) +@ESIntegTestCase.SuiteScopeTestCase public class SearchTimeoutIT extends ESIntegTestCase { @Override protected Collection> nodePlugins() { - return Collections.singleton(ScriptedTimeoutPlugin.class); + return Collections.singleton(BulkScorerTimeoutQueryPlugin.class); } @Override @@ -46,75 +66,253 @@ public class SearchTimeoutIT extends ESIntegTestCase { return Settings.builder().put(super.nodeSettings(nodeOrdinal, otherSettings)).build(); } - private void indexDocs() { - for (int i = 0; i < 32; i++) { - prepareIndex("test").setId(Integer.toString(i)).setSource("field", "value").get(); - } - refresh("test"); + @Override + protected void setupSuiteScopeCluster() throws Exception { + super.setupSuiteScopeCluster(); + indexRandom(true, "test", randomIntBetween(20, 50)); } - @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/98369") - public void testTopHitsTimeout() { - indexDocs(); - SearchResponse searchResponse = prepareSearch("test").setTimeout(new TimeValue(10, TimeUnit.MILLISECONDS)) - .setQuery(scriptQuery(new Script(ScriptType.INLINE, "mockscript", SCRIPT_NAME, Collections.emptyMap()))) - .get(); - assertThat(searchResponse.isTimedOut(), equalTo(true)); - assertEquals(0, searchResponse.getShardFailures().length); - assertEquals(0, searchResponse.getFailedShards()); - assertThat(searchResponse.getSuccessfulShards(), greaterThan(0)); - assertEquals(searchResponse.getSuccessfulShards(), searchResponse.getTotalShards()); - assertThat(searchResponse.getHits().getTotalHits().value(), greaterThan(0L)); - assertThat(searchResponse.getHits().getHits().length, greaterThan(0)); + public void testTopHitsTimeoutBeforeCollecting() { + // setting the timeout is necessary only because we check that if a TimeExceededException is thrown, a timeout was set + SearchRequestBuilder searchRequestBuilder = prepareSearch("test").setTimeout(new TimeValue(10, TimeUnit.SECONDS)) + .setQuery(new BulkScorerTimeoutQuery(false)); + ElasticsearchAssertions.assertResponse(searchRequestBuilder, searchResponse -> { + assertThat(searchResponse.isTimedOut(), equalTo(true)); + assertEquals(0, searchResponse.getShardFailures().length); + assertEquals(0, searchResponse.getFailedShards()); + assertThat(searchResponse.getSuccessfulShards(), greaterThan(0)); + assertEquals(searchResponse.getSuccessfulShards(), searchResponse.getTotalShards()); + // timeout happened before we could collect any doc, total hits is 0 and no hits are returned + assertEquals(0, searchResponse.getHits().getTotalHits().value()); + assertEquals(0, searchResponse.getHits().getHits().length); + }); } - @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/98053") - public void testAggsTimeout() { - indexDocs(); - SearchResponse searchResponse = prepareSearch("test").setTimeout(new TimeValue(10, TimeUnit.MILLISECONDS)) - .setSize(0) - .setQuery(scriptQuery(new Script(ScriptType.INLINE, "mockscript", SCRIPT_NAME, Collections.emptyMap()))) - .addAggregation(new TermsAggregationBuilder("terms").field("field.keyword")) - .get(); - assertThat(searchResponse.isTimedOut(), equalTo(true)); - assertEquals(0, searchResponse.getShardFailures().length); - assertEquals(0, searchResponse.getFailedShards()); - assertThat(searchResponse.getSuccessfulShards(), greaterThan(0)); - assertEquals(searchResponse.getSuccessfulShards(), searchResponse.getTotalShards()); - assertThat(searchResponse.getHits().getTotalHits().value(), greaterThan(0L)); - assertEquals(searchResponse.getHits().getHits().length, 0); - StringTerms terms = searchResponse.getAggregations().get("terms"); - assertEquals(1, terms.getBuckets().size()); - StringTerms.Bucket bucket = terms.getBuckets().get(0); - assertEquals("value", bucket.getKeyAsString()); - assertThat(bucket.getDocCount(), greaterThan(0L)); + public void testTopHitsTimeoutWhileCollecting() { + // setting the timeout is necessary only because we check that if a TimeExceededException is thrown, a timeout was set + SearchRequestBuilder searchRequestBuilder = prepareSearch("test").setTimeout(new TimeValue(10, TimeUnit.SECONDS)) + .setQuery(new BulkScorerTimeoutQuery(true)); + ElasticsearchAssertions.assertResponse(searchRequestBuilder, searchResponse -> { + assertThat(searchResponse.isTimedOut(), equalTo(true)); + assertEquals(0, searchResponse.getShardFailures().length); + assertEquals(0, searchResponse.getFailedShards()); + assertThat(searchResponse.getSuccessfulShards(), greaterThan(0)); + assertEquals(searchResponse.getSuccessfulShards(), searchResponse.getTotalShards()); + assertThat(searchResponse.getHits().getTotalHits().value(), greaterThan(0L)); + assertThat(searchResponse.getHits().getHits().length, greaterThan(0)); + }); } - public void testPartialResultsIntolerantTimeout() throws Exception { - prepareIndex("test").setId("1").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get(); + public void testAggsTimeoutBeforeCollecting() { + SearchRequestBuilder searchRequestBuilder = prepareSearch("test").setSize(0) + // setting the timeout is necessary only because we check that if a TimeExceededException is thrown, a timeout was set + .setTimeout(new TimeValue(10, TimeUnit.SECONDS)) + .setQuery(new BulkScorerTimeoutQuery(false)) + .addAggregation(new TermsAggregationBuilder("terms").field("field.keyword")); + ElasticsearchAssertions.assertResponse(searchRequestBuilder, searchResponse -> { + assertThat(searchResponse.isTimedOut(), equalTo(true)); + assertEquals(0, searchResponse.getShardFailures().length); + assertEquals(0, searchResponse.getFailedShards()); + assertThat(searchResponse.getSuccessfulShards(), greaterThan(0)); + assertEquals(searchResponse.getSuccessfulShards(), searchResponse.getTotalShards()); + assertEquals(0, searchResponse.getHits().getTotalHits().value()); + assertEquals(0, searchResponse.getHits().getHits().length); + StringTerms terms = searchResponse.getAggregations().get("terms"); + // timeout happened before we could collect any doc, total hits is 0 and no buckets are returned + assertEquals(0, terms.getBuckets().size()); + }); + } + public void testAggsTimeoutWhileCollecting() { + SearchRequestBuilder searchRequestBuilder = prepareSearch("test").setSize(0) + // setting the timeout is necessary only because we check that if a TimeExceededException is thrown, a timeout was set + .setTimeout(new TimeValue(10, TimeUnit.SECONDS)) + .setQuery(new BulkScorerTimeoutQuery(true)) + .addAggregation(new TermsAggregationBuilder("terms").field("field.keyword")); + ElasticsearchAssertions.assertResponse(searchRequestBuilder, searchResponse -> { + assertThat(searchResponse.isTimedOut(), equalTo(true)); + assertEquals(0, searchResponse.getShardFailures().length); + assertEquals(0, searchResponse.getFailedShards()); + assertThat(searchResponse.getSuccessfulShards(), greaterThan(0)); + assertEquals(searchResponse.getSuccessfulShards(), searchResponse.getTotalShards()); + assertThat(searchResponse.getHits().getTotalHits().value(), greaterThan(0L)); + assertEquals(0, searchResponse.getHits().getHits().length); + StringTerms terms = searchResponse.getAggregations().get("terms"); + assertEquals(1, terms.getBuckets().size()); + StringTerms.Bucket bucket = terms.getBuckets().get(0); + assertEquals("value", bucket.getKeyAsString()); + assertThat(bucket.getDocCount(), greaterThan(0L)); + }); + } + + public void testPartialResultsIntolerantTimeoutBeforeCollecting() { ElasticsearchException ex = expectThrows( ElasticsearchException.class, - prepareSearch("test").setTimeout(new TimeValue(10, TimeUnit.MILLISECONDS)) - .setQuery(scriptQuery(new Script(ScriptType.INLINE, "mockscript", SCRIPT_NAME, Collections.emptyMap()))) + prepareSearch("test") + // setting the timeout is necessary only because we check that if a TimeExceededException is thrown, a timeout was set + .setTimeout(new TimeValue(10, TimeUnit.SECONDS)) + .setQuery(new BulkScorerTimeoutQuery(false)) .setAllowPartialSearchResults(false) // this line causes timeouts to report failures ); assertTrue(ex.toString().contains("Time exceeded")); + assertEquals(429, ex.status().getStatus()); } - public static class ScriptedTimeoutPlugin extends MockScriptPlugin { - static final String SCRIPT_NAME = "search_timeout"; + public void testPartialResultsIntolerantTimeoutWhileCollecting() { + ElasticsearchException ex = expectThrows( + ElasticsearchException.class, + prepareSearch("test") + // setting the timeout is necessary only because we check that if a TimeExceededException is thrown, a timeout was set + .setTimeout(new TimeValue(10, TimeUnit.SECONDS)) + .setQuery(new BulkScorerTimeoutQuery(true)) + .setAllowPartialSearchResults(false) // this line causes timeouts to report failures + ); + assertTrue(ex.toString().contains("Time exceeded")); + assertEquals(429, ex.status().getStatus()); + } + + public static final class BulkScorerTimeoutQueryPlugin extends Plugin implements SearchPlugin { + @Override + public List> getQueries() { + return Collections.singletonList(new QuerySpec("timeout", BulkScorerTimeoutQuery::new, parser -> { + throw new UnsupportedOperationException(); + })); + } + } + + /** + * Query builder that produces a Lucene Query which throws a + * {@link org.elasticsearch.search.internal.ContextIndexSearcher.TimeExceededException} before or while scoring documents. + * This helps make this test not time dependent, otherwise it would be unpredictable when exactly the timeout happens, which is + * rather important if we want to test that we are able to return partial results on timeout. + */ + public static final class BulkScorerTimeoutQuery extends AbstractQueryBuilder { + + private final boolean partialResults; + + BulkScorerTimeoutQuery(boolean partialResults) { + this.partialResults = partialResults; + } + + BulkScorerTimeoutQuery(StreamInput in) throws IOException { + super(in); + this.partialResults = in.readBoolean(); + } @Override - public Map, Object>> pluginScripts() { - return Collections.singletonMap(SCRIPT_NAME, params -> { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - throw new RuntimeException(e); + protected void doWriteTo(StreamOutput out) throws IOException { + out.writeBoolean(partialResults); + } + + @Override + protected void doXContent(XContentBuilder builder, Params params) {} + + @Override + protected Query doToQuery(SearchExecutionContext context) { + return new Query() { + @Override + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) { + return new ConstantScoreWeight(this, boost) { + @Override + public boolean isCacheable(LeafReaderContext ctx) { + return false; + } + + @Override + public ScorerSupplier scorerSupplier(LeafReaderContext context) { + return new ScorerSupplier() { + @Override + public BulkScorer bulkScorer() { + if (partialResults == false) { + ((ContextIndexSearcher) searcher).throwTimeExceededException(); + } + final int maxDoc = context.reader().maxDoc(); + return new BulkScorer() { + @Override + public int score(LeafCollector collector, Bits acceptDocs, int min, int max) throws IOException { + max = Math.min(max, maxDoc); + collector.setScorer(new Scorable() { + @Override + public float score() { + return 1f; + } + }); + for (int doc = min; doc < max; ++doc) { + if (acceptDocs == null || acceptDocs.get(doc)) { + collector.collect(doc); + // collect one doc per segment, only then throw a timeout: this ensures partial + // results are returned + ((ContextIndexSearcher) searcher).throwTimeExceededException(); + } + } + // there is a slight chance that no docs are scored for a specific segment. + // other shards / slices will throw the timeout anyway, one is enough. + return max == maxDoc ? DocIdSetIterator.NO_MORE_DOCS : max; + } + + @Override + public long cost() { + return maxDoc; + } + }; + } + + @Override + public Scorer get(long leadCost) { + assert false; + return new ConstantScoreScorer(score(), scoreMode, DocIdSetIterator.all(context.reader().maxDoc())); + } + + @Override + public long cost() { + assert false; + return context.reader().maxDoc(); + } + }; + } + }; } - return true; - }); + + @Override + public String toString(String field) { + return "timeout query"; + } + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + + @Override + public boolean equals(Object obj) { + return sameClassAs(obj); + } + + @Override + public int hashCode() { + return classHash(); + } + }; + } + + @Override + protected boolean doEquals(BulkScorerTimeoutQuery other) { + return false; + } + + @Override + protected int doHashCode() { + return 0; + } + + @Override + public String getWriteableName() { + return "timeout"; + } + + @Override + public TransportVersion getMinimalSupportedVersion() { + return null; } } } diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java index 0ebfcae9d5a3..56f6744a6a72 100644 --- a/server/src/main/java/org/elasticsearch/TransportVersions.java +++ b/server/src/main/java/org/elasticsearch/TransportVersions.java @@ -175,12 +175,17 @@ public class TransportVersions { public static final TransportVersion ML_INFERENCE_IBM_WATSONX_RERANK_ADDED = def(8_840_0_00); public static final TransportVersion COHERE_BIT_EMBEDDING_TYPE_SUPPORT_ADDED_BACKPORT_8_X = def(8_840_0_01); public static final TransportVersion ELASTICSEARCH_9_0 = def(9_000_0_00); + public static final TransportVersion REMOVE_SNAPSHOT_FAILURES_90 = def(9_000_0_01); + public static final TransportVersion TRANSPORT_STATS_HANDLING_TIME_REQUIRED_90 = def(9_000_0_02); + public static final TransportVersion REMOVE_DESIRED_NODE_VERSION_90 = def(9_000_0_03); + public static final TransportVersion ESQL_DRIVER_TASK_DESCRIPTION_90 = def(9_000_0_04); public static final TransportVersion COHERE_BIT_EMBEDDING_TYPE_SUPPORT_ADDED = def(9_001_0_00); public static final TransportVersion REMOVE_SNAPSHOT_FAILURES = def(9_002_0_00); public static final TransportVersion TRANSPORT_STATS_HANDLING_TIME_REQUIRED = def(9_003_0_00); public static final TransportVersion REMOVE_DESIRED_NODE_VERSION = def(9_004_0_00); public static final TransportVersion ESQL_DRIVER_TASK_DESCRIPTION = def(9_005_0_00); public static final TransportVersion ESQL_RETRY_ON_SHARD_LEVEL_FAILURE = def(9_006_0_00); + public static final TransportVersion ESQL_PROFILE_ASYNC_NANOS = def(9_007_00_0); /* * WARNING: DO NOT MERGE INTO MAIN! diff --git a/server/src/main/java/org/elasticsearch/Version.java b/server/src/main/java/org/elasticsearch/Version.java index 49f1f6c0d4a1..75be3a1db906 100644 --- a/server/src/main/java/org/elasticsearch/Version.java +++ b/server/src/main/java/org/elasticsearch/Version.java @@ -193,9 +193,11 @@ public class Version implements VersionId, ToXContentFragment { public static final Version V_8_16_2 = new Version(8_16_02_99); public static final Version V_8_16_3 = new Version(8_16_03_99); public static final Version V_8_16_4 = new Version(8_16_04_99); + public static final Version V_8_16_5 = new Version(8_16_05_99); public static final Version V_8_17_0 = new Version(8_17_00_99); public static final Version V_8_17_1 = new Version(8_17_01_99); public static final Version V_8_17_2 = new Version(8_17_02_99); + public static final Version V_8_17_3 = new Version(8_17_03_99); public static final Version V_8_18_0 = new Version(8_18_00_99); public static final Version V_8_19_0 = new Version(8_19_00_99); public static final Version V_9_0_0 = new Version(9_00_00_99); diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/desirednodes/TransportUpdateDesiredNodesAction.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/desirednodes/TransportUpdateDesiredNodesAction.java index 86b476f84ecf..da9626d14ca6 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/desirednodes/TransportUpdateDesiredNodesAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/desirednodes/TransportUpdateDesiredNodesAction.java @@ -22,14 +22,12 @@ import org.elasticsearch.cluster.block.ClusterBlockLevel; import org.elasticsearch.cluster.desirednodes.VersionConflictException; import org.elasticsearch.cluster.metadata.DesiredNodes; import org.elasticsearch.cluster.metadata.DesiredNodesMetadata; -import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.routing.RerouteService; import org.elasticsearch.cluster.routing.allocation.AllocationService; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.service.MasterServiceTaskQueue; import org.elasticsearch.common.Priority; import org.elasticsearch.common.util.concurrent.EsExecutors; -import org.elasticsearch.features.FeatureService; import org.elasticsearch.injection.guice.Inject; import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; @@ -42,7 +40,6 @@ import static java.lang.String.format; public class TransportUpdateDesiredNodesAction extends TransportMasterNodeAction { private static final Logger logger = LogManager.getLogger(TransportUpdateDesiredNodesAction.class); - private final FeatureService featureService; private final MasterServiceTaskQueue taskQueue; @Inject @@ -50,10 +47,8 @@ public class TransportUpdateDesiredNodesAction extends TransportMasterNodeAction TransportService transportService, ClusterService clusterService, RerouteService rerouteService, - FeatureService featureService, ThreadPool threadPool, ActionFilters actionFilters, - IndexNameExpressionResolver indexNameExpressionResolver, AllocationService allocationService ) { super( @@ -67,7 +62,6 @@ public class TransportUpdateDesiredNodesAction extends TransportMasterNodeAction UpdateDesiredNodesResponse::new, EsExecutors.DIRECT_EXECUTOR_SERVICE ); - this.featureService = featureService; this.taskQueue = clusterService.createTaskQueue( "update-desired-nodes", Priority.URGENT, diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/GetSnapshotsResponse.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/GetSnapshotsResponse.java index 2436a9e29887..797d95529ee2 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/GetSnapshotsResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/GetSnapshotsResponse.java @@ -49,7 +49,8 @@ public class GetSnapshotsResponse extends ActionResponse implements ChunkedToXCo public GetSnapshotsResponse(StreamInput in) throws IOException { this.snapshots = in.readCollectionAsImmutableList(SnapshotInfo::readFrom); - if (in.getTransportVersion().before(TransportVersions.REMOVE_SNAPSHOT_FAILURES)) { + if (in.getTransportVersion().before(TransportVersions.REMOVE_SNAPSHOT_FAILURES) + && in.getTransportVersion().isPatchFrom(TransportVersions.REMOVE_SNAPSHOT_FAILURES_90) == false) { // Deprecated `failures` field in.readMap(StreamInput::readException); } @@ -83,7 +84,8 @@ public class GetSnapshotsResponse extends ActionResponse implements ChunkedToXCo @Override public void writeTo(StreamOutput out) throws IOException { out.writeCollection(snapshots); - if (out.getTransportVersion().before(TransportVersions.REMOVE_SNAPSHOT_FAILURES)) { + if (out.getTransportVersion().before(TransportVersions.REMOVE_SNAPSHOT_FAILURES) + && out.getTransportVersion().isPatchFrom(TransportVersions.REMOVE_SNAPSHOT_FAILURES_90) == false) { // Deprecated `failures` field out.writeMap(Map.of(), StreamOutput::writeException); } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesResponse.java index 69ab9f57d2be..071e9b42752c 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesResponse.java @@ -77,6 +77,17 @@ public class IndicesAliasesResponse extends AcknowledgedResponse { return errors; } + /** + * Get a list of all errors from the response. If there are no errors, an empty list is returned. + */ + public List getErrors() { + if (errors == false) { + return List.of(); + } else { + return actionResults.stream().filter(a -> a.getError() != null).map(AliasActionResult::getError).toList(); + } + } + /** * Build a response from a list of action results. Sets the errors boolean based * on whether an of the individual results contain an error. @@ -165,6 +176,13 @@ public class IndicesAliasesResponse extends AcknowledgedResponse { return new AliasActionResult(indices, action, null); } + /** + * The error result if the action failed, null if the action succeeded. + */ + public ElasticsearchException getError() { + return error; + } + private int getStatus() { return error == null ? 200 : error.status().getStatus(); } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/refresh/TransportShardRefreshAction.java b/server/src/main/java/org/elasticsearch/action/admin/indices/refresh/TransportShardRefreshAction.java index 6b77a39c32ff..2286f6464818 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/refresh/TransportShardRefreshAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/refresh/TransportShardRefreshAction.java @@ -23,6 +23,7 @@ import org.elasticsearch.cluster.routing.IndexShardRoutingTable; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.engine.Engine; import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.indices.IndicesService; import org.elasticsearch.injection.guice.Inject; @@ -125,17 +126,16 @@ public class TransportShardRefreshAction extends TransportReplicationAction< IndexShardRoutingTable indexShardRoutingTable, ActionListener listener ) { - assert replicaRequest.primaryRefreshResult.refreshed() : "primary has not refreshed"; - UnpromotableShardRefreshRequest unpromotableReplicaRequest = new UnpromotableShardRefreshRequest( - indexShardRoutingTable, - replicaRequest.primaryRefreshResult.primaryTerm(), - replicaRequest.primaryRefreshResult.generation(), - false - ); + var primaryTerm = replicaRequest.primaryRefreshResult.primaryTerm(); + assert Engine.UNKNOWN_PRIMARY_TERM < primaryTerm : primaryTerm; + + var generation = replicaRequest.primaryRefreshResult.generation(); + assert Engine.RefreshResult.UNKNOWN_GENERATION < generation : generation; + transportService.sendRequest( transportService.getLocalNode(), TransportUnpromotableShardRefreshAction.NAME, - unpromotableReplicaRequest, + new UnpromotableShardRefreshRequest(indexShardRoutingTable, primaryTerm, generation, false), new ActionListenerResponseHandler<>(listener.safeMap(r -> null), in -> ActionResponse.Empty.INSTANCE, refreshExecutor) ); } diff --git a/server/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java b/server/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java index 8308c2b40e10..5f6c56b23ec5 100644 --- a/server/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java +++ b/server/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java @@ -23,7 +23,6 @@ import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.support.ActionFilters; -import org.elasticsearch.action.support.RefCountingListener; import org.elasticsearch.action.support.replication.PostWriteRefresh; import org.elasticsearch.action.support.replication.TransportReplicationAction; import org.elasticsearch.action.support.replication.TransportWriteAction; @@ -155,12 +154,7 @@ public class TransportShardBulkAction extends TransportWriteAction> listener ) { - final ActionListener wrappedListener = listener.delegateFailure( - (l, ignored) -> super.shardOperationOnPrimary(request, primary, l) - ); - try (var preBulkProceedListeners = new RefCountingListener(wrappedListener)) { - primary.getIndexingOperationListener().preBulkOnPrimary(primary, () -> preBulkProceedListeners.acquire()); - } + primary.ensureMutable(listener.delegateFailure((l, ignored) -> super.shardOperationOnPrimary(request, primary, l))); } @Override diff --git a/server/src/main/java/org/elasticsearch/action/get/TransportGetAction.java b/server/src/main/java/org/elasticsearch/action/get/TransportGetAction.java index 36254aac4ec1..d474eee8375b 100644 --- a/server/src/main/java/org/elasticsearch/action/get/TransportGetAction.java +++ b/server/src/main/java/org/elasticsearch/action/get/TransportGetAction.java @@ -11,6 +11,7 @@ package org.elasticsearch.action.get; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.lucene.store.AlreadyClosedException; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.action.ActionListener; @@ -31,7 +32,6 @@ import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.ProjectId; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.project.ProjectResolver; -import org.elasticsearch.cluster.routing.PlainShardIterator; import org.elasticsearch.cluster.routing.ShardIterator; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.io.stream.Writeable; @@ -113,7 +113,7 @@ public class TransportGetAction extends TransportSingleShardAction { final var cause = ExceptionsHelper.unwrapCause(e); logger.debug("get_from_translog failed", cause); - if (cause instanceof ShardNotFoundException || cause instanceof IndexNotFoundException) { + if (cause instanceof ShardNotFoundException + || cause instanceof IndexNotFoundException + || cause instanceof AlreadyClosedException) { + // TODO AlreadyClosedException the engine reset should be fixed by ES-10826 logger.debug("retrying get_from_translog"); observer.waitForNextChange(new ClusterStateObserver.Listener() { @Override @@ -252,7 +255,13 @@ public class TransportGetAction extends TransportSingleShardAction { final var cause = ExceptionsHelper.unwrapCause(e); logger.debug("mget_from_translog[shard] failed", cause); - if (cause instanceof ShardNotFoundException || cause instanceof IndexNotFoundException) { + if (cause instanceof ShardNotFoundException + || cause instanceof IndexNotFoundException + || cause instanceof AlreadyClosedException) { + // TODO AlreadyClosedException the engine reset should be fixed by ES-10826 logger.debug("retrying mget_from_translog[shard]"); observer.waitForNextChange(new ClusterStateObserver.Listener() { @Override @@ -233,7 +236,13 @@ public class TransportShardMultiGetAction extends TransportSingleShardAction exten successfulShardExecution(); } - private static boolean assertExecuteOnStartThread() { - // Ensure that the current code has the following stacktrace: - // AbstractSearchAsyncAction#start -> AbstractSearchAsyncAction#executePhase -> AbstractSearchAsyncAction#performPhaseOnShard - final StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); - assert stackTraceElements.length >= 6 : stackTraceElements; - int index = 0; - assert stackTraceElements[index++].getMethodName().equals("getStackTrace"); - assert stackTraceElements[index++].getMethodName().equals("assertExecuteOnStartThread"); - assert stackTraceElements[index++].getMethodName().equals("failOnUnavailable"); - if (stackTraceElements[index].getMethodName().equals("performPhaseOnShard")) { - assert stackTraceElements[index].getClassName().endsWith("CanMatchPreFilterSearchPhase"); - index++; - } - assert stackTraceElements[index].getClassName().endsWith("AbstractSearchAsyncAction"); - assert stackTraceElements[index++].getMethodName().equals("run"); - - assert stackTraceElements[index].getClassName().endsWith("AbstractSearchAsyncAction"); - assert stackTraceElements[index++].getMethodName().equals("executePhase"); - - assert stackTraceElements[index].getClassName().endsWith("AbstractSearchAsyncAction"); - assert stackTraceElements[index++].getMethodName().equals("start"); - - assert stackTraceElements[index].getClassName().endsWith("AbstractSearchAsyncAction") == false; - return true; - } - private void performPhaseOnShard(final int shardIndex, final SearchShardIterator shardIt, final SearchShardTarget shard) { if (throttleConcurrentRequests) { var pendingExecutions = pendingExecutionsPerNode.computeIfAbsent( @@ -290,7 +264,7 @@ abstract class AbstractSearchAsyncAction exten public void innerOnResponse(Result result) { try { releasable.close(); - onShardResult(result, shardIt); + onShardResult(result); } catch (Exception exc) { onShardFailure(shardIndex, shard, shardIt, exc); } @@ -313,7 +287,6 @@ abstract class AbstractSearchAsyncAction exten } private void failOnUnavailable(int shardIndex, SearchShardIterator shardIt) { - assert assertExecuteOnStartThread(); SearchShardTarget unassignedShard = new SearchShardTarget(null, shardIt.shardId(), shardIt.getClusterAlias()); onShardFailure(shardIndex, unassignedShard, shardIt, new NoShardAvailableActionException(shardIt.shardId())); } @@ -513,9 +486,8 @@ abstract class AbstractSearchAsyncAction exten /** * Executed once for every successful shard level request. * @param result the result returned form the shard - * @param shardIt the shard iterator */ - protected void onShardResult(Result result, SearchShardIterator shardIt) { + protected void onShardResult(Result result) { assert result.getShardIndex() != -1 : "shard index is not set"; assert result.getSearchShardTarget() != null : "search shard target must not be null"; hasShardResponse.set(true); @@ -705,7 +677,7 @@ abstract class AbstractSearchAsyncAction exten /** * Executed once all shard results have been received and processed * @see #onShardFailure(int, SearchShardTarget, Exception) - * @see #onShardResult(SearchPhaseResult, SearchShardIterator) + * @see #onShardResult(SearchPhaseResult) */ private void onPhaseDone() { // as a tribute to @kimchy aka. finishHim() executeNextPhase(getName(), this::getNextPhase); diff --git a/server/src/main/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncAction.java b/server/src/main/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncAction.java index 088a16deb76d..1f595f47dc48 100644 --- a/server/src/main/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncAction.java +++ b/server/src/main/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncAction.java @@ -104,7 +104,7 @@ class SearchQueryThenFetchAsyncAction extends AbstractSearchAsyncAction targetNodesIterator; /** - * Creates a {@link PlainShardIterator} instance that iterates over a subset of the given shards + * Creates a {@link SearchShardIterator} instance that iterates over a subset of the given shards * this the a given shardId. * * @param clusterAlias the alias of the cluster where the shard is located @@ -55,7 +55,7 @@ public final class SearchShardIterator implements Comparable { * that are also present across the whole cluster as a result. */ private Set calculateEffectiveClusterFeatures(DiscoveryNodes nodes, Map> nodeFeatures) { - if (featureService.featuresCanBeAssumedForNodes(nodes)) { + if (FeatureService.featuresCanBeAssumedForNodes(nodes)) { Set assumedFeatures = featureService.getNodeFeatures() .values() .stream() @@ -382,7 +382,7 @@ public class NodeJoinExecutor implements ClusterStateTaskExecutor { // add all assumed features to the featureset of all nodes of the next major version nodeFeatures = new HashMap<>(nodeFeatures); for (var node : nodes.getNodes().entrySet()) { - if (featureService.featuresCanBeAssumedForNode(node.getValue())) { + if (FeatureService.featuresCanBeAssumedForNode(node.getValue())) { assert nodeFeatures.containsKey(node.getKey()) : "Node " + node.getKey() + " does not have any features"; nodeFeatures.computeIfPresent(node.getKey(), (k, v) -> { var newFeatures = new HashSet<>(v); @@ -525,7 +525,7 @@ public class NodeJoinExecutor implements ClusterStateTaskExecutor { return newNodeFeatures; } - if (featureService.featuresCanBeAssumedForNode(node)) { + if (FeatureService.featuresCanBeAssumedForNode(node)) { // it might still be ok for this node to join if this node can have assumed features, // and all the missing features are assumed // we can get the NodeFeature object direct from this node's registered features diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/DesiredNode.java b/server/src/main/java/org/elasticsearch/cluster/metadata/DesiredNode.java index b0d1758d895e..41b716dd99bd 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/DesiredNode.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/DesiredNode.java @@ -161,7 +161,8 @@ public final class DesiredNode implements Writeable, ToXContentObject, Comparabl } final var memory = ByteSizeValue.readFrom(in); final var storage = ByteSizeValue.readFrom(in); - if (in.getTransportVersion().before(TransportVersions.REMOVE_DESIRED_NODE_VERSION)) { + if (in.getTransportVersion().before(TransportVersions.REMOVE_DESIRED_NODE_VERSION) + && in.getTransportVersion().isPatchFrom(TransportVersions.REMOVE_DESIRED_NODE_VERSION_90) == false) { in.readOptionalString(); } return new DesiredNode(settings, processors, processorsRange, memory, storage); @@ -180,7 +181,8 @@ public final class DesiredNode implements Writeable, ToXContentObject, Comparabl } memory.writeTo(out); storage.writeTo(out); - if (out.getTransportVersion().before(TransportVersions.REMOVE_DESIRED_NODE_VERSION)) { + if (out.getTransportVersion().before(TransportVersions.REMOVE_DESIRED_NODE_VERSION) + && out.getTransportVersion().isPatchFrom(TransportVersions.REMOVE_DESIRED_NODE_VERSION_90) == false) { out.writeOptionalString(null); } } diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolver.java b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolver.java index aa29acbcd1f3..856248bce0f9 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolver.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolver.java @@ -168,6 +168,13 @@ public class IndexAbstractionResolver { final boolean isHidden = indexAbstraction.isHidden(); boolean isVisible = isHidden == false || indicesOptions.expandWildcardsHidden() || isVisibleDueToImplicitHidden(expression, index); if (indexAbstraction.getType() == IndexAbstraction.Type.ALIAS) { + if (indexAbstraction.isSystem()) { + // check if it is net new + if (resolver.getNetNewSystemIndexPredicate().test(indexAbstraction.getName())) { + return isSystemIndexVisible(resolver, indexAbstraction); + } + } + // it's an alias, ignore expandWildcardsOpen and expandWildcardsClosed. // complicated to support those options with aliases pointing to multiple indices... isVisible = isVisible && indicesOptions.ignoreAliases() == false; diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/IndexShardRoutingTable.java b/server/src/main/java/org/elasticsearch/cluster/routing/IndexShardRoutingTable.java index c2a27a841467..80146029e0d9 100644 --- a/server/src/main/java/org/elasticsearch/cluster/routing/IndexShardRoutingTable.java +++ b/server/src/main/java/org/elasticsearch/cluster/routing/IndexShardRoutingTable.java @@ -207,11 +207,11 @@ public class IndexShardRoutingTable { } public ShardIterator shardsRandomIt() { - return new PlainShardIterator(shardId, shuffler.shuffle(Arrays.asList(shards))); + return new ShardIterator(shardId, shuffler.shuffle(Arrays.asList(shards))); } public ShardIterator shardsIt(int seed) { - return new PlainShardIterator(shardId, shuffler.shuffle(Arrays.asList(shards), seed)); + return new ShardIterator(shardId, shuffler.shuffle(Arrays.asList(shards), seed)); } /** @@ -228,12 +228,12 @@ public class IndexShardRoutingTable { */ public ShardIterator activeInitializingShardsIt(int seed) { if (allInitializingShards.isEmpty()) { - return new PlainShardIterator(shardId, shuffler.shuffle(activeShards, seed)); + return new ShardIterator(shardId, shuffler.shuffle(activeShards, seed)); } ArrayList ordered = new ArrayList<>(activeShards.size() + allInitializingShards.size()); ordered.addAll(shuffler.shuffle(activeShards, seed)); ordered.addAll(allInitializingShards); - return new PlainShardIterator(shardId, ordered); + return new ShardIterator(shardId, ordered); } /** @@ -247,10 +247,7 @@ public class IndexShardRoutingTable { ) { final int seed = shuffler.nextSeed(); if (allInitializingShards.isEmpty()) { - return new PlainShardIterator( - shardId, - rankShardsAndUpdateStats(shuffler.shuffle(activeShards, seed), collector, nodeSearchCounts) - ); + return new ShardIterator(shardId, rankShardsAndUpdateStats(shuffler.shuffle(activeShards, seed), collector, nodeSearchCounts)); } ArrayList ordered = new ArrayList<>(activeShards.size() + allInitializingShards.size()); @@ -258,7 +255,7 @@ public class IndexShardRoutingTable { ordered.addAll(rankedActiveShards); List rankedInitializingShards = rankShardsAndUpdateStats(allInitializingShards, collector, nodeSearchCounts); ordered.addAll(rankedInitializingShards); - return new PlainShardIterator(shardId, ordered); + return new ShardIterator(shardId, ordered); } private static Set getAllNodeIds(final List shards) { @@ -416,9 +413,9 @@ public class IndexShardRoutingTable { */ public ShardIterator primaryShardIt() { if (primary != null) { - return new PlainShardIterator(shardId, Collections.singletonList(primary)); + return new ShardIterator(shardId, Collections.singletonList(primary)); } - return new PlainShardIterator(shardId, Collections.emptyList()); + return new ShardIterator(shardId, Collections.emptyList()); } public ShardIterator onlyNodeActiveInitializingShardsIt(String nodeId) { @@ -434,7 +431,7 @@ public class IndexShardRoutingTable { ordered.add(shardRouting); } } - return new PlainShardIterator(shardId, ordered); + return new ShardIterator(shardId, ordered); } public ShardIterator onlyNodeSelectorActiveInitializingShardsIt(String nodeAttributes, DiscoveryNodes discoveryNodes) { @@ -469,7 +466,7 @@ public class IndexShardRoutingTable { ); throw new IllegalArgumentException(message); } - return new PlainShardIterator(shardId, ordered); + return new ShardIterator(shardId, ordered); } public ShardIterator preferNodeActiveInitializingShardsIt(Set nodeIds) { @@ -487,7 +484,7 @@ public class IndexShardRoutingTable { if (allInitializingShards.isEmpty() == false) { preferred.addAll(allInitializingShards); } - return new PlainShardIterator(shardId, preferred); + return new ShardIterator(shardId, preferred); } @Override diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/OperationRouting.java b/server/src/main/java/org/elasticsearch/cluster/routing/OperationRouting.java index e824793d2636..e140a81bdfbb 100644 --- a/server/src/main/java/org/elasticsearch/cluster/routing/OperationRouting.java +++ b/server/src/main/java/org/elasticsearch/cluster/routing/OperationRouting.java @@ -84,7 +84,7 @@ public class OperationRouting { // If it is stateless, only route promotable shards. This is a temporary workaround until a more cohesive solution can be // implemented for search shards. if (isStateless && shards != null) { - return new PlainShardIterator( + return new ShardIterator( shards.shardId(), shards.getShardRoutings().stream().filter(ShardRouting::isPromotableToPrimary).collect(Collectors.toList()) ); @@ -123,10 +123,10 @@ public class OperationRouting { nodeCounts ); if (iterator != null) { - set.add(PlainShardIterator.allSearchableShards(iterator)); + set.add(ShardIterator.allSearchableShards(iterator)); } } - var res = new ArrayList<>(set); + List res = new ArrayList<>(set); CollectionUtil.timSort(res); return res; } diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/PlainShardIterator.java b/server/src/main/java/org/elasticsearch/cluster/routing/PlainShardIterator.java deleted file mode 100644 index a429cc040de3..000000000000 --- a/server/src/main/java/org/elasticsearch/cluster/routing/PlainShardIterator.java +++ /dev/null @@ -1,73 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -package org.elasticsearch.cluster.routing; - -import org.elasticsearch.index.shard.ShardId; - -import java.util.ArrayList; -import java.util.List; - -/** - * The {@link PlainShardIterator} is a {@link ShardsIterator} which iterates all - * shards or a given {@link ShardId shard id} - */ -public class PlainShardIterator extends PlainShardsIterator implements ShardIterator { - - private final ShardId shardId; - - public static PlainShardIterator allSearchableShards(ShardIterator shardIterator) { - return new PlainShardIterator(shardIterator.shardId(), shardsThatCanHandleSearches(shardIterator)); - } - - private static List shardsThatCanHandleSearches(ShardIterator iterator) { - final List shardsThatCanHandleSearches = new ArrayList<>(iterator.size()); - for (ShardRouting shardRouting : iterator) { - if (shardRouting.isSearchable()) { - shardsThatCanHandleSearches.add(shardRouting); - } - } - return shardsThatCanHandleSearches; - } - - /** - * Creates a {@link PlainShardIterator} instance that iterates over a subset of the given shards - * this the a given shardId. - * - * @param shardId shard id of the group - * @param shards shards to iterate - */ - public PlainShardIterator(ShardId shardId, List shards) { - super(shards); - this.shardId = shardId; - } - - @Override - public ShardId shardId() { - return this.shardId; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ShardIterator that = (ShardIterator) o; - return shardId.equals(that.shardId()); - } - - @Override - public int hashCode() { - return shardId.hashCode(); - } - - @Override - public int compareTo(ShardIterator o) { - return shardId.compareTo(o.shardId()); - } -} diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/RoutingTable.java b/server/src/main/java/org/elasticsearch/cluster/routing/RoutingTable.java index 94dc08fbea2b..a4f6f6f1136f 100644 --- a/server/src/main/java/org/elasticsearch/cluster/routing/RoutingTable.java +++ b/server/src/main/java/org/elasticsearch/cluster/routing/RoutingTable.java @@ -229,7 +229,7 @@ public class RoutingTable implements Iterable, Diffable, Diffable { +public final class ShardIterator extends PlainShardsIterator implements Comparable { + + private final ShardId shardId; + + public static ShardIterator allSearchableShards(ShardIterator shardIterator) { + return new ShardIterator(shardIterator.shardId(), shardsThatCanHandleSearches(shardIterator)); + } + + private static List shardsThatCanHandleSearches(ShardIterator iterator) { + final List shardsThatCanHandleSearches = new ArrayList<>(iterator.size()); + for (ShardRouting shardRouting : iterator) { + if (shardRouting.isSearchable()) { + shardsThatCanHandleSearches.add(shardRouting); + } + } + return shardsThatCanHandleSearches; + } + + /** + * Creates a {@link ShardIterator} instance that iterates all shards + * of a given shardId. + * + * @param shardId shard id of the group + * @param shards shards to iterate + */ + public ShardIterator(ShardId shardId, List shards) { + super(shards); + this.shardId = shardId; + } /** * The shard id this group relates to. */ - ShardId shardId(); + public ShardId shardId() { + return this.shardId; + } - /** - * Resets the iterator. - */ @Override - void reset(); + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ShardIterator that = (ShardIterator) o; + return shardId.equals(that.shardId()); + } + + @Override + public int hashCode() { + return shardId.hashCode(); + } + + @Override + public int compareTo(ShardIterator o) { + return shardId.compareTo(o.shardId()); + } } diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/ShardRouting.java b/server/src/main/java/org/elasticsearch/cluster/routing/ShardRouting.java index 7e947da0210e..2ce349e2d3b6 100644 --- a/server/src/main/java/org/elasticsearch/cluster/routing/ShardRouting.java +++ b/server/src/main/java/org/elasticsearch/cluster/routing/ShardRouting.java @@ -328,7 +328,7 @@ public final class ShardRouting implements Writeable, ToXContentObject { * A shard iterator with just this shard in it. */ public ShardIterator shardsIt() { - return new PlainShardIterator(shardId, List.of(this)); + return new ShardIterator(shardId, List.of(this)); } public ShardRouting(ShardId shardId, StreamInput in) throws IOException { diff --git a/server/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java b/server/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java index 35289352d7da..0686b7d7683e 100644 --- a/server/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java +++ b/server/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java @@ -42,6 +42,9 @@ import org.elasticsearch.index.store.Store; import org.elasticsearch.indices.IndicesRequestCache; import org.elasticsearch.indices.ShardLimitValidator; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -51,180 +54,192 @@ import java.util.Set; */ public final class IndexScopedSettings extends AbstractScopedSettings { - public static final Set> BUILT_IN_INDEX_SETTINGS = Set.of( - MaxRetryAllocationDecider.SETTING_ALLOCATION_MAX_RETRY, - MergeSchedulerConfig.AUTO_THROTTLE_SETTING, - MergeSchedulerConfig.MAX_MERGE_COUNT_SETTING, - MergeSchedulerConfig.MAX_THREAD_COUNT_SETTING, - IndexMetadata.SETTING_INDEX_VERSION_CREATED, - IndexMetadata.SETTING_INDEX_VERSION_COMPATIBILITY, - IndexMetadata.INDEX_ROUTING_EXCLUDE_GROUP_SETTING, - IndexMetadata.INDEX_ROUTING_INCLUDE_GROUP_SETTING, - IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_SETTING, - IndexMetadata.INDEX_AUTO_EXPAND_REPLICAS_SETTING, - IndexMetadata.INDEX_NUMBER_OF_REPLICAS_SETTING, - IndexMetadata.INDEX_NUMBER_OF_SHARDS_SETTING, - IndexMetadata.INDEX_ROUTING_PARTITION_SIZE_SETTING, - IndexMetadata.INDEX_NUMBER_OF_ROUTING_SHARDS_SETTING, - IndexMetadata.INDEX_READ_ONLY_SETTING, - IndexMetadata.INDEX_BLOCKS_READ_SETTING, - IndexMetadata.INDEX_BLOCKS_WRITE_SETTING, - IndexMetadata.INDEX_BLOCKS_METADATA_SETTING, - IndexMetadata.INDEX_BLOCKS_READ_ONLY_ALLOW_DELETE_SETTING, - IndexMetadata.INDEX_PRIORITY_SETTING, - IndexMetadata.INDEX_DATA_PATH_SETTING, - IndexMetadata.INDEX_HIDDEN_SETTING, - IndexMetadata.INDEX_FORMAT_SETTING, - IndexMetadata.INDEX_DOWNSAMPLE_SOURCE_NAME, - IndexMetadata.INDEX_DOWNSAMPLE_SOURCE_UUID, - IndexMetadata.INDEX_DOWNSAMPLE_ORIGIN_NAME, - IndexMetadata.INDEX_DOWNSAMPLE_ORIGIN_UUID, - IndexMetadata.INDEX_DOWNSAMPLE_STATUS, - IndexMetadata.INDEX_DOWNSAMPLE_INTERVAL, - SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_DEBUG_SETTING, - SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_WARN_SETTING, - SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_INFO_SETTING, - SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_TRACE_SETTING, - SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_WARN_SETTING, - SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_DEBUG_SETTING, - SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_INFO_SETTING, - SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_TRACE_SETTING, - SearchSlowLog.INDEX_SEARCH_SLOWLOG_INCLUDE_USER_SETTING, - IndexingSlowLog.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_WARN_SETTING, - IndexingSlowLog.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_DEBUG_SETTING, - IndexingSlowLog.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_INFO_SETTING, - IndexingSlowLog.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_TRACE_SETTING, - IndexingSlowLog.INDEX_INDEXING_SLOWLOG_REFORMAT_SETTING, - IndexingSlowLog.INDEX_INDEXING_SLOWLOG_MAX_SOURCE_CHARS_TO_LOG_SETTING, - IndexingSlowLog.INDEX_INDEXING_SLOWLOG_INCLUDE_USER_SETTING, - MergePolicyConfig.INDEX_COMPOUND_FORMAT_SETTING, - MergePolicyConfig.INDEX_MERGE_POLICY_TYPE_SETTING, - MergePolicyConfig.INDEX_MERGE_POLICY_DELETES_PCT_ALLOWED_SETTING, - MergePolicyConfig.INDEX_MERGE_POLICY_EXPUNGE_DELETES_ALLOWED_SETTING, - MergePolicyConfig.INDEX_MERGE_POLICY_FLOOR_SEGMENT_SETTING, - MergePolicyConfig.INDEX_MERGE_POLICY_MAX_MERGE_AT_ONCE_SETTING, - MergePolicyConfig.INDEX_MERGE_POLICY_MAX_MERGE_AT_ONCE_EXPLICIT_SETTING, - MergePolicyConfig.INDEX_MERGE_POLICY_MAX_MERGED_SEGMENT_SETTING, - MergePolicyConfig.INDEX_MERGE_POLICY_SEGMENTS_PER_TIER_SETTING, - MergePolicyConfig.INDEX_MERGE_POLICY_MERGE_FACTOR_SETTING, - IndexSortConfig.INDEX_SORT_FIELD_SETTING, - IndexSortConfig.INDEX_SORT_ORDER_SETTING, - IndexSortConfig.INDEX_SORT_MISSING_SETTING, - IndexSortConfig.INDEX_SORT_MODE_SETTING, - IndexSettings.INDEX_TRANSLOG_DURABILITY_SETTING, - IndexSettings.INDEX_WARMER_ENABLED_SETTING, - IndexSettings.INDEX_REFRESH_INTERVAL_SETTING, - IndexSettings.INDEX_FAST_REFRESH_SETTING, - IndexSettings.MAX_RESULT_WINDOW_SETTING, - IndexSettings.MAX_INNER_RESULT_WINDOW_SETTING, - IndexSettings.MAX_TOKEN_COUNT_SETTING, - IndexSettings.MAX_DOCVALUE_FIELDS_SEARCH_SETTING, - IndexSettings.MAX_SCRIPT_FIELDS_SETTING, - IndexSettings.MAX_NGRAM_DIFF_SETTING, - IndexSettings.MAX_SHINGLE_DIFF_SETTING, - IndexSettings.MAX_RESCORE_WINDOW_SETTING, - IndexSettings.MAX_ANALYZED_OFFSET_SETTING, - IndexSettings.WEIGHT_MATCHES_MODE_ENABLED_SETTING, - IndexSettings.MAX_TERMS_COUNT_SETTING, - IndexSettings.INDEX_TRANSLOG_SYNC_INTERVAL_SETTING, - IndexSettings.DEFAULT_FIELD_SETTING, - IndexSettings.QUERY_STRING_LENIENT_SETTING, - IndexSettings.ALLOW_UNMAPPED, - IndexSettings.INDEX_CHECK_ON_STARTUP, - IndexSettings.MAX_REFRESH_LISTENERS_PER_SHARD, - IndexSettings.MAX_SLICES_PER_SCROLL, - IndexSettings.MAX_REGEX_LENGTH_SETTING, - ShardsLimitAllocationDecider.INDEX_TOTAL_SHARDS_PER_NODE_SETTING, - IndexSettings.INDEX_GC_DELETES_SETTING, - IndexSettings.INDEX_SOFT_DELETES_SETTING, - IndexSettings.INDEX_SOFT_DELETES_RETENTION_OPERATIONS_SETTING, - IndexSettings.INDEX_SOFT_DELETES_RETENTION_LEASE_PERIOD_SETTING, - IndicesRequestCache.INDEX_CACHE_REQUEST_ENABLED_SETTING, - UnassignedInfo.INDEX_DELAYED_NODE_LEFT_TIMEOUT_SETTING, - EnableAllocationDecider.INDEX_ROUTING_REBALANCE_ENABLE_SETTING, - EnableAllocationDecider.INDEX_ROUTING_ALLOCATION_ENABLE_SETTING, - IndexSettings.INDEX_FLUSH_AFTER_MERGE_THRESHOLD_SIZE_SETTING, - IndexSettings.INDEX_TRANSLOG_FLUSH_THRESHOLD_SIZE_SETTING, - IndexSettings.INDEX_TRANSLOG_FLUSH_THRESHOLD_AGE_SETTING, - IndexSettings.INDEX_TRANSLOG_GENERATION_THRESHOLD_SIZE_SETTING, - IndexSettings.INDEX_TRANSLOG_RETENTION_AGE_SETTING, - IndexSettings.INDEX_TRANSLOG_RETENTION_SIZE_SETTING, - IndexSettings.INDEX_SEARCH_IDLE_AFTER, - IndexSettings.INDEX_SEARCH_THROTTLED, - IndexFieldDataService.INDEX_FIELDDATA_CACHE_KEY, - IndexSettings.IGNORE_ABOVE_SETTING, - FieldMapper.IGNORE_MALFORMED_SETTING, - FieldMapper.COERCE_SETTING, - Store.INDEX_STORE_STATS_REFRESH_INTERVAL_SETTING, - MapperService.INDEX_MAPPING_NESTED_FIELDS_LIMIT_SETTING, - MapperService.INDEX_MAPPING_NESTED_DOCS_LIMIT_SETTING, - MapperService.INDEX_MAPPING_IGNORE_DYNAMIC_BEYOND_LIMIT_SETTING, - MapperService.INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING, - MapperService.INDEX_MAPPING_DEPTH_LIMIT_SETTING, - MapperService.INDEX_MAPPING_DIMENSION_FIELDS_LIMIT_SETTING, - MapperService.INDEX_MAPPING_FIELD_NAME_LENGTH_LIMIT_SETTING, - MapperService.INDEX_MAPPER_DYNAMIC_SETTING, - BitsetFilterCache.INDEX_LOAD_RANDOM_ACCESS_FILTERS_EAGERLY_SETTING, - IndexModule.INDEX_STORE_TYPE_SETTING, - IndexModule.INDEX_STORE_PRE_LOAD_SETTING, - IndexModule.INDEX_RECOVERY_TYPE_SETTING, - IndexModule.INDEX_QUERY_CACHE_ENABLED_SETTING, - FsDirectoryFactory.INDEX_LOCK_FACTOR_SETTING, - EngineConfig.INDEX_CODEC_SETTING, - IndexMetadata.SETTING_WAIT_FOR_ACTIVE_SHARDS, - IndexSettings.DEFAULT_PIPELINE, - IndexSettings.FINAL_PIPELINE, - MetadataIndexStateService.VERIFIED_BEFORE_CLOSE_SETTING, - MetadataIndexStateService.VERIFIED_READ_ONLY_SETTING, - ExistingShardsAllocator.EXISTING_SHARDS_ALLOCATOR_SETTING, - DiskThresholdDecider.SETTING_IGNORE_DISK_WATERMARKS, - ShardLimitValidator.INDEX_SETTING_SHARD_LIMIT_GROUP, - DataTier.TIER_PREFERENCE_SETTING, - IndexSettings.BLOOM_FILTER_ID_FIELD_ENABLED_SETTING, - IndexSettings.LIFECYCLE_ORIGINATION_DATE_SETTING, - IndexSettings.LIFECYCLE_PARSE_ORIGINATION_DATE_SETTING, - IndexSettings.TIME_SERIES_ES87TSDB_CODEC_ENABLED_SETTING, - IndexSettings.LOGSDB_ROUTE_ON_SORT_FIELDS, - IndexSettings.LOGSDB_SORT_ON_HOST_NAME, - IndexSettings.LOGSDB_ADD_HOST_NAME_FIELD, - IndexSettings.PREFER_ILM_SETTING, - DataStreamFailureStoreDefinition.FAILURE_STORE_DEFINITION_VERSION_SETTING, - FieldMapper.SYNTHETIC_SOURCE_KEEP_INDEX_SETTING, - IgnoredSourceFieldMapper.SKIP_IGNORED_SOURCE_WRITE_SETTING, - IgnoredSourceFieldMapper.SKIP_IGNORED_SOURCE_READ_SETTING, - IndexSettings.INDEX_MAPPER_SOURCE_MODE_SETTING, - IndexSettings.RECOVERY_USE_SYNTHETIC_SOURCE_SETTING, - InferenceMetadataFieldsMapper.USE_LEGACY_SEMANTIC_TEXT_FORMAT, + public static final Set> BUILT_IN_INDEX_SETTINGS; - // validate that built-in similarities don't get redefined - Setting.groupSetting("index.similarity.", (s) -> { - Map groups = s.getAsGroups(); - for (String key : SimilarityService.BUILT_IN.keySet()) { - if (groups.containsKey(key)) { - throw new IllegalArgumentException( - "illegal value for [index.similarity." + key + "] cannot redefine built-in similarity" - ); - } - } - }, Property.IndexScope, Property.ServerlessPublic), // this allows similarity settings to be passed - Setting.groupSetting("index.analysis.", Property.IndexScope, Property.ServerlessPublic), // this allows analysis settings to be - // passed + static { + Set> settings = new HashSet<>( + Arrays.asList( + MaxRetryAllocationDecider.SETTING_ALLOCATION_MAX_RETRY, + MergeSchedulerConfig.AUTO_THROTTLE_SETTING, + MergeSchedulerConfig.MAX_MERGE_COUNT_SETTING, + MergeSchedulerConfig.MAX_THREAD_COUNT_SETTING, + IndexMetadata.SETTING_INDEX_VERSION_CREATED, + IndexMetadata.SETTING_INDEX_VERSION_COMPATIBILITY, + IndexMetadata.INDEX_ROUTING_EXCLUDE_GROUP_SETTING, + IndexMetadata.INDEX_ROUTING_INCLUDE_GROUP_SETTING, + IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_SETTING, + IndexMetadata.INDEX_AUTO_EXPAND_REPLICAS_SETTING, + IndexMetadata.INDEX_NUMBER_OF_REPLICAS_SETTING, + IndexMetadata.INDEX_NUMBER_OF_SHARDS_SETTING, + IndexMetadata.INDEX_ROUTING_PARTITION_SIZE_SETTING, + IndexMetadata.INDEX_NUMBER_OF_ROUTING_SHARDS_SETTING, + IndexMetadata.INDEX_READ_ONLY_SETTING, + IndexMetadata.INDEX_BLOCKS_READ_SETTING, + IndexMetadata.INDEX_BLOCKS_WRITE_SETTING, + IndexMetadata.INDEX_BLOCKS_METADATA_SETTING, + IndexMetadata.INDEX_BLOCKS_READ_ONLY_ALLOW_DELETE_SETTING, + IndexMetadata.INDEX_PRIORITY_SETTING, + IndexMetadata.INDEX_DATA_PATH_SETTING, + IndexMetadata.INDEX_HIDDEN_SETTING, + IndexMetadata.INDEX_FORMAT_SETTING, + IndexMetadata.INDEX_DOWNSAMPLE_SOURCE_NAME, + IndexMetadata.INDEX_DOWNSAMPLE_SOURCE_UUID, + IndexMetadata.INDEX_DOWNSAMPLE_ORIGIN_NAME, + IndexMetadata.INDEX_DOWNSAMPLE_ORIGIN_UUID, + IndexMetadata.INDEX_DOWNSAMPLE_STATUS, + IndexMetadata.INDEX_DOWNSAMPLE_INTERVAL, + SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_DEBUG_SETTING, + SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_WARN_SETTING, + SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_INFO_SETTING, + SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_TRACE_SETTING, + SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_WARN_SETTING, + SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_DEBUG_SETTING, + SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_INFO_SETTING, + SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_TRACE_SETTING, + SearchSlowLog.INDEX_SEARCH_SLOWLOG_INCLUDE_USER_SETTING, + IndexingSlowLog.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_WARN_SETTING, + IndexingSlowLog.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_DEBUG_SETTING, + IndexingSlowLog.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_INFO_SETTING, + IndexingSlowLog.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_TRACE_SETTING, + IndexingSlowLog.INDEX_INDEXING_SLOWLOG_REFORMAT_SETTING, + IndexingSlowLog.INDEX_INDEXING_SLOWLOG_MAX_SOURCE_CHARS_TO_LOG_SETTING, + IndexingSlowLog.INDEX_INDEXING_SLOWLOG_INCLUDE_USER_SETTING, + MergePolicyConfig.INDEX_COMPOUND_FORMAT_SETTING, + MergePolicyConfig.INDEX_MERGE_POLICY_TYPE_SETTING, + MergePolicyConfig.INDEX_MERGE_POLICY_DELETES_PCT_ALLOWED_SETTING, + MergePolicyConfig.INDEX_MERGE_POLICY_EXPUNGE_DELETES_ALLOWED_SETTING, + MergePolicyConfig.INDEX_MERGE_POLICY_FLOOR_SEGMENT_SETTING, + MergePolicyConfig.INDEX_MERGE_POLICY_MAX_MERGE_AT_ONCE_SETTING, + MergePolicyConfig.INDEX_MERGE_POLICY_MAX_MERGE_AT_ONCE_EXPLICIT_SETTING, + MergePolicyConfig.INDEX_MERGE_POLICY_MAX_MERGED_SEGMENT_SETTING, + MergePolicyConfig.INDEX_MERGE_POLICY_SEGMENTS_PER_TIER_SETTING, + MergePolicyConfig.INDEX_MERGE_POLICY_MERGE_FACTOR_SETTING, + IndexSortConfig.INDEX_SORT_FIELD_SETTING, + IndexSortConfig.INDEX_SORT_ORDER_SETTING, + IndexSortConfig.INDEX_SORT_MISSING_SETTING, + IndexSortConfig.INDEX_SORT_MODE_SETTING, + IndexSettings.INDEX_TRANSLOG_DURABILITY_SETTING, + IndexSettings.INDEX_WARMER_ENABLED_SETTING, + IndexSettings.INDEX_REFRESH_INTERVAL_SETTING, + IndexSettings.INDEX_FAST_REFRESH_SETTING, + IndexSettings.MAX_RESULT_WINDOW_SETTING, + IndexSettings.MAX_INNER_RESULT_WINDOW_SETTING, + IndexSettings.MAX_TOKEN_COUNT_SETTING, + IndexSettings.MAX_DOCVALUE_FIELDS_SEARCH_SETTING, + IndexSettings.MAX_SCRIPT_FIELDS_SETTING, + IndexSettings.MAX_NGRAM_DIFF_SETTING, + IndexSettings.MAX_SHINGLE_DIFF_SETTING, + IndexSettings.MAX_RESCORE_WINDOW_SETTING, + IndexSettings.MAX_ANALYZED_OFFSET_SETTING, + IndexSettings.WEIGHT_MATCHES_MODE_ENABLED_SETTING, + IndexSettings.MAX_TERMS_COUNT_SETTING, + IndexSettings.INDEX_TRANSLOG_SYNC_INTERVAL_SETTING, + IndexSettings.DEFAULT_FIELD_SETTING, + IndexSettings.QUERY_STRING_LENIENT_SETTING, + IndexSettings.ALLOW_UNMAPPED, + IndexSettings.INDEX_CHECK_ON_STARTUP, + IndexSettings.MAX_REFRESH_LISTENERS_PER_SHARD, + IndexSettings.MAX_SLICES_PER_SCROLL, + IndexSettings.MAX_REGEX_LENGTH_SETTING, + ShardsLimitAllocationDecider.INDEX_TOTAL_SHARDS_PER_NODE_SETTING, + IndexSettings.INDEX_GC_DELETES_SETTING, + IndexSettings.INDEX_SOFT_DELETES_SETTING, + IndexSettings.INDEX_SOFT_DELETES_RETENTION_OPERATIONS_SETTING, + IndexSettings.INDEX_SOFT_DELETES_RETENTION_LEASE_PERIOD_SETTING, + IndicesRequestCache.INDEX_CACHE_REQUEST_ENABLED_SETTING, + UnassignedInfo.INDEX_DELAYED_NODE_LEFT_TIMEOUT_SETTING, + EnableAllocationDecider.INDEX_ROUTING_REBALANCE_ENABLE_SETTING, + EnableAllocationDecider.INDEX_ROUTING_ALLOCATION_ENABLE_SETTING, + IndexSettings.INDEX_FLUSH_AFTER_MERGE_THRESHOLD_SIZE_SETTING, + IndexSettings.INDEX_TRANSLOG_FLUSH_THRESHOLD_SIZE_SETTING, + IndexSettings.INDEX_TRANSLOG_FLUSH_THRESHOLD_AGE_SETTING, + IndexSettings.INDEX_TRANSLOG_GENERATION_THRESHOLD_SIZE_SETTING, + IndexSettings.INDEX_TRANSLOG_RETENTION_AGE_SETTING, + IndexSettings.INDEX_TRANSLOG_RETENTION_SIZE_SETTING, + IndexSettings.INDEX_SEARCH_IDLE_AFTER, + IndexSettings.INDEX_SEARCH_THROTTLED, + IndexFieldDataService.INDEX_FIELDDATA_CACHE_KEY, + IndexSettings.IGNORE_ABOVE_SETTING, + FieldMapper.IGNORE_MALFORMED_SETTING, + FieldMapper.COERCE_SETTING, + Store.INDEX_STORE_STATS_REFRESH_INTERVAL_SETTING, + MapperService.INDEX_MAPPING_NESTED_FIELDS_LIMIT_SETTING, + MapperService.INDEX_MAPPING_NESTED_DOCS_LIMIT_SETTING, + MapperService.INDEX_MAPPING_IGNORE_DYNAMIC_BEYOND_LIMIT_SETTING, + MapperService.INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING, + MapperService.INDEX_MAPPING_DEPTH_LIMIT_SETTING, + MapperService.INDEX_MAPPING_DIMENSION_FIELDS_LIMIT_SETTING, + MapperService.INDEX_MAPPING_FIELD_NAME_LENGTH_LIMIT_SETTING, + MapperService.INDEX_MAPPER_DYNAMIC_SETTING, + BitsetFilterCache.INDEX_LOAD_RANDOM_ACCESS_FILTERS_EAGERLY_SETTING, + IndexModule.INDEX_STORE_TYPE_SETTING, + IndexModule.INDEX_STORE_PRE_LOAD_SETTING, + IndexModule.INDEX_RECOVERY_TYPE_SETTING, + IndexModule.INDEX_QUERY_CACHE_ENABLED_SETTING, + FsDirectoryFactory.INDEX_LOCK_FACTOR_SETTING, + EngineConfig.INDEX_CODEC_SETTING, + IndexMetadata.SETTING_WAIT_FOR_ACTIVE_SHARDS, + IndexSettings.DEFAULT_PIPELINE, + IndexSettings.FINAL_PIPELINE, + MetadataIndexStateService.VERIFIED_BEFORE_CLOSE_SETTING, + MetadataIndexStateService.VERIFIED_READ_ONLY_SETTING, + ExistingShardsAllocator.EXISTING_SHARDS_ALLOCATOR_SETTING, + DiskThresholdDecider.SETTING_IGNORE_DISK_WATERMARKS, + ShardLimitValidator.INDEX_SETTING_SHARD_LIMIT_GROUP, + DataTier.TIER_PREFERENCE_SETTING, + IndexSettings.BLOOM_FILTER_ID_FIELD_ENABLED_SETTING, + IndexSettings.LIFECYCLE_ORIGINATION_DATE_SETTING, + IndexSettings.LIFECYCLE_PARSE_ORIGINATION_DATE_SETTING, + IndexSettings.TIME_SERIES_ES87TSDB_CODEC_ENABLED_SETTING, + IndexSettings.LOGSDB_ROUTE_ON_SORT_FIELDS, + IndexSettings.LOGSDB_SORT_ON_HOST_NAME, + IndexSettings.LOGSDB_ADD_HOST_NAME_FIELD, + IndexSettings.PREFER_ILM_SETTING, + DataStreamFailureStoreDefinition.FAILURE_STORE_DEFINITION_VERSION_SETTING, + FieldMapper.SYNTHETIC_SOURCE_KEEP_INDEX_SETTING, + IgnoredSourceFieldMapper.SKIP_IGNORED_SOURCE_WRITE_SETTING, + IgnoredSourceFieldMapper.SKIP_IGNORED_SOURCE_READ_SETTING, + IndexSettings.INDEX_MAPPER_SOURCE_MODE_SETTING, + IndexSettings.RECOVERY_USE_SYNTHETIC_SOURCE_SETTING, + InferenceMetadataFieldsMapper.USE_LEGACY_SEMANTIC_TEXT_FORMAT, - // TSDB index settings - IndexSettings.MODE, - IndexMetadata.INDEX_ROUTING_PATH, - IndexSettings.TIME_SERIES_START_TIME, - IndexSettings.TIME_SERIES_END_TIME, + // validate that built-in similarities don't get redefined + Setting.groupSetting("index.similarity.", (s) -> { + Map groups = s.getAsGroups(); + for (String key : SimilarityService.BUILT_IN.keySet()) { + if (groups.containsKey(key)) { + throw new IllegalArgumentException( + "illegal value for [index.similarity." + key + "] cannot redefine built-in similarity" + ); + } + } + }, Property.IndexScope, Property.ServerlessPublic), // this allows similarity settings to be passed + Setting.groupSetting("index.analysis.", Property.IndexScope, Property.ServerlessPublic), // this allows analysis settings to + // be + // passed - // Legacy index settings we must keep around for BWC from 7.x - EngineConfig.INDEX_OPTIMIZE_AUTO_GENERATED_IDS, - IndexMetadata.INDEX_ROLLUP_SOURCE_NAME, - IndexMetadata.INDEX_ROLLUP_SOURCE_UUID, - IndexSettings.MAX_ADJACENCY_MATRIX_FILTERS_SETTING, - IndexingSlowLog.INDEX_INDEXING_SLOWLOG_LEVEL_SETTING, - SearchSlowLog.INDEX_SEARCH_SLOWLOG_LEVEL, - Store.FORCE_RAM_TERM_DICT - ); + // TSDB index settings + IndexSettings.MODE, + IndexMetadata.INDEX_ROUTING_PATH, + IndexSettings.TIME_SERIES_START_TIME, + IndexSettings.TIME_SERIES_END_TIME, + + // Legacy index settings we must keep around for BWC from 7.x + EngineConfig.INDEX_OPTIMIZE_AUTO_GENERATED_IDS, + IndexMetadata.INDEX_ROLLUP_SOURCE_NAME, + IndexMetadata.INDEX_ROLLUP_SOURCE_UUID, + IndexSettings.MAX_ADJACENCY_MATRIX_FILTERS_SETTING, + IndexingSlowLog.INDEX_INDEXING_SLOWLOG_LEVEL_SETTING, + SearchSlowLog.INDEX_SEARCH_SLOWLOG_LEVEL, + Store.FORCE_RAM_TERM_DICT + ) + ); + + if (IndexSettings.DOC_VALUES_SKIPPER.isEnabled()) { + settings.add(IndexSettings.USE_DOC_VALUES_SKIPPER); + } + BUILT_IN_INDEX_SETTINGS = Collections.unmodifiableSet(settings); + }; public static final IndexScopedSettings DEFAULT_SCOPED_SETTINGS = new IndexScopedSettings(Settings.EMPTY, BUILT_IN_INDEX_SETTINGS); diff --git a/server/src/main/java/org/elasticsearch/features/FeatureService.java b/server/src/main/java/org/elasticsearch/features/FeatureService.java index 9f4ec6209c6f..a4316aeeaf30 100644 --- a/server/src/main/java/org/elasticsearch/features/FeatureService.java +++ b/server/src/main/java/org/elasticsearch/features/FeatureService.java @@ -53,14 +53,14 @@ public class FeatureService { /** * Returns {@code true} if {@code node} can have assumed features. */ - public boolean featuresCanBeAssumedForNode(DiscoveryNode node) { + public static boolean featuresCanBeAssumedForNode(DiscoveryNode node) { return ClusterFeatures.featuresCanBeAssumedForNode(node); } /** * Returns {@code true} if one or more nodes in {@code nodes} can have assumed features. */ - public boolean featuresCanBeAssumedForNodes(DiscoveryNodes nodes) { + public static boolean featuresCanBeAssumedForNodes(DiscoveryNodes nodes) { return ClusterFeatures.featuresCanBeAssumedForNodes(nodes); } diff --git a/server/src/main/java/org/elasticsearch/health/metadata/HealthMetadataService.java b/server/src/main/java/org/elasticsearch/health/metadata/HealthMetadataService.java index 0d30e157a3a0..1c3ac11fb50e 100644 --- a/server/src/main/java/org/elasticsearch/health/metadata/HealthMetadataService.java +++ b/server/src/main/java/org/elasticsearch/health/metadata/HealthMetadataService.java @@ -26,7 +26,6 @@ import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.Nullable; import org.elasticsearch.core.Tuple; -import org.elasticsearch.features.FeatureService; import org.elasticsearch.gateway.GatewayService; import java.util.List; @@ -50,7 +49,6 @@ public class HealthMetadataService { private static final Logger logger = LogManager.getLogger(HealthMetadataService.class); private final ClusterService clusterService; - private final FeatureService featureService; private final ClusterStateListener clusterStateListener; private final MasterServiceTaskQueue taskQueue; private volatile boolean enabled; @@ -64,17 +62,16 @@ public class HealthMetadataService { // ClusterState to maintain an up-to-date version of it across the cluster. private volatile HealthMetadata localHealthMetadata; - private HealthMetadataService(ClusterService clusterService, FeatureService featureService, Settings settings) { + private HealthMetadataService(ClusterService clusterService, Settings settings) { this.clusterService = clusterService; - this.featureService = featureService; this.clusterStateListener = this::updateOnClusterStateChange; this.enabled = ENABLED_SETTING.get(settings); this.localHealthMetadata = initialHealthMetadata(settings); this.taskQueue = clusterService.createTaskQueue("health metadata service", Priority.NORMAL, new Executor()); } - public static HealthMetadataService create(ClusterService clusterService, FeatureService featureService, Settings settings) { - HealthMetadataService healthMetadataService = new HealthMetadataService(clusterService, featureService, settings); + public static HealthMetadataService create(ClusterService clusterService, Settings settings) { + HealthMetadataService healthMetadataService = new HealthMetadataService(clusterService, settings); healthMetadataService.registerListeners(); return healthMetadataService; } diff --git a/server/src/main/java/org/elasticsearch/health/node/DiskHealthIndicatorService.java b/server/src/main/java/org/elasticsearch/health/node/DiskHealthIndicatorService.java index de1c2c1f7113..e7333223389d 100644 --- a/server/src/main/java/org/elasticsearch/health/node/DiskHealthIndicatorService.java +++ b/server/src/main/java/org/elasticsearch/health/node/DiskHealthIndicatorService.java @@ -19,7 +19,6 @@ import org.elasticsearch.cluster.routing.RoutingNodes; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.core.FixForMultiProject; -import org.elasticsearch.features.FeatureService; import org.elasticsearch.health.Diagnosis; import org.elasticsearch.health.HealthIndicatorDetails; import org.elasticsearch.health.HealthIndicatorImpact; @@ -74,11 +73,9 @@ public class DiskHealthIndicatorService implements HealthIndicatorService { private static final String IMPACT_CLUSTER_FUNCTIONALITY_UNAVAILABLE_ID = "cluster_functionality_unavailable"; private final ClusterService clusterService; - private final FeatureService featureService; - public DiskHealthIndicatorService(ClusterService clusterService, FeatureService featureService) { + public DiskHealthIndicatorService(ClusterService clusterService) { this.clusterService = clusterService; - this.featureService = featureService; } @Override diff --git a/server/src/main/java/org/elasticsearch/health/node/selection/HealthNodeTaskExecutor.java b/server/src/main/java/org/elasticsearch/health/node/selection/HealthNodeTaskExecutor.java index 7c37a0ce5d92..48cbbb188dd9 100644 --- a/server/src/main/java/org/elasticsearch/health/node/selection/HealthNodeTaskExecutor.java +++ b/server/src/main/java/org/elasticsearch/health/node/selection/HealthNodeTaskExecutor.java @@ -23,7 +23,6 @@ import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.TimeValue; -import org.elasticsearch.features.FeatureService; import org.elasticsearch.node.NodeClosedException; import org.elasticsearch.persistent.AllocatedPersistentTask; import org.elasticsearch.persistent.PersistentTaskParams; @@ -60,22 +59,15 @@ public final class HealthNodeTaskExecutor extends PersistentTasksExecutor currentTask = new AtomicReference<>(); private final ClusterStateListener taskStarter; private final ClusterStateListener shutdownListener; private volatile boolean enabled; - private HealthNodeTaskExecutor( - ClusterService clusterService, - PersistentTasksService persistentTasksService, - FeatureService featureService, - Settings settings - ) { + private HealthNodeTaskExecutor(ClusterService clusterService, PersistentTasksService persistentTasksService, Settings settings) { super(TASK_NAME, clusterService.threadPool().executor(ThreadPool.Names.MANAGEMENT)); this.clusterService = clusterService; this.persistentTasksService = persistentTasksService; - this.featureService = featureService; this.taskStarter = this::startTask; this.shutdownListener = this::shuttingDown; this.enabled = ENABLED_SETTING.get(settings); @@ -84,16 +76,10 @@ public final class HealthNodeTaskExecutor extends PersistentTasksExecutor "failed to send failure response for uri [" + restRequest.uri() + "]", inner); + } + return; + } dispatcher.dispatchRequest(restRequest, channel, threadContext); } } } - private void populatePerRequestThreadContext0(RestRequest restRequest, RestChannel channel, ThreadContext threadContext) { - try { - populatePerRequestThreadContext(restRequest, threadContext); - } catch (Exception e) { - try { - channel.sendResponse(new RestResponse(channel, e)); - } catch (Exception inner) { - inner.addSuppressed(e); - logger.error(() -> "failed to send failure response for uri [" + restRequest.uri() + "]", inner); - } - } - } - protected void populatePerRequestThreadContext(RestRequest restRequest, ThreadContext threadContext) {} private void handleIncomingRequest(final HttpRequest httpRequest, final HttpChannel httpChannel, final Exception exception) { diff --git a/server/src/main/java/org/elasticsearch/index/CompositeIndexEventListener.java b/server/src/main/java/org/elasticsearch/index/CompositeIndexEventListener.java index 56d12b6d563c..1f55b92982ab 100644 --- a/server/src/main/java/org/elasticsearch/index/CompositeIndexEventListener.java +++ b/server/src/main/java/org/elasticsearch/index/CompositeIndexEventListener.java @@ -137,6 +137,24 @@ final class CompositeIndexEventListener implements IndexEventListener { } } + @Override + public void beforeIndexShardMutableOperation(IndexShard indexShard, ActionListener listener) { + iterateBeforeIndexShardMutableOperation(indexShard, listener.delegateResponse((l, e) -> { + logger.warn(() -> format("%s failed to invoke the listener before ensuring shard mutability", indexShard.shardId()), e); + l.onFailure(e); + })); + } + + private void iterateBeforeIndexShardMutableOperation(IndexShard indexShard, ActionListener outerListener) { + callListeners( + indexShard, + listeners.stream() + .map(iel -> (Consumer>) (l) -> iel.beforeIndexShardMutableOperation(indexShard, l)) + .iterator(), + outerListener + ); + } + @Override public void beforeIndexCreated(Index index, Settings indexSettings) { for (IndexEventListener listener : listeners) { diff --git a/server/src/main/java/org/elasticsearch/index/IndexSettings.java b/server/src/main/java/org/elasticsearch/index/IndexSettings.java index 525f90accdf3..4c7bda1c52f1 100644 --- a/server/src/main/java/org/elasticsearch/index/IndexSettings.java +++ b/server/src/main/java/org/elasticsearch/index/IndexSettings.java @@ -685,6 +685,14 @@ public final class IndexSettings { Property.Final ); + public static final FeatureFlag DOC_VALUES_SKIPPER = new FeatureFlag("doc_values_skipper"); + public static final Setting USE_DOC_VALUES_SKIPPER = Setting.boolSetting( + "index.mapping.use_doc_values_skipper", + IndexSettings.DOC_VALUES_SKIPPER.isEnabled(), + Property.IndexScope, + Property.Final + ); + /** * The {@link IndexMode "mode"} of the index. */ @@ -922,6 +930,7 @@ public final class IndexSettings { private final SourceFieldMapper.Mode indexMappingSourceMode; private final boolean recoverySourceEnabled; private final boolean recoverySourceSyntheticEnabled; + private final boolean useDocValuesSkipper; /** * The maximum number of refresh listeners allows on this shard. @@ -1103,6 +1112,7 @@ public final class IndexSettings { recoverySourceEnabled = RecoverySettings.INDICES_RECOVERY_SOURCE_ENABLED_SETTING.get(nodeSettings); recoverySourceSyntheticEnabled = DiscoveryNode.isStateless(nodeSettings) == false && scopedSettings.get(RECOVERY_USE_SYNTHETIC_SOURCE_SETTING); + useDocValuesSkipper = DOC_VALUES_SKIPPER.isEnabled() && scopedSettings.get(USE_DOC_VALUES_SKIPPER); if (recoverySourceSyntheticEnabled) { if (DiscoveryNode.isStateless(settings)) { throw new IllegalArgumentException("synthetic recovery source is only allowed in stateful"); @@ -1822,6 +1832,10 @@ public final class IndexSettings { return recoverySourceSyntheticEnabled; } + public boolean useDocValuesSkipper() { + return useDocValuesSkipper; + } + /** * The bounds for {@code @timestamp} on this index or * {@code null} if there are no bounds. diff --git a/server/src/main/java/org/elasticsearch/index/IndexSortConfig.java b/server/src/main/java/org/elasticsearch/index/IndexSortConfig.java index 94d1cc518245..28de14ec0422 100644 --- a/server/src/main/java/org/elasticsearch/index/IndexSortConfig.java +++ b/server/src/main/java/org/elasticsearch/index/IndexSortConfig.java @@ -302,6 +302,15 @@ public final class IndexSortConfig { } } + public boolean hasSortOnField(final String fieldName) { + for (FieldSortSpec sortSpec : sortSpecs) { + if (sortSpec.field.equals(fieldName)) { + return true; + } + } + return false; + } + public static class FieldSortSpec { final String field; SortOrder order; diff --git a/server/src/main/java/org/elasticsearch/index/engine/Engine.java b/server/src/main/java/org/elasticsearch/index/engine/Engine.java index 36fd18144ad6..0589741a7028 100644 --- a/server/src/main/java/org/elasticsearch/index/engine/Engine.java +++ b/server/src/main/java/org/elasticsearch/index/engine/Engine.java @@ -2346,4 +2346,8 @@ public abstract class Engine implements Closeable { public void prepareForEngineReset() throws IOException { throw new UnsupportedOperationException("does not support engine reset"); } + + public long getLastUnsafeSegmentGenerationForGets() { + throw new UnsupportedOperationException("Doesn't support getting the latest segment generation"); + } } diff --git a/server/src/main/java/org/elasticsearch/index/engine/LuceneSyntheticSourceChangesSnapshot.java b/server/src/main/java/org/elasticsearch/index/engine/LuceneSyntheticSourceChangesSnapshot.java index 20154c20b363..73a92869e31b 100644 --- a/server/src/main/java/org/elasticsearch/index/engine/LuceneSyntheticSourceChangesSnapshot.java +++ b/server/src/main/java/org/elasticsearch/index/engine/LuceneSyntheticSourceChangesSnapshot.java @@ -9,6 +9,8 @@ package org.elasticsearch.index.engine; +import com.carrotsearch.hppc.IntArrayList; + import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.FieldDoc; import org.apache.lucene.search.ScoreDoc; @@ -191,8 +193,28 @@ public class LuceneSyntheticSourceChangesSnapshot extends SearchBasedChangesSnap maxDoc = leafReaderContext.reader().maxDoc(); } while (docRecord.docID() >= docBase + maxDoc); - leafFieldLoader = storedFieldLoader.getLoader(leafReaderContext, null); - leafSourceLoader = sourceLoader.leaf(leafReaderContext.reader(), null); + // TODO: instead of building an array, consider just checking whether doc ids are dense. + // Note, field loaders then would lose the ability to optionally eagerly loading values. + IntArrayList nextDocIds = new IntArrayList(); + for (int j = i; j < documentRecords.size(); j++) { + var record = documentRecords.get(j); + if (record.isTombstone()) { + continue; + } + int docID = record.docID(); + if (docID >= docBase + maxDoc) { + break; + } + int segmentDocID = docID - docBase; + nextDocIds.add(segmentDocID); + } + + // This computed doc ids arrays us used by stored field loader as a heuristic to determine whether to use a sequential + // stored field reader (which bulk loads stored fields and avoids decompressing the same blocks multiple times). For + // source loader, it is also used as a heuristic for bulk reading doc values (E.g. SingletonDocValuesLoader). + int[] nextDocIdArray = nextDocIds.toArray(); + leafFieldLoader = storedFieldLoader.getLoader(leafReaderContext, nextDocIdArray); + leafSourceLoader = sourceLoader.leaf(leafReaderContext.reader(), nextDocIdArray); setNextSourceMetadataReader(leafReaderContext); } int segmentDocID = docRecord.docID() - docBase; diff --git a/server/src/main/java/org/elasticsearch/index/get/ShardGetService.java b/server/src/main/java/org/elasticsearch/index/get/ShardGetService.java index 9ed9fc6dabf3..f0f56333c752 100644 --- a/server/src/main/java/org/elasticsearch/index/get/ShardGetService.java +++ b/server/src/main/java/org/elasticsearch/index/get/ShardGetService.java @@ -21,7 +21,6 @@ import org.elasticsearch.common.metrics.CounterMetric; import org.elasticsearch.common.metrics.MeanMetric; import org.elasticsearch.core.Nullable; import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.IndexVersion; import org.elasticsearch.index.IndexVersions; import org.elasticsearch.index.VersionType; import org.elasticsearch.index.engine.Engine; @@ -93,7 +92,7 @@ public final class ShardGetService extends AbstractIndexShardComponent { FetchSourceContext fetchSourceContext, boolean forceSyntheticSource ) throws IOException { - return get( + return doGet( id, gFields, realtime, @@ -107,7 +106,7 @@ public final class ShardGetService extends AbstractIndexShardComponent { ); } - public GetResult get( + public GetResult mget( String id, String[] gFields, boolean realtime, @@ -117,7 +116,7 @@ public final class ShardGetService extends AbstractIndexShardComponent { boolean forceSyntheticSource, MultiEngineGet mget ) throws IOException { - return get( + return doGet( id, gFields, realtime, @@ -131,7 +130,7 @@ public final class ShardGetService extends AbstractIndexShardComponent { ); } - private GetResult get( + private GetResult doGet( String id, String[] gFields, boolean realtime, @@ -144,21 +143,40 @@ public final class ShardGetService extends AbstractIndexShardComponent { Function engineGetOperator ) throws IOException { currentMetric.inc(); + final long now = System.nanoTime(); try { - long now = System.nanoTime(); - GetResult getResult = innerGet( - id, - gFields, - realtime, - version, - versionType, - ifSeqNo, - ifPrimaryTerm, - fetchSourceContext, - forceSyntheticSource, - engineGetOperator - ); + var engineGet = new Engine.Get(realtime, realtime, id).version(version) + .versionType(versionType) + .setIfSeqNo(ifSeqNo) + .setIfPrimaryTerm(ifPrimaryTerm); + final GetResult getResult; + try (Engine.GetResult get = engineGetOperator.apply(engineGet)) { + if (get == null) { + getResult = null; + } else if (get.exists() == false) { + getResult = new GetResult( + shardId.getIndexName(), + id, + UNASSIGNED_SEQ_NO, + UNASSIGNED_PRIMARY_TERM, + -1, + false, + null, + null, + null + ); + } else { + // break between having loaded it from translog (so we only have _source), and having a document to load + getResult = innerGetFetch( + id, + gFields, + normalizeFetchSourceContent(fetchSourceContext, gFields), + get, + forceSyntheticSource + ); + } + } if (getResult != null && getResult.isExists()) { existsMetric.inc(System.nanoTime() - now); } else { @@ -179,7 +197,7 @@ public final class ShardGetService extends AbstractIndexShardComponent { FetchSourceContext fetchSourceContext, boolean forceSyntheticSource ) throws IOException { - return get( + return doGet( id, gFields, realtime, @@ -193,12 +211,8 @@ public final class ShardGetService extends AbstractIndexShardComponent { ); } - public GetResult getForUpdate(String id, long ifSeqNo, long ifPrimaryTerm) throws IOException { - return getForUpdate(id, ifSeqNo, ifPrimaryTerm, new String[] { RoutingFieldMapper.NAME }); - } - public GetResult getForUpdate(String id, long ifSeqNo, long ifPrimaryTerm, String[] gFields) throws IOException { - return get( + return doGet( id, gFields, true, @@ -259,35 +273,6 @@ public final class ShardGetService extends AbstractIndexShardComponent { return FetchSourceContext.DO_NOT_FETCH_SOURCE; } - private GetResult innerGet( - String id, - String[] gFields, - boolean realtime, - long version, - VersionType versionType, - long ifSeqNo, - long ifPrimaryTerm, - FetchSourceContext fetchSourceContext, - boolean forceSyntheticSource, - Function engineGetOperator - ) throws IOException { - fetchSourceContext = normalizeFetchSourceContent(fetchSourceContext, gFields); - var engineGet = new Engine.Get(realtime, realtime, id).version(version) - .versionType(versionType) - .setIfSeqNo(ifSeqNo) - .setIfPrimaryTerm(ifPrimaryTerm); - try (Engine.GetResult get = engineGetOperator.apply(engineGet)) { - if (get == null) { - return null; - } - if (get.exists() == false) { - return new GetResult(shardId.getIndexName(), id, UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM, -1, false, null, null, null); - } - // break between having loaded it from translog (so we only have _source), and having a document to load - return innerGetFetch(id, gFields, fetchSourceContext, get, forceSyntheticSource); - } - } - private GetResult innerGetFetch( String id, String[] storedFields, @@ -298,7 +283,6 @@ public final class ShardGetService extends AbstractIndexShardComponent { assert get.exists() : "method should only be called if document could be retrieved"; // check first if stored fields to be loaded don't contain an object field MappingLookup mappingLookup = mapperService.mappingLookup(); - final IndexVersion indexVersion = indexSettings.getIndexVersionCreated(); final Set storedFieldSet = new HashSet<>(); boolean hasInferenceMetadataFields = false; if (storedFields != null) { @@ -338,6 +322,9 @@ public final class ShardGetService extends AbstractIndexShardComponent { throw new ElasticsearchException("Failed to get id [" + id + "]", e); } + final boolean supportDocValuesForIgnoredMetaField = indexSettings.getIndexVersionCreated() + .onOrAfter(IndexVersions.DOC_VALUES_FOR_IGNORED_META_FIELD); + // put stored fields into result objects if (leafStoredFieldLoader.storedFields().isEmpty() == false) { Set needed = new HashSet<>(); @@ -351,8 +338,7 @@ public final class ShardGetService extends AbstractIndexShardComponent { if (false == needed.contains(entry.getKey())) { continue; } - if (IgnoredFieldMapper.NAME.equals(entry.getKey()) - && indexVersion.onOrAfter(IndexVersions.DOC_VALUES_FOR_IGNORED_META_FIELD)) { + if (IgnoredFieldMapper.NAME.equals(entry.getKey()) && supportDocValuesForIgnoredMetaField) { continue; } MappedFieldType ft = mapperService.fieldType(entry.getKey()); @@ -371,9 +357,7 @@ public final class ShardGetService extends AbstractIndexShardComponent { // NOTE: when _ignored is requested via `stored_fields` we need to load it from doc values instead of loading it from stored fields. // The _ignored field used to be stored, but as a result of supporting aggregations on it, it moved from using a stored field to // using doc values. - if (indexVersion.onOrAfter(IndexVersions.DOC_VALUES_FOR_IGNORED_META_FIELD) - && storedFields != null - && Arrays.asList(storedFields).contains(IgnoredFieldMapper.NAME)) { + if (supportDocValuesForIgnoredMetaField && storedFields != null && Arrays.asList(storedFields).contains(IgnoredFieldMapper.NAME)) { final DocumentField ignoredDocumentField = loadIgnoredMetadataField(docIdAndVersion); if (ignoredDocumentField != null) { if (metadataFields == null) { diff --git a/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java index 2dfbf871ea18..11db4d3d5aa6 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java @@ -21,7 +21,6 @@ import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.util.CollectionUtils; -import org.elasticsearch.common.util.FeatureFlag; import org.elasticsearch.common.util.Maps; import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.index.IndexMode; @@ -63,8 +62,6 @@ import static org.elasticsearch.core.Strings.format; public abstract class FieldMapper extends Mapper { private static final Logger logger = LogManager.getLogger(FieldMapper.class); - - public static final FeatureFlag DOC_VALUES_SPARSE_INDEX = new FeatureFlag("doc_values_sparse_index"); public static final Setting IGNORE_MALFORMED_SETTING = Setting.boolSetting("index.mapping.ignore_malformed", settings -> { if (IndexSettings.MODE.get(settings) == IndexMode.LOGSDB && IndexMetadata.SETTING_INDEX_VERSION_CREATED.get(settings).onOrAfter(IndexVersions.ENABLE_IGNORE_MALFORMED_LOGSDB)) { diff --git a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java index 5cd968dff52a..df308a4bf983 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java @@ -84,6 +84,7 @@ import java.util.Set; import static org.apache.lucene.index.IndexWriter.MAX_TERM_LENGTH; import static org.elasticsearch.core.Strings.format; import static org.elasticsearch.index.IndexSettings.IGNORE_ABOVE_SETTING; +import static org.elasticsearch.index.IndexSettings.USE_DOC_VALUES_SKIPPER; /** * A field mapper for keywords. This mapper accepts strings and indexes them as-is. @@ -201,6 +202,7 @@ public final class KeywordFieldMapper extends FieldMapper { private final IndexAnalyzers indexAnalyzers; private final ScriptCompiler scriptCompiler; private final IndexVersion indexCreatedVersion; + private final boolean useDocValuesSkipper; public Builder(final String name, final MappingParserContext mappingParserContext) { this( @@ -210,7 +212,8 @@ public final class KeywordFieldMapper extends FieldMapper { IGNORE_ABOVE_SETTING.get(mappingParserContext.getSettings()), mappingParserContext.getIndexSettings().getIndexVersionCreated(), mappingParserContext.getIndexSettings().getMode(), - mappingParserContext.getIndexSettings().getIndexSortConfig() + mappingParserContext.getIndexSettings().getIndexSortConfig(), + USE_DOC_VALUES_SKIPPER.get(mappingParserContext.getSettings()) ); } @@ -221,7 +224,7 @@ public final class KeywordFieldMapper extends FieldMapper { int ignoreAboveDefault, IndexVersion indexCreatedVersion ) { - this(name, indexAnalyzers, scriptCompiler, ignoreAboveDefault, indexCreatedVersion, IndexMode.STANDARD, null); + this(name, indexAnalyzers, scriptCompiler, ignoreAboveDefault, indexCreatedVersion, IndexMode.STANDARD, null, false); } private Builder( @@ -231,7 +234,8 @@ public final class KeywordFieldMapper extends FieldMapper { int ignoreAboveDefault, IndexVersion indexCreatedVersion, IndexMode indexMode, - IndexSortConfig indexSortConfig + IndexSortConfig indexSortConfig, + boolean useDocValuesSkipper ) { super(name); this.indexAnalyzers = indexAnalyzers; @@ -268,6 +272,7 @@ public final class KeywordFieldMapper extends FieldMapper { }); this.indexSortConfig = indexSortConfig; this.indexMode = indexMode; + this.useDocValuesSkipper = useDocValuesSkipper; } public Builder(String name, IndexVersion indexCreatedVersion) { @@ -394,7 +399,13 @@ public final class KeywordFieldMapper extends FieldMapper { @Override public KeywordFieldMapper build(MapperBuilderContext context) { - FieldType fieldtype = resolveFieldType(indexCreatedVersion, indexSortConfig, indexMode, context.buildFullName(leafName())); + FieldType fieldtype = resolveFieldType( + useDocValuesSkipper, + indexCreatedVersion, + indexSortConfig, + indexMode, + context.buildFullName(leafName()) + ); fieldtype.setOmitNorms(this.hasNorms.getValue() == false); fieldtype.setStored(this.stored.getValue()); fieldtype.setDocValuesType(this.hasDocValues.getValue() ? DocValuesType.SORTED_SET : DocValuesType.NONE); @@ -417,65 +428,40 @@ public final class KeywordFieldMapper extends FieldMapper { buildFieldType(context, fieldtype), builderParams(this, context), context.isSourceSynthetic(), + useDocValuesSkipper, this ); } private FieldType resolveFieldType( + final boolean useDocValuesSkipper, final IndexVersion indexCreatedVersion, final IndexSortConfig indexSortConfig, final IndexMode indexMode, final String fullFieldName ) { - if (FieldMapper.DOC_VALUES_SPARSE_INDEX.isEnabled() + if (useDocValuesSkipper && indexCreatedVersion.onOrAfter(IndexVersions.HOSTNAME_DOC_VALUES_SPARSE_INDEX) - && shouldUseDocValuesSparseIndex(indexSortConfig, indexMode, fullFieldName)) { + && shouldUseDocValuesSkipper(hasDocValues.getValue(), indexSortConfig, indexMode, fullFieldName)) { return new FieldType(Defaults.FIELD_TYPE_WITH_SKIP_DOC_VALUES); } return new FieldType(Defaults.FIELD_TYPE); } - /** - * Determines whether to use a sparse index representation for doc values. - * - *

If the field is explicitly indexed by setting {@code index: true}, we do not use - * a sparse doc values index but instead rely on the inverted index, as is typically - * the case for keyword fields.

- * - *

This method checks several conditions to decide if the sparse index format - * should be applied:

- * - *
    - *
  • Returns {@code false} immediately if the field is explicitly indexed.
  • - *
  • Ensures the field is not explicitly configured as indexed (i.e., {@code index} has its default value).
  • - *
  • Requires doc values to be enabled.
  • - *
  • Index mode must be {@link IndexMode#LOGSDB}.
  • - *
  • Field name must be {@code host.name}.
  • - *
  • The {@code host.name} field must be a primary sort field.
  • - *
- * - *

Returns {@code true} if all conditions are met, indicating that sparse doc values - * should be used. Otherwise, returns {@code false}.

- * - * @param indexSortConfig The index sort configuration, used to check primary sorting. - * @param indexMode The mode of the index, which must be {@link IndexMode#LOGSDB}. - * @param fullFieldName The name of the field being checked, which must be {@code host.name}. - * @return {@code true} if sparse doc values should be used, otherwise {@code false}. - */ - - private boolean shouldUseDocValuesSparseIndex( + private static boolean shouldUseDocValuesSkipper( + final boolean hasDocValues, final IndexSortConfig indexSortConfig, final IndexMode indexMode, final String fullFieldName ) { - if (indexed.isSet() && indexed.getValue()) { - return false; - } - return indexed.isConfigured() == false - && hasDocValues.getValue() + return hasDocValues && IndexMode.LOGSDB.equals(indexMode) && HOST_NAME.equals(fullFieldName) - && (indexSortConfig != null && indexSortConfig.hasPrimarySortOnField(HOST_NAME)); + && indexSortConfigByHostName(indexSortConfig); + } + + private static boolean indexSortConfigByHostName(final IndexSortConfig indexSortConfig) { + return indexSortConfig != null && indexSortConfig.hasIndexSort() && indexSortConfig.hasSortOnField(HOST_NAME); } } @@ -492,7 +478,7 @@ public final class KeywordFieldMapper extends FieldMapper { private final boolean isSyntheticSource; private final IndexMode indexMode; private final IndexSortConfig indexSortConfig; - private final boolean hasDocValuesSparseIndex; + private final boolean hasDocValuesSkipper; public KeywordFieldType( String name, @@ -520,7 +506,7 @@ public final class KeywordFieldMapper extends FieldMapper { this.isSyntheticSource = isSyntheticSource; this.indexMode = builder.indexMode; this.indexSortConfig = builder.indexSortConfig; - this.hasDocValuesSparseIndex = DocValuesSkipIndexType.NONE.equals(fieldType.docValuesSkipIndexType()) == false; + this.hasDocValuesSkipper = DocValuesSkipIndexType.NONE.equals(fieldType.docValuesSkipIndexType()) == false; } public KeywordFieldType(String name, boolean isIndexed, boolean hasDocValues, Map meta) { @@ -534,7 +520,7 @@ public final class KeywordFieldMapper extends FieldMapper { this.isSyntheticSource = false; this.indexMode = IndexMode.STANDARD; this.indexSortConfig = null; - this.hasDocValuesSparseIndex = false; + this.hasDocValuesSkipper = false; } public KeywordFieldType(String name) { @@ -559,7 +545,7 @@ public final class KeywordFieldMapper extends FieldMapper { this.isSyntheticSource = false; this.indexMode = IndexMode.STANDARD; this.indexSortConfig = null; - this.hasDocValuesSparseIndex = DocValuesSkipIndexType.NONE.equals(fieldType.docValuesSkipIndexType()) == false; + this.hasDocValuesSkipper = DocValuesSkipIndexType.NONE.equals(fieldType.docValuesSkipIndexType()) == false; } public KeywordFieldType(String name, NamedAnalyzer analyzer) { @@ -573,7 +559,7 @@ public final class KeywordFieldMapper extends FieldMapper { this.isSyntheticSource = false; this.indexMode = IndexMode.STANDARD; this.indexSortConfig = null; - this.hasDocValuesSparseIndex = false; + this.hasDocValuesSkipper = false; } @Override @@ -1021,8 +1007,8 @@ public final class KeywordFieldMapper extends FieldMapper { return indexSortConfig; } - public boolean hasDocValuesSparseIndex() { - return hasDocValuesSparseIndex; + public boolean hasDocValuesSkipper() { + return hasDocValuesSkipper; } } @@ -1041,6 +1027,7 @@ public final class KeywordFieldMapper extends FieldMapper { private final int ignoreAboveDefault; private final IndexMode indexMode; private final IndexSortConfig indexSortConfig; + private final boolean useDocValuesSkipper; private KeywordFieldMapper( String simpleName, @@ -1048,6 +1035,7 @@ public final class KeywordFieldMapper extends FieldMapper { KeywordFieldType mappedFieldType, BuilderParams builderParams, boolean isSyntheticSource, + boolean useDocValuesSkipper, Builder builder ) { super(simpleName, mappedFieldType, builderParams); @@ -1066,6 +1054,7 @@ public final class KeywordFieldMapper extends FieldMapper { this.ignoreAboveDefault = builder.ignoreAboveDefault; this.indexMode = builder.indexMode; this.indexSortConfig = builder.indexSortConfig; + this.useDocValuesSkipper = useDocValuesSkipper; } @Override @@ -1183,9 +1172,16 @@ public final class KeywordFieldMapper extends FieldMapper { @Override public FieldMapper.Builder getMergeBuilder() { - return new Builder(leafName(), indexAnalyzers, scriptCompiler, ignoreAboveDefault, indexCreatedVersion, indexMode, indexSortConfig) - .dimension(fieldType().isDimension()) - .init(this); + return new Builder( + leafName(), + indexAnalyzers, + scriptCompiler, + ignoreAboveDefault, + indexCreatedVersion, + indexMode, + indexSortConfig, + useDocValuesSkipper + ).dimension(fieldType().isDimension()).init(this); } @Override diff --git a/server/src/main/java/org/elasticsearch/index/mapper/MapperService.java b/server/src/main/java/org/elasticsearch/index/mapper/MapperService.java index b181225d80dd..7958fd8e5152 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/MapperService.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/MapperService.java @@ -801,7 +801,8 @@ public class MapperService extends AbstractIndexComponent implements Closeable { * this method considers all mapper plugins */ public boolean isMetadataField(String field) { - return mapperRegistry.getMetadataMapperParsers(indexVersionCreated).containsKey(field); + var mapper = mappingLookup().getMapper(field); + return mapper instanceof MetadataFieldMapper; } /** diff --git a/server/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java index a6cb5561f2e7..5ee7ee2ae9bf 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java @@ -58,6 +58,8 @@ public class SourceFieldMapper extends MetadataFieldMapper { public static final String LOSSY_PARAMETERS_ALLOWED_SETTING_NAME = "index.lossy.source-mapping-parameters"; + public static final String DEPRECATION_WARNING_TITLE = "Configuring source mode in mappings is deprecated."; + public static final String DEPRECATION_WARNING = "Configuring source mode in mappings is deprecated and will be removed " + "in future versions. Use [index.mapping.source.mode] index setting instead."; diff --git a/server/src/main/java/org/elasticsearch/index/shard/IndexEventListener.java b/server/src/main/java/org/elasticsearch/index/shard/IndexEventListener.java index 4e55a2e9599d..3cd594e646f4 100644 --- a/server/src/main/java/org/elasticsearch/index/shard/IndexEventListener.java +++ b/server/src/main/java/org/elasticsearch/index/shard/IndexEventListener.java @@ -86,6 +86,25 @@ public interface IndexEventListener { @Nullable String reason ) {} + /** + * Invoked before a shard performs a mutable operation. Mutable operations include, but are not limited to: + *
    + *
  • Indexing operations
  • + *
  • Force merges
  • + *
+ * + * This method ensures that the shard is ready to accept mutating operations. This is particularly useful in cases + * where the shard initializes its internal {@link org.elasticsearch.index.engine.Engine} lazily, which may take some time. + * The provided listener should be notified once the shard is prepared to proceed with the operation. + * This can be called from a transport thread and therefore the function should be lightweight and not block the thread. + * + * @param indexShard the shard where the mutable operation will be performed + * @param listener the listener to be notified when the shard is ready to proceed + */ + default void beforeIndexShardMutableOperation(IndexShard indexShard, ActionListener listener) { + listener.onResponse(null); + } + /** * Called before the index gets created. Note that this is also called * when the index is created on data nodes diff --git a/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java b/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java index b172b6ff4ba3..e5085ce9944b 100644 --- a/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java +++ b/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java @@ -451,10 +451,6 @@ public class IndexShard extends AbstractIndexShardComponent implements IndicesCl return this.bulkOperationListener; } - public IndexingOperationListener getIndexingOperationListener() { - return this.indexingOperationListeners; - } - public ShardIndexWarmerService warmerService() { return this.shardWarmerService; } @@ -4507,4 +4503,19 @@ public class IndexShard extends AbstractIndexShardComponent implements IndicesCl ); } + /** + * Ensures that the shard is ready to perform mutable operations. + * This method is particularly useful when the shard initializes its internal + * {@link org.elasticsearch.index.engine.Engine} lazily, as it may take some time before becoming mutable. + * + * The provided listener will be notified once the shard is ready for mutating operations. + * + * @param listener the listener to be notified when the shard is mutable + */ + public void ensureMutable(ActionListener listener) { + indexEventListener.beforeIndexShardMutableOperation(this, listener.delegateFailure((l, unused) -> { + // TODO ES-10826: Acquire ref to engine and retry if it's immutable again? + l.onResponse(null); + })); + } } diff --git a/server/src/main/java/org/elasticsearch/index/shard/IndexingOperationListener.java b/server/src/main/java/org/elasticsearch/index/shard/IndexingOperationListener.java index 8cb155aa2e99..0e796d2fb38c 100644 --- a/server/src/main/java/org/elasticsearch/index/shard/IndexingOperationListener.java +++ b/server/src/main/java/org/elasticsearch/index/shard/IndexingOperationListener.java @@ -9,11 +9,9 @@ package org.elasticsearch.index.shard; import org.apache.logging.log4j.Logger; -import org.elasticsearch.action.ActionListener; import org.elasticsearch.index.engine.Engine; import java.util.List; -import java.util.function.Supplier; /** * An indexing listener for indexing, delete, events. @@ -64,18 +62,6 @@ public interface IndexingOperationListener { */ default void postDelete(ShardId shardId, Engine.Delete delete, Exception ex) {} - /** - * Called when a {@link org.elasticsearch.action.bulk.TransportShardBulkAction} is about to perform index and/or delete operation(s) - * on a primary shard. - * - * This is called from a transport thread and therefore the function should be lightweight and not block the thread. The acquired - * listener(s) can be asynchronously completed on another thread at a later time. - * - * @param indexShard the shard the bulk is about to be performed on - * @param proceedListenerSupplier call this immediately to get a listener which must be completed so that the bulk can proceed. - */ - default void preBulkOnPrimary(IndexShard indexShard, Supplier> proceedListenerSupplier) {} - /** * A Composite listener that multiplexes calls to each of the listeners methods. */ @@ -163,16 +149,5 @@ public interface IndexingOperationListener { } } } - - @Override - public void preBulkOnPrimary(IndexShard indexShard, Supplier> proceedListenerSupplier) { - for (IndexingOperationListener listener : listeners) { - try { - listener.preBulkOnPrimary(indexShard, proceedListenerSupplier); - } catch (Exception e) { - logger.warn(() -> "preBulkOnPrimary listener [" + listener + "] failed", e); - } - } - } } } diff --git a/server/src/main/java/org/elasticsearch/indices/IndicesService.java b/server/src/main/java/org/elasticsearch/indices/IndicesService.java index 54766806e761..4c633618e1b7 100644 --- a/server/src/main/java/org/elasticsearch/indices/IndicesService.java +++ b/server/src/main/java/org/elasticsearch/indices/IndicesService.java @@ -81,7 +81,6 @@ import org.elasticsearch.core.TimeValue; import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.env.ShardLock; import org.elasticsearch.env.ShardLockObtainFailedException; -import org.elasticsearch.features.FeatureService; import org.elasticsearch.gateway.MetaStateService; import org.elasticsearch.gateway.MetadataStateFormat; import org.elasticsearch.index.CloseUtils; @@ -239,7 +238,6 @@ public class IndicesService extends AbstractLifecycleComponent private final ClusterService clusterService; private final ProjectResolver projectResolver; private final Client client; - private final FeatureService featureService; private volatile Map indices = Map.of(); private final Map> pendingDeletes = new HashMap<>(); private final AtomicInteger numUncompletedDeletes = new AtomicInteger(); @@ -313,7 +311,6 @@ public class IndicesService extends AbstractLifecycleComponent this.clusterService = builder.clusterService; this.projectResolver = builder.projectResolver; this.client = builder.client; - this.featureService = builder.featureService; this.idFieldDataEnabled = INDICES_ID_FIELD_DATA_ENABLED_SETTING.get(clusterService.getSettings()); clusterService.getClusterSettings().addSettingsUpdateConsumer(INDICES_ID_FIELD_DATA_ENABLED_SETTING, this::setIdFieldDataEnabled); this.indicesFieldDataCache = new IndicesFieldDataCache(settings, new IndexFieldDataCache.Listener() { diff --git a/server/src/main/java/org/elasticsearch/indices/IndicesServiceBuilder.java b/server/src/main/java/org/elasticsearch/indices/IndicesServiceBuilder.java index c9b03ef2b3e2..49aeba37acd4 100644 --- a/server/src/main/java/org/elasticsearch/indices/IndicesServiceBuilder.java +++ b/server/src/main/java/org/elasticsearch/indices/IndicesServiceBuilder.java @@ -21,7 +21,6 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.core.Nullable; import org.elasticsearch.env.NodeEnvironment; -import org.elasticsearch.features.FeatureService; import org.elasticsearch.gateway.MetaStateService; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.SlowLogFieldProvider; @@ -69,7 +68,6 @@ public class IndicesServiceBuilder { ClusterService clusterService; ProjectResolver projectResolver; Client client; - FeatureService featureService; MetaStateService metaStateService; Collection>> engineFactoryProviders = List.of(); Map directoryFactories = Map.of(); @@ -180,11 +178,6 @@ public class IndicesServiceBuilder { return this; } - public IndicesServiceBuilder featureService(FeatureService featureService) { - this.featureService = featureService; - return this; - } - public IndicesServiceBuilder metaStateService(MetaStateService metaStateService) { this.metaStateService = metaStateService; return this; @@ -238,7 +231,6 @@ public class IndicesServiceBuilder { Objects.requireNonNull(clusterService); Objects.requireNonNull(projectResolver); Objects.requireNonNull(client); - Objects.requireNonNull(featureService); Objects.requireNonNull(metaStateService); Objects.requireNonNull(engineFactoryProviders); Objects.requireNonNull(directoryFactories); diff --git a/server/src/main/java/org/elasticsearch/indices/store/IndicesStore.java b/server/src/main/java/org/elasticsearch/indices/store/IndicesStore.java index bfe2291c75e1..44b8ff4dc2a8 100644 --- a/server/src/main/java/org/elasticsearch/indices/store/IndicesStore.java +++ b/server/src/main/java/org/elasticsearch/indices/store/IndicesStore.java @@ -235,6 +235,11 @@ public final class IndicesStore implements ClusterStateListener, Closeable { long clusterStateVersion, IndexShardRoutingTable indexShardRoutingTable ) { + if (DiscoveryNode.isStateless(clusterService.getSettings())) { + deleteShardStoreOnApplierThread(indexShardRoutingTable.shardId(), clusterStateVersion); + return; + } + List> requests = new ArrayList<>(indexShardRoutingTable.size()); String indexUUID = indexShardRoutingTable.shardId().getIndex().getUUID(); for (int copy = 0; copy < indexShardRoutingTable.size(); copy++) { @@ -326,34 +331,37 @@ public final class IndicesStore implements ClusterStateListener, Closeable { return; } - clusterService.getClusterApplierService() - .runOnApplierThread("indices_store ([" + shardId + "] active fully on other nodes)", Priority.HIGH, currentState -> { - if (clusterStateVersion != currentState.getVersion()) { - logger.trace( - "not deleting shard {}, the update task state version[{}] is not equal to cluster state before " - + "shard active api call [{}]", - shardId, - currentState.getVersion(), - clusterStateVersion - ); - return; - } - try { - indicesService.deleteShardStore("no longer used", shardId, currentState); - } catch (Exception ex) { - logger.debug(() -> format("%s failed to delete unallocated shard, ignoring", shardId), ex); - } - }, new ActionListener<>() { - @Override - public void onResponse(Void unused) {} - - @Override - public void onFailure(Exception e) { - logger.error(() -> format("%s unexpected error during deletion of unallocated shard", shardId), e); - } - }); + deleteShardStoreOnApplierThread(shardId, clusterStateVersion); } + } + private void deleteShardStoreOnApplierThread(ShardId shardId, long clusterStateVersion) { + clusterService.getClusterApplierService() + .runOnApplierThread("indices_store ([" + shardId + "] active fully on other nodes)", Priority.HIGH, currentState -> { + if (clusterStateVersion != currentState.getVersion()) { + logger.trace( + "not deleting shard {}, the update task state version[{}] is not equal to cluster state before " + + "shard active api call [{}]", + shardId, + currentState.getVersion(), + clusterStateVersion + ); + return; + } + try { + indicesService.deleteShardStore("no longer used", shardId, currentState); + } catch (Exception ex) { + logger.debug(() -> format("%s failed to delete unallocated shard, ignoring", shardId), ex); + } + }, new ActionListener<>() { + @Override + public void onResponse(Void unused) {} + + @Override + public void onFailure(Exception e) { + logger.error(() -> format("%s unexpected error during deletion of unallocated shard", shardId), e); + } + }); } private class ShardActiveRequestHandler implements TransportRequestHandler { diff --git a/server/src/main/java/org/elasticsearch/node/NodeConstruction.java b/server/src/main/java/org/elasticsearch/node/NodeConstruction.java index df476160fdef..b6e24a23591b 100644 --- a/server/src/main/java/org/elasticsearch/node/NodeConstruction.java +++ b/server/src/main/java/org/elasticsearch/node/NodeConstruction.java @@ -863,7 +863,6 @@ class NodeConstruction { .clusterService(clusterService) .projectResolver(projectResolver) .client(client) - .featureService(featureService) .metaStateService(metaStateService) .valuesSourceRegistry(searchModule.getValuesSourceRegistry()) .requestCacheKeyDifferentiator(searchModule.getRequestCacheKeyDifferentiator()) @@ -1168,7 +1167,6 @@ class NodeConstruction { clusterService, threadPool, systemIndices, - featureService, clusterModule.getIndexNameExpressionResolver(), metadataUpdateSettingsService, metadataCreateIndexService @@ -1182,7 +1180,6 @@ class NodeConstruction { discoveryModule.getCoordinator(), clusterService, transportService, - featureService, threadPool, telemetryProvider, repositoriesService, @@ -1354,7 +1351,6 @@ class NodeConstruction { Coordinator coordinator, ClusterService clusterService, TransportService transportService, - FeatureService featureService, ThreadPool threadPool, TelemetryProvider telemetryProvider, RepositoriesService repositoriesService, @@ -1372,7 +1368,7 @@ class NodeConstruction { var serverHealthIndicatorServices = Stream.of( new StableMasterHealthIndicatorService(coordinationDiagnosticsService, clusterService), new RepositoryIntegrityHealthIndicatorService(clusterService), - new DiskHealthIndicatorService(clusterService, featureService), + new DiskHealthIndicatorService(clusterService), new ShardsCapacityHealthIndicatorService(clusterService), fileSettingsHealthIndicatorService ); @@ -1390,7 +1386,7 @@ class NodeConstruction { healthService, telemetryProvider ); - HealthMetadataService healthMetadataService = HealthMetadataService.create(clusterService, featureService, settings); + HealthMetadataService healthMetadataService = HealthMetadataService.create(clusterService, settings); List> healthTrackers = List.of( new DiskHealthTracker(nodeService, clusterService), @@ -1679,7 +1675,6 @@ class NodeConstruction { ClusterService clusterService, ThreadPool threadPool, SystemIndices systemIndices, - FeatureService featureService, IndexNameExpressionResolver indexNameExpressionResolver, MetadataUpdateSettingsService metadataUpdateSettingsService, MetadataCreateIndexService metadataCreateIndexService @@ -1696,7 +1691,6 @@ class NodeConstruction { HealthNodeTaskExecutor healthNodeTaskExecutor = HealthNodeTaskExecutor.create( clusterService, persistentTasksService, - featureService, settingsModule.getSettings(), clusterService.getClusterSettings() ); diff --git a/server/src/main/java/org/elasticsearch/search/DefaultSearchContext.java b/server/src/main/java/org/elasticsearch/search/DefaultSearchContext.java index 47d3ed337af7..7095d3ec92c7 100644 --- a/server/src/main/java/org/elasticsearch/search/DefaultSearchContext.java +++ b/server/src/main/java/org/elasticsearch/search/DefaultSearchContext.java @@ -21,7 +21,6 @@ import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.TotalHits; import org.apache.lucene.util.NumericUtils; -import org.elasticsearch.action.search.SearchShardTask; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.cluster.routing.IndexRouting; import org.elasticsearch.common.lucene.search.Queries; @@ -77,6 +76,7 @@ import org.elasticsearch.search.rescore.RescorePhase; import org.elasticsearch.search.slice.SliceBuilder; import org.elasticsearch.search.sort.SortAndFormats; import org.elasticsearch.search.suggest.SuggestionSearchContext; +import org.elasticsearch.tasks.CancellableTask; import java.io.IOException; import java.io.UncheckedIOException; @@ -131,7 +131,7 @@ final class DefaultSearchContext extends SearchContext { private CollapseContext collapse; // filter for sliced scroll private SliceBuilder sliceBuilder; - private SearchShardTask task; + private CancellableTask task; private QueryPhaseRankShardContext queryPhaseRankShardContext; /** @@ -433,7 +433,7 @@ final class DefaultSearchContext extends SearchContext { this.query = buildFilteredQuery(query); if (lowLevelCancellation) { searcher().addQueryCancellation(() -> { - final SearchShardTask task = getTask(); + final CancellableTask task = getTask(); if (task != null) { task.ensureNotCancelled(); } @@ -907,12 +907,12 @@ final class DefaultSearchContext extends SearchContext { } @Override - public void setTask(SearchShardTask task) { + public void setTask(CancellableTask task) { this.task = task; } @Override - public SearchShardTask getTask() { + public CancellableTask getTask() { return task; } diff --git a/server/src/main/java/org/elasticsearch/search/SearchService.java b/server/src/main/java/org/elasticsearch/search/SearchService.java index e8a529c99dd6..80fc8795322e 100644 --- a/server/src/main/java/org/elasticsearch/search/SearchService.java +++ b/server/src/main/java/org/elasticsearch/search/SearchService.java @@ -126,6 +126,7 @@ import org.elasticsearch.search.sort.SortAndFormats; import org.elasticsearch.search.sort.SortBuilder; import org.elasticsearch.search.suggest.Suggest; import org.elasticsearch.search.suggest.completion.CompletionSuggestion; +import org.elasticsearch.tasks.CancellableTask; import org.elasticsearch.tasks.TaskCancelledException; import org.elasticsearch.telemetry.tracing.Tracer; import org.elasticsearch.threadpool.Scheduler; @@ -581,33 +582,36 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv } } - public void executeQueryPhase(ShardSearchRequest request, SearchShardTask task, ActionListener listener) { - ActionListener finalListener = maybeWrapListenerForStackTrace(listener, request.getChannelVersion(), threadPool); + public void executeQueryPhase(ShardSearchRequest request, CancellableTask task, ActionListener listener) { assert request.canReturnNullResponseIfMatchNoDocs() == false || request.numberOfShards() > 1 : "empty responses require more than one shard"; final IndexShard shard = getShard(request); - rewriteAndFetchShardRequest(shard, request, finalListener.delegateFailure((l, orig) -> { - // check if we can shortcut the query phase entirely. - if (orig.canReturnNullResponseIfMatchNoDocs()) { - assert orig.scroll() == null; - ShardSearchRequest clone = new ShardSearchRequest(orig); - CanMatchContext canMatchContext = new CanMatchContext( - clone, - indicesService::indexServiceSafe, - this::findReaderContext, - defaultKeepAlive, - maxKeepAlive - ); - CanMatchShardResponse canMatchResp = canMatch(canMatchContext, false); - if (canMatchResp.canMatch() == false) { - finalListener.onResponse(QuerySearchResult.nullInstance()); - return; + rewriteAndFetchShardRequest( + shard, + request, + maybeWrapListenerForStackTrace(listener, request.getChannelVersion(), threadPool).delegateFailure((l, orig) -> { + // check if we can shortcut the query phase entirely. + if (orig.canReturnNullResponseIfMatchNoDocs()) { + assert orig.scroll() == null; + ShardSearchRequest clone = new ShardSearchRequest(orig); + CanMatchContext canMatchContext = new CanMatchContext( + clone, + indicesService::indexServiceSafe, + this::findReaderContext, + defaultKeepAlive, + maxKeepAlive + ); + CanMatchShardResponse canMatchResp = canMatch(canMatchContext, false); + if (canMatchResp.canMatch() == false) { + l.onResponse(QuerySearchResult.nullInstance()); + return; + } } - } - // TODO: i think it makes sense to always do a canMatch here and - // return an empty response (not null response) in case canMatch is false? - ensureAfterSeqNoRefreshed(shard, orig, () -> executeQueryPhase(orig, task), l); - })); + // TODO: i think it makes sense to always do a canMatch here and + // return an empty response (not null response) in case canMatch is false? + ensureAfterSeqNoRefreshed(shard, orig, () -> executeQueryPhase(orig, task), l); + }) + ); } private void ensureAfterSeqNoRefreshed( @@ -729,7 +733,7 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv * It is the responsibility of the caller to ensure that the ref count is correctly decremented * when the object is no longer needed. */ - private SearchPhaseResult executeQueryPhase(ShardSearchRequest request, SearchShardTask task) throws Exception { + private SearchPhaseResult executeQueryPhase(ShardSearchRequest request, CancellableTask task) throws Exception { final ReaderContext readerContext = createOrGetReaderContext(request); try ( Releasable scope = tracer.withScope(task); @@ -953,7 +957,7 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv }, wrapFailureListener(listener, readerContext, markAsUsed)); } - public void executeFetchPhase(ShardFetchRequest request, SearchShardTask task, ActionListener listener) { + public void executeFetchPhase(ShardFetchRequest request, CancellableTask task, ActionListener listener) { final ReaderContext readerContext = findReaderContext(request.contextId(), request); final ShardSearchRequest shardSearchRequest = readerContext.getShardSearchRequest(request.getShardSearchRequest()); final Releasable markAsUsed = readerContext.markAsUsed(getKeepAlive(shardSearchRequest)); @@ -991,7 +995,7 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv })); } - protected void checkCancelled(SearchShardTask task) { + protected void checkCancelled(CancellableTask task) { // check cancellation as early as possible, as it avoids opening up a Lucene reader on FrozenEngine try { task.ensureNotCancelled(); @@ -1122,7 +1126,7 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv protected SearchContext createContext( ReaderContext readerContext, ShardSearchRequest request, - SearchShardTask task, + CancellableTask task, ResultsType resultsType, boolean includeAggregations ) throws IOException { diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/BucketsAggregator.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/BucketsAggregator.java index 592f7b488759..e85d01930807 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/BucketsAggregator.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/BucketsAggregator.java @@ -26,6 +26,7 @@ import org.elasticsearch.search.aggregations.bucket.terms.LongKeyedBucketOrds; import org.elasticsearch.search.aggregations.support.AggregationContext; import org.elasticsearch.search.aggregations.support.AggregationPath; import org.elasticsearch.search.sort.SortOrder; +import org.elasticsearch.tasks.TaskCancelledException; import java.io.IOException; import java.util.AbstractList; @@ -163,6 +164,10 @@ public abstract class BucketsAggregator extends AggregatorBase { * array of ordinals */ protected final IntFunction buildSubAggsForBuckets(LongArray bucketOrdsToCollect) throws IOException { + if (context.isCancelled()) { + throw new TaskCancelledException("not building sub-aggregations due to task cancellation"); + } + prepareSubAggs(bucketOrdsToCollect); InternalAggregation[][] aggregations = new InternalAggregation[subAggregators.length][]; for (int i = 0; i < subAggregators.length; i++) { diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/GlobalOrdinalsStringTermsAggregator.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/GlobalOrdinalsStringTermsAggregator.java index 439b61cc43dd..0e0b7f3f5f5e 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/GlobalOrdinalsStringTermsAggregator.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/GlobalOrdinalsStringTermsAggregator.java @@ -290,7 +290,6 @@ public class GlobalOrdinalsStringTermsAggregator extends AbstractStringTermsAggr BucketCountThresholds bucketCountThresholds, AggregationContext context, Aggregator parent, - boolean remapGlobalOrds, SubAggCollectionMode collectionMode, boolean showTermDocCountError, Map metadata, @@ -308,7 +307,7 @@ public class GlobalOrdinalsStringTermsAggregator extends AbstractStringTermsAggr ALWAYS_TRUE, context, parent, - remapGlobalOrds, + false, collectionMode, showTermDocCountError, CardinalityUpperBound.ONE, @@ -385,7 +384,7 @@ public class GlobalOrdinalsStringTermsAggregator extends AbstractStringTermsAggr Releasables.close(resultStrategy, segmentDocCounts, collectionStrategy); } - private void mapSegmentCountsToGlobalCounts(LongUnaryOperator mapping) throws IOException { + private void mapSegmentCountsToGlobalCounts(LongUnaryOperator mapping) { for (long i = 1; i < segmentDocCounts.size(); i++) { // We use set(...) here, because we need to reset the slow to 0. // segmentDocCounts get reused over the segments and otherwise counts would be too high. @@ -395,7 +394,7 @@ public class GlobalOrdinalsStringTermsAggregator extends AbstractStringTermsAggr } long ord = i - 1; // remember we do +1 when counting long globalOrd = mapping.applyAsLong(ord); - incrementBucketDocCount(collectionStrategy.globalOrdToBucketOrd(0, globalOrd), inc); + incrementBucketDocCount(collectionStrategy.globalOrdToBucketOrd(globalOrd), inc); } } } @@ -440,7 +439,7 @@ public class GlobalOrdinalsStringTermsAggregator extends AbstractStringTermsAggr /** * Convert a global ordinal into a bucket ordinal. */ - abstract long globalOrdToBucketOrd(long owningBucketOrd, long globalOrd); + abstract long globalOrdToBucketOrd(long globalOrd); /** * Create the aggregation result @@ -491,8 +490,7 @@ public class GlobalOrdinalsStringTermsAggregator extends AbstractStringTermsAggr } @Override - long globalOrdToBucketOrd(long owningBucketOrd, long globalOrd) { - assert owningBucketOrd == 0; + long globalOrdToBucketOrd(long globalOrd) { return globalOrd; } @@ -659,8 +657,8 @@ public class GlobalOrdinalsStringTermsAggregator extends AbstractStringTermsAggr } @Override - long globalOrdToBucketOrd(long owningBucketOrd, long globalOrd) { - return bucketOrds.find(owningBucketOrd, globalOrd); + long globalOrdToBucketOrd(long globalOrd) { + return bucketOrds.find(0, globalOrd); } private void collectZeroDocEntriesIfNeeded(long owningBucketOrd) throws IOException { @@ -789,7 +787,7 @@ public class GlobalOrdinalsStringTermsAggregator extends AbstractStringTermsAggr /** * Strategy for building results. */ - abstract class ResultStrategy< + abstract static class ResultStrategy< R extends InternalAggregation, B extends InternalMultiBucketAggregation.InternalBucket, TB extends InternalMultiBucketAggregation.InternalBucket> implements Releasable { diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/SignificanceLookup.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/SignificanceLookup.java index a5534f75d4f6..9bd0e7eac35a 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/SignificanceLookup.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/SignificanceLookup.java @@ -89,8 +89,7 @@ class SignificanceLookup { this.backgroundFilter = null; } } else { - Query contextFiltered = context.filterQuery(backgroundQuery); - this.backgroundFilter = contextFiltered; + this.backgroundFilter = context.filterQuery(backgroundQuery); } /* * We need to use a superset size that includes deleted docs or we diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/SignificantTermsAggregatorFactory.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/SignificantTermsAggregatorFactory.java index 080cac9cbfb8..1b68d55260fe 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/SignificantTermsAggregatorFactory.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/SignificantTermsAggregatorFactory.java @@ -13,7 +13,6 @@ import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.search.MatchNoDocsQuery; import org.elasticsearch.ElasticsearchStatusException; import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.search.SearchShardTask; import org.elasticsearch.common.logging.DeprecationCategory; import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.index.query.QueryBuilder; @@ -38,6 +37,7 @@ import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFacto import org.elasticsearch.search.aggregations.support.ValuesSourceConfig; import org.elasticsearch.search.aggregations.support.ValuesSourceRegistry; import org.elasticsearch.search.internal.ShardSearchRequest; +import org.elasticsearch.tasks.CancellableTask; import org.elasticsearch.xcontent.ParseField; import java.io.IOException; @@ -128,7 +128,7 @@ public class SignificantTermsAggregatorFactory extends ValuesSourceAggregatorFac *

* Some searches that will never match can still fall through and we endup running query that will produce no results. * However even in that case we sometimes do expensive things like loading global ordinals. This method should prevent this. - * Note that if {@link org.elasticsearch.search.SearchService#executeQueryPhase(ShardSearchRequest, SearchShardTask, ActionListener)} + * Note that if {@link org.elasticsearch.search.SearchService#executeQueryPhase(ShardSearchRequest, CancellableTask, ActionListener)} * always do a can match then we don't need this code here. */ static boolean matchNoDocs(AggregationContext context, Aggregator parent) { @@ -422,6 +422,10 @@ public class SignificantTermsAggregatorFactory extends ValuesSourceAggregatorFac if ("global_ordinals".equals(value)) { return GLOBAL_ORDINALS; } else if ("global_ordinals_hash".equals(value)) { + /* + * We have no plans to remove this so we don't break anyone, no matter + * how few people still use this or how long it's been deprecated. + */ deprecationLogger.warn( DeprecationCategory.AGGREGATIONS, "global_ordinals_hash", diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java index da5ae37b0822..5a692b934a41 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java @@ -511,7 +511,6 @@ public class TermsAggregatorFactory extends ValuesSourceAggregatorFactory { bucketCountThresholds, context, parent, - false, subAggCollectMode, showTermDocCountError, metadata, diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/UnmappedSignificantTerms.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/UnmappedSignificantTerms.java index 6d1370f147f3..82011528fef7 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/UnmappedSignificantTerms.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/UnmappedSignificantTerms.java @@ -8,7 +8,6 @@ */ package org.elasticsearch.search.aggregations.bucket.terms; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.search.DocValueFormat; @@ -40,7 +39,7 @@ public class UnmappedSignificantTerms extends InternalSignificantTerms { - private Bucket(BytesRef term, long subsetDf, long supersetDf, InternalAggregations aggregations, DocValueFormat format) { + private Bucket(long subsetDf, long supersetDf, InternalAggregations aggregations, DocValueFormat format) { super(subsetDf, supersetDf, aggregations, format); } } diff --git a/server/src/main/java/org/elasticsearch/search/internal/FilteredSearchContext.java b/server/src/main/java/org/elasticsearch/search/internal/FilteredSearchContext.java index 8c4f912c5988..5bad06d08f96 100644 --- a/server/src/main/java/org/elasticsearch/search/internal/FilteredSearchContext.java +++ b/server/src/main/java/org/elasticsearch/search/internal/FilteredSearchContext.java @@ -12,7 +12,6 @@ package org.elasticsearch.search.internal; import org.apache.lucene.search.FieldDoc; import org.apache.lucene.search.Query; import org.apache.lucene.search.TotalHits; -import org.elasticsearch.action.search.SearchShardTask; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.core.TimeValue; import org.elasticsearch.index.cache.bitset.BitsetFilterCache; @@ -40,6 +39,7 @@ import org.elasticsearch.search.rank.feature.RankFeatureResult; import org.elasticsearch.search.rescore.RescoreContext; import org.elasticsearch.search.sort.SortAndFormats; import org.elasticsearch.search.suggest.SuggestionSearchContext; +import org.elasticsearch.tasks.CancellableTask; import java.util.List; @@ -422,12 +422,12 @@ public abstract class FilteredSearchContext extends SearchContext { } @Override - public void setTask(SearchShardTask task) { + public void setTask(CancellableTask task) { in.setTask(task); } @Override - public SearchShardTask getTask() { + public CancellableTask getTask() { return in.getTask(); } diff --git a/server/src/main/java/org/elasticsearch/search/internal/SearchContext.java b/server/src/main/java/org/elasticsearch/search/internal/SearchContext.java index 7da71b77c6a6..5a8c280e12f8 100644 --- a/server/src/main/java/org/elasticsearch/search/internal/SearchContext.java +++ b/server/src/main/java/org/elasticsearch/search/internal/SearchContext.java @@ -11,7 +11,6 @@ package org.elasticsearch.search.internal; import org.apache.lucene.search.FieldDoc; import org.apache.lucene.search.Query; import org.apache.lucene.search.TotalHits; -import org.elasticsearch.action.search.SearchShardTask; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.core.Assertions; import org.elasticsearch.core.Nullable; @@ -48,6 +47,7 @@ import org.elasticsearch.search.rank.feature.RankFeatureResult; import org.elasticsearch.search.rescore.RescoreContext; import org.elasticsearch.search.sort.SortAndFormats; import org.elasticsearch.search.suggest.SuggestionSearchContext; +import org.elasticsearch.tasks.CancellableTask; import org.elasticsearch.transport.LeakTracker; import java.io.IOException; @@ -90,7 +90,7 @@ public abstract class SearchContext implements Releasable { if (lowLevelCancellation()) { // This searching doesn't live beyond this phase, so we don't need to remove query cancellation Runnable c = () -> { - final SearchShardTask task = getTask(); + final CancellableTask task = getTask(); if (task != null) { task.ensureNotCancelled(); } @@ -100,9 +100,9 @@ public abstract class SearchContext implements Releasable { return timeoutRunnable == null ? List.of() : List.of(timeoutRunnable); } - public abstract void setTask(SearchShardTask task); + public abstract void setTask(CancellableTask task); - public abstract SearchShardTask getTask(); + public abstract CancellableTask getTask(); public abstract boolean isCancelled(); diff --git a/server/src/main/java/org/elasticsearch/search/rank/RankSearchContext.java b/server/src/main/java/org/elasticsearch/search/rank/RankSearchContext.java index ad70e7d39aff..951a9b0cf352 100644 --- a/server/src/main/java/org/elasticsearch/search/rank/RankSearchContext.java +++ b/server/src/main/java/org/elasticsearch/search/rank/RankSearchContext.java @@ -12,7 +12,6 @@ package org.elasticsearch.search.rank; import org.apache.lucene.search.FieldDoc; import org.apache.lucene.search.Query; import org.apache.lucene.search.TotalHits; -import org.elasticsearch.action.search.SearchShardTask; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.core.TimeValue; import org.elasticsearch.index.cache.bitset.BitsetFilterCache; @@ -48,6 +47,7 @@ import org.elasticsearch.search.rank.feature.RankFeatureResult; import org.elasticsearch.search.rescore.RescoreContext; import org.elasticsearch.search.sort.SortAndFormats; import org.elasticsearch.search.suggest.SuggestionSearchContext; +import org.elasticsearch.tasks.CancellableTask; import java.util.List; @@ -211,12 +211,12 @@ public class RankSearchContext extends SearchContext { /* ---- ALL METHODS ARE UNSUPPORTED BEYOND HERE ---- */ @Override - public void setTask(SearchShardTask task) { + public void setTask(CancellableTask task) { throw new UnsupportedOperationException(); } @Override - public SearchShardTask getTask() { + public CancellableTask getTask() { throw new UnsupportedOperationException(); } diff --git a/server/src/main/java/org/elasticsearch/transport/TransportStats.java b/server/src/main/java/org/elasticsearch/transport/TransportStats.java index 1163cfbcb270..2c06cd759e3a 100644 --- a/server/src/main/java/org/elasticsearch/transport/TransportStats.java +++ b/server/src/main/java/org/elasticsearch/transport/TransportStats.java @@ -69,7 +69,8 @@ public class TransportStats implements Writeable, ChunkedToXContent { rxSize = in.readVLong(); txCount = in.readVLong(); txSize = in.readVLong(); - if (in.getTransportVersion().before(TransportVersions.TRANSPORT_STATS_HANDLING_TIME_REQUIRED)) { + if (in.getTransportVersion().before(TransportVersions.TRANSPORT_STATS_HANDLING_TIME_REQUIRED) + && in.getTransportVersion().isPatchFrom(TransportVersions.TRANSPORT_STATS_HANDLING_TIME_REQUIRED_90) == false) { in.readBoolean(); } inboundHandlingTimeBucketFrequencies = new long[HandlingTimeTracker.BUCKET_COUNT]; @@ -98,7 +99,8 @@ public class TransportStats implements Writeable, ChunkedToXContent { out.writeVLong(txSize); assert inboundHandlingTimeBucketFrequencies.length == HandlingTimeTracker.BUCKET_COUNT; assert outboundHandlingTimeBucketFrequencies.length == HandlingTimeTracker.BUCKET_COUNT; - if (out.getTransportVersion().before(TransportVersions.TRANSPORT_STATS_HANDLING_TIME_REQUIRED)) { + if (out.getTransportVersion().before(TransportVersions.TRANSPORT_STATS_HANDLING_TIME_REQUIRED) + && out.getTransportVersion().isPatchFrom(TransportVersions.TRANSPORT_STATS_HANDLING_TIME_REQUIRED_90) == false) { out.writeBoolean(true); } for (long handlingTimeBucketFrequency : inboundHandlingTimeBucketFrequencies) { diff --git a/server/src/main/java/org/elasticsearch/upgrades/SystemIndexMigrator.java b/server/src/main/java/org/elasticsearch/upgrades/SystemIndexMigrator.java index 970b71e9950c..fba1b50200e5 100644 --- a/server/src/main/java/org/elasticsearch/upgrades/SystemIndexMigrator.java +++ b/server/src/main/java/org/elasticsearch/upgrades/SystemIndexMigrator.java @@ -15,7 +15,9 @@ import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse; import org.elasticsearch.action.admin.indices.create.CreateIndexClusterStateUpdateRequest; +import org.elasticsearch.action.admin.indices.readonly.AddIndexBlockRequest; import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsClusterStateUpdateRequest; import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.action.support.master.AcknowledgedResponse; @@ -33,7 +35,6 @@ import org.elasticsearch.cluster.metadata.MetadataIndexTemplateService; import org.elasticsearch.cluster.metadata.MetadataUpdateSettingsService; import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.CheckedBiConsumer; import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.IndexScopedSettings; import org.elasticsearch.common.settings.Settings; @@ -61,6 +62,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import static org.elasticsearch.action.admin.cluster.migration.TransportGetFeatureUpgradeStatusAction.NO_UPGRADE_REQUIRED_INDEX_VERSION; +import static org.elasticsearch.cluster.metadata.IndexMetadata.APIBlock.WRITE; import static org.elasticsearch.cluster.metadata.IndexMetadata.State.CLOSE; import static org.elasticsearch.core.Strings.format; @@ -451,12 +453,33 @@ public class SystemIndexMigrator extends AllocatedPersistentTask { logAndThrowExceptionForFailures(bulkByScrollResponse) ); } else { - // Successful completion of reindexing - remove read only and delete old index - setWriteBlock( - oldIndex, - false, - delegate2.delegateFailureAndWrap(setAliasAndRemoveOldIndex(migrationInfo, bulkByScrollResponse)) - ); + // Successful completion of reindexing. Now we need to set the alias and remove the old index. + setAliasAndRemoveOldIndex(migrationInfo, ActionListener.wrap(aliasesResponse -> { + if (aliasesResponse.hasErrors()) { + var e = new ElasticsearchException("Aliases request had errors"); + for (var error : aliasesResponse.getErrors()) { + e.addSuppressed(error); + } + throw e; + } + logger.info( + "Successfully migrated old index [{}] to new index [{}] from feature [{}]", + oldIndexName, + migrationInfo.getNextIndexName(), + migrationInfo.getFeatureName() + ); + delegate2.onResponse(bulkByScrollResponse); + }, e -> { + logger.error( + () -> format( + "An error occurred while changing aliases and removing the old index [%s] from feature [%s]", + oldIndexName, + migrationInfo.getFeatureName() + ), + e + ); + removeReadOnlyBlockOnReindexFailure(oldIndex, delegate2, e); + })); } }, e -> { logger.error( @@ -514,10 +537,7 @@ public class SystemIndexMigrator extends AllocatedPersistentTask { ); } - private CheckedBiConsumer, AcknowledgedResponse, Exception> setAliasAndRemoveOldIndex( - SystemIndexMigrationInfo migrationInfo, - BulkByScrollResponse bulkByScrollResponse - ) { + private void setAliasAndRemoveOldIndex(SystemIndexMigrationInfo migrationInfo, ActionListener listener) { final IndicesAliasesRequestBuilder aliasesRequest = migrationInfo.createClient(baseClient).admin().indices().prepareAliases(); aliasesRequest.removeIndex(migrationInfo.getCurrentIndexName()); aliasesRequest.addAlias(migrationInfo.getNextIndexName(), migrationInfo.getCurrentIndexName()); @@ -536,32 +556,44 @@ public class SystemIndexMigrator extends AllocatedPersistentTask { ); }); - // Technically this callback might have a different cluster state, but it shouldn't matter - these indices shouldn't be changing - // while we're trying to migrate them. - return (listener, unsetReadOnlyResponse) -> aliasesRequest.execute( - listener.delegateFailureAndWrap((l, deleteIndexResponse) -> l.onResponse(bulkByScrollResponse)) - ); + aliasesRequest.execute(listener); } /** - * Makes the index readonly if it's not set as a readonly yet + * Sets the write block on the index to the given value. */ @FixForMultiProject(description = "Don't use default project id to update settings") private void setWriteBlock(Index index, boolean readOnlyValue, ActionListener listener) { - final Settings readOnlySettings = Settings.builder().put(IndexMetadata.INDEX_BLOCKS_WRITE_SETTING.getKey(), readOnlyValue).build(); - - metadataUpdateSettingsService.updateSettings( - new UpdateSettingsClusterStateUpdateRequest( - Metadata.DEFAULT_PROJECT_ID, - MasterNodeRequest.INFINITE_MASTER_NODE_TIMEOUT, - TimeValue.ZERO, - readOnlySettings, - UpdateSettingsClusterStateUpdateRequest.OnExisting.OVERWRITE, - UpdateSettingsClusterStateUpdateRequest.OnStaticSetting.REJECT, - index - ), - listener - ); + if (readOnlyValue) { + // Setting the Block with an AddIndexBlockRequest ensures all shards have accounted for the block and all + // in-flight writes are completed before returning. + baseClient.admin() + .indices() + .addBlock( + new AddIndexBlockRequest(WRITE, index.getName()).masterNodeTimeout(MasterNodeRequest.INFINITE_MASTER_NODE_TIMEOUT), + listener.delegateFailureAndWrap((l, response) -> { + if (response.isAcknowledged() == false) { + throw new ElasticsearchException("Failed to acknowledge read-only block index request"); + } + l.onResponse(response); + }) + ); + } else { + // The only way to remove a Block is via a settings update. + final Settings readOnlySettings = Settings.builder().put(IndexMetadata.INDEX_BLOCKS_WRITE_SETTING.getKey(), false).build(); + metadataUpdateSettingsService.updateSettings( + new UpdateSettingsClusterStateUpdateRequest( + Metadata.DEFAULT_PROJECT_ID, + MasterNodeRequest.INFINITE_MASTER_NODE_TIMEOUT, + TimeValue.ZERO, + readOnlySettings, + UpdateSettingsClusterStateUpdateRequest.OnExisting.OVERWRITE, + UpdateSettingsClusterStateUpdateRequest.OnStaticSetting.REJECT, + index + ), + listener + ); + } } private void reindex(SystemIndexMigrationInfo migrationInfo, ActionListener listener) { diff --git a/server/src/main/resources/org/elasticsearch/TransportVersions.csv b/server/src/main/resources/org/elasticsearch/TransportVersions.csv index 81d9bf5cb30a..97b6dd76bf02 100644 --- a/server/src/main/resources/org/elasticsearch/TransportVersions.csv +++ b/server/src/main/resources/org/elasticsearch/TransportVersions.csv @@ -137,5 +137,7 @@ 8.16.1,8772004 8.16.2,8772004 8.16.3,8772004 +8.16.4,8772004 8.17.0,8797002 8.17.1,8797002 +8.17.2,8797002 diff --git a/server/src/main/resources/org/elasticsearch/bootstrap/test-framework.policy b/server/src/main/resources/org/elasticsearch/bootstrap/test-framework.policy index 77aae99907df..ada61c118ec3 100644 --- a/server/src/main/resources/org/elasticsearch/bootstrap/test-framework.policy +++ b/server/src/main/resources/org/elasticsearch/bootstrap/test-framework.policy @@ -23,6 +23,13 @@ grant codeBase "${codebase.mockito-core}" { permission java.lang.RuntimePermission "accessDeclaredMembers"; permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; permission java.lang.RuntimePermission "getClassLoader"; + // needed when calling bytebuddy + permission java.lang.RuntimePermission "createClassLoader"; + permission java.lang.RuntimePermission "net.bytebuddy.createJavaDispatcher"; + permission java.lang.reflect.ReflectPermission "newProxyInPackage.net.bytebuddy.utility"; + permission java.lang.reflect.ReflectPermission "newProxyInPackage.net.bytebuddy.dynamic.loading"; + permission java.lang.reflect.ReflectPermission "newProxyInPackage.net.bytebuddy.description.type"; + permission java.lang.reflect.ReflectPermission "newProxyInPackage.net.bytebuddy.description.method"; }; grant codeBase "${codebase.byte-buddy}" { diff --git a/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv b/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv index 874d9fe3d015..164516a562b7 100644 --- a/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv +++ b/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv @@ -137,5 +137,7 @@ 8.16.1,8518000 8.16.2,8518000 8.16.3,8518000 +8.16.4,8518000 8.17.0,8521000 8.17.1,8521000 +8.17.2,8521000 diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/desirednodes/TransportUpdateDesiredNodesActionTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/desirednodes/TransportUpdateDesiredNodesActionTests.java index c8d7f9b7948c..f32ebd323514 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/desirednodes/TransportUpdateDesiredNodesActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/desirednodes/TransportUpdateDesiredNodesActionTests.java @@ -21,12 +21,10 @@ import org.elasticsearch.cluster.metadata.DesiredNodeWithStatus; import org.elasticsearch.cluster.metadata.DesiredNodes; import org.elasticsearch.cluster.metadata.DesiredNodesMetadata; import org.elasticsearch.cluster.metadata.DesiredNodesTestCase; -import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.Metadata; import org.elasticsearch.cluster.routing.RerouteService; import org.elasticsearch.cluster.routing.allocation.AllocationService; import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.features.FeatureService; import org.elasticsearch.test.MockUtils; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; @@ -53,10 +51,8 @@ public class TransportUpdateDesiredNodesActionTests extends DesiredNodesTestCase transportService, mock(ClusterService.class), mock(RerouteService.class), - mock(FeatureService.class), threadPool, mock(ActionFilters.class), - mock(IndexNameExpressionResolver.class), mock(AllocationService.class) ); @@ -81,10 +77,8 @@ public class TransportUpdateDesiredNodesActionTests extends DesiredNodesTestCase transportService, mock(ClusterService.class), mock(RerouteService.class), - mock(FeatureService.class), threadPool, mock(ActionFilters.class), - mock(IndexNameExpressionResolver.class), mock(AllocationService.class) ); diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/diskusage/TransportAnalyzeIndexDiskUsageActionTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/diskusage/TransportAnalyzeIndexDiskUsageActionTests.java index 658637c4d379..78a33b6f4f31 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/diskusage/TransportAnalyzeIndexDiskUsageActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/diskusage/TransportAnalyzeIndexDiskUsageActionTests.java @@ -20,7 +20,6 @@ import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNodeUtils; import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.project.TestProjectResolvers; -import org.elasticsearch.cluster.routing.PlainShardIterator; import org.elasticsearch.cluster.routing.ShardIterator; import org.elasticsearch.cluster.routing.ShardRouting; import org.elasticsearch.cluster.routing.ShardRoutingState; @@ -312,7 +311,7 @@ public class TransportAnalyzeIndexDiskUsageActionTests extends ESTestCase { ) { final List shardIterators = new ArrayList<>(targetShards.size()); for (Map.Entry> e : targetShards.entrySet()) { - shardIterators.add(new PlainShardIterator(e.getKey(), e.getValue())); + shardIterators.add(new ShardIterator(e.getKey(), e.getValue())); } return shardIterators; } diff --git a/server/src/test/java/org/elasticsearch/action/get/TransportMultiGetActionTests.java b/server/src/test/java/org/elasticsearch/action/get/TransportMultiGetActionTests.java index cc9c0e456cba..ed8718008d71 100644 --- a/server/src/test/java/org/elasticsearch/action/get/TransportMultiGetActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/get/TransportMultiGetActionTests.java @@ -50,6 +50,7 @@ import org.elasticsearch.xcontent.XContentType; import org.junit.AfterClass; import org.junit.BeforeClass; +import java.util.Collections; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -72,7 +73,6 @@ public class TransportMultiGetActionTests extends ESTestCase { private static ProjectResolver projectResolver; private static ClusterService clusterService; private static TransportMultiGetAction transportAction; - private static TransportShardMultiGetAction shardAction; @BeforeClass public static void beforeClass() throws Exception { @@ -143,11 +143,9 @@ public class TransportMultiGetActionTests extends ESTestCase { .metadata(new Metadata.Builder().put(project)) .build(); - final ShardIterator index1ShardIterator = mock(ShardIterator.class); - when(index1ShardIterator.shardId()).thenReturn(new ShardId(index1, randomInt())); + final ShardIterator index1ShardIterator = new ShardIterator(new ShardId(index1, randomInt()), Collections.emptyList()); - final ShardIterator index2ShardIterator = mock(ShardIterator.class); - when(index2ShardIterator.shardId()).thenReturn(new ShardId(index2, randomInt())); + final ShardIterator index2ShardIterator = new ShardIterator(new ShardId(index2, randomInt()), Collections.emptyList()); final OperationRouting operationRouting = mock(OperationRouting.class); @@ -174,22 +172,6 @@ public class TransportMultiGetActionTests extends ESTestCase { when(clusterService.localNode()).thenReturn(transportService.getLocalNode()); when(clusterService.state()).thenReturn(clusterState); when(clusterService.operationRouting()).thenReturn(operationRouting); - final NodeClient client = new NodeClient(Settings.EMPTY, threadPool); - - shardAction = new TransportShardMultiGetAction( - clusterService, - transportService, - mock(IndicesService.class), - threadPool, - new ActionFilters(emptySet()), - projectResolver, - new Resolver(), - EmptySystemIndices.INSTANCE.getExecutorSelector(), - client - ) { - @Override - protected void doExecute(Task task, MultiGetShardRequest request, ActionListener listener) {} - }; } @AfterClass @@ -199,7 +181,6 @@ public class TransportMultiGetActionTests extends ESTestCase { transportService = null; clusterService = null; transportAction = null; - shardAction = null; } public void testTransportMultiGetAction() { @@ -294,5 +275,4 @@ public class TransportMultiGetActionTests extends ESTestCase { return new Index("index1", randomBase64UUID()); } } - } diff --git a/server/src/test/java/org/elasticsearch/action/search/MockSearchPhaseContext.java b/server/src/test/java/org/elasticsearch/action/search/MockSearchPhaseContext.java index 97d420b7cd3c..b642787fbf90 100644 --- a/server/src/test/java/org/elasticsearch/action/search/MockSearchPhaseContext.java +++ b/server/src/test/java/org/elasticsearch/action/search/MockSearchPhaseContext.java @@ -150,7 +150,7 @@ public final class MockSearchPhaseContext extends AbstractSearchAsyncAction listener ) { onShardResult(new SearchPhaseResult() { - }, shardIt); + }); } @Override diff --git a/server/src/test/java/org/elasticsearch/action/termvectors/TransportMultiTermVectorsActionTests.java b/server/src/test/java/org/elasticsearch/action/termvectors/TransportMultiTermVectorsActionTests.java index 4dc9b98c92a4..70c4d0ca8ce5 100644 --- a/server/src/test/java/org/elasticsearch/action/termvectors/TransportMultiTermVectorsActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/termvectors/TransportMultiTermVectorsActionTests.java @@ -38,7 +38,6 @@ import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexVersion; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.indices.EmptySystemIndices; -import org.elasticsearch.indices.IndicesService; import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.TaskId; import org.elasticsearch.test.ESTestCase; @@ -51,6 +50,7 @@ import org.elasticsearch.xcontent.XContentType; import org.junit.AfterClass; import org.junit.BeforeClass; +import java.util.Collections; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -73,7 +73,6 @@ public class TransportMultiTermVectorsActionTests extends ESTestCase { private static ClusterService clusterService; private static ProjectResolver projectResolver; private static TransportMultiTermVectorsAction transportAction; - private static TransportShardMultiTermsVectorAction shardAction; @BeforeClass public static void beforeClass() throws Exception { @@ -144,12 +143,8 @@ public class TransportMultiTermVectorsActionTests extends ESTestCase { .metadata(new Metadata.Builder().put(project).build()) .build(); - final ShardIterator index1ShardIterator = mock(ShardIterator.class); - when(index1ShardIterator.shardId()).thenReturn(new ShardId(index1, randomInt())); - - final ShardIterator index2ShardIterator = mock(ShardIterator.class); - when(index2ShardIterator.shardId()).thenReturn(new ShardId(index2, randomInt())); - + final ShardIterator index1ShardIterator = new ShardIterator(new ShardId(index1, randomInt()), Collections.emptyList()); + final ShardIterator index2ShardIterator = new ShardIterator(new ShardId(index2, randomInt()), Collections.emptyList()); final OperationRouting operationRouting = mock(OperationRouting.class); when( operationRouting.getShards( @@ -174,23 +169,6 @@ public class TransportMultiTermVectorsActionTests extends ESTestCase { when(clusterService.localNode()).thenReturn(transportService.getLocalNode()); when(clusterService.state()).thenReturn(clusterState); when(clusterService.operationRouting()).thenReturn(operationRouting); - - shardAction = new TransportShardMultiTermsVectorAction( - clusterService, - transportService, - mock(IndicesService.class), - threadPool, - new ActionFilters(emptySet()), - projectResolver, - new Resolver() - ) { - @Override - protected void doExecute( - Task task, - MultiTermVectorsShardRequest request, - ActionListener listener - ) {} - }; } @AfterClass @@ -200,7 +178,6 @@ public class TransportMultiTermVectorsActionTests extends ESTestCase { transportService = null; clusterService = null; transportAction = null; - shardAction = null; } public void testTransportMultiGetAction() { diff --git a/server/src/test/java/org/elasticsearch/bootstrap/NoSecurityManagerTests.java b/server/src/test/java/org/elasticsearch/bootstrap/NoSecurityManagerTests.java index c1bb94102057..d7628be0d7f0 100644 --- a/server/src/test/java/org/elasticsearch/bootstrap/NoSecurityManagerTests.java +++ b/server/src/test/java/org/elasticsearch/bootstrap/NoSecurityManagerTests.java @@ -12,6 +12,7 @@ package org.elasticsearch.bootstrap; import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters; import org.apache.lucene.tests.util.LuceneTestCase; +import org.elasticsearch.jdk.RuntimeVersionFeature; import org.elasticsearch.test.GraalVMThreadsFilter; import static org.hamcrest.Matchers.is; @@ -20,6 +21,7 @@ import static org.hamcrest.Matchers.is; public class NoSecurityManagerTests extends LuceneTestCase { public void testPrepopulateSecurityCaller() { + assumeTrue("security manager must be available", RuntimeVersionFeature.isSecurityManagerAvailable()); assumeTrue("Unexpected security manager:" + System.getSecurityManager(), System.getSecurityManager() == null); boolean isAtLeastJava17 = Runtime.version().feature() >= 17; boolean isPrepopulated = Security.prepopulateSecurityCaller(); diff --git a/server/src/test/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolverTests.java b/server/src/test/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolverTests.java index 9dc6b3244a2b..821420185565 100644 --- a/server/src/test/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolverTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolverTests.java @@ -14,15 +14,24 @@ import org.elasticsearch.cluster.project.TestProjectResolvers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.core.Tuple; +import org.elasticsearch.index.IndexVersion; import org.elasticsearch.indices.EmptySystemIndices; import org.elasticsearch.indices.InvalidIndexNameException; +import org.elasticsearch.indices.SystemIndexDescriptor; +import org.elasticsearch.indices.SystemIndices; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xcontent.XContentBuilder; +import java.io.IOException; +import java.io.UncheckedIOException; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; +import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME; +import static org.elasticsearch.indices.SystemIndices.SYSTEM_INDEX_ACCESS_CONTROL_HEADER_KEY; +import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.either; @@ -227,13 +236,78 @@ public class IndexAbstractionResolverTests extends ESTestCase { "*", selector, index, - IndicesOptions.strictExpandOpen(), + IndicesOptions.strictExpandHidden(), projectMetadata, indexNameExpressionResolver, true ); } + public void testIsNetNewSystemIndexVisible() { + final Settings settings = Settings.builder() + .put("index.number_of_replicas", 0) + .put("index.number_of_shards", 1) + .put(IndexMetadata.SETTING_VERSION_CREATED, IndexVersion.current()) + .build(); + + final Settings hiddenSettings = Settings.builder().put(settings).put("index.hidden", true).build(); + + final IndexMetadata foo = IndexMetadata.builder(".foo").settings(hiddenSettings).system(true).build(); + final IndexMetadata barReindexed = IndexMetadata.builder(".bar-reindexed") + .settings(hiddenSettings) + .system(true) + .putAlias(AliasMetadata.builder(".bar").isHidden(true).build()) + .build(); + final IndexMetadata other = IndexMetadata.builder("other").settings(settings).build(); + + final SystemIndexDescriptor fooDescriptor = SystemIndexDescriptor.builder() + .setDescription("foo indices") + .setOrigin("foo origin") + .setPrimaryIndex(".foo") + .setIndexPattern(".foo*") + .setSettings(settings) + .setMappings(mappings()) + .setNetNew() + .build(); + final SystemIndexDescriptor barDescriptor = SystemIndexDescriptor.builder() + .setDescription("bar indices") + .setOrigin("bar origin") + .setPrimaryIndex(".bar") + .setIndexPattern(".bar*") + .setSettings(settings) + .setMappings(mappings()) + .setNetNew() + .build(); + final SystemIndices systemIndices = new SystemIndices( + List.of(new SystemIndices.Feature("name", "description", List.of(fooDescriptor, barDescriptor))) + ); + + final ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + threadContext.putHeader(SYSTEM_INDEX_ACCESS_CONTROL_HEADER_KEY, "false"); + indexNameExpressionResolver = new IndexNameExpressionResolver(threadContext, systemIndices); + indexAbstractionResolver = new IndexAbstractionResolver(indexNameExpressionResolver); + + metadata = Metadata.builder().put(foo, true).put(barReindexed, true).put(other, true).build(); + + assertThat(isIndexVisible("other", "*"), is(true)); + assertThat(isIndexVisible(".foo", "*"), is(false)); + assertThat(isIndexVisible(".bar", "*"), is(false)); + } + + private static XContentBuilder mappings() { + try (XContentBuilder builder = jsonBuilder()) { + return builder.startObject() + .startObject(SINGLE_MAPPING_NAME) + .startObject("_meta") + .field(SystemIndexDescriptor.VERSION_META_KEY, 0) + .endObject() + .endObject() + .endObject(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + private List resolveAbstractionsSelectorNotAllowed(List expressions) { return resolveAbstractions(expressions, IndicesOptions.strictExpandHiddenNoSelectors(), defaultMask); } diff --git a/server/src/test/java/org/elasticsearch/cluster/routing/PlainShardIteratorTests.java b/server/src/test/java/org/elasticsearch/cluster/routing/ShardIteratorTests.java similarity index 77% rename from server/src/test/java/org/elasticsearch/cluster/routing/PlainShardIteratorTests.java rename to server/src/test/java/org/elasticsearch/cluster/routing/ShardIteratorTests.java index a7d3ed95320c..8666abf1292c 100644 --- a/server/src/test/java/org/elasticsearch/cluster/routing/PlainShardIteratorTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/routing/ShardIteratorTests.java @@ -19,12 +19,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -public class PlainShardIteratorTests extends ESTestCase { +public class ShardIteratorTests extends ESTestCase { public void testEqualsAndHashCode() { EqualsHashCodeTestUtils.checkEqualsAndHashCode( randomPlainShardIterator(), - i -> new PlainShardIterator(i.shardId(), i.getShardRoutings()), + i -> new ShardIterator(i.shardId(), i.getShardRoutings()), i -> { ShardId shardId = switch (randomIntBetween(0, 2)) { case 0 -> new ShardId(i.shardId().getIndex(), i.shardId().getId() + randomIntBetween(1, 1000)); @@ -40,7 +40,7 @@ public class PlainShardIteratorTests extends ESTestCase { ); default -> throw new UnsupportedOperationException(); }; - return new PlainShardIterator(shardId, i.getShardRoutings()); + return new ShardIterator(shardId, i.getShardRoutings()); } ); } @@ -50,26 +50,26 @@ public class PlainShardIteratorTests extends ESTestCase { Arrays.sort(indices); String[] uuids = generateRandomStringArray(3, 10, false, false); Arrays.sort(uuids); - List shardIterators = new ArrayList<>(); + List shardIterators = new ArrayList<>(); int numShards = randomIntBetween(1, 5); for (int i = 0; i < numShards; i++) { for (String index : indices) { for (String uuid : uuids) { ShardId shardId = new ShardId(index, uuid, i); - shardIterators.add(new PlainShardIterator(shardId, SearchShardIteratorTests.randomShardRoutings(shardId))); + shardIterators.add(new ShardIterator(shardId, SearchShardIteratorTests.randomShardRoutings(shardId))); } } } for (int i = 0; i < shardIterators.size(); i++) { - PlainShardIterator currentIterator = shardIterators.get(i); + ShardIterator currentIterator = shardIterators.get(i); for (int j = i + 1; j < shardIterators.size(); j++) { - PlainShardIterator greaterIterator = shardIterators.get(j); + ShardIterator greaterIterator = shardIterators.get(j); assertThat(currentIterator, Matchers.lessThan(greaterIterator)); assertThat(greaterIterator, Matchers.greaterThan(currentIterator)); assertNotEquals(currentIterator, greaterIterator); } for (int j = i - 1; j >= 0; j--) { - PlainShardIterator smallerIterator = shardIterators.get(j); + ShardIterator smallerIterator = shardIterators.get(j); assertThat(smallerIterator, Matchers.lessThan(currentIterator)); assertThat(currentIterator, Matchers.greaterThan(smallerIterator)); assertNotEquals(currentIterator, smallerIterator); @@ -78,15 +78,15 @@ public class PlainShardIteratorTests extends ESTestCase { } public void testCompareToEqualItems() { - PlainShardIterator shardIterator1 = randomPlainShardIterator(); - PlainShardIterator shardIterator2 = new PlainShardIterator(shardIterator1.shardId(), shardIterator1.getShardRoutings()); + ShardIterator shardIterator1 = randomPlainShardIterator(); + ShardIterator shardIterator2 = new ShardIterator(shardIterator1.shardId(), shardIterator1.getShardRoutings()); assertEquals(shardIterator1, shardIterator2); assertEquals(0, shardIterator1.compareTo(shardIterator2)); assertEquals(0, shardIterator2.compareTo(shardIterator1)); } - private static PlainShardIterator randomPlainShardIterator() { + private static ShardIterator randomPlainShardIterator() { ShardId shardId = new ShardId(randomAlphaOfLengthBetween(5, 10), randomAlphaOfLength(10), randomIntBetween(1, Integer.MAX_VALUE)); - return new PlainShardIterator(shardId, SearchShardIteratorTests.randomShardRoutings(shardId)); + return new ShardIterator(shardId, SearchShardIteratorTests.randomShardRoutings(shardId)); } } diff --git a/server/src/test/java/org/elasticsearch/cluster/structure/RoutingIteratorTests.java b/server/src/test/java/org/elasticsearch/cluster/structure/RoutingIteratorTests.java index 7d3fa2d79126..e76dcc82364c 100644 --- a/server/src/test/java/org/elasticsearch/cluster/structure/RoutingIteratorTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/structure/RoutingIteratorTests.java @@ -23,7 +23,6 @@ import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.routing.GlobalRoutingTable; import org.elasticsearch.cluster.routing.GlobalRoutingTableTestHelper; import org.elasticsearch.cluster.routing.OperationRouting; -import org.elasticsearch.cluster.routing.PlainShardIterator; import org.elasticsearch.cluster.routing.RotationShardShuffler; import org.elasticsearch.cluster.routing.RoutingTable; import org.elasticsearch.cluster.routing.ShardIterator; @@ -55,7 +54,7 @@ import static org.hamcrest.Matchers.sameInstance; public class RoutingIteratorTests extends ESAllocationTestCase { public void testEmptyIterator() { ShardShuffler shuffler = new RotationShardShuffler(0); - ShardIterator shardIterator = new PlainShardIterator( + ShardIterator shardIterator = new ShardIterator( new ShardId("test1", "_na_", 0), shuffler.shuffle(Collections.emptyList()) ); @@ -65,21 +64,21 @@ public class RoutingIteratorTests extends ESAllocationTestCase { assertThat(shardIterator.nextOrNull(), nullValue()); assertThat(shardIterator.remaining(), equalTo(0)); - shardIterator = new PlainShardIterator(new ShardId("test1", "_na_", 0), shuffler.shuffle(Collections.emptyList())); + shardIterator = new ShardIterator(new ShardId("test1", "_na_", 0), shuffler.shuffle(Collections.emptyList())); assertThat(shardIterator.remaining(), equalTo(0)); assertThat(shardIterator.nextOrNull(), nullValue()); assertThat(shardIterator.remaining(), equalTo(0)); assertThat(shardIterator.nextOrNull(), nullValue()); assertThat(shardIterator.remaining(), equalTo(0)); - shardIterator = new PlainShardIterator(new ShardId("test1", "_na_", 0), shuffler.shuffle(Collections.emptyList())); + shardIterator = new ShardIterator(new ShardId("test1", "_na_", 0), shuffler.shuffle(Collections.emptyList())); assertThat(shardIterator.remaining(), equalTo(0)); assertThat(shardIterator.nextOrNull(), nullValue()); assertThat(shardIterator.remaining(), equalTo(0)); assertThat(shardIterator.nextOrNull(), nullValue()); assertThat(shardIterator.remaining(), equalTo(0)); - shardIterator = new PlainShardIterator(new ShardId("test1", "_na_", 0), shuffler.shuffle(Collections.emptyList())); + shardIterator = new ShardIterator(new ShardId("test1", "_na_", 0), shuffler.shuffle(Collections.emptyList())); assertThat(shardIterator.remaining(), equalTo(0)); assertThat(shardIterator.nextOrNull(), nullValue()); assertThat(shardIterator.remaining(), equalTo(0)); diff --git a/server/src/test/java/org/elasticsearch/health/node/DiskHealthIndicatorServiceTests.java b/server/src/test/java/org/elasticsearch/health/node/DiskHealthIndicatorServiceTests.java index 07aa9af3b403..b77f970d9e78 100644 --- a/server/src/test/java/org/elasticsearch/health/node/DiskHealthIndicatorServiceTests.java +++ b/server/src/test/java/org/elasticsearch/health/node/DiskHealthIndicatorServiceTests.java @@ -117,7 +117,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { public void testServiceBasics() { Set discoveryNodes = createNodesWithAllRoles(); ClusterService clusterService = createClusterService(discoveryNodes, false); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); { HealthStatus expectedStatus = HealthStatus.UNKNOWN; HealthInfo healthInfo = HealthInfo.EMPTY_HEALTH_INFO; @@ -141,7 +141,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { public void testIndicatorYieldsGreenWhenNodeHasUnknownStatus() { Set discoveryNodes = createNodesWithAllRoles(); ClusterService clusterService = createClusterService(discoveryNodes, false); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); HealthStatus expectedStatus = HealthStatus.GREEN; HealthInfo healthInfo = createHealthInfoWithOneUnhealthyNode(HealthStatus.UNKNOWN, discoveryNodes); @@ -152,7 +152,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { public void testGreen() throws IOException { Set discoveryNodes = createNodesWithAllRoles(); ClusterService clusterService = createClusterService(discoveryNodes, false); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); HealthStatus expectedStatus = HealthStatus.GREEN; HealthInfo healthInfo = createHealthInfoWithOneUnhealthyNode(expectedStatus, discoveryNodes); HealthIndicatorResult result = diskHealthIndicatorService.calculate(true, healthInfo); @@ -187,7 +187,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { final var clusterService = createClusterService(Set.of(), allNodes, indexNameToNodeIdsMap); HealthStatus expectedStatus = HealthStatus.YELLOW; HealthInfo healthInfo = createHealthInfo(new HealthInfoConfig(expectedStatus, allNodes.size(), allNodes)); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); HealthIndicatorResult result = diskHealthIndicatorService.calculate(true, healthInfo); assertThat(result.status(), equalTo(expectedStatus)); assertThat(result.symptom(), containsString("with roles: [data")); @@ -265,7 +265,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { indexNameToNodeIdsMap.put(indexName, new HashSet<>(randomNonEmptySubsetOf(affectedNodeIds))); } ClusterService clusterService = createClusterService(Set.of(), discoveryNodes, indexNameToNodeIdsMap); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); Map diskInfoByNode = new HashMap<>(); for (DiscoveryNode discoveryNode : discoveryNodes) { if (affectedNodeIds.contains(discoveryNode.getId())) { @@ -329,7 +329,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { public void testRedWithBlockedIndicesAndGreenNodes() throws IOException { Set discoveryNodes = createNodesWithAllRoles(); ClusterService clusterService = createClusterService(discoveryNodes, true); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); HealthStatus expectedStatus = HealthStatus.RED; HealthInfo healthInfo = createHealthInfoWithOneUnhealthyNode(HealthStatus.GREEN, discoveryNodes); @@ -374,7 +374,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { public void testRedWithBlockedIndicesAndYellowNodes() throws IOException { Set discoveryNodes = createNodesWithAllRoles(); ClusterService clusterService = createClusterService(discoveryNodes, true); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); HealthStatus expectedStatus = HealthStatus.RED; int numberOfYellowNodes = randomIntBetween(1, discoveryNodes.size()); HealthInfo healthInfo = createHealthInfo(new HealthInfoConfig(HealthStatus.YELLOW, numberOfYellowNodes, discoveryNodes)); @@ -453,7 +453,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { } } ClusterService clusterService = createClusterService(blockedIndices, discoveryNodes, indexNameToNodeIdsMap); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); HealthIndicatorResult result = diskHealthIndicatorService.calculate(true, healthInfo); assertThat(result.status(), equalTo(expectedStatus)); assertThat( @@ -492,7 +492,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { indexNameToNodeIdsMap.put(indexName, nonRedNodeIds); } ClusterService clusterService = createClusterService(Set.of(), discoveryNodes, indexNameToNodeIdsMap); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); HealthIndicatorResult result = diskHealthIndicatorService.calculate(true, healthInfo); assertThat(result.status(), equalTo(expectedStatus)); assertThat(result.impacts().size(), equalTo(3)); @@ -528,7 +528,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { Set discoveryNodesInClusterState = new HashSet<>(discoveryNodes); discoveryNodesInClusterState.add(DiscoveryNodeUtils.create(randomAlphaOfLength(30), UUID.randomUUID().toString())); ClusterService clusterService = createClusterService(discoveryNodesInClusterState, false); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); { HealthInfo healthInfo = HealthInfo.EMPTY_HEALTH_INFO; HealthIndicatorResult result = diskHealthIndicatorService.calculate(true, healthInfo); @@ -560,7 +560,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { Set roles = Set.of(DiscoveryNodeRole.MASTER_ROLE, otherRole); Set discoveryNodes = createNodes(roles); ClusterService clusterService = createClusterService(discoveryNodes, false); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); HealthStatus expectedStatus = randomFrom(HealthStatus.RED, HealthStatus.YELLOW); int numberOfProblemNodes = randomIntBetween(1, discoveryNodes.size()); HealthInfo healthInfo = createHealthInfo(new HealthInfoConfig(expectedStatus, numberOfProblemNodes, discoveryNodes)); @@ -615,7 +615,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { Set roles = new HashSet<>(randomNonEmptySubsetOf(OTHER_ROLES)); Set nodes = createNodes(roles); ClusterService clusterService = createClusterService(nodes, false); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); HealthStatus expectedStatus = randomFrom(HealthStatus.RED, HealthStatus.YELLOW); int numberOfProblemNodes = randomIntBetween(1, nodes.size()); HealthInfo healthInfo = createHealthInfo(new HealthInfoConfig(expectedStatus, numberOfProblemNodes, nodes)); @@ -671,7 +671,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { Set masterNodes = createNodes(masterRole); Set otherNodes = createNodes(otherRoles); ClusterService clusterService = createClusterService(Sets.union(Sets.union(dataNodes, masterNodes), otherNodes), true); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); int numberOfRedMasterNodes = randomIntBetween(1, masterNodes.size()); int numberOfRedOtherNodes = randomIntBetween(1, otherNodes.size()); int numberOfYellowDataNodes = randomIntBetween(1, dataNodes.size()); @@ -893,7 +893,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { Set masterNodes = createNodes(20, masterRole); Set otherNodes = createNodes(10, otherRoles); ClusterService clusterService = createClusterService(Sets.union(Sets.union(dataNodes, masterNodes), otherNodes), true); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); int numberOfRedMasterNodes = masterNodes.size(); int numberOfRedOtherNodes = otherNodes.size(); int numberOfYellowDataNodes = dataNodes.size(); @@ -968,7 +968,7 @@ public class DiskHealthIndicatorServiceTests extends ESTestCase { public void testSkippingFieldsWhenVerboseIsFalse() { Set discoveryNodes = createNodesWithAllRoles(); ClusterService clusterService = createClusterService(discoveryNodes, false); - DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService, featureService); + DiskHealthIndicatorService diskHealthIndicatorService = new DiskHealthIndicatorService(clusterService); HealthStatus expectedStatus = HealthStatus.RED; HealthInfo healthInfo = createHealthInfoWithOneUnhealthyNode(expectedStatus, discoveryNodes); HealthIndicatorResult result = diskHealthIndicatorService.calculate(false, healthInfo); diff --git a/server/src/test/java/org/elasticsearch/health/node/selection/HealthNodeTaskExecutorTests.java b/server/src/test/java/org/elasticsearch/health/node/selection/HealthNodeTaskExecutorTests.java index aee02fb288b5..420a655e092e 100644 --- a/server/src/test/java/org/elasticsearch/health/node/selection/HealthNodeTaskExecutorTests.java +++ b/server/src/test/java/org/elasticsearch/health/node/selection/HealthNodeTaskExecutorTests.java @@ -94,7 +94,7 @@ public class HealthNodeTaskExecutorTests extends ESTestCase { } public void testTaskCreation() throws Exception { - HealthNodeTaskExecutor.create(clusterService, persistentTasksService, featureService, settings, clusterSettings); + HealthNodeTaskExecutor.create(clusterService, persistentTasksService, settings, clusterSettings); clusterService.getClusterApplierService().onNewClusterState("initialization", this::initialState, ActionListener.noop()); // Ensure that if the task is gone, it will be recreated. clusterService.getClusterApplierService().onNewClusterState("initialization", this::initialState, ActionListener.noop()); @@ -110,13 +110,7 @@ public class HealthNodeTaskExecutorTests extends ESTestCase { } public void testSkippingTaskCreationIfItExists() { - HealthNodeTaskExecutor executor = HealthNodeTaskExecutor.create( - clusterService, - persistentTasksService, - featureService, - settings, - clusterSettings - ); + HealthNodeTaskExecutor executor = HealthNodeTaskExecutor.create(clusterService, persistentTasksService, settings, clusterSettings); executor.startTask(new ClusterChangedEvent("", stateWithHealthNodeSelectorTask(initialState()), ClusterState.EMPTY_STATE)); verify(persistentTasksService, never()).sendStartRequest( eq("health-node"), @@ -132,7 +126,6 @@ public class HealthNodeTaskExecutorTests extends ESTestCase { HealthNodeTaskExecutor executor = HealthNodeTaskExecutor.create( clusterService, persistentTasksService, - featureService, settings, clusterSettings ); @@ -150,7 +143,6 @@ public class HealthNodeTaskExecutorTests extends ESTestCase { HealthNodeTaskExecutor executor = HealthNodeTaskExecutor.create( clusterService, persistentTasksService, - featureService, settings, clusterSettings ); @@ -165,13 +157,7 @@ public class HealthNodeTaskExecutorTests extends ESTestCase { } public void testAbortOnDisable() { - HealthNodeTaskExecutor executor = HealthNodeTaskExecutor.create( - clusterService, - persistentTasksService, - featureService, - settings, - clusterSettings - ); + HealthNodeTaskExecutor executor = HealthNodeTaskExecutor.create(clusterService, persistentTasksService, settings, clusterSettings); HealthNode task = mock(HealthNode.class); PersistentTaskState state = mock(PersistentTaskState.class); executor.nodeOperation(task, new HealthNodeTaskParams(), state); diff --git a/server/src/test/java/org/elasticsearch/http/AbstractHttpServerTransportTests.java b/server/src/test/java/org/elasticsearch/http/AbstractHttpServerTransportTests.java index b873fbdef912..b075e08a9ea0 100644 --- a/server/src/test/java/org/elasticsearch/http/AbstractHttpServerTransportTests.java +++ b/server/src/test/java/org/elasticsearch/http/AbstractHttpServerTransportTests.java @@ -356,8 +356,6 @@ public class AbstractHttpServerTransportTests extends ESTestCase { } }; - // the set of headers to copy - Set headers = Set.of(new RestHeaderDefinition(Task.TRACE_PARENT_HTTP_HEADER, false)); // sample request headers to test with Map> restHeaders = new HashMap<>(); restHeaders.put(Task.TRACE_PARENT_HTTP_HEADER, Collections.singletonList(traceParentValue)); @@ -398,7 +396,7 @@ public class AbstractHttpServerTransportTests extends ESTestCase { @Override protected void populatePerRequestThreadContext(RestRequest restRequest, ThreadContext threadContext) { - getFakeActionModule(headers).copyRequestHeadersToThreadContext(restRequest.getHttpRequest(), threadContext); + getFakeActionModule(Set.of()).copyRequestHeadersToThreadContext(restRequest.getHttpRequest(), threadContext); } } ) { diff --git a/server/src/test/java/org/elasticsearch/index/SearchSlowLogTests.java b/server/src/test/java/org/elasticsearch/index/SearchSlowLogTests.java index 359118c7cb5a..d4aec300c666 100644 --- a/server/src/test/java/org/elasticsearch/index/SearchSlowLogTests.java +++ b/server/src/test/java/org/elasticsearch/index/SearchSlowLogTests.java @@ -26,6 +26,7 @@ import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.internal.ShardSearchRequest; +import org.elasticsearch.tasks.CancellableTask; import org.elasticsearch.tasks.Task; import org.elasticsearch.test.ESSingleNodeTestCase; import org.elasticsearch.test.TestSearchContext; @@ -93,7 +94,7 @@ public class SearchSlowLogTests extends ESSingleNodeTestCase { } @Override - public SearchShardTask getTask() { + public CancellableTask getTask() { return super.getTask(); } }; diff --git a/server/src/test/java/org/elasticsearch/index/mapper/KeywordFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/KeywordFieldMapperTests.java index 924c32f527f7..198988832cb5 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/KeywordFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/KeywordFieldMapperTests.java @@ -772,34 +772,12 @@ public class KeywordFieldMapperTests extends MapperTestCase { assertScriptDocValues(mapper, "foo", equalTo(List.of("foo"))); } - public void testFieldTypeWithSkipDocValues_LogsDbMode() throws IOException { - assumeTrue("Needs feature flag to be enabled", FieldMapper.DOC_VALUES_SPARSE_INDEX.isEnabled()); - + public void testFieldTypeWithSkipDocValues_LogsDbModeDisabledSetting() throws IOException { final MapperService mapperService = createMapperService( Settings.builder() .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "host.name") - .build(), - mapping(b -> { - b.startObject("host.name"); - b.field("type", "keyword"); - b.endObject(); - }) - ); - - final KeywordFieldMapper mapper = (KeywordFieldMapper) mapperService.documentMapper().mappers().getMapper("host.name"); - assertTrue(mapper.fieldType().hasDocValues()); - assertFalse(mapper.fieldType().isIndexed()); - assertTrue(mapper.fieldType().hasDocValuesSparseIndex()); - } - - public void testFieldTypeDefault_StandardMode() throws IOException { - assumeTrue("Needs feature flag to be enabled", FieldMapper.DOC_VALUES_SPARSE_INDEX.isEnabled()); - - final MapperService mapperService = createMapperService( - Settings.builder() - .put(IndexSettings.MODE.getKey(), IndexMode.STANDARD.name()) - .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "host.name") + .put(IndexSettings.USE_DOC_VALUES_SKIPPER.getKey(), false) .build(), mapping(b -> { b.startObject("host.name"); @@ -811,135 +789,186 @@ public class KeywordFieldMapperTests extends MapperTestCase { final KeywordFieldMapper mapper = (KeywordFieldMapper) mapperService.documentMapper().mappers().getMapper("host.name"); assertTrue(mapper.fieldType().hasDocValues()); assertTrue(mapper.fieldType().isIndexed()); - assertFalse(mapper.fieldType().hasDocValuesSparseIndex()); + assertFalse(mapper.fieldType().hasDocValuesSkipper()); + } + + public void testFieldTypeWithSkipDocValues_LogsDbMode() throws IOException { + final Settings settings = Settings.builder() + .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) + .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "host.name") + .build(); + final MapperService mapperService = createMapperService(settings, mapping(b -> { + b.startObject("host.name"); + b.field("type", "keyword"); + b.endObject(); + })); + + final KeywordFieldMapper mapper = (KeywordFieldMapper) mapperService.documentMapper().mappers().getMapper("host.name"); + assertTrue(mapper.fieldType().hasDocValues()); + assertFalse(IndexSettings.USE_DOC_VALUES_SKIPPER.get(settings) && mapper.fieldType().isIndexed()); + if (IndexSettings.USE_DOC_VALUES_SKIPPER.get(settings)) { + assertTrue(mapper.fieldType().hasDocValuesSkipper()); + } else { + assertFalse(mapper.fieldType().hasDocValuesSkipper()); + } + } + + public void testFieldTypeDefault_StandardMode() throws IOException { + final Settings settings = Settings.builder() + .put(IndexSettings.MODE.getKey(), IndexMode.STANDARD.name()) + .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "host.name") + .build(); + final MapperService mapperService = createMapperService(settings, mapping(b -> { + b.startObject("host.name"); + b.field("type", "keyword"); + b.endObject(); + })); + + final KeywordFieldMapper mapper = (KeywordFieldMapper) mapperService.documentMapper().mappers().getMapper("host.name"); + assertTrue(mapper.fieldType().hasDocValues()); + assertTrue(mapper.fieldType().isIndexed()); + assertFalse(mapper.fieldType().hasDocValuesSkipper()); } public void testFieldTypeDefault_NonMatchingFieldName() throws IOException { - assumeTrue("Needs feature flag to be enabled", FieldMapper.DOC_VALUES_SPARSE_INDEX.isEnabled()); - - final MapperService mapperService = createMapperService( - Settings.builder() - .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) - .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "hostname") - .build(), - mapping(b -> { - b.startObject("hostname"); - b.field("type", "keyword"); - b.endObject(); - }) - ); + final Settings settings = Settings.builder() + .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) + .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "hostname") + .build(); + final MapperService mapperService = createMapperService(settings, mapping(b -> { + b.startObject("hostname"); + b.field("type", "keyword"); + b.endObject(); + })); final KeywordFieldMapper mapper = (KeywordFieldMapper) mapperService.documentMapper().mappers().getMapper("hostname"); assertTrue(mapper.fieldType().hasDocValues()); assertTrue(mapper.fieldType().isIndexed()); - assertFalse(mapper.fieldType().hasDocValuesSparseIndex()); + assertFalse(mapper.fieldType().hasDocValuesSkipper()); } - public void testFieldTypeDefault_ConfiguredIndexed() throws IOException { - assumeTrue("Needs feature flag to be enabled", FieldMapper.DOC_VALUES_SPARSE_INDEX.isEnabled()); - - final MapperService mapperService = createMapperService( - Settings.builder() - .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) - .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "host.name") - .build(), - mapping(b -> { - b.startObject("host.name"); - b.field("type", "keyword"); - b.field("index", true); - b.endObject(); - }) - ); + public void testFieldTypeDefault_ConfiguredIndexedWithSettingOverride() throws IOException { + final Settings settings = Settings.builder() + .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) + .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "host.name") + .build(); + final MapperService mapperService = createMapperService(settings, mapping(b -> { + b.startObject("host.name"); + b.field("type", "keyword"); + b.field("index", true); + b.endObject(); + })); final KeywordFieldMapper mapper = (KeywordFieldMapper) mapperService.documentMapper().mappers().getMapper("host.name"); assertTrue(mapper.fieldType().hasDocValues()); - assertTrue(mapper.fieldType().isIndexed()); - assertFalse(mapper.fieldType().hasDocValuesSparseIndex()); + assertFalse(IndexSettings.USE_DOC_VALUES_SKIPPER.get(settings) && mapper.fieldType().isIndexed()); + if (IndexSettings.USE_DOC_VALUES_SKIPPER.get(settings)) { + assertTrue(mapper.fieldType().hasDocValuesSkipper()); + } else { + assertFalse(mapper.fieldType().hasDocValuesSkipper()); + } + } + + public void testFieldTypeDefault_ConfiguredIndexedWithoutSettingOverride() throws IOException { + final Settings settings = Settings.builder() + .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) + .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "host.name") + .build(); + final MapperService mapperService = createMapperService(settings, mapping(b -> { + b.startObject("host.name"); + b.field("type", "keyword"); + b.field("index", true); + b.endObject(); + })); + + final KeywordFieldMapper mapper = (KeywordFieldMapper) mapperService.documentMapper().mappers().getMapper("host.name"); + assertTrue(mapper.fieldType().hasDocValues()); + assertFalse(IndexSettings.USE_DOC_VALUES_SKIPPER.get(settings) && mapper.fieldType().isIndexed()); + if (IndexSettings.USE_DOC_VALUES_SKIPPER.get(settings)) { + assertTrue(mapper.fieldType().hasDocValuesSkipper()); + } else { + assertFalse(mapper.fieldType().hasDocValuesSkipper()); + } } public void testFieldTypeDefault_ConfiguredDocValues() throws IOException { - assumeTrue("Needs feature flag to be enabled", FieldMapper.DOC_VALUES_SPARSE_INDEX.isEnabled()); - - final MapperService mapperService = createMapperService( - Settings.builder() - .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) - .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "host.name") - .build(), - mapping(b -> { - b.startObject("host.name"); - b.field("type", "keyword"); - b.field("doc_values", true); - b.endObject(); - }) - ); + final Settings settings = Settings.builder() + .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) + .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "host.name") + .build(); + final MapperService mapperService = createMapperService(settings, mapping(b -> { + b.startObject("host.name"); + b.field("type", "keyword"); + b.field("doc_values", true); + b.endObject(); + })); final KeywordFieldMapper mapper = (KeywordFieldMapper) mapperService.documentMapper().mappers().getMapper("host.name"); assertTrue(mapper.fieldType().hasDocValues()); - assertFalse(mapper.fieldType().isIndexed()); - assertTrue(mapper.fieldType().hasDocValuesSparseIndex()); + assertFalse(IndexSettings.USE_DOC_VALUES_SKIPPER.get(settings) && mapper.fieldType().isIndexed()); + if (IndexSettings.USE_DOC_VALUES_SKIPPER.get(settings)) { + assertTrue(mapper.fieldType().hasDocValuesSkipper()); + } else { + assertFalse(mapper.fieldType().hasDocValuesSkipper()); + } } public void testFieldTypeDefault_LogsDbMode_NonSortField() throws IOException { - assumeTrue("Needs feature flag to be enabled", FieldMapper.DOC_VALUES_SPARSE_INDEX.isEnabled()); - - final MapperService mapperService = createMapperService( - Settings.builder().put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()).build(), - mapping(b -> { - b.startObject("host.name"); - b.field("type", "keyword"); - b.endObject(); - }) - ); + final Settings settings = Settings.builder() + .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) + .put(IndexSettings.USE_DOC_VALUES_SKIPPER.getKey(), true) + .build(); + final MapperService mapperService = createMapperService(settings, mapping(b -> { + b.startObject("host.name"); + b.field("type", "keyword"); + b.endObject(); + })); final KeywordFieldMapper mapper = (KeywordFieldMapper) mapperService.documentMapper().mappers().getMapper("host.name"); assertTrue(mapper.fieldType().hasDocValues()); assertTrue(mapper.fieldType().isIndexed()); - assertFalse(mapper.fieldType().hasDocValuesSparseIndex()); + assertFalse(mapper.fieldType().hasDocValuesSkipper()); } public void testFieldTypeWithSkipDocValues_IndexedFalseDocValuesTrue() throws IOException { - assumeTrue("Needs feature flag to be enabled", FieldMapper.DOC_VALUES_SPARSE_INDEX.isEnabled()); - - final MapperService mapperService = createMapperService( - Settings.builder() - .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) - .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "host.name") - .build(), - mapping(b -> { - b.startObject("host.name"); - b.field("type", "keyword"); - b.field("index", false); - b.field("doc_values", true); - b.endObject(); - }) - ); + final Settings settings = Settings.builder() + .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) + .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "host.name") + .build(); + final MapperService mapperService = createMapperService(settings, mapping(b -> { + b.startObject("host.name"); + b.field("type", "keyword"); + b.field("index", false); + b.field("doc_values", true); + b.endObject(); + })); final KeywordFieldMapper mapper = (KeywordFieldMapper) mapperService.documentMapper().mappers().getMapper("host.name"); assertTrue(mapper.fieldType().hasDocValues()); - assertFalse(mapper.fieldType().isIndexed()); - assertFalse(mapper.fieldType().hasDocValuesSparseIndex()); + assertFalse(IndexSettings.USE_DOC_VALUES_SKIPPER.get(settings) && mapper.fieldType().isIndexed()); + if (IndexSettings.USE_DOC_VALUES_SKIPPER.get(settings)) { + assertTrue(mapper.fieldType().hasDocValuesSkipper()); + } else { + assertFalse(mapper.fieldType().hasDocValuesSkipper()); + } } public void testFieldTypeDefault_IndexedFalseDocValuesFalse() throws IOException { - assumeTrue("Needs feature flag to be enabled", FieldMapper.DOC_VALUES_SPARSE_INDEX.isEnabled()); - - final MapperService mapperService = createMapperService( - Settings.builder() - .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) - .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "host.name") - .build(), - mapping(b -> { - b.startObject("host.name"); - b.field("type", "keyword"); - b.field("index", false); - b.field("doc_values", false); - b.endObject(); - }) - ); + final Settings settings = Settings.builder() + .put(IndexSettings.MODE.getKey(), IndexMode.LOGSDB.name()) + .put(IndexSortConfig.INDEX_SORT_FIELD_SETTING.getKey(), "host.name") + .build(); + final MapperService mapperService = createMapperService(settings, mapping(b -> { + b.startObject("host.name"); + b.field("type", "keyword"); + b.field("index", false); + b.field("doc_values", false); + b.endObject(); + })); final KeywordFieldMapper mapper = (KeywordFieldMapper) mapperService.documentMapper().mappers().getMapper("host.name"); assertFalse(mapper.fieldType().hasDocValues()); assertFalse(mapper.fieldType().isIndexed()); - assertFalse(mapper.fieldType().hasDocValuesSparseIndex()); + assertFalse(mapper.fieldType().hasDocValuesSkipper()); } } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java b/server/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java index 507314b31d00..c89753214b6a 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java @@ -15,6 +15,9 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.core.CheckedFunction; +import org.elasticsearch.index.IndexMode; +import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.IndexVersion; import org.elasticsearch.index.IndexVersions; import org.elasticsearch.index.mapper.MapperService.MergeReason; @@ -26,6 +29,7 @@ import org.elasticsearch.xcontent.XContentFactory; import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -304,16 +308,56 @@ public class MapperServiceTests extends MapperServiceTestCase { public void testIsMetadataField() throws IOException { IndexVersion version = IndexVersionUtils.randomCompatibleVersion(random()); - Settings settings = Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, version).build(); - MapperService mapperService = createMapperService(settings, mapping(b -> {})); - assertFalse(mapperService.isMetadataField(randomAlphaOfLengthBetween(10, 15))); + CheckedFunction initMapperService = (indexMode) -> { + Settings.Builder settingsBuilder = Settings.builder() + .put(IndexMetadata.SETTING_VERSION_CREATED, version) + .put(IndexSettings.MODE.getKey(), indexMode); - for (String builtIn : IndicesModule.getBuiltInMetadataFields()) { - if (NestedPathFieldMapper.NAME.equals(builtIn) && version.before(IndexVersions.V_8_0_0)) { - continue; // Nested field does not exist in the 7x line + if (indexMode == IndexMode.TIME_SERIES) { + settingsBuilder.put(IndexMetadata.INDEX_ROUTING_PATH.getKey(), "foo"); } - assertTrue("Expected " + builtIn + " to be a metadata field for version " + version, mapperService.isMetadataField(builtIn)); + + return createMapperService(settingsBuilder.build(), mapping(b -> {})); + }; + + Consumer assertMapperService = (mapperService) -> { + assertFalse(mapperService.isMetadataField(randomAlphaOfLengthBetween(10, 15))); + + for (String builtIn : IndicesModule.getBuiltInMetadataFields()) { + if (NestedPathFieldMapper.NAME.equals(builtIn) && version.before(IndexVersions.V_8_0_0)) { + continue; // Nested field does not exist in the 7x line + } + boolean isTimeSeriesField = builtIn.equals("_tsid") || builtIn.equals("_ts_routing_hash"); + boolean isTimeSeriesMode = mapperService.getIndexSettings().getMode().equals(IndexMode.TIME_SERIES); + + if (isTimeSeriesField && isTimeSeriesMode == false) { + assertFalse( + "Expected " + + builtIn + + " to not be a metadata field for version " + + version + + " and index mode " + + mapperService.getIndexSettings().getMode(), + mapperService.isMetadataField(builtIn) + ); + } else { + assertTrue( + "Expected " + + builtIn + + " to be a metadata field for version " + + version + + " and index mode " + + mapperService.getIndexSettings().getMode(), + mapperService.isMetadataField(builtIn) + ); + } + } + }; + + for (IndexMode indexMode : IndexMode.values()) { + MapperService mapperService = initMapperService.apply(indexMode); + assertMapperService.accept(mapperService); } } diff --git a/server/src/test/java/org/elasticsearch/index/shard/ShardGetServiceTests.java b/server/src/test/java/org/elasticsearch/index/shard/ShardGetServiceTests.java index 532e30804947..feb44261ce3e 100644 --- a/server/src/test/java/org/elasticsearch/index/shard/ShardGetServiceTests.java +++ b/server/src/test/java/org/elasticsearch/index/shard/ShardGetServiceTests.java @@ -34,6 +34,10 @@ import static org.hamcrest.Matchers.equalTo; public class ShardGetServiceTests extends IndexShardTestCase { + private GetResult getForUpdate(IndexShard indexShard, String id, long ifSeqNo, long ifPrimaryTerm) throws IOException { + return indexShard.getService().getForUpdate(id, ifSeqNo, ifPrimaryTerm, new String[] { RoutingFieldMapper.NAME }); + } + public void testGetForUpdate() throws IOException { Settings settings = indexSettings(IndexVersion.current(), 1, 1).build(); IndexMetadata metadata = IndexMetadata.builder("test").putMapping(""" @@ -44,7 +48,7 @@ public class ShardGetServiceTests extends IndexShardTestCase { long translogInMemorySegmentCountExpected = 0; Engine.IndexResult test = indexDoc(primary, "test", "0", "{\"foo\" : \"bar\"}"); assertTrue(primary.getEngine().refreshNeeded()); - GetResult testGet = primary.getService().getForUpdate("0", UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM); + GetResult testGet = getForUpdate(primary, "0", UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM); assertFalse(testGet.getFields().containsKey(RoutingFieldMapper.NAME)); assertEquals(testGet.sourceRef().utf8ToString(), "{\"foo\" : \"bar\"}"); assertEquals(translogInMemorySegmentCountExpected, translogInMemorySegmentCount.getAsLong()); @@ -54,7 +58,7 @@ public class ShardGetServiceTests extends IndexShardTestCase { Engine.IndexResult test1 = indexDoc(primary, "1", "{\"foo\" : \"baz\"}", XContentType.JSON, "foobar"); assertTrue(primary.getEngine().refreshNeeded()); - GetResult testGet1 = primary.getService().getForUpdate("1", UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM); + GetResult testGet1 = getForUpdate(primary, "1", UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM); assertEquals(testGet1.sourceRef().utf8ToString(), "{\"foo\" : \"baz\"}"); assertTrue(testGet1.getFields().containsKey(RoutingFieldMapper.NAME)); assertEquals("foobar", testGet1.getFields().get(RoutingFieldMapper.NAME).getValue()); @@ -70,19 +74,19 @@ public class ShardGetServiceTests extends IndexShardTestCase { // now again from the reader Engine.IndexResult test2 = indexDoc(primary, "1", "{\"foo\" : \"baz\"}", XContentType.JSON, "foobar"); assertTrue(primary.getEngine().refreshNeeded()); - testGet1 = primary.getService().getForUpdate("1", UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM); + testGet1 = getForUpdate(primary, "1", UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM); assertEquals(testGet1.sourceRef().utf8ToString(), "{\"foo\" : \"baz\"}"); assertTrue(testGet1.getFields().containsKey(RoutingFieldMapper.NAME)); assertEquals("foobar", testGet1.getFields().get(RoutingFieldMapper.NAME).getValue()); assertEquals(translogInMemorySegmentCountExpected, translogInMemorySegmentCount.getAsLong()); final long primaryTerm = primary.getOperationPrimaryTerm(); - testGet1 = primary.getService().getForUpdate("1", test2.getSeqNo(), primaryTerm); + testGet1 = getForUpdate(primary, "1", test2.getSeqNo(), primaryTerm); assertEquals(testGet1.sourceRef().utf8ToString(), "{\"foo\" : \"baz\"}"); assertEquals(translogInMemorySegmentCountExpected, translogInMemorySegmentCount.getAsLong()); - expectThrows(VersionConflictEngineException.class, () -> primary.getService().getForUpdate("1", test2.getSeqNo() + 1, primaryTerm)); - expectThrows(VersionConflictEngineException.class, () -> primary.getService().getForUpdate("1", test2.getSeqNo(), primaryTerm + 1)); + expectThrows(VersionConflictEngineException.class, () -> getForUpdate(primary, "1", test2.getSeqNo() + 1, primaryTerm)); + expectThrows(VersionConflictEngineException.class, () -> getForUpdate(primary, "1", test2.getSeqNo(), primaryTerm + 1)); closeShards(primary); } @@ -183,7 +187,7 @@ public class ShardGetServiceTests extends IndexShardTestCase { Engine.IndexResult res = indexDoc(primary, "test", "0", docToIndex); assertTrue(res.isCreated()); assertTrue(primary.getEngine().refreshNeeded()); - GetResult testGet = primary.getService().getForUpdate("0", UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM); + GetResult testGet = getForUpdate(primary, "0", UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM); assertFalse(testGet.getFields().containsKey(RoutingFieldMapper.NAME)); assertFalse(testGet.getFields().containsKey("foo")); assertFalse(testGet.getFields().containsKey("bar")); @@ -194,7 +198,7 @@ public class ShardGetServiceTests extends IndexShardTestCase { indexDoc(primary, "1", docToIndex, XContentType.JSON, "foobar"); assertTrue(primary.getEngine().refreshNeeded()); - GetResult testGet1 = primary.getService().getForUpdate("1", UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM); + GetResult testGet1 = getForUpdate(primary, "1", UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM); assertEquals(testGet1.sourceRef() == null ? "" : testGet1.sourceRef().utf8ToString(), expectedResult); assertTrue(testGet1.getFields().containsKey(RoutingFieldMapper.NAME)); assertFalse(testGet.getFields().containsKey("foo")); @@ -252,7 +256,7 @@ public class ShardGetServiceTests extends IndexShardTestCase { Engine.IndexResult indexResult = indexDoc(shard, "some_type", "0", "{\"foo\" : \"bar\"}"); assertTrue(indexResult.isCreated()); - GetResult getResult = shard.getService().getForUpdate("0", UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM); + GetResult getResult = getForUpdate(shard, "0", UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM); assertTrue(getResult.isExists()); closeShards(shard); diff --git a/server/src/test/java/org/elasticsearch/indices/cluster/ClusterStateChanges.java b/server/src/test/java/org/elasticsearch/indices/cluster/ClusterStateChanges.java index bdba69899b3e..347ab1d17e43 100644 --- a/server/src/test/java/org/elasticsearch/indices/cluster/ClusterStateChanges.java +++ b/server/src/test/java/org/elasticsearch/indices/cluster/ClusterStateChanges.java @@ -138,7 +138,6 @@ import static org.mockito.Mockito.when; public class ClusterStateChanges { private static final Settings SETTINGS = Settings.builder().put(PATH_HOME_SETTING.getKey(), "dummy").build(); - private final TransportService transportService; private final AllocationService allocationService; private final ClusterService clusterService; private final FeatureService featureService; @@ -226,7 +225,7 @@ public class ClusterStateChanges { // services featureService = new FeatureService(List.of()); - transportService = new TransportService( + TransportService transportService = new TransportService( SETTINGS, transport, threadPool, diff --git a/server/src/test/java/org/elasticsearch/plugins/PluginsServiceTests.java b/server/src/test/java/org/elasticsearch/plugins/PluginsServiceTests.java index 57158df344a3..ef12e767c1e2 100644 --- a/server/src/test/java/org/elasticsearch/plugins/PluginsServiceTests.java +++ b/server/src/test/java/org/elasticsearch/plugins/PluginsServiceTests.java @@ -18,6 +18,7 @@ import org.elasticsearch.core.Strings; import org.elasticsearch.env.Environment; import org.elasticsearch.env.TestEnvironment; import org.elasticsearch.index.IndexModule; +import org.elasticsearch.jdk.RuntimeVersionFeature; import org.elasticsearch.plugin.analysis.CharFilterFactory; import org.elasticsearch.plugins.scanners.PluginInfo; import org.elasticsearch.plugins.spi.BarPlugin; @@ -873,6 +874,7 @@ public class PluginsServiceTests extends ESTestCase { } public void testCanCreateAClassLoader() { + assumeTrue("security manager must be available", RuntimeVersionFeature.isSecurityManagerAvailable()); assertEquals( "access denied (\"java.lang.RuntimePermission\" \"createClassLoader\")", expectThrows(AccessControlException.class, () -> new Loader(this.getClass().getClassLoader())).getMessage() diff --git a/server/src/test/java/org/elasticsearch/snapshots/SnapshotResiliencyTests.java b/server/src/test/java/org/elasticsearch/snapshots/SnapshotResiliencyTests.java index 28afc66fd5b1..6c10976fc4b0 100644 --- a/server/src/test/java/org/elasticsearch/snapshots/SnapshotResiliencyTests.java +++ b/server/src/test/java/org/elasticsearch/snapshots/SnapshotResiliencyTests.java @@ -2244,7 +2244,6 @@ public class SnapshotResiliencyTests extends ESTestCase { .clusterService(clusterService) .projectResolver(DefaultProjectResolver.INSTANCE) .client(client) - .featureService(new FeatureService(List.of())) .metaStateService(new MetaStateService(nodeEnv, namedXContentRegistry)) .mapperMetrics(MapperMetrics.NOOP) .build(); diff --git a/server/src/test/java/org/elasticsearch/transport/InboundHandlerTests.java b/server/src/test/java/org/elasticsearch/transport/InboundHandlerTests.java index 7f5c4fbb1c4d..3ec248e0d8d9 100644 --- a/server/src/test/java/org/elasticsearch/transport/InboundHandlerTests.java +++ b/server/src/test/java/org/elasticsearch/transport/InboundHandlerTests.java @@ -291,8 +291,11 @@ public class InboundHandlerTests extends ESTestCase { BytesStreamOutput byteData = new BytesStreamOutput(); TaskId.EMPTY_TASK_ID.writeTo(byteData); // simulate bytes of a transport handshake: vInt transport version then release version string - TransportVersion.writeVersion(remoteVersion, byteData); - byteData.writeString(randomIdentifier()); + try (var payloadByteData = new BytesStreamOutput()) { + TransportVersion.writeVersion(remoteVersion, payloadByteData); + payloadByteData.writeString(randomIdentifier()); + byteData.writeBytesReference(payloadByteData.bytes()); + } final InboundMessage requestMessage = new InboundMessage( requestHeader, ReleasableBytesReference.wrap(byteData.bytes()), diff --git a/server/src/test/java/org/elasticsearch/transport/TransportHandshakerTests.java b/server/src/test/java/org/elasticsearch/transport/TransportHandshakerTests.java index 379ee0fecaff..398c5d1df778 100644 --- a/server/src/test/java/org/elasticsearch/transport/TransportHandshakerTests.java +++ b/server/src/test/java/org/elasticsearch/transport/TransportHandshakerTests.java @@ -18,6 +18,7 @@ import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNodeUtils; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.core.FixForMultiProject; import org.elasticsearch.core.TimeValue; import org.elasticsearch.core.UpdateForV10; import org.elasticsearch.tasks.TaskId; @@ -234,7 +235,9 @@ public class TransportHandshakerTests extends ESTestCase { TaskId.EMPTY_TASK_ID.writeTo(futureHandshake); final var extraDataSize = between(0, 1024); try (BytesStreamOutput internalMessage = new BytesStreamOutput()) { - TransportVersion.writeVersion(TransportVersionUtils.getNextVersion(TransportVersion.current(), true), internalMessage); + @FixForMultiProject(description = "update to between(0, 100) when multi-projects get a real transport version") + final var futureTransportVersionId = TransportVersion.current().id() + between(0, 1); + internalMessage.writeVInt(futureTransportVersionId); internalMessage.writeString(buildVersion); lengthCheckingHandshake.writeBytesReference(internalMessage.bytes()); internalMessage.write(new byte[extraDataSize]); diff --git a/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/HeapAttackIT.java b/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/HeapAttackIT.java index 79e28d955c6f..70f1ba529ec5 100644 --- a/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/HeapAttackIT.java +++ b/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/HeapAttackIT.java @@ -684,6 +684,7 @@ public class HeapAttackIT extends ESRestTestCase { return responseAsMap(query(query.toString(), null)); } finally { deleteIndex("sensor_data"); + deleteIndex("sensor_lookup"); } } diff --git a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoIP2-City.tgz b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoIP2-City.tgz index 76dd40000f13..708b94759e11 100644 Binary files a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoIP2-City.tgz and b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoIP2-City.tgz differ diff --git a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-ASN.mmdb b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-ASN.mmdb new file mode 100644 index 000000000000..af37b8ae278f Binary files /dev/null and b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-ASN.mmdb differ diff --git a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-ASN.tgz b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-ASN.tgz index 4e92ad982227..f47f34c74844 100644 Binary files a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-ASN.tgz and b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-ASN.tgz differ diff --git a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-City.mmdb b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-City.mmdb index 0809201619b5..67dcd4a8e5a1 100644 Binary files a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-City.mmdb and b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-City.mmdb differ diff --git a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-City.tgz b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-City.tgz index a86f548d6e33..44e0135bbfed 100644 Binary files a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-City.tgz and b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-City.tgz differ diff --git a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-Country.mmdb b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-Country.mmdb index aa81cbe8a2f0..8b1436b0c387 100644 Binary files a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-Country.mmdb and b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-Country.mmdb differ diff --git a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-Country.tgz b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-Country.tgz index 2d000ce65ef2..cf4fe0721b59 100644 Binary files a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-Country.tgz and b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/GeoLite2-Country.tgz differ diff --git a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/MyCustomGeoLite2-City.mmdb b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/MyCustomGeoLite2-City.mmdb index 0809201619b5..67dcd4a8e5a1 100644 Binary files a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/MyCustomGeoLite2-City.mmdb and b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/MyCustomGeoLite2-City.mmdb differ diff --git a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/MyCustomGeoLite2-City.tgz b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/MyCustomGeoLite2-City.tgz index ffe71bc1d23c..64db9c0a17e7 100644 Binary files a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/MyCustomGeoLite2-City.tgz and b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/MyCustomGeoLite2-City.tgz differ diff --git a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/data.json b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/data.json index 3ce4ba88dae0..b58b6f0e29e4 100644 --- a/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/data.json +++ b/test/fixtures/geoip-fixture/src/main/resources/geoip-fixture/data.json @@ -1,24 +1,24 @@ [ { - "md5_hash": "da5bb1c00c74e3f5a34ca1ec0022c550", + "md5_hash": "ec117f3c605b4998365e45fb2c382396", "name": "GeoLite2-City.tgz", "url": "db/GeoLite2-City.tgz", "provider": "maxmind" }, { - "md5_hash": "61c38f0fcec4a7b0b359201f124004df", + "md5_hash": "60a8f72665e59fe34420a148f97d4e2c", "name": "GeoLite2-ASN.tgz", "url": "db/GeoLite2-ASN.tgz", "provider": "maxmind" }, { - "md5_hash": "8f3229d6158f85adef296f8781f7ab49", + "md5_hash": "2363fb6c277679b242b320282b21bf04", "name": "GeoLite2-Country.tgz", "url": "db/GeoLite2-Country.tgz", "provider": "maxmind" }, { - "md5_hash": "77dcf272548942520d1b549957065a9f", + "md5_hash": "102662f11359a3074dd756ab474495e8", "name": "MyCustomGeoLite2-City.tgz", "url": "db/MyCustomGeoLite2-City.tgz", "provider": "maxmind" diff --git a/test/fixtures/geoip-fixture/src/main/resources/ipinfo-fixture/ip_asn_sample.mmdb b/test/fixtures/geoip-fixture/src/main/resources/ipinfo-fixture/ip_asn_sample.mmdb index 3e1fc49ba48a..fb52368827f6 100644 Binary files a/test/fixtures/geoip-fixture/src/main/resources/ipinfo-fixture/ip_asn_sample.mmdb and b/test/fixtures/geoip-fixture/src/main/resources/ipinfo-fixture/ip_asn_sample.mmdb differ diff --git a/test/framework/build.gradle b/test/framework/build.gradle index 3a2f4037f702..a5bff2d0166c 100644 --- a/test/framework/build.gradle +++ b/test/framework/build.gradle @@ -25,9 +25,9 @@ dependencies { api "commons-codec:commons-codec:${versions.commonscodec}" // mockito - api 'org.mockito:mockito-core:5.11.0' - api 'org.mockito:mockito-subclass:5.11.0' - api 'net.bytebuddy:byte-buddy:1.14.12' + api 'org.mockito:mockito-core:5.15.2' + api 'org.mockito:mockito-subclass:5.15.2' + api 'net.bytebuddy:byte-buddy:1.15.11' api 'org.objenesis:objenesis:3.3' api "org.elasticsearch:mocksocket:${versions.mocksocket}" @@ -65,6 +65,7 @@ tasks.named("thirdPartyAudit").configure { 'org.apache.log4j.Priority', // mockito + 'net.bytebuddy.agent.Installer', 'net.bytebuddy.agent.ByteBuddyAgent', 'org.mockito.internal.creation.bytebuddy.inject.MockMethodDispatcher', 'org.opentest4j.AssertionFailedError', diff --git a/test/framework/src/main/java/org/elasticsearch/cluster/coordination/AbstractCoordinatorTestCase.java b/test/framework/src/main/java/org/elasticsearch/cluster/coordination/AbstractCoordinatorTestCase.java index ef98815a7fff..3ad79a1fd079 100644 --- a/test/framework/src/main/java/org/elasticsearch/cluster/coordination/AbstractCoordinatorTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/cluster/coordination/AbstractCoordinatorTestCase.java @@ -971,9 +971,7 @@ public class AbstractCoordinatorTestCase extends ESTestCase { private AckedFakeThreadPoolMasterService masterService; private DisruptableClusterApplierService clusterApplierService; private ClusterService clusterService; - private FeatureService featureService; TransportService transportService; - private MasterHistoryService masterHistoryService; CoordinationDiagnosticsService coordinationDiagnosticsService; StableMasterHealthIndicatorService stableMasterHealthIndicatorService; private DisruptableMockTransport mockTransport; @@ -1134,8 +1132,7 @@ public class AbstractCoordinatorTestCase extends ESTestCase { threadPool ); clusterService = new ClusterService(settings, clusterSettings, masterService, clusterApplierService); - featureService = new FeatureService(List.of()); - masterHistoryService = new MasterHistoryService(transportService, threadPool, clusterService); + MasterHistoryService masterHistoryService = new MasterHistoryService(transportService, threadPool, clusterService); clusterService.setNodeConnectionsService( new NodeConnectionsService(clusterService.getSettings(), threadPool, transportService) ); @@ -1173,7 +1170,7 @@ public class AbstractCoordinatorTestCase extends ESTestCase { coordinationServices.getLeaderHeartbeatService(), coordinationServices.getPreVoteCollectorFactory(), CompatibilityVersionsUtils.staticCurrent(), - featureService + new FeatureService(List.of()) ); coordinationDiagnosticsService = new CoordinationDiagnosticsService( clusterService, diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/DocumentGenerator.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/DocumentGenerator.java index 9b2878ff7bfc..cfdec40bf919 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/DocumentGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/DocumentGenerator.java @@ -40,7 +40,10 @@ public class DocumentGenerator { public Map generate(Template template, Mapping mapping) { var documentMap = new TreeMap(); for (var predefinedField : specification.predefinedFields()) { - documentMap.put(predefinedField.name(), predefinedField.generator(specification.dataSource()).generateValue()); + documentMap.put( + predefinedField.name(), + predefinedField.generator(specification.dataSource()).generateValue(predefinedField.mapping()) + ); } generateFields(documentMap, template.template(), new Context("", mapping.lookup())); @@ -53,16 +56,18 @@ public class DocumentGenerator { Template.Entry templateEntry = entry.getValue(); if (templateEntry instanceof Template.Leaf leaf) { + var fieldMapping = context.mappingLookup().get(context.pathTo(fieldName)); + // Unsigned long does not play well when dynamically mapped because // it gets mapped as just long and large values fail to index. // Just skip it. - if (leaf.type() == FieldType.UNSIGNED_LONG && context.mappingLookup().get(context.pathTo(fieldName)) == null) { + if (leaf.type() == FieldType.UNSIGNED_LONG && fieldMapping == null) { continue; } var generator = leaf.type().generator(fieldName, specification.dataSource()); - document.put(fieldName, generator.generateValue()); + document.put(fieldName, generator.generateValue(fieldMapping)); } else if (templateEntry instanceof Template.Object object) { Optional arrayLength = objectArrayGenerator.lengthGenerator().get(); diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/FieldDataGenerator.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/FieldDataGenerator.java index 7e28a0a0fab2..1d84c5adc4ed 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/FieldDataGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/FieldDataGenerator.java @@ -9,11 +9,13 @@ package org.elasticsearch.logsdb.datageneration; +import java.util.Map; + /** * Entity responsible for generating a valid value for a field. * * Generator is expected to produce a different value on every call. */ public interface FieldDataGenerator { - Object generateValue(); + Object generateValue(Map fieldMapping); } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DataSourceHandler.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DataSourceHandler.java index 3aad8e55c326..beef9fb4dd79 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DataSourceHandler.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DataSourceHandler.java @@ -58,6 +58,10 @@ public interface DataSourceHandler { return null; } + default DataSourceResponse.MalformedWrapper handle(DataSourceRequest.MalformedWrapper request) { + return null; + } + default DataSourceResponse.ChildFieldGenerator handle(DataSourceRequest.ChildFieldGenerator request) { return null; } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DataSourceRequest.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DataSourceRequest.java index 999e9a8bf6c7..0e6e796ff6d5 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DataSourceRequest.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DataSourceRequest.java @@ -15,6 +15,7 @@ import org.elasticsearch.logsdb.datageneration.FieldType; import org.elasticsearch.logsdb.datageneration.fields.DynamicMapping; import java.util.Set; +import java.util.function.Supplier; public interface DataSourceRequest { TResponse accept(DataSourceHandler handler); @@ -91,6 +92,12 @@ public interface DataSourceRequest { } } + record MalformedWrapper(Supplier malformedValues) implements DataSourceRequest { + public DataSourceResponse.MalformedWrapper accept(DataSourceHandler handler) { + return handler.handle(this); + } + } + record ChildFieldGenerator(DataGeneratorSpecification specification) implements DataSourceRequest { diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DataSourceResponse.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DataSourceResponse.java index 3722e75d916d..e9f1adb98d24 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DataSourceResponse.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DataSourceResponse.java @@ -41,6 +41,8 @@ public interface DataSourceResponse { record RepeatingWrapper(Function, Supplier> wrapper) implements DataSourceResponse {} + record MalformedWrapper(Function, Supplier> wrapper) implements DataSourceResponse {} + interface ChildFieldGenerator extends DataSourceResponse { int generateChildFieldCount(); diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DefaultMappingParametersHandler.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DefaultMappingParametersHandler.java index 702145dd9a50..bf99ab71d014 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DefaultMappingParametersHandler.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DefaultMappingParametersHandler.java @@ -11,6 +11,7 @@ package org.elasticsearch.logsdb.datageneration.datasource; import org.elasticsearch.index.mapper.Mapper; import org.elasticsearch.index.mapper.ObjectMapper; +import org.elasticsearch.logsdb.datageneration.FieldType; import org.elasticsearch.test.ESTestCase; import java.util.HashMap; @@ -31,7 +32,7 @@ public class DefaultMappingParametersHandler implements DataSourceHandler { return new DataSourceResponse.LeafMappingParametersGenerator(switch (request.fieldType()) { case KEYWORD -> keywordMapping(request, map); - case LONG, INTEGER, SHORT, BYTE, DOUBLE, FLOAT, HALF_FLOAT, UNSIGNED_LONG -> plain(map); + case LONG, INTEGER, SHORT, BYTE, DOUBLE, FLOAT, HALF_FLOAT, UNSIGNED_LONG -> numberMapping(map, request.fieldType()); case SCALED_FLOAT -> scaledFloatMapping(map); case COUNTED_KEYWORD -> plain(Map.of("index", ESTestCase.randomBoolean())); }); @@ -41,6 +42,30 @@ public class DefaultMappingParametersHandler implements DataSourceHandler { return () -> injected; } + private Supplier> numberMapping(Map injected, FieldType fieldType) { + return () -> { + if (ESTestCase.randomBoolean()) { + injected.put("ignore_malformed", ESTestCase.randomBoolean()); + } + if (ESTestCase.randomDouble() <= 0.2) { + Number value = switch (fieldType) { + case LONG -> ESTestCase.randomLong(); + case UNSIGNED_LONG -> ESTestCase.randomNonNegativeLong(); + case INTEGER -> ESTestCase.randomInt(); + case SHORT -> ESTestCase.randomShort(); + case BYTE -> ESTestCase.randomByte(); + case DOUBLE -> ESTestCase.randomDouble(); + case FLOAT, HALF_FLOAT -> ESTestCase.randomFloat(); + default -> throw new IllegalStateException("Unexpected field type"); + }; + + injected.put("null_value", value); + } + + return injected; + }; + } + private Supplier> keywordMapping( DataSourceRequest.LeafMappingParametersGenerator request, Map injected @@ -75,6 +100,15 @@ public class DefaultMappingParametersHandler implements DataSourceHandler { private Supplier> scaledFloatMapping(Map injected) { return () -> { injected.put("scaling_factor", ESTestCase.randomFrom(10, 1000, 100000, 100.5)); + + if (ESTestCase.randomDouble() <= 0.2) { + injected.put("null_value", ESTestCase.randomFloat()); + } + + if (ESTestCase.randomBoolean()) { + injected.put("ignore_malformed", ESTestCase.randomBoolean()); + } + return injected; }; } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DefaultWrappersHandler.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DefaultWrappersHandler.java index 3640f98e25b5..ac686e020132 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DefaultWrappersHandler.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/datasource/DefaultWrappersHandler.java @@ -32,6 +32,11 @@ public class DefaultWrappersHandler implements DataSourceHandler { return new DataSourceResponse.RepeatingWrapper(repeatValues()); } + @Override + public DataSourceResponse.MalformedWrapper handle(DataSourceRequest.MalformedWrapper request) { + return new DataSourceResponse.MalformedWrapper(injectMalformed(request.malformedValues())); + } + private static Function, Supplier> injectNulls() { // Inject some nulls but majority of data should be non-null (as it likely is in reality). return (values) -> () -> ESTestCase.randomDouble() <= 0.05 ? null : values.get(); @@ -62,4 +67,8 @@ public class DefaultWrappersHandler implements DataSourceHandler { }; }; } + + private static Function, Supplier> injectMalformed(Supplier malformedValues) { + return (values) -> () -> ESTestCase.randomDouble() <= 0.1 ? malformedValues.get() : values.get(); + } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/ByteFieldDataGenerator.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/ByteFieldDataGenerator.java index 4ead8ffd0b71..809354c01e94 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/ByteFieldDataGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/ByteFieldDataGenerator.java @@ -13,21 +13,28 @@ import org.elasticsearch.logsdb.datageneration.FieldDataGenerator; import org.elasticsearch.logsdb.datageneration.datasource.DataSource; import org.elasticsearch.logsdb.datageneration.datasource.DataSourceRequest; +import java.util.Map; import java.util.function.Supplier; public class ByteFieldDataGenerator implements FieldDataGenerator { private final Supplier valueGenerator; + private final Supplier valueGeneratorWithMalformed; public ByteFieldDataGenerator(String fieldName, DataSource dataSource) { - var bytes = dataSource.get(new DataSourceRequest.ByteGenerator()); - var nulls = dataSource.get(new DataSourceRequest.NullWrapper()); - var arrays = dataSource.get(new DataSourceRequest.ArrayWrapper()); + var bytes = dataSource.get(new DataSourceRequest.ByteGenerator()).generator(); - this.valueGenerator = arrays.wrapper().compose(nulls.wrapper()).apply(() -> bytes.generator().get()); + this.valueGenerator = Wrappers.defaults(bytes::get, dataSource); + + var strings = dataSource.get(new DataSourceRequest.StringGenerator()).generator(); + this.valueGeneratorWithMalformed = Wrappers.defaultsWithMalformed(bytes::get, strings::get, dataSource); } @Override - public Object generateValue() { + public Object generateValue(Map fieldMapping) { + if (fieldMapping != null && (Boolean) fieldMapping.getOrDefault("ignore_malformed", false)) { + return valueGeneratorWithMalformed.get(); + } + return valueGenerator.get(); } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/CountedKeywordFieldDataGenerator.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/CountedKeywordFieldDataGenerator.java index f09ef2397bfc..64a40704a64c 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/CountedKeywordFieldDataGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/CountedKeywordFieldDataGenerator.java @@ -14,6 +14,7 @@ import org.elasticsearch.logsdb.datageneration.datasource.DataSource; import org.elasticsearch.logsdb.datageneration.datasource.DataSourceRequest; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.function.Supplier; @@ -31,7 +32,7 @@ public class CountedKeywordFieldDataGenerator implements FieldDataGenerator { } @Override - public Object generateValue() { + public Object generateValue(Map fieldMapping) { return valueGenerator.get(); } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/DoubleFieldDataGenerator.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/DoubleFieldDataGenerator.java index cf2c4f6abdbf..8cd72c93cb6d 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/DoubleFieldDataGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/DoubleFieldDataGenerator.java @@ -13,21 +13,28 @@ import org.elasticsearch.logsdb.datageneration.FieldDataGenerator; import org.elasticsearch.logsdb.datageneration.datasource.DataSource; import org.elasticsearch.logsdb.datageneration.datasource.DataSourceRequest; +import java.util.Map; import java.util.function.Supplier; public class DoubleFieldDataGenerator implements FieldDataGenerator { private final Supplier valueGenerator; + private final Supplier valueGeneratorWithMalformed; public DoubleFieldDataGenerator(String fieldName, DataSource dataSource) { - var doubles = dataSource.get(new DataSourceRequest.DoubleGenerator()); - var nulls = dataSource.get(new DataSourceRequest.NullWrapper()); - var arrays = dataSource.get(new DataSourceRequest.ArrayWrapper()); + var doubles = dataSource.get(new DataSourceRequest.DoubleGenerator()).generator(); - this.valueGenerator = arrays.wrapper().compose(nulls.wrapper()).apply(() -> doubles.generator().get()); + this.valueGenerator = Wrappers.defaults(doubles::get, dataSource); + + var strings = dataSource.get(new DataSourceRequest.StringGenerator()).generator(); + this.valueGeneratorWithMalformed = Wrappers.defaultsWithMalformed(doubles::get, strings::get, dataSource); } @Override - public Object generateValue() { + public Object generateValue(Map fieldMapping) { + if (fieldMapping != null && (Boolean) fieldMapping.getOrDefault("ignore_malformed", false)) { + return valueGeneratorWithMalformed.get(); + } + return valueGenerator.get(); } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/FloatFieldDataGenerator.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/FloatFieldDataGenerator.java index b59d5ceabb18..651c1e40e410 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/FloatFieldDataGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/FloatFieldDataGenerator.java @@ -13,21 +13,28 @@ import org.elasticsearch.logsdb.datageneration.FieldDataGenerator; import org.elasticsearch.logsdb.datageneration.datasource.DataSource; import org.elasticsearch.logsdb.datageneration.datasource.DataSourceRequest; +import java.util.Map; import java.util.function.Supplier; public class FloatFieldDataGenerator implements FieldDataGenerator { private final Supplier valueGenerator; + private final Supplier valueGeneratorWithMalformed; public FloatFieldDataGenerator(String fieldName, DataSource dataSource) { - var floats = dataSource.get(new DataSourceRequest.FloatGenerator()); - var nulls = dataSource.get(new DataSourceRequest.NullWrapper()); - var arrays = dataSource.get(new DataSourceRequest.ArrayWrapper()); + var floats = dataSource.get(new DataSourceRequest.FloatGenerator()).generator(); - this.valueGenerator = arrays.wrapper().compose(nulls.wrapper()).apply(() -> floats.generator().get()); + this.valueGenerator = Wrappers.defaults(floats::get, dataSource); + + var strings = dataSource.get(new DataSourceRequest.StringGenerator()).generator(); + this.valueGeneratorWithMalformed = Wrappers.defaultsWithMalformed(floats::get, strings::get, dataSource); } @Override - public Object generateValue() { + public Object generateValue(Map fieldMapping) { + if (fieldMapping != null && (Boolean) fieldMapping.getOrDefault("ignore_malformed", false)) { + return valueGeneratorWithMalformed.get(); + } + return valueGenerator.get(); } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/HalfFloatFieldDataGenerator.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/HalfFloatFieldDataGenerator.java index e2ed299f1a4d..35de92b09308 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/HalfFloatFieldDataGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/HalfFloatFieldDataGenerator.java @@ -13,21 +13,28 @@ import org.elasticsearch.logsdb.datageneration.FieldDataGenerator; import org.elasticsearch.logsdb.datageneration.datasource.DataSource; import org.elasticsearch.logsdb.datageneration.datasource.DataSourceRequest; +import java.util.Map; import java.util.function.Supplier; public class HalfFloatFieldDataGenerator implements FieldDataGenerator { private final Supplier valueGenerator; + private final Supplier valueGeneratorWithMalformed; public HalfFloatFieldDataGenerator(String fieldName, DataSource dataSource) { - var halfFloats = dataSource.get(new DataSourceRequest.HalfFloatGenerator()); - var nulls = dataSource.get(new DataSourceRequest.NullWrapper()); - var arrays = dataSource.get(new DataSourceRequest.ArrayWrapper()); + var halfFloats = dataSource.get(new DataSourceRequest.HalfFloatGenerator()).generator(); - this.valueGenerator = arrays.wrapper().compose(nulls.wrapper()).apply(() -> halfFloats.generator().get()); + this.valueGenerator = Wrappers.defaults(halfFloats::get, dataSource); + + var strings = dataSource.get(new DataSourceRequest.StringGenerator()).generator(); + this.valueGeneratorWithMalformed = Wrappers.defaultsWithMalformed(halfFloats::get, strings::get, dataSource); } @Override - public Object generateValue() { + public Object generateValue(Map fieldMapping) { + if (fieldMapping != null && (Boolean) fieldMapping.getOrDefault("ignore_malformed", false)) { + return valueGeneratorWithMalformed.get(); + } + return valueGenerator.get(); } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/IntegerFieldDataGenerator.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/IntegerFieldDataGenerator.java index f2fe8ed8362e..0d7d8194c400 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/IntegerFieldDataGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/IntegerFieldDataGenerator.java @@ -13,21 +13,28 @@ import org.elasticsearch.logsdb.datageneration.FieldDataGenerator; import org.elasticsearch.logsdb.datageneration.datasource.DataSource; import org.elasticsearch.logsdb.datageneration.datasource.DataSourceRequest; +import java.util.Map; import java.util.function.Supplier; public class IntegerFieldDataGenerator implements FieldDataGenerator { private final Supplier valueGenerator; + private final Supplier valueGeneratorWithMalformed; public IntegerFieldDataGenerator(String fieldName, DataSource dataSource) { - var ints = dataSource.get(new DataSourceRequest.IntegerGenerator()); - var nulls = dataSource.get(new DataSourceRequest.NullWrapper()); - var arrays = dataSource.get(new DataSourceRequest.ArrayWrapper()); + var ints = dataSource.get(new DataSourceRequest.IntegerGenerator()).generator(); - this.valueGenerator = arrays.wrapper().compose(nulls.wrapper()).apply(() -> ints.generator().get()); + this.valueGenerator = Wrappers.defaults(ints::get, dataSource); + + var strings = dataSource.get(new DataSourceRequest.StringGenerator()).generator(); + this.valueGeneratorWithMalformed = Wrappers.defaultsWithMalformed(ints::get, strings::get, dataSource); } @Override - public Object generateValue() { + public Object generateValue(Map fieldMapping) { + if (fieldMapping != null && (Boolean) fieldMapping.getOrDefault("ignore_malformed", false)) { + return valueGeneratorWithMalformed.get(); + } + return valueGenerator.get(); } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/KeywordFieldDataGenerator.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/KeywordFieldDataGenerator.java index 8dc4d8b8767c..4dbbc6b740dc 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/KeywordFieldDataGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/KeywordFieldDataGenerator.java @@ -13,6 +13,7 @@ import org.elasticsearch.logsdb.datageneration.FieldDataGenerator; import org.elasticsearch.logsdb.datageneration.datasource.DataSource; import org.elasticsearch.logsdb.datageneration.datasource.DataSourceRequest; +import java.util.Map; import java.util.function.Supplier; public class KeywordFieldDataGenerator implements FieldDataGenerator { @@ -27,7 +28,7 @@ public class KeywordFieldDataGenerator implements FieldDataGenerator { } @Override - public Object generateValue() { + public Object generateValue(Map fieldMapping) { return valueGenerator.get(); } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/LongFieldDataGenerator.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/LongFieldDataGenerator.java index f17610e501ed..bd22d58af16a 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/LongFieldDataGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/LongFieldDataGenerator.java @@ -13,21 +13,28 @@ import org.elasticsearch.logsdb.datageneration.FieldDataGenerator; import org.elasticsearch.logsdb.datageneration.datasource.DataSource; import org.elasticsearch.logsdb.datageneration.datasource.DataSourceRequest; +import java.util.Map; import java.util.function.Supplier; public class LongFieldDataGenerator implements FieldDataGenerator { private final Supplier valueGenerator; + private final Supplier valueGeneratorWithMalformed; public LongFieldDataGenerator(String fieldName, DataSource dataSource) { - var longs = dataSource.get(new DataSourceRequest.LongGenerator()); - var nulls = dataSource.get(new DataSourceRequest.NullWrapper()); - var arrays = dataSource.get(new DataSourceRequest.ArrayWrapper()); + var longs = dataSource.get(new DataSourceRequest.LongGenerator()).generator(); - this.valueGenerator = arrays.wrapper().compose(nulls.wrapper()).apply(() -> longs.generator().get()); + this.valueGenerator = Wrappers.defaults(longs::get, dataSource); + + var strings = dataSource.get(new DataSourceRequest.StringGenerator()).generator(); + this.valueGeneratorWithMalformed = Wrappers.defaultsWithMalformed(longs::get, strings::get, dataSource); } @Override - public Object generateValue() { + public Object generateValue(Map fieldMapping) { + if (fieldMapping != null && (Boolean) fieldMapping.getOrDefault("ignore_malformed", false)) { + return valueGeneratorWithMalformed.get(); + } + return valueGenerator.get(); } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/ScaledFloatFieldDataGenerator.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/ScaledFloatFieldDataGenerator.java index 008dd04179dc..117682e73946 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/ScaledFloatFieldDataGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/ScaledFloatFieldDataGenerator.java @@ -13,21 +13,28 @@ import org.elasticsearch.logsdb.datageneration.FieldDataGenerator; import org.elasticsearch.logsdb.datageneration.datasource.DataSource; import org.elasticsearch.logsdb.datageneration.datasource.DataSourceRequest; +import java.util.Map; import java.util.function.Supplier; public class ScaledFloatFieldDataGenerator implements FieldDataGenerator { private final Supplier valueGenerator; + private final Supplier valueGeneratorWithMalformed; public ScaledFloatFieldDataGenerator(String fieldName, DataSource dataSource) { - var doubles = dataSource.get(new DataSourceRequest.DoubleGenerator()); - var nulls = dataSource.get(new DataSourceRequest.NullWrapper()); - var arrays = dataSource.get(new DataSourceRequest.ArrayWrapper()); + var doubles = dataSource.get(new DataSourceRequest.DoubleGenerator()).generator(); - this.valueGenerator = arrays.wrapper().compose(nulls.wrapper()).apply(() -> doubles.generator().get()); + this.valueGenerator = Wrappers.defaults(doubles::get, dataSource); + + var strings = dataSource.get(new DataSourceRequest.StringGenerator()).generator(); + this.valueGeneratorWithMalformed = Wrappers.defaultsWithMalformed(doubles::get, strings::get, dataSource); } @Override - public Object generateValue() { + public Object generateValue(Map fieldMapping) { + if (fieldMapping != null && (Boolean) fieldMapping.getOrDefault("ignore_malformed", false)) { + return valueGeneratorWithMalformed.get(); + } + return valueGenerator.get(); } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/ShortFieldDataGenerator.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/ShortFieldDataGenerator.java index 85bff2c85e53..a7e50ffc6d0f 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/ShortFieldDataGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/ShortFieldDataGenerator.java @@ -13,21 +13,28 @@ import org.elasticsearch.logsdb.datageneration.FieldDataGenerator; import org.elasticsearch.logsdb.datageneration.datasource.DataSource; import org.elasticsearch.logsdb.datageneration.datasource.DataSourceRequest; +import java.util.Map; import java.util.function.Supplier; public class ShortFieldDataGenerator implements FieldDataGenerator { private final Supplier valueGenerator; + private final Supplier valueGeneratorWithMalformed; public ShortFieldDataGenerator(String fieldName, DataSource dataSource) { - var shorts = dataSource.get(new DataSourceRequest.ShortGenerator()); - var nulls = dataSource.get(new DataSourceRequest.NullWrapper()); - var arrays = dataSource.get(new DataSourceRequest.ArrayWrapper()); + var shorts = dataSource.get(new DataSourceRequest.ShortGenerator()).generator(); - this.valueGenerator = arrays.wrapper().compose(nulls.wrapper()).apply(() -> shorts.generator().get()); + this.valueGenerator = Wrappers.defaults(shorts::get, dataSource); + + var strings = dataSource.get(new DataSourceRequest.StringGenerator()).generator(); + this.valueGeneratorWithMalformed = Wrappers.defaultsWithMalformed(shorts::get, strings::get, dataSource); } @Override - public Object generateValue() { + public Object generateValue(Map fieldMapping) { + if (fieldMapping != null && (Boolean) fieldMapping.getOrDefault("ignore_malformed", false)) { + return valueGeneratorWithMalformed.get(); + } + return valueGenerator.get(); } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/UnsignedLongFieldDataGenerator.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/UnsignedLongFieldDataGenerator.java index 329f684bef70..18dd61f0c8ff 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/UnsignedLongFieldDataGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/UnsignedLongFieldDataGenerator.java @@ -13,21 +13,28 @@ import org.elasticsearch.logsdb.datageneration.FieldDataGenerator; import org.elasticsearch.logsdb.datageneration.datasource.DataSource; import org.elasticsearch.logsdb.datageneration.datasource.DataSourceRequest; +import java.util.Map; import java.util.function.Supplier; public class UnsignedLongFieldDataGenerator implements FieldDataGenerator { private final Supplier valueGenerator; + private final Supplier valueGeneratorWithMalformed; public UnsignedLongFieldDataGenerator(String fieldName, DataSource dataSource) { - var unsignedLongs = dataSource.get(new DataSourceRequest.UnsignedLongGenerator()); - var nulls = dataSource.get(new DataSourceRequest.NullWrapper()); - var arrays = dataSource.get(new DataSourceRequest.ArrayWrapper()); + var unsignedLongs = dataSource.get(new DataSourceRequest.UnsignedLongGenerator()).generator(); - this.valueGenerator = arrays.wrapper().compose(nulls.wrapper()).apply(() -> unsignedLongs.generator().get()); + this.valueGenerator = Wrappers.defaults(unsignedLongs::get, dataSource); + + var strings = dataSource.get(new DataSourceRequest.StringGenerator()).generator(); + this.valueGeneratorWithMalformed = Wrappers.defaultsWithMalformed(unsignedLongs::get, strings::get, dataSource); } @Override - public Object generateValue() { + public Object generateValue(Map fieldMapping) { + if (fieldMapping != null && (Boolean) fieldMapping.getOrDefault("ignore_malformed", false)) { + return valueGeneratorWithMalformed.get(); + } + return valueGenerator.get(); } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/Wrappers.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/Wrappers.java new file mode 100644 index 000000000000..74be106620d4 --- /dev/null +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/fields/leaf/Wrappers.java @@ -0,0 +1,40 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.logsdb.datageneration.fields.leaf; + +import org.elasticsearch.logsdb.datageneration.datasource.DataSource; +import org.elasticsearch.logsdb.datageneration.datasource.DataSourceRequest; + +import java.util.function.Supplier; + +public class Wrappers { + /** + * Applies default wrappers for raw values - adds nulls and wraps values in arrays. + * @return + */ + static Supplier defaults(Supplier rawValues, DataSource dataSource) { + var nulls = dataSource.get(new DataSourceRequest.NullWrapper()); + var arrays = dataSource.get(new DataSourceRequest.ArrayWrapper()); + + return arrays.wrapper().compose(nulls.wrapper()).apply(rawValues::get); + } + + /** + * Applies default wrappers for raw values and also adds malformed values. + * @return + */ + static Supplier defaultsWithMalformed(Supplier rawValues, Supplier malformedValues, DataSource dataSource) { + var nulls = dataSource.get(new DataSourceRequest.NullWrapper()); + var malformed = dataSource.get(new DataSourceRequest.MalformedWrapper(malformedValues)); + var arrays = dataSource.get(new DataSourceRequest.ArrayWrapper()); + + return arrays.wrapper().compose(nulls.wrapper()).compose(malformed.wrapper()).apply(rawValues::get); + } +} diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/matchers/source/DynamicFieldMatcher.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/matchers/source/DynamicFieldMatcher.java index 5bcf53cfa5c9..7957ed1eebe4 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/matchers/source/DynamicFieldMatcher.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/matchers/source/DynamicFieldMatcher.java @@ -10,6 +10,7 @@ package org.elasticsearch.logsdb.datageneration.matchers.source; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.logsdb.datageneration.matchers.ListEqualMatcher; import org.elasticsearch.logsdb.datageneration.matchers.MatchResult; import org.elasticsearch.xcontent.XContentBuilder; @@ -46,9 +47,12 @@ class DynamicFieldMatcher { * @return {#{@link MatchResult}} if field values need special treatment by this matcher. * If field values can be matched using generic mapper, returns {@link Optional#empty()}. */ - public Optional match(List actual, List expected) { + public MatchResult match(List actual, List expected) { if (expected == null) { - return Optional.empty(); + expected = List.of(); + } + if (actual == null) { + actual = List.of(); } // Floating point values are always mapped as float with dynamic mapping. @@ -59,7 +63,7 @@ class DynamicFieldMatcher { var normalizedActual = normalizeDoubles(actual); var normalizedExpected = normalizeDoubles(expected); - var matchResult = normalizedActual.equals(normalizedExpected) + return normalizedActual.equals(normalizedExpected) ? MatchResult.match() : MatchResult.noMatch( formatErrorMessage( @@ -71,10 +75,9 @@ class DynamicFieldMatcher { + prettyPrintCollections(normalizedActual, normalizedExpected) ) ); - return Optional.of(matchResult); } - return Optional.empty(); + return matchWithGenericMatcher(actual, expected); } private static Set normalizeDoubles(List values) { @@ -85,4 +88,18 @@ class DynamicFieldMatcher { Function toFloat = (o) -> o instanceof Number n ? n.floatValue() : Float.parseFloat((String) o); return values.stream().filter(Objects::nonNull).map(toFloat).collect(Collectors.toSet()); } + + private MatchResult matchWithGenericMatcher(List actualValues, List expectedValues) { + var genericListMatcher = new ListEqualMatcher( + actualMappings, + actualSettings, + expectedMappings, + expectedSettings, + SourceTransforms.normalizeValues(actualValues), + SourceTransforms.normalizeValues(expectedValues), + true + ); + + return genericListMatcher.match(); + } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/matchers/source/FieldSpecificMatcher.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/matchers/source/FieldSpecificMatcher.java index df26b652a806..e2acea4ad91d 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/matchers/source/FieldSpecificMatcher.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/matchers/source/FieldSpecificMatcher.java @@ -15,12 +15,11 @@ import org.elasticsearch.logsdb.datageneration.matchers.MatchResult; import org.elasticsearch.xcontent.XContentBuilder; import java.math.BigInteger; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.function.Function; +import java.util.TreeMap; import java.util.stream.Collectors; import static org.elasticsearch.logsdb.datageneration.matchers.Messages.formatErrorMessage; @@ -29,13 +28,13 @@ import static org.elasticsearch.logsdb.datageneration.matchers.Messages.prettyPr interface FieldSpecificMatcher { MatchResult match(List actual, List expected, Map actualMapping, Map expectedMapping); - class HalfFloatMatcher implements FieldSpecificMatcher { + class CountedKeywordMatcher implements FieldSpecificMatcher { private final XContentBuilder actualMappings; private final Settings.Builder actualSettings; private final XContentBuilder expectedMappings; private final Settings.Builder expectedSettings; - HalfFloatMatcher( + CountedKeywordMatcher( XContentBuilder actualMappings, Settings.Builder actualSettings, XContentBuilder expectedMappings, @@ -54,35 +53,83 @@ interface FieldSpecificMatcher { Map actualMapping, Map expectedMapping ) { - var actualHalfFloatBytes = normalize(actual); - var expectedHalfFloatBytes = normalize(expected); + var actualNormalized = normalize(actual); + var expectedNormalized = normalize(expected); - return actualHalfFloatBytes.equals(expectedHalfFloatBytes) - ? MatchResult.match() - : MatchResult.noMatch( + Map counts = new TreeMap<>(); + for (String value : actualNormalized) { + counts.put(value, counts.getOrDefault(value, 0) + 1); + } + for (String value : expectedNormalized) { + int newCount = counts.getOrDefault(value, 0) - 1; + if (newCount == 0) { + counts.remove(value); + } else { + counts.put(value, newCount); + } + } + + if (counts.isEmpty() == false) { + var extraValuesMessage = new StringBuilder("extra values: "); + for (var entry : counts.entrySet()) { + extraValuesMessage.append('\n').append(entry.getKey()).append(": ").append(entry.getValue()); + } + + return MatchResult.noMatch( formatErrorMessage( actualMappings, actualSettings, expectedMappings, expectedSettings, - "Values of type [half_float] don't match after normalization, normalized " - + prettyPrintCollections(actualHalfFloatBytes, expectedHalfFloatBytes) + "Values of type [counted_keyword] don't match, " + + extraValuesMessage + + ".\n" + + prettyPrintCollections(actualNormalized, expectedNormalized) ) ); - } - - private static Set normalize(List values) { - if (values == null) { - return Set.of(); } - Function toFloat = (o) -> o instanceof Number n ? n.floatValue() : Float.parseFloat((String) o); - return values.stream() - .filter(Objects::nonNull) - .map(toFloat) - // Based on logic in NumberFieldMapper - .map(HalfFloatPoint::halfFloatToSortableShort) - .collect(Collectors.toSet()); + return MatchResult.match(); + } + + private static List normalize(List values) { + return values.stream().filter(Objects::nonNull).map(it -> (String) it).toList(); + } + } + + class HalfFloatMatcher extends GenericMappingAwareMatcher { + HalfFloatMatcher( + XContentBuilder actualMappings, + Settings.Builder actualSettings, + XContentBuilder expectedMappings, + Settings.Builder expectedSettings + ) { + super("half_float", actualMappings, actualSettings, expectedMappings, expectedSettings); + } + + @Override + Object convert(Object value, Object nullValue) { + var nullValueShort = nullValue != null ? HalfFloatPoint.halfFloatToSortableShort(((Number) nullValue).floatValue()) : null; + + return switch (value) { + case null -> nullValueShort; + case Number n -> HalfFloatPoint.halfFloatToSortableShort(n.floatValue()); + case String s -> { + // Special case for number coercion from strings + if (s.isEmpty()) { + yield nullValueShort; + } + + try { + var f = Float.parseFloat(s); + yield HalfFloatPoint.halfFloatToSortableShort(f); + } catch (NumberFormatException e) { + // Malformed, leave it be and match as is + yield s; + } + } + default -> value; + }; } } @@ -111,23 +158,23 @@ interface FieldSpecificMatcher { Map actualMapping, Map expectedMapping ) { - var scalingFactor = actualMapping.get("scaling_factor"); - var expectedScalingFactor = expectedMapping.get("scaling_factor"); - if (Objects.equals(scalingFactor, expectedScalingFactor) == false) { - throw new IllegalStateException("Scaling factor for scaled_float field does not match between actual and expected mapping"); - } + var scalingFactor = FieldSpecificMatcher.getMappingParameter("scaling_factor", actualMapping, expectedMapping); assert scalingFactor instanceof Number; double scalingFactorDouble = ((Number) scalingFactor).doubleValue(); + + var nullValue = (Number) FieldSpecificMatcher.getNullValue(actualMapping, expectedMapping); + // It is possible that we receive a mix of reduced precision values and original values. // F.e. in case of `synthetic_source_keep: "arrays"` in nested objects only arrays are preserved as is // and therefore any singleton values have reduced precision. // Therefore, we need to match either an exact value or a normalized value. - var expectedNormalized = normalizeValues(expected); - var actualNormalized = normalizeValues(actual); - for (var expectedValue : expectedNormalized) { - if (actualNormalized.contains(expectedValue) == false - && actualNormalized.contains(encodeDecodeWithPrecisionLoss(expectedValue, scalingFactorDouble)) == false) { + var expectedNumbers = numbers(expected, nullValue); + var actualNumbers = numbers(actual, nullValue); + + for (var expectedValue : expectedNumbers) { + if (actualNumbers.contains(expectedValue) == false + && actualNumbers.contains(encodeDecodeWithPrecisionLoss(expectedValue, scalingFactorDouble)) == false) { return MatchResult.noMatch( formatErrorMessage( actualMappings, @@ -135,7 +182,24 @@ interface FieldSpecificMatcher { expectedMappings, expectedSettings, "Values of type [scaled_float] don't match after normalization, normalized " - + prettyPrintCollections(actualNormalized, expectedNormalized) + + prettyPrintCollections(actualNumbers, expectedNumbers) + ) + ); + } + } + + var expectedNotNumbers = notNumbers(expected); + var actualNotNumbers = notNumbers(actual); + for (var expectedValue : expectedNotNumbers) { + if (actualNotNumbers.contains(expectedValue) == false) { + return MatchResult.noMatch( + formatErrorMessage( + actualMappings, + actualSettings, + expectedMappings, + expectedSettings, + "Malformed values of [scaled_float] field don't match, values:" + + prettyPrintCollections(actualNotNumbers, expectedNotNumbers) ) ); } @@ -144,18 +208,49 @@ interface FieldSpecificMatcher { return MatchResult.match(); } - private Double encodeDecodeWithPrecisionLoss(double value, double scalingFactor) { - // Based on logic in ScaledFloatFieldMapper - var encoded = Math.round(value * scalingFactor); - return encoded / scalingFactor; - } - - private static Set normalizeValues(List values) { + private Set numbers(List values, Number nullValue) { if (values == null) { return Set.of(); } - return values.stream().filter(Objects::nonNull).map(ScaledFloatMatcher::toDouble).collect(Collectors.toSet()); + return values.stream() + .map(v -> convertNumber(v, nullValue)) + .filter(Objects::nonNull) + .map(ScaledFloatMatcher::toDouble) + .collect(Collectors.toSet()); + } + + private static Object convertNumber(Object value, Number nullValue) { + if (value == null) { + return nullValue; + } + // Special case for number coercion from strings + if (value instanceof String s && s.isEmpty()) { + return nullValue; + } + if (value instanceof Number n) { + return n; + } + + return null; + } + + private Set notNumbers(List values) { + if (values == null) { + return Set.of(); + } + + return values.stream() + .filter(Objects::nonNull) + .filter(v -> v instanceof Number == false) + .filter(v -> v instanceof String == false || ((String) v).isEmpty() == false) + .collect(Collectors.toSet()); + } + + private Double encodeDecodeWithPrecisionLoss(double value, double scalingFactor) { + // Based on logic in ScaledFloatFieldMapper + var encoded = Math.round(value * scalingFactor); + return encoded / scalingFactor; } private static double toDouble(Object value) { @@ -163,144 +258,118 @@ interface FieldSpecificMatcher { } } - class UnsignedLongMatcher implements FieldSpecificMatcher { - private final XContentBuilder actualMappings; - private final Settings.Builder actualSettings; - private final XContentBuilder expectedMappings; - private final Settings.Builder expectedSettings; - + class UnsignedLongMatcher extends GenericMappingAwareMatcher { UnsignedLongMatcher( XContentBuilder actualMappings, Settings.Builder actualSettings, XContentBuilder expectedMappings, Settings.Builder expectedSettings ) { - this.actualMappings = actualMappings; - this.actualSettings = actualSettings; - this.expectedMappings = expectedMappings; - this.expectedSettings = expectedSettings; + super("unsigned_long", actualMappings, actualSettings, expectedMappings, expectedSettings); } @Override - public MatchResult match( - List actual, - List expected, - Map actualMapping, - Map expectedMapping - ) { - var expectedNormalized = normalize(expected); - var actualNormalized = normalize(actual); + Object convert(Object value, Object nullValue) { + var nullValueBigInt = nullValue != null ? BigInteger.valueOf(((Number) nullValue).longValue()) : null; - return actualNormalized.equals(expectedNormalized) - ? MatchResult.match() - : MatchResult.noMatch( - formatErrorMessage( - actualMappings, - actualSettings, - expectedMappings, - expectedSettings, - "Values of type [unsigned_long] don't match after normalization, normalized " - + prettyPrintCollections(actualNormalized, expectedNormalized) - ) - ); - } + return switch (value) { + case null -> nullValueBigInt; + case String s -> { + // Special case for number coercion from strings + if (s.isEmpty()) { + yield nullValueBigInt; + } - private static Set normalize(List values) { - if (values == null) { - return Set.of(); - } - - return values.stream().filter(Objects::nonNull).map(UnsignedLongMatcher::toBigInteger).collect(Collectors.toSet()); - } - - private static BigInteger toBigInteger(Object value) { - if (value instanceof String s) { - return new BigInteger(s, 10); - } - if (value instanceof Long l) { - return BigInteger.valueOf(l); - } - - return (BigInteger) value; - } - } - - class CountedKeywordMatcher implements FieldSpecificMatcher { - private final XContentBuilder actualMappings; - private final Settings.Builder actualSettings; - private final XContentBuilder expectedMappings; - private final Settings.Builder expectedSettings; - - CountedKeywordMatcher( - XContentBuilder actualMappings, - Settings.Builder actualSettings, - XContentBuilder expectedMappings, - Settings.Builder expectedSettings - ) { - this.actualMappings = actualMappings; - this.actualSettings = actualSettings; - this.expectedMappings = expectedMappings; - this.expectedSettings = expectedSettings; - } - - private static List normalize(List values) { - return values.stream().filter(Objects::nonNull).map(it -> (String) it).toList(); - } - - private static boolean matchCountsEqualExact(List actualNormalized, List expectedNormalized) { - HashMap counts = new HashMap<>(); - for (String value : actualNormalized) { - counts.put(value, counts.getOrDefault(value, 0) + 1); - } - for (String value : expectedNormalized) { - int newCount = counts.getOrDefault(value, 0) - 1; - if (newCount == 0) { - counts.remove(value); - } else { - counts.put(value, newCount); + yield s; } - } + case Long l -> BigInteger.valueOf(l); + default -> value; + }; - return counts.isEmpty(); - } - - @Override - public MatchResult match( - List actual, - List expected, - Map actualMapping, - Map expectedMapping - ) { - var actualNormalized = normalize(actual); - var expectedNormalized = normalize(expected); - - return matchCountsEqualExact(actualNormalized, expectedNormalized) - ? MatchResult.match() - : MatchResult.noMatch( - formatErrorMessage( - actualMappings, - actualSettings, - expectedMappings, - expectedSettings, - "Values of type [counted_keyword] don't match after normalization, normalized" - + prettyPrintCollections(actualNormalized, expectedNormalized) - ) - ); } } - class KeywordMatcher implements FieldSpecificMatcher { - private final XContentBuilder actualMappings; - private final Settings.Builder actualSettings; - private final XContentBuilder expectedMappings; - private final Settings.Builder expectedSettings; - + class KeywordMatcher extends GenericMappingAwareMatcher { KeywordMatcher( XContentBuilder actualMappings, Settings.Builder actualSettings, XContentBuilder expectedMappings, Settings.Builder expectedSettings ) { + super("keyword", actualMappings, actualSettings, expectedMappings, expectedSettings); + } + + @Override + Object convert(Object value, Object nullValue) { + if (value == null) { + return nullValue; + } + + return value; + } + } + + class NumberMatcher extends GenericMappingAwareMatcher { + NumberMatcher( + String fieldType, + XContentBuilder actualMappings, + Settings.Builder actualSettings, + XContentBuilder expectedMappings, + Settings.Builder expectedSettings + ) { + super(fieldType, actualMappings, actualSettings, expectedMappings, expectedSettings); + } + + @Override + Object convert(Object value, Object nullValue) { + if (value == null) { + return nullValue; + } + // Special case for number coercion from strings + if (value instanceof String s && s.isEmpty()) { + return nullValue; + } + + return value; + } + } + + // TODO basic implementation only right now + class DateMatcher extends GenericMappingAwareMatcher { + DateMatcher( + XContentBuilder actualMappings, + Settings.Builder actualSettings, + XContentBuilder expectedMappings, + Settings.Builder expectedSettings + ) { + super("date", actualMappings, actualSettings, expectedMappings, expectedSettings); + } + + @Override + Object convert(Object value, Object nullValue) { + return value; + } + } + + /** + * Generic matcher that supports common matching logic like null values. + */ + abstract class GenericMappingAwareMatcher implements FieldSpecificMatcher { + private final String fieldType; + + private final XContentBuilder actualMappings; + private final Settings.Builder actualSettings; + private final XContentBuilder expectedMappings; + private final Settings.Builder expectedSettings; + + GenericMappingAwareMatcher( + String fieldType, + XContentBuilder actualMappings, + Settings.Builder actualSettings, + XContentBuilder expectedMappings, + Settings.Builder expectedSettings + ) { + this.fieldType = fieldType; this.actualMappings = actualMappings; this.actualSettings = actualSettings; this.expectedMappings = expectedMappings; @@ -308,22 +377,17 @@ interface FieldSpecificMatcher { } @Override + @SuppressWarnings("unchecked") public MatchResult match( List actual, List expected, Map actualMapping, Map expectedMapping ) { - var nullValue = actualMapping.get("null_value"); - var expectedNullValue = expectedMapping.get("null_value"); - if (Objects.equals(nullValue, expectedNullValue) == false) { - throw new IllegalStateException( - "[null_value] parameter for [keyword] field does not match between actual and expected mapping" - ); - } + var nullValue = getNullValue(actualMapping, expectedMapping); - var expectedNormalized = normalize(expected, (String) nullValue); - var actualNormalized = normalize(actual, (String) nullValue); + var expectedNormalized = normalize(expected, nullValue); + var actualNormalized = normalize(actual, nullValue); return actualNormalized.equals(expectedNormalized) ? MatchResult.match() @@ -333,18 +397,35 @@ interface FieldSpecificMatcher { actualSettings, expectedMappings, expectedSettings, - "Values of type [keyword] don't match after normalization, normalized " + "Values of type [" + + fieldType + + "] don't match after normalization, normalized " + prettyPrintCollections(actualNormalized, expectedNormalized) ) ); } - private static Set normalize(List values, String nullValue) { + private Set normalize(List values, Object nullValue) { if (values == null) { return Set.of(); } - return values.stream().map(v -> v == null ? nullValue : (String) v).filter(Objects::nonNull).collect(Collectors.toSet()); + return values.stream().map(v -> convert(v, nullValue)).filter(Objects::nonNull).collect(Collectors.toSet()); } + + abstract Object convert(Object value, Object nullValue); + } + + private static Object getNullValue(Map actualMapping, Map expectedMapping) { + return getMappingParameter("null_value", actualMapping, expectedMapping); + } + + private static Object getMappingParameter(String name, Map actualMapping, Map expectedMapping) { + var actualValue = actualMapping.get(name); + var expectedValue = expectedMapping.get(name); + if (Objects.equals(actualValue, expectedValue) == false) { + throw new IllegalStateException("[" + name + "] parameter does not match between actual and expected mapping"); + } + return actualValue; } } diff --git a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/matchers/source/SourceMatcher.java b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/matchers/source/SourceMatcher.java index 57c7a92bfa55..7390f846b017 100644 --- a/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/matchers/source/SourceMatcher.java +++ b/test/framework/src/main/java/org/elasticsearch/logsdb/datageneration/matchers/source/SourceMatcher.java @@ -13,14 +13,13 @@ import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.logsdb.datageneration.matchers.GenericEqualsMatcher; -import org.elasticsearch.logsdb.datageneration.matchers.ListEqualMatcher; import org.elasticsearch.logsdb.datageneration.matchers.MatchResult; import org.elasticsearch.xcontent.XContentBuilder; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import static org.elasticsearch.logsdb.datageneration.matchers.Messages.formatErrorMessage; import static org.elasticsearch.logsdb.datageneration.matchers.Messages.prettyPrintCollections; @@ -51,18 +50,52 @@ public class SourceMatcher extends GenericEqualsMatcher .v2(); this.expectedNormalizedMapping = MappingTransforms.normalizeMapping(expectedMappingAsMap); - this.fieldSpecificMatchers = Map.of( - "half_float", - new FieldSpecificMatcher.HalfFloatMatcher(actualMappings, actualSettings, expectedMappings, expectedSettings), - "scaled_float", - new FieldSpecificMatcher.ScaledFloatMatcher(actualMappings, actualSettings, expectedMappings, expectedSettings), - "unsigned_long", - new FieldSpecificMatcher.UnsignedLongMatcher(actualMappings, actualSettings, expectedMappings, expectedSettings), - "counted_keyword", - new FieldSpecificMatcher.CountedKeywordMatcher(actualMappings, actualSettings, expectedMappings, expectedSettings), - "keyword", - new FieldSpecificMatcher.KeywordMatcher(actualMappings, actualSettings, expectedMappings, expectedSettings) - ); + this.fieldSpecificMatchers = new HashMap<>() { + { + put("keyword", new FieldSpecificMatcher.KeywordMatcher(actualMappings, actualSettings, expectedMappings, expectedSettings)); + put("date", new FieldSpecificMatcher.DateMatcher(actualMappings, actualSettings, expectedMappings, expectedSettings)); + put( + "long", + new FieldSpecificMatcher.NumberMatcher("long", actualMappings, actualSettings, expectedMappings, expectedSettings) + ); + put( + "unsigned_long", + new FieldSpecificMatcher.UnsignedLongMatcher(actualMappings, actualSettings, expectedMappings, expectedSettings) + ); + put( + "integer", + new FieldSpecificMatcher.NumberMatcher("integer", actualMappings, actualSettings, expectedMappings, expectedSettings) + ); + put( + "short", + new FieldSpecificMatcher.NumberMatcher("short", actualMappings, actualSettings, expectedMappings, expectedSettings) + ); + put( + "byte", + new FieldSpecificMatcher.NumberMatcher("byte", actualMappings, actualSettings, expectedMappings, expectedSettings) + ); + put( + "double", + new FieldSpecificMatcher.NumberMatcher("double", actualMappings, actualSettings, expectedMappings, expectedSettings) + ); + put( + "float", + new FieldSpecificMatcher.NumberMatcher("float", actualMappings, actualSettings, expectedMappings, expectedSettings) + ); + put( + "half_float", + new FieldSpecificMatcher.HalfFloatMatcher(actualMappings, actualSettings, expectedMappings, expectedSettings) + ); + put( + "scaled_float", + new FieldSpecificMatcher.ScaledFloatMatcher(actualMappings, actualSettings, expectedMappings, expectedSettings) + ); + put( + "counted_keyword", + new FieldSpecificMatcher.CountedKeywordMatcher(actualMappings, actualSettings, expectedMappings, expectedSettings) + ); + } + }; this.dynamicFieldMatcher = new DynamicFieldMatcher(actualMappings, actualSettings, expectedMappings, expectedSettings); } @@ -104,9 +137,7 @@ public class SourceMatcher extends GenericEqualsMatcher var actualValues = actual.get(name); var expectedValues = expectedFieldEntry.getValue(); - var matchIncludingFieldSpecificMatchers = matchWithFieldSpecificMatcher(name, actualValues, expectedValues).orElseGet( - () -> matchWithGenericMatcher(actualValues, expectedValues) - ); + var matchIncludingFieldSpecificMatchers = matchWithFieldSpecificMatcher(name, actualValues, expectedValues); if (matchIncludingFieldSpecificMatchers.isMatch() == false) { var message = "Source documents don't match for field [" + name + "]: " + matchIncludingFieldSpecificMatchers.getMessage(); return MatchResult.noMatch(message); @@ -115,7 +146,7 @@ public class SourceMatcher extends GenericEqualsMatcher return MatchResult.match(); } - private Optional matchWithFieldSpecificMatcher(String fieldName, List actualValues, List expectedValues) { + private MatchResult matchWithFieldSpecificMatcher(String fieldName, List actualValues, List expectedValues) { var actualFieldMapping = actualNormalizedMapping.get(fieldName); if (actualFieldMapping == null) { if (expectedNormalizedMapping.get(fieldName) != null @@ -155,30 +186,13 @@ public class SourceMatcher extends GenericEqualsMatcher } var fieldSpecificMatcher = fieldSpecificMatchers.get(actualFieldType); - if (fieldSpecificMatcher == null) { - return Optional.empty(); - } + assert fieldSpecificMatcher != null : "Missing matcher for field type [" + actualFieldType + "]"; - MatchResult matched = fieldSpecificMatcher.match( + return fieldSpecificMatcher.match( actualValues, expectedValues, actualFieldMapping.mappingParameters(), expectedFieldMapping.mappingParameters() ); - return Optional.of(matched); - } - - private MatchResult matchWithGenericMatcher(List actualValues, List expectedValues) { - var genericListMatcher = new ListEqualMatcher( - actualMappings, - actualSettings, - expectedMappings, - expectedSettings, - SourceTransforms.normalizeValues(actualValues), - SourceTransforms.normalizeValues(expectedValues), - true - ); - - return genericListMatcher.match(); } } diff --git a/test/framework/src/main/java/org/elasticsearch/search/ErrorTraceHelper.java b/test/framework/src/main/java/org/elasticsearch/search/ErrorTraceHelper.java new file mode 100644 index 000000000000..a9fa5ba36fde --- /dev/null +++ b/test/framework/src/main/java/org/elasticsearch/search/ErrorTraceHelper.java @@ -0,0 +1,41 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.search; + +import org.elasticsearch.ExceptionsHelper; +import org.elasticsearch.test.InternalTestCluster; +import org.elasticsearch.transport.TransportMessageListener; +import org.elasticsearch.transport.TransportService; + +import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BooleanSupplier; + +/** + * Utilities around testing the `error_trace` message header in search. + */ +public enum ErrorTraceHelper { + ; + + public static BooleanSupplier setupErrorTraceListener(InternalTestCluster internalCluster) { + final AtomicBoolean transportMessageHasStackTrace = new AtomicBoolean(false); + internalCluster.getDataNodeInstances(TransportService.class).forEach(ts -> ts.addMessageListener(new TransportMessageListener() { + @Override + public void onResponseSent(long requestId, String action, Exception error) { + TransportMessageListener.super.onResponseSent(requestId, action, error); + if (action.startsWith("indices:data/read/search")) { + Optional throwable = ExceptionsHelper.unwrapCausesAndSuppressed(error, t -> t.getStackTrace().length > 0); + transportMessageHasStackTrace.set(throwable.isPresent()); + } + } + })); + return transportMessageHasStackTrace::get; + } +} diff --git a/test/framework/src/main/java/org/elasticsearch/search/MockSearchService.java b/test/framework/src/main/java/org/elasticsearch/search/MockSearchService.java index 79c61cacb58e..42b11173a3b1 100644 --- a/test/framework/src/main/java/org/elasticsearch/search/MockSearchService.java +++ b/test/framework/src/main/java/org/elasticsearch/search/MockSearchService.java @@ -9,7 +9,6 @@ package org.elasticsearch.search; -import org.elasticsearch.action.search.SearchShardTask; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.core.TimeValue; @@ -23,6 +22,7 @@ import org.elasticsearch.search.fetch.FetchPhase; import org.elasticsearch.search.internal.ReaderContext; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.internal.ShardSearchRequest; +import org.elasticsearch.tasks.CancellableTask; import org.elasticsearch.telemetry.tracing.Tracer; import org.elasticsearch.threadpool.ThreadPool; @@ -46,7 +46,7 @@ public class MockSearchService extends SearchService { private Consumer onCreateSearchContext = context -> {}; - private Function onCheckCancelled = Function.identity(); + private Function onCheckCancelled = Function.identity(); /** Throw an {@link AssertionError} if there are still in-flight contexts. */ public static void assertNoInFlightContext() { @@ -132,7 +132,7 @@ public class MockSearchService extends SearchService { protected SearchContext createContext( ReaderContext readerContext, ShardSearchRequest request, - SearchShardTask task, + CancellableTask task, ResultsType resultsType, boolean includeAggregations ) throws IOException { @@ -154,12 +154,12 @@ public class MockSearchService extends SearchService { return searchContext; } - public void setOnCheckCancelled(Function onCheckCancelled) { + public void setOnCheckCancelled(Function onCheckCancelled) { this.onCheckCancelled = onCheckCancelled; } @Override - protected void checkCancelled(SearchShardTask task) { + protected void checkCancelled(CancellableTask task) { super.checkCancelled(onCheckCancelled.apply(task)); } } diff --git a/test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java b/test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java index 9e2dee4d9421..d034e6e6679c 100644 --- a/test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java @@ -129,6 +129,7 @@ import org.elasticsearch.search.NestedDocuments; import org.elasticsearch.search.SearchModule; import org.elasticsearch.search.aggregations.AggregatorFactories.Builder; import org.elasticsearch.search.aggregations.MultiBucketConsumerService.MultiBucketConsumer; +import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation; import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.MetricsAggregator; import org.elasticsearch.search.aggregations.metrics.MultiValueAggregation; @@ -149,6 +150,7 @@ import org.elasticsearch.search.internal.ContextIndexSearcher; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.internal.ShardSearchRequest; import org.elasticsearch.search.internal.SubSearchContext; +import org.elasticsearch.tasks.TaskCancelledException; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.InternalAggregationTestCase; import org.elasticsearch.threadpool.TestThreadPool; @@ -251,29 +253,12 @@ public abstract class AggregatorTestCase extends ESTestCase { return List.of(); } - /** - * Deprecated - this will be made private in a future update - */ - @Deprecated - protected A createAggregator( - AggregationBuilder aggregationBuilder, - IndexReader indexReader, - MappedFieldType... fieldTypes - ) throws IOException { - return createAggregator(aggregationBuilder, createAggregationContext(indexReader, new MatchAllDocsQuery(), fieldTypes)); - } - protected A createAggregator(AggregationBuilder aggregationBuilder, AggregationContext context) throws IOException { return createAggregator(new AggregatorFactories.Builder().addAggregator(aggregationBuilder), context); } - /** - * Deprecated - this will be made private in a future update - */ - @Deprecated - protected A createAggregator(AggregatorFactories.Builder builder, AggregationContext context) - throws IOException { + private A createAggregator(AggregatorFactories.Builder builder, AggregationContext context) throws IOException { Aggregator[] aggregators = builder.build(context, null).createTopLevelAggregators(); assertThat(aggregators.length, equalTo(1)); @SuppressWarnings("unchecked") @@ -310,10 +295,7 @@ public abstract class AggregatorTestCase extends ESTestCase { * While {@linkplain AggregationContext} is {@link Releasable} the caller is * not responsible for releasing it. Instead, it is released automatically in * in {@link #cleanupReleasables()}. - * - * Deprecated - this will be made private in a future update */ - @Deprecated protected AggregationContext createAggregationContext( IndexReader indexReader, IndexSettings indexSettings, @@ -346,6 +328,56 @@ public abstract class AggregatorTestCase extends ESTestCase { int maxBucket, boolean isInSortOrderExecutionRequired, MappedFieldType... fieldTypes + ) { + return createAggregationContext( + searcher, + indexSettings, + query, + breakerService, + bytesToPreallocate, + maxBucket, + isInSortOrderExecutionRequired, + () -> false, + fieldTypes + ); + } + + /** + * Creates an aggregation context that will randomly report that the query has been cancelled + */ + private AggregationContext createCancellingAggregationContext( + IndexSearcher searcher, + IndexSettings indexSettings, + Query query, + CircuitBreakerService breakerService, + long bytesToPreallocate, + int maxBucket, + boolean isInSortOrderExecutionRequired, + MappedFieldType... fieldTypes + ) { + return createAggregationContext( + searcher, + indexSettings, + query, + breakerService, + bytesToPreallocate, + maxBucket, + isInSortOrderExecutionRequired, + () -> ESTestCase.random().nextInt(20) == 0, + fieldTypes + ); + } + + private AggregationContext createAggregationContext( + IndexSearcher searcher, + IndexSettings indexSettings, + Query query, + CircuitBreakerService breakerService, + long bytesToPreallocate, + int maxBucket, + boolean isInSortOrderExecutionRequired, + Supplier isCancelled, + MappedFieldType... fieldTypes ) { MappingLookup mappingLookup = MappingLookup.fromMappers( Mapping.EMPTY, @@ -409,7 +441,7 @@ public abstract class AggregatorTestCase extends ESTestCase { bitsetFilterCache, randomInt(), () -> 0L, - () -> false, + isCancelled, q -> q, true, isInSortOrderExecutionRequired @@ -536,9 +568,11 @@ public abstract class AggregatorTestCase extends ESTestCase { IndexSettings indexSettings = createIndexSettings(); // First run it to find circuit breaker leaks on the aggregator runWithCrankyCircuitBreaker(indexSettings, searcher, aggTestConfig); - // Second run it to the end CircuitBreakerService breakerService = new NoneCircuitBreakerService(); - return searchAndReduce(indexSettings, searcher, breakerService, aggTestConfig); + // Next, try with random cancellations, again looking for leaks + runWithCancellingConfig(indexSettings, searcher, breakerService, aggTestConfig); + // Finally, run it to the end + return searchAndReduce(indexSettings, searcher, breakerService, aggTestConfig, this::createAggregationContext); } /** @@ -552,7 +586,7 @@ public abstract class AggregatorTestCase extends ESTestCase { CircuitBreakerService crankyService = new CrankyCircuitBreakerService(); for (int i = 0; i < 5; i++) { try { - searchAndReduce(indexSettings, searcher, crankyService, aggTestConfig); + searchAndReduce(indexSettings, searcher, crankyService, aggTestConfig, this::createAggregationContext); } catch (CircuitBreakingException e) { // Circuit breaks from the cranky breaker are expected - it randomly fails, after all assertThat(e.getMessage(), equalTo(CrankyCircuitBreakerService.ERROR_MESSAGE)); @@ -560,12 +594,43 @@ public abstract class AggregatorTestCase extends ESTestCase { } } + private void runWithCancellingConfig( + IndexSettings indexSettings, + IndexSearcher searcher, + CircuitBreakerService breakerService, + AggTestConfig aggTestConfig + ) throws IOException { + for (int i = 0; i < 5; i++) { + try { + searchAndReduce(indexSettings, searcher, breakerService, aggTestConfig, this::createCancellingAggregationContext); + } catch (TaskCancelledException e) { + // we don't want to expectThrows this because the randomizer might just never report cancellation, + // but it's also normal that it should throw here. + } + } + } + + @FunctionalInterface + public interface AggregationcContextSupplier { + AggregationContext get( + IndexSearcher searcher, + IndexSettings indexSettings, + Query query, + CircuitBreakerService breakerService, + long bytesToPreallocate, + int maxBucket, + boolean isInSortOrderExecutionRequired, + MappedFieldType... fieldTypes + ); + } + @SuppressWarnings("unchecked") private A searchAndReduce( IndexSettings indexSettings, IndexSearcher searcher, CircuitBreakerService breakerService, - AggTestConfig aggTestConfig + AggTestConfig aggTestConfig, + AggregationcContextSupplier contextSupplier ) throws IOException { Query query = aggTestConfig.query(); AggregatorFactories.Builder builder = new AggregatorFactories.Builder().addAggregator(aggTestConfig.builder()); @@ -591,7 +656,7 @@ public abstract class AggregatorTestCase extends ESTestCase { subSearchers[searcherIDX] = new ShardSearcher(leave, compCTX); } for (ShardSearcher subSearcher : subSearchers) { - AggregationContext context = createAggregationContext( + AggregationContext context = contextSupplier.get( subSearcher, indexSettings, query, @@ -620,7 +685,7 @@ public abstract class AggregatorTestCase extends ESTestCase { } } } else { - AggregationContext context = createAggregationContext( + AggregationContext context = contextSupplier.get( searcher, indexSettings, query, @@ -688,8 +753,41 @@ public abstract class AggregatorTestCase extends ESTestCase { assertRoundTrip(internalAggregation.copyResults()); } } + /* Verify that cancellation during final reduce correctly throws. + * We check reduce time cancellation only when consuming buckets. + */ + if (aggTestConfig.testReductionCancellation()) { + try { + // I can't remember if we mutate the InternalAggregations list, so make a defensive copy + List internalAggsCopy = new ArrayList<>(internalAggs); + A internalAgg = doFinalReduce(maxBucket, bigArraysForReduction, builder, internalAggsCopy, true); + if (internalAgg instanceof MultiBucketsAggregation mb) { + // Empty mutli-bucket aggs are expected to return before even getting to the cancellation check + assertEquals("Got non-empty result for a cancelled reduction", 0, mb.getBuckets().size()); + } // other cases? + } catch (TaskCancelledException e) { + /* We may not always honor cancellation in reduce, for example if we are returning no results, so we can't + * just expectThrows here. + */ + } + } // now do the final reduce + A internalAgg = doFinalReduce(maxBucket, bigArraysForReduction, builder, internalAggs, false); + assertRoundTrip(internalAgg); + if (aggTestConfig.builder instanceof ValuesSourceAggregationBuilder.MetricsAggregationBuilder) { + verifyMetricNames((ValuesSourceAggregationBuilder.MetricsAggregationBuilder) aggTestConfig.builder, internalAgg); + } + return internalAgg; + } + + private A doFinalReduce( + int maxBucket, + BigArrays bigArraysForReduction, + Builder builder, + List internalAggs, + boolean cancelled + ) throws IOException { MultiBucketConsumer reduceBucketConsumer = new MultiBucketConsumer( maxBucket, new NoneCircuitBreakerService().getBreaker(CircuitBreaker.REQUEST) @@ -697,7 +795,7 @@ public abstract class AggregatorTestCase extends ESTestCase { AggregationReduceContext reduceContext = new AggregationReduceContext.ForFinal( bigArraysForReduction, getMockScriptService(), - () -> false, + () -> cancelled, builder, reduceBucketConsumer ); @@ -707,10 +805,6 @@ public abstract class AggregatorTestCase extends ESTestCase { assertRoundTrip(internalAgg); doAssertReducedMultiBucketConsumer(internalAgg, reduceBucketConsumer); - assertRoundTrip(internalAgg); - if (aggTestConfig.builder instanceof ValuesSourceAggregationBuilder.MetricsAggregationBuilder) { - verifyMetricNames((ValuesSourceAggregationBuilder.MetricsAggregationBuilder) aggTestConfig.builder, internalAgg); - } return internalAgg; } @@ -1601,11 +1695,12 @@ public abstract class AggregatorTestCase extends ESTestCase { boolean incrementalReduce, boolean useLogDocMergePolicy, + boolean testReductionCancellation, MappedFieldType... fieldTypes ) { public AggTestConfig(AggregationBuilder builder, MappedFieldType... fieldTypes) { - this(new MatchAllDocsQuery(), builder, DEFAULT_MAX_BUCKETS, randomBoolean(), true, randomBoolean(), false, fieldTypes); + this(new MatchAllDocsQuery(), builder, DEFAULT_MAX_BUCKETS, randomBoolean(), true, randomBoolean(), false, true, fieldTypes); } public AggTestConfig withQuery(Query query) { @@ -1617,6 +1712,7 @@ public abstract class AggregatorTestCase extends ESTestCase { shouldBeCached, incrementalReduce, useLogDocMergePolicy, + testReductionCancellation, fieldTypes ); } @@ -1630,6 +1726,7 @@ public abstract class AggregatorTestCase extends ESTestCase { shouldBeCached, incrementalReduce, useLogDocMergePolicy, + testReductionCancellation, fieldTypes ); } @@ -1643,6 +1740,7 @@ public abstract class AggregatorTestCase extends ESTestCase { shouldBeCached, incrementalReduce, useLogDocMergePolicy, + testReductionCancellation, fieldTypes ); } @@ -1656,6 +1754,7 @@ public abstract class AggregatorTestCase extends ESTestCase { shouldBeCached, incrementalReduce, useLogDocMergePolicy, + testReductionCancellation, fieldTypes ); } @@ -1669,6 +1768,7 @@ public abstract class AggregatorTestCase extends ESTestCase { shouldBeCached, incrementalReduce, useLogDocMergePolicy, + testReductionCancellation, fieldTypes ); } @@ -1682,6 +1782,21 @@ public abstract class AggregatorTestCase extends ESTestCase { shouldBeCached, incrementalReduce, true, + testReductionCancellation, + fieldTypes + ); + } + + public AggTestConfig noReductionCancellation() { + return new AggTestConfig( + query, + builder, + maxBuckets, + splitLeavesIntoSeparateAggregators, + shouldBeCached, + incrementalReduce, + useLogDocMergePolicy, + false, fieldTypes ); } diff --git a/test/framework/src/main/java/org/elasticsearch/test/LambdaMatchers.java b/test/framework/src/main/java/org/elasticsearch/test/LambdaMatchers.java index 67a6cd49b072..a329b5fbaebb 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/LambdaMatchers.java +++ b/test/framework/src/main/java/org/elasticsearch/test/LambdaMatchers.java @@ -24,10 +24,12 @@ import java.util.function.Predicate; public class LambdaMatchers { private static class TransformMatcher extends TypeSafeMatcher { + private final String transformDescription; private final Matcher matcher; private final Function transform; - private TransformMatcher(Matcher matcher, Function transform) { + private TransformMatcher(String transformDescription, Matcher matcher, Function transform) { + this.transformDescription = transformDescription; this.matcher = matcher; this.transform = transform; } @@ -53,25 +55,31 @@ public class LambdaMatchers { return; } - description.appendText("transformed value "); + description.appendText(transformDescription).appendText(" "); matcher.describeMismatch(u, description); } @Override public void describeTo(Description description) { - description.appendText("transformed to match ").appendDescriptionOf(matcher); + description.appendText(transformDescription).appendText(" matches ").appendDescriptionOf(matcher); } } public static Matcher transformedMatch(Function function, Matcher matcher) { - return new TransformMatcher<>(matcher, function); + return new TransformMatcher<>("transformed value", matcher, function); + } + + public static Matcher transformedMatch(String description, Function function, Matcher matcher) { + return new TransformMatcher<>(description, matcher, function); } private static class ListTransformMatcher extends TypeSafeMatcher> { + private final String transformDescription; private final Matcher> matcher; private final Function transform; - private ListTransformMatcher(Matcher> matcher, Function transform) { + private ListTransformMatcher(String transformDescription, Matcher> matcher, Function transform) { + this.transformDescription = transformDescription; this.matcher = matcher; this.transform = transform; } @@ -107,25 +115,35 @@ public class LambdaMatchers { } } - description.appendText("transformed item "); + description.appendText(transformDescription).appendText(" "); matcher.describeMismatch(us, description); } @Override public void describeTo(Description description) { - description.appendText("iterable with transformed items to match ").appendDescriptionOf(matcher); + description.appendText("iterable with ").appendText(transformDescription).appendText(" matching ").appendDescriptionOf(matcher); } } public static Matcher> transformedItemsMatch(Function function, Matcher> matcher) { - return new ListTransformMatcher<>(matcher, function); + return new ListTransformMatcher<>("transformed items", matcher, function); + } + + public static Matcher> transformedItemsMatch( + String transformDescription, + Function function, + Matcher> matcher + ) { + return new ListTransformMatcher<>(transformDescription, matcher, function); } private static class ArrayTransformMatcher extends TypeSafeMatcher { + private final String transformDescription; private final Matcher matcher; private final Function transform; - private ArrayTransformMatcher(Matcher matcher, Function transform) { + private ArrayTransformMatcher(String transformDescription, Matcher matcher, Function transform) { + this.transformDescription = transformDescription; this.matcher = matcher; this.transform = transform; } @@ -174,18 +192,26 @@ public class LambdaMatchers { us[i] = u; } - description.appendText("transformed item "); + description.appendText(transformDescription).appendText(" "); matcher.describeMismatch(us, description); } @Override public void describeTo(Description description) { - description.appendText("array with transformed items to match ").appendDescriptionOf(matcher); + description.appendText("array with ").appendText(transformDescription).appendText(" matching ").appendDescriptionOf(matcher); } } public static Matcher transformedArrayItemsMatch(Function function, Matcher matcher) { - return new ArrayTransformMatcher<>(matcher, function); + return new ArrayTransformMatcher<>("transformed items", matcher, function); + } + + public static Matcher transformedArrayItemsMatch( + String transformDescription, + Function function, + Matcher matcher + ) { + return new ArrayTransformMatcher<>(transformDescription, matcher, function); } private static class PredicateMatcher extends BaseMatcher> { diff --git a/test/framework/src/main/java/org/elasticsearch/test/TestSearchContext.java b/test/framework/src/main/java/org/elasticsearch/test/TestSearchContext.java index 103cf1c15abc..c46442485ff9 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/TestSearchContext.java +++ b/test/framework/src/main/java/org/elasticsearch/test/TestSearchContext.java @@ -11,7 +11,6 @@ package org.elasticsearch.test; import org.apache.lucene.search.FieldDoc; import org.apache.lucene.search.Query; import org.apache.lucene.search.TotalHits; -import org.elasticsearch.action.search.SearchShardTask; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.core.TimeValue; import org.elasticsearch.index.IndexService; @@ -49,6 +48,7 @@ import org.elasticsearch.search.rank.feature.RankFeatureResult; import org.elasticsearch.search.rescore.RescoreContext; import org.elasticsearch.search.sort.SortAndFormats; import org.elasticsearch.search.suggest.SuggestionSearchContext; +import org.elasticsearch.tasks.CancellableTask; import java.util.Collections; import java.util.HashMap; @@ -67,7 +67,7 @@ public class TestSearchContext extends SearchContext { ParsedQuery postFilter; Query query; Float minScore; - SearchShardTask task; + CancellableTask task; SortAndFormats sort; boolean trackScores = false; int trackTotalHitsUpTo = SearchContext.DEFAULT_TRACK_TOTAL_HITS_UP_TO; @@ -506,12 +506,12 @@ public class TestSearchContext extends SearchContext { } @Override - public void setTask(SearchShardTask task) { + public void setTask(CancellableTask task) { this.task = task; } @Override - public SearchShardTask getTask() { + public CancellableTask getTask() { return task; } diff --git a/test/framework/src/main/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java b/test/framework/src/main/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java index 40aee8eed423..b0d64a87c4d3 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java +++ b/test/framework/src/main/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java @@ -257,7 +257,7 @@ public class ElasticsearchAssertions { assertThat( "Request should have been blocked by [" + expectedBlockId + "] instead of " + e.blocks(), e.blocks(), - hasItem(transformedMatch(ClusterBlock::id, equalTo(expectedBlockId))) + hasItem(transformedMatch("ClusterBlock id", ClusterBlock::id, equalTo(expectedBlockId))) ); } } @@ -764,33 +764,39 @@ public class ElasticsearchAssertions { * Assert that an index template is missing */ public static void assertIndexTemplateMissing(GetIndexTemplatesResponse templatesResponse, String name) { - assertThat(templatesResponse.getIndexTemplates(), not(hasItem(transformedMatch(IndexTemplateMetadata::name, equalTo(name))))); + assertThat( + templatesResponse.getIndexTemplates(), + not(hasItem(transformedMatch("IndexTemplateMetadata name", IndexTemplateMetadata::name, equalTo(name)))) + ); } /** * Assert that an index template exists */ public static void assertIndexTemplateExists(GetIndexTemplatesResponse templatesResponse, String name) { - assertThat(templatesResponse.getIndexTemplates(), hasItem(transformedMatch(IndexTemplateMetadata::name, equalTo(name)))); + assertThat( + templatesResponse.getIndexTemplates(), + hasItem(transformedMatch("IndexTemplateMetadata name", IndexTemplateMetadata::name, equalTo(name))) + ); } /* * matchers */ public static Matcher hasId(final String id) { - return transformedMatch(SearchHit::getId, equalTo(id)); + return transformedMatch("SearchHit id", SearchHit::getId, equalTo(id)); } public static Matcher hasIndex(final String index) { - return transformedMatch(SearchHit::getIndex, equalTo(index)); + return transformedMatch("SearchHit index", SearchHit::getIndex, equalTo(index)); } public static Matcher hasScore(final float score) { - return transformedMatch(SearchHit::getScore, equalTo(score)); + return transformedMatch("SearchHit score", SearchHit::getScore, equalTo(score)); } public static Matcher hasRank(final int rank) { - return transformedMatch(SearchHit::getRank, equalTo(rank)); + return transformedMatch("SearchHit rank", SearchHit::getRank, equalTo(rank)); } public static T assertBooleanSubQuery(Query query, Class subqueryType, int i) { diff --git a/test/framework/src/test/java/org/elasticsearch/logsdb/datageneration/SourceMatcherTests.java b/test/framework/src/test/java/org/elasticsearch/logsdb/datageneration/SourceMatcherTests.java index bc7a558a0b68..aba5cbc9878e 100644 --- a/test/framework/src/test/java/org/elasticsearch/logsdb/datageneration/SourceMatcherTests.java +++ b/test/framework/src/test/java/org/elasticsearch/logsdb/datageneration/SourceMatcherTests.java @@ -62,8 +62,8 @@ public class SourceMatcherTests extends ESTestCase { public void testMappedMatch() throws IOException { List> values = List.of( - Map.of("aaa", 124, "bbb", false, "ccc", 12.34), - Map.of("aaa", 124, "bbb", false, "ccc", 12.34) + Map.of("aaa", 124, "bbb", "hey", "ccc", 12.34), + Map.of("aaa", 124, "bbb", "yeh", "ccc", 12.34) ); var mapping = XContentBuilder.builder(XContentType.JSON.xContent()); @@ -71,7 +71,7 @@ public class SourceMatcherTests extends ESTestCase { mapping.startObject("_doc"); { mapping.startObject("aaa").field("type", "long").endObject(); - mapping.startObject("bbb").field("type", "boolean").endObject(); + mapping.startObject("bbb").field("type", "keyword").endObject(); mapping.startObject("ccc").field("type", "half_float").endObject(); } mapping.endObject(); @@ -83,12 +83,12 @@ public class SourceMatcherTests extends ESTestCase { public void testMappedMismatch() throws IOException { List> actual = List.of( - Map.of("aaa", 124, "bbb", false, "ccc", 12.34), - Map.of("aaa", 124, "bbb", false, "ccc", 12.34) + Map.of("aaa", 124, "bbb", "hey", "ccc", 12.34), + Map.of("aaa", 124, "bbb", "yeh", "ccc", 12.34) ); List> expected = List.of( - Map.of("aaa", 124, "bbb", false, "ccc", 12.34), - Map.of("aaa", 124, "bbb", false, "ccc", 12.35) + Map.of("aaa", 124, "bbb", "hey", "ccc", 12.34), + Map.of("aaa", 124, "bbb", "yeh", "ccc", 12.35) ); var mapping = XContentBuilder.builder(XContentType.JSON.xContent()); @@ -96,7 +96,7 @@ public class SourceMatcherTests extends ESTestCase { mapping.startObject("_doc"); { mapping.startObject("aaa").field("type", "long").endObject(); - mapping.startObject("bbb").field("type", "boolean").endObject(); + mapping.startObject("bbb").field("type", "keyword").endObject(); mapping.startObject("ccc").field("type", "half_float").endObject(); } mapping.endObject(); diff --git a/test/framework/src/test/java/org/elasticsearch/test/LambdaMatchersTests.java b/test/framework/src/test/java/org/elasticsearch/test/LambdaMatchersTests.java index 20f9b354f2b4..c97a369a9853 100644 --- a/test/framework/src/test/java/org/elasticsearch/test/LambdaMatchersTests.java +++ b/test/framework/src/test/java/org/elasticsearch/test/LambdaMatchersTests.java @@ -63,7 +63,8 @@ public class LambdaMatchersTests extends ESTestCase { } public void testTransformDescription() { - assertDescribeTo(transformedMatch((A a) -> a.str, emptyString()), equalTo("transformed to match an empty string")); + assertDescribeTo(transformedMatch((A a) -> a.str, emptyString()), equalTo("transformed value matches an empty string")); + assertDescribeTo(transformedMatch("str field", (A a) -> a.str, emptyString()), equalTo("str field matches an empty string")); } public void testListTransformMatcher() { @@ -74,14 +75,23 @@ public class LambdaMatchersTests extends ESTestCase { assertMismatch( as, transformedItemsMatch(a -> a.str, containsInAnyOrder("1", "2", "4")), - equalTo("transformed item not matched: \"3\"") + equalTo("transformed items not matched: \"3\"") + ); + assertMismatch( + as, + transformedItemsMatch("str field", a -> a.str, containsInAnyOrder("1", "2", "4")), + equalTo("str field not matched: \"3\"") ); } public void testListTransformDescription() { assertDescribeTo( transformedItemsMatch((A a) -> a.str, containsInAnyOrder("1")), - equalTo("iterable with transformed items to match iterable with items [\"1\"] in any order") + equalTo("iterable with transformed items matching iterable with items [\"1\"] in any order") + ); + assertDescribeTo( + transformedItemsMatch("str field", (A a) -> a.str, containsInAnyOrder("1")), + equalTo("iterable with str field matching iterable with items [\"1\"] in any order") ); } @@ -92,14 +102,23 @@ public class LambdaMatchersTests extends ESTestCase { assertMismatch( as, transformedArrayItemsMatch(a -> a.str, arrayContainingInAnyOrder("1", "2", "4")), - equalTo("transformed item not matched: \"3\"") + equalTo("transformed items not matched: \"3\"") + ); + assertMismatch( + as, + transformedArrayItemsMatch("str field", a -> a.str, arrayContainingInAnyOrder("1", "2", "4")), + equalTo("str field not matched: \"3\"") ); } public void testArrayTransformDescription() { assertDescribeTo( transformedArrayItemsMatch((A a) -> a.str, arrayContainingInAnyOrder("1")), - equalTo("array with transformed items to match [\"1\"] in any order") + equalTo("array with transformed items matching [\"1\"] in any order") + ); + assertDescribeTo( + transformedArrayItemsMatch("str field", (A a) -> a.str, arrayContainingInAnyOrder("1")), + equalTo("array with str field matching [\"1\"] in any order") ); } diff --git a/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java b/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java index 11787866af0d..013a502d93ce 100644 --- a/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java +++ b/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java @@ -18,7 +18,12 @@ import org.elasticsearch.test.cluster.util.Version; public enum FeatureFlag { TIME_SERIES_MODE("es.index_mode_feature_flag_registered=true", Version.fromString("8.0.0"), null), FAILURE_STORE_ENABLED("es.failure_store_feature_flag_enabled=true", Version.fromString("8.12.0"), null), - SUB_OBJECTS_AUTO_ENABLED("es.sub_objects_auto_feature_flag_enabled=true", Version.fromString("8.16.0"), null); + SUB_OBJECTS_AUTO_ENABLED("es.sub_objects_auto_feature_flag_enabled=true", Version.fromString("8.16.0"), null), + INDEX_RECOVERY_USE_SYNTHETIC_SOURCE( + "es.index_recovery_use_synthetic_source_feature_flag_enabled=true", + Version.fromString("8.18.0"), + null + ); public final String systemProperty; public final Version from; diff --git a/x-pack/plugin/analytics/build.gradle b/x-pack/plugin/analytics/build.gradle index 9a21f40a4c4a..7aaaaaf66864 100644 --- a/x-pack/plugin/analytics/build.gradle +++ b/x-pack/plugin/analytics/build.gradle @@ -7,6 +7,7 @@ apply plugin: 'elasticsearch.internal-es-plugin' apply plugin: 'elasticsearch.internal-cluster-test' +apply plugin: 'elasticsearch.internal-java-rest-test' esplugin { name = 'x-pack-analytics' @@ -18,6 +19,10 @@ base { archivesName = 'x-pack-analytics' } +tasks.named('javaRestTest') { + usesDefaultDistribution() +} + dependencies { api 'org.apache.commons:commons-math3:3.6.1' compileOnly project(path: xpackModule('core')) diff --git a/x-pack/plugin/analytics/src/javaRestTest/java/org/elasticsearch/multiterms/AggsTimeoutIT.java b/x-pack/plugin/analytics/src/javaRestTest/java/org/elasticsearch/multiterms/AggsTimeoutIT.java new file mode 100644 index 000000000000..6ca7d38d8784 --- /dev/null +++ b/x-pack/plugin/analytics/src/javaRestTest/java/org/elasticsearch/multiterms/AggsTimeoutIT.java @@ -0,0 +1,321 @@ +/* + * 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.multiterms; + +import org.apache.http.client.config.RequestConfig; +import org.apache.http.util.EntityUtils; +import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; +import org.elasticsearch.client.Request; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.unit.ByteSizeValue; +import org.elasticsearch.core.CheckedConsumer; +import org.elasticsearch.core.TimeValue; +import org.elasticsearch.index.mapper.DateFieldMapper; +import org.elasticsearch.test.ListMatcher; +import org.elasticsearch.test.MapMatcher; +import org.elasticsearch.test.cluster.ElasticsearchCluster; +import org.elasticsearch.test.cluster.local.distribution.DistributionType; +import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xcontent.json.JsonXContent; +import org.junit.Before; +import org.junit.ClassRule; + +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import static org.elasticsearch.test.ListMatcher.matchesList; +import static org.elasticsearch.test.MapMatcher.assertMap; +import static org.elasticsearch.test.MapMatcher.matchesMap; +import static org.hamcrest.Matchers.any; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasSize; + +/** + * Runs slow aggregations with a timeout and asserts that they timeout and + * cancel the queries. + */ +public class AggsTimeoutIT extends ESRestTestCase { + private static final int DEPTH = 10; + private static final int VALUE_COUNT = 4; + private static final int TOTAL_DOCS = Math.toIntExact((long) Math.pow(VALUE_COUNT, DEPTH)); + private static final TimeValue TIMEOUT = TimeValue.timeValueSeconds(1); + + @ClassRule + public static ElasticsearchCluster cluster = ElasticsearchCluster.local() + .distribution(DistributionType.DEFAULT) + .setting("xpack.watcher.enabled", "false") + .setting("xpack.ml.enabled", "false") + .setting("xpack.security.enabled", "false") + .setting("xpack.security.transport.ssl.enabled", "false") + .setting("xpack.security.http.ssl.enabled", "false") + .jvmArg("-Xmx1g") + .build(); + + @Override + protected String getTestRestCluster() { + return cluster.getHttpAddresses(); + } + + public void testTerms() throws Exception { + Request request = new Request("POST", "/deep/_search"); + XContentBuilder body = JsonXContent.contentBuilder().prettyPrint().startObject(); + body.field("size", 0); + agg(body, "terms", 10); + request.setJsonEntity(Strings.toString(body.endObject())); + setTimeout(request); + try { + Map response = responseAsMap(client().performRequest(request)); + assertMap("not expected to finish", response, matchesMap()); + } catch (SocketTimeoutException timeout) { + logger.info("timed out"); + assertNoSearchesRunning(); + } + } + + private void agg(XContentBuilder body, String type, int depth) throws IOException { + if (depth == 0) { + return; + } + body.startObject("aggs").startObject(field("agg", depth)); + { + body.startObject(type); + body.field("field", field("kwd", depth - 1)); + body.endObject(); + } + agg(body, type, depth - 1); + body.endObject().endObject(); + } + + public void testMultiTerms() throws Exception { + Request request = new Request("POST", "/deep/_search"); + XContentBuilder body = JsonXContent.contentBuilder().prettyPrint().startObject(); + body.field("size", 0); + autoDateInMultiTerms(body, b -> { + for (int i = 0; i < DEPTH; i++) { + b.startObject().field("field", field("kwd", i)).endObject(); + } + }); + request.setJsonEntity(Strings.toString(body.endObject())); + setTimeout(request); + try { + Map response = responseAsMap(client().performRequest(request)); + ListMatcher buckets = matchesList(); + for (int i = 0; i < 10; i++) { + buckets = buckets.item( + matchesMap().entry("key_as_string", any(String.class)) + .entry("key", hasSize(10)) + .entry("doc_count", 1) + .entry("adh", matchesMap().entry("buckets", hasSize(1)).entry("interval", "1s")) + ); + } + MapMatcher agg = matchesMap().entry("buckets", buckets) + .entry("doc_count_error_upper_bound", 0) + .entry("sum_other_doc_count", greaterThan(0)); + assertMap(response, matchesMap().extraOk().entry("aggregations", matchesMap().entry("multi", agg))); + } catch (SocketTimeoutException timeout) { + logger.info("timed out"); + assertNoSearchesRunning(); + } + } + + public void testMultiTermWithTimestamp() throws Exception { + Request request = new Request("POST", "/deep/_search"); + XContentBuilder body = JsonXContent.contentBuilder().prettyPrint().startObject(); + body.field("size", 0); + autoDateInMultiTerms(body, b -> { + b.startObject().field("field", field("kwd", 0)).endObject(); + b.startObject().field("field", "@timestamp").endObject(); + }); + request.setJsonEntity(Strings.toString(body.endObject())); + setTimeout(request); + try { + Map response = responseAsMap(client().performRequest(request)); + ListMatcher buckets = matchesList(); + for (int i = 0; i < 10; i++) { + buckets = buckets.item( + matchesMap().entry("key_as_string", any(String.class)) + .entry("key", hasSize(10)) + .entry("doc_count", 1) + .entry("adh", matchesMap().entry("buckets", hasSize(1)).entry("interval", "1s")) + ); + } + MapMatcher agg = matchesMap().entry("buckets", buckets) + .entry("doc_count_error_upper_bound", 0) + .entry("sum_other_doc_count", greaterThan(0)); + assertMap(response, matchesMap().extraOk().entry("aggregations", matchesMap().entry("multi", agg))); + } catch (SocketTimeoutException timeout) { + logger.info("timed out"); + assertNoSearchesRunning(); + } + } + + private void autoDateInMultiTerms(XContentBuilder body, CheckedConsumer terms) throws IOException { + body.startObject("aggs").startObject("multi"); + { + body.startObject("multi_terms"); + { + body.startArray("terms"); + terms.accept(body); + body.endArray(); + body.startArray("order"); + { + body.startObject().field("_count", "desc").endObject(); + body.startObject().field("_key", "asc").endObject(); + } + body.endArray(); + } + body.endObject(); + body.startObject("aggs").startObject("adh").startObject("auto_date_histogram"); + { + body.field("field", "@timestamp"); + body.field("buckets", 1); + } + body.endObject().endObject().endObject(); + } + body.endObject().endObject(); + } + + @Before + public void createDeep() throws IOException { + if (indexExists("deep")) { + return; + } + logger.info("creating deep index"); + XContentBuilder mapping = JsonXContent.contentBuilder().startObject(); + mapping.startObject("properties"); + mapping.startObject("@timestamp").field("type", "date").endObject(); + for (int f = 0; f < DEPTH; f++) { + mapping.startObject(field("kwd", f)).field("type", "keyword").endObject(); + } + CreateIndexResponse createIndexResponse = createIndex( + "deep", + Settings.builder().put("index.number_of_replicas", 0).build(), + Strings.toString(mapping.endObject().endObject()) + ); + assertThat(createIndexResponse.isAcknowledged(), equalTo(true)); + Bulk bulk = new Bulk(); + bulk.doc(new StringBuilder("{"), 0); + bulk.flush(); + + MapMatcher shardsOk = matchesMap().entry("total", 1).entry("failed", 0).entry("successful", 1); + logger.info("refreshing deep index"); + Map refresh = responseAsMap(client().performRequest(new Request("POST", "/_refresh"))); + assertMap(refresh, matchesMap().entry("_shards", shardsOk)); + + logger.info("double checking deep index count"); + Map count = responseAsMap(client().performRequest(new Request("POST", "/deep/_count"))); + assertMap(count, matchesMap().entry("_shards", shardsOk.entry("skipped", 0)).entry("count", TOTAL_DOCS)); + + logger.info("deep index ready for test"); + } + + private String field(String prefix, int field) { + return String.format(Locale.ROOT, "%s%03d", prefix, field); + } + + @Override + protected boolean preserveClusterUponCompletion() { + return true; + } + + class Bulk { + private static final int BULK_SIZE = Math.toIntExact(ByteSizeValue.ofMb(2).getBytes()); + + StringBuilder bulk = new StringBuilder(); + int current = 0; + int total = 0; + long timestamp = DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parseMillis("2025-01-01T00:00:00Z"); + + void doc(StringBuilder doc, int field) throws IOException { + if (field != 0) { + doc.append(','); + } + int len = doc.length(); + for (int value = 0; value < VALUE_COUNT; value++) { + doc.append('"').append(field("kwd", field)).append("\":\"").append(value).append('"'); + if (field == DEPTH - 1) { + doc.append(",\"@timestamp\":").append(timestamp).append('}'); + timestamp += TimeValue.timeValueMinutes(1).millis(); + addToBulk(doc); + } else { + doc(doc, field + 1); + } + doc.setLength(len); + } + } + + void addToBulk(StringBuilder doc) throws IOException { + current++; + total++; + bulk.append("{\"index\":{}}\n"); + bulk.append(doc).append('\n'); + if (bulk.length() > BULK_SIZE) { + flush(); + } + } + + void flush() throws IOException { + logger.info( + "Flushing to deep {} docs/{}. Total {}% {}/{}", + current, + ByteSizeValue.ofBytes(bulk.length()), + String.format(Locale.ROOT, "%04.1f", 100.0 * total / TOTAL_DOCS), + total, + TOTAL_DOCS + ); + Request request = new Request("POST", "/deep/_bulk"); + request.setJsonEntity(bulk.toString()); + Map response = responseAsMap(client().performRequest(request)); + assertMap(response, matchesMap().extraOk().entry("errors", false)); + bulk.setLength(0); + current = 0; + } + } + + private void setTimeout(Request request) { + RequestConfig.Builder config = RequestConfig.custom(); + config.setSocketTimeout(Math.toIntExact(TIMEOUT.millis())); + request.setOptions(request.getOptions().toBuilder().setRequestConfig(config.build())); + } + + /** + * Asserts that within a minute the _search has left the _tasks api. + *

+ * It'd sure be more convenient if, whenever the _search has returned + * back to us the _tasks API doesn't contain the _search. But sometimes + * it still does. So long as it stops eventually that's + * still indicative of the interrupt code working. + *

+ */ + private void assertNoSearchesRunning() throws Exception { + assertBusy(() -> { + Request tasks = new Request("GET", "/_tasks"); + tasks.addParameter("actions", "*search"); + tasks.addParameter("detailed", ""); + assertBusy(() -> { + Map response = responseAsMap(client().performRequest(tasks)); + // If there are running searches the map in `nodes` is non-empty. + if (response.isEmpty() == false) { + logger.warn("search still running, hot threads:\n{}", hotThreads()); + } + assertMap(response, matchesMap().entry("nodes", matchesMap())); + }); + }, 1, TimeUnit.MINUTES); + } + + private String hotThreads() throws IOException { + Request tasks = new Request("GET", "/_nodes/hot_threads"); + return EntityUtils.toString(client().performRequest(tasks).getEntity()); + } +} diff --git a/x-pack/plugin/async-search/src/internalClusterTest/java/org/elasticsearch/xpack/search/AsyncSearchErrorTraceIT.java b/x-pack/plugin/async-search/src/internalClusterTest/java/org/elasticsearch/xpack/search/AsyncSearchErrorTraceIT.java index 39a6fa1e4b34..8583844e76ae 100644 --- a/x-pack/plugin/async-search/src/internalClusterTest/java/org/elasticsearch/xpack/search/AsyncSearchErrorTraceIT.java +++ b/x-pack/plugin/async-search/src/internalClusterTest/java/org/elasticsearch/xpack/search/AsyncSearchErrorTraceIT.java @@ -7,15 +7,13 @@ package org.elasticsearch.xpack.search; -import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.client.Request; import org.elasticsearch.client.Response; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.core.TimeValue; import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.search.ErrorTraceHelper; import org.elasticsearch.test.ESIntegTestCase; -import org.elasticsearch.transport.TransportMessageListener; -import org.elasticsearch.transport.TransportService; import org.elasticsearch.xcontent.XContentType; import org.junit.Before; @@ -23,8 +21,7 @@ import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BooleanSupplier; public class AsyncSearchErrorTraceIT extends ESIntegTestCase { @@ -38,25 +35,11 @@ public class AsyncSearchErrorTraceIT extends ESIntegTestCase { return List.of(AsyncSearch.class); } - private AtomicBoolean transportMessageHasStackTrace; + private BooleanSupplier transportMessageHasStackTrace; @Before - private void setupMessageListener() { - internalCluster().getDataNodeInstances(TransportService.class).forEach(ts -> { - ts.addMessageListener(new TransportMessageListener() { - @Override - public void onResponseSent(long requestId, String action, Exception error) { - TransportMessageListener.super.onResponseSent(requestId, action, error); - if (action.startsWith("indices:data/read/search")) { - Optional throwable = ExceptionsHelper.unwrapCausesAndSuppressed( - error, - t -> t.getStackTrace().length > 0 - ); - transportMessageHasStackTrace.set(throwable.isPresent()); - } - } - }); - }); + public void setupMessageListener() { + transportMessageHasStackTrace = ErrorTraceHelper.setupErrorTraceListener(internalCluster()); } private void setupIndexWithDocs() { @@ -70,7 +53,6 @@ public class AsyncSearchErrorTraceIT extends ESIntegTestCase { } public void testAsyncSearchFailingQueryErrorTraceDefault() throws IOException, InterruptedException { - transportMessageHasStackTrace = new AtomicBoolean(); setupIndexWithDocs(); Request searchRequest = new Request("POST", "/_async_search"); @@ -93,11 +75,10 @@ public class AsyncSearchErrorTraceIT extends ESIntegTestCase { responseEntity = performRequestAndGetResponseEntityAfterDelay(request, TimeValue.timeValueSeconds(1L)); } // check that the stack trace was not sent from the data node to the coordinating node - assertFalse(transportMessageHasStackTrace.get()); + assertFalse(transportMessageHasStackTrace.getAsBoolean()); } public void testAsyncSearchFailingQueryErrorTraceTrue() throws IOException, InterruptedException { - transportMessageHasStackTrace = new AtomicBoolean(); setupIndexWithDocs(); Request searchRequest = new Request("POST", "/_async_search"); @@ -122,11 +103,10 @@ public class AsyncSearchErrorTraceIT extends ESIntegTestCase { responseEntity = performRequestAndGetResponseEntityAfterDelay(request, TimeValue.timeValueSeconds(1L)); } // check that the stack trace was sent from the data node to the coordinating node - assertTrue(transportMessageHasStackTrace.get()); + assertTrue(transportMessageHasStackTrace.getAsBoolean()); } public void testAsyncSearchFailingQueryErrorTraceFalse() throws IOException, InterruptedException { - transportMessageHasStackTrace = new AtomicBoolean(); setupIndexWithDocs(); Request searchRequest = new Request("POST", "/_async_search"); @@ -151,11 +131,10 @@ public class AsyncSearchErrorTraceIT extends ESIntegTestCase { responseEntity = performRequestAndGetResponseEntityAfterDelay(request, TimeValue.timeValueSeconds(1L)); } // check that the stack trace was not sent from the data node to the coordinating node - assertFalse(transportMessageHasStackTrace.get()); + assertFalse(transportMessageHasStackTrace.getAsBoolean()); } public void testAsyncSearchFailingQueryErrorTraceFalseOnSubmitAndTrueOnGet() throws IOException, InterruptedException { - transportMessageHasStackTrace = new AtomicBoolean(); setupIndexWithDocs(); Request searchRequest = new Request("POST", "/_async_search"); @@ -180,11 +159,10 @@ public class AsyncSearchErrorTraceIT extends ESIntegTestCase { responseEntity = performRequestAndGetResponseEntityAfterDelay(request, TimeValue.timeValueSeconds(1L)); } // check that the stack trace was not sent from the data node to the coordinating node - assertFalse(transportMessageHasStackTrace.get()); + assertFalse(transportMessageHasStackTrace.getAsBoolean()); } public void testAsyncSearchFailingQueryErrorTraceTrueOnSubmitAndFalseOnGet() throws IOException, InterruptedException { - transportMessageHasStackTrace = new AtomicBoolean(); setupIndexWithDocs(); Request searchRequest = new Request("POST", "/_async_search"); @@ -209,7 +187,7 @@ public class AsyncSearchErrorTraceIT extends ESIntegTestCase { responseEntity = performRequestAndGetResponseEntityAfterDelay(request, TimeValue.timeValueSeconds(1L)); } // check that the stack trace was sent from the data node to the coordinating node - assertTrue(transportMessageHasStackTrace.get()); + assertTrue(transportMessageHasStackTrace.getAsBoolean()); } private Map performRequestAndGetResponseEntityAfterDelay(Request r, TimeValue sleep) throws IOException, diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java index 3b4d4aec776d..c2d157e512a2 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java @@ -317,7 +317,7 @@ public class XPackSettings { }, Property.NodeScope); } - public static final List DEFAULT_SUPPORTED_PROTOCOLS = Arrays.asList("TLSv1.3", "TLSv1.2", "TLSv1.1"); + public static final List DEFAULT_SUPPORTED_PROTOCOLS = Arrays.asList("TLSv1.3", "TLSv1.2"); public static final SslClientAuthenticationMode CLIENT_AUTH_DEFAULT = SslClientAuthenticationMode.REQUIRED; public static final SslClientAuthenticationMode HTTP_CLIENT_AUTH_DEFAULT = SslClientAuthenticationMode.NONE; diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/async/AsyncTaskIndexService.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/async/AsyncTaskIndexService.java index fe970bef8714..199354507597 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/async/AsyncTaskIndexService.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/async/AsyncTaskIndexService.java @@ -391,6 +391,22 @@ public final class AsyncTaskIndexService> { TaskManager taskManager, AsyncExecutionId asyncExecutionId, Class tClass + ) throws IOException { + return getTaskAndCheckAuthentication(taskManager, security, asyncExecutionId, tClass); + } + + /** + * Returns the {@link AsyncTask} if the provided asyncTaskId + * is registered in the task manager, null otherwise. + * + * This method throws a {@link ResourceNotFoundException} if the authenticated user + * is not the creator of the original task. + */ + public static T getTaskAndCheckAuthentication( + TaskManager taskManager, + AsyncSearchSecurity security, + AsyncExecutionId asyncExecutionId, + Class tClass ) throws IOException { T asyncTask = getTask(taskManager, asyncExecutionId, tClass); if (asyncTask == null) { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/common/notifications/AbstractAuditor.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/common/notifications/AbstractAuditor.java index f5c9f4845407..26ad24d80e14 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/common/notifications/AbstractAuditor.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/common/notifications/AbstractAuditor.java @@ -19,6 +19,7 @@ import org.elasticsearch.client.internal.OriginSettingClient; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.core.TimeValue; +import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xpack.core.ml.utils.MlIndexAndAlias; @@ -28,6 +29,7 @@ import java.util.Date; import java.util.Objects; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicBoolean; import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder; @@ -51,6 +53,7 @@ public abstract class AbstractAuditor { private Queue backlog; private final AtomicBoolean indexAndAliasCreationInProgress; + private final ExecutorService executorService; protected AbstractAuditor( OriginSettingClient client, @@ -58,7 +61,8 @@ public abstract class AbstractAuditor { String nodeName, AbstractAuditMessageFactory messageFactory, ClusterService clusterService, - IndexNameExpressionResolver indexNameExpressionResolver + IndexNameExpressionResolver indexNameExpressionResolver, + ExecutorService executorService ) { this.client = Objects.requireNonNull(client); this.auditIndexWriteAlias = Objects.requireNonNull(auditIndexWriteAlias); @@ -69,6 +73,7 @@ public abstract class AbstractAuditor { this.backlog = new ConcurrentLinkedQueue<>(); this.indexAndAliasCreated = new AtomicBoolean(); this.indexAndAliasCreationInProgress = new AtomicBoolean(); + this.executorService = executorService; } public void audit(Level level, String resourceId, String message) { @@ -148,7 +153,16 @@ public abstract class AbstractAuditor { } private void writeDoc(ToXContent toXContent) { - client.index(indexRequest(toXContent), ActionListener.wrap(AbstractAuditor::onIndexResponse, AbstractAuditor::onIndexFailure)); + client.index(indexRequest(toXContent), ActionListener.wrap(AbstractAuditor::onIndexResponse, e -> { + if (e instanceof IndexNotFoundException) { + executorService.execute(() -> { + reset(); + indexDoc(toXContent); + }); + } else { + onIndexFailure(e); + } + })); } private IndexRequest indexRequest(ToXContent toXContent) { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/InferenceAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/InferenceAction.java index f88909ba4208..f2b2c563d751 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/InferenceAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/InferenceAction.java @@ -47,7 +47,7 @@ import static org.elasticsearch.core.Strings.format; public class InferenceAction extends ActionType { public static final InferenceAction INSTANCE = new InferenceAction(); - public static final String NAME = "cluster:monitor/xpack/inference"; + public static final String NAME = "cluster:internal/xpack/inference"; public InferenceAction() { super(NAME); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/InferenceActionProxy.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/InferenceActionProxy.java new file mode 100644 index 000000000000..68cd39f26b45 --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/InferenceActionProxy.java @@ -0,0 +1,133 @@ +/* + * 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.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.ActionType; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.core.TimeValue; +import org.elasticsearch.inference.TaskType; +import org.elasticsearch.xcontent.XContentType; + +import java.io.IOException; +import java.util.Objects; + +/** + * This action is used when making a REST request to the inference API. The transport handler + * will then look at the task type in the params (or retrieve it from the persisted model if it wasn't + * included in the params) to determine where this request should be routed. If the task type is chat completion + * then it will be routed to the unified chat completion handler by creating the {@link UnifiedCompletionAction}. + * If not, it will be passed along to {@link InferenceAction}. + */ +public class InferenceActionProxy extends ActionType { + public static final InferenceActionProxy INSTANCE = new InferenceActionProxy(); + public static final String NAME = "cluster:monitor/xpack/inference/post"; + + public InferenceActionProxy() { + super(NAME); + } + + public static class Request extends ActionRequest { + + private final TaskType taskType; + private final String inferenceEntityId; + private final BytesReference content; + private final XContentType contentType; + private final TimeValue timeout; + private final boolean stream; + + public Request( + TaskType taskType, + String inferenceEntityId, + BytesReference content, + XContentType contentType, + TimeValue timeout, + boolean stream + ) { + this.taskType = taskType; + this.inferenceEntityId = inferenceEntityId; + this.content = content; + this.contentType = contentType; + this.timeout = timeout; + this.stream = stream; + } + + public Request(StreamInput in) throws IOException { + super(in); + this.taskType = TaskType.fromStream(in); + this.inferenceEntityId = in.readString(); + this.content = in.readBytesReference(); + this.contentType = in.readEnum(XContentType.class); + this.timeout = in.readTimeValue(); + + // streaming is not supported yet for transport traffic + this.stream = false; + } + + public TaskType getTaskType() { + return taskType; + } + + public String getInferenceEntityId() { + return inferenceEntityId; + } + + public BytesReference getContent() { + return content; + } + + public XContentType getContentType() { + return contentType; + } + + public TimeValue getTimeout() { + return timeout; + } + + public boolean isStreaming() { + return stream; + } + + @Override + public ActionRequestValidationException validate() { + return null; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeString(inferenceEntityId); + taskType.writeTo(out); + out.writeBytesReference(content); + XContentHelper.writeTo(out, contentType); + out.writeTimeValue(timeout); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Request request = (Request) o; + return taskType == request.taskType + && Objects.equals(inferenceEntityId, request.inferenceEntityId) + && Objects.equals(content, request.content) + && contentType == request.contentType + && timeout == request.timeout + && stream == request.stream; + } + + @Override + public int hashCode() { + return Objects.hash(taskType, inferenceEntityId, content, contentType, timeout, stream); + } + } +} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/UnifiedCompletionAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/UnifiedCompletionAction.java index f5c852a0450a..43c84ad914c2 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/UnifiedCompletionAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/UnifiedCompletionAction.java @@ -21,7 +21,7 @@ import java.util.Objects; public class UnifiedCompletionAction extends ActionType { public static final UnifiedCompletionAction INSTANCE = new UnifiedCompletionAction(); - public static final String NAME = "cluster:monitor/xpack/inference/unified"; + public static final String NAME = "cluster:internal/xpack/inference/unified"; public UnifiedCompletionAction() { super(NAME); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/UpdateInferenceModelAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/UpdateInferenceModelAction.java index cc59ae890467..505d058394db 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/UpdateInferenceModelAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/action/UpdateInferenceModelAction.java @@ -70,8 +70,8 @@ public class UpdateInferenceModelAction extends ActionType auditor = createTestAuditorWithoutTemplate( + writeSomeDocsBeforeTemplateLatch + ); + + auditor.info("foobar", "Here is my info to queue"); + + verify(client, never()).execute(eq(TransportIndexAction.TYPE), any(), any()); + // fire the put template response + writeSomeDocsBeforeTemplateLatch.countDown(); + + assertBusy(() -> verify(client, times(1)).execute(eq(TransportPutComposableIndexTemplateAction.TYPE), any(), any())); + assertBusy(() -> verify(client, times(1)).execute(eq(TransportCreateIndexAction.TYPE), any(), any())); + + // the back log will be written some point later + assertBusy(() -> verify(client, times(1)).execute(eq(TransportBulkAction.TYPE), any(), any())); + + // "delete" the index + doAnswer(ans -> { + ActionListener listener = ans.getArgument(2); + listener.onFailure(new IndexNotFoundException("some index")); + return null; + }).when(client).execute(eq(TransportIndexAction.TYPE), any(), any()); + + // audit more data + auditor.info("foobar", "Here is another message"); + + // verify the template is recreated and the audit message is processed + assertBusy(() -> verify(client, times(2)).execute(eq(TransportPutComposableIndexTemplateAction.TYPE), any(), any())); + assertBusy(() -> verify(client, times(2)).execute(eq(TransportCreateIndexAction.TYPE), any(), any())); + assertBusy(() -> verify(client, times(2)).execute(eq(TransportBulkAction.TYPE), any(), any())); + } + public void testMaxBufferSize() throws Exception { CountDownLatch writeSomeDocsBeforeTemplateLatch = new CountDownLatch(1); AbstractAuditor auditor = createTestAuditorWithoutTemplate( @@ -358,7 +394,8 @@ public class AbstractAuditorTests extends ESTestCase { nodeName, AbstractAuditMessageTests.TestAuditMessage::new, clusterService, - TestIndexNameExpressionResolver.newInstance() + TestIndexNameExpressionResolver.newInstance(), + EsExecutors.DIRECT_EXECUTOR_SERVICE ); } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java index f78a39208429..0dec67f3939e 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java @@ -4141,7 +4141,7 @@ public class ReservedRolesStoreTests extends ESTestCase { assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true)); Role role = Role.buildFromRoleDescriptor(roleDescriptor, new FieldPermissionsCache(Settings.EMPTY), RESTRICTED_INDICES); - assertTrue(role.cluster().check("cluster:monitor/xpack/inference", request, authentication)); + assertTrue(role.cluster().check("cluster:monitor/xpack/inference/post", request, authentication)); assertTrue(role.cluster().check("cluster:monitor/xpack/inference/get", request, authentication)); assertTrue(role.cluster().check("cluster:admin/xpack/inference/put", request, authentication)); assertTrue(role.cluster().check("cluster:admin/xpack/inference/delete", request, authentication)); @@ -4161,10 +4161,9 @@ public class ReservedRolesStoreTests extends ESTestCase { assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true)); Role role = Role.buildFromRoleDescriptor(roleDescriptor, new FieldPermissionsCache(Settings.EMPTY), RESTRICTED_INDICES); - assertTrue(role.cluster().check("cluster:monitor/xpack/inference", request, authentication)); + assertTrue(role.cluster().check("cluster:monitor/xpack/inference/post", request, authentication)); assertTrue(role.cluster().check("cluster:monitor/xpack/inference/get", request, authentication)); assertFalse(role.cluster().check("cluster:admin/xpack/inference/put", request, authentication)); - assertTrue(role.cluster().check("cluster:monitor/xpack/inference/unified", request, authentication)); assertFalse(role.cluster().check("cluster:admin/xpack/inference/delete", request, authentication)); assertTrue(role.cluster().check("cluster:monitor/xpack/ml/trained_models/deployment/infer", request, authentication)); assertFalse(role.cluster().check("cluster:admin/xpack/ml/trained_models/deployment/start", request, authentication)); diff --git a/x-pack/plugin/deprecation/src/main/java/org/elasticsearch/xpack/deprecation/TemplateDeprecationChecker.java b/x-pack/plugin/deprecation/src/main/java/org/elasticsearch/xpack/deprecation/TemplateDeprecationChecker.java index a859c204fb99..ce29c0dd6cd7 100644 --- a/x-pack/plugin/deprecation/src/main/java/org/elasticsearch/xpack/deprecation/TemplateDeprecationChecker.java +++ b/x-pack/plugin/deprecation/src/main/java/org/elasticsearch/xpack/deprecation/TemplateDeprecationChecker.java @@ -122,9 +122,9 @@ public class TemplateDeprecationChecker implements ResourceDeprecationChecker { if (sourceMap.containsKey("mode")) { return new DeprecationIssue( DeprecationIssue.Level.CRITICAL, + SourceFieldMapper.DEPRECATION_WARNING_TITLE, + "https://ela.st/migrate-source-mode", SourceFieldMapper.DEPRECATION_WARNING, - "https://github.com/elastic/elasticsearch/pull/117172", - null, false, null ); diff --git a/x-pack/plugin/deprecation/src/test/java/org/elasticsearch/xpack/deprecation/TemplateDeprecationCheckerTests.java b/x-pack/plugin/deprecation/src/test/java/org/elasticsearch/xpack/deprecation/TemplateDeprecationCheckerTests.java index 69bb396a50a9..4e1b28b34128 100644 --- a/x-pack/plugin/deprecation/src/test/java/org/elasticsearch/xpack/deprecation/TemplateDeprecationCheckerTests.java +++ b/x-pack/plugin/deprecation/src/test/java/org/elasticsearch/xpack/deprecation/TemplateDeprecationCheckerTests.java @@ -51,9 +51,9 @@ public class TemplateDeprecationCheckerTests extends ESTestCase { Map> issuesByComponentTemplate = checker.check(clusterState); final DeprecationIssue expected = new DeprecationIssue( DeprecationIssue.Level.CRITICAL, + SourceFieldMapper.DEPRECATION_WARNING_TITLE, + "https://ela.st/migrate-source-mode", SourceFieldMapper.DEPRECATION_WARNING, - "https://github.com/elastic/elasticsearch/pull/117172", - null, false, null ); diff --git a/x-pack/plugin/downsample/src/internalClusterTest/java/org/elasticsearch/xpack/downsample/DataStreamLifecycleDownsampleDisruptionIT.java b/x-pack/plugin/downsample/src/internalClusterTest/java/org/elasticsearch/xpack/downsample/DataStreamLifecycleDownsampleDisruptionIT.java index afa2e95e1284..917ce781fb1f 100644 --- a/x-pack/plugin/downsample/src/internalClusterTest/java/org/elasticsearch/xpack/downsample/DataStreamLifecycleDownsampleDisruptionIT.java +++ b/x-pack/plugin/downsample/src/internalClusterTest/java/org/elasticsearch/xpack/downsample/DataStreamLifecycleDownsampleDisruptionIT.java @@ -119,7 +119,7 @@ public class DataStreamLifecycleDownsampleDisruptionIT extends ESIntegTestCase { } catch (Exception e) { throw new AssertionError(e); } - }, 60, TimeUnit.SECONDS); + }, 120, TimeUnit.SECONDS); ensureGreen(targetIndex); } } diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java index cbede5871f27..ccaf4ce3a886 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java @@ -71,6 +71,9 @@ public class Verifier { // start bottom-up plan.forEachUp(p -> { + if (p.getClass().equals(Join.class)) { + failures.add(fail(p, "JOIN command is not supported")); + } if (p.analyzed()) { return; } diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java index bec71a984656..887132ab729e 100644 --- a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java @@ -368,6 +368,13 @@ public class VerifierTests extends ESTestCase { accept(idxr, "foo where serial_event_id == 0"); } + public void testJoinCommand() { + final IndexResolution idxr = loadIndexResolution("mapping-ip.json"); + + assertEquals("1:1: JOIN command is not supported", error(idxr, "join [any where true] [any where true]")); + assertEquals("1:1: JOIN command is not supported", error(idxr, "join [any where true] [any where true] | tail 3")); + } + public void testMultiField() { final IndexResolution idxr = loadIndexResolution("mapping-multi-field.json"); accept(idxr, "foo where multi_field.raw == \"bar\""); diff --git a/x-pack/plugin/esql/compute/ann/src/main/java/org/elasticsearch/compute/ann/Aggregator.java b/x-pack/plugin/esql/compute/ann/src/main/java/org/elasticsearch/compute/ann/Aggregator.java index 794baf175920..cdff28acecdb 100644 --- a/x-pack/plugin/esql/compute/ann/src/main/java/org/elasticsearch/compute/ann/Aggregator.java +++ b/x-pack/plugin/esql/compute/ann/src/main/java/org/elasticsearch/compute/ann/Aggregator.java @@ -39,11 +39,8 @@ import java.lang.annotation.Target; *

* The generation code also looks for the optional methods {@code combineIntermediate} * and {@code evaluateFinal} which are used to combine intermediate states and - * produce the final output. If the first is missing then the generated code will - * call the {@code combine} method to combine intermediate states. If the second - * is missing the generated code will make a block containing the primitive from - * the state. If either of those don't have sensible interpretations then the code - * generation code will throw an error, aborting the compilation. + * produce the final output. Please note, those are auto-generated when aggregating + * primitive types such as boolean, int, long, float, double. *

*/ @Target(ElementType.TYPE) @@ -58,4 +55,8 @@ public @interface Aggregator { */ Class[] warnExceptions() default {}; + /** + * If {@code true} then the @timestamp LongVector will be appended to the input blocks of the aggregation function. + */ + boolean includeTimestamps() default false; } diff --git a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/AggregatorFunctionSupplierImplementer.java b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/AggregatorFunctionSupplierImplementer.java index 9c70b7f4cac7..52e4e66f3848 100644 --- a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/AggregatorFunctionSupplierImplementer.java +++ b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/AggregatorFunctionSupplierImplementer.java @@ -31,6 +31,7 @@ import javax.lang.model.util.Elements; import static org.elasticsearch.compute.gen.Types.AGGREGATOR_FUNCTION_SUPPLIER; import static org.elasticsearch.compute.gen.Types.DRIVER_CONTEXT; +import static org.elasticsearch.compute.gen.Types.LIST_AGG_FUNC_DESC; import static org.elasticsearch.compute.gen.Types.LIST_INTEGER; import static org.elasticsearch.compute.gen.Types.STRING; import static org.elasticsearch.compute.gen.Types.WARNINGS; @@ -67,7 +68,6 @@ public class AggregatorFunctionSupplierImplementer { createParameters.addAll(groupingAggregatorImplementer.createParameters()); } this.createParameters = new ArrayList<>(createParameters); - this.createParameters.add(0, new Parameter(LIST_INTEGER, "channels")); this.implementation = ClassName.get( elements.getPackageOf(declarationType).toString(), @@ -99,11 +99,9 @@ public class AggregatorFunctionSupplierImplementer { } createParameters.stream().forEach(p -> p.declareField(builder)); builder.addMethod(ctor()); - if (aggregatorImplementer != null) { - builder.addMethod(aggregator()); - } else { - builder.addMethod(unsupportedNonGroupingAggregator()); - } + builder.addMethod(nonGroupingIntermediateStateDesc()); + builder.addMethod(groupingIntermediateStateDesc()); + builder.addMethod(aggregator()); builder.addMethod(groupingAggregator()); builder.addMethod(describe()); return builder.build(); @@ -123,12 +121,28 @@ public class AggregatorFunctionSupplierImplementer { return builder.build(); } - private MethodSpec unsupportedNonGroupingAggregator() { - MethodSpec.Builder builder = MethodSpec.methodBuilder("aggregator") - .addParameter(DRIVER_CONTEXT, "driverContext") - .returns(Types.AGGREGATOR_FUNCTION); + private MethodSpec nonGroupingIntermediateStateDesc() { + MethodSpec.Builder builder = MethodSpec.methodBuilder("nonGroupingIntermediateStateDesc"); builder.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC); - builder.addStatement("throw new UnsupportedOperationException($S)", "non-grouping aggregator is not supported"); + builder.returns(LIST_AGG_FUNC_DESC); + + if (aggregatorImplementer == null) { + builder.addStatement("throw new UnsupportedOperationException($S)", "non-grouping aggregator is not supported"); + return builder.build(); + } + + builder.addStatement("return $T.intermediateStateDesc()", aggregatorImplementer.implementation()); + + return builder.build(); + } + + private MethodSpec groupingIntermediateStateDesc() { + MethodSpec.Builder builder = MethodSpec.methodBuilder("groupingIntermediateStateDesc"); + builder.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC); + builder.returns(LIST_AGG_FUNC_DESC); + + builder.addStatement("return $T.intermediateStateDesc()", groupingAggregatorImplementer.implementation()); + return builder.build(); } @@ -136,6 +150,14 @@ public class AggregatorFunctionSupplierImplementer { MethodSpec.Builder builder = MethodSpec.methodBuilder("aggregator"); builder.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC); builder.addParameter(DRIVER_CONTEXT, "driverContext"); + builder.addParameter(LIST_INTEGER, "channels"); + + if (aggregatorImplementer == null) { + builder.returns(Types.AGGREGATOR_FUNCTION); + builder.addStatement("throw new UnsupportedOperationException($S)", "non-grouping aggregator is not supported"); + return builder.build(); + } + builder.returns(aggregatorImplementer.implementation()); if (hasWarnings) { @@ -162,6 +184,7 @@ public class AggregatorFunctionSupplierImplementer { MethodSpec.Builder builder = MethodSpec.methodBuilder("groupingAggregator"); builder.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC); builder.addParameter(DRIVER_CONTEXT, "driverContext"); + builder.addParameter(LIST_INTEGER, "channels"); builder.returns(groupingAggregatorImplementer.implementation()); if (hasWarnings) { diff --git a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/AggregatorImplementer.java b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/AggregatorImplementer.java index c62dc9ed24d8..8a02f8bc4c69 100644 --- a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/AggregatorImplementer.java +++ b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/AggregatorImplementer.java @@ -17,12 +17,12 @@ import com.squareup.javapoet.TypeSpec; import org.elasticsearch.compute.ann.Aggregator; import org.elasticsearch.compute.ann.IntermediateState; +import org.elasticsearch.compute.gen.Methods.TypeMatcher; import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Objects; -import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -34,27 +34,24 @@ import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import static java.util.stream.Collectors.joining; -import static org.elasticsearch.compute.gen.Methods.findMethod; -import static org.elasticsearch.compute.gen.Methods.findRequiredMethod; +import static org.elasticsearch.compute.gen.Methods.requireAnyArgs; +import static org.elasticsearch.compute.gen.Methods.requireAnyType; +import static org.elasticsearch.compute.gen.Methods.requireArgs; +import static org.elasticsearch.compute.gen.Methods.requireName; +import static org.elasticsearch.compute.gen.Methods.requirePrimitiveOrImplements; +import static org.elasticsearch.compute.gen.Methods.requireStaticMethod; +import static org.elasticsearch.compute.gen.Methods.requireType; +import static org.elasticsearch.compute.gen.Methods.requireVoidType; import static org.elasticsearch.compute.gen.Methods.vectorAccessorName; import static org.elasticsearch.compute.gen.Types.AGGREGATOR_FUNCTION; import static org.elasticsearch.compute.gen.Types.BIG_ARRAYS; import static org.elasticsearch.compute.gen.Types.BLOCK; import static org.elasticsearch.compute.gen.Types.BLOCK_ARRAY; -import static org.elasticsearch.compute.gen.Types.BOOLEAN_BLOCK; import static org.elasticsearch.compute.gen.Types.BOOLEAN_VECTOR; import static org.elasticsearch.compute.gen.Types.BYTES_REF; -import static org.elasticsearch.compute.gen.Types.BYTES_REF_BLOCK; -import static org.elasticsearch.compute.gen.Types.BYTES_REF_VECTOR; -import static org.elasticsearch.compute.gen.Types.DOUBLE_BLOCK; -import static org.elasticsearch.compute.gen.Types.DOUBLE_VECTOR; import static org.elasticsearch.compute.gen.Types.DRIVER_CONTEXT; import static org.elasticsearch.compute.gen.Types.ELEMENT_TYPE; -import static org.elasticsearch.compute.gen.Types.FLOAT_BLOCK; -import static org.elasticsearch.compute.gen.Types.FLOAT_VECTOR; import static org.elasticsearch.compute.gen.Types.INTERMEDIATE_STATE_DESC; -import static org.elasticsearch.compute.gen.Types.INT_BLOCK; -import static org.elasticsearch.compute.gen.Types.INT_VECTOR; import static org.elasticsearch.compute.gen.Types.LIST_AGG_FUNC_DESC; import static org.elasticsearch.compute.gen.Types.LIST_INTEGER; import static org.elasticsearch.compute.gen.Types.LONG_BLOCK; @@ -78,44 +75,42 @@ public class AggregatorImplementer { private final List warnExceptions; private final ExecutableElement init; private final ExecutableElement combine; - private final ExecutableElement combineIntermediate; - private final ExecutableElement evaluateFinal; - private final ClassName implementation; - private final TypeName stateType; - private final boolean stateTypeHasSeen; - private final boolean stateTypeHasFailed; - private final boolean valuesIsBytesRef; - private final boolean valuesIsArray; - private final List intermediateState; private final List createParameters; + private final ClassName implementation; + private final List intermediateState; + private final boolean includeTimestampVector; + + private final AggregationState aggState; + private final AggregationParameter aggParam; public AggregatorImplementer( Elements elements, TypeElement declarationType, IntermediateState[] interStateAnno, - List warnExceptions + List warnExceptions, + boolean includeTimestampVector ) { this.declarationType = declarationType; this.warnExceptions = warnExceptions; - this.init = findRequiredMethod(declarationType, new String[] { "init", "initSingle" }, e -> true); - this.stateType = choseStateType(); - this.stateTypeHasSeen = elements.getAllMembers(elements.getTypeElement(stateType.toString())) - .stream() - .anyMatch(e -> e.toString().equals("seen()")); - this.stateTypeHasFailed = elements.getAllMembers(elements.getTypeElement(stateType.toString())) - .stream() - .anyMatch(e -> e.toString().equals("failed()")); + this.init = requireStaticMethod( + declarationType, + // This should be more restrictive and require org.elasticsearch.compute.aggregation.AggregatorState + requirePrimitiveOrImplements(elements, Types.RELEASABLE), + requireName("init", "initSingle"), + requireAnyArgs("") + ); + this.aggState = AggregationState.create(elements, init.getReturnType(), warnExceptions.isEmpty() == false, false); + + this.combine = requireStaticMethod( + declarationType, + aggState.declaredType().isPrimitive() ? requireType(aggState.declaredType()) : requireVoidType(), + requireName("combine"), + combineArgs(aggState, includeTimestampVector) + ); + // TODO support multiple parameters + this.aggParam = AggregationParameter.create(combine.getParameters().getLast().asType()); - this.combine = findRequiredMethod(declarationType, new String[] { "combine" }, e -> { - if (e.getParameters().size() == 0) { - return false; - } - TypeName firstParamType = TypeName.get(e.getParameters().get(0).asType()); - return firstParamType.isPrimitive() || firstParamType.toString().equals(stateType.toString()); - }); - this.combineIntermediate = findMethod(declarationType, "combineIntermediate"); - this.evaluateFinal = findMethod(declarationType, "evaluateFinal"); this.createParameters = init.getParameters() .stream() .map(Parameter::from) @@ -126,9 +121,20 @@ public class AggregatorImplementer { elements.getPackageOf(declarationType).toString(), (declarationType.getSimpleName() + "AggregatorFunction").replace("AggregatorAggregator", "Aggregator") ); - this.valuesIsBytesRef = BYTES_REF.equals(valueTypeName()); - this.valuesIsArray = TypeKind.ARRAY.equals(valueTypeKind()); - intermediateState = Arrays.stream(interStateAnno).map(IntermediateStateDesc::newIntermediateStateDesc).toList(); + this.intermediateState = Arrays.stream(interStateAnno).map(IntermediateStateDesc::newIntermediateStateDesc).toList(); + this.includeTimestampVector = includeTimestampVector; + } + + private static Methods.ArgumentMatcher combineArgs(AggregationState aggState, boolean includeTimestampVector) { + if (includeTimestampVector) { + return requireArgs( + requireType(aggState.declaredType()), + requireType(TypeName.LONG), // @timestamp + requireAnyType("") + ); + } else { + return requireArgs(requireType(aggState.declaredType()), requireAnyType("")); + } } ClassName implementation() { @@ -139,68 +145,8 @@ public class AggregatorImplementer { return createParameters; } - private TypeName choseStateType() { - TypeName initReturn = TypeName.get(init.getReturnType()); - if (false == initReturn.isPrimitive()) { - return initReturn; - } - String simpleName = firstUpper(initReturn.toString()); - if (warnExceptions.isEmpty()) { - return ClassName.get("org.elasticsearch.compute.aggregation", simpleName + "State"); - } - return ClassName.get("org.elasticsearch.compute.aggregation", simpleName + "FallibleState"); - } - - static String valueType(ExecutableElement init, ExecutableElement combine) { - if (combine != null) { - // If there's an explicit combine function it's final parameter is the type of the value. - return combine.getParameters().get(combine.getParameters().size() - 1).asType().toString(); - } - String initReturn = init.getReturnType().toString(); - switch (initReturn) { - case "double": - return "double"; - case "float": - return "float"; - case "long": - return "long"; - case "int": - return "int"; - case "boolean": - return "boolean"; - default: - throw new IllegalArgumentException("unknown primitive type for " + initReturn); - } - } - - static ClassName valueBlockType(ExecutableElement init, ExecutableElement combine) { - return switch (valueType(init, combine)) { - case "boolean" -> BOOLEAN_BLOCK; - case "double" -> DOUBLE_BLOCK; - case "float" -> FLOAT_BLOCK; - case "long" -> LONG_BLOCK; - case "int", "int[]" -> INT_BLOCK; - case "org.apache.lucene.util.BytesRef" -> BYTES_REF_BLOCK; - default -> throw new IllegalArgumentException("unknown block type for " + valueType(init, combine)); - }; - } - - static ClassName valueVectorType(ExecutableElement init, ExecutableElement combine) { - return switch (valueType(init, combine)) { - case "boolean" -> BOOLEAN_VECTOR; - case "double" -> DOUBLE_VECTOR; - case "float" -> FLOAT_VECTOR; - case "long" -> LONG_VECTOR; - case "int", "int[]" -> INT_VECTOR; - case "org.apache.lucene.util.BytesRef" -> BYTES_REF_VECTOR; - default -> throw new IllegalArgumentException("unknown vector type for " + valueType(init, combine)); - }; - } - - public static String firstUpper(String s) { - String head = s.toString().substring(0, 1).toUpperCase(Locale.ROOT); - String tail = s.toString().substring(1); - return head + tail; + public static String capitalize(String s) { + return Character.toUpperCase(s.charAt(0)) + s.substring(1); } public JavaFile sourceFile() { @@ -230,7 +176,7 @@ public class AggregatorImplementer { } builder.addField(DRIVER_CONTEXT, "driverContext", Modifier.PRIVATE, Modifier.FINAL); - builder.addField(stateType, "state", Modifier.PRIVATE, Modifier.FINAL); + builder.addField(aggState.type, "state", Modifier.PRIVATE, Modifier.FINAL); builder.addField(LIST_INTEGER, "channels", Modifier.PRIVATE, Modifier.FINAL); for (Parameter p : createParameters) { @@ -290,10 +236,10 @@ public class AggregatorImplementer { .map(p -> TypeName.get(p.asType()).equals(BIG_ARRAYS) ? "driverContext.bigArrays()" : p.getSimpleName().toString()) .collect(joining(", ")); CodeBlock.Builder builder = CodeBlock.builder(); - if (init.getReturnType().toString().equals(stateType.toString())) { - builder.add("$T.$L($L)", declarationType, init.getSimpleName(), initParametersCall); + if (aggState.declaredType().isPrimitive()) { + builder.add("new $T($T.$L($L))", aggState.type(), declarationType, init.getSimpleName(), initParametersCall); } else { - builder.add("new $T($T.$L($L))", stateType, declarationType, init.getSimpleName(), initParametersCall); + builder.add("$T.$L($L)", declarationType, init.getSimpleName(), initParametersCall); } return builder.build(); } @@ -318,7 +264,7 @@ public class AggregatorImplementer { } builder.addParameter(DRIVER_CONTEXT, "driverContext"); builder.addParameter(LIST_INTEGER, "channels"); - builder.addParameter(stateType, "state"); + builder.addParameter(aggState.type, "state"); if (warnExceptions.isEmpty() == false) { builder.addStatement("this.warnings = warnings"); @@ -350,7 +296,7 @@ public class AggregatorImplementer { private MethodSpec addRawInput() { MethodSpec.Builder builder = MethodSpec.methodBuilder("addRawInput"); builder.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).addParameter(PAGE, "page").addParameter(BOOLEAN_VECTOR, "mask"); - if (stateTypeHasFailed) { + if (aggState.hasFailed()) { builder.beginControlFlow("if (state.failed())"); builder.addStatement("return"); builder.endControlFlow(); @@ -364,43 +310,62 @@ public class AggregatorImplementer { builder.beginControlFlow("if (mask.allTrue())"); { builder.addComment("No masking"); - builder.addStatement("$T block = page.getBlock(channels.get(0))", valueBlockType(init, combine)); - builder.addStatement("$T vector = block.asVector()", valueVectorType(init, combine)); + builder.addStatement("$T block = page.getBlock(channels.get(0))", blockType(aggParam.type())); + builder.addStatement("$T vector = block.asVector()", vectorType(aggParam.type())); + if (includeTimestampVector) { + builder.addStatement("$T timestampsBlock = page.getBlock(channels.get(1))", LONG_BLOCK); + builder.addStatement("$T timestampsVector = timestampsBlock.asVector()", LONG_VECTOR); + + builder.beginControlFlow("if (timestampsVector == null) "); + builder.addStatement("throw new IllegalStateException($S)", "expected @timestamp vector; but got a block"); + builder.endControlFlow(); + } builder.beginControlFlow("if (vector != null)"); - builder.addStatement("addRawVector(vector)"); + builder.addStatement(includeTimestampVector ? "addRawVector(vector, timestampsVector)" : "addRawVector(vector)"); builder.nextControlFlow("else"); - builder.addStatement("addRawBlock(block)"); + builder.addStatement(includeTimestampVector ? "addRawBlock(block, timestampsVector)" : "addRawBlock(block)"); builder.endControlFlow(); builder.addStatement("return"); } builder.endControlFlow(); builder.addComment("Some positions masked away, others kept"); - builder.addStatement("$T block = page.getBlock(channels.get(0))", valueBlockType(init, combine)); - builder.addStatement("$T vector = block.asVector()", valueVectorType(init, combine)); + builder.addStatement("$T block = page.getBlock(channels.get(0))", blockType(aggParam.type())); + builder.addStatement("$T vector = block.asVector()", vectorType(aggParam.type())); + if (includeTimestampVector) { + builder.addStatement("$T timestampsBlock = page.getBlock(channels.get(1))", LONG_BLOCK); + builder.addStatement("$T timestampsVector = timestampsBlock.asVector()", LONG_VECTOR); + + builder.beginControlFlow("if (timestampsVector == null) "); + builder.addStatement("throw new IllegalStateException($S)", "expected @timestamp vector; but got a block"); + builder.endControlFlow(); + } builder.beginControlFlow("if (vector != null)"); - builder.addStatement("addRawVector(vector, mask)"); + builder.addStatement(includeTimestampVector ? "addRawVector(vector, timestampsVector, mask)" : "addRawVector(vector, mask)"); builder.nextControlFlow("else"); - builder.addStatement("addRawBlock(block, mask)"); + builder.addStatement(includeTimestampVector ? "addRawBlock(block, timestampsVector, mask)" : "addRawBlock(block, mask)"); builder.endControlFlow(); return builder.build(); } private MethodSpec addRawVector(boolean masked) { MethodSpec.Builder builder = MethodSpec.methodBuilder("addRawVector"); - builder.addModifiers(Modifier.PRIVATE).addParameter(valueVectorType(init, combine), "vector"); + builder.addModifiers(Modifier.PRIVATE).addParameter(vectorType(aggParam.type()), "vector"); + if (includeTimestampVector) { + builder.addParameter(LONG_VECTOR, "timestamps"); + } if (masked) { builder.addParameter(BOOLEAN_VECTOR, "mask"); } - if (valuesIsArray) { + if (aggParam.isArray()) { builder.addComment("This type does not support vectors because all values are multi-valued"); return builder.build(); } - if (stateTypeHasSeen) { + if (aggState.hasSeen()) { builder.addStatement("state.seen(true)"); } - if (valuesIsBytesRef) { + if (aggParam.isBytesRef()) { // Add bytes_ref scratch var that will be used for bytes_ref blocks/vectors builder.addStatement("$T scratch = new $T()", BYTES_REF, BYTES_REF); } @@ -418,12 +383,15 @@ public class AggregatorImplementer { private MethodSpec addRawBlock(boolean masked) { MethodSpec.Builder builder = MethodSpec.methodBuilder("addRawBlock"); - builder.addModifiers(Modifier.PRIVATE).addParameter(valueBlockType(init, combine), "block"); + builder.addModifiers(Modifier.PRIVATE).addParameter(blockType(aggParam.type()), "block"); + if (includeTimestampVector) { + builder.addParameter(LONG_VECTOR, "timestamps"); + } if (masked) { builder.addParameter(BOOLEAN_VECTOR, "mask"); } - if (valuesIsBytesRef) { + if (aggParam.isBytesRef()) { // Add bytes_ref scratch var that will only be used for bytes_ref blocks/vectors builder.addStatement("$T scratch = new $T()", BYTES_REF, BYTES_REF); } @@ -435,16 +403,16 @@ public class AggregatorImplementer { builder.beginControlFlow("if (block.isNull(p))"); builder.addStatement("continue"); builder.endControlFlow(); - if (stateTypeHasSeen) { + if (aggState.hasSeen()) { builder.addStatement("state.seen(true)"); } builder.addStatement("int start = block.getFirstValueIndex(p)"); builder.addStatement("int end = start + block.getValueCount(p)"); - if (valuesIsArray) { - String arrayType = valueTypeString(); + if (aggParam.isArray()) { + String arrayType = aggParam.type().toString().replace("[]", ""); builder.addStatement("$L[] valuesArray = new $L[end - start]", arrayType, arrayType); builder.beginControlFlow("for (int i = start; i < end; i++)"); - builder.addStatement("valuesArray[i-start] = $L.get$L(i)", "block", firstUpper(arrayType)); + builder.addStatement("valuesArray[i-start] = $L.get$L(i)", "block", capitalize(arrayType)); builder.endControlFlow(); combineRawInputForArray(builder, "valuesArray"); } else { @@ -460,7 +428,7 @@ public class AggregatorImplementer { private void combineRawInput(MethodSpec.Builder builder, String blockVariable) { TypeName returnType = TypeName.get(combine.getReturnType()); warningsBlock(builder, () -> { - if (valuesIsBytesRef) { + if (aggParam.isBytesRef()) { combineRawInputForBytesRef(builder, blockVariable); } else if (returnType.isPrimitive()) { combineRawInputForPrimitive(returnType, builder, blockVariable); @@ -472,35 +440,59 @@ public class AggregatorImplementer { }); } + private void combineRawInputForBytesRef(MethodSpec.Builder builder, String blockVariable) { + // scratch is a BytesRef var that must have been defined before the iteration starts + if (includeTimestampVector) { + builder.addStatement("$T.combine(state, timestamps.getLong(i), $L.getBytesRef(i, scratch))", declarationType, blockVariable); + } else { + builder.addStatement("$T.combine(state, $L.getBytesRef(i, scratch))", declarationType, blockVariable); + } + } + private void combineRawInputForPrimitive(TypeName returnType, MethodSpec.Builder builder, String blockVariable) { - builder.addStatement( - "state.$TValue($T.combine(state.$TValue(), $L.get$L(i)))", - returnType, - declarationType, - returnType, - blockVariable, - firstUpper(combine.getParameters().get(1).asType().toString()) - ); + if (includeTimestampVector) { + builder.addStatement( + "state.$TValue($T.combine(state.$TValue(), timestamps.getLong(i), $L.get$L(i)))", + returnType, + declarationType, + returnType, + blockVariable, + capitalize(combine.getParameters().get(1).asType().toString()) + ); + } else { + builder.addStatement( + "state.$TValue($T.combine(state.$TValue(), $L.get$L(i)))", + returnType, + declarationType, + returnType, + blockVariable, + capitalize(combine.getParameters().get(1).asType().toString()) + ); + } + } + + private void combineRawInputForVoid(MethodSpec.Builder builder, String blockVariable) { + if (includeTimestampVector) { + builder.addStatement( + "$T.combine(state, timestamps.getLong(i), $L.get$L(i))", + declarationType, + blockVariable, + capitalize(combine.getParameters().get(1).asType().toString()) + ); + } else { + builder.addStatement( + "$T.combine(state, $L.get$L(i))", + declarationType, + blockVariable, + capitalize(combine.getParameters().get(1).asType().toString()) + ); + } } private void combineRawInputForArray(MethodSpec.Builder builder, String arrayVariable) { warningsBlock(builder, () -> builder.addStatement("$T.combine(state, $L)", declarationType, arrayVariable)); } - private void combineRawInputForVoid(MethodSpec.Builder builder, String blockVariable) { - builder.addStatement( - "$T.combine(state, $L.get$L(i))", - declarationType, - blockVariable, - firstUpper(combine.getParameters().get(1).asType().toString()) - ); - } - - private void combineRawInputForBytesRef(MethodSpec.Builder builder, String blockVariable) { - // scratch is a BytesRef var that must have been defined before the iteration starts - builder.addStatement("$T.combine(state, $L.getBytesRef(i, scratch))", declarationType, blockVariable); - } - private void warningsBlock(MethodSpec.Builder builder, Runnable block) { if (warnExceptions.isEmpty() == false) { builder.beginControlFlow("try"); @@ -526,12 +518,7 @@ public class AggregatorImplementer { interState.assignToVariable(builder, i); builder.addStatement("assert $L.getPositionCount() == 1", interState.name()); } - if (combineIntermediate != null) { - if (intermediateState.stream().map(IntermediateStateDesc::elementType).anyMatch(n -> n.equals("BYTES_REF"))) { - builder.addStatement("$T scratch = new $T()", BYTES_REF, BYTES_REF); - } - builder.addStatement("$T.combineIntermediate(state, " + intermediateStateRowAccess() + ")", declarationType); - } else if (hasPrimitiveState()) { + if (aggState.declaredType().isPrimitive()) { if (warnExceptions.isEmpty()) { assert intermediateState.size() == 2; assert intermediateState.get(1).name().equals("seen"); @@ -549,14 +536,36 @@ public class AggregatorImplementer { } warningsBlock(builder, () -> { + var primitiveStateMethod = switch (aggState.declaredType().toString()) { + case "boolean" -> "booleanValue"; + case "int" -> "intValue"; + case "long" -> "longValue"; + case "double" -> "doubleValue"; + case "float" -> "floatValue"; + default -> throw new IllegalArgumentException("Unexpected primitive type: [" + aggState.declaredType() + "]"); + }; var state = intermediateState.get(0); var s = "state.$L($T.combine(state.$L(), " + state.name() + "." + vectorAccessorName(state.elementType()) + "(0)))"; - builder.addStatement(s, primitiveStateMethod(), declarationType, primitiveStateMethod()); + builder.addStatement(s, primitiveStateMethod, declarationType, primitiveStateMethod); builder.addStatement("state.seen(true)"); }); builder.endControlFlow(); } else { - throw new IllegalArgumentException("Don't know how to combine intermediate input. Define combineIntermediate"); + requireStaticMethod( + declarationType, + requireVoidType(), + requireName("combineIntermediate"), + requireArgs( + Stream.concat( + Stream.of(aggState.declaredType()), // aggState + intermediateState.stream().map(IntermediateStateDesc::combineArgType) // intermediate state + ).map(Methods::requireType).toArray(TypeMatcher[]::new) + ) + ); + if (intermediateState.stream().map(IntermediateStateDesc::elementType).anyMatch(n -> n.equals("BYTES_REF"))) { + builder.addStatement("$T scratch = new $T()", BYTES_REF, BYTES_REF); + } + builder.addStatement("$T.combineIntermediate(state, " + intermediateStateRowAccess() + ")", declarationType); } return builder.build(); } @@ -565,25 +574,6 @@ public class AggregatorImplementer { return intermediateState.stream().map(desc -> desc.access("0")).collect(joining(", ")); } - private String primitiveStateMethod() { - switch (stateType.toString()) { - case "org.elasticsearch.compute.aggregation.BooleanState", "org.elasticsearch.compute.aggregation.BooleanFallibleState": - return "booleanValue"; - case "org.elasticsearch.compute.aggregation.IntState", "org.elasticsearch.compute.aggregation.IntFallibleState": - return "intValue"; - case "org.elasticsearch.compute.aggregation.LongState", "org.elasticsearch.compute.aggregation.LongFallibleState": - return "longValue"; - case "org.elasticsearch.compute.aggregation.DoubleState", "org.elasticsearch.compute.aggregation.DoubleFallibleState": - return "doubleValue"; - case "org.elasticsearch.compute.aggregation.FloatState", "org.elasticsearch.compute.aggregation.FloatFallibleState": - return "floatValue"; - default: - throw new IllegalArgumentException( - "don't know how to fetch primitive values from " + stateType + ". define combineIntermediate." - ); - } - } - private MethodSpec evaluateIntermediate() { MethodSpec.Builder builder = MethodSpec.methodBuilder("evaluateIntermediate"); builder.addAnnotation(Override.class) @@ -602,45 +592,39 @@ public class AggregatorImplementer { .addParameter(BLOCK_ARRAY, "blocks") .addParameter(TypeName.INT, "offset") .addParameter(DRIVER_CONTEXT, "driverContext"); - if (stateTypeHasSeen || stateTypeHasFailed) { - var condition = Stream.of(stateTypeHasSeen ? "state.seen() == false" : null, stateTypeHasFailed ? "state.failed()" : null) - .filter(Objects::nonNull) - .collect(joining(" || ")); - builder.beginControlFlow("if ($L)", condition); + if (aggState.hasSeen() || aggState.hasFailed()) { + builder.beginControlFlow( + "if ($L)", + Stream.concat( + Stream.of("state.seen() == false").filter(c -> aggState.hasSeen()), + Stream.of("state.failed()").filter(c -> aggState.hasFailed()) + ).collect(joining(" || ")) + ); builder.addStatement("blocks[offset] = driverContext.blockFactory().newConstantNullBlock(1)", BLOCK); builder.addStatement("return"); builder.endControlFlow(); } - if (evaluateFinal == null) { - primitiveStateToResult(builder); + if (aggState.declaredType().isPrimitive()) { + builder.addStatement(switch (aggState.declaredType().toString()) { + case "boolean" -> "blocks[offset] = driverContext.blockFactory().newConstantBooleanBlockWith(state.booleanValue(), 1)"; + case "int" -> "blocks[offset] = driverContext.blockFactory().newConstantIntBlockWith(state.intValue(), 1)"; + case "long" -> "blocks[offset] = driverContext.blockFactory().newConstantLongBlockWith(state.longValue(), 1)"; + case "double" -> "blocks[offset] = driverContext.blockFactory().newConstantDoubleBlockWith(state.doubleValue(), 1)"; + case "float" -> "blocks[offset] = driverContext.blockFactory().newConstantFloatBlockWith(state.floatValue(), 1)"; + default -> throw new IllegalArgumentException("Unexpected primitive type: [" + aggState.declaredType() + "]"); + }); } else { + requireStaticMethod( + declarationType, + requireType(BLOCK), + requireName("evaluateFinal"), + requireArgs(requireType(aggState.declaredType()), requireType(DRIVER_CONTEXT)) + ); builder.addStatement("blocks[offset] = $T.evaluateFinal(state, driverContext)", declarationType); } return builder.build(); } - private void primitiveStateToResult(MethodSpec.Builder builder) { - switch (stateType.toString()) { - case "org.elasticsearch.compute.aggregation.BooleanState", "org.elasticsearch.compute.aggregation.BooleanFallibleState": - builder.addStatement("blocks[offset] = driverContext.blockFactory().newConstantBooleanBlockWith(state.booleanValue(), 1)"); - return; - case "org.elasticsearch.compute.aggregation.IntState", "org.elasticsearch.compute.aggregation.IntFallibleState": - builder.addStatement("blocks[offset] = driverContext.blockFactory().newConstantIntBlockWith(state.intValue(), 1)"); - return; - case "org.elasticsearch.compute.aggregation.LongState", "org.elasticsearch.compute.aggregation.LongFallibleState": - builder.addStatement("blocks[offset] = driverContext.blockFactory().newConstantLongBlockWith(state.longValue(), 1)"); - return; - case "org.elasticsearch.compute.aggregation.DoubleState", "org.elasticsearch.compute.aggregation.DoubleFallibleState": - builder.addStatement("blocks[offset] = driverContext.blockFactory().newConstantDoubleBlockWith(state.doubleValue(), 1)"); - return; - case "org.elasticsearch.compute.aggregation.FloatState", "org.elasticsearch.compute.aggregation.FloatFallibleState": - builder.addStatement("blocks[offset] = driverContext.blockFactory().newConstantFloatBlockWith(state.floatValue(), 1)"); - return; - default: - throw new IllegalArgumentException("don't know how to convert state to result: " + stateType); - } - } - private MethodSpec toStringMethod() { MethodSpec.Builder builder = MethodSpec.methodBuilder("toString"); builder.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).returns(String.class); @@ -659,14 +643,6 @@ public class AggregatorImplementer { return builder.build(); } - private static final Pattern PRIMITIVE_STATE_PATTERN = Pattern.compile( - "org.elasticsearch.compute.aggregation.(Boolean|Int|Long|Double|Float)(Fallible)?State" - ); - - private boolean hasPrimitiveState() { - return PRIMITIVE_STATE_PATTERN.matcher(stateType.toString()).matches(); - } - record IntermediateStateDesc(String name, String elementType, boolean block) { static IntermediateStateDesc newIntermediateStateDesc(IntermediateState state) { String type = state.type(); @@ -703,22 +679,57 @@ public class AggregatorImplementer { builder.addStatement("$T $L = (($T) $L).asVector()", vectorType(elementType), name, blockType, name + "Uncast"); } } + + public TypeName combineArgType() { + var type = Types.fromString(elementType); + return block ? blockType(type) : type; + } } - private TypeMirror valueTypeMirror() { - return combine.getParameters().get(combine.getParameters().size() - 1).asType(); + /** + * This represents the type returned by init method used to keep aggregation state + * @param declaredType declared state type as returned by init method + * @param type actual type used (we have some predefined state types for primitive values) + */ + public record AggregationState(TypeName declaredType, TypeName type, boolean hasSeen, boolean hasFailed) { + + public static AggregationState create(Elements elements, TypeMirror mirror, boolean hasFailures, boolean isArray) { + var declaredType = TypeName.get(mirror); + var stateType = declaredType.isPrimitive() + ? ClassName.get("org.elasticsearch.compute.aggregation", primitiveStateStoreClassname(declaredType, hasFailures, isArray)) + : declaredType; + return new AggregationState( + declaredType, + stateType, + hasMethod(elements, stateType, "seen()"), + hasMethod(elements, stateType, "failed()") + ); + } + + private static String primitiveStateStoreClassname(TypeName declaredType, boolean hasFailures, boolean isArray) { + var name = capitalize(declaredType.toString()); + if (hasFailures) { + name += "Fallible"; + } + if (isArray) { + name += "Array"; + } + return name + "State"; + } } - private TypeName valueTypeName() { - return TypeName.get(valueTypeMirror()); + public record AggregationParameter(TypeName type, boolean isArray) { + + public static AggregationParameter create(TypeMirror mirror) { + return new AggregationParameter(TypeName.get(mirror), Objects.equals(mirror.getKind(), TypeKind.ARRAY)); + } + + public boolean isBytesRef() { + return Objects.equals(type, BYTES_REF); + } } - private TypeKind valueTypeKind() { - return valueTypeMirror().getKind(); - } - - private String valueTypeString() { - String valueTypeString = TypeName.get(valueTypeMirror()).toString(); - return valuesIsArray ? valueTypeString.substring(0, valueTypeString.length() - 2) : valueTypeString; + private static boolean hasMethod(Elements elements, TypeName type, String name) { + return elements.getAllMembers(elements.getTypeElement(type.toString())).stream().anyMatch(e -> e.toString().equals(name)); } } diff --git a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/AggregatorProcessor.java b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/AggregatorProcessor.java index 863db86eb934..3ad2343ad165 100644 --- a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/AggregatorProcessor.java +++ b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/AggregatorProcessor.java @@ -87,7 +87,13 @@ public class AggregatorProcessor implements Processor { ); if (aggClass.getAnnotation(Aggregator.class) != null) { IntermediateState[] intermediateState = aggClass.getAnnotation(Aggregator.class).value(); - implementer = new AggregatorImplementer(env.getElementUtils(), aggClass, intermediateState, warnExceptionsTypes); + implementer = new AggregatorImplementer( + env.getElementUtils(), + aggClass, + intermediateState, + warnExceptionsTypes, + aggClass.getAnnotation(Aggregator.class).includeTimestamps() + ); write(aggClass, "aggregator", implementer.sourceFile(), env); } GroupingAggregatorImplementer groupingAggregatorImplementer = null; @@ -96,13 +102,12 @@ public class AggregatorProcessor implements Processor { if (intermediateState.length == 0 && aggClass.getAnnotation(Aggregator.class) != null) { intermediateState = aggClass.getAnnotation(Aggregator.class).value(); } - boolean includeTimestamps = aggClass.getAnnotation(GroupingAggregator.class).includeTimestamps(); groupingAggregatorImplementer = new GroupingAggregatorImplementer( env.getElementUtils(), aggClass, intermediateState, warnExceptionsTypes, - includeTimestamps + aggClass.getAnnotation(GroupingAggregator.class).includeTimestamps() ); write(aggClass, "grouping aggregator", groupingAggregatorImplementer.sourceFile(), env); } diff --git a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/GroupingAggregatorImplementer.java b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/GroupingAggregatorImplementer.java index 8224c73936b9..fc377f22bbbc 100644 --- a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/GroupingAggregatorImplementer.java +++ b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/GroupingAggregatorImplementer.java @@ -17,28 +17,35 @@ import com.squareup.javapoet.TypeSpec; import org.elasticsearch.compute.ann.Aggregator; import org.elasticsearch.compute.ann.IntermediateState; +import org.elasticsearch.compute.gen.AggregatorImplementer.AggregationParameter; +import org.elasticsearch.compute.gen.AggregatorImplementer.AggregationState; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; -import java.util.regex.Pattern; +import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; -import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import static java.util.stream.Collectors.joining; -import static org.elasticsearch.compute.gen.AggregatorImplementer.firstUpper; -import static org.elasticsearch.compute.gen.AggregatorImplementer.valueBlockType; -import static org.elasticsearch.compute.gen.AggregatorImplementer.valueVectorType; -import static org.elasticsearch.compute.gen.Methods.findMethod; -import static org.elasticsearch.compute.gen.Methods.findRequiredMethod; +import static org.elasticsearch.compute.gen.AggregatorImplementer.capitalize; +import static org.elasticsearch.compute.gen.Methods.requireAnyArgs; +import static org.elasticsearch.compute.gen.Methods.requireAnyType; +import static org.elasticsearch.compute.gen.Methods.requireArgs; +import static org.elasticsearch.compute.gen.Methods.requireName; +import static org.elasticsearch.compute.gen.Methods.requirePrimitiveOrImplements; +import static org.elasticsearch.compute.gen.Methods.requireStaticMethod; +import static org.elasticsearch.compute.gen.Methods.requireType; +import static org.elasticsearch.compute.gen.Methods.requireVoidType; import static org.elasticsearch.compute.gen.Methods.vectorAccessorName; import static org.elasticsearch.compute.gen.Types.BIG_ARRAYS; +import static org.elasticsearch.compute.gen.Types.BLOCK; import static org.elasticsearch.compute.gen.Types.BLOCK_ARRAY; import static org.elasticsearch.compute.gen.Types.BYTES_REF; import static org.elasticsearch.compute.gen.Types.DRIVER_CONTEXT; @@ -55,6 +62,8 @@ import static org.elasticsearch.compute.gen.Types.LONG_VECTOR; import static org.elasticsearch.compute.gen.Types.PAGE; import static org.elasticsearch.compute.gen.Types.SEEN_GROUP_IDS; import static org.elasticsearch.compute.gen.Types.WARNINGS; +import static org.elasticsearch.compute.gen.Types.blockType; +import static org.elasticsearch.compute.gen.Types.vectorType; /** * Implements "GroupingAggregationFunction" from a class containing static methods @@ -70,17 +79,14 @@ public class GroupingAggregatorImplementer { private final List warnExceptions; private final ExecutableElement init; private final ExecutableElement combine; - private final ExecutableElement combineStates; - private final ExecutableElement evaluateFinal; - private final ExecutableElement combineIntermediate; - private final TypeName stateType; - private final boolean valuesIsBytesRef; - private final boolean valuesIsArray; private final List createParameters; private final ClassName implementation; private final List intermediateState; private final boolean includeTimestampVector; + private final AggregationState aggState; + private final AggregationParameter aggParam; + public GroupingAggregatorImplementer( Elements elements, TypeElement declarationType, @@ -91,21 +97,24 @@ public class GroupingAggregatorImplementer { this.declarationType = declarationType; this.warnExceptions = warnExceptions; - this.init = findRequiredMethod(declarationType, new String[] { "init", "initGrouping" }, e -> true); - this.stateType = choseStateType(); + this.init = requireStaticMethod( + declarationType, + // This should be more restrictive and require org.elasticsearch.compute.aggregation.GroupingAggregatorState + requirePrimitiveOrImplements(elements, Types.RELEASABLE), + requireName("init", "initGrouping"), + requireAnyArgs("") + ); + this.aggState = AggregationState.create(elements, init.getReturnType(), warnExceptions.isEmpty() == false, true); + + this.combine = requireStaticMethod( + declarationType, + aggState.declaredType().isPrimitive() ? requireType(aggState.declaredType()) : requireVoidType(), + requireName("combine"), + combineArgs(aggState, includeTimestampVector) + ); + // TODO support multiple parameters + this.aggParam = AggregationParameter.create(combine.getParameters().getLast().asType()); - this.combine = findRequiredMethod(declarationType, new String[] { "combine" }, e -> { - if (e.getParameters().size() == 0) { - return false; - } - TypeName firstParamType = TypeName.get(e.getParameters().get(0).asType()); - return firstParamType.isPrimitive() || firstParamType.toString().equals(stateType.toString()); - }); - this.combineStates = findMethod(declarationType, "combineStates"); - this.combineIntermediate = findMethod(declarationType, "combineIntermediate"); - this.evaluateFinal = findMethod(declarationType, "evaluateFinal"); - this.valuesIsBytesRef = BYTES_REF.equals(valueTypeName()); - this.valuesIsArray = TypeKind.ARRAY.equals(valueTypeKind()); this.createParameters = init.getParameters() .stream() .map(Parameter::from) @@ -117,12 +126,31 @@ public class GroupingAggregatorImplementer { (declarationType.getSimpleName() + "GroupingAggregatorFunction").replace("AggregatorGroupingAggregator", "GroupingAggregator") ); - intermediateState = Arrays.stream(interStateAnno) + this.intermediateState = Arrays.stream(interStateAnno) .map(AggregatorImplementer.IntermediateStateDesc::newIntermediateStateDesc) .toList(); this.includeTimestampVector = includeTimestampVector; } + private static Methods.ArgumentMatcher combineArgs(AggregationState aggState, boolean includeTimestampVector) { + if (aggState.declaredType().isPrimitive()) { + return requireArgs(requireType(aggState.declaredType()), requireAnyType("")); + } else if (includeTimestampVector) { + return requireArgs( + requireType(aggState.declaredType()), + requireType(TypeName.INT), + requireType(TypeName.LONG), // @timestamp + requireAnyType("") + ); + } else { + return requireArgs( + requireType(aggState.declaredType()), + requireType(TypeName.INT), + requireAnyType("") + ); + } + } + public ClassName implementation() { return implementation; } @@ -131,18 +159,6 @@ public class GroupingAggregatorImplementer { return createParameters; } - private TypeName choseStateType() { - TypeName initReturn = TypeName.get(init.getReturnType()); - if (false == initReturn.isPrimitive()) { - return initReturn; - } - String simpleName = firstUpper(initReturn.toString()); - if (warnExceptions.isEmpty()) { - return ClassName.get("org.elasticsearch.compute.aggregation", simpleName + "ArrayState"); - } - return ClassName.get("org.elasticsearch.compute.aggregation", simpleName + "FallibleArrayState"); - } - public JavaFile sourceFile() { JavaFile.Builder builder = JavaFile.builder(implementation.packageName(), type()); builder.addFileComment(""" @@ -164,7 +180,7 @@ public class GroupingAggregatorImplementer { .initializer(initInterState()) .build() ); - builder.addField(stateType, "state", Modifier.PRIVATE, Modifier.FINAL); + builder.addField(aggState.type(), "state", Modifier.PRIVATE, Modifier.FINAL); if (warnExceptions.isEmpty() == false) { builder.addField(WARNINGS, "warnings", Modifier.PRIVATE, Modifier.FINAL); } @@ -180,10 +196,10 @@ public class GroupingAggregatorImplementer { builder.addMethod(intermediateStateDesc()); builder.addMethod(intermediateBlockCount()); builder.addMethod(prepareProcessPage()); - builder.addMethod(addRawInputLoop(INT_VECTOR, valueBlockType(init, combine))); - builder.addMethod(addRawInputLoop(INT_VECTOR, valueVectorType(init, combine))); - builder.addMethod(addRawInputLoop(INT_BLOCK, valueBlockType(init, combine))); - builder.addMethod(addRawInputLoop(INT_BLOCK, valueVectorType(init, combine))); + builder.addMethod(addRawInputLoop(INT_VECTOR, blockType(aggParam.type()))); + builder.addMethod(addRawInputLoop(INT_VECTOR, vectorType(aggParam.type()))); + builder.addMethod(addRawInputLoop(INT_BLOCK, blockType(aggParam.type()))); + builder.addMethod(addRawInputLoop(INT_BLOCK, vectorType(aggParam.type()))); builder.addMethod(selectedMayContainUnseenGroups()); builder.addMethod(addIntermediateInput()); builder.addMethod(addIntermediateRowInput()); @@ -230,16 +246,16 @@ public class GroupingAggregatorImplementer { .map(p -> TypeName.get(p.asType()).equals(BIG_ARRAYS) ? "driverContext.bigArrays()" : p.getSimpleName().toString()) .collect(joining(", ")); CodeBlock.Builder builder = CodeBlock.builder(); - if (init.getReturnType().toString().equals(stateType.toString())) { - builder.add("$T.$L($L)", declarationType, init.getSimpleName(), initParametersCall); - } else { + if (aggState.declaredType().isPrimitive()) { builder.add( "new $T(driverContext.bigArrays(), $T.$L($L))", - stateType, + aggState.type(), declarationType, init.getSimpleName(), initParametersCall ); + } else { + builder.add("$T.$L($L)", declarationType, init.getSimpleName(), initParametersCall); } return builder.build(); } @@ -263,7 +279,7 @@ public class GroupingAggregatorImplementer { builder.addParameter(WARNINGS, "warnings"); } builder.addParameter(LIST_INTEGER, "channels"); - builder.addParameter(stateType, "state"); + builder.addParameter(aggState.type(), "state"); builder.addParameter(DRIVER_CONTEXT, "driverContext"); if (warnExceptions.isEmpty() == false) { builder.addStatement("this.warnings = warnings"); @@ -301,8 +317,8 @@ public class GroupingAggregatorImplementer { builder.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).returns(GROUPING_AGGREGATOR_FUNCTION_ADD_INPUT); builder.addParameter(SEEN_GROUP_IDS, "seenGroupIds").addParameter(PAGE, "page"); - builder.addStatement("$T valuesBlock = page.getBlock(channels.get(0))", valueBlockType(init, combine)); - builder.addStatement("$T valuesVector = valuesBlock.asVector()", valueVectorType(init, combine)); + builder.addStatement("$T valuesBlock = page.getBlock(channels.get(0))", blockType(aggParam.type())); + builder.addStatement("$T valuesVector = valuesBlock.asVector()", vectorType(aggParam.type())); if (includeTimestampVector) { builder.addStatement("$T timestampsBlock = page.getBlock(channels.get(1))", LONG_BLOCK); builder.addStatement("$T timestampsVector = timestampsBlock.asVector()", LONG_VECTOR); @@ -355,18 +371,17 @@ public class GroupingAggregatorImplementer { private MethodSpec addRawInputLoop(TypeName groupsType, TypeName valuesType) { boolean groupsIsBlock = groupsType.toString().endsWith("Block"); boolean valuesIsBlock = valuesType.toString().endsWith("Block"); - String methodName = "addRawInput"; - MethodSpec.Builder builder = MethodSpec.methodBuilder(methodName); + MethodSpec.Builder builder = MethodSpec.methodBuilder("addRawInput"); builder.addModifiers(Modifier.PRIVATE); builder.addParameter(TypeName.INT, "positionOffset").addParameter(groupsType, "groups").addParameter(valuesType, "values"); if (includeTimestampVector) { builder.addParameter(LONG_VECTOR, "timestamps"); } - if (valuesIsBytesRef) { + if (aggParam.isBytesRef()) { // Add bytes_ref scratch var that will be used for bytes_ref blocks/vectors builder.addStatement("$T scratch = new $T()", BYTES_REF, BYTES_REF); } - if (valuesIsArray && valuesIsBlock == false) { + if (aggParam.isArray() && valuesIsBlock == false) { builder.addComment("This type does not support vectors because all values are multi-valued"); return builder.build(); } @@ -397,11 +412,11 @@ public class GroupingAggregatorImplementer { builder.endControlFlow(); builder.addStatement("int valuesStart = values.getFirstValueIndex(groupPosition + positionOffset)"); builder.addStatement("int valuesEnd = valuesStart + values.getValueCount(groupPosition + positionOffset)"); - if (valuesIsArray) { - String arrayType = valueTypeString(); + if (aggParam.isArray()) { + String arrayType = aggParam.type().toString().replace("[]", ""); builder.addStatement("$L[] valuesArray = new $L[valuesEnd - valuesStart]", arrayType, arrayType); builder.beginControlFlow("for (int v = valuesStart; v < valuesEnd; v++)"); - builder.addStatement("valuesArray[v-valuesStart] = $L.get$L(v)", "values", firstUpper(arrayType)); + builder.addStatement("valuesArray[v-valuesStart] = $L.get$L(v)", "values", capitalize(arrayType)); builder.endControlFlow(); combineRawInputForArray(builder, "valuesArray"); } else { @@ -422,14 +437,12 @@ public class GroupingAggregatorImplementer { } private void combineRawInput(MethodSpec.Builder builder, String blockVariable, String offsetVariable) { - TypeName valueType = valueTypeName(); + TypeName valueType = aggParam.type(); TypeName returnType = TypeName.get(combine.getReturnType()); warningsBlock(builder, () -> { - if (valuesIsBytesRef) { + if (aggParam.isBytesRef()) { combineRawInputForBytesRef(builder, blockVariable, offsetVariable); - } else if (includeTimestampVector) { - combineRawInputWithTimestamp(builder, offsetVariable); } else if (valueType.isPrimitive() == false) { throw new IllegalArgumentException("second parameter to combine must be a primitive, array or BytesRef: " + valueType); } else if (returnType.isPrimitive()) { @@ -442,50 +455,77 @@ public class GroupingAggregatorImplementer { }); } + private void combineRawInputForBytesRef(MethodSpec.Builder builder, String blockVariable, String offsetVariable) { + // scratch is a BytesRef var that must have been defined before the iteration starts + if (includeTimestampVector) { + if (offsetVariable.contains(" + ")) { + builder.addStatement("var valuePosition = $L", offsetVariable); + offsetVariable = "valuePosition"; + } + builder.addStatement( + "$T.combine(state, groupId, timestamps.getLong($L), $L.getBytesRef($L, scratch))", + declarationType, + offsetVariable, + blockVariable, + offsetVariable + ); + } else { + builder.addStatement("$T.combine(state, groupId, $L.getBytesRef($L, scratch))", declarationType, blockVariable, offsetVariable); + } + } + private void combineRawInputForPrimitive(MethodSpec.Builder builder, String blockVariable, String offsetVariable) { - builder.addStatement( - "state.set(groupId, $T.combine(state.getOrDefault(groupId), $L.get$L($L)))", - declarationType, - blockVariable, - firstUpper(valueTypeName().toString()), - offsetVariable - ); + if (includeTimestampVector) { + if (offsetVariable.contains(" + ")) { + builder.addStatement("var valuePosition = $L", offsetVariable); + offsetVariable = "valuePosition"; + } + builder.addStatement( + "$T.combine(state, groupId, timestamps.getLong($L), values.get$L($L))", + declarationType, + offsetVariable, + capitalize(aggParam.type().toString()), + offsetVariable + ); + } else { + builder.addStatement( + "state.set(groupId, $T.combine(state.getOrDefault(groupId), $L.get$L($L)))", + declarationType, + blockVariable, + capitalize(aggParam.type().toString()), + offsetVariable + ); + } + } + + private void combineRawInputForVoid(MethodSpec.Builder builder, String blockVariable, String offsetVariable) { + if (includeTimestampVector) { + if (offsetVariable.contains(" + ")) { + builder.addStatement("var valuePosition = $L", offsetVariable); + offsetVariable = "valuePosition"; + } + builder.addStatement( + "$T.combine(state, groupId, timestamps.getLong($L), values.get$L($L))", + declarationType, + offsetVariable, + capitalize(aggParam.type().toString()), + offsetVariable + ); + } else { + builder.addStatement( + "$T.combine(state, groupId, $L.get$L($L))", + declarationType, + blockVariable, + capitalize(aggParam.type().toString()), + offsetVariable + ); + } } private void combineRawInputForArray(MethodSpec.Builder builder, String arrayVariable) { warningsBlock(builder, () -> builder.addStatement("$T.combine(state, groupId, $L)", declarationType, arrayVariable)); } - private void combineRawInputForVoid(MethodSpec.Builder builder, String blockVariable, String offsetVariable) { - builder.addStatement( - "$T.combine(state, groupId, $L.get$L($L))", - declarationType, - blockVariable, - firstUpper(valueTypeName().toString()), - offsetVariable - ); - } - - private void combineRawInputWithTimestamp(MethodSpec.Builder builder, String offsetVariable) { - String blockType = firstUpper(valueTypeName().toString()); - if (offsetVariable.contains(" + ")) { - builder.addStatement("var valuePosition = $L", offsetVariable); - offsetVariable = "valuePosition"; - } - builder.addStatement( - "$T.combine(state, groupId, timestamps.getLong($L), values.get$L($L))", - declarationType, - offsetVariable, - blockType, - offsetVariable - ); - } - - private void combineRawInputForBytesRef(MethodSpec.Builder builder, String blockVariable, String offsetVariable) { - // scratch is a BytesRef var that must have been defined before the iteration starts - builder.addStatement("$T.combine(state, groupId, $L.getBytesRef($L, scratch))", declarationType, blockVariable, offsetVariable); - } - private void warningsBlock(MethodSpec.Builder builder, Runnable block) { if (warnExceptions.isEmpty() == false) { builder.beginControlFlow("try"); @@ -539,7 +579,7 @@ public class GroupingAggregatorImplementer { builder.beginControlFlow("for (int groupPosition = 0; groupPosition < groups.getPositionCount(); groupPosition++)"); { builder.addStatement("int groupId = groups.getInt(groupPosition)"); - if (hasPrimitiveState()) { + if (aggState.declaredType().isPrimitive()) { if (warnExceptions.isEmpty()) { assert intermediateState.size() == 2; assert intermediateState.get(1).name().equals("seen"); @@ -567,31 +607,33 @@ public class GroupingAggregatorImplementer { }); builder.endControlFlow(); } else { - builder.addStatement("$T.combineIntermediate(state, groupId, " + intermediateStateRowAccess() + ")", declarationType); + var stateHasBlock = intermediateState.stream().anyMatch(AggregatorImplementer.IntermediateStateDesc::block); + requireStaticMethod( + declarationType, + requireVoidType(), + requireName("combineIntermediate"), + requireArgs( + Stream.of( + Stream.of(aggState.declaredType(), TypeName.INT), // aggState and groupId + intermediateState.stream().map(AggregatorImplementer.IntermediateStateDesc::combineArgType), + Stream.of(TypeName.INT).filter(p -> stateHasBlock) // position + ).flatMap(Function.identity()).map(Methods::requireType).toArray(Methods.TypeMatcher[]::new) + ) + ); + + builder.addStatement( + "$T.combineIntermediate(state, groupId, " + + intermediateState.stream().map(desc -> desc.access("groupPosition + positionOffset")).collect(joining(", ")) + + (stateHasBlock ? ", groupPosition + positionOffset" : "") + + ")", + declarationType + ); } builder.endControlFlow(); } return builder.build(); } - String intermediateStateRowAccess() { - String rowAccess = intermediateState.stream().map(desc -> desc.access("groupPosition + positionOffset")).collect(joining(", ")); - if (intermediateState.stream().anyMatch(AggregatorImplementer.IntermediateStateDesc::block)) { - rowAccess += ", groupPosition + positionOffset"; - } - return rowAccess; - } - - private void combineStates(MethodSpec.Builder builder) { - if (combineStates == null) { - builder.beginControlFlow("if (inState.hasValue(position))"); - builder.addStatement("state.set(groupId, $T.combine(state.getOrDefault(groupId), inState.get(position)))", declarationType); - builder.endControlFlow(); - return; - } - builder.addStatement("$T.combineStates(state, groupId, inState, position)", declarationType); - } - private MethodSpec addIntermediateRowInput() { MethodSpec.Builder builder = MethodSpec.methodBuilder("addIntermediateRowInput"); builder.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC); @@ -601,9 +643,26 @@ public class GroupingAggregatorImplementer { builder.addStatement("throw new IllegalArgumentException($S + getClass() + $S + input.getClass())", "expected ", "; got "); } builder.endControlFlow(); - builder.addStatement("$T inState = (($T) input).state", stateType, implementation); + builder.addStatement("$T inState = (($T) input).state", aggState.type(), implementation); builder.addStatement("state.enableGroupIdTracking(new $T.Empty())", SEEN_GROUP_IDS); - combineStates(builder); + if (aggState.declaredType().isPrimitive()) { + builder.beginControlFlow("if (inState.hasValue(position))"); + builder.addStatement("state.set(groupId, $T.combine(state.getOrDefault(groupId), inState.get(position)))", declarationType); + builder.endControlFlow(); + } else { + requireStaticMethod( + declarationType, + requireVoidType(), + requireName("combineStates"), + requireArgs( + requireType(aggState.declaredType()), + requireType(TypeName.INT), + requireType(aggState.declaredType()), + requireType(TypeName.INT) + ) + ); + builder.addStatement("$T.combineStates(state, groupId, inState, position)", declarationType); + } return builder.build(); } @@ -627,9 +686,15 @@ public class GroupingAggregatorImplementer { .addParameter(INT_VECTOR, "selected") .addParameter(DRIVER_CONTEXT, "driverContext"); - if (evaluateFinal == null) { + if (aggState.declaredType().isPrimitive()) { builder.addStatement("blocks[offset] = state.toValuesBlock(selected, driverContext)"); } else { + requireStaticMethod( + declarationType, + requireType(BLOCK), + requireName("evaluateFinal"), + requireArgs(requireType(aggState.declaredType()), requireType(INT_VECTOR), requireType(DRIVER_CONTEXT)) + ); builder.addStatement("blocks[offset] = $T.evaluateFinal(state, selected, driverContext)", declarationType); } return builder.build(); @@ -652,32 +717,4 @@ public class GroupingAggregatorImplementer { builder.addStatement("state.close()"); return builder.build(); } - - private static final Pattern PRIMITIVE_STATE_PATTERN = Pattern.compile( - "org.elasticsearch.compute.aggregation.(Boolean|Int|Long|Double|Float)(Fallible)?ArrayState" - ); - - private boolean hasPrimitiveState() { - return PRIMITIVE_STATE_PATTERN.matcher(stateType.toString()).matches(); - } - - private TypeMirror valueTypeMirror() { - return combine.getParameters().get(combine.getParameters().size() - 1).asType(); - } - - private TypeName valueTypeName() { - return TypeName.get(valueTypeMirror()); - } - - private TypeKind valueTypeKind() { - return valueTypeMirror().getKind(); - } - - private String valueTypeString() { - String valueTypeString = TypeName.get(valueTypeMirror()).toString(); - if (valuesIsArray) { - valueTypeString = valueTypeString.substring(0, valueTypeString.length() - 2); - } - return valueTypeString; - } } diff --git a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/Methods.java b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/Methods.java index 6f98f1f797ab..f2fa7b808444 100644 --- a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/Methods.java +++ b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/Methods.java @@ -9,18 +9,22 @@ package org.elasticsearch.compute.gen; import com.squareup.javapoet.TypeName; -import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Set; import java.util.function.Predicate; +import java.util.stream.IntStream; +import java.util.stream.Stream; -import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeKind; import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Elements; +import static java.util.stream.Collectors.joining; import static org.elasticsearch.compute.gen.Types.BOOLEAN_BLOCK; import static org.elasticsearch.compute.gen.Types.BOOLEAN_BLOCK_BUILDER; import static org.elasticsearch.compute.gen.Types.BOOLEAN_VECTOR; @@ -49,30 +53,116 @@ import static org.elasticsearch.compute.gen.Types.LONG_VECTOR_FIXED_BUILDER; * Finds declared methods for the code generator. */ public class Methods { - static ExecutableElement findRequiredMethod(TypeElement declarationType, String[] names, Predicate filter) { - ExecutableElement result = findMethod(names, filter, declarationType, superClassOf(declarationType)); - if (result == null) { - if (names.length == 1) { - throw new IllegalArgumentException(declarationType + "#" + names[0] + " is required"); - } - throw new IllegalArgumentException("one of " + declarationType + "#" + Arrays.toString(names) + " is required"); - } - return result; + + static ExecutableElement requireStaticMethod( + TypeElement declarationType, + TypeMatcher returnTypeMatcher, + NameMatcher nameMatcher, + ArgumentMatcher argumentMatcher + ) { + return typeAndSuperType(declarationType).flatMap(type -> ElementFilter.methodsIn(type.getEnclosedElements()).stream()) + .filter(method -> method.getModifiers().contains(Modifier.STATIC)) + .filter(method -> nameMatcher.test(method.getSimpleName().toString())) + .filter(method -> returnTypeMatcher.test(TypeName.get(method.getReturnType()))) + .filter(method -> argumentMatcher.test(method.getParameters().stream().map(it -> TypeName.get(it.asType())).toList())) + .findFirst() + .orElseThrow(() -> { + var message = nameMatcher.names.size() == 1 ? "Requires method: " : "Requires one of methods: "; + var signatures = nameMatcher.names.stream() + .map(name -> "public static " + returnTypeMatcher + " " + declarationType + "#" + name + "(" + argumentMatcher + ")") + .collect(joining(" or ")); + return new IllegalArgumentException(message + signatures); + }); } - static ExecutableElement findMethod(TypeElement declarationType, String name) { - return findMethod(new String[] { name }, e -> true, declarationType, superClassOf(declarationType)); + static NameMatcher requireName(String... names) { + return new NameMatcher(Set.of(names)); } - private static TypeElement superClassOf(TypeElement declarationType) { - TypeMirror superclass = declarationType.getSuperclass(); - if (superclass instanceof DeclaredType declaredType) { - Element superclassElement = declaredType.asElement(); - if (superclassElement instanceof TypeElement) { - return (TypeElement) superclassElement; - } + static TypeMatcher requireVoidType() { + return new TypeMatcher(type -> Objects.equals(TypeName.VOID, type), "void"); + } + + static TypeMatcher requireAnyType(String description) { + return new TypeMatcher(type -> true, description); + } + + static TypeMatcher requirePrimitiveOrImplements(Elements elements, TypeName requiredInterface) { + return new TypeMatcher( + type -> type.isPrimitive() || isImplementing(elements, type, requiredInterface), + "[boolean|int|long|float|double|" + requiredInterface + "]" + ); + } + + static TypeMatcher requireType(TypeName requiredType) { + return new TypeMatcher(type -> Objects.equals(requiredType, type), requiredType.toString()); + } + + static ArgumentMatcher requireAnyArgs(String description) { + return new ArgumentMatcher(args -> true, description); + } + + static ArgumentMatcher requireArgs(TypeMatcher... argTypes) { + return new ArgumentMatcher( + args -> args.size() == argTypes.length && IntStream.range(0, argTypes.length).allMatch(i -> argTypes[i].test(args.get(i))), + Stream.of(argTypes).map(TypeMatcher::toString).collect(joining(", ")) + ); + } + + record NameMatcher(Set names) implements Predicate { + @Override + public boolean test(String name) { + return names.contains(name); + } + } + + record TypeMatcher(Predicate matcher, String description) implements Predicate { + @Override + public boolean test(TypeName typeName) { + return matcher.test(typeName); + } + + @Override + public String toString() { + return description; + } + } + + record ArgumentMatcher(Predicate> matcher, String description) implements Predicate> { + @Override + public boolean test(List typeName) { + return matcher.test(typeName); + } + + @Override + public String toString() { + return description; + } + } + + private static boolean isImplementing(Elements elements, TypeName type, TypeName requiredInterface) { + return allInterfacesOf(elements, type).anyMatch( + anInterface -> Objects.equals(anInterface.toString(), requiredInterface.toString()) + ); + } + + private static Stream allInterfacesOf(Elements elements, TypeName type) { + var typeElement = elements.getTypeElement(type.toString()); + var superType = Stream.of(typeElement.getSuperclass()).filter(sType -> sType.getKind() != TypeKind.NONE).map(TypeName::get); + var interfaces = typeElement.getInterfaces().stream().map(TypeName::get); + return Stream.concat( + superType.flatMap(sType -> allInterfacesOf(elements, sType)), + interfaces.flatMap(anInterface -> Stream.concat(Stream.of(anInterface), allInterfacesOf(elements, anInterface))) + ); + } + + private static Stream typeAndSuperType(TypeElement declarationType) { + if (declarationType.getSuperclass() instanceof DeclaredType declaredType + && declaredType.asElement() instanceof TypeElement superType) { + return Stream.of(declarationType, superType); + } else { + return Stream.of(declarationType); } - return null; } static ExecutableElement findMethod(TypeElement declarationType, String[] names, Predicate filter) { @@ -95,16 +185,6 @@ public class Methods { return null; } - /** - * Returns the arguments of a method after applying a filter. - */ - static VariableElement[] findMethodArguments(ExecutableElement method, Predicate filter) { - if (method.getParameters().isEmpty()) { - return new VariableElement[0]; - } - return method.getParameters().stream().filter(filter).toArray(VariableElement[]::new); - } - /** * Returns the name of the method used to add {@code valueType} instances * to vector or block builders. diff --git a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/Types.java b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/Types.java index 8b01d957f3bd..fcd9c64be767 100644 --- a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/Types.java +++ b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/Types.java @@ -15,9 +15,13 @@ import com.squareup.javapoet.TypeName; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; +import java.util.Map; +import java.util.stream.Stream; import javax.lang.model.type.TypeMirror; +import static java.util.stream.Collectors.toUnmodifiableMap; + /** * Types used by the code generator. */ @@ -75,27 +79,6 @@ public class Types { static final ClassName DOUBLE_VECTOR_FIXED_BUILDER = ClassName.get(DATA_PACKAGE, "DoubleVector", "FixedBuilder"); static final ClassName FLOAT_VECTOR_FIXED_BUILDER = ClassName.get(DATA_PACKAGE, "FloatVector", "FixedBuilder"); - static final ClassName BOOLEAN_ARRAY_VECTOR = ClassName.get(DATA_PACKAGE, "BooleanArrayVector"); - static final ClassName BYTES_REF_ARRAY_VECTOR = ClassName.get(DATA_PACKAGE, "BytesRefArrayVector"); - static final ClassName INT_ARRAY_VECTOR = ClassName.get(DATA_PACKAGE, "IntArrayVector"); - static final ClassName LONG_ARRAY_VECTOR = ClassName.get(DATA_PACKAGE, "LongArrayVector"); - static final ClassName DOUBLE_ARRAY_VECTOR = ClassName.get(DATA_PACKAGE, "DoubleArrayVector"); - static final ClassName FLOAT_ARRAY_VECTOR = ClassName.get(DATA_PACKAGE, "FloatArrayVector"); - - static final ClassName BOOLEAN_ARRAY_BLOCK = ClassName.get(DATA_PACKAGE, "BooleanArrayBlock"); - static final ClassName BYTES_REF_ARRAY_BLOCK = ClassName.get(DATA_PACKAGE, "BytesRefArrayBlock"); - static final ClassName INT_ARRAY_BLOCK = ClassName.get(DATA_PACKAGE, "IntArrayBlock"); - static final ClassName LONG_ARRAY_BLOCK = ClassName.get(DATA_PACKAGE, "LongArrayBlock"); - static final ClassName DOUBLE_ARRAY_BLOCK = ClassName.get(DATA_PACKAGE, "DoubleArrayBlock"); - static final ClassName FLOAT_ARRAY_BLOCK = ClassName.get(DATA_PACKAGE, "FloatArrayBlock"); - - static final ClassName BOOLEAN_CONSTANT_VECTOR = ClassName.get(DATA_PACKAGE, "ConstantBooleanVector"); - static final ClassName BYTES_REF_CONSTANT_VECTOR = ClassName.get(DATA_PACKAGE, "ConstantBytesRefVector"); - static final ClassName INT_CONSTANT_VECTOR = ClassName.get(DATA_PACKAGE, "ConstantIntVector"); - static final ClassName LONG_CONSTANT_VECTOR = ClassName.get(DATA_PACKAGE, "ConstantLongVector"); - static final ClassName DOUBLE_CONSTANT_VECTOR = ClassName.get(DATA_PACKAGE, "ConstantDoubleVector"); - static final ClassName FLOAT_CONSTANT_VECTOR = ClassName.get(DATA_PACKAGE, "ConstantFloatVector"); - static final ClassName AGGREGATOR_FUNCTION = ClassName.get(AGGREGATION_PACKAGE, "AggregatorFunction"); static final ClassName AGGREGATOR_FUNCTION_SUPPLIER = ClassName.get(AGGREGATION_PACKAGE, "AggregatorFunctionSupplier"); static final ClassName GROUPING_AGGREGATOR_FUNCTION = ClassName.get(AGGREGATION_PACKAGE, "GroupingAggregatorFunction"); @@ -138,89 +121,50 @@ public class Types { static final ClassName RELEASABLE = ClassName.get("org.elasticsearch.core", "Releasable"); static final ClassName RELEASABLES = ClassName.get("org.elasticsearch.core", "Releasables"); + private record TypeDef(TypeName type, String alias, ClassName block, ClassName vector) { + + public static TypeDef of(TypeName type, String alias, String block, String vector) { + return new TypeDef(type, alias, ClassName.get(DATA_PACKAGE, block), ClassName.get(DATA_PACKAGE, vector)); + } + } + + private static final Map TYPES = Stream.of( + TypeDef.of(TypeName.BOOLEAN, "BOOLEAN", "BooleanBlock", "BooleanVector"), + TypeDef.of(TypeName.INT, "INT", "IntBlock", "IntVector"), + TypeDef.of(TypeName.LONG, "LONG", "LongBlock", "LongVector"), + TypeDef.of(TypeName.FLOAT, "FLOAT", "FloatBlock", "FloatVector"), + TypeDef.of(TypeName.DOUBLE, "DOUBLE", "DoubleBlock", "DoubleVector"), + TypeDef.of(BYTES_REF, "BYTES_REF", "BytesRefBlock", "BytesRefVector") + ) + .flatMap(def -> Stream.of(def.type.toString(), def.type + "[]", def.alias).map(alias -> Map.entry(alias, def))) + .collect(toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue)); + + private static TypeDef findRequired(String name, String kind) { + TypeDef typeDef = TYPES.get(name); + if (typeDef == null) { + throw new IllegalArgumentException("unknown " + kind + " type [" + name + "]"); + } + return typeDef; + } + + static TypeName fromString(String type) { + return findRequired(type, "plain").type; + } + static ClassName blockType(TypeName elementType) { - if (elementType.equals(TypeName.BOOLEAN)) { - return BOOLEAN_BLOCK; - } - if (elementType.equals(BYTES_REF)) { - return BYTES_REF_BLOCK; - } - if (elementType.equals(TypeName.INT)) { - return INT_BLOCK; - } - if (elementType.equals(TypeName.LONG)) { - return LONG_BLOCK; - } - if (elementType.equals(TypeName.DOUBLE)) { - return DOUBLE_BLOCK; - } - throw new IllegalArgumentException("unknown block type for [" + elementType + "]"); + return blockType(elementType.toString()); } static ClassName blockType(String elementType) { - if (elementType.equalsIgnoreCase(TypeName.BOOLEAN.toString())) { - return BOOLEAN_BLOCK; - } - if (elementType.equalsIgnoreCase("BYTES_REF")) { - return BYTES_REF_BLOCK; - } - if (elementType.equalsIgnoreCase(TypeName.INT.toString())) { - return INT_BLOCK; - } - if (elementType.equalsIgnoreCase(TypeName.LONG.toString())) { - return LONG_BLOCK; - } - if (elementType.equalsIgnoreCase(TypeName.DOUBLE.toString())) { - return DOUBLE_BLOCK; - } - if (elementType.equalsIgnoreCase(TypeName.FLOAT.toString())) { - return FLOAT_BLOCK; - } - throw new IllegalArgumentException("unknown vector type for [" + elementType + "]"); + return findRequired(elementType, "block").block; } static ClassName vectorType(TypeName elementType) { - if (elementType.equals(TypeName.BOOLEAN)) { - return BOOLEAN_VECTOR; - } - if (elementType.equals(BYTES_REF)) { - return BYTES_REF_VECTOR; - } - if (elementType.equals(TypeName.INT)) { - return INT_VECTOR; - } - if (elementType.equals(TypeName.LONG)) { - return LONG_VECTOR; - } - if (elementType.equals(TypeName.DOUBLE)) { - return DOUBLE_VECTOR; - } - if (elementType.equals(TypeName.FLOAT)) { - return FLOAT_VECTOR; - } - throw new IllegalArgumentException("unknown vector type for [" + elementType + "]"); + return vectorType(elementType.toString()); } static ClassName vectorType(String elementType) { - if (elementType.equalsIgnoreCase(TypeName.BOOLEAN.toString())) { - return BOOLEAN_VECTOR; - } - if (elementType.equalsIgnoreCase("BYTES_REF")) { - return BYTES_REF_VECTOR; - } - if (elementType.equalsIgnoreCase(TypeName.INT.toString())) { - return INT_VECTOR; - } - if (elementType.equalsIgnoreCase(TypeName.LONG.toString())) { - return LONG_VECTOR; - } - if (elementType.equalsIgnoreCase(TypeName.DOUBLE.toString())) { - return DOUBLE_VECTOR; - } - if (elementType.equalsIgnoreCase(TypeName.FLOAT.toString())) { - return FLOAT_VECTOR; - } - throw new IllegalArgumentException("unknown vector type for [" + elementType + "]"); + return findRequired(elementType, "vector").vector; } static ClassName builderType(TypeName resultType) { @@ -282,63 +226,6 @@ public class Types { throw new IllegalArgumentException("unknown vector fixed builder type for [" + elementType + "]"); } - static ClassName arrayVectorType(TypeName elementType) { - if (elementType.equals(TypeName.BOOLEAN)) { - return BOOLEAN_ARRAY_VECTOR; - } - if (elementType.equals(BYTES_REF)) { - return BYTES_REF_ARRAY_VECTOR; - } - if (elementType.equals(TypeName.INT)) { - return INT_ARRAY_VECTOR; - } - if (elementType.equals(TypeName.LONG)) { - return LONG_ARRAY_VECTOR; - } - if (elementType.equals(TypeName.DOUBLE)) { - return DOUBLE_ARRAY_VECTOR; - } - throw new IllegalArgumentException("unknown vector type for [" + elementType + "]"); - } - - static ClassName arrayBlockType(TypeName elementType) { - if (elementType.equals(TypeName.BOOLEAN)) { - return BOOLEAN_ARRAY_BLOCK; - } - if (elementType.equals(BYTES_REF)) { - return BYTES_REF_ARRAY_BLOCK; - } - if (elementType.equals(TypeName.INT)) { - return INT_ARRAY_BLOCK; - } - if (elementType.equals(TypeName.LONG)) { - return LONG_ARRAY_BLOCK; - } - if (elementType.equals(TypeName.DOUBLE)) { - return DOUBLE_ARRAY_BLOCK; - } - throw new IllegalArgumentException("unknown vector type for [" + elementType + "]"); - } - - static ClassName constantVectorType(TypeName elementType) { - if (elementType.equals(TypeName.BOOLEAN)) { - return BOOLEAN_CONSTANT_VECTOR; - } - if (elementType.equals(BYTES_REF)) { - return BYTES_REF_CONSTANT_VECTOR; - } - if (elementType.equals(TypeName.INT)) { - return INT_CONSTANT_VECTOR; - } - if (elementType.equals(TypeName.LONG)) { - return LONG_CONSTANT_VECTOR; - } - if (elementType.equals(TypeName.DOUBLE)) { - return DOUBLE_CONSTANT_VECTOR; - } - throw new IllegalArgumentException("unknown vector type for [" + elementType + "]"); - } - static TypeName elementType(TypeName t) { if (t.equals(BOOLEAN_BLOCK) || t.equals(BOOLEAN_VECTOR) || t.equals(BOOLEAN_BLOCK_BUILDER)) { return TypeName.BOOLEAN; diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBooleanAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBooleanAggregatorFunctionSupplier.java index 6ea78052c5f5..bbfb2a34f920 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBooleanAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBooleanAggregatorFunctionSupplier.java @@ -15,20 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class CountDistinctBooleanAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public CountDistinctBooleanAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public CountDistinctBooleanAggregatorFunctionSupplier() { } @Override - public CountDistinctBooleanAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return CountDistinctBooleanAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return CountDistinctBooleanGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public CountDistinctBooleanAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return CountDistinctBooleanAggregatorFunction.create(driverContext, channels); } @Override public CountDistinctBooleanGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return CountDistinctBooleanGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBytesRefAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBytesRefAggregatorFunctionSupplier.java index 9191b7d7cfa5..cb92d715c91d 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBytesRefAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBytesRefAggregatorFunctionSupplier.java @@ -15,23 +15,31 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class CountDistinctBytesRefAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final int precision; - public CountDistinctBytesRefAggregatorFunctionSupplier(List channels, int precision) { - this.channels = channels; + public CountDistinctBytesRefAggregatorFunctionSupplier(int precision) { this.precision = precision; } @Override - public CountDistinctBytesRefAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return CountDistinctBytesRefAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return CountDistinctBytesRefGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public CountDistinctBytesRefAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return CountDistinctBytesRefAggregatorFunction.create(driverContext, channels, precision); } @Override public CountDistinctBytesRefGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return CountDistinctBytesRefGroupingAggregatorFunction.create(channels, driverContext, precision); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctDoubleAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctDoubleAggregatorFunctionSupplier.java index 08153afd30d8..f4d9c2425b4e 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctDoubleAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctDoubleAggregatorFunctionSupplier.java @@ -15,23 +15,31 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class CountDistinctDoubleAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final int precision; - public CountDistinctDoubleAggregatorFunctionSupplier(List channels, int precision) { - this.channels = channels; + public CountDistinctDoubleAggregatorFunctionSupplier(int precision) { this.precision = precision; } @Override - public CountDistinctDoubleAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return CountDistinctDoubleAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return CountDistinctDoubleGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public CountDistinctDoubleAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return CountDistinctDoubleAggregatorFunction.create(driverContext, channels, precision); } @Override public CountDistinctDoubleGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return CountDistinctDoubleGroupingAggregatorFunction.create(channels, driverContext, precision); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctFloatAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctFloatAggregatorFunctionSupplier.java index a107f38d07a5..f4c941d8d7f5 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctFloatAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctFloatAggregatorFunctionSupplier.java @@ -15,23 +15,31 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class CountDistinctFloatAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final int precision; - public CountDistinctFloatAggregatorFunctionSupplier(List channels, int precision) { - this.channels = channels; + public CountDistinctFloatAggregatorFunctionSupplier(int precision) { this.precision = precision; } @Override - public CountDistinctFloatAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return CountDistinctFloatAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return CountDistinctFloatGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public CountDistinctFloatAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return CountDistinctFloatAggregatorFunction.create(driverContext, channels, precision); } @Override public CountDistinctFloatGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return CountDistinctFloatGroupingAggregatorFunction.create(channels, driverContext, precision); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctIntAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctIntAggregatorFunctionSupplier.java index 891b2f7f553e..8a09acde9156 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctIntAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctIntAggregatorFunctionSupplier.java @@ -15,23 +15,31 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class CountDistinctIntAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final int precision; - public CountDistinctIntAggregatorFunctionSupplier(List channels, int precision) { - this.channels = channels; + public CountDistinctIntAggregatorFunctionSupplier(int precision) { this.precision = precision; } @Override - public CountDistinctIntAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return CountDistinctIntAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return CountDistinctIntGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public CountDistinctIntAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return CountDistinctIntAggregatorFunction.create(driverContext, channels, precision); } @Override - public CountDistinctIntGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + public CountDistinctIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return CountDistinctIntGroupingAggregatorFunction.create(channels, driverContext, precision); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctLongAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctLongAggregatorFunctionSupplier.java index b9b171c45f88..1443fb6d66e6 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctLongAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctLongAggregatorFunctionSupplier.java @@ -15,23 +15,31 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class CountDistinctLongAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final int precision; - public CountDistinctLongAggregatorFunctionSupplier(List channels, int precision) { - this.channels = channels; + public CountDistinctLongAggregatorFunctionSupplier(int precision) { this.precision = precision; } @Override - public CountDistinctLongAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return CountDistinctLongAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return CountDistinctLongGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public CountDistinctLongAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return CountDistinctLongAggregatorFunction.create(driverContext, channels, precision); } @Override - public CountDistinctLongGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + public CountDistinctLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return CountDistinctLongGroupingAggregatorFunction.create(channels, driverContext, precision); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBooleanAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBooleanAggregatorFunctionSupplier.java index d000f49920a3..e8ccdb92e519 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBooleanAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBooleanAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MaxBooleanAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MaxBooleanAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MaxBooleanAggregatorFunctionSupplier() { } @Override - public MaxBooleanAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MaxBooleanAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MaxBooleanGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MaxBooleanAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return MaxBooleanAggregatorFunction.create(driverContext, channels); } @Override - public MaxBooleanGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MaxBooleanGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MaxBooleanGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBytesRefAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBytesRefAggregatorFunctionSupplier.java index 9c97ce88c006..bc52373bb933 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBytesRefAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBytesRefAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MaxBytesRefAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MaxBytesRefAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MaxBytesRefAggregatorFunctionSupplier() { } @Override - public MaxBytesRefAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MaxBytesRefAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MaxBytesRefGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MaxBytesRefAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return MaxBytesRefAggregatorFunction.create(driverContext, channels); } @Override - public MaxBytesRefGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MaxBytesRefGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MaxBytesRefGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxDoubleAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxDoubleAggregatorFunctionSupplier.java index df4d2749c436..417cb4b7c9c3 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxDoubleAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxDoubleAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MaxDoubleAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MaxDoubleAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MaxDoubleAggregatorFunctionSupplier() { } @Override - public MaxDoubleAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MaxDoubleAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MaxDoubleGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MaxDoubleAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return MaxDoubleAggregatorFunction.create(driverContext, channels); } @Override - public MaxDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MaxDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MaxDoubleGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxFloatAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxFloatAggregatorFunctionSupplier.java index 70628ace17f3..3279506e75af 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxFloatAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxFloatAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MaxFloatAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MaxFloatAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MaxFloatAggregatorFunctionSupplier() { } @Override - public MaxFloatAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MaxFloatAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MaxFloatGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MaxFloatAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return MaxFloatAggregatorFunction.create(driverContext, channels); } @Override - public MaxFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MaxFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MaxFloatGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIntAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIntAggregatorFunctionSupplier.java index c2c6fdcb8e1a..0e1dca2b52f0 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIntAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIntAggregatorFunctionSupplier.java @@ -15,19 +15,27 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MaxIntAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MaxIntAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MaxIntAggregatorFunctionSupplier() { } @Override - public MaxIntAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MaxIntAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MaxIntGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MaxIntAggregatorFunction aggregator(DriverContext driverContext, List channels) { return MaxIntAggregatorFunction.create(driverContext, channels); } @Override - public MaxIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MaxIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MaxIntGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIpAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIpAggregatorFunctionSupplier.java index cd08981c7b2a..fa84acd602af 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIpAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIpAggregatorFunctionSupplier.java @@ -15,19 +15,27 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MaxIpAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MaxIpAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MaxIpAggregatorFunctionSupplier() { } @Override - public MaxIpAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MaxIpAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MaxIpGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MaxIpAggregatorFunction aggregator(DriverContext driverContext, List channels) { return MaxIpAggregatorFunction.create(driverContext, channels); } @Override - public MaxIpGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MaxIpGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MaxIpGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxLongAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxLongAggregatorFunctionSupplier.java index 0a56f3107600..7683622aadd1 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxLongAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxLongAggregatorFunctionSupplier.java @@ -15,19 +15,27 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MaxLongAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MaxLongAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MaxLongAggregatorFunctionSupplier() { } @Override - public MaxLongAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MaxLongAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MaxLongGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MaxLongAggregatorFunction aggregator(DriverContext driverContext, List channels) { return MaxLongAggregatorFunction.create(driverContext, channels); } @Override - public MaxLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MaxLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MaxLongGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier.java index b78346f4b57b..08ae3c3fe866 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier.java @@ -15,20 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier() { } @Override - public MedianAbsoluteDeviationDoubleAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MedianAbsoluteDeviationDoubleAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MedianAbsoluteDeviationDoubleGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MedianAbsoluteDeviationDoubleAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return MedianAbsoluteDeviationDoubleAggregatorFunction.create(driverContext, channels); } @Override public MedianAbsoluteDeviationDoubleGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return MedianAbsoluteDeviationDoubleGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatAggregatorFunctionSupplier.java index 069f125c0347..d63c9ce2dcdc 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatAggregatorFunctionSupplier.java @@ -15,20 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MedianAbsoluteDeviationFloatAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MedianAbsoluteDeviationFloatAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MedianAbsoluteDeviationFloatAggregatorFunctionSupplier() { } @Override - public MedianAbsoluteDeviationFloatAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MedianAbsoluteDeviationFloatAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MedianAbsoluteDeviationFloatGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MedianAbsoluteDeviationFloatAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return MedianAbsoluteDeviationFloatAggregatorFunction.create(driverContext, channels); } @Override public MedianAbsoluteDeviationFloatGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return MedianAbsoluteDeviationFloatGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntAggregatorFunctionSupplier.java index 147809fae080..c496749ff19e 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntAggregatorFunctionSupplier.java @@ -15,20 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MedianAbsoluteDeviationIntAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MedianAbsoluteDeviationIntAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MedianAbsoluteDeviationIntAggregatorFunctionSupplier() { } @Override - public MedianAbsoluteDeviationIntAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MedianAbsoluteDeviationIntAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MedianAbsoluteDeviationIntGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MedianAbsoluteDeviationIntAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return MedianAbsoluteDeviationIntAggregatorFunction.create(driverContext, channels); } @Override public MedianAbsoluteDeviationIntGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return MedianAbsoluteDeviationIntGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongAggregatorFunctionSupplier.java index 1246c96941c3..25af01363494 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongAggregatorFunctionSupplier.java @@ -15,20 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MedianAbsoluteDeviationLongAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MedianAbsoluteDeviationLongAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MedianAbsoluteDeviationLongAggregatorFunctionSupplier() { } @Override - public MedianAbsoluteDeviationLongAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MedianAbsoluteDeviationLongAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MedianAbsoluteDeviationLongGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MedianAbsoluteDeviationLongAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return MedianAbsoluteDeviationLongAggregatorFunction.create(driverContext, channels); } @Override public MedianAbsoluteDeviationLongGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return MedianAbsoluteDeviationLongGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBooleanAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBooleanAggregatorFunctionSupplier.java index 02d2fda11ff7..53f80570e397 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBooleanAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBooleanAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MinBooleanAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MinBooleanAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MinBooleanAggregatorFunctionSupplier() { } @Override - public MinBooleanAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MinBooleanAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MinBooleanGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MinBooleanAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return MinBooleanAggregatorFunction.create(driverContext, channels); } @Override - public MinBooleanGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MinBooleanGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MinBooleanGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBytesRefAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBytesRefAggregatorFunctionSupplier.java index 65e7b4b58e94..258894797698 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBytesRefAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBytesRefAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MinBytesRefAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MinBytesRefAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MinBytesRefAggregatorFunctionSupplier() { } @Override - public MinBytesRefAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MinBytesRefAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MinBytesRefGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MinBytesRefAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return MinBytesRefAggregatorFunction.create(driverContext, channels); } @Override - public MinBytesRefGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MinBytesRefGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MinBytesRefGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinDoubleAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinDoubleAggregatorFunctionSupplier.java index 18aadce9baa5..3af1017b5de2 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinDoubleAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinDoubleAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MinDoubleAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MinDoubleAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MinDoubleAggregatorFunctionSupplier() { } @Override - public MinDoubleAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MinDoubleAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MinDoubleGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MinDoubleAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return MinDoubleAggregatorFunction.create(driverContext, channels); } @Override - public MinDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MinDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MinDoubleGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinFloatAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinFloatAggregatorFunctionSupplier.java index 04d08ed6ea4b..c120706ebba2 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinFloatAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinFloatAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MinFloatAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MinFloatAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MinFloatAggregatorFunctionSupplier() { } @Override - public MinFloatAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MinFloatAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MinFloatGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MinFloatAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return MinFloatAggregatorFunction.create(driverContext, channels); } @Override - public MinFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MinFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MinFloatGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIntAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIntAggregatorFunctionSupplier.java index 51761433e025..c44b47bad0cf 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIntAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIntAggregatorFunctionSupplier.java @@ -15,19 +15,27 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MinIntAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MinIntAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MinIntAggregatorFunctionSupplier() { } @Override - public MinIntAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MinIntAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MinIntGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MinIntAggregatorFunction aggregator(DriverContext driverContext, List channels) { return MinIntAggregatorFunction.create(driverContext, channels); } @Override - public MinIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MinIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MinIntGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIpAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIpAggregatorFunctionSupplier.java index dd066820b50e..a00ebdb43e1a 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIpAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIpAggregatorFunctionSupplier.java @@ -15,19 +15,27 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MinIpAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MinIpAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MinIpAggregatorFunctionSupplier() { } @Override - public MinIpAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MinIpAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MinIpGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MinIpAggregatorFunction aggregator(DriverContext driverContext, List channels) { return MinIpAggregatorFunction.create(driverContext, channels); } @Override - public MinIpGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MinIpGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MinIpGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinLongAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinLongAggregatorFunctionSupplier.java index 58311b65589f..850ae6284e0f 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinLongAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinLongAggregatorFunctionSupplier.java @@ -15,19 +15,27 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class MinLongAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public MinLongAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public MinLongAggregatorFunctionSupplier() { } @Override - public MinLongAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return MinLongAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return MinLongGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public MinLongAggregatorFunction aggregator(DriverContext driverContext, List channels) { return MinLongAggregatorFunction.create(driverContext, channels); } @Override - public MinLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public MinLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return MinLongGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileDoubleAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileDoubleAggregatorFunctionSupplier.java index 28fe487f9919..bd50841421a6 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileDoubleAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileDoubleAggregatorFunctionSupplier.java @@ -15,23 +15,31 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class PercentileDoubleAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final double percentile; - public PercentileDoubleAggregatorFunctionSupplier(List channels, double percentile) { - this.channels = channels; + public PercentileDoubleAggregatorFunctionSupplier(double percentile) { this.percentile = percentile; } @Override - public PercentileDoubleAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return PercentileDoubleAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return PercentileDoubleGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public PercentileDoubleAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return PercentileDoubleAggregatorFunction.create(driverContext, channels, percentile); } @Override - public PercentileDoubleGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + public PercentileDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return PercentileDoubleGroupingAggregatorFunction.create(channels, driverContext, percentile); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileFloatAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileFloatAggregatorFunctionSupplier.java index 4288d062ec23..d705ad8da70d 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileFloatAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileFloatAggregatorFunctionSupplier.java @@ -15,22 +15,31 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class PercentileFloatAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final double percentile; - public PercentileFloatAggregatorFunctionSupplier(List channels, double percentile) { - this.channels = channels; + public PercentileFloatAggregatorFunctionSupplier(double percentile) { this.percentile = percentile; } @Override - public PercentileFloatAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return PercentileFloatAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return PercentileFloatGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public PercentileFloatAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return PercentileFloatAggregatorFunction.create(driverContext, channels, percentile); } @Override - public PercentileFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public PercentileFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return PercentileFloatGroupingAggregatorFunction.create(channels, driverContext, percentile); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileIntAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileIntAggregatorFunctionSupplier.java index 3a9996aed0d8..d925ef91ed6e 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileIntAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileIntAggregatorFunctionSupplier.java @@ -15,22 +15,31 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class PercentileIntAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final double percentile; - public PercentileIntAggregatorFunctionSupplier(List channels, double percentile) { - this.channels = channels; + public PercentileIntAggregatorFunctionSupplier(double percentile) { this.percentile = percentile; } @Override - public PercentileIntAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return PercentileIntAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return PercentileIntGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public PercentileIntAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return PercentileIntAggregatorFunction.create(driverContext, channels, percentile); } @Override - public PercentileIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public PercentileIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return PercentileIntGroupingAggregatorFunction.create(channels, driverContext, percentile); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileLongAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileLongAggregatorFunctionSupplier.java index d3cdf57a1862..36d2ed23cee9 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileLongAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileLongAggregatorFunctionSupplier.java @@ -15,22 +15,31 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class PercentileLongAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final double percentile; - public PercentileLongAggregatorFunctionSupplier(List channels, double percentile) { - this.channels = channels; + public PercentileLongAggregatorFunctionSupplier(double percentile) { this.percentile = percentile; } @Override - public PercentileLongAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return PercentileLongAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return PercentileLongGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public PercentileLongAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return PercentileLongAggregatorFunction.create(driverContext, channels, percentile); } @Override - public PercentileLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public PercentileLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return PercentileLongGroupingAggregatorFunction.create(channels, driverContext, percentile); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateDoubleAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateDoubleAggregatorFunctionSupplier.java index 92d73864fa77..d2dd780bf43a 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateDoubleAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateDoubleAggregatorFunctionSupplier.java @@ -15,22 +15,30 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class RateDoubleAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final long unitInMillis; - public RateDoubleAggregatorFunctionSupplier(List channels, long unitInMillis) { - this.channels = channels; + public RateDoubleAggregatorFunctionSupplier(long unitInMillis) { this.unitInMillis = unitInMillis; } @Override - public AggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { throw new UnsupportedOperationException("non-grouping aggregator is not supported"); } @Override - public RateDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public List groupingIntermediateStateDesc() { + return RateDoubleGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public AggregatorFunction aggregator(DriverContext driverContext, List channels) { + throw new UnsupportedOperationException("non-grouping aggregator is not supported"); + } + + @Override + public RateDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return RateDoubleGroupingAggregatorFunction.create(channels, driverContext, unitInMillis); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateFloatAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateFloatAggregatorFunctionSupplier.java index d4914ba36e80..be8456b28b3f 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateFloatAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateFloatAggregatorFunctionSupplier.java @@ -15,22 +15,30 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class RateFloatAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final long unitInMillis; - public RateFloatAggregatorFunctionSupplier(List channels, long unitInMillis) { - this.channels = channels; + public RateFloatAggregatorFunctionSupplier(long unitInMillis) { this.unitInMillis = unitInMillis; } @Override - public AggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { throw new UnsupportedOperationException("non-grouping aggregator is not supported"); } @Override - public RateFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public List groupingIntermediateStateDesc() { + return RateFloatGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public AggregatorFunction aggregator(DriverContext driverContext, List channels) { + throw new UnsupportedOperationException("non-grouping aggregator is not supported"); + } + + @Override + public RateFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return RateFloatGroupingAggregatorFunction.create(channels, driverContext, unitInMillis); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateIntAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateIntAggregatorFunctionSupplier.java index 6c0fd0ed2195..c9c6ce5a55be 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateIntAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateIntAggregatorFunctionSupplier.java @@ -15,22 +15,30 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class RateIntAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final long unitInMillis; - public RateIntAggregatorFunctionSupplier(List channels, long unitInMillis) { - this.channels = channels; + public RateIntAggregatorFunctionSupplier(long unitInMillis) { this.unitInMillis = unitInMillis; } @Override - public AggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { throw new UnsupportedOperationException("non-grouping aggregator is not supported"); } @Override - public RateIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public List groupingIntermediateStateDesc() { + return RateIntGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public AggregatorFunction aggregator(DriverContext driverContext, List channels) { + throw new UnsupportedOperationException("non-grouping aggregator is not supported"); + } + + @Override + public RateIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return RateIntGroupingAggregatorFunction.create(channels, driverContext, unitInMillis); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateLongAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateLongAggregatorFunctionSupplier.java index 311616effba3..a1f503b726aa 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateLongAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateLongAggregatorFunctionSupplier.java @@ -15,22 +15,30 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class RateLongAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final long unitInMillis; - public RateLongAggregatorFunctionSupplier(List channels, long unitInMillis) { - this.channels = channels; + public RateLongAggregatorFunctionSupplier(long unitInMillis) { this.unitInMillis = unitInMillis; } @Override - public AggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { throw new UnsupportedOperationException("non-grouping aggregator is not supported"); } @Override - public RateLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public List groupingIntermediateStateDesc() { + return RateLongGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public AggregatorFunction aggregator(DriverContext driverContext, List channels) { + throw new UnsupportedOperationException("non-grouping aggregator is not supported"); + } + + @Override + public RateLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return RateLongGroupingAggregatorFunction.create(channels, driverContext, unitInMillis); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevDoubleAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevDoubleAggregatorFunctionSupplier.java index caf53dad23b0..5310a11c1fdd 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevDoubleAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevDoubleAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class StdDevDoubleAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public StdDevDoubleAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public StdDevDoubleAggregatorFunctionSupplier() { } @Override - public StdDevDoubleAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return StdDevDoubleAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return StdDevDoubleGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public StdDevDoubleAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return StdDevDoubleAggregatorFunction.create(driverContext, channels); } @Override - public StdDevDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public StdDevDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return StdDevDoubleGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevFloatAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevFloatAggregatorFunctionSupplier.java index c807c1582e1c..52ffb0f5d580 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevFloatAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevFloatAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class StdDevFloatAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public StdDevFloatAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public StdDevFloatAggregatorFunctionSupplier() { } @Override - public StdDevFloatAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return StdDevFloatAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return StdDevFloatGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public StdDevFloatAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return StdDevFloatAggregatorFunction.create(driverContext, channels); } @Override - public StdDevFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public StdDevFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return StdDevFloatGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevIntAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevIntAggregatorFunctionSupplier.java index 36560af8557e..2f43a867bf83 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevIntAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevIntAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class StdDevIntAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public StdDevIntAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public StdDevIntAggregatorFunctionSupplier() { } @Override - public StdDevIntAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return StdDevIntAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return StdDevIntGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public StdDevIntAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return StdDevIntAggregatorFunction.create(driverContext, channels); } @Override - public StdDevIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public StdDevIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return StdDevIntGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevLongAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevLongAggregatorFunctionSupplier.java index dc6ed063031e..364fc4820c28 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevLongAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevLongAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class StdDevLongAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public StdDevLongAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public StdDevLongAggregatorFunctionSupplier() { } @Override - public StdDevLongAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return StdDevLongAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return StdDevLongGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public StdDevLongAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return StdDevLongAggregatorFunction.create(driverContext, channels); } @Override - public StdDevLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public StdDevLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return StdDevLongGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumDoubleAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumDoubleAggregatorFunctionSupplier.java index a88b6ddc3bf5..6fbe13d696ec 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumDoubleAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumDoubleAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SumDoubleAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public SumDoubleAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public SumDoubleAggregatorFunctionSupplier() { } @Override - public SumDoubleAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return SumDoubleAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SumDoubleGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public SumDoubleAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return SumDoubleAggregatorFunction.create(driverContext, channels); } @Override - public SumDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public SumDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return SumDoubleGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumFloatAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumFloatAggregatorFunctionSupplier.java index 5a01eaeaafd3..9b9d863fc817 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumFloatAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumFloatAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SumFloatAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public SumFloatAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public SumFloatAggregatorFunctionSupplier() { } @Override - public SumFloatAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return SumFloatAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SumFloatGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public SumFloatAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return SumFloatAggregatorFunction.create(driverContext, channels); } @Override - public SumFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public SumFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return SumFloatGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumIntAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumIntAggregatorFunctionSupplier.java index bef192a06c3d..ef48162d214b 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumIntAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumIntAggregatorFunctionSupplier.java @@ -15,19 +15,27 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SumIntAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public SumIntAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public SumIntAggregatorFunctionSupplier() { } @Override - public SumIntAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return SumIntAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SumIntGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public SumIntAggregatorFunction aggregator(DriverContext driverContext, List channels) { return SumIntAggregatorFunction.create(driverContext, channels); } @Override - public SumIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public SumIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return SumIntGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumLongAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumLongAggregatorFunctionSupplier.java index 9f5f3d7d493a..fe666c535f63 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumLongAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumLongAggregatorFunctionSupplier.java @@ -15,19 +15,27 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SumLongAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public SumLongAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public SumLongAggregatorFunctionSupplier() { } @Override - public SumLongAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return SumLongAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SumLongGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public SumLongAggregatorFunction aggregator(DriverContext driverContext, List channels) { return SumLongAggregatorFunction.create(driverContext, channels); } @Override - public SumLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public SumLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return SumLongGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBooleanAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBooleanAggregatorFunctionSupplier.java index aebe53c4c4fb..5ee84e44bad6 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBooleanAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBooleanAggregatorFunctionSupplier.java @@ -15,26 +15,34 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class TopBooleanAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final int limit; private final boolean ascending; - public TopBooleanAggregatorFunctionSupplier(List channels, int limit, - boolean ascending) { - this.channels = channels; + public TopBooleanAggregatorFunctionSupplier(int limit, boolean ascending) { this.limit = limit; this.ascending = ascending; } @Override - public TopBooleanAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return TopBooleanAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return TopBooleanGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public TopBooleanAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return TopBooleanAggregatorFunction.create(driverContext, channels, limit, ascending); } @Override - public TopBooleanGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public TopBooleanGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return TopBooleanGroupingAggregatorFunction.create(channels, driverContext, limit, ascending); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBytesRefAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBytesRefAggregatorFunctionSupplier.java index 9108cfcef189..89417c4a98ad 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBytesRefAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBytesRefAggregatorFunctionSupplier.java @@ -15,26 +15,34 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class TopBytesRefAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final int limit; private final boolean ascending; - public TopBytesRefAggregatorFunctionSupplier(List channels, int limit, - boolean ascending) { - this.channels = channels; + public TopBytesRefAggregatorFunctionSupplier(int limit, boolean ascending) { this.limit = limit; this.ascending = ascending; } @Override - public TopBytesRefAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return TopBytesRefAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return TopBytesRefGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public TopBytesRefAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return TopBytesRefAggregatorFunction.create(driverContext, channels, limit, ascending); } @Override - public TopBytesRefGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public TopBytesRefGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return TopBytesRefGroupingAggregatorFunction.create(channels, driverContext, limit, ascending); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopDoubleAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopDoubleAggregatorFunctionSupplier.java index 3e65be2efb21..0aa10d3cc48e 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopDoubleAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopDoubleAggregatorFunctionSupplier.java @@ -15,25 +15,34 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class TopDoubleAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final int limit; private final boolean ascending; - public TopDoubleAggregatorFunctionSupplier(List channels, int limit, boolean ascending) { - this.channels = channels; + public TopDoubleAggregatorFunctionSupplier(int limit, boolean ascending) { this.limit = limit; this.ascending = ascending; } @Override - public TopDoubleAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return TopDoubleAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return TopDoubleGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public TopDoubleAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return TopDoubleAggregatorFunction.create(driverContext, channels, limit, ascending); } @Override - public TopDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public TopDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return TopDoubleGroupingAggregatorFunction.create(channels, driverContext, limit, ascending); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopFloatAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopFloatAggregatorFunctionSupplier.java index 79561a349cef..52e2dbc30495 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopFloatAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopFloatAggregatorFunctionSupplier.java @@ -15,25 +15,34 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class TopFloatAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final int limit; private final boolean ascending; - public TopFloatAggregatorFunctionSupplier(List channels, int limit, boolean ascending) { - this.channels = channels; + public TopFloatAggregatorFunctionSupplier(int limit, boolean ascending) { this.limit = limit; this.ascending = ascending; } @Override - public TopFloatAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return TopFloatAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return TopFloatGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public TopFloatAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return TopFloatAggregatorFunction.create(driverContext, channels, limit, ascending); } @Override - public TopFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public TopFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return TopFloatGroupingAggregatorFunction.create(channels, driverContext, limit, ascending); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIntAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIntAggregatorFunctionSupplier.java index cd7690f18900..88919a4b25ce 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIntAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIntAggregatorFunctionSupplier.java @@ -15,25 +15,33 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class TopIntAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final int limit; private final boolean ascending; - public TopIntAggregatorFunctionSupplier(List channels, int limit, boolean ascending) { - this.channels = channels; + public TopIntAggregatorFunctionSupplier(int limit, boolean ascending) { this.limit = limit; this.ascending = ascending; } @Override - public TopIntAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return TopIntAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return TopIntGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public TopIntAggregatorFunction aggregator(DriverContext driverContext, List channels) { return TopIntAggregatorFunction.create(driverContext, channels, limit, ascending); } @Override - public TopIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public TopIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return TopIntGroupingAggregatorFunction.create(channels, driverContext, limit, ascending); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIpAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIpAggregatorFunctionSupplier.java index 9b137b39d8e8..461f9809b673 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIpAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIpAggregatorFunctionSupplier.java @@ -15,25 +15,33 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class TopIpAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final int limit; private final boolean ascending; - public TopIpAggregatorFunctionSupplier(List channels, int limit, boolean ascending) { - this.channels = channels; + public TopIpAggregatorFunctionSupplier(int limit, boolean ascending) { this.limit = limit; this.ascending = ascending; } @Override - public TopIpAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return TopIpAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return TopIpGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public TopIpAggregatorFunction aggregator(DriverContext driverContext, List channels) { return TopIpAggregatorFunction.create(driverContext, channels, limit, ascending); } @Override - public TopIpGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public TopIpGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return TopIpGroupingAggregatorFunction.create(channels, driverContext, limit, ascending); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopLongAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopLongAggregatorFunctionSupplier.java index 8fd7f5913598..cefd6082c22e 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopLongAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopLongAggregatorFunctionSupplier.java @@ -15,25 +15,33 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class TopLongAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - private final int limit; private final boolean ascending; - public TopLongAggregatorFunctionSupplier(List channels, int limit, boolean ascending) { - this.channels = channels; + public TopLongAggregatorFunctionSupplier(int limit, boolean ascending) { this.limit = limit; this.ascending = ascending; } @Override - public TopLongAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return TopLongAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return TopLongGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public TopLongAggregatorFunction aggregator(DriverContext driverContext, List channels) { return TopLongAggregatorFunction.create(driverContext, channels, limit, ascending); } @Override - public TopLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public TopLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return TopLongGroupingAggregatorFunction.create(channels, driverContext, limit, ascending); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBooleanAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBooleanAggregatorFunctionSupplier.java index b15dd0ed696a..80279a8d6c73 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBooleanAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBooleanAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class ValuesBooleanAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public ValuesBooleanAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public ValuesBooleanAggregatorFunctionSupplier() { } @Override - public ValuesBooleanAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return ValuesBooleanAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return ValuesBooleanGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public ValuesBooleanAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return ValuesBooleanAggregatorFunction.create(driverContext, channels); } @Override - public ValuesBooleanGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public ValuesBooleanGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return ValuesBooleanGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregatorFunctionSupplier.java index c09331bf1970..16fa41876122 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class ValuesBytesRefAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public ValuesBytesRefAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public ValuesBytesRefAggregatorFunctionSupplier() { } @Override - public ValuesBytesRefAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return ValuesBytesRefAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return ValuesBytesRefGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public ValuesBytesRefAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return ValuesBytesRefAggregatorFunction.create(driverContext, channels); } @Override - public ValuesBytesRefGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public ValuesBytesRefGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return ValuesBytesRefGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesDoubleAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesDoubleAggregatorFunctionSupplier.java index c8f93159eb3c..0a70a3d71ef9 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesDoubleAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesDoubleAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class ValuesDoubleAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public ValuesDoubleAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public ValuesDoubleAggregatorFunctionSupplier() { } @Override - public ValuesDoubleAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return ValuesDoubleAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return ValuesDoubleGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public ValuesDoubleAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return ValuesDoubleAggregatorFunction.create(driverContext, channels); } @Override - public ValuesDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public ValuesDoubleGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return ValuesDoubleGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesFloatAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesFloatAggregatorFunctionSupplier.java index 7802a06a6935..f8c395b01b5c 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesFloatAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesFloatAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class ValuesFloatAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public ValuesFloatAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public ValuesFloatAggregatorFunctionSupplier() { } @Override - public ValuesFloatAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return ValuesFloatAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return ValuesFloatGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public ValuesFloatAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return ValuesFloatAggregatorFunction.create(driverContext, channels); } @Override - public ValuesFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public ValuesFloatGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return ValuesFloatGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesIntAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesIntAggregatorFunctionSupplier.java index a86b3838d7c9..f4aa9722bff7 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesIntAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesIntAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class ValuesIntAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public ValuesIntAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public ValuesIntAggregatorFunctionSupplier() { } @Override - public ValuesIntAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return ValuesIntAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return ValuesIntGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public ValuesIntAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return ValuesIntAggregatorFunction.create(driverContext, channels); } @Override - public ValuesIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public ValuesIntGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return ValuesIntGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesLongAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesLongAggregatorFunctionSupplier.java index dd302cc4eb69..9f3bbf2b3122 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesLongAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesLongAggregatorFunctionSupplier.java @@ -15,19 +15,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class ValuesLongAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public ValuesLongAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public ValuesLongAggregatorFunctionSupplier() { } @Override - public ValuesLongAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return ValuesLongAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return ValuesLongGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public ValuesLongAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return ValuesLongAggregatorFunction.create(driverContext, channels); } @Override - public ValuesLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public ValuesLongGroupingAggregatorFunction groupingAggregator(DriverContext driverContext, + List channels) { return ValuesLongGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointDocValuesAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointDocValuesAggregatorFunctionSupplier.java index 19139c22863d..593e7c9d4291 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointDocValuesAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointDocValuesAggregatorFunctionSupplier.java @@ -9,6 +9,7 @@ import java.lang.Override; import java.lang.String; import java.util.List; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.operator.DriverContext; /** @@ -16,21 +17,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SpatialCentroidCartesianPointDocValuesAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; + public SpatialCentroidCartesianPointDocValuesAggregatorFunctionSupplier() { + } - public SpatialCentroidCartesianPointDocValuesAggregatorFunctionSupplier(List channels) { - this.channels = channels; + @Override + public List nonGroupingIntermediateStateDesc() { + return SpatialCentroidCartesianPointDocValuesAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SpatialCentroidCartesianPointDocValuesGroupingAggregatorFunction.intermediateStateDesc(); } @Override public SpatialCentroidCartesianPointDocValuesAggregatorFunction aggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialCentroidCartesianPointDocValuesAggregatorFunction.create(driverContext, channels); } @Override public SpatialCentroidCartesianPointDocValuesGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialCentroidCartesianPointDocValuesGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointSourceValuesAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointSourceValuesAggregatorFunctionSupplier.java index b43fb64f6730..8ae5fc6180d9 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointSourceValuesAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointSourceValuesAggregatorFunctionSupplier.java @@ -9,6 +9,7 @@ import java.lang.Override; import java.lang.String; import java.util.List; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.operator.DriverContext; /** @@ -16,22 +17,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SpatialCentroidCartesianPointSourceValuesAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; + public SpatialCentroidCartesianPointSourceValuesAggregatorFunctionSupplier() { + } - public SpatialCentroidCartesianPointSourceValuesAggregatorFunctionSupplier( - List channels) { - this.channels = channels; + @Override + public List nonGroupingIntermediateStateDesc() { + return SpatialCentroidCartesianPointSourceValuesAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SpatialCentroidCartesianPointSourceValuesGroupingAggregatorFunction.intermediateStateDesc(); } @Override public SpatialCentroidCartesianPointSourceValuesAggregatorFunction aggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialCentroidCartesianPointSourceValuesAggregatorFunction.create(driverContext, channels); } @Override public SpatialCentroidCartesianPointSourceValuesGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialCentroidCartesianPointSourceValuesGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointDocValuesAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointDocValuesAggregatorFunctionSupplier.java index 34414a9e9c5c..ae38d6d91ab8 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointDocValuesAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointDocValuesAggregatorFunctionSupplier.java @@ -9,6 +9,7 @@ import java.lang.Override; import java.lang.String; import java.util.List; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.operator.DriverContext; /** @@ -16,21 +17,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SpatialCentroidGeoPointDocValuesAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public SpatialCentroidGeoPointDocValuesAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public SpatialCentroidGeoPointDocValuesAggregatorFunctionSupplier() { } @Override - public SpatialCentroidGeoPointDocValuesAggregatorFunction aggregator( - DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return SpatialCentroidGeoPointDocValuesAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SpatialCentroidGeoPointDocValuesGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public SpatialCentroidGeoPointDocValuesAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return SpatialCentroidGeoPointDocValuesAggregatorFunction.create(driverContext, channels); } @Override public SpatialCentroidGeoPointDocValuesGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialCentroidGeoPointDocValuesGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointSourceValuesAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointSourceValuesAggregatorFunctionSupplier.java index 80f608a10a6f..e10e2b50ef61 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointSourceValuesAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointSourceValuesAggregatorFunctionSupplier.java @@ -9,6 +9,7 @@ import java.lang.Override; import java.lang.String; import java.util.List; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.operator.DriverContext; /** @@ -16,21 +17,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SpatialCentroidGeoPointSourceValuesAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; + public SpatialCentroidGeoPointSourceValuesAggregatorFunctionSupplier() { + } - public SpatialCentroidGeoPointSourceValuesAggregatorFunctionSupplier(List channels) { - this.channels = channels; + @Override + public List nonGroupingIntermediateStateDesc() { + return SpatialCentroidGeoPointSourceValuesAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SpatialCentroidGeoPointSourceValuesGroupingAggregatorFunction.intermediateStateDesc(); } @Override public SpatialCentroidGeoPointSourceValuesAggregatorFunction aggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialCentroidGeoPointSourceValuesAggregatorFunction.create(driverContext, channels); } @Override public SpatialCentroidGeoPointSourceValuesGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialCentroidGeoPointSourceValuesGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointDocValuesAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointDocValuesAggregatorFunctionSupplier.java index c9447dfce0f1..0d41ea3bf7e8 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointDocValuesAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointDocValuesAggregatorFunctionSupplier.java @@ -9,6 +9,7 @@ import java.lang.Override; import java.lang.String; import java.util.List; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.operator.DriverContext; /** @@ -16,21 +17,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SpatialExtentCartesianPointDocValuesAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; + public SpatialExtentCartesianPointDocValuesAggregatorFunctionSupplier() { + } - public SpatialExtentCartesianPointDocValuesAggregatorFunctionSupplier(List channels) { - this.channels = channels; + @Override + public List nonGroupingIntermediateStateDesc() { + return SpatialExtentCartesianPointDocValuesAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SpatialExtentCartesianPointDocValuesGroupingAggregatorFunction.intermediateStateDesc(); } @Override public SpatialExtentCartesianPointDocValuesAggregatorFunction aggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialExtentCartesianPointDocValuesAggregatorFunction.create(driverContext, channels); } @Override public SpatialExtentCartesianPointDocValuesGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialExtentCartesianPointDocValuesGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointSourceValuesAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointSourceValuesAggregatorFunctionSupplier.java index d0cd2e33fe0f..1cccb66bfa0e 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointSourceValuesAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointSourceValuesAggregatorFunctionSupplier.java @@ -9,6 +9,7 @@ import java.lang.Override; import java.lang.String; import java.util.List; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.operator.DriverContext; /** @@ -16,21 +17,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SpatialExtentCartesianPointSourceValuesAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; + public SpatialExtentCartesianPointSourceValuesAggregatorFunctionSupplier() { + } - public SpatialExtentCartesianPointSourceValuesAggregatorFunctionSupplier(List channels) { - this.channels = channels; + @Override + public List nonGroupingIntermediateStateDesc() { + return SpatialExtentCartesianPointSourceValuesAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SpatialExtentCartesianPointSourceValuesGroupingAggregatorFunction.intermediateStateDesc(); } @Override public SpatialExtentCartesianPointSourceValuesAggregatorFunction aggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialExtentCartesianPointSourceValuesAggregatorFunction.create(driverContext, channels); } @Override public SpatialExtentCartesianPointSourceValuesGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialExtentCartesianPointSourceValuesGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeDocValuesAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeDocValuesAggregatorFunctionSupplier.java index 2fa68f522648..40432cfb548e 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeDocValuesAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeDocValuesAggregatorFunctionSupplier.java @@ -9,6 +9,7 @@ import java.lang.Override; import java.lang.String; import java.util.List; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.operator.DriverContext; /** @@ -16,21 +17,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SpatialExtentCartesianShapeDocValuesAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; + public SpatialExtentCartesianShapeDocValuesAggregatorFunctionSupplier() { + } - public SpatialExtentCartesianShapeDocValuesAggregatorFunctionSupplier(List channels) { - this.channels = channels; + @Override + public List nonGroupingIntermediateStateDesc() { + return SpatialExtentCartesianShapeDocValuesAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SpatialExtentCartesianShapeDocValuesGroupingAggregatorFunction.intermediateStateDesc(); } @Override public SpatialExtentCartesianShapeDocValuesAggregatorFunction aggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialExtentCartesianShapeDocValuesAggregatorFunction.create(driverContext, channels); } @Override public SpatialExtentCartesianShapeDocValuesGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialExtentCartesianShapeDocValuesGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeSourceValuesAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeSourceValuesAggregatorFunctionSupplier.java index 822a10fbe479..dfb2aaee9aff 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeSourceValuesAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeSourceValuesAggregatorFunctionSupplier.java @@ -9,6 +9,7 @@ import java.lang.Override; import java.lang.String; import java.util.List; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.operator.DriverContext; /** @@ -16,21 +17,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SpatialExtentCartesianShapeSourceValuesAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; + public SpatialExtentCartesianShapeSourceValuesAggregatorFunctionSupplier() { + } - public SpatialExtentCartesianShapeSourceValuesAggregatorFunctionSupplier(List channels) { - this.channels = channels; + @Override + public List nonGroupingIntermediateStateDesc() { + return SpatialExtentCartesianShapeSourceValuesAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SpatialExtentCartesianShapeSourceValuesGroupingAggregatorFunction.intermediateStateDesc(); } @Override public SpatialExtentCartesianShapeSourceValuesAggregatorFunction aggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialExtentCartesianShapeSourceValuesAggregatorFunction.create(driverContext, channels); } @Override public SpatialExtentCartesianShapeSourceValuesGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialExtentCartesianShapeSourceValuesGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointDocValuesAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointDocValuesAggregatorFunctionSupplier.java index 3c5d7c835513..1f2dfb378498 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointDocValuesAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointDocValuesAggregatorFunctionSupplier.java @@ -9,6 +9,7 @@ import java.lang.Override; import java.lang.String; import java.util.List; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.operator.DriverContext; /** @@ -16,20 +17,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SpatialExtentGeoPointDocValuesAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public SpatialExtentGeoPointDocValuesAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public SpatialExtentGeoPointDocValuesAggregatorFunctionSupplier() { } @Override - public SpatialExtentGeoPointDocValuesAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return SpatialExtentGeoPointDocValuesAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SpatialExtentGeoPointDocValuesGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public SpatialExtentGeoPointDocValuesAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return SpatialExtentGeoPointDocValuesAggregatorFunction.create(driverContext, channels); } @Override public SpatialExtentGeoPointDocValuesGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialExtentGeoPointDocValuesGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointSourceValuesAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointSourceValuesAggregatorFunctionSupplier.java index 8018b7d8d829..e97d858511c0 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointSourceValuesAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointSourceValuesAggregatorFunctionSupplier.java @@ -9,6 +9,7 @@ import java.lang.Override; import java.lang.String; import java.util.List; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.operator.DriverContext; /** @@ -16,21 +17,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SpatialExtentGeoPointSourceValuesAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public SpatialExtentGeoPointSourceValuesAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public SpatialExtentGeoPointSourceValuesAggregatorFunctionSupplier() { } @Override - public SpatialExtentGeoPointSourceValuesAggregatorFunction aggregator( - DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return SpatialExtentGeoPointSourceValuesAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SpatialExtentGeoPointSourceValuesGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public SpatialExtentGeoPointSourceValuesAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return SpatialExtentGeoPointSourceValuesAggregatorFunction.create(driverContext, channels); } @Override public SpatialExtentGeoPointSourceValuesGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialExtentGeoPointSourceValuesGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeDocValuesAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeDocValuesAggregatorFunctionSupplier.java index cd36ee8fd14a..958241155157 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeDocValuesAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeDocValuesAggregatorFunctionSupplier.java @@ -9,6 +9,7 @@ import java.lang.Override; import java.lang.String; import java.util.List; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.operator.DriverContext; /** @@ -16,20 +17,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SpatialExtentGeoShapeDocValuesAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public SpatialExtentGeoShapeDocValuesAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public SpatialExtentGeoShapeDocValuesAggregatorFunctionSupplier() { } @Override - public SpatialExtentGeoShapeDocValuesAggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return SpatialExtentGeoShapeDocValuesAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SpatialExtentGeoShapeDocValuesGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public SpatialExtentGeoShapeDocValuesAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return SpatialExtentGeoShapeDocValuesAggregatorFunction.create(driverContext, channels); } @Override public SpatialExtentGeoShapeDocValuesGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialExtentGeoShapeDocValuesGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeSourceValuesAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeSourceValuesAggregatorFunctionSupplier.java index 95aa4f3d3007..be425646e90e 100644 --- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeSourceValuesAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeSourceValuesAggregatorFunctionSupplier.java @@ -9,6 +9,7 @@ import java.lang.Override; import java.lang.String; import java.util.List; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.operator.DriverContext; /** @@ -16,21 +17,28 @@ import org.elasticsearch.compute.operator.DriverContext; * This class is generated. Edit {@code AggregatorFunctionSupplierImplementer} instead. */ public final class SpatialExtentGeoShapeSourceValuesAggregatorFunctionSupplier implements AggregatorFunctionSupplier { - private final List channels; - - public SpatialExtentGeoShapeSourceValuesAggregatorFunctionSupplier(List channels) { - this.channels = channels; + public SpatialExtentGeoShapeSourceValuesAggregatorFunctionSupplier() { } @Override - public SpatialExtentGeoShapeSourceValuesAggregatorFunction aggregator( - DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return SpatialExtentGeoShapeSourceValuesAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return SpatialExtentGeoShapeSourceValuesGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public SpatialExtentGeoShapeSourceValuesAggregatorFunction aggregator(DriverContext driverContext, + List channels) { return SpatialExtentGeoShapeSourceValuesAggregatorFunction.create(driverContext, channels); } @Override public SpatialExtentGeoShapeSourceValuesGroupingAggregatorFunction groupingAggregator( - DriverContext driverContext) { + DriverContext driverContext, List channels) { return SpatialExtentGeoShapeSourceValuesGroupingAggregatorFunction.create(channels, driverContext); } diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/AggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/AggregatorFunctionSupplier.java index 9f2395960477..e192d1b2de7f 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/AggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/AggregatorFunctionSupplier.java @@ -10,19 +10,25 @@ package org.elasticsearch.compute.aggregation; import org.elasticsearch.compute.Describable; import org.elasticsearch.compute.operator.DriverContext; +import java.util.List; + /** * Builds aggregation implementations, closing over any state required to do so. */ public interface AggregatorFunctionSupplier extends Describable { - AggregatorFunction aggregator(DriverContext driverContext); + List nonGroupingIntermediateStateDesc(); - GroupingAggregatorFunction groupingAggregator(DriverContext driverContext); + List groupingIntermediateStateDesc(); - default Aggregator.Factory aggregatorFactory(AggregatorMode mode) { + AggregatorFunction aggregator(DriverContext driverContext, List channels); + + GroupingAggregatorFunction groupingAggregator(DriverContext driverContext, List channels); + + default Aggregator.Factory aggregatorFactory(AggregatorMode mode, List channels) { return new Aggregator.Factory() { @Override public Aggregator apply(DriverContext driverContext) { - return new Aggregator(aggregator(driverContext), mode); + return new Aggregator(aggregator(driverContext, channels), mode); } @Override @@ -32,11 +38,11 @@ public interface AggregatorFunctionSupplier extends Describable { }; } - default GroupingAggregator.Factory groupingAggregatorFactory(AggregatorMode mode) { + default GroupingAggregator.Factory groupingAggregatorFactory(AggregatorMode mode, List channels) { return new GroupingAggregator.Factory() { @Override public GroupingAggregator apply(DriverContext driverContext) { - return new GroupingAggregator(groupingAggregator(driverContext), mode); + return new GroupingAggregator(groupingAggregator(driverContext, channels), mode); } @Override diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/CountAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/CountAggregatorFunction.java index c6416f6d075d..a9d21babfbd9 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/CountAggregatorFunction.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/CountAggregatorFunction.java @@ -19,15 +19,25 @@ import org.elasticsearch.compute.operator.DriverContext; import java.util.List; public class CountAggregatorFunction implements AggregatorFunction { - public static AggregatorFunctionSupplier supplier(List channels) { + public static AggregatorFunctionSupplier supplier() { return new AggregatorFunctionSupplier() { @Override - public AggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return CountAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return CountGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public AggregatorFunction aggregator(DriverContext driverContext, List channels) { return CountAggregatorFunction.create(channels); } @Override - public GroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public GroupingAggregatorFunction groupingAggregator(DriverContext driverContext, List channels) { return CountGroupingAggregatorFunction.create(driverContext, channels); } diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/FilteredAggregatorFunctionSupplier.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/FilteredAggregatorFunctionSupplier.java index ed63a283b356..eab897fe24fc 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/FilteredAggregatorFunctionSupplier.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/FilteredAggregatorFunctionSupplier.java @@ -11,6 +11,8 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import java.util.List; + /** * A {@link AggregatorFunctionSupplier} that wraps another, filtering which positions * are supplied to the aggregator. @@ -20,8 +22,18 @@ public record FilteredAggregatorFunctionSupplier(AggregatorFunctionSupplier next AggregatorFunctionSupplier { @Override - public AggregatorFunction aggregator(DriverContext driverContext) { - AggregatorFunction next = this.next.aggregator(driverContext); + public List nonGroupingIntermediateStateDesc() { + return next.nonGroupingIntermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return next.groupingIntermediateStateDesc(); + } + + @Override + public AggregatorFunction aggregator(DriverContext driverContext, List channels) { + AggregatorFunction next = this.next.aggregator(driverContext, channels); EvalOperator.ExpressionEvaluator filter = null; try { filter = this.filter.get(driverContext); @@ -35,8 +47,8 @@ public record FilteredAggregatorFunctionSupplier(AggregatorFunctionSupplier next } @Override - public GroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { - GroupingAggregatorFunction next = this.next.groupingAggregator(driverContext); + public GroupingAggregatorFunction groupingAggregator(DriverContext driverContext, List channels) { + GroupingAggregatorFunction next = this.next.groupingAggregator(driverContext, channels); EvalOperator.ExpressionEvaluator filter = null; try { filter = this.filter.get(driverContext); diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingOperator.java index 09d04d36f831..d0b4aaad22a3 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingOperator.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingOperator.java @@ -188,7 +188,10 @@ public abstract class AbstractPageMappingOperator implements Operator { if (builder.humanReadable()) { builder.field("process_time", TimeValue.timeValueNanos(processNanos)); } - return builder.field("pages_processed", pagesProcessed).field("rows_received", rowsReceived).field("rows_emitted", rowsEmitted); + builder.field("pages_processed", pagesProcessed); + builder.field("rows_received", rowsReceived); + builder.field("rows_emitted", rowsEmitted); + return builder; } @Override diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AsyncOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AsyncOperator.java index df522e931ca0..112fc44311a5 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AsyncOperator.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AsyncOperator.java @@ -45,7 +45,7 @@ public abstract class AsyncOperator implements Operator { private final DriverContext driverContext; private final int maxOutstandingRequests; - private final LongAdder totalTimeInNanos = new LongAdder(); + private final LongAdder processNanos = new LongAdder(); private boolean finished = false; private volatile boolean closed = false; @@ -98,7 +98,7 @@ public abstract class AsyncOperator implements Operator { final long startNanos = System.nanoTime(); performAsync(input, ActionListener.runAfter(listener, () -> { driverContext.removeAsyncAction(); - totalTimeInNanos.add(System.nanoTime() - startNanos); + processNanos.add(System.nanoTime() - startNanos); })); success = true; } finally { @@ -231,15 +231,11 @@ public abstract class AsyncOperator implements Operator { @Override public final Operator.Status status() { - return status( - Math.max(0L, checkpoint.getMaxSeqNo()), - Math.max(0L, checkpoint.getProcessedCheckpoint()), - TimeValue.timeValueNanos(totalTimeInNanos.sum()).millis() - ); + return status(Math.max(0L, checkpoint.getMaxSeqNo()), Math.max(0L, checkpoint.getProcessedCheckpoint()), processNanos.sum()); } - protected Operator.Status status(long receivedPages, long completedPages, long totalTimeInMillis) { - return new Status(receivedPages, completedPages, totalTimeInMillis); + protected Operator.Status status(long receivedPages, long completedPages, long processNanos) { + return new Status(receivedPages, completedPages, processNanos); } public static class Status implements Operator.Status { @@ -251,25 +247,31 @@ public abstract class AsyncOperator implements Operator { final long receivedPages; final long completedPages; - final long totalTimeInMillis; + final long processNanos; - protected Status(long receivedPages, long completedPages, long totalTimeInMillis) { + protected Status(long receivedPages, long completedPages, long processNanos) { this.receivedPages = receivedPages; this.completedPages = completedPages; - this.totalTimeInMillis = totalTimeInMillis; + this.processNanos = processNanos; } protected Status(StreamInput in) throws IOException { this.receivedPages = in.readVLong(); this.completedPages = in.readVLong(); - this.totalTimeInMillis = in.readVLong(); + this.processNanos = in.getTransportVersion().onOrAfter(TransportVersions.ESQL_PROFILE_ASYNC_NANOS) + ? in.readVLong() + : TimeValue.timeValueMillis(in.readVLong()).nanos(); } @Override public void writeTo(StreamOutput out) throws IOException { out.writeVLong(receivedPages); out.writeVLong(completedPages); - out.writeVLong(totalTimeInMillis); + out.writeVLong( + out.getTransportVersion().onOrAfter(TransportVersions.ESQL_PROFILE_ASYNC_NANOS) + ? processNanos + : TimeValue.timeValueNanos(processNanos).millis() + ); } public long receivedPages() { @@ -280,8 +282,8 @@ public abstract class AsyncOperator implements Operator { return completedPages; } - public long totalTimeInMillis() { - return totalTimeInMillis; + public long procesNanos() { + return processNanos; } @Override @@ -297,12 +299,12 @@ public abstract class AsyncOperator implements Operator { } protected final XContentBuilder innerToXContent(XContentBuilder builder) throws IOException { + builder.field("process_nanos", processNanos); + if (builder.humanReadable()) { + builder.field("process_time", TimeValue.timeValueNanos(processNanos)); + } builder.field("received_pages", receivedPages); builder.field("completed_pages", completedPages); - builder.field("total_time_in_millis", totalTimeInMillis); - if (totalTimeInMillis >= 0) { - builder.field("total_time", TimeValue.timeValueMillis(totalTimeInMillis)); - } return builder; } @@ -311,14 +313,12 @@ public abstract class AsyncOperator implements Operator { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Status status = (Status) o; - return receivedPages == status.receivedPages - && completedPages == status.completedPages - && totalTimeInMillis == status.totalTimeInMillis; + return receivedPages == status.receivedPages && completedPages == status.completedPages && processNanos == status.processNanos; } @Override public int hashCode() { - return Objects.hash(receivedPages, completedPages, totalTimeInMillis); + return Objects.hash(receivedPages, completedPages, processNanos); } @Override diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/ChangePointOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/ChangePointOperator.java new file mode 100644 index 000000000000..2693c13a5383 --- /dev/null +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/ChangePointOperator.java @@ -0,0 +1,236 @@ +/* + * 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.compute.operator; + +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.compute.data.Block; +import org.elasticsearch.compute.data.BlockFactory; +import org.elasticsearch.compute.data.BlockUtils; +import org.elasticsearch.compute.data.BytesRefBlock; +import org.elasticsearch.compute.data.DoubleBlock; +import org.elasticsearch.compute.data.Page; +import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.ml.aggs.MlAggsHelper; +import org.elasticsearch.xpack.ml.aggs.changepoint.ChangePointDetector; +import org.elasticsearch.xpack.ml.aggs.changepoint.ChangeType; + +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; + +/** + * Find spikes, dips and change point in a list of values. + *

+ * Warning: this operator cannot handle large amounts of data! It buffers all + * data that is passed to it, runs the change point detector on the data (which + * is a compute-heavy process), and then outputs all data with the change points. + */ +public class ChangePointOperator implements Operator { + + public static final int INPUT_VALUE_COUNT_LIMIT = 1000; + + public record Factory(int channel, String sourceText, int sourceLine, int sourceColumn) implements OperatorFactory { + @Override + public Operator get(DriverContext driverContext) { + return new ChangePointOperator(driverContext, channel, sourceText, sourceLine, sourceColumn); + } + + @Override + public String describe() { + return "ChangePointOperator[channel=" + channel + "]"; + } + } + + private final DriverContext driverContext; + private final int channel; + private final String sourceText; + private final int sourceLine; + private final int sourceColumn; + + private final Deque inputPages; + private final Deque outputPages; + private boolean finished; + private Warnings warnings; + + // TODO: make org.elasticsearch.xpack.esql.core.tree.Source available here + // (by modularizing esql-core) and use that instead of the individual fields. + public ChangePointOperator(DriverContext driverContext, int channel, String sourceText, int sourceLine, int sourceColumn) { + this.driverContext = driverContext; + this.channel = channel; + this.sourceText = sourceText; + this.sourceLine = sourceLine; + this.sourceColumn = sourceColumn; + + finished = false; + inputPages = new LinkedList<>(); + outputPages = new LinkedList<>(); + warnings = null; + } + + @Override + public boolean needsInput() { + return finished == false; + } + + @Override + public void addInput(Page page) { + inputPages.add(page); + } + + @Override + public void finish() { + if (finished == false) { + finished = true; + createOutputPages(); + } + } + + @Override + public boolean isFinished() { + return finished && outputPages.isEmpty(); + } + + @Override + public Page getOutput() { + if (finished == false || outputPages.isEmpty()) { + return null; + } + return outputPages.removeFirst(); + } + + private void createOutputPages() { + int valuesCount = 0; + for (Page page : inputPages) { + valuesCount += page.getPositionCount(); + } + boolean tooManyValues = valuesCount > INPUT_VALUE_COUNT_LIMIT; + if (tooManyValues) { + valuesCount = INPUT_VALUE_COUNT_LIMIT; + } + + List values = new ArrayList<>(valuesCount); + List bucketIndexes = new ArrayList<>(valuesCount); + int valuesIndex = 0; + boolean hasNulls = false; + boolean hasMultivalued = false; + for (Page inputPage : inputPages) { + Block inputBlock = inputPage.getBlock(channel); + for (int i = 0; i < inputBlock.getPositionCount() && valuesIndex < valuesCount; i++) { + Object value = BlockUtils.toJavaObject(inputBlock, i); + if (value == null) { + hasNulls = true; + valuesIndex++; + } else if (value instanceof List) { + hasMultivalued = true; + valuesIndex++; + } else { + values.add(((Number) value).doubleValue()); + bucketIndexes.add(valuesIndex++); + } + } + } + + MlAggsHelper.DoubleBucketValues bucketValues = new MlAggsHelper.DoubleBucketValues( + null, + values.stream().mapToDouble(Double::doubleValue).toArray(), + bucketIndexes.stream().mapToInt(Integer::intValue).toArray() + ); + ChangeType changeType = ChangePointDetector.getChangeType(bucketValues); + int changePointIndex = changeType.changePoint(); + + BlockFactory blockFactory = driverContext.blockFactory(); + int pageStartIndex = 0; + while (inputPages.isEmpty() == false) { + Page inputPage = inputPages.peek(); + Page outputPage; + Block changeTypeBlock = null; + Block changePvalueBlock = null; + boolean success = false; + try { + if (pageStartIndex <= changePointIndex && changePointIndex < pageStartIndex + inputPage.getPositionCount()) { + try ( + BytesRefBlock.Builder changeTypeBlockBuilder = blockFactory.newBytesRefBlockBuilder(inputPage.getPositionCount()); + DoubleBlock.Builder pvalueBlockBuilder = blockFactory.newDoubleBlockBuilder(inputPage.getPositionCount()) + ) { + for (int i = 0; i < inputPage.getPositionCount(); i++) { + if (pageStartIndex + i == changePointIndex) { + changeTypeBlockBuilder.appendBytesRef(new BytesRef(changeType.getWriteableName())); + pvalueBlockBuilder.appendDouble(changeType.pValue()); + } else { + changeTypeBlockBuilder.appendNull(); + pvalueBlockBuilder.appendNull(); + } + } + changeTypeBlock = changeTypeBlockBuilder.build(); + changePvalueBlock = pvalueBlockBuilder.build(); + } + } else { + changeTypeBlock = blockFactory.newConstantNullBlock(inputPage.getPositionCount()); + changePvalueBlock = blockFactory.newConstantNullBlock(inputPage.getPositionCount()); + } + + outputPage = inputPage.appendBlocks(new Block[] { changeTypeBlock, changePvalueBlock }); + success = true; + } finally { + if (success == false) { + Releasables.closeExpectNoException(changeTypeBlock, changePvalueBlock); + } + } + + inputPages.removeFirst(); + outputPages.add(outputPage); + pageStartIndex += inputPage.getPositionCount(); + } + + if (changeType instanceof ChangeType.Indeterminable indeterminable) { + warnings(false).registerException(new IllegalArgumentException(indeterminable.getReason())); + } + if (tooManyValues) { + warnings(true).registerException( + new IllegalArgumentException("too many values; keeping only first " + INPUT_VALUE_COUNT_LIMIT + " values") + ); + } + if (hasNulls) { + warnings(true).registerException(new IllegalArgumentException("values contain nulls; skipping them")); + } + if (hasMultivalued) { + warnings(true).registerException( + new IllegalArgumentException( + "values contains multivalued entries; skipping them (please consider reducing them with e.g. MV_AVG or MV_SUM)" + ) + ); + } + } + + @Override + public void close() { + for (Page page : inputPages) { + page.releaseBlocks(); + } + for (Page page : outputPages) { + page.releaseBlocks(); + } + } + + @Override + public String toString() { + return "ChangePointOperator[channel=" + channel + "]"; + } + + private Warnings warnings(boolean onlyWarnings) { + if (warnings == null) { + if (onlyWarnings) { + this.warnings = Warnings.createOnlyWarnings(driverContext.warningsMode(), sourceLine, sourceColumn, sourceText); + } else { + this.warnings = Warnings.createWarnings(driverContext.warningsMode(), sourceLine, sourceColumn, sourceText); + } + } + return warnings; + } +} diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverProfile.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverProfile.java index 38fb298a7cff..9cc9f2335ffd 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverProfile.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverProfile.java @@ -89,7 +89,12 @@ public class DriverProfile implements Writeable, ChunkedToXContentObject { } public DriverProfile(StreamInput in) throws IOException { - this.taskDescription = in.getTransportVersion().onOrAfter(TransportVersions.ESQL_DRIVER_TASK_DESCRIPTION) ? in.readString() : ""; + if (in.getTransportVersion().onOrAfter(TransportVersions.ESQL_DRIVER_TASK_DESCRIPTION) + || in.getTransportVersion().isPatchFrom(TransportVersions.ESQL_DRIVER_TASK_DESCRIPTION_90)) { + this.taskDescription = in.readString(); + } else { + this.taskDescription = ""; + } if (in.getTransportVersion().onOrAfter(TransportVersions.V_8_16_0)) { this.startMillis = in.readVLong(); this.stopMillis = in.readVLong(); @@ -112,7 +117,8 @@ public class DriverProfile implements Writeable, ChunkedToXContentObject { @Override public void writeTo(StreamOutput out) throws IOException { - if (out.getTransportVersion().onOrAfter(TransportVersions.ESQL_DRIVER_TASK_DESCRIPTION)) { + if (out.getTransportVersion().onOrAfter(TransportVersions.ESQL_DRIVER_TASK_DESCRIPTION) + || out.getTransportVersion().isPatchFrom(TransportVersions.ESQL_DRIVER_TASK_DESCRIPTION_90)) { out.writeString(taskDescription); } if (out.getTransportVersion().onOrAfter(TransportVersions.V_8_16_0)) { diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverScheduler.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverScheduler.java index 05fe38007a92..9d82f73f3105 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverScheduler.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverScheduler.java @@ -7,7 +7,9 @@ package org.elasticsearch.compute.operator; +import org.elasticsearch.common.util.concurrent.AbstractRunnable; import org.elasticsearch.common.util.concurrent.EsExecutors; +import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException; import java.util.List; import java.util.concurrent.Executor; @@ -21,7 +23,7 @@ import java.util.concurrent.atomic.AtomicReference; */ final class DriverScheduler { private final AtomicReference delayedTask = new AtomicReference<>(); - private final AtomicReference scheduledTask = new AtomicReference<>(); + private final AtomicReference scheduledTask = new AtomicReference<>(); private final AtomicBoolean completing = new AtomicBoolean(); void addOrRunDelayedTask(Runnable task) { @@ -35,22 +37,32 @@ final class DriverScheduler { } } - void scheduleOrRunTask(Executor executor, Runnable task) { - final Runnable existing = scheduledTask.getAndSet(task); + void scheduleOrRunTask(Executor executor, AbstractRunnable task) { + final AbstractRunnable existing = scheduledTask.getAndSet(task); assert existing == null : existing; final Executor executorToUse = completing.get() ? EsExecutors.DIRECT_EXECUTOR_SERVICE : executor; - executorToUse.execute(() -> { - final Runnable next = scheduledTask.getAndSet(null); - if (next != null) { - assert next == task; - next.run(); + executorToUse.execute(new AbstractRunnable() { + @Override + public void onFailure(Exception e) { + assert e instanceof EsRejectedExecutionException : new AssertionError(e); + if (scheduledTask.getAndUpdate(t -> t == task ? null : t) == task) { + task.onFailure(e); + } + } + + @Override + protected void doRun() { + AbstractRunnable toRun = scheduledTask.getAndSet(null); + if (toRun == task) { + task.run(); + } } }); } void runPendingTasks() { completing.set(true); - for (var taskHolder : List.of(delayedTask, scheduledTask)) { + for (var taskHolder : List.of(scheduledTask, delayedTask)) { final Runnable task = taskHolder.getAndSet(null); if (task != null) { task.run(); diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverStatus.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverStatus.java index 87537755bba3..41d0aee14fe6 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverStatus.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverStatus.java @@ -112,7 +112,12 @@ public class DriverStatus implements Task.Status { public DriverStatus(StreamInput in) throws IOException { this.sessionId = in.readString(); - this.taskDescription = in.getTransportVersion().onOrAfter(TransportVersions.ESQL_DRIVER_TASK_DESCRIPTION) ? in.readString() : ""; + if (in.getTransportVersion().onOrAfter(TransportVersions.ESQL_DRIVER_TASK_DESCRIPTION) + || in.getTransportVersion().isPatchFrom(TransportVersions.ESQL_DRIVER_TASK_DESCRIPTION_90)) { + this.taskDescription = in.readString(); + } else { + this.taskDescription = ""; + } this.started = in.getTransportVersion().onOrAfter(TransportVersions.V_8_14_0) ? in.readLong() : 0; this.lastUpdated = in.readLong(); this.cpuNanos = in.getTransportVersion().onOrAfter(TransportVersions.V_8_14_0) ? in.readVLong() : 0; @@ -130,7 +135,8 @@ public class DriverStatus implements Task.Status { @Override public void writeTo(StreamOutput out) throws IOException { out.writeString(sessionId); - if (out.getTransportVersion().onOrAfter(TransportVersions.ESQL_DRIVER_TASK_DESCRIPTION)) { + if (out.getTransportVersion().onOrAfter(TransportVersions.ESQL_DRIVER_TASK_DESCRIPTION) + || out.getTransportVersion().isPatchFrom(TransportVersions.ESQL_DRIVER_TASK_DESCRIPTION_90)) { out.writeString(taskDescription); } if (out.getTransportVersion().onOrAfter(TransportVersions.V_8_14_0)) { diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/TimeSeriesAggregationOperatorFactories.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/TimeSeriesAggregationOperatorFactories.java index 1e9ea88b2f1d..3b011d4a682f 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/TimeSeriesAggregationOperatorFactories.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/TimeSeriesAggregationOperatorFactories.java @@ -41,22 +41,24 @@ import java.util.List; */ public final class TimeSeriesAggregationOperatorFactories { + public record SupplierWithChannels(AggregatorFunctionSupplier supplier, List channels) {} + public record Initial( int tsHashChannel, int timeBucketChannel, List groupings, - List rates, - List nonRates, + List rates, + List nonRates, int maxPageSize ) implements Operator.OperatorFactory { @Override public Operator get(DriverContext driverContext) { List aggregators = new ArrayList<>(groupings.size() + rates.size() + nonRates.size()); - for (AggregatorFunctionSupplier f : rates) { - aggregators.add(f.groupingAggregatorFactory(AggregatorMode.INITIAL)); + for (SupplierWithChannels f : rates) { + aggregators.add(f.supplier.groupingAggregatorFactory(AggregatorMode.INITIAL, f.channels)); } - for (AggregatorFunctionSupplier f : nonRates) { - aggregators.add(f.groupingAggregatorFactory(AggregatorMode.INITIAL)); + for (SupplierWithChannels f : nonRates) { + aggregators.add(f.supplier.groupingAggregatorFactory(AggregatorMode.INITIAL, f.channels)); } aggregators.addAll(valuesAggregatorForGroupings(groupings, timeBucketChannel)); return new HashAggregationOperator( @@ -76,18 +78,18 @@ public final class TimeSeriesAggregationOperatorFactories { int tsHashChannel, int timeBucketChannel, List groupings, - List rates, - List nonRates, + List rates, + List nonRates, int maxPageSize ) implements Operator.OperatorFactory { @Override public Operator get(DriverContext driverContext) { List aggregators = new ArrayList<>(groupings.size() + rates.size() + nonRates.size()); - for (AggregatorFunctionSupplier f : rates) { - aggregators.add(f.groupingAggregatorFactory(AggregatorMode.FINAL)); + for (SupplierWithChannels f : rates) { + aggregators.add(f.supplier.groupingAggregatorFactory(AggregatorMode.FINAL, f.channels)); } - for (AggregatorFunctionSupplier f : nonRates) { - aggregators.add(f.groupingAggregatorFactory(AggregatorMode.INTERMEDIATE)); + for (SupplierWithChannels f : nonRates) { + aggregators.add(f.supplier.groupingAggregatorFactory(AggregatorMode.INTERMEDIATE, f.channels)); } aggregators.addAll(valuesAggregatorForGroupings(groupings, timeBucketChannel)); List hashGroups = List.of( @@ -109,18 +111,18 @@ public final class TimeSeriesAggregationOperatorFactories { public record Final( List groupings, - List outerRates, - List nonRates, + List outerRates, + List nonRates, int maxPageSize ) implements Operator.OperatorFactory { @Override public Operator get(DriverContext driverContext) { List aggregators = new ArrayList<>(outerRates.size() + nonRates.size()); - for (AggregatorFunctionSupplier f : outerRates) { - aggregators.add(f.groupingAggregatorFactory(AggregatorMode.SINGLE)); + for (SupplierWithChannels f : outerRates) { + aggregators.add(f.supplier.groupingAggregatorFactory(AggregatorMode.SINGLE, f.channels)); } - for (AggregatorFunctionSupplier f : nonRates) { - aggregators.add(f.groupingAggregatorFactory(AggregatorMode.FINAL)); + for (SupplierWithChannels f : nonRates) { + aggregators.add(f.supplier.groupingAggregatorFactory(AggregatorMode.FINAL, f.channels)); } return new HashAggregationOperator( aggregators, @@ -139,17 +141,17 @@ public final class TimeSeriesAggregationOperatorFactories { List aggregators = new ArrayList<>(); for (BlockHash.GroupSpec g : groupings) { if (g.channel() != timeBucketChannel) { - final List channels = List.of(g.channel()); // TODO: perhaps introduce a specialized aggregator for this? var aggregatorSupplier = (switch (g.elementType()) { - case BYTES_REF -> new org.elasticsearch.compute.aggregation.ValuesBytesRefAggregatorFunctionSupplier(channels); - case DOUBLE -> new org.elasticsearch.compute.aggregation.ValuesDoubleAggregatorFunctionSupplier(channels); - case INT -> new org.elasticsearch.compute.aggregation.ValuesIntAggregatorFunctionSupplier(channels); - case LONG -> new org.elasticsearch.compute.aggregation.ValuesLongAggregatorFunctionSupplier(channels); - case BOOLEAN -> new org.elasticsearch.compute.aggregation.ValuesBooleanAggregatorFunctionSupplier(channels); + case BYTES_REF -> new org.elasticsearch.compute.aggregation.ValuesBytesRefAggregatorFunctionSupplier(); + case DOUBLE -> new org.elasticsearch.compute.aggregation.ValuesDoubleAggregatorFunctionSupplier(); + case INT -> new org.elasticsearch.compute.aggregation.ValuesIntAggregatorFunctionSupplier(); + case LONG -> new org.elasticsearch.compute.aggregation.ValuesLongAggregatorFunctionSupplier(); + case BOOLEAN -> new org.elasticsearch.compute.aggregation.ValuesBooleanAggregatorFunctionSupplier(); case FLOAT, NULL, DOC, COMPOSITE, UNKNOWN -> throw new IllegalArgumentException("unsupported grouping type"); }); - aggregators.add(aggregatorSupplier.groupingAggregatorFactory(AggregatorMode.SINGLE)); + final List channels = List.of(g.channel()); + aggregators.add(aggregatorSupplier.groupingAggregatorFactory(AggregatorMode.SINGLE, channels)); } } return aggregators; diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/Warnings.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/Warnings.java index ec697219563a..999ecca91619 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/Warnings.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/Warnings.java @@ -31,8 +31,9 @@ public class Warnings { * @param sourceText The source text that caused the warning. Same as `source.text()` * @return A warnings collector object */ + // TODO: rename to createWarningsTreatedAsNull public static Warnings createWarnings(DriverContext.WarningsMode warningsMode, int lineNumber, int columnNumber, String sourceText) { - return createWarnings(warningsMode, lineNumber, columnNumber, sourceText, "treating result as null"); + return createWarnings(warningsMode, lineNumber, columnNumber, sourceText, "evaluation of [{}] failed, treating result as null"); } /** @@ -50,7 +51,26 @@ public class Warnings { int columnNumber, String sourceText ) { - return createWarnings(warningsMode, lineNumber, columnNumber, sourceText, "treating result as false"); + return createWarnings(warningsMode, lineNumber, columnNumber, sourceText, "evaluation of [{}] failed, treating result as false"); + } + + /** + * Create a new warnings object based on the given mode which warns that + * evaluation resulted in warnings. + * @param warningsMode The warnings collection strategy to use + * @param lineNumber The line number of the source text. Same as `source.getLineNumber()` + * @param columnNumber The column number of the source text. Same as `source.getColumnNumber()` + * @param sourceText The source text that caused the warning. Same as `source.text()` + * @return A warnings collector object + */ + // TODO: rename to createWarnings + public static Warnings createOnlyWarnings( + DriverContext.WarningsMode warningsMode, + int lineNumber, + int columnNumber, + String sourceText + ) { + return createWarnings(warningsMode, lineNumber, columnNumber, sourceText, "warnings during evaluation of [{}]"); } private static Warnings createWarnings( @@ -78,14 +98,7 @@ public class Warnings { private Warnings(int lineNumber, int columnNumber, String sourceText, String first) { this.location = format("Line {}:{}: ", lineNumber, columnNumber); - this.first = format( - null, - "{}evaluation of [{}] failed, {}. Only first {} failures recorded.", - location, - sourceText, - first, - MAX_ADDED_WARNINGS - ); + this.first = format(null, "{}" + first + ". Only first {} failures recorded.", location, sourceText, MAX_ADDED_WARNINGS); } public void registerException(Exception exception) { diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/exchange/ExchangeBuffer.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/exchange/ExchangeBuffer.java index ce400ddbdd6f..23c98a1df193 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/exchange/ExchangeBuffer.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/exchange/ExchangeBuffer.java @@ -47,7 +47,17 @@ final class ExchangeBuffer { notifyNotEmpty(); } if (noMoreInputs) { - discardPages(); + // O(N) but acceptable because it only occurs with the stop API, and the queue size should be very small. + if (queue.removeIf(p -> p == page)) { + page.releaseBlocks(); + final int size = queueSize.decrementAndGet(); + if (size == maxSize - 1) { + notifyNotFull(); + } + if (size == 0) { + completionFuture.onResponse(null); + } + } } } diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/exchange/ExchangeSourceHandler.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/exchange/ExchangeSourceHandler.java index db9a62da5d9e..ebbddaeeb0d2 100644 --- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/exchange/ExchangeSourceHandler.java +++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/exchange/ExchangeSourceHandler.java @@ -7,17 +7,17 @@ package org.elasticsearch.compute.operator.exchange; -import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRunnable; import org.elasticsearch.action.support.RefCountingRunnable; import org.elasticsearch.action.support.SubscribableListener; import org.elasticsearch.common.util.concurrent.AbstractRunnable; import org.elasticsearch.common.util.concurrent.ConcurrentCollections; import org.elasticsearch.compute.EsqlRefCountingListener; import org.elasticsearch.compute.data.Page; -import org.elasticsearch.compute.operator.FailureCollector; import org.elasticsearch.compute.operator.IsBlockedResult; import org.elasticsearch.core.Releasable; +import org.elasticsearch.tasks.TaskCancelledException; import java.util.List; import java.util.Map; @@ -38,10 +38,9 @@ public final class ExchangeSourceHandler { private final PendingInstances outstandingSinks; private final PendingInstances outstandingSources; - // Collect failures that occur while fetching pages from the remote sink with `failFast=true`. - // The exchange source will stop fetching and abort as soon as any failure is added to this failure collector. - // The final failure collected will be notified to callers via the {@code completionListener}. - private final FailureCollector failure = new FailureCollector(); + // Track if this exchange source should abort. There is no need to track the actual failure since the actual failure + // should be notified via #addRemoteSink(RemoteSink, boolean, Runnable, int, ActionListener). + private volatile boolean aborted = false; private final AtomicInteger nextSinkId = new AtomicInteger(); private final Map remoteSinks = ConcurrentCollections.newConcurrentMap(); @@ -52,7 +51,7 @@ public final class ExchangeSourceHandler { * @param maxBufferSize the maximum size of the exchange buffer. A larger buffer reduces ``pauses`` but uses more memory, * which could otherwise be allocated for other purposes. * @param fetchExecutor the executor used to fetch pages. - * @param completionListener a listener that will be notified when the exchange source handler fails or completes + * @param completionListener a listener that will be notified when the exchange source handler completes */ public ExchangeSourceHandler(int maxBufferSize, Executor fetchExecutor, ActionListener completionListener) { this.buffer = new ExchangeBuffer(maxBufferSize); @@ -63,14 +62,7 @@ public final class ExchangeSourceHandler { this.outstandingSources = new PendingInstances(() -> finishEarly(true, ActionListener.running(closingSinks::finishInstance))); buffer.addCompletionListener(ActionListener.running(() -> { final ActionListener listener = ActionListener.assertAtLeastOnce(completionListener); - try (RefCountingRunnable refs = new RefCountingRunnable(() -> { - final Exception e = failure.getFailure(); - if (e != null) { - listener.onFailure(e); - } else { - listener.onResponse(null); - } - })) { + try (RefCountingRunnable refs = new RefCountingRunnable(ActionRunnable.run(listener, this::checkFailure))) { closingSinks.completion.addListener(refs.acquireListener()); for (PendingInstances pending : List.of(outstandingSinks, outstandingSources)) { // Create an outstanding instance and then finish to complete the completionListener @@ -83,6 +75,12 @@ public final class ExchangeSourceHandler { })); } + private void checkFailure() { + if (aborted) { + throw new TaskCancelledException("remote sinks failed"); + } + } + private class ExchangeSourceImpl implements ExchangeSource { private boolean finished; @@ -90,13 +88,6 @@ public final class ExchangeSourceHandler { outstandingSources.trackNewInstance(); } - private void checkFailure() { - Exception e = failure.getFailure(); - if (e != null) { - throw ExceptionsHelper.convertToRuntime(e); - } - } - @Override public Page pollPage() { checkFailure(); @@ -201,7 +192,7 @@ public final class ExchangeSourceHandler { while (loopControl.isRunning()) { loopControl.exiting(); // finish other sinks if one of them failed or source no longer need pages. - boolean toFinishSinks = buffer.noMoreInputs() || failure.hasFailure(); + boolean toFinishSinks = buffer.noMoreInputs() || aborted; remoteSink.fetchPageAsync(toFinishSinks, ActionListener.wrap(resp -> { Page page = resp.takePage(); if (page != null) { @@ -231,7 +222,7 @@ public final class ExchangeSourceHandler { void onSinkFailed(Exception e) { if (failFast) { - failure.unwrapAndCollect(e); + aborted = true; } buffer.waitForReading().listener().onResponse(null); // resume the Driver if it is being blocked on reading if (finished == false) { @@ -260,12 +251,12 @@ public final class ExchangeSourceHandler { * - If {@code false}, failures from this remote sink will not cause the exchange source to abort. * Callers must handle these failures notified via {@code listener}. * - If {@code true}, failures from this remote sink will cause the exchange source to abort. - * Callers can safely ignore failures notified via this listener, as they are collected and - * reported by the exchange source. + * * @param onPageFetched a callback that will be called when a page is fetched from the remote sink * @param instances the number of concurrent ``clients`` that this handler should use to fetch pages. * More clients reduce latency, but add overhead. - * @param listener a listener that will be notified when the sink fails or completes + * @param listener a listener that will be notified when the sink fails or completes. Callers must handle failures notified via + * this listener. * @see ExchangeSinkHandler#fetchPageAsync(boolean, ActionListener) */ public void addRemoteSink( @@ -284,7 +275,7 @@ public final class ExchangeSourceHandler { @Override public void onFailure(Exception e) { if (failFast) { - failure.unwrapAndCollect(e); + aborted = true; } buffer.waitForReading().listener().onResponse(null); // resume the Driver if it is being blocked on reading remoteSink.close(ActionListener.running(() -> sinkListener.onFailure(e))); diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java index 41b319be6c5f..401fa0d14cd9 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java @@ -197,14 +197,14 @@ public class OperatorTests extends MapperServiceTestCase { ElementType.BYTES_REF, 0, gField, - List.of(CountAggregatorFunction.supplier(List.of(1)).groupingAggregatorFactory(INITIAL)), + List.of(CountAggregatorFunction.supplier().groupingAggregatorFactory(INITIAL, List.of(1))), randomPageSize(), driverContext ) ); operators.add( new HashAggregationOperator( - List.of(CountAggregatorFunction.supplier(List.of(1, 2)).groupingAggregatorFactory(FINAL)), + List.of(CountAggregatorFunction.supplier().groupingAggregatorFactory(FINAL, List.of(1, 2))), () -> BlockHash.build( List.of(new BlockHash.GroupSpec(0, ElementType.BYTES_REF)), driverContext.blockFactory(), diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/AggregatorFunctionTestCase.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/AggregatorFunctionTestCase.java index cea6b6a2a85a..abac7a4cd47e 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/AggregatorFunctionTestCase.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/AggregatorFunctionTestCase.java @@ -47,10 +47,10 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; public abstract class AggregatorFunctionTestCase extends ForkingOperatorTestCase { - protected abstract AggregatorFunctionSupplier aggregatorFunction(List inputChannels); + protected abstract AggregatorFunctionSupplier aggregatorFunction(); protected final int aggregatorIntermediateBlockCount() { - try (var agg = aggregatorFunction(List.of()).aggregator(driverContext())) { + try (var agg = aggregatorFunction().aggregator(driverContext(), List.of())) { return agg.intermediateBlockCount(); } } @@ -69,8 +69,8 @@ public abstract class AggregatorFunctionTestCase extends ForkingOperatorTestCase Function wrap ) { List channels = mode.isInputPartial() ? range(0, aggregatorIntermediateBlockCount()).boxed().toList() : List.of(0); - AggregatorFunctionSupplier supplier = aggregatorFunction(channels); - Aggregator.Factory factory = wrap.apply(supplier).aggregatorFactory(mode); + AggregatorFunctionSupplier supplier = aggregatorFunction(); + Aggregator.Factory factory = wrap.apply(supplier).aggregatorFactory(mode, channels); return new AggregationOperator.AggregationOperatorFactory(List.of(factory), mode); } @@ -224,7 +224,7 @@ public abstract class AggregatorFunctionTestCase extends ForkingOperatorTestCase // Returns an intermediate state that is equivalent to what the local execution planner will emit // if it determines that certain shards have no relevant data. List nullIntermediateState(BlockFactory blockFactory) { - try (var agg = aggregatorFunction(List.of()).aggregator(driverContext())) { + try (var agg = aggregatorFunction().aggregator(driverContext(), List.of())) { var method = agg.getClass().getMethod("intermediateStateDesc"); @SuppressWarnings("unchecked") List intermediateStateDescs = (List) method.invoke(null); diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountAggregatorFunctionTests.java index 452fa206a559..e30082c843b1 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountAggregatorFunctionTests.java @@ -26,8 +26,8 @@ public class CountAggregatorFunctionTests extends AggregatorFunctionTestCase { } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return CountAggregatorFunction.supplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return CountAggregatorFunction.supplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBooleanAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBooleanAggregatorFunctionTests.java index 1c0f3c4f64cb..d91fdce40983 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBooleanAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBooleanAggregatorFunctionTests.java @@ -26,8 +26,8 @@ public class CountDistinctBooleanAggregatorFunctionTests extends AggregatorFunct } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new CountDistinctBooleanAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new CountDistinctBooleanAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBooleanGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBooleanGroupingAggregatorFunctionTests.java index c39fe32620ff..f86c29687877 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBooleanGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBooleanGroupingAggregatorFunctionTests.java @@ -25,8 +25,8 @@ import static org.hamcrest.Matchers.equalTo; public class CountDistinctBooleanGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new CountDistinctBooleanAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new CountDistinctBooleanAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBytesRefAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBytesRefAggregatorFunctionTests.java index e8e51c2adf29..d01cbb39bf47 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBytesRefAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBytesRefAggregatorFunctionTests.java @@ -32,8 +32,8 @@ public class CountDistinctBytesRefAggregatorFunctionTests extends AggregatorFunc } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new CountDistinctBytesRefAggregatorFunctionSupplier(inputChannels, 40000); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new CountDistinctBytesRefAggregatorFunctionSupplier(40000); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBytesRefGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBytesRefGroupingAggregatorFunctionTests.java index dd739d2189ba..c430249ffceb 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBytesRefGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctBytesRefGroupingAggregatorFunctionTests.java @@ -27,8 +27,8 @@ import static org.hamcrest.Matchers.equalTo; public class CountDistinctBytesRefGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new CountDistinctBytesRefAggregatorFunctionSupplier(inputChannels, 40000); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new CountDistinctBytesRefAggregatorFunctionSupplier(40000); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctDoubleAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctDoubleAggregatorFunctionTests.java index a3e7a6a6d70f..d1e845fba40c 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctDoubleAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctDoubleAggregatorFunctionTests.java @@ -28,8 +28,8 @@ public class CountDistinctDoubleAggregatorFunctionTests extends AggregatorFuncti } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new CountDistinctDoubleAggregatorFunctionSupplier(inputChannels, 40000); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new CountDistinctDoubleAggregatorFunctionSupplier(40000); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctDoubleGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctDoubleGroupingAggregatorFunctionTests.java index 7b6f928d57dd..9b45c8dd6e50 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctDoubleGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctDoubleGroupingAggregatorFunctionTests.java @@ -26,8 +26,8 @@ import static org.hamcrest.Matchers.equalTo; public class CountDistinctDoubleGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new CountDistinctDoubleAggregatorFunctionSupplier(inputChannels, 40000); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new CountDistinctDoubleAggregatorFunctionSupplier(40000); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctFloatAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctFloatAggregatorFunctionTests.java index bbd61455a305..7c0d7c1e3d2f 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctFloatAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctFloatAggregatorFunctionTests.java @@ -28,8 +28,8 @@ public class CountDistinctFloatAggregatorFunctionTests extends AggregatorFunctio } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new CountDistinctFloatAggregatorFunctionSupplier(inputChannels, 40000); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new CountDistinctFloatAggregatorFunctionSupplier(40000); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctFloatGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctFloatGroupingAggregatorFunctionTests.java index 6b4a8f2900aa..d536affb34a0 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctFloatGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctFloatGroupingAggregatorFunctionTests.java @@ -26,8 +26,8 @@ import static org.hamcrest.Matchers.equalTo; public class CountDistinctFloatGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new CountDistinctFloatAggregatorFunctionSupplier(inputChannels, 40000); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new CountDistinctFloatAggregatorFunctionSupplier(40000); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctIntAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctIntAggregatorFunctionTests.java index 67dcf4e78d13..8657caafef40 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctIntAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctIntAggregatorFunctionTests.java @@ -34,8 +34,8 @@ public class CountDistinctIntAggregatorFunctionTests extends AggregatorFunctionT } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new CountDistinctIntAggregatorFunctionSupplier(inputChannels, 40000); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new CountDistinctIntAggregatorFunctionSupplier(40000); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctIntGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctIntGroupingAggregatorFunctionTests.java index cfd3357a14c0..88f594b5a6d6 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctIntGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctIntGroupingAggregatorFunctionTests.java @@ -26,8 +26,8 @@ import static org.hamcrest.Matchers.equalTo; public class CountDistinctIntGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new CountDistinctIntAggregatorFunctionSupplier(inputChannels, 40000); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new CountDistinctIntAggregatorFunctionSupplier(40000); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctLongAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctLongAggregatorFunctionTests.java index b136d302ccfb..55f522f31b28 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctLongAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctLongAggregatorFunctionTests.java @@ -35,8 +35,8 @@ public class CountDistinctLongAggregatorFunctionTests extends AggregatorFunction } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new CountDistinctLongAggregatorFunctionSupplier(inputChannels, 40000); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new CountDistinctLongAggregatorFunctionSupplier(40000); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctLongGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctLongGroupingAggregatorFunctionTests.java index 55be7fe9a8ed..db08fd0428e7 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctLongGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountDistinctLongGroupingAggregatorFunctionTests.java @@ -25,8 +25,8 @@ import static org.hamcrest.Matchers.equalTo; public class CountDistinctLongGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new CountDistinctLongAggregatorFunctionSupplier(inputChannels, 40000); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new CountDistinctLongAggregatorFunctionSupplier(40000); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountGroupingAggregatorFunctionTests.java index 06c267ff2d6a..06a066658629 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/CountGroupingAggregatorFunctionTests.java @@ -25,8 +25,8 @@ import static org.hamcrest.Matchers.equalTo; public class CountGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return CountAggregatorFunction.supplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return CountAggregatorFunction.supplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/FilteredAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/FilteredAggregatorFunctionTests.java index 35ecced470e0..a4411d92c6c2 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/FilteredAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/FilteredAggregatorFunctionTests.java @@ -28,10 +28,10 @@ public class FilteredAggregatorFunctionTests extends AggregatorFunctionTestCase private final List unclosed = Collections.synchronizedList(new ArrayList<>()); @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { + protected AggregatorFunctionSupplier aggregatorFunction() { return new FilteredAggregatorFunctionSupplier( - new SumIntAggregatorFunctionSupplier(inputChannels), - new FilteredGroupingAggregatorFunctionTests.AnyGreaterThanFactory(unclosed, inputChannels) + new SumIntAggregatorFunctionSupplier(), + new FilteredGroupingAggregatorFunctionTests.AnyGreaterThanFactory(unclosed, List.of(0)) ); } diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/FilteredGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/FilteredGroupingAggregatorFunctionTests.java index 26971dc927cd..efe7fccd4f06 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/FilteredGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/FilteredGroupingAggregatorFunctionTests.java @@ -34,10 +34,10 @@ public class FilteredGroupingAggregatorFunctionTests extends GroupingAggregatorF private final List unclosed = Collections.synchronizedList(new ArrayList<>()); @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { + protected AggregatorFunctionSupplier aggregatorFunction() { return new FilteredAggregatorFunctionSupplier( - new SumIntAggregatorFunctionSupplier(inputChannels), - new AnyGreaterThanFactory(unclosed, inputChannels) + new SumIntAggregatorFunctionSupplier(), + new AnyGreaterThanFactory(unclosed, List.of(1)) ); } @@ -112,11 +112,12 @@ public class FilteredGroupingAggregatorFunctionTests extends GroupingAggregatorF */ public void testAddIntermediateRowInput() { DriverContext ctx = driverContext(); - AggregatorFunctionSupplier supplier = aggregatorFunction(channels(AggregatorMode.SINGLE)); + AggregatorFunctionSupplier supplier = aggregatorFunction(); + List channels = channels(AggregatorMode.SINGLE); Block[] results = new Block[2]; try ( - GroupingAggregatorFunction main = supplier.groupingAggregator(ctx); - GroupingAggregatorFunction leaf = supplier.groupingAggregator(ctx); + GroupingAggregatorFunction main = supplier.groupingAggregator(ctx, channels); + GroupingAggregatorFunction leaf = supplier.groupingAggregator(ctx, channels); SourceOperator source = simpleInput(ctx.blockFactory(), 10); ) { Page p; diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/GroupingAggregatorFunctionTestCase.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/GroupingAggregatorFunctionTestCase.java index ff96336dc0bb..d82a8487b539 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/GroupingAggregatorFunctionTestCase.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/GroupingAggregatorFunctionTestCase.java @@ -59,10 +59,10 @@ import static org.hamcrest.Matchers.hasSize; * Shared tests for testing grouped aggregations. */ public abstract class GroupingAggregatorFunctionTestCase extends ForkingOperatorTestCase { - protected abstract AggregatorFunctionSupplier aggregatorFunction(List inputChannels); + protected abstract AggregatorFunctionSupplier aggregatorFunction(); protected final int aggregatorIntermediateBlockCount() { - try (var agg = aggregatorFunction(List.of()).groupingAggregator(driverContext())) { + try (var agg = aggregatorFunction().groupingAggregator(driverContext(), List.of())) { return agg.intermediateBlockCount(); } } @@ -98,14 +98,14 @@ public abstract class GroupingAggregatorFunctionTestCase extends ForkingOperator ) { int emitChunkSize = between(100, 200); - AggregatorFunctionSupplier supplier = wrap.apply(aggregatorFunction(channels(mode))); + AggregatorFunctionSupplier supplier = wrap.apply(aggregatorFunction()); if (randomBoolean()) { supplier = chunkGroups(emitChunkSize, supplier); } return new HashAggregationOperator.HashAggregationOperatorFactory( List.of(new BlockHash.GroupSpec(0, ElementType.LONG)), mode, - List.of(supplier.groupingAggregatorFactory(mode)), + List.of(supplier.groupingAggregatorFactory(mode, channels(mode))), randomPageSize(), null ); @@ -619,14 +619,24 @@ public abstract class GroupingAggregatorFunctionTestCase extends ForkingOperator private AggregatorFunctionSupplier chunkGroups(int emitChunkSize, AggregatorFunctionSupplier supplier) { return new AggregatorFunctionSupplier() { @Override - public AggregatorFunction aggregator(DriverContext driverContext) { - return supplier.aggregator(driverContext); + public List nonGroupingIntermediateStateDesc() { + return supplier.nonGroupingIntermediateStateDesc(); } @Override - public GroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public List groupingIntermediateStateDesc() { + return supplier.groupingIntermediateStateDesc(); + } + + @Override + public AggregatorFunction aggregator(DriverContext driverContext, List channels) { + return supplier.aggregator(driverContext, channels); + } + + @Override + public GroupingAggregatorFunction groupingAggregator(DriverContext driverContext, List channels) { return new GroupingAggregatorFunction() { - GroupingAggregatorFunction delegate = supplier.groupingAggregator(driverContext); + GroupingAggregatorFunction delegate = supplier.groupingAggregator(driverContext, channels); BitArray seenGroupIds = new BitArray(0, nonBreakingBigArrays()); @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxBooleanAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxBooleanAggregatorFunctionTests.java index 11119aade12f..a7164740af00 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxBooleanAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxBooleanAggregatorFunctionTests.java @@ -26,8 +26,8 @@ public class MaxBooleanAggregatorFunctionTests extends AggregatorFunctionTestCas } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MaxBooleanAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MaxBooleanAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxBytesRefAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxBytesRefAggregatorFunctionTests.java index adc891a6a977..54b82dcbc500 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxBytesRefAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxBytesRefAggregatorFunctionTests.java @@ -31,8 +31,8 @@ public class MaxBytesRefAggregatorFunctionTests extends AggregatorFunctionTestCa } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MaxBytesRefAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MaxBytesRefAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxBytesRefGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxBytesRefGroupingAggregatorFunctionTests.java index 75a6a839ea62..97d3126fa767 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxBytesRefGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxBytesRefGroupingAggregatorFunctionTests.java @@ -40,8 +40,8 @@ public class MaxBytesRefGroupingAggregatorFunctionTests extends GroupingAggregat } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MaxBytesRefAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MaxBytesRefAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxDoubleAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxDoubleAggregatorFunctionTests.java index 9d638fae4e82..fee5950c0825 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxDoubleAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxDoubleAggregatorFunctionTests.java @@ -26,8 +26,8 @@ public class MaxDoubleAggregatorFunctionTests extends AggregatorFunctionTestCase } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MaxDoubleAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MaxDoubleAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxDoubleGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxDoubleGroupingAggregatorFunctionTests.java index 18aec87a9d07..0e7d716d2c0c 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxDoubleGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxDoubleGroupingAggregatorFunctionTests.java @@ -32,8 +32,8 @@ public class MaxDoubleGroupingAggregatorFunctionTests extends GroupingAggregator } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MaxDoubleAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MaxDoubleAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxFloatAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxFloatAggregatorFunctionTests.java index 5e14a99fd0fa..a1f13566a069 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxFloatAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxFloatAggregatorFunctionTests.java @@ -26,8 +26,8 @@ public class MaxFloatAggregatorFunctionTests extends AggregatorFunctionTestCase } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MaxFloatAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MaxFloatAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxFloatGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxFloatGroupingAggregatorFunctionTests.java index e4da581a5913..62fe712beb4e 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxFloatGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxFloatGroupingAggregatorFunctionTests.java @@ -33,8 +33,8 @@ public class MaxFloatGroupingAggregatorFunctionTests extends GroupingAggregatorF } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MaxFloatAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MaxFloatAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIntAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIntAggregatorFunctionTests.java index af198e3aec9d..5507e2c261e9 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIntAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIntAggregatorFunctionTests.java @@ -25,8 +25,8 @@ public class MaxIntAggregatorFunctionTests extends AggregatorFunctionTestCase { } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MaxIntAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MaxIntAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIntGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIntGroupingAggregatorFunctionTests.java index 372015ebd767..da59a0f91ccd 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIntGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIntGroupingAggregatorFunctionTests.java @@ -23,8 +23,8 @@ import static org.hamcrest.Matchers.equalTo; public class MaxIntGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MaxIntAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MaxIntAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIpAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIpAggregatorFunctionTests.java index 84488b5115e5..b39b5fe38496 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIpAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIpAggregatorFunctionTests.java @@ -32,8 +32,8 @@ public class MaxIpAggregatorFunctionTests extends AggregatorFunctionTestCase { } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MaxIpAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MaxIpAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIpGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIpGroupingAggregatorFunctionTests.java index 12e34fcf9a50..2e6210c70136 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIpGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxIpGroupingAggregatorFunctionTests.java @@ -42,8 +42,8 @@ public class MaxIpGroupingAggregatorFunctionTests extends GroupingAggregatorFunc } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MaxIpAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MaxIpAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxLongAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxLongAggregatorFunctionTests.java index 27a6fb066046..081ef44f3704 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxLongAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxLongAggregatorFunctionTests.java @@ -26,8 +26,8 @@ public class MaxLongAggregatorFunctionTests extends AggregatorFunctionTestCase { } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MaxLongAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MaxLongAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxLongGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxLongGroupingAggregatorFunctionTests.java index 1bf7cd9eea27..6d6c37fb306a 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxLongGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MaxLongGroupingAggregatorFunctionTests.java @@ -23,8 +23,8 @@ import static org.hamcrest.Matchers.equalTo; public class MaxLongGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MaxLongAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MaxLongAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleAggregatorFunctionTests.java index 1d105430ce1d..db9ab2c99810 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleAggregatorFunctionTests.java @@ -29,8 +29,8 @@ public class MedianAbsoluteDeviationDoubleAggregatorFunctionTests extends Aggreg } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleGroupingAggregatorFunctionTests.java index a6ca769036e5..75305708bd93 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleGroupingAggregatorFunctionTests.java @@ -46,8 +46,8 @@ public class MedianAbsoluteDeviationDoubleGroupingAggregatorFunctionTests extend } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatAggregatorFunctionTests.java index 786603e12f9c..fb70fa6385d7 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatAggregatorFunctionTests.java @@ -29,8 +29,8 @@ public class MedianAbsoluteDeviationFloatAggregatorFunctionTests extends Aggrega } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MedianAbsoluteDeviationFloatAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MedianAbsoluteDeviationFloatAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatGroupingAggregatorFunctionTests.java index 14416b3aec1e..a0b5495d53bd 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatGroupingAggregatorFunctionTests.java @@ -46,8 +46,8 @@ public class MedianAbsoluteDeviationFloatGroupingAggregatorFunctionTests extends } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MedianAbsoluteDeviationFloatAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MedianAbsoluteDeviationFloatAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntAggregatorFunctionTests.java index fa396d7dcf7a..fca7ec47b05a 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntAggregatorFunctionTests.java @@ -29,8 +29,8 @@ public class MedianAbsoluteDeviationIntAggregatorFunctionTests extends Aggregato } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MedianAbsoluteDeviationIntAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MedianAbsoluteDeviationIntAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntGroupingAggregatorFunctionTests.java index 8a8b05152819..d5e5f0869988 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntGroupingAggregatorFunctionTests.java @@ -46,8 +46,8 @@ public class MedianAbsoluteDeviationIntGroupingAggregatorFunctionTests extends G } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MedianAbsoluteDeviationIntAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MedianAbsoluteDeviationIntAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongAggregatorFunctionTests.java index 0f570adfc6fd..f700d4270f4d 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongAggregatorFunctionTests.java @@ -29,8 +29,8 @@ public class MedianAbsoluteDeviationLongAggregatorFunctionTests extends Aggregat } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MedianAbsoluteDeviationLongAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MedianAbsoluteDeviationLongAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongGroupingAggregatorFunctionTests.java index 818150d3234a..55895ceadd52 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongGroupingAggregatorFunctionTests.java @@ -46,8 +46,8 @@ public class MedianAbsoluteDeviationLongGroupingAggregatorFunctionTests extends } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MedianAbsoluteDeviationLongAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MedianAbsoluteDeviationLongAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinBooleanAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinBooleanAggregatorFunctionTests.java index 74cdca31da34..186d9edf2a9e 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinBooleanAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinBooleanAggregatorFunctionTests.java @@ -26,8 +26,8 @@ public class MinBooleanAggregatorFunctionTests extends AggregatorFunctionTestCas } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MinBooleanAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MinBooleanAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinBytesRefAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinBytesRefAggregatorFunctionTests.java index b4383d6b0f56..678f7259f784 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinBytesRefAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinBytesRefAggregatorFunctionTests.java @@ -31,8 +31,8 @@ public class MinBytesRefAggregatorFunctionTests extends AggregatorFunctionTestCa } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MinBytesRefAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MinBytesRefAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinBytesRefGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinBytesRefGroupingAggregatorFunctionTests.java index d4cfca819f3b..7d099e760684 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinBytesRefGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinBytesRefGroupingAggregatorFunctionTests.java @@ -40,8 +40,8 @@ public class MinBytesRefGroupingAggregatorFunctionTests extends GroupingAggregat } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MinBytesRefAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MinBytesRefAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinDoubleAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinDoubleAggregatorFunctionTests.java index e92b98ebf91d..7f7095d13aa4 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinDoubleAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinDoubleAggregatorFunctionTests.java @@ -26,8 +26,8 @@ public class MinDoubleAggregatorFunctionTests extends AggregatorFunctionTestCase } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MinDoubleAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MinDoubleAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinDoubleGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinDoubleGroupingAggregatorFunctionTests.java index 62cf954a1909..756d19345aa9 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinDoubleGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinDoubleGroupingAggregatorFunctionTests.java @@ -31,8 +31,8 @@ public class MinDoubleGroupingAggregatorFunctionTests extends GroupingAggregator } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MinDoubleAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MinDoubleAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinFloatAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinFloatAggregatorFunctionTests.java index 59a09569c65a..ef98a2dd7b95 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinFloatAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinFloatAggregatorFunctionTests.java @@ -26,8 +26,8 @@ public class MinFloatAggregatorFunctionTests extends AggregatorFunctionTestCase } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MinFloatAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MinFloatAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinFloatGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinFloatGroupingAggregatorFunctionTests.java index be41e058f60d..9044732c1b8c 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinFloatGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinFloatGroupingAggregatorFunctionTests.java @@ -31,8 +31,8 @@ public class MinFloatGroupingAggregatorFunctionTests extends GroupingAggregatorF } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MinFloatAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MinFloatAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIntAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIntAggregatorFunctionTests.java index ffa2189f96b6..e7296a5b08f4 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIntAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIntAggregatorFunctionTests.java @@ -25,8 +25,8 @@ public class MinIntAggregatorFunctionTests extends AggregatorFunctionTestCase { } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MinIntAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MinIntAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIntGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIntGroupingAggregatorFunctionTests.java index a7644c8bb26a..d77b63bbb54c 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIntGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIntGroupingAggregatorFunctionTests.java @@ -23,8 +23,8 @@ import static org.hamcrest.Matchers.equalTo; public class MinIntGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MinIntAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MinIntAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIpAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIpAggregatorFunctionTests.java index 17e9812d2e4e..907270217831 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIpAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIpAggregatorFunctionTests.java @@ -32,8 +32,8 @@ public class MinIpAggregatorFunctionTests extends AggregatorFunctionTestCase { } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MinIpAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MinIpAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIpGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIpGroupingAggregatorFunctionTests.java index f51662ffee35..86d7d0e961a1 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIpGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinIpGroupingAggregatorFunctionTests.java @@ -42,8 +42,8 @@ public class MinIpGroupingAggregatorFunctionTests extends GroupingAggregatorFunc } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MinIpAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MinIpAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinLongAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinLongAggregatorFunctionTests.java index 2ce7aab455c5..8bb82a149f45 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinLongAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinLongAggregatorFunctionTests.java @@ -26,8 +26,8 @@ public class MinLongAggregatorFunctionTests extends AggregatorFunctionTestCase { } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MinLongAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MinLongAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinLongGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinLongGroupingAggregatorFunctionTests.java index 5591fb57a8f2..da8a63a42920 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinLongGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/MinLongGroupingAggregatorFunctionTests.java @@ -23,8 +23,8 @@ import static org.hamcrest.Matchers.equalTo; public class MinLongGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new MinLongAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new MinLongAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileDoubleAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileDoubleAggregatorFunctionTests.java index b9ee31fb481f..aa18c47733ff 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileDoubleAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileDoubleAggregatorFunctionTests.java @@ -32,8 +32,8 @@ public class PercentileDoubleAggregatorFunctionTests extends AggregatorFunctionT } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new PercentileDoubleAggregatorFunctionSupplier(inputChannels, percentile); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new PercentileDoubleAggregatorFunctionSupplier(percentile); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileDoubleGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileDoubleGroupingAggregatorFunctionTests.java index d000fba1ee29..8a44fba3bfa1 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileDoubleGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileDoubleGroupingAggregatorFunctionTests.java @@ -33,8 +33,8 @@ public class PercentileDoubleGroupingAggregatorFunctionTests extends GroupingAgg } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new PercentileDoubleAggregatorFunctionSupplier(inputChannels, percentile); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new PercentileDoubleAggregatorFunctionSupplier(percentile); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileFloatAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileFloatAggregatorFunctionTests.java index da69e11734b3..d23436310cff 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileFloatAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileFloatAggregatorFunctionTests.java @@ -32,8 +32,8 @@ public class PercentileFloatAggregatorFunctionTests extends AggregatorFunctionTe } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new PercentileFloatAggregatorFunctionSupplier(inputChannels, percentile); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new PercentileFloatAggregatorFunctionSupplier(percentile); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileFloatGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileFloatGroupingAggregatorFunctionTests.java index 917f6b6a0b64..c338dc38395f 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileFloatGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileFloatGroupingAggregatorFunctionTests.java @@ -33,8 +33,8 @@ public class PercentileFloatGroupingAggregatorFunctionTests extends GroupingAggr } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new PercentileFloatAggregatorFunctionSupplier(inputChannels, percentile); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new PercentileFloatAggregatorFunctionSupplier(percentile); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileIntAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileIntAggregatorFunctionTests.java index 4b8ef49e09d9..278c37c02be3 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileIntAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileIntAggregatorFunctionTests.java @@ -31,8 +31,8 @@ public class PercentileIntAggregatorFunctionTests extends AggregatorFunctionTest } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new PercentileIntAggregatorFunctionSupplier(inputChannels, percentile); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new PercentileIntAggregatorFunctionSupplier(percentile); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileIntGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileIntGroupingAggregatorFunctionTests.java index 15cf0c920252..ef8fa6eab85f 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileIntGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileIntGroupingAggregatorFunctionTests.java @@ -33,8 +33,8 @@ public class PercentileIntGroupingAggregatorFunctionTests extends GroupingAggreg } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new PercentileIntAggregatorFunctionSupplier(inputChannels, percentile); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new PercentileIntAggregatorFunctionSupplier(percentile); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileLongAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileLongAggregatorFunctionTests.java index 664fe1edc6ad..b1896025c363 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileLongAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileLongAggregatorFunctionTests.java @@ -31,8 +31,8 @@ public class PercentileLongAggregatorFunctionTests extends AggregatorFunctionTes } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new PercentileLongAggregatorFunctionSupplier(inputChannels, percentile); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new PercentileLongAggregatorFunctionSupplier(percentile); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileLongGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileLongGroupingAggregatorFunctionTests.java index f09d395c877c..55065129df0c 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileLongGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/PercentileLongGroupingAggregatorFunctionTests.java @@ -33,8 +33,8 @@ public class PercentileLongGroupingAggregatorFunctionTests extends GroupingAggre } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new PercentileLongAggregatorFunctionSupplier(inputChannels, percentile); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new PercentileLongAggregatorFunctionSupplier(percentile); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumDoubleAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumDoubleAggregatorFunctionTests.java index 4d94d4d2e029..a64ec4e155ad 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumDoubleAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumDoubleAggregatorFunctionTests.java @@ -33,8 +33,8 @@ public class SumDoubleAggregatorFunctionTests extends AggregatorFunctionTestCase } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new SumDoubleAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new SumDoubleAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumDoubleGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumDoubleGroupingAggregatorFunctionTests.java index f982ee6cd58d..8e6970ebdd10 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumDoubleGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumDoubleGroupingAggregatorFunctionTests.java @@ -31,8 +31,8 @@ public class SumDoubleGroupingAggregatorFunctionTests extends GroupingAggregator } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new SumDoubleAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new SumDoubleAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumFloatAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumFloatAggregatorFunctionTests.java index c7a9fb75404f..11205907acb2 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumFloatAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumFloatAggregatorFunctionTests.java @@ -33,8 +33,8 @@ public class SumFloatAggregatorFunctionTests extends AggregatorFunctionTestCase } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new SumFloatAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new SumFloatAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumFloatGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumFloatGroupingAggregatorFunctionTests.java index 54bd92cbfff2..008b8a18a6b0 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumFloatGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumFloatGroupingAggregatorFunctionTests.java @@ -31,8 +31,8 @@ public class SumFloatGroupingAggregatorFunctionTests extends GroupingAggregatorF } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new SumFloatAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new SumFloatAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumIntAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumIntAggregatorFunctionTests.java index 365b9cc75e01..6484382d5ff5 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumIntAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumIntAggregatorFunctionTests.java @@ -32,8 +32,8 @@ public class SumIntAggregatorFunctionTests extends AggregatorFunctionTestCase { } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new SumIntAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new SumIntAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumIntGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumIntGroupingAggregatorFunctionTests.java index 3dfa4e9332a0..d83357940d99 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumIntGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumIntGroupingAggregatorFunctionTests.java @@ -22,8 +22,8 @@ import static org.hamcrest.Matchers.equalTo; public class SumIntGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new SumIntAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new SumIntAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumLongAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumLongAggregatorFunctionTests.java index 4821c72229d8..c2b805291f4f 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumLongAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumLongAggregatorFunctionTests.java @@ -32,8 +32,8 @@ public class SumLongAggregatorFunctionTests extends AggregatorFunctionTestCase { } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new SumLongAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new SumLongAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumLongGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumLongGroupingAggregatorFunctionTests.java index f41a5cbef94f..f289686f8e84 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumLongGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/SumLongGroupingAggregatorFunctionTests.java @@ -22,8 +22,8 @@ import static org.hamcrest.Matchers.equalTo; public class SumLongGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new SumLongAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new SumLongAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopBooleanAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopBooleanAggregatorFunctionTests.java index 662b963d3247..cfb91acb1cf2 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopBooleanAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopBooleanAggregatorFunctionTests.java @@ -27,8 +27,8 @@ public class TopBooleanAggregatorFunctionTests extends AggregatorFunctionTestCas } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new TopBooleanAggregatorFunctionSupplier(inputChannels, LIMIT, true); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new TopBooleanAggregatorFunctionSupplier(LIMIT, true); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopBytesRefAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopBytesRefAggregatorFunctionTests.java index 732229c98f9c..e1f38692877a 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopBytesRefAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopBytesRefAggregatorFunctionTests.java @@ -9,8 +9,6 @@ package org.elasticsearch.compute.aggregation; import org.apache.lucene.util.BytesRef; -import java.util.List; - public class TopBytesRefAggregatorFunctionTests extends AbstractTopBytesRefAggregatorFunctionTests { @Override protected BytesRef randomValue() { @@ -18,8 +16,8 @@ public class TopBytesRefAggregatorFunctionTests extends AbstractTopBytesRefAggre } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new TopBytesRefAggregatorFunctionSupplier(inputChannels, LIMIT, true); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new TopBytesRefAggregatorFunctionSupplier(LIMIT, true); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopBytesRefGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopBytesRefGroupingAggregatorFunctionTests.java index 4932e1abef46..0c27a5f38681 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopBytesRefGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopBytesRefGroupingAggregatorFunctionTests.java @@ -10,8 +10,6 @@ package org.elasticsearch.compute.aggregation; import org.apache.lucene.util.BytesRef; import org.elasticsearch.xpack.esql.core.type.DataType; -import java.util.List; - public class TopBytesRefGroupingAggregatorFunctionTests extends AbstractTopBytesRefGroupingAggregatorFunctionTests { @Override protected BytesRef randomValue() { @@ -19,8 +17,8 @@ public class TopBytesRefGroupingAggregatorFunctionTests extends AbstractTopBytes } @Override - protected final AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new TopBytesRefAggregatorFunctionSupplier(inputChannels, LIMIT, true); + protected final AggregatorFunctionSupplier aggregatorFunction() { + return new TopBytesRefAggregatorFunctionSupplier(LIMIT, true); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopDoubleAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopDoubleAggregatorFunctionTests.java index 817df4ba4713..04c2000d2e2d 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopDoubleAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopDoubleAggregatorFunctionTests.java @@ -27,8 +27,8 @@ public class TopDoubleAggregatorFunctionTests extends AggregatorFunctionTestCase } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new TopDoubleAggregatorFunctionSupplier(inputChannels, LIMIT, true); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new TopDoubleAggregatorFunctionSupplier(LIMIT, true); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopFloatAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopFloatAggregatorFunctionTests.java index c565a13fb73d..8dd2d5d82f81 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopFloatAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopFloatAggregatorFunctionTests.java @@ -27,8 +27,8 @@ public class TopFloatAggregatorFunctionTests extends AggregatorFunctionTestCase } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new TopFloatAggregatorFunctionSupplier(inputChannels, LIMIT, true); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new TopFloatAggregatorFunctionSupplier(LIMIT, true); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopIntAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopIntAggregatorFunctionTests.java index a0ac1a685413..b52439dc9826 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopIntAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopIntAggregatorFunctionTests.java @@ -27,8 +27,8 @@ public class TopIntAggregatorFunctionTests extends AggregatorFunctionTestCase { } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new TopIntAggregatorFunctionSupplier(inputChannels, LIMIT, true); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new TopIntAggregatorFunctionSupplier(LIMIT, true); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopIpAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopIpAggregatorFunctionTests.java index 840e4cf9af96..c9ec81cb5981 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopIpAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopIpAggregatorFunctionTests.java @@ -10,8 +10,6 @@ package org.elasticsearch.compute.aggregation; import org.apache.lucene.document.InetAddressPoint; import org.apache.lucene.util.BytesRef; -import java.util.List; - public class TopIpAggregatorFunctionTests extends AbstractTopBytesRefAggregatorFunctionTests { @Override protected BytesRef randomValue() { @@ -19,8 +17,8 @@ public class TopIpAggregatorFunctionTests extends AbstractTopBytesRefAggregatorF } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new TopIpAggregatorFunctionSupplier(inputChannels, LIMIT, true); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new TopIpAggregatorFunctionSupplier(LIMIT, true); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopIpGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopIpGroupingAggregatorFunctionTests.java index 02bf6b667192..3c0577f7a1a9 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopIpGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopIpGroupingAggregatorFunctionTests.java @@ -11,8 +11,6 @@ import org.apache.lucene.document.InetAddressPoint; import org.apache.lucene.util.BytesRef; import org.elasticsearch.xpack.esql.core.type.DataType; -import java.util.List; - public class TopIpGroupingAggregatorFunctionTests extends AbstractTopBytesRefGroupingAggregatorFunctionTests { @Override protected BytesRef randomValue() { @@ -20,8 +18,8 @@ public class TopIpGroupingAggregatorFunctionTests extends AbstractTopBytesRefGro } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new TopIpAggregatorFunctionSupplier(inputChannels, LIMIT, true); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new TopIpAggregatorFunctionSupplier(LIMIT, true); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopLongAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopLongAggregatorFunctionTests.java index cb42be67844d..4ff27b092a18 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopLongAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/TopLongAggregatorFunctionTests.java @@ -27,8 +27,8 @@ public class TopLongAggregatorFunctionTests extends AggregatorFunctionTestCase { } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new TopLongAggregatorFunctionSupplier(inputChannels, LIMIT, true); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new TopLongAggregatorFunctionSupplier(LIMIT, true); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregatorFunctionTests.java index c0a91fe22b87..7c5e3f386116 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregatorFunctionTests.java @@ -32,8 +32,8 @@ public class ValuesBytesRefAggregatorFunctionTests extends AggregatorFunctionTes } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new ValuesBytesRefAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new ValuesBytesRefAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesBytesRefGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesBytesRefGroupingAggregatorFunctionTests.java index fc9bc90828df..a1367bee5334 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesBytesRefGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesBytesRefGroupingAggregatorFunctionTests.java @@ -28,8 +28,8 @@ import static org.hamcrest.Matchers.nullValue; public class ValuesBytesRefGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new ValuesBytesRefAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new ValuesBytesRefAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesDoubleAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesDoubleAggregatorFunctionTests.java index e5bb8e3138e2..497813e058e6 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesDoubleAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesDoubleAggregatorFunctionTests.java @@ -28,8 +28,8 @@ public class ValuesDoubleAggregatorFunctionTests extends AggregatorFunctionTestC } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new ValuesDoubleAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new ValuesDoubleAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesDoubleGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesDoubleGroupingAggregatorFunctionTests.java index a4b1a3c028e4..b89612a52c68 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesDoubleGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesDoubleGroupingAggregatorFunctionTests.java @@ -27,8 +27,8 @@ import static org.hamcrest.Matchers.nullValue; public class ValuesDoubleGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new ValuesDoubleAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new ValuesDoubleAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesFloatAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesFloatAggregatorFunctionTests.java index 67068ce10c99..0cf536d3e0ec 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesFloatAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesFloatAggregatorFunctionTests.java @@ -28,8 +28,8 @@ public class ValuesFloatAggregatorFunctionTests extends AggregatorFunctionTestCa } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new ValuesFloatAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new ValuesFloatAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesFloatGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesFloatGroupingAggregatorFunctionTests.java index e25d7567a193..7dc550abd4e4 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesFloatGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesFloatGroupingAggregatorFunctionTests.java @@ -27,8 +27,8 @@ import static org.hamcrest.Matchers.nullValue; public class ValuesFloatGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new ValuesFloatAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new ValuesFloatAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesIntAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesIntAggregatorFunctionTests.java index c60707046a0b..9e4d56a962b2 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesIntAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesIntAggregatorFunctionTests.java @@ -28,8 +28,8 @@ public class ValuesIntAggregatorFunctionTests extends AggregatorFunctionTestCase } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new ValuesIntAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new ValuesIntAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesIntGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesIntGroupingAggregatorFunctionTests.java index 154b076d6a24..7368ed285ddb 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesIntGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesIntGroupingAggregatorFunctionTests.java @@ -27,8 +27,8 @@ import static org.hamcrest.Matchers.nullValue; public class ValuesIntGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new ValuesIntAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new ValuesIntAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesLongAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesLongAggregatorFunctionTests.java index 933058d8d8e1..32609edd2b8f 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesLongAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesLongAggregatorFunctionTests.java @@ -28,8 +28,8 @@ public class ValuesLongAggregatorFunctionTests extends AggregatorFunctionTestCas } @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new ValuesLongAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new ValuesLongAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesLongGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesLongGroupingAggregatorFunctionTests.java index 8259d84d955e..3180ac53f6ef 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesLongGroupingAggregatorFunctionTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/ValuesLongGroupingAggregatorFunctionTests.java @@ -27,8 +27,8 @@ import static org.hamcrest.Matchers.nullValue; public class ValuesLongGroupingAggregatorFunctionTests extends GroupingAggregatorFunctionTestCase { @Override - protected AggregatorFunctionSupplier aggregatorFunction(List inputChannels) { - return new ValuesLongAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier aggregatorFunction() { + return new ValuesLongAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/blockhash/CategorizeBlockHashTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/blockhash/CategorizeBlockHashTests.java index d0a1fc1e2959..42e9fc8deafc 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/blockhash/CategorizeBlockHashTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/blockhash/CategorizeBlockHashTests.java @@ -424,8 +424,8 @@ public class CategorizeBlockHashTests extends BlockHashTestCase { List.of(makeGroupSpec()), AggregatorMode.INITIAL, List.of( - new SumLongAggregatorFunctionSupplier(List.of(1)).groupingAggregatorFactory(AggregatorMode.INITIAL), - new MaxLongAggregatorFunctionSupplier(List.of(1)).groupingAggregatorFactory(AggregatorMode.INITIAL) + new SumLongAggregatorFunctionSupplier().groupingAggregatorFactory(AggregatorMode.INITIAL, List.of(1)), + new MaxLongAggregatorFunctionSupplier().groupingAggregatorFactory(AggregatorMode.INITIAL, List.of(1)) ), 16 * 1024, analysisRegistry @@ -445,8 +445,8 @@ public class CategorizeBlockHashTests extends BlockHashTestCase { List.of(makeGroupSpec()), AggregatorMode.INITIAL, List.of( - new SumLongAggregatorFunctionSupplier(List.of(1)).groupingAggregatorFactory(AggregatorMode.INITIAL), - new MaxLongAggregatorFunctionSupplier(List.of(1)).groupingAggregatorFactory(AggregatorMode.INITIAL) + new SumLongAggregatorFunctionSupplier().groupingAggregatorFactory(AggregatorMode.INITIAL, List.of(1)), + new MaxLongAggregatorFunctionSupplier().groupingAggregatorFactory(AggregatorMode.INITIAL, List.of(1)) ), 16 * 1024, analysisRegistry @@ -468,8 +468,8 @@ public class CategorizeBlockHashTests extends BlockHashTestCase { List.of(makeGroupSpec()), AggregatorMode.FINAL, List.of( - new SumLongAggregatorFunctionSupplier(List.of(1, 2)).groupingAggregatorFactory(AggregatorMode.FINAL), - new MaxLongAggregatorFunctionSupplier(List.of(3, 4)).groupingAggregatorFactory(AggregatorMode.FINAL) + new SumLongAggregatorFunctionSupplier().groupingAggregatorFactory(AggregatorMode.FINAL, List.of(1, 2)), + new MaxLongAggregatorFunctionSupplier().groupingAggregatorFactory(AggregatorMode.FINAL, List.of(3, 4)) ), 16 * 1024, analysisRegistry diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/blockhash/CategorizePackedValuesBlockHashTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/blockhash/CategorizePackedValuesBlockHashTests.java index 17f41e27703f..9c89317e4c35 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/blockhash/CategorizePackedValuesBlockHashTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/blockhash/CategorizePackedValuesBlockHashTests.java @@ -144,7 +144,7 @@ public class CategorizePackedValuesBlockHashTests extends BlockHashTestCase { new HashAggregationOperator.HashAggregationOperatorFactory( groupSpecs, AggregatorMode.INITIAL, - List.of(new ValuesBytesRefAggregatorFunctionSupplier(List.of(0)).groupingAggregatorFactory(AggregatorMode.INITIAL)), + List.of(new ValuesBytesRefAggregatorFunctionSupplier().groupingAggregatorFactory(AggregatorMode.INITIAL, List.of(0))), 16 * 1024, analysisRegistry ).get(driverContext) @@ -162,7 +162,7 @@ public class CategorizePackedValuesBlockHashTests extends BlockHashTestCase { new HashAggregationOperator.HashAggregationOperatorFactory( groupSpecs, AggregatorMode.INITIAL, - List.of(new ValuesBytesRefAggregatorFunctionSupplier(List.of(0)).groupingAggregatorFactory(AggregatorMode.INITIAL)), + List.of(new ValuesBytesRefAggregatorFunctionSupplier().groupingAggregatorFactory(AggregatorMode.INITIAL, List.of(0))), 16 * 1024, analysisRegistry ).get(driverContext) @@ -182,7 +182,7 @@ public class CategorizePackedValuesBlockHashTests extends BlockHashTestCase { new HashAggregationOperator.HashAggregationOperatorFactory( groupSpecs, AggregatorMode.FINAL, - List.of(new ValuesBytesRefAggregatorFunctionSupplier(List.of(2)).groupingAggregatorFactory(AggregatorMode.FINAL)), + List.of(new ValuesBytesRefAggregatorFunctionSupplier().groupingAggregatorFactory(AggregatorMode.FINAL, List.of(2))), 16 * 1024, analysisRegistry ).get(driverContext) diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxDoubleOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxDoubleOperatorTests.java index 4cb113457b23..49d7e42e49df 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxDoubleOperatorTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxDoubleOperatorTests.java @@ -70,7 +70,7 @@ public class LuceneMaxDoubleOperatorTests extends LuceneMaxOperatorTestCase { @Override public AggregatorFunction newAggregatorFunction(DriverContext context) { - return new MaxDoubleAggregatorFunctionSupplier(List.of(0, 1)).aggregator(context); + return new MaxDoubleAggregatorFunctionSupplier().aggregator(context, List.of(0, 1)); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxFloatOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxFloatOperatorTests.java index 4a009a2d84c6..7651cf5c0b87 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxFloatOperatorTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxFloatOperatorTests.java @@ -70,7 +70,7 @@ public class LuceneMaxFloatOperatorTests extends LuceneMaxOperatorTestCase { @Override public AggregatorFunction newAggregatorFunction(DriverContext context) { - return new MaxFloatAggregatorFunctionSupplier(List.of(0, 1)).aggregator(context); + return new MaxFloatAggregatorFunctionSupplier().aggregator(context, List.of(0, 1)); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxIntOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxIntOperatorTests.java index a6118481ca43..f26274be6f81 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxIntOperatorTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxIntOperatorTests.java @@ -69,7 +69,7 @@ public class LuceneMaxIntOperatorTests extends LuceneMaxOperatorTestCase { @Override public AggregatorFunction newAggregatorFunction(DriverContext context) { - return new MaxIntAggregatorFunctionSupplier(List.of(0, 1)).aggregator(context); + return new MaxIntAggregatorFunctionSupplier().aggregator(context, List.of(0, 1)); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxLongOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxLongOperatorTests.java index 894c8e862123..ae096b5e3630 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxLongOperatorTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMaxLongOperatorTests.java @@ -69,7 +69,7 @@ public class LuceneMaxLongOperatorTests extends LuceneMaxOperatorTestCase { @Override public AggregatorFunction newAggregatorFunction(DriverContext context) { - return new MaxLongAggregatorFunctionSupplier(List.of(0, 1)).aggregator(context); + return new MaxLongAggregatorFunctionSupplier().aggregator(context, List.of(0, 1)); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinDoubleOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinDoubleOperatorTests.java index 5fef2d489703..ce212392ef88 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinDoubleOperatorTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinDoubleOperatorTests.java @@ -70,7 +70,7 @@ public class LuceneMinDoubleOperatorTests extends LuceneMinOperatorTestCase { @Override public AggregatorFunction newAggregatorFunction(DriverContext context) { - return new MinDoubleAggregatorFunctionSupplier(List.of(0, 1)).aggregator(context); + return new MinDoubleAggregatorFunctionSupplier().aggregator(context, List.of(0, 1)); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinFloatOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinFloatOperatorTests.java index 41c8751c08a9..9500879f450b 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinFloatOperatorTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinFloatOperatorTests.java @@ -71,7 +71,7 @@ public class LuceneMinFloatOperatorTests extends LuceneMinOperatorTestCase { @Override public AggregatorFunction newAggregatorFunction(DriverContext context) { - return new MinFloatAggregatorFunctionSupplier(List.of(0, 1)).aggregator(context); + return new MinFloatAggregatorFunctionSupplier().aggregator(context, List.of(0, 1)); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinIntegerOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinIntegerOperatorTests.java index 5d2c867f4f66..e800619ef747 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinIntegerOperatorTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinIntegerOperatorTests.java @@ -69,7 +69,7 @@ public class LuceneMinIntegerOperatorTests extends LuceneMinOperatorTestCase { @Override public AggregatorFunction newAggregatorFunction(DriverContext context) { - return new MinIntAggregatorFunctionSupplier(List.of(0, 1)).aggregator(context); + return new MinIntAggregatorFunctionSupplier().aggregator(context, List.of(0, 1)); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinLongOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinLongOperatorTests.java index 15c34f5853ae..a20d90f1fcb5 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinLongOperatorTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneMinLongOperatorTests.java @@ -69,7 +69,7 @@ public class LuceneMinLongOperatorTests extends LuceneMinOperatorTestCase { @Override public AggregatorFunction newAggregatorFunction(DriverContext context) { - return new MinLongAggregatorFunctionSupplier(List.of(0, 1)).aggregator(context); + return new MinLongAggregatorFunctionSupplier().aggregator(context, List.of(0, 1)); } @Override diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/AggregationOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/AggregationOperatorTests.java index 5e16fce2af00..6fbef583cbef 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/AggregationOperatorTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/AggregationOperatorTests.java @@ -48,8 +48,8 @@ public class AggregationOperatorTests extends ForkingOperatorTestCase { return new AggregationOperator.AggregationOperatorFactory( List.of( - new SumLongAggregatorFunctionSupplier(sumChannels).aggregatorFactory(mode), - new MaxLongAggregatorFunctionSupplier(maxChannels).aggregatorFactory(mode) + new SumLongAggregatorFunctionSupplier().aggregatorFactory(mode, sumChannels), + new MaxLongAggregatorFunctionSupplier().aggregatorFactory(mode, maxChannels) ), mode ); diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/AsyncOperatorStatusTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/AsyncOperatorStatusTests.java index ab2dcc5e6c44..1990728e128f 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/AsyncOperatorStatusTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/AsyncOperatorStatusTests.java @@ -39,31 +39,31 @@ public class AsyncOperatorStatusTests extends AbstractWireSerializingTestCase new AsyncOperator.Status( randomValueOtherThan(in.receivedPages(), ESTestCase::randomNonNegativeLong), in.completedPages(), - in.totalTimeInMillis() + in.procesNanos() ); case 1 -> new AsyncOperator.Status( in.receivedPages(), randomValueOtherThan(in.completedPages(), ESTestCase::randomNonNegativeLong), - in.totalTimeInMillis() + in.procesNanos() ); case 2 -> new AsyncOperator.Status( in.receivedPages(), in.completedPages(), - randomValueOtherThan(in.totalTimeInMillis(), ESTestCase::randomNonNegativeLong) + randomValueOtherThan(in.procesNanos(), ESTestCase::randomNonNegativeLong) ); default -> throw new AssertionError("unknown "); }; } public void testToXContent() { - var status = new AsyncOperator.Status(100, 50, TimeValue.timeValueSeconds(10).millis()); + var status = new AsyncOperator.Status(100, 50, TimeValue.timeValueNanos(10).nanos()); String json = Strings.toString(status, true, true); assertThat(json, equalTo(""" { + "process_nanos" : 10, + "process_time" : "10nanos", "received_pages" : 100, - "completed_pages" : 50, - "total_time_in_millis" : 10000, - "total_time" : "10s" + "completed_pages" : 50 }""")); } } diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/ChangePointOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/ChangePointOperatorTests.java new file mode 100644 index 000000000000..3175bb06c562 --- /dev/null +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/ChangePointOperatorTests.java @@ -0,0 +1,86 @@ +/* + * 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.compute.operator; + +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.compute.data.BlockFactory; +import org.elasticsearch.compute.data.BytesRefBlock; +import org.elasticsearch.compute.data.DoubleBlock; +import org.elasticsearch.compute.data.LongBlock; +import org.elasticsearch.compute.data.Page; +import org.elasticsearch.compute.test.OperatorTestCase; +import org.elasticsearch.compute.test.SequenceLongBlockSourceOperator; +import org.hamcrest.Matcher; + +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; + +public class ChangePointOperatorTests extends OperatorTestCase { + + @Override + protected SourceOperator simpleInput(BlockFactory blockFactory, int size) { + // size must be in [25, 1000] for ChangePoint to function correctly + // and detect the step change. + size = Math.clamp(size, 25, 1000); + List data = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + if (i <= size / 2) { + data.add(0L); + } else { + data.add(1L); + } + } + return new SequenceLongBlockSourceOperator(blockFactory, data); + } + + @Override + protected void assertSimpleOutput(List input, List results) { + boolean seenOne = false; + assertThat(results, hasSize(input.size())); + for (int i = 0; i < results.size(); i++) { + Page inputPage = input.get(i); + Page resultPage = results.get(i); + assertThat(resultPage.getPositionCount(), equalTo(inputPage.getPositionCount())); + assertThat(resultPage.getBlockCount(), equalTo(3)); + for (int j = 0; j < resultPage.getPositionCount(); j++) { + long inputValue = ((LongBlock) resultPage.getBlock(0)).getLong(j); + long resultValue = ((LongBlock) resultPage.getBlock(0)).getLong(j); + assertThat(resultValue, equalTo(inputValue)); + if (seenOne == false && resultValue == 1L) { + BytesRef type = ((BytesRefBlock) resultPage.getBlock(1)).getBytesRef(j, new BytesRef()); + double pvalue = ((DoubleBlock) resultPage.getBlock(2)).getDouble(j); + assertThat(type.utf8ToString(), equalTo("step_change")); + assertThat(pvalue, equalTo(0.0)); + seenOne = true; + } else { + assertThat(resultPage.getBlock(1).isNull(j), equalTo(true)); + assertThat(resultPage.getBlock(2).isNull(j), equalTo(true)); + } + } + } + assertThat(seenOne, equalTo(true)); + } + + @Override + protected Operator.OperatorFactory simple() { + return new ChangePointOperator.Factory(0, null, 0, 0); + } + + @Override + protected Matcher expectedDescriptionOfSimple() { + return equalTo("ChangePointOperator[channel=0]"); + } + + @Override + protected Matcher expectedToStringOfSimple() { + return equalTo("ChangePointOperator[channel=0]"); + } +} diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverSchedulerTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverSchedulerTests.java new file mode 100644 index 000000000000..ec6bf38e557a --- /dev/null +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverSchedulerTests.java @@ -0,0 +1,61 @@ +/* + * 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.compute.operator; + +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.AbstractRunnable; +import org.elasticsearch.common.util.concurrent.EsExecutors; +import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.threadpool.FixedExecutorBuilder; +import org.elasticsearch.threadpool.TestThreadPool; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.hamcrest.Matchers.equalTo; + +public class DriverSchedulerTests extends ESTestCase { + + public void testClearPendingTaskOnRejection() { + DriverScheduler scheduler = new DriverScheduler(); + AtomicInteger counter = new AtomicInteger(); + var threadPool = new TestThreadPool( + "test", + new FixedExecutorBuilder(Settings.EMPTY, "test", 1, 2, "test", EsExecutors.TaskTrackingConfig.DEFAULT) + ); + CountDownLatch latch = new CountDownLatch(1); + Executor executor = threadPool.executor("test"); + try { + for (int i = 0; i < 10; i++) { + try { + executor.execute(() -> safeAwait(latch)); + } catch (EsRejectedExecutionException e) { + break; + } + } + scheduler.scheduleOrRunTask(executor, new AbstractRunnable() { + @Override + public void onFailure(Exception e) { + counter.incrementAndGet(); + } + + @Override + protected void doRun() { + counter.incrementAndGet(); + } + }); + scheduler.runPendingTasks(); + assertThat(counter.get(), equalTo(1)); + } finally { + latch.countDown(); + terminate(threadPool); + } + } +} diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/HashAggregationOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/HashAggregationOperatorTests.java index 953c7d1c313f..30579f864abc 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/HashAggregationOperatorTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/HashAggregationOperatorTests.java @@ -56,8 +56,8 @@ public class HashAggregationOperatorTests extends ForkingOperatorTestCase { List.of(new BlockHash.GroupSpec(0, ElementType.LONG)), mode, List.of( - new SumLongAggregatorFunctionSupplier(sumChannels).groupingAggregatorFactory(mode), - new MaxLongAggregatorFunctionSupplier(maxChannels).groupingAggregatorFactory(mode) + new SumLongAggregatorFunctionSupplier().groupingAggregatorFactory(mode, sumChannels), + new MaxLongAggregatorFunctionSupplier().groupingAggregatorFactory(mode, maxChannels) ), randomPageSize(), null diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/TimeSeriesAggregationOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/TimeSeriesAggregationOperatorTests.java index b960a12e6f90..103a6a35651c 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/TimeSeriesAggregationOperatorTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/TimeSeriesAggregationOperatorTests.java @@ -41,6 +41,7 @@ import java.util.stream.IntStream; import static org.elasticsearch.compute.lucene.TimeSeriesSortedSourceOperatorTests.createTimeSeriesSourceOperator; import static org.elasticsearch.compute.lucene.TimeSeriesSortedSourceOperatorTests.writeTS; +import static org.elasticsearch.compute.operator.TimeSeriesAggregationOperatorFactories.SupplierWithChannels; import static org.hamcrest.Matchers.equalTo; public class TimeSeriesAggregationOperatorTests extends ComputeTestCase { @@ -269,7 +270,7 @@ public class TimeSeriesAggregationOperatorTests extends ComputeTestCase { 1, 3, IntStream.range(0, nonBucketGroupings.size()).mapToObj(n -> new BlockHash.GroupSpec(5 + n, ElementType.BYTES_REF)).toList(), - List.of(new RateLongAggregatorFunctionSupplier(List.of(4, 2), unitInMillis)), + List.of(new SupplierWithChannels(new RateLongAggregatorFunctionSupplier(unitInMillis), List.of(4, 2))), List.of(), between(1, 100) ).get(ctx); @@ -279,7 +280,7 @@ public class TimeSeriesAggregationOperatorTests extends ComputeTestCase { 0, 1, IntStream.range(0, nonBucketGroupings.size()).mapToObj(n -> new BlockHash.GroupSpec(5 + n, ElementType.BYTES_REF)).toList(), - List.of(new RateLongAggregatorFunctionSupplier(List.of(2, 3, 4), unitInMillis)), + List.of(new SupplierWithChannels(new RateLongAggregatorFunctionSupplier(unitInMillis), List.of(2, 3, 4))), List.of(), between(1, 100) ).get(ctx); @@ -295,7 +296,7 @@ public class TimeSeriesAggregationOperatorTests extends ComputeTestCase { } Operator finalAgg = new TimeSeriesAggregationOperatorFactories.Final( finalGroups, - List.of(new SumDoubleAggregatorFunctionSupplier(List.of(2))), + List.of(new SupplierWithChannels(new SumDoubleAggregatorFunctionSupplier(), List.of(2))), List.of(), between(1, 100) ).get(ctx); diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/exchange/ExchangeBufferTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/exchange/ExchangeBufferTests.java index bd5b53fb25c8..7213e0b27aea 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/exchange/ExchangeBufferTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/exchange/ExchangeBufferTests.java @@ -66,6 +66,25 @@ public class ExchangeBufferTests extends ESTestCase { blockFactory.ensureAllBlocksAreReleased(); } + public void testOutstandingPages() throws Exception { + ExchangeBuffer buffer = new ExchangeBuffer(randomIntBetween(1000, 10000)); + var blockFactory = blockFactory(); + Page p1 = randomPage(blockFactory); + Page p2 = randomPage(blockFactory); + buffer.addPage(p1); + buffer.addPage(p2); + buffer.finish(false); + buffer.addPage(randomPage(blockFactory)); + assertThat(buffer.size(), equalTo(2)); + assertSame(buffer.pollPage(), p1); + p1.releaseBlocks(); + assertSame(buffer.pollPage(), p2); + p2.releaseBlocks(); + assertNull(buffer.pollPage()); + assertTrue(buffer.isFinished()); + blockFactory.ensureAllBlocksAreReleased(); + } + private static MockBlockFactory blockFactory() { BigArrays bigArrays = new MockBigArrays(PageCacheRecycler.NON_RECYCLING_INSTANCE, ByteSizeValue.ofGb(1)).withCircuitBreaking(); CircuitBreaker breaker = bigArrays.breakerService().getBreaker(CircuitBreaker.REQUEST); diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/exchange/ExchangeServiceTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/exchange/ExchangeServiceTests.java index 2edf156f92da..2927bc5439af 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/exchange/ExchangeServiceTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/exchange/ExchangeServiceTests.java @@ -7,6 +7,7 @@ package org.elasticsearch.compute.operator.exchange; +import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.TransportVersion; import org.elasticsearch.action.ActionListener; @@ -16,6 +17,7 @@ import org.elasticsearch.cluster.ClusterModule; import org.elasticsearch.cluster.node.VersionInformation; import org.elasticsearch.common.breaker.CircuitBreaker; import org.elasticsearch.common.breaker.CircuitBreakingException; +import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.ByteSizeValue; @@ -23,6 +25,7 @@ import org.elasticsearch.common.util.MockBigArrays; import org.elasticsearch.common.util.PageCacheRecycler; import org.elasticsearch.common.util.concurrent.ConcurrentCollections; import org.elasticsearch.common.util.concurrent.EsExecutors; +import org.elasticsearch.compute.EsqlRefCountingListener; import org.elasticsearch.compute.data.BlockFactory; import org.elasticsearch.compute.data.BlockWritables; import org.elasticsearch.compute.data.IntBlock; @@ -37,6 +40,7 @@ import org.elasticsearch.core.ReleasableRef; import org.elasticsearch.core.TimeValue; import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.TaskCancellationService; +import org.elasticsearch.tasks.TaskCancelledException; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.transport.MockTransportService; import org.elasticsearch.test.transport.StubbableTransport; @@ -69,6 +73,7 @@ import java.util.stream.IntStream; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; public class ExchangeServiceTests extends ESTestCase { @@ -623,14 +628,15 @@ public class ExchangeServiceTests extends ESTestCase { ); ExchangeSinkHandler sinkHandler = exchange1.createSinkHandler(exchangeId, randomIntBetween(1, 128)); Transport.Connection connection = node0.getConnection(node1.getLocalNode()); + PlainActionFuture remoteSinkFuture = new PlainActionFuture<>(); sourceHandler.addRemoteSink( exchange0.newRemoteSink(task, exchangeId, node0, connection), true, () -> {}, randomIntBetween(1, 5), - ActionListener.noop() + remoteSinkFuture ); - Exception err = expectThrows( + Exception driverException = expectThrows( Exception.class, () -> runConcurrentTest( maxSeqNo, @@ -639,7 +645,9 @@ public class ExchangeServiceTests extends ESTestCase { () -> sinkHandler.createExchangeSink(() -> {}) ) ); - Throwable cause = ExceptionsHelper.unwrap(err, IOException.class); + assertThat(driverException, instanceOf(TaskCancelledException.class)); + var sinkException = expectThrows(Exception.class, remoteSinkFuture::actionGet); + Throwable cause = ExceptionsHelper.unwrap(sinkException, IOException.class); assertNotNull(cause); assertThat(cause.getMessage(), equalTo("page is too large")); PlainActionFuture sinkCompletionFuture = new PlainActionFuture<>(); @@ -649,6 +657,28 @@ public class ExchangeServiceTests extends ESTestCase { } } + public void testNoCyclicException() throws Exception { + PlainActionFuture future = new PlainActionFuture<>(); + try (EsqlRefCountingListener refs = new EsqlRefCountingListener(future)) { + var exchangeSourceHandler = new ExchangeSourceHandler(between(10, 100), threadPool.generic(), refs.acquire()); + int numSinks = between(5, 10); + for (int i = 0; i < numSinks; i++) { + RemoteSink remoteSink = (allSourcesFinished, listener) -> threadPool.schedule( + () -> listener.onFailure(new IOException("simulated")), + TimeValue.timeValueMillis(1), + threadPool.generic() + ); + exchangeSourceHandler.addRemoteSink(remoteSink, randomBoolean(), () -> {}, between(1, 3), refs.acquire()); + } + } + Exception err = expectThrows(Exception.class, () -> future.actionGet(10, TimeUnit.SECONDS)); + assertThat(ExceptionsHelper.unwrap(err, IOException.class).getMessage(), equalTo("simulated")); + try (BytesStreamOutput output = new BytesStreamOutput()) { + // ensure no cyclic exception + ElasticsearchException.writeException(err, output); + } + } + private MockTransportService newTransportService() { List namedWriteables = new ArrayList<>(ClusterModule.getNamedWriteables()); namedWriteables.addAll(BlockWritables.getNamedWriteables()); diff --git a/x-pack/plugin/esql/compute/test/src/main/java/org/elasticsearch/compute/test/OperatorTestCase.java b/x-pack/plugin/esql/compute/test/src/main/java/org/elasticsearch/compute/test/OperatorTestCase.java index d9fca11ecdcf..876461cafcf8 100644 --- a/x-pack/plugin/esql/compute/test/src/main/java/org/elasticsearch/compute/test/OperatorTestCase.java +++ b/x-pack/plugin/esql/compute/test/src/main/java/org/elasticsearch/compute/test/OperatorTestCase.java @@ -46,7 +46,6 @@ import java.util.stream.LongStream; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.in; /** * Base tests for {@link Operator}s that are not {@link SourceOperator} or {@link SinkOperator}. @@ -242,16 +241,16 @@ public abstract class OperatorTestCase extends AnyOperatorTestCase { * Tests that finish then close without calling {@link Operator#getOutput} to * retrieve a potential last page, releases all memory. */ - public void testSimpleFinishClose() throws Exception { + public void testSimpleFinishClose() { DriverContext driverContext = driverContext(); List input = CannedSourceOperator.collectPages(simpleInput(driverContext.blockFactory(), 1)); - assert input.size() == 1 : "Expected single page, got: " + input; // eventually, when driverContext always returns a tracking factory, we can enable this assertion // assertThat(driverContext.blockFactory().breaker().getUsed(), greaterThan(0L)); - Page page = input.get(0); try (var operator = simple().get(driverContext)) { assert operator.needsInput(); - operator.addInput(page); + for (Page page : input) { + operator.addInput(page); + } operator.finish(); } } diff --git a/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java b/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java index 790b12346bb1..9623d6071d32 100644 --- a/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java +++ b/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java @@ -70,6 +70,11 @@ public class MixedClusterEsqlSpecIT extends EsqlSpecTestCase { assumeTrue("Test " + testName + " is skipped on " + bwcVersion, isEnabled(testName, instructions, bwcVersion)); } + @Override + protected boolean shouldSkipTestsWithSemanticTextFields() { + return true; + } + @Override protected boolean enableRoundingDoubleValuesOnAsserting() { return true; diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java index 4d06db94801b..84bf34b70372 100644 --- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java +++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java @@ -127,6 +127,11 @@ public class MultiClusterSpecIT extends EsqlSpecTestCase { assumeFalse("LOOKUP JOIN not yet supported in CCS", testCase.requiredCapabilities.contains(JOIN_LOOKUP_V12.capabilityName())); } + @Override + protected boolean shouldSkipTestsWithSemanticTextFields() { + return true; + } + private TestFeatureService remoteFeaturesService() throws IOException { if (remoteFeaturesService == null) { var remoteNodeVersions = readVersionsFromNodesInfo(remoteClusterClient()); diff --git a/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java b/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java index 64c113345bd5..c0e82a455a4f 100644 --- a/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java +++ b/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java @@ -37,4 +37,9 @@ public class EsqlSpecIT extends EsqlSpecTestCase { protected boolean enableRoundingDoubleValuesOnAsserting() { return true; } + + @Override + protected boolean shouldSkipTestsWithSemanticTextFields() { + return true; + } } diff --git a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java index 368eebe808ee..42974795a77d 100644 --- a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java +++ b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java @@ -42,4 +42,9 @@ public class EsqlSpecIT extends EsqlSpecTestCase { // This suite runs with more than one node and three shards in serverless return cluster.getNumNodes() > 1; } + + @Override + protected boolean shouldSkipTestsWithSemanticTextFields() { + return cluster.getNumNodes() > 1; + } } diff --git a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/GenerativeIT.java b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/GenerativeIT.java index 9b98c29f5c3e..d322263ce918 100644 --- a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/GenerativeIT.java +++ b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/GenerativeIT.java @@ -15,7 +15,7 @@ import org.elasticsearch.test.cluster.ElasticsearchCluster; import org.elasticsearch.xpack.esql.qa.rest.generative.GenerativeRestTest; import org.junit.ClassRule; -@AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/102084") +@AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/121754") @ThreadLeakFilters(filters = TestClustersThreadFilter.class) public class GenerativeIT extends GenerativeRestTest { @ClassRule diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java index 5911da032690..d5e4651a847c 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java @@ -70,6 +70,7 @@ import static org.elasticsearch.xpack.esql.CsvTestsDataLoader.createInferenceEnd import static org.elasticsearch.xpack.esql.CsvTestsDataLoader.deleteInferenceEndpoint; import static org.elasticsearch.xpack.esql.CsvTestsDataLoader.loadDataSetIntoEs; import static org.elasticsearch.xpack.esql.EsqlTestUtils.classpathResources; +import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.SEMANTIC_TEXT_TYPE; // This test can run very long in serverless configurations @TimeoutSuite(millis = 30 * TimeUnits.MINUTE) @@ -128,15 +129,22 @@ public abstract class EsqlSpecTestCase extends ESRestTestCase { @Before public void setup() throws IOException { + if (shouldSkipTestsWithSemanticTextFields()) { + assumeFalse("semantic_text tests are muted", testCase.requiredCapabilities.contains(SEMANTIC_TEXT_TYPE.capabilityName())); + } if (supportsInferenceTestService() && clusterHasInferenceEndpoint(client()) == false) { createInferenceEndpoint(client()); } - if (indexExists(availableDatasetsForEs(client(), supportsIndexModeLookup()).iterator().next().indexName()) == false) { loadDataSetIntoEs(client(), supportsIndexModeLookup()); } } + // https://github.com/elastic/elasticsearch/issues/121411 + protected boolean shouldSkipTestsWithSemanticTextFields() { + return false; + } + @AfterClass public static void wipeTestData() throws IOException { try { @@ -172,6 +180,9 @@ public abstract class EsqlSpecTestCase extends ESRestTestCase { } checkCapabilities(adminClient(), testFeatureService, testName, testCase); assumeTrue("Test " + testName + " is not enabled", isEnabled(testName, instructions, Version.CURRENT)); + if (shouldSkipTestsWithSemanticTextFields()) { + assumeFalse("semantic_text tests are muted", testCase.requiredCapabilities.contains(SEMANTIC_TEXT_TYPE.capabilityName())); + } } protected static void checkCapabilities(RestClient client, TestFeatureService testFeatureService, String testName, CsvTestCase testCase) diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java index 88fc8a9a3631..dc979806370f 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java @@ -33,7 +33,6 @@ import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.esql.AssertWarnings; import org.elasticsearch.xpack.esql.EsqlTestUtils; -import org.elasticsearch.xpack.esql.action.EsqlCapabilities; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -660,10 +659,6 @@ public abstract class RestEsqlTestCase extends ESRestTestCase { } public void testNamedParamsForIdentifierAndIdentifierPatterns() throws IOException { - assumeTrue( - "named parameters for identifiers and patterns require snapshot build", - EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - ); bulkLoadTestData(10); // positive var query = requestObjectBuilder().query( diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/EsqlQueryGenerator.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/EsqlQueryGenerator.java index 844ccd3802bf..5bf13d2d9c76 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/EsqlQueryGenerator.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/EsqlQueryGenerator.java @@ -28,10 +28,13 @@ public class EsqlQueryGenerator { public record QueryExecuted(String query, int depth, List outputSchema, Exception exception) {} public static String sourceCommand(List availabeIndices) { - return switch (randomIntBetween(0, 2)) { + return switch (randomIntBetween(0, 1)) { case 0 -> from(availabeIndices); - case 1 -> metaFunctions(); - default -> row(); + // case 1 -> metaFunctions(); + default -> from(availabeIndices); + // TODO re-enable ROW. + // now it crashes nodes in some cases: exiting java.lang.AssertionError: estimated row size [0] wasn't set + // default -> row(); }; } @@ -41,8 +44,12 @@ public class EsqlQueryGenerator { * @param policies * @return a new command that can process it as input */ - public static String pipeCommand(List previousOutput, List policies) { - return switch (randomIntBetween(0, 11)) { + public static String pipeCommand( + List previousOutput, + List policies, + List lookupIndices + ) { + return switch (randomIntBetween(0, 12)) { case 0 -> dissect(previousOutput); case 1 -> drop(previousOutput); case 2 -> enrich(previousOutput, policies); @@ -54,10 +61,26 @@ public class EsqlQueryGenerator { case 8 -> rename(previousOutput); case 9 -> sort(previousOutput); case 10 -> stats(previousOutput); + case 11 -> join(previousOutput, lookupIndices); default -> where(previousOutput); }; } + private static String join(List previousOutput, List lookupIndices) { + + GenerativeRestTest.LookupIdx lookupIdx = randomFrom(lookupIndices); + String lookupIdxName = lookupIdx.idxName(); + String idxKey = lookupIdx.key(); + String keyType = lookupIdx.keyType(); + + var candidateKeys = previousOutput.stream().filter(x -> x.type.equals(keyType)).toList(); + if (candidateKeys.isEmpty()) { + return ""; + } + Column key = randomFrom(candidateKeys); + return "| rename " + key.name + " as " + idxKey + " | lookup join " + lookupIdxName + " on " + idxKey; + } + private static String where(List previousOutput) { // TODO more complex conditions StringBuilder result = new StringBuilder(" | where "); @@ -191,7 +214,53 @@ public class EsqlQueryGenerator { } private static String randomName(List previousOutput) { - return previousOutput.get(randomIntBetween(0, previousOutput.size() - 1)).name(); + // we need to exclude + // https://github.com/elastic/elasticsearch/issues/121741 + return randomFrom(previousOutput.stream().filter(x -> x.name().equals("") == false).toList()).name(); + } + + private static String randomGroupableName(List previousOutput) { + // we need to exclude + // https://github.com/elastic/elasticsearch/issues/121741 + var candidates = previousOutput.stream() + .filter(EsqlQueryGenerator::groupable) + .filter(x -> x.name().equals("") == false) + .toList(); + if (candidates.isEmpty()) { + return null; + } + return randomFrom(candidates).name(); + } + + private static boolean groupable(Column col) { + return col.type.equals("keyword") + || col.type.equals("text") + || col.type.equals("long") + || col.type.equals("integer") + || col.type.equals("ip") + || col.type.equals("version"); + } + + private static String randomSortableName(List previousOutput) { + // we need to exclude + // https://github.com/elastic/elasticsearch/issues/121741 + var candidates = previousOutput.stream() + .filter(EsqlQueryGenerator::sortable) + .filter(x -> x.name().equals("") == false) + .toList(); + if (candidates.isEmpty()) { + return null; + } + return randomFrom(candidates).name(); + } + + private static boolean sortable(Column col) { + return col.type.equals("keyword") + || col.type.equals("text") + || col.type.equals("long") + || col.type.equals("integer") + || col.type.equals("ip") + || col.type.equals("version"); } private static String rename(List previousOutput) { @@ -199,7 +268,12 @@ public class EsqlQueryGenerator { List proj = new ArrayList<>(); List names = new ArrayList<>(previousOutput.stream().map(Column::name).collect(Collectors.toList())); for (int i = 0; i < n; i++) { - String name = names.remove(randomIntBetween(0, names.size() - 1)); + var colN = randomIntBetween(0, names.size() - 1); + if (previousOutput.get(colN).type().endsWith("_range")) { + // ranges are not fully supported yet + continue; + } + String name = names.remove(colN); String newName; if (names.isEmpty() || randomBoolean()) { newName = randomAlphaOfLength(5); @@ -209,6 +283,9 @@ public class EsqlQueryGenerator { names.add(newName); proj.add(name + " AS " + newName); } + if (proj.isEmpty()) { + return ""; + } return " | rename " + proj.stream().collect(Collectors.joining(", ")); } @@ -227,7 +304,7 @@ public class EsqlQueryGenerator { name = "*" + name.substring(randomIntBetween(1, name.length() - 1)); } } - proj.add(name); + proj.add(name.contains("*") ? name : "`" + name + "`"); } return " | drop " + proj.stream().collect(Collectors.joining(", ")); } @@ -236,7 +313,11 @@ public class EsqlQueryGenerator { int n = randomIntBetween(1, previousOutput.size()); Set proj = new HashSet<>(); for (int i = 0; i < n; i++) { - proj.add(randomName(previousOutput)); + String col = randomSortableName(previousOutput); + if (col == null) { + return "";// no sortable columns + } + proj.add(col); } return " | sort " + proj.stream() @@ -295,9 +376,10 @@ public class EsqlQueryGenerator { cmd.append(expression); } if (randomBoolean()) { - cmd.append(" by "); - - cmd.append(randomName(nonNull)); + var col = randomGroupableName(nonNull); + if (col != null) { + cmd.append(" by " + col); + } } return cmd.toString(); } diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java index 588d5870d89e..a841c2fc9995 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java @@ -35,7 +35,18 @@ public abstract class GenerativeRestTest extends ESRestTestCase { public static final Set ALLOWED_ERRORS = Set.of( "Reference \\[.*\\] is ambiguous", "Cannot use field \\[.*\\] due to ambiguities", - "cannot sort on .*" + "cannot sort on .*", + "argument of \\[count_distinct\\(.*\\)\\] must", + "Cannot use field \\[.*\\] with unsupported type \\[.*_range\\]", + // warnings + "Field '.*' shadowed by field at line .*", + "evaluation of \\[.*\\] failed, treating result as null", // TODO investigate? + // Awaiting fixes + "estimated row size \\[0\\] wasn't set", // https://github.com/elastic/elasticsearch/issues/121739 + "unknown physical plan node \\[OrderExec\\]", // https://github.com/elastic/elasticsearch/issues/120817 + "Unknown column \\[\\]", // https://github.com/elastic/elasticsearch/issues/121741 + // + "The incoming YAML document exceeds the limit:" // still to investigate, but it seems to be specific to the test framework ); public static final Set ALLOWED_ERROR_PATTERNS = ALLOWED_ERRORS.stream() @@ -64,6 +75,7 @@ public abstract class GenerativeRestTest extends ESRestTestCase { public void test() { List indices = availableIndices(); + List lookupIndices = lookupIndices(); List policies = availableEnrichPolicies(); for (int i = 0; i < ITERATIONS; i++) { String command = EsqlQueryGenerator.sourceCommand(indices); @@ -76,7 +88,7 @@ public abstract class GenerativeRestTest extends ESRestTestCase { if (result.outputSchema().isEmpty()) { break; } - command = EsqlQueryGenerator.pipeCommand(result.outputSchema(), policies); + command = EsqlQueryGenerator.pipeCommand(result.outputSchema(), policies, lookupIndices); result = execute(result.query() + command, result.depth() + 1); if (result.exception() != null) { checkException(result); @@ -102,6 +114,9 @@ public abstract class GenerativeRestTest extends ESRestTestCase { return new EsqlQueryGenerator.QueryExecuted(command, depth, outputSchema, null); } catch (Exception e) { return new EsqlQueryGenerator.QueryExecuted(command, depth, null, e); + } catch (AssertionError ae) { + // this is for ensureNoWarnings() + return new EsqlQueryGenerator.QueryExecuted(command, depth, null, new RuntimeException(ae.getMessage())); } } @@ -116,7 +131,23 @@ public abstract class GenerativeRestTest extends ESRestTestCase { } private List availableIndices() { - return new ArrayList<>(CSV_DATASET_MAP.keySet()); + return new ArrayList<>( + CSV_DATASET_MAP.entrySet() + .stream() + .filter(x -> x.getValue().requiresInferenceEndpoint() == false) + .map(Map.Entry::getKey) + .toList() + ); + } + + record LookupIdx(String idxName, String key, String keyType) {} + + private List lookupIndices() { + List result = new ArrayList<>(); + // we don't have key info from the dataset loader, let's hardcode it for now + result.add(new LookupIdx("languages_lookup", "language_code", "integer")); + result.add(new LookupIdx("message_types_lookup", "message", "keyword")); + return result; } List availableEnrichPolicies() { diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/change_point.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/change_point.csv-spec new file mode 100644 index 000000000000..64269e0d2849 --- /dev/null +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/change_point.csv-spec @@ -0,0 +1,1200 @@ +detect nothing (long) +required_capability: change_point + +FROM k8s + | STATS count=COUNT() BY @timestamp=BUCKET(@timestamp, 1 MINUTE) + | CHANGE_POINT count ON @timestamp AS type, pvalue +; + +count:long | @timestamp:datetime | type:keyword | pvalue:double +4 | 2024-05-10T00:00:00.000Z | null | null +4 | 2024-05-10T00:01:00.000Z | null | null +8 | 2024-05-10T00:02:00.000Z | null | null +8 | 2024-05-10T00:03:00.000Z | null | null +5 | 2024-05-10T00:04:00.000Z | null | null +8 | 2024-05-10T00:05:00.000Z | null | null +10 | 2024-05-10T00:06:00.000Z | null | null +5 | 2024-05-10T00:07:00.000Z | null | null +12 | 2024-05-10T00:08:00.000Z | null | null +20 | 2024-05-10T00:09:00.000Z | null | null +5 | 2024-05-10T00:10:00.000Z | null | null +7 | 2024-05-10T00:11:00.000Z | null | null +8 | 2024-05-10T00:12:00.000Z | null | null +9 | 2024-05-10T00:13:00.000Z | null | null +9 | 2024-05-10T00:14:00.000Z | null | null +11 | 2024-05-10T00:15:00.000Z | null | null +7 | 2024-05-10T00:16:00.000Z | null | null +15 | 2024-05-10T00:17:00.000Z | null | null +17 | 2024-05-10T00:18:00.000Z | null | null +5 | 2024-05-10T00:19:00.000Z | null | null +10 | 2024-05-10T00:20:00.000Z | null | null +4 | 2024-05-10T00:21:00.000Z | null | null +9 | 2024-05-10T00:22:00.000Z | null | null +; + + +detect spike (long; default output columns) +required_capability: change_point + +FROM k8s + | STATS count=COUNT() BY @timestamp=BUCKET(@timestamp, 1 MINUTE) + | EVAL count=count+CASE(@timestamp=="2024-05-10T00:08:00.000Z", 100, 0) + | CHANGE_POINT count ON @timestamp +; + +@timestamp:datetime | count:long | type:keyword | pvalue:double +2024-05-10T00:00:00.000Z | 4 | null | null +2024-05-10T00:01:00.000Z | 4 | null | null +2024-05-10T00:02:00.000Z | 8 | null | null +2024-05-10T00:03:00.000Z | 8 | null | null +2024-05-10T00:04:00.000Z | 5 | null | null +2024-05-10T00:05:00.000Z | 8 | null | null +2024-05-10T00:06:00.000Z | 10 | null | null +2024-05-10T00:07:00.000Z | 5 | null | null +2024-05-10T00:08:00.000Z | 112 | spike | 1.7502597878858522E-193 +2024-05-10T00:09:00.000Z | 20 | null | null +2024-05-10T00:10:00.000Z | 5 | null | null +2024-05-10T00:11:00.000Z | 7 | null | null +2024-05-10T00:12:00.000Z | 8 | null | null +2024-05-10T00:13:00.000Z | 9 | null | null +2024-05-10T00:14:00.000Z | 9 | null | null +2024-05-10T00:15:00.000Z | 11 | null | null +2024-05-10T00:16:00.000Z | 7 | null | null +2024-05-10T00:17:00.000Z | 15 | null | null +2024-05-10T00:18:00.000Z | 17 | null | null +2024-05-10T00:19:00.000Z | 5 | null | null +2024-05-10T00:20:00.000Z | 10 | null | null +2024-05-10T00:21:00.000Z | 4 | null | null +2024-05-10T00:22:00.000Z | 9 | null | null +; + + +detect step change (long; default timestamp) +required_capability: change_point + +FROM k8s + | STATS count=COUNT() BY @timestamp=BUCKET(@timestamp, 1 MINUTE) + | EVAL count=count+CASE(@timestamp>="2024-05-10T00:11:00.000Z", 100, 0) + | CHANGE_POINT count AS type, pvalue +; + +@timestamp:datetime | count:long | type:keyword | pvalue:double +2024-05-10T00:00:00.000Z | 4 | null | null +2024-05-10T00:01:00.000Z | 4 | null | null +2024-05-10T00:02:00.000Z | 8 | null | null +2024-05-10T00:03:00.000Z | 8 | null | null +2024-05-10T00:04:00.000Z | 5 | null | null +2024-05-10T00:05:00.000Z | 8 | null | null +2024-05-10T00:06:00.000Z | 10 | null | null +2024-05-10T00:07:00.000Z | 5 | null | null +2024-05-10T00:08:00.000Z | 12 | null | null +2024-05-10T00:09:00.000Z | 20 | null | null +2024-05-10T00:10:00.000Z | 5 | null | null +2024-05-10T00:11:00.000Z | 107 | step_change | 3.0924162021968114E-23 +2024-05-10T00:12:00.000Z | 108 | null | null +2024-05-10T00:13:00.000Z | 109 | null | null +2024-05-10T00:14:00.000Z | 109 | null | null +2024-05-10T00:15:00.000Z | 111 | null | null +2024-05-10T00:16:00.000Z | 107 | null | null +2024-05-10T00:17:00.000Z | 115 | null | null +2024-05-10T00:18:00.000Z | 117 | null | null +2024-05-10T00:19:00.000Z | 105 | null | null +2024-05-10T00:20:00.000Z | 110 | null | null +2024-05-10T00:21:00.000Z | 104 | null | null +2024-05-10T00:22:00.000Z | 109 | null | null +; + + +detect dip (double) +required_capability: change_point + +FROM employees + | STATS salary=AVG(salary) BY height + | EVAL salary=CASE(height==2.1, 0.0, salary) + | CHANGE_POINT salary ON height AS type, pvalue +; + +height:double | salary:double | type:keyword | pvalue:double +1.41 | 40031.0 | null | null +1.42 | 34142.5 | null | null +1.44 | 40266.0 | null | null +1.45 | 49095.0 | null | null +1.46 | 39878.0 | null | null +1.47 | 60408.0 | null | null +1.48 | 44307.0 | null | null +1.5 | 31120.0 | null | null +1.51 | 28035.0 | null | null +1.52 | 41243.5 | null | null +1.53 | 60079.333333333336 | null | null +1.54 | 61358.0 | null | null +1.55 | 36876.5 | null | null +1.56 | 60335.0 | null | null +1.57 | 38486.0 | null | null +1.58 | 41701.5 | null | null +1.59 | 36575.666666666664 | null | null +1.61 | 55299.5 | null | null +1.63 | 70011.0 | null | null +1.64 | 38992.0 | null | null +1.66 | 28946.0 | null | null +1.68 | 42155.5 | null | null +1.69 | 45656.0 | null | null +1.7 | 65092.25 | null | null +1.74 | 53178.0 | null | null +1.75 | 43429.0 | null | null +1.77 | 54184.25 | null | null +1.78 | 44147.5 | null | null +1.79 | 55360.0 | null | null +1.8 | 52833.0 | null | null +1.81 | 56475.666666666664 | null | null +1.82 | 56039.333333333336 | null | null +1.83 | 54195.333333333336 | null | null +1.85 | 66174.0 | null | null +1.87 | 47411.0 | null | null +1.89 | 58121.0 | null | null +1.9 | 37112.0 | null | null +1.91 | 39638.0 | null | null +1.92 | 67492.0 | null | null +1.93 | 33956.0 | null | null +1.94 | 48193.333333333336 | null | null +1.96 | 43026.0 | null | null +1.97 | 52851.0 | null | null +1.99 | 56068.0 | null | null +2.0 | 36314.666666666664 | null | null +2.01 | 35742.0 | null | null +2.03 | 51130.5 | null | null +2.04 | 49281.0 | null | null +2.05 | 63528.0 | null | null +2.06 | 56722.5 | null | null +2.07 | 39984.0 | null | null +2.08 | 60523.0 | null | null +2.09 | 38645.0 | null | null +2.1 | 0.0 | dip | 9.590143836835097E-6 +; + + +no stats command +required_capability: change_point + +FROM employees + | KEEP emp_no, salary + | CHANGE_POINT salary ON emp_no AS type, pvalue +; + +emp_no:integer | salary:integer | type:keyword | pvalue:double +10001 | 57305 | null | null +10002 | 56371 | null | null +10003 | 61805 | null | null +10004 | 36174 | null | null +10005 | 63528 | null | null +10006 | 60335 | null | null +10007 | 74572 | null | null +10008 | 43906 | null | null +10009 | 66174 | null | null +10010 | 45797 | null | null +10011 | 31120 | null | null +10012 | 48942 | null | null +10013 | 48735 | null | null +10014 | 37137 | null | null +10015 | 25324 | null | null +10016 | 61358 | null | null +10017 | 58715 | null | null +10018 | 56760 | null | null +10019 | 73717 | null | null +10020 | 40031 | null | null +10021 | 60408 | null | null +10022 | 48233 | null | null +10023 | 47896 | null | null +10024 | 64675 | null | null +10025 | 47411 | null | null +10026 | 28336 | null | null +10027 | 73851 | null | null +10028 | 39356 | null | null +10029 | 74999 | null | null +10030 | 67492 | null | null +10031 | 37716 | null | null +10032 | 62233 | null | null +10033 | 70011 | null | null +10034 | 39878 | null | null +10035 | 25945 | null | null +10036 | 60781 | null | null +10037 | 37691 | null | null +10038 | 35222 | null | null +10039 | 36051 | null | null +10040 | 37112 | null | null +10041 | 56415 | null | null +10042 | 30404 | null | null +10043 | 34341 | null | null +10044 | 39728 | null | null +10045 | 74970 | null | null +10046 | 50064 | null | null +10047 | 42716 | null | null +10048 | 26436 | null | null +10049 | 37853 | null | null +10050 | 43026 | null | null +10051 | 58121 | null | null +10052 | 55360 | null | null +10053 | 54462 | null | null +10054 | 65367 | null | null +10055 | 49281 | null | null +10056 | 33370 | null | null +10057 | 27215 | null | null +10058 | 38376 | null | null +10059 | 44307 | null | null +10060 | 29175 | null | null +10061 | 49095 | null | null +10062 | 65030 | null | null +10063 | 52121 | null | null +10064 | 33956 | null | null +10065 | 50249 | null | null +10066 | 31897 | null | null +10067 | 52044 | null | null +10068 | 28941 | null | null +10069 | 41933 | null | null +10070 | 54329 | null | null +10071 | 40612 | null | null +10072 | 54518 | null | null +10073 | 32568 | null | null +10074 | 38992 | null | null +10075 | 51956 | null | null +10076 | 62405 | null | null +10077 | 46595 | null | null +10078 | 69904 | null | null +10079 | 32263 | null | null +10080 | 52833 | null | null +10081 | 50128 | null | null +10082 | 49818 | null | null +10083 | 39110 | null | null +10084 | 28035 | null | null +10085 | 35742 | null | null +10086 | 68547 | null | null +10087 | 32272 | null | null +10088 | 39638 | null | null +10089 | 43602 | null | null +10090 | 44956 | null | null +10091 | 38645 | null | null +10092 | 25976 | null | null +10093 | 45656 | null | null +10094 | 66817 | null | null +10095 | 37702 | null | null +10096 | 43889 | null | null +10097 | 71165 | null | null +10098 | 44817 | null | null +10099 | 73578 | null | null +10100 | 68431 | null | null +; + + +where before change point +required_capability: change_point + +FROM employees + | KEEP emp_no, salary + | EVAL salary = CASE(emp_no==10022, 100000, salary) + | EVAL salary = CASE(emp_no==10033, 1000000, salary) + | WHERE emp_no < 10025 + | CHANGE_POINT salary ON emp_no AS type, pvalue +; + +emp_no:integer | salary:integer | type:keyword | pvalue:double +10001 | 57305 | null | null +10002 | 56371 | null | null +10003 | 61805 | null | null +10004 | 36174 | null | null +10005 | 63528 | null | null +10006 | 60335 | null | null +10007 | 74572 | null | null +10008 | 43906 | null | null +10009 | 66174 | null | null +10010 | 45797 | null | null +10011 | 31120 | null | null +10012 | 48942 | null | null +10013 | 48735 | null | null +10014 | 37137 | null | null +10015 | 25324 | null | null +10016 | 61358 | null | null +10017 | 58715 | null | null +10018 | 56760 | null | null +10019 | 73717 | null | null +10020 | 40031 | null | null +10021 | 60408 | null | null +10022 | 100000 | spike | 0.0019710754505321004 +10023 | 47896 | null | null +10024 | 64675 | null | null +; + + +where after change point +required_capability: change_point + +FROM employees + | KEEP emp_no, salary + | EVAL salary = CASE(emp_no==10022, 100000, salary) + | EVAL salary = CASE(emp_no==10033, 1000000, salary) + | CHANGE_POINT salary ON emp_no AS type, pvalue + | WHERE emp_no < 10025 +; + +emp_no:integer | salary:integer | type:keyword | pvalue:double +10001 | 57305 | null | null +10002 | 56371 | null | null +10003 | 61805 | null | null +10004 | 36174 | null | null +10005 | 63528 | null | null +10006 | 60335 | null | null +10007 | 74572 | null | null +10008 | 43906 | null | null +10009 | 66174 | null | null +10010 | 45797 | null | null +10011 | 31120 | null | null +10012 | 48942 | null | null +10013 | 48735 | null | null +10014 | 37137 | null | null +10015 | 25324 | null | null +10016 | 61358 | null | null +10017 | 58715 | null | null +10018 | 56760 | null | null +10019 | 73717 | null | null +10020 | 40031 | null | null +10021 | 60408 | null | null +10022 | 100000 | null | null +10023 | 47896 | null | null +10024 | 64675 | null | null +; + + +where with shadowing +required_capability: change_point + +FROM employees + | KEEP emp_no, salary + | EVAL salary=CASE(emp_no==10015, -1000000, salary) + | WHERE emp_no < 10025 + | CHANGE_POINT salary ON emp_no AS type, emp_no + | WHERE emp_no IS NOT NULL + | RENAME emp_no AS pvalue +; + +salary:integer | type:keyword | pvalue:double +-1000000 | dip | 0.0 +; + + +stats after change point +required_capability: change_point + +FROM employees + | KEEP emp_no, salary + | EVAL salary=CASE(emp_no==10042, 1000000, salary) + | CHANGE_POINT salary ON emp_no + | STATS COUNT() by type + | SORT type +; + +COUNT():long | type:keyword +1 | spike +99 | null +; + + +sort/limit before change point +required_capability: change_point + +FROM k8s + | STATS count=COUNT() BY @timestamp=BUCKET(@timestamp, 1 MINUTE) + | SORT count, @timestamp + | LIMIT 22 + | CHANGE_POINT count AS type, pvalue +; + +count:long | @timestamp:datetime | type:keyword | pvalue:double +4 | 2024-05-10T00:00:00.000Z | null | null +4 | 2024-05-10T00:01:00.000Z | null | null +8 | 2024-05-10T00:02:00.000Z | null | null +8 | 2024-05-10T00:03:00.000Z | null | null +5 | 2024-05-10T00:04:00.000Z | null | null +8 | 2024-05-10T00:05:00.000Z | null | null +10 | 2024-05-10T00:06:00.000Z | null | null +5 | 2024-05-10T00:07:00.000Z | null | null +12 | 2024-05-10T00:08:00.000Z | null | null +5 | 2024-05-10T00:10:00.000Z | null | null +7 | 2024-05-10T00:11:00.000Z | null | null +8 | 2024-05-10T00:12:00.000Z | null | null +9 | 2024-05-10T00:13:00.000Z | null | null +9 | 2024-05-10T00:14:00.000Z | null | null +11 | 2024-05-10T00:15:00.000Z | null | null +7 | 2024-05-10T00:16:00.000Z | null | null +15 | 2024-05-10T00:17:00.000Z | null | null +17 | 2024-05-10T00:18:00.000Z | null | null +5 | 2024-05-10T00:19:00.000Z | null | null +10 | 2024-05-10T00:20:00.000Z | null | null +4 | 2024-05-10T00:21:00.000Z | null | null +9 | 2024-05-10T00:22:00.000Z | null | null +; + + +sort after change point +required_capability: change_point + +FROM k8s + | STATS count=COUNT() BY @timestamp=BUCKET(@timestamp, 1 MINUTE) + | EVAL count=count+CASE(@timestamp>="2024-05-10T00:11:00.000Z", 100, 0) + | CHANGE_POINT count AS type, pvalue + | SORT type, count, @timestamp +; + +@timestamp:datetime | count:long | type:keyword | pvalue:double +2024-05-10T00:11:00.000Z | 107 | step_change | 3.0924162021968114E-23 +2024-05-10T00:00:00.000Z | 4 | null | null +2024-05-10T00:01:00.000Z | 4 | null | null +2024-05-10T00:04:00.000Z | 5 | null | null +2024-05-10T00:07:00.000Z | 5 | null | null +2024-05-10T00:10:00.000Z | 5 | null | null +2024-05-10T00:02:00.000Z | 8 | null | null +2024-05-10T00:03:00.000Z | 8 | null | null +2024-05-10T00:05:00.000Z | 8 | null | null +2024-05-10T00:06:00.000Z | 10 | null | null +2024-05-10T00:08:00.000Z | 12 | null | null +2024-05-10T00:09:00.000Z | 20 | null | null +2024-05-10T00:21:00.000Z | 104 | null | null +2024-05-10T00:19:00.000Z | 105 | null | null +2024-05-10T00:16:00.000Z | 107 | null | null +2024-05-10T00:12:00.000Z | 108 | null | null +2024-05-10T00:13:00.000Z | 109 | null | null +2024-05-10T00:14:00.000Z | 109 | null | null +2024-05-10T00:22:00.000Z | 109 | null | null +2024-05-10T00:20:00.000Z | 110 | null | null +2024-05-10T00:15:00.000Z | 111 | null | null +2024-05-10T00:17:00.000Z | 115 | null | null +2024-05-10T00:18:00.000Z | 117 | null | null +; + + +reuse input column names +required_capability: change_point + +FROM k8s + | STATS count=COUNT() BY @timestamp=BUCKET(@timestamp, 1 MINUTE) + | EVAL count=count+CASE(@timestamp=="2024-05-10T00:08:00.000Z", 100, 0) + | CHANGE_POINT count ON @timestamp AS @timestamp, count +; + +@timestamp:keyword | count:double +null | null +null | null +null | null +null | null +null | null +null | null +null | null +null | null +spike | 1.7502597878858522E-193 +null | null +null | null +null | null +null | null +null | null +null | null +null | null +null | null +null | null +null | null +null | null +null | null +null | null +null | null +; + + +reuse value column name twice +required_capability: change_point + +FROM k8s + | STATS count=COUNT() BY @timestamp=BUCKET(@timestamp, 1 MINUTE) + | EVAL count=count+CASE(@timestamp=="2024-05-10T00:08:00.000Z", 100, 0) + | CHANGE_POINT count ON @timestamp AS count, count +; + +@timestamp:datetime | count:double +2024-05-10T00:00:00.000Z | null +2024-05-10T00:01:00.000Z | null +2024-05-10T00:02:00.000Z | null +2024-05-10T00:03:00.000Z | null +2024-05-10T00:04:00.000Z | null +2024-05-10T00:05:00.000Z | null +2024-05-10T00:06:00.000Z | null +2024-05-10T00:07:00.000Z | null +2024-05-10T00:08:00.000Z | 1.7502597878858522E-193 +2024-05-10T00:09:00.000Z | null +2024-05-10T00:10:00.000Z | null +2024-05-10T00:11:00.000Z | null +2024-05-10T00:12:00.000Z | null +2024-05-10T00:13:00.000Z | null +2024-05-10T00:14:00.000Z | null +2024-05-10T00:15:00.000Z | null +2024-05-10T00:16:00.000Z | null +2024-05-10T00:17:00.000Z | null +2024-05-10T00:18:00.000Z | null +2024-05-10T00:19:00.000Z | null +2024-05-10T00:20:00.000Z | null +2024-05-10T00:21:00.000Z | null +2024-05-10T00:22:00.000Z | null +; + + +same key and value column +required_capability: change_point + +FROM k8s + | STATS count=COUNT() BY BUCKET(@timestamp, 1 MINUTE) + | KEEP count + | CHANGE_POINT count ON count AS type, pvalue +; + +count:long | type:keyword | pvalue:double +4 | null | null +4 | null | null +4 | null | null +5 | null | null +5 | null | null +5 | null | null +5 | null | null +7 | null | null +7 | null | null +8 | null | null +8 | null | null +8 | null | null +8 | trend_change | 3.793633808495355E-12 +9 | null | null +9 | null | null +9 | null | null +10 | null | null +10 | null | null +11 | null | null +12 | null | null +15 | null | null +17 | null | null +20 | null | null +; + + +all four columns the same +required_capability: change_point + +FROM k8s + | STATS count=COUNT() BY BUCKET(@timestamp, 1 MINUTE) + | KEEP count + | CHANGE_POINT count ON count AS count, count +; + +count:double +null +null +null +null +null +null +null +null +null +null +null +null +3.793633808495355E-12 +null +null +null +null +null +null +null +null +null +null +; + + +rename columns +required_capability: change_point + +FROM k8s + | STATS count=COUNT() BY @timestamp=BUCKET(@timestamp, 1 MINUTE) + | EVAL count=count+CASE(@timestamp=="2024-05-10T00:08:00.000Z", 100, 0) + | RENAME count AS count2, @timestamp AS time2 + | CHANGE_POINT count2 ON time2 AS type, pvalue + | RENAME time2 AS time, count2 AS cnt, type AS kind, pvalue AS significance +; + +time:datetime | cnt:long | kind:keyword | significance:double +2024-05-10T00:00:00.000Z | 4 | null | null +2024-05-10T00:01:00.000Z | 4 | null | null +2024-05-10T00:02:00.000Z | 8 | null | null +2024-05-10T00:03:00.000Z | 8 | null | null +2024-05-10T00:04:00.000Z | 5 | null | null +2024-05-10T00:05:00.000Z | 8 | null | null +2024-05-10T00:06:00.000Z | 10 | null | null +2024-05-10T00:07:00.000Z | 5 | null | null +2024-05-10T00:08:00.000Z | 112 | spike | 1.7502597878858522E-193 +2024-05-10T00:09:00.000Z | 20 | null | null +2024-05-10T00:10:00.000Z | 5 | null | null +2024-05-10T00:11:00.000Z | 7 | null | null +2024-05-10T00:12:00.000Z | 8 | null | null +2024-05-10T00:13:00.000Z | 9 | null | null +2024-05-10T00:14:00.000Z | 9 | null | null +2024-05-10T00:15:00.000Z | 11 | null | null +2024-05-10T00:16:00.000Z | 7 | null | null +2024-05-10T00:17:00.000Z | 15 | null | null +2024-05-10T00:18:00.000Z | 17 | null | null +2024-05-10T00:19:00.000Z | 5 | null | null +2024-05-10T00:20:00.000Z | 10 | null | null +2024-05-10T00:21:00.000Z | 4 | null | null +2024-05-10T00:22:00.000Z | 9 | null | null +; + + +null keys +required_capability: change_point + +FROM k8s + | STATS count=COUNT() BY @timestamp=BUCKET(@timestamp, 1 MINUTE) + | EVAL @timestamp=CASE(@timestamp=="2024-05-10T00:04:00.000Z", NULL, @timestamp) + | EVAL @timestamp=CASE(@timestamp=="2024-05-10T00:08:00.000Z", NULL, @timestamp) + | EVAL count=count+CASE(@timestamp<="2024-05-10T00:11:00.000Z", 100, 0) + | CHANGE_POINT count ON @timestamp AS type, pvalue + | SORT @timestamp, count +; + +@timestamp:datetime | count:long | type:keyword | pvalue:double +2024-05-10T00:00:00.000Z | 104 | null | null +2024-05-10T00:01:00.000Z | 104 | null | null +2024-05-10T00:02:00.000Z | 108 | null | null +2024-05-10T00:03:00.000Z | 108 | null | null +2024-05-10T00:05:00.000Z | 108 | null | null +2024-05-10T00:06:00.000Z | 110 | null | null +2024-05-10T00:07:00.000Z | 105 | null | null +2024-05-10T00:09:00.000Z | 120 | null | null +2024-05-10T00:10:00.000Z | 105 | null | null +2024-05-10T00:11:00.000Z | 107 | null | null +2024-05-10T00:12:00.000Z | 8 | step_change | 9.678892139828202E-24 +2024-05-10T00:13:00.000Z | 9 | null | null +2024-05-10T00:14:00.000Z | 9 | null | null +2024-05-10T00:15:00.000Z | 11 | null | null +2024-05-10T00:16:00.000Z | 7 | null | null +2024-05-10T00:17:00.000Z | 15 | null | null +2024-05-10T00:18:00.000Z | 17 | null | null +2024-05-10T00:19:00.000Z | 5 | null | null +2024-05-10T00:20:00.000Z | 10 | null | null +2024-05-10T00:21:00.000Z | 4 | null | null +2024-05-10T00:22:00.000Z | 9 | null | null +null | 5 | null | null +null | 12 | null | null +; + +null values +required_capability: change_point + +FROM k8s + | STATS count=COUNT() BY @timestamp=BUCKET(@timestamp, 1 MINUTE) + | EVAL count=count+CASE(@timestamp>="2024-05-10T00:11:00.000Z", 100, 0) + | EVAL count=CASE(@timestamp=="2024-05-10T00:04:00.000Z", NULL, count) + | CHANGE_POINT count ON @timestamp AS type, pvalue +; + +warning:Line 5:3: warnings during evaluation of [CHANGE_POINT count ON @timestamp AS type, pvalue]. Only first 20 failures recorded. +warning:Line 5:3: java.lang.IllegalArgumentException: values contain nulls; skipping them + +@timestamp:datetime | count:long | type:keyword | pvalue:double +2024-05-10T00:00:00.000Z | 4 | null | null +2024-05-10T00:01:00.000Z | 4 | null | null +2024-05-10T00:02:00.000Z | 8 | null | null +2024-05-10T00:03:00.000Z | 8 | null | null +2024-05-10T00:04:00.000Z | null | null | null +2024-05-10T00:05:00.000Z | 8 | null | null +2024-05-10T00:06:00.000Z | 10 | null | null +2024-05-10T00:07:00.000Z | 5 | null | null +2024-05-10T00:08:00.000Z | 12 | null | null +2024-05-10T00:09:00.000Z | 20 | null | null +2024-05-10T00:10:00.000Z | 5 | null | null +2024-05-10T00:11:00.000Z | 107 | step_change | 3.438939970021414E-22 +2024-05-10T00:12:00.000Z | 108 | null | null +2024-05-10T00:13:00.000Z | 109 | null | null +2024-05-10T00:14:00.000Z | 109 | null | null +2024-05-10T00:15:00.000Z | 111 | null | null +2024-05-10T00:16:00.000Z | 107 | null | null +2024-05-10T00:17:00.000Z | 115 | null | null +2024-05-10T00:18:00.000Z | 117 | null | null +2024-05-10T00:19:00.000Z | 105 | null | null +2024-05-10T00:20:00.000Z | 110 | null | null +2024-05-10T00:21:00.000Z | 104 | null | null +2024-05-10T00:22:00.000Z | 109 | null | null +; + + +multivalued +required_capability: change_point + +FROM employees + | STATS salary=MV_SORT(VALUES(salary)) BY height + | EVAL salary = CASE(height == 1.5, [1, 22222, 33333], salary) + | EVAL salary = CASE(height == 1.63, [43210, -10000, 999999999], salary) + | EVAL salary = CASE(height == 1.8, 999999999, salary) + | CHANGE_POINT salary ON height +; + +warning:Line 6:3: warnings during evaluation of [CHANGE_POINT salary ON height]. Only first 20 failures recorded. +warning:Line 6:3: java.lang.IllegalArgumentException: values contains multivalued entries; skipping them (please consider reducing them with e.g. MV_AVG or MV_SUM) + +height:double | salary:integer | type:keyword | pvalue:double +1.41 | 40031 | null | null +1.42 | [29175, 39110] | null | null +1.44 | [30404, 50128] | null | null +1.45 | 49095 | null | null +1.46 | 39878 | null | null +1.47 | 60408 | null | null +1.48 | 44307 | null | null +1.5 | [1, 22222, 33333] | null | null +1.51 | 28035 | null | null +1.52 | [34341, 37853, 42716, 50064] | null | null +1.53 | [35222, 71165, 73851] | null | null +1.54 | 61358 | null | null +1.55 | [36051, 37702] | null | null +1.56 | 60335 | null | null +1.57 | [33370, 43602] | null | null +1.58 | [28941, 54462] | null | null +1.59 | [27215, 32263, 50249] | null | null +1.61 | [49818, 60781] | null | null +1.63 | [43210, -10000, 999999999] | null | null +1.64 | 38992 | null | null +1.66 | [25324, 32568] | null | null +1.68 | [37716, 46595] | null | null +1.69 | 45656 | null | null +1.7 | [45797, 65030, 74572, 74970] | null | null +1.74 | [32272, 58715, 68547] | null | null +1.75 | [25976, 47896, 56415] | null | null +1.77 | [41933, 52044, 54329, 68431] | null | null +1.78 | [36174, 52121] | null | null +1.79 | 55360 | null | null +1.8 | 999999999 | spike | 0.0 +1.81 | [25945, 69904, 73578] | null | null +1.82 | [48233, 54518, 65367] | null | null +1.83 | [38376, 61805, 62405] | null | null +1.85 | 66174 | null | null +1.87 | 47411 | null | null +1.89 | 58121 | null | null +1.9 | 37112 | null | null +1.91 | 39638 | null | null +1.92 | 67492 | null | null +1.93 | 33956 | null | null +1.94 | [43889, 48735, 51956] | null | null +1.96 | 43026 | null | null +1.97 | [48942, 56760] | null | null +1.99 | [37137, 74999] | null | null +2.0 | [26436, 37691, 44817] | null | null +2.01 | 35742 | null | null +2.03 | [44956, 57305] | null | null +2.04 | 49281 | null | null +2.05 | 63528 | null | null +2.06 | [39728, 73717] | null | null +2.07 | [39356, 40612] | null | null +2.08 | [56371, 64675] | null | null +2.09 | 38645 | null | null +2.1 | [28336, 31897, 43906, 62233, 66817] | null | null +; + + +multivalued with MV_AVG +required_capability: change_point + +FROM employees + | STATS salary=MV_SORT(VALUES(salary)) BY height + | EVAL salary = CASE(height == 1.5, [1, 22222, 33333], salary) + | EVAL salary = CASE(height == 1.63, [43210, -10000, 999999999], salary) + | EVAL salary = MV_AVG(salary) + | CHANGE_POINT salary ON height +; + +height:double | salary:double | type:keyword | pvalue:double +1.41 | 40031.0 | null | null +1.42 | 34142.5 | null | null +1.44 | 40266.0 | null | null +1.45 | 49095.0 | null | null +1.46 | 39878.0 | null | null +1.47 | 60408.0 | null | null +1.48 | 44307.0 | null | null +1.5 | 18518.666666666668 | null | null +1.51 | 28035.0 | null | null +1.52 | 41243.5 | null | null +1.53 | 60079.333333333336 | null | null +1.54 | 61358.0 | null | null +1.55 | 36876.5 | null | null +1.56 | 60335.0 | null | null +1.57 | 38486.0 | null | null +1.58 | 41701.5 | null | null +1.59 | 36575.666666666664 | null | null +1.61 | 55299.5 | null | null +1.63 | 3.33344403E8 | spike | 0.0 +1.64 | 38992.0 | null | null +1.66 | 28946.0 | null | null +1.68 | 42155.5 | null | null +1.69 | 45656.0 | null | null +1.7 | 65092.25 | null | null +1.74 | 53178.0 | null | null +1.75 | 43429.0 | null | null +1.77 | 54184.25 | null | null +1.78 | 44147.5 | null | null +1.79 | 55360.0 | null | null +1.8 | 52833.0 | null | null +1.81 | 56475.666666666664 | null | null +1.82 | 56039.333333333336 | null | null +1.83 | 54195.333333333336 | null | null +1.85 | 66174.0 | null | null +1.87 | 47411.0 | null | null +1.89 | 58121.0 | null | null +1.9 | 37112.0 | null | null +1.91 | 39638.0 | null | null +1.92 | 67492.0 | null | null +1.93 | 33956.0 | null | null +1.94 | 48193.333333333336 | null | null +1.96 | 43026.0 | null | null +1.97 | 52851.0 | null | null +1.99 | 56068.0 | null | null +2.0 | 36314.666666666664 | null | null +2.01 | 35742.0 | null | null +2.03 | 51130.5 | null | null +2.04 | 49281.0 | null | null +2.05 | 63528.0 | null | null +2.06 | 56722.5 | null | null +2.07 | 39984.0 | null | null +2.08 | 60523.0 | null | null +2.09 | 38645.0 | null | null +2.1 | 46637.8 | null | null +; + + +too much data (change point inside limit) +required_capability: change_point + +ROW key1=["A","B","C","D","E","F","G","H","I","J","K","L","M"], + key2=["0","1","2","3","4","5","6","7","8","9"], + key3=["0","1","2","3","4","5","6","7","8","9"] + | MV_EXPAND key1 + | MV_EXPAND key2 + | MV_EXPAND key3 + | EVAL key=CONCAT(key1,key2,key3) + | EVAL value=CASE(key >= "I42", 1000, 1) + | KEEP key, value + | CHANGE_POINT value ON key AS type, pvalue + | WHERE type IS NOT NULL +; + +warning:Line 10:3: warnings during evaluation of [CHANGE_POINT value ON key AS type, pvalue]. Only first 20 failures recorded. +warning:Line 10:3: java.lang.IllegalArgumentException: too many values; keeping only first 1000 values + +key:keyword | value:integer | type:keyword | pvalue:double +I42 | 1000 | step_change | 0.0 +; + + +too much data (change point outside limit) +required_capability: change_point + +ROW key1=["A","B","C","D","E","F","G","H","I","J","K","L","M"], + key2=["0","1","2","3","4","5","6","7","8","9"], + key3=["0","1","2","3","4","5","6","7","8","9"] + | MV_EXPAND key1 + | MV_EXPAND key2 + | MV_EXPAND key3 + | EVAL key=CONCAT(key1,key2,key3) + | EVAL value=CASE(key >= "L42", 1000, 1) + | KEEP key, value + | CHANGE_POINT value ON key AS type, pvalue + | WHERE type IS NOT NULL +; + +warning:Line 10:3: warnings during evaluation of [CHANGE_POINT value ON key AS type, pvalue]. Only first 20 failures recorded. +warning:Line 10:3: java.lang.IllegalArgumentException: too many values; keeping only first 1000 values + +key:keyword | value:integer | type:keyword | pvalue:double +; + + +too much data (assert output size) +required_capability: change_point + +ROW key1=["A","B","C","D","E","F","G","H","I","J","K","L","M"], + key2=["0","1","2","3","4","5","6","7","8","9"], + key3=["0","1","2","3","4","5","6","7","8","9"] + | MV_EXPAND key1 + | MV_EXPAND key2 + | MV_EXPAND key3 + | EVAL key=CONCAT(key1,key2,key3) + | EVAL value=CASE(key >= "I42", 1000, 1) + | KEEP key, value + | CHANGE_POINT value ON key AS type, pvalue + | STATS count=COUNT() +; + +warning:Line 10:3: warnings during evaluation of [CHANGE_POINT value ON key AS type, pvalue]. Only first 20 failures recorded. +warning:Line 10:3: java.lang.IllegalArgumentException: too many values; keeping only first 1000 values + +count:LONG +1000 +; + + +detect trend_change (using row) +required_capability: change_point + +ROW time = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25] + | MV_EXPAND time + | EVAL val = ABS(15-time) + | CHANGE_POINT val ON time +; + +time:integer | val:integer | type:keyword | pvalue:double +1 | 14 | null | null +2 | 13 | null | null +3 | 12 | null | null +4 | 11 | null | null +5 | 10 | null | null +6 | 9 | null | null +7 | 8 | null | null +8 | 7 | null | null +9 | 6 | null | null +10 | 5 | null | null +11 | 4 | null | null +12 | 3 | null | null +13 | 2 | null | null +14 | 1 | null | null +15 | 0 | trend_change | 1.2352704486638883E-112 +16 | 1 | null | null +17 | 2 | null | null +18 | 3 | null | null +19 | 4 | null | null +20 | 5 | null | null +21 | 6 | null | null +22 | 7 | null | null +23 | 8 | null | null +24 | 9 | null | null +25 | 10 | null | null +; + + +keys null column +required_capability: change_point + +ROW key=NULL, value=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] + | MV_EXPAND value + | CHANGE_POINT value ON key +; + +key:null | value:integer | type:keyword | pvalue:double +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +null | 1 | null | null +; + + +values null column +required_capability: change_point + +ROW time=[7,13,12,17,14,5,16,10,19,18,20,2,3,21,25,4,22,15,6,23,9,11,1,8,24], values=NULL::INTEGER + | MV_EXPAND time + | CHANGE_POINT values ON time +; + +warning: Line 3:3: evaluation of [CHANGE_POINT values ON time] failed, treating result as null. Only first 20 failures recorded. +warning: Line 3:3: java.lang.IllegalArgumentException: not enough buckets to calculate change_point. Requires at least [22]; found [0] +warning: Line 3:3: java.lang.IllegalArgumentException: values contain nulls; skipping them + +time:integer | values:integer | type:keyword | pvalue:double +1 | null | null | null +2 | null | null | null +3 | null | null | null +4 | null | null | null +5 | null | null | null +6 | null | null | null +7 | null | null | null +8 | null | null | null +9 | null | null | null +10 | null | null | null +11 | null | null | null +12 | null | null | null +13 | null | null | null +14 | null | null | null +15 | null | null | null +16 | null | null | null +17 | null | null | null +18 | null | null | null +19 | null | null | null +20 | null | null | null +21 | null | null | null +22 | null | null | null +23 | null | null | null +24 | null | null | null +25 | null | null | null +; + + +row with integer key and value +required_capability: change_point + +ROW key=[7,13,12,17,14,5,16,10,19,18,20,2,3,21,25,4,22,15,6,23,9,11,1,8,24] + | MV_EXPAND key + | EVAL value=CASE(key<13, 0, 1) + | CHANGE_POINT value ON key + | WHERE type IS NOT NULL +; + +key:integer | value:integer | type:keyword | pvalue:double +13 | 1 | step_change | 0.0 +; + + +row with long key and value +required_capability: change_point + +ROW key=[7,13,12,17,14,5,16,10,19,18,20,2,3,21,25,4,22,15,6,23,9,11,1,8,24] + | MV_EXPAND key + | EVAL key=TO_LONG(key), value=CASE(key<13, 0::LONG, 1::LONG) + | CHANGE_POINT value ON key + | WHERE type IS NOT NULL +; + +key:long | value:long | type:keyword | pvalue:double +13 | 1 | step_change | 0.0 +; + + +row with double key and value +required_capability: change_point + +ROW key=[7,13,12,17,14,5,16,10,19,18,20,2,3,21,25,4,22,15,6,23,9,11,1,8,24] + | MV_EXPAND key + | EVAL key=TO_DOUBLE(key), value=CASE(key<13, 0::DOUBLE, 1::DOUBLE) + | CHANGE_POINT value ON key + | WHERE type IS NOT NULL +; + +key:double | value:double | type:keyword | pvalue:double +13 | 1 | step_change | 0.0 +; + + +row with string key +required_capability: change_point + +ROW key=["23","17","02","06","01","21","12","15","19","07","11","05","24","04","10","14","13","22","09","18","20","08","25","16","03"] + | MV_EXPAND key + | EVAL value=CASE(key<"13", 0, 1) + | CHANGE_POINT value ON key + | WHERE type IS NOT NULL +; + +key:string | value:integer | type:keyword | pvalue:double +13 | 1 | step_change | 0.0 +; + + +row with datetime key +required_capability: change_point + +ROW key=[7,13,12,17,14,5,16,10,19,18,20,2,3,21,25,4,22,15,6,23,9,11,1,8,24] + | MV_EXPAND key + | EVAL key=TO_DATETIME(key), value=CASE(key<"1970-01-01T00:00:00.013Z", 0, 1) + | CHANGE_POINT value ON key + | WHERE type IS NOT NULL +; + +key:datetime | value:integer | type:keyword | pvalue:double +1970-01-01T00:00:00.013Z | 1 | step_change | 0.0 +; + + +row with ip key +required_capability: change_point + +ROW key=[7,13,12,17,14,5,16,10,19,18,20,2,3,21,25,4,22,15,6,23,9,11,1,8,24] + | MV_EXPAND key + | EVAL key=TO_STRING(key), key=TO_IP(CONCAT(key,".",key,".",key,".",key)), value=CASE(key<"13.13.13.13", 0, 1) + | CHANGE_POINT value ON key + | WHERE type IS NOT NULL +; + +key:ip | value:integer | type:keyword | pvalue:double +13.13.13.13 | 1 | step_change | 0.0 +; + + +row with version key +required_capability: change_point + +ROW key=[7,13,12,17,14,5,16,10,19,18,20,2,3,21,25,4,22,15,6,23,9,11,1,8,24] + | MV_EXPAND key + | EVAL key=TO_STRING(key), key=TO_VERSION(CONCAT(key,".",key,".",key)), value=CASE(key<"13.13.13", 0, 1) + | CHANGE_POINT value ON key + | WHERE type IS NOT NULL +; + +key:version | value:integer | type:keyword | pvalue:double +13.13.13 | 1 | step_change | 0.0 +; + + +row with boolean key +required_capability: change_point + +ROW key=[1,0,1,1,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0,0,1,0,0,0,1] + | MV_EXPAND key + | EVAL key=TO_BOOLEAN(key), value=CASE(key==false, 0, 1) + | CHANGE_POINT value ON key +; + +key:boolean | value:integer | type:keyword | pvalue:double +false | 0 | null | null +false | 0 | null | null +false | 0 | null | null +false | 0 | null | null +false | 0 | null | null +false | 0 | null | null +false | 0 | null | null +false | 0 | null | null +false | 0 | null | null +false | 0 | null | null +false | 0 | null | null +false | 0 | null | null +true | 1 | step_change | 0.0 +true | 1 | null | null +true | 1 | null | null +true | 1 | null | null +true | 1 | null | null +true | 1 | null | null +true | 1 | null | null +true | 1 | null | null +true | 1 | null | null +true | 1 | null | null +true | 1 | null | null +true | 1 | null | null +true | 1 | null | null +; diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup-join.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup-join.csv-spec index d4a98fdc70a9..8ca4292f97fa 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup-join.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup-join.csv-spec @@ -1346,3 +1346,50 @@ language_code:integer | language_name:keyword | country:text 1 | English | United States of America 1 | English | null ; + + +sortBeforeAndAfterJoin +required_capability: join_lookup_v12 +required_capability: remove_redundant_sort + +FROM employees +| sort first_name +| EVAL language_code = languages +| LOOKUP JOIN languages_lookup ON language_code +| WHERE emp_no >= 10091 AND emp_no < 10094 +| SORT emp_no +| KEEP emp_no, language_code, language_name +; + +emp_no:integer | language_code:integer | language_name:keyword +10091 | 3 | Spanish +10092 | 1 | English +10093 | 3 | Spanish +; + + + +sortBeforeAndAfterMultipleJoinAndMvExpand +required_capability: join_lookup_v12 +required_capability: remove_redundant_sort + +FROM employees +| sort first_name +| EVAL language_code = languages +| LOOKUP JOIN languages_lookup ON language_code +| WHERE emp_no >= 10091 AND emp_no < 10094 +| SORT language_name +| MV_EXPAND first_name +| SORT first_name +| MV_EXPAND last_name +| SORT last_name +| LOOKUP JOIN languages_lookup ON language_code +| SORT emp_no +| KEEP emp_no, language_code, language_name +; + +emp_no:integer | language_code:integer | language_name:keyword +10091 | 3 | Spanish +10092 | 1 | English +10093 | 3 | Spanish +; diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mv_expand.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mv_expand.csv-spec index 2a7c09279840..1b4c1f0bc2b6 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mv_expand.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mv_expand.csv-spec @@ -404,3 +404,17 @@ from employees | where emp_no == 10003 | mv_expand first_name | keep first_name first_name:keyword Parto ; + + +sortBeforeAndAfterMvExpand +from employees +| sort first_name +| mv_expand job_positions +| sort emp_no, job_positions +| keep emp_no, job_positions +| limit 2; + +emp_no:integer | job_positions:keyword +10001 | Accountant +10001 | Senior Python Developer +; diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractCrossClusterTestCase.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractCrossClusterTestCase.java index 1c2ac0e10b79..571e89c3fa50 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractCrossClusterTestCase.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractCrossClusterTestCase.java @@ -23,6 +23,7 @@ import org.elasticsearch.test.XContentTestUtils; import org.elasticsearch.transport.RemoteClusterAware; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.json.JsonXContent; +import org.junit.After; import org.junit.Before; import java.io.IOException; @@ -107,6 +108,13 @@ public abstract class AbstractCrossClusterTestCase extends AbstractMultiClusters CrossClusterAsyncQueryIT.CountingPauseFieldPlugin.resetPlugin(); } + @After + public void releaseLatches() { + SimplePauseFieldPlugin.release(); + FailingPauseFieldPlugin.release(); + CrossClusterAsyncQueryIT.CountingPauseFieldPlugin.release(); + } + protected void assertClusterInfoSuccess(EsqlExecutionInfo.Cluster cluster, int numShards) { assertThat(cluster.getTook().millis(), greaterThanOrEqualTo(0L)); assertThat(cluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SUCCESSFUL)); diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractCrossClustersUsageTelemetryIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractCrossClusterUsageTelemetryIT.java similarity index 98% rename from x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractCrossClustersUsageTelemetryIT.java rename to x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractCrossClusterUsageTelemetryIT.java index 7df40da0344a..73dbb0de8acd 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractCrossClustersUsageTelemetryIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractCrossClusterUsageTelemetryIT.java @@ -33,8 +33,8 @@ import static org.elasticsearch.core.TimeValue.timeValueMillis; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertResponse; -public class AbstractCrossClustersUsageTelemetryIT extends AbstractMultiClustersTestCase { - private static final Logger LOGGER = LogManager.getLogger(AbstractCrossClustersUsageTelemetryIT.class); +public class AbstractCrossClusterUsageTelemetryIT extends AbstractMultiClustersTestCase { + private static final Logger LOGGER = LogManager.getLogger(AbstractCrossClusterUsageTelemetryIT.class); protected static final String REMOTE1 = "cluster-a"; protected static final String REMOTE2 = "cluster-b"; protected static final String LOCAL_INDEX = "logs-1"; diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractEnrichBasedCrossClusterTestCase.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractEnrichBasedCrossClusterTestCase.java index 4d1f90870215..de54e7de13b7 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractEnrichBasedCrossClusterTestCase.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/AbstractEnrichBasedCrossClusterTestCase.java @@ -75,7 +75,7 @@ public abstract class AbstractEnrichBasedCrossClusterTestCase extends AbstractMu @Override protected Collection> nodePlugins(String clusterAlias) { List> plugins = new ArrayList<>(super.nodePlugins(clusterAlias)); - plugins.add(CrossClustersEnrichIT.LocalStateEnrich.class); + plugins.add(CrossClusterEnrichIT.LocalStateEnrich.class); plugins.add(IngestCommonPlugin.class); plugins.add(ReindexPlugin.class); return plugins; @@ -274,7 +274,7 @@ public abstract class AbstractEnrichBasedCrossClusterTestCase extends AbstractMu @Override protected Class> getInfoAction() { - return CrossClustersQueriesWithInvalidLicenseIT.LocalStateEnrich.EnrichTransportXPackInfoAction.class; + return CrossClusterQueriesWithInvalidLicenseIT.LocalStateEnrich.EnrichTransportXPackInfoAction.class; } } } diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java index 1c67b956de5e..8a09c4af8ca5 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java @@ -53,65 +53,71 @@ public class CrossClusterAsyncQueryStopIT extends AbstractCrossClusterTestCase { includeCCSMetadata.v1(), Map.of("page_size", 1, "data_partitioning", "shard", "task_concurrency", 1) ); + try { + // wait until we know that the query against 'remote-b:blocking' has started + CountingPauseFieldPlugin.startEmitting.await(30, TimeUnit.SECONDS); - // wait until we know that the query against 'remote-b:blocking' has started - CountingPauseFieldPlugin.startEmitting.await(30, TimeUnit.SECONDS); + // wait until the query of 'cluster-a:logs-*' has finished (it is not blocked since we are not searching the 'blocking' index on + // it) + waitForCluster(client(), REMOTE_CLUSTER_1, asyncExecutionId); + waitForCluster(client(), LOCAL_CLUSTER, asyncExecutionId); - // wait until the query of 'cluster-a:logs-*' has finished (it is not blocked since we are not searching the 'blocking' index on it) - waitForCluster(client(), REMOTE_CLUSTER_1, asyncExecutionId); - waitForCluster(client(), LOCAL_CLUSTER, asyncExecutionId); + /* at this point: + * the query against cluster-a should be finished + * the query against remote-b should be running (blocked on the PauseFieldPlugin.allowEmitting CountDown) + * the query against the local cluster should be running because it has a STATS clause that needs to wait on remote-b + */ - /* at this point: - * the query against cluster-a should be finished - * the query against remote-b should be running (blocked on the PauseFieldPlugin.allowEmitting CountDown) - * the query against the local cluster should be running because it has a STATS clause that needs to wait on remote-b - */ + // run the stop query + AsyncStopRequest stopRequest = new AsyncStopRequest(asyncExecutionId); + ActionFuture stopAction = client().execute(EsqlAsyncStopAction.INSTANCE, stopRequest); + assertBusy(() -> { + List tasks = getDriverTasks(client(REMOTE_CLUSTER_2)); + List reduceTasks = tasks.stream() + .filter(t -> t.description().contains("_LuceneSourceOperator") == false) + .toList(); + assertThat(reduceTasks, empty()); + }); + // allow remoteB query to proceed + CountingPauseFieldPlugin.allowEmitting.countDown(); - // run the stop query - AsyncStopRequest stopRequest = new AsyncStopRequest(asyncExecutionId); - ActionFuture stopAction = client().execute(EsqlAsyncStopAction.INSTANCE, stopRequest); - assertBusy(() -> { - List tasks = getDriverTasks(client(REMOTE_CLUSTER_2)); - List reduceTasks = tasks.stream().filter(t -> t.description().contains("_LuceneSourceOperator") == false).toList(); - assertThat(reduceTasks, empty()); - }); - // allow remoteB query to proceed - CountingPauseFieldPlugin.allowEmitting.countDown(); + // Since part of the query has not been stopped, we expect some result to emerge here + try (EsqlQueryResponse asyncResponse = stopAction.actionGet(30, TimeUnit.SECONDS)) { + // Check that we did not process all the fields on remote-b + // Should not be getting more than one page here, and we set page size to 1 + assertThat(CountingPauseFieldPlugin.count.get(), lessThanOrEqualTo(1L)); + assertThat(asyncResponse.isRunning(), is(false)); + assertThat(asyncResponse.columns().size(), equalTo(1)); + assertThat(asyncResponse.values().hasNext(), is(true)); + Iterator row = asyncResponse.values().next(); + // sum of 0-9 is 45, and sum of 0-9 squared is 285 + assertThat(row.next(), equalTo(330L)); - // Since part of the query has not been stopped, we expect some result to emerge here - try (EsqlQueryResponse asyncResponse = stopAction.actionGet(30, TimeUnit.SECONDS)) { - // Check that we did not process all the fields on remote-b - // Should not be getting more than one page here, and we set page size to 1 - assertThat(CountingPauseFieldPlugin.count.get(), lessThanOrEqualTo(1L)); - assertThat(asyncResponse.isRunning(), is(false)); - assertThat(asyncResponse.columns().size(), equalTo(1)); - assertThat(asyncResponse.values().hasNext(), is(true)); - Iterator row = asyncResponse.values().next(); - // sum of 0-9 is 45, and sum of 0-9 squared is 285 - assertThat(row.next(), equalTo(330L)); + EsqlExecutionInfo executionInfo = asyncResponse.getExecutionInfo(); + assertNotNull(executionInfo); + assertThat(executionInfo.isCrossClusterSearch(), is(true)); + long overallTookMillis = executionInfo.overallTook().millis(); + assertThat(overallTookMillis, greaterThanOrEqualTo(0L)); + assertThat(executionInfo.clusterAliases(), equalTo(Set.of(LOCAL_CLUSTER, REMOTE_CLUSTER_1, REMOTE_CLUSTER_2))); + assertThat(executionInfo.isPartial(), equalTo(true)); - EsqlExecutionInfo executionInfo = asyncResponse.getExecutionInfo(); - assertNotNull(executionInfo); - assertThat(executionInfo.isCrossClusterSearch(), is(true)); - long overallTookMillis = executionInfo.overallTook().millis(); - assertThat(overallTookMillis, greaterThanOrEqualTo(0L)); - assertThat(executionInfo.clusterAliases(), equalTo(Set.of(LOCAL_CLUSTER, REMOTE_CLUSTER_1, REMOTE_CLUSTER_2))); - assertThat(executionInfo.isPartial(), equalTo(true)); + EsqlExecutionInfo.Cluster remoteCluster = executionInfo.getCluster(REMOTE_CLUSTER_1); + assertThat(remoteCluster.getIndexExpression(), equalTo("logs-*")); + assertClusterInfoSuccess(remoteCluster, remote1NumShards); - EsqlExecutionInfo.Cluster remoteCluster = executionInfo.getCluster(REMOTE_CLUSTER_1); - assertThat(remoteCluster.getIndexExpression(), equalTo("logs-*")); - assertClusterInfoSuccess(remoteCluster, remote1NumShards); + EsqlExecutionInfo.Cluster remote2Cluster = executionInfo.getCluster(REMOTE_CLUSTER_2); + assertThat(remote2Cluster.getIndexExpression(), equalTo("blocking")); + assertThat(remote2Cluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.PARTIAL)); - EsqlExecutionInfo.Cluster remote2Cluster = executionInfo.getCluster(REMOTE_CLUSTER_2); - assertThat(remote2Cluster.getIndexExpression(), equalTo("blocking")); - assertThat(remote2Cluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.PARTIAL)); + EsqlExecutionInfo.Cluster localCluster = executionInfo.getCluster(LOCAL_CLUSTER); + assertThat(localCluster.getIndexExpression(), equalTo("logs-*")); + assertClusterInfoSuccess(localCluster, localNumShards); - EsqlExecutionInfo.Cluster localCluster = executionInfo.getCluster(LOCAL_CLUSTER); - assertThat(localCluster.getIndexExpression(), equalTo("logs-*")); - assertClusterInfoSuccess(localCluster, localNumShards); - - assertClusterMetadataInResponse(asyncResponse, responseExpectMeta, 3); + assertClusterMetadataInResponse(asyncResponse, responseExpectMeta, 3); + } } finally { + // Ensure proper cleanup if the test fails + CountingPauseFieldPlugin.allowEmitting.countDown(); assertAcked(deleteAsyncId(client(), asyncExecutionId)); } } @@ -131,63 +137,66 @@ public class CrossClusterAsyncQueryStopIT extends AbstractCrossClusterTestCase { includeCCSMetadata.v1() ); - // wait until we know that the query against 'remote-b:blocking' has started - SimplePauseFieldPlugin.startEmitting.await(30, TimeUnit.SECONDS); + try { + // wait until we know that the query against 'remote-b:blocking' has started + SimplePauseFieldPlugin.startEmitting.await(30, TimeUnit.SECONDS); - // wait until the remotes are done - waitForCluster(client(), REMOTE_CLUSTER_1, asyncExecutionId); - waitForCluster(client(), REMOTE_CLUSTER_2, asyncExecutionId); + // wait until the remotes are done + waitForCluster(client(), REMOTE_CLUSTER_1, asyncExecutionId); + waitForCluster(client(), REMOTE_CLUSTER_2, asyncExecutionId); - /* at this point: - * the query against remotes should be finished - * the query against the local cluster should be running because it's blocked - */ + /* at this point: + * the query against remotes should be finished + * the query against the local cluster should be running because it's blocked + */ + + // run the stop query + AsyncStopRequest stopRequest = new AsyncStopRequest(asyncExecutionId); + ActionFuture stopAction = client().execute(EsqlAsyncStopAction.INSTANCE, stopRequest); + // ensure stop operation is running + assertBusy(() -> { + try (EsqlQueryResponse asyncResponse = getAsyncResponse(client(), asyncExecutionId)) { + EsqlExecutionInfo executionInfo = asyncResponse.getExecutionInfo(); + assertNotNull(executionInfo); + assertThat(executionInfo.isPartial(), is(true)); + } + }); + // allow local query to proceed + SimplePauseFieldPlugin.allowEmitting.countDown(); + + // Since part of the query has not been stopped, we expect some result to emerge here + try (EsqlQueryResponse asyncResponse = stopAction.actionGet(30, TimeUnit.SECONDS)) { + assertThat(asyncResponse.isRunning(), is(false)); + assertThat(asyncResponse.columns().size(), equalTo(1)); + assertThat(asyncResponse.values().hasNext(), is(true)); + Iterator row = asyncResponse.values().next(); + // sum of 0-9 squared is 285, from two remotes it's 570 + assertThat(row.next(), equalTo(570L)); - // run the stop query - AsyncStopRequest stopRequest = new AsyncStopRequest(asyncExecutionId); - ActionFuture stopAction = client().execute(EsqlAsyncStopAction.INSTANCE, stopRequest); - // ensure stop operation is running - assertBusy(() -> { - try (EsqlQueryResponse asyncResponse = getAsyncResponse(client(), asyncExecutionId)) { EsqlExecutionInfo executionInfo = asyncResponse.getExecutionInfo(); assertNotNull(executionInfo); - assertThat(executionInfo.isPartial(), is(true)); + assertThat(executionInfo.isCrossClusterSearch(), is(true)); + long overallTookMillis = executionInfo.overallTook().millis(); + assertThat(overallTookMillis, greaterThanOrEqualTo(0L)); + assertThat(executionInfo.clusterAliases(), equalTo(Set.of(LOCAL_CLUSTER, REMOTE_CLUSTER_1, REMOTE_CLUSTER_2))); + assertThat(executionInfo.isPartial(), equalTo(true)); + + EsqlExecutionInfo.Cluster remoteCluster = executionInfo.getCluster(REMOTE_CLUSTER_1); + assertThat(remoteCluster.getIndexExpression(), equalTo("logs-*")); + assertClusterInfoSuccess(remoteCluster, remote1NumShards); + + EsqlExecutionInfo.Cluster remote2Cluster = executionInfo.getCluster(REMOTE_CLUSTER_2); + assertThat(remote2Cluster.getIndexExpression(), equalTo("logs-*")); + assertClusterInfoSuccess(remote2Cluster, remote2NumShards); + + EsqlExecutionInfo.Cluster localCluster = executionInfo.getCluster(LOCAL_CLUSTER); + assertThat(localCluster.getIndexExpression(), equalTo("blocking")); + assertThat(localCluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.PARTIAL)); + + assertClusterMetadataInResponse(asyncResponse, responseExpectMeta, 3); } - }); - // allow local query to proceed - SimplePauseFieldPlugin.allowEmitting.countDown(); - - // Since part of the query has not been stopped, we expect some result to emerge here - try (EsqlQueryResponse asyncResponse = stopAction.actionGet(30, TimeUnit.SECONDS)) { - assertThat(asyncResponse.isRunning(), is(false)); - assertThat(asyncResponse.columns().size(), equalTo(1)); - assertThat(asyncResponse.values().hasNext(), is(true)); - Iterator row = asyncResponse.values().next(); - // sum of 0-9 squared is 285, from two remotes it's 570 - assertThat(row.next(), equalTo(570L)); - - EsqlExecutionInfo executionInfo = asyncResponse.getExecutionInfo(); - assertNotNull(executionInfo); - assertThat(executionInfo.isCrossClusterSearch(), is(true)); - long overallTookMillis = executionInfo.overallTook().millis(); - assertThat(overallTookMillis, greaterThanOrEqualTo(0L)); - assertThat(executionInfo.clusterAliases(), equalTo(Set.of(LOCAL_CLUSTER, REMOTE_CLUSTER_1, REMOTE_CLUSTER_2))); - assertThat(executionInfo.isPartial(), equalTo(true)); - - EsqlExecutionInfo.Cluster remoteCluster = executionInfo.getCluster(REMOTE_CLUSTER_1); - assertThat(remoteCluster.getIndexExpression(), equalTo("logs-*")); - assertClusterInfoSuccess(remoteCluster, remote1NumShards); - - EsqlExecutionInfo.Cluster remote2Cluster = executionInfo.getCluster(REMOTE_CLUSTER_2); - assertThat(remote2Cluster.getIndexExpression(), equalTo("logs-*")); - assertClusterInfoSuccess(remote2Cluster, remote2NumShards); - - EsqlExecutionInfo.Cluster localCluster = executionInfo.getCluster(LOCAL_CLUSTER); - assertThat(localCluster.getIndexExpression(), equalTo("blocking")); - assertThat(localCluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.PARTIAL)); - - assertClusterMetadataInResponse(asyncResponse, responseExpectMeta, 3); } finally { + SimplePauseFieldPlugin.allowEmitting.countDown(); assertAcked(deleteAsyncId(client(), asyncExecutionId)); } } @@ -205,30 +214,33 @@ public class CrossClusterAsyncQueryStopIT extends AbstractCrossClusterTestCase { includeCCSMetadata.v1() ); - // wait until we know that the query against 'remote-b:blocking' has started - SimplePauseFieldPlugin.startEmitting.await(30, TimeUnit.SECONDS); + try { + // wait until we know that the query against 'remote-b:blocking' has started + SimplePauseFieldPlugin.startEmitting.await(30, TimeUnit.SECONDS); - /* at this point: - * the query against the local cluster should be running because it's blocked - */ + /* at this point: + * the query against the local cluster should be running because it's blocked + */ - // run the stop query - var stopRequest = new AsyncStopRequest(asyncExecutionId); - var stopAction = client().execute(EsqlAsyncStopAction.INSTANCE, stopRequest); - // allow local query to proceed - SimplePauseFieldPlugin.allowEmitting.countDown(); + // run the stop query + var stopRequest = new AsyncStopRequest(asyncExecutionId); + var stopAction = client().execute(EsqlAsyncStopAction.INSTANCE, stopRequest); + // allow local query to proceed + SimplePauseFieldPlugin.allowEmitting.countDown(); - try (EsqlQueryResponse asyncResponse = stopAction.actionGet(30, TimeUnit.SECONDS)) { - assertThat(asyncResponse.isRunning(), is(false)); - assertThat(asyncResponse.columns().size(), equalTo(1)); - assertThat(asyncResponse.values().hasNext(), is(true)); - Iterator row = asyncResponse.values().next(); - assertThat((long) row.next(), greaterThanOrEqualTo(0L)); + try (EsqlQueryResponse asyncResponse = stopAction.actionGet(30, TimeUnit.SECONDS)) { + assertThat(asyncResponse.isRunning(), is(false)); + assertThat(asyncResponse.columns().size(), equalTo(1)); + assertThat(asyncResponse.values().hasNext(), is(true)); + Iterator row = asyncResponse.values().next(); + assertThat((long) row.next(), greaterThanOrEqualTo(0L)); - EsqlExecutionInfo executionInfo = asyncResponse.getExecutionInfo(); - assertNotNull(executionInfo); - assertThat(executionInfo.isCrossClusterSearch(), is(false)); + EsqlExecutionInfo executionInfo = asyncResponse.getExecutionInfo(); + assertNotNull(executionInfo); + assertThat(executionInfo.isCrossClusterSearch(), is(false)); + } } finally { + SimplePauseFieldPlugin.allowEmitting.countDown(); assertAcked(deleteAsyncId(client(), asyncExecutionId)); } } diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersCancellationIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterCancellationIT.java similarity index 96% rename from x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersCancellationIT.java rename to x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterCancellationIT.java index 91610817af54..57041d3d6a06 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersCancellationIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterCancellationIT.java @@ -21,12 +21,14 @@ import org.elasticsearch.compute.operator.DriverTaskRunner; import org.elasticsearch.compute.operator.exchange.ExchangeService; import org.elasticsearch.core.TimeValue; import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.tasks.TaskCancelledException; import org.elasticsearch.tasks.TaskInfo; import org.elasticsearch.test.AbstractMultiClustersTestCase; import org.elasticsearch.transport.TransportService; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.json.JsonXContent; import org.elasticsearch.xpack.esql.plugin.ComputeService; +import org.junit.After; import org.junit.Before; import java.util.ArrayList; @@ -40,8 +42,9 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; -public class CrossClustersCancellationIT extends AbstractMultiClustersTestCase { +public class CrossClusterCancellationIT extends AbstractMultiClustersTestCase { private static final String REMOTE_CLUSTER = "cluster-a"; @Override @@ -76,6 +79,11 @@ public class CrossClustersCancellationIT extends AbstractMultiClustersTestCase { SimplePauseFieldPlugin.resetPlugin(); } + @After + public void releasePlugin() { + SimplePauseFieldPlugin.release(); + } + @Override protected boolean reuseClusters() { return false; @@ -109,6 +117,7 @@ public class CrossClustersCancellationIT extends AbstractMultiClustersTestCase { mapping.startObject("const"); { mapping.field("type", "long"); + mapping.startObject("script").field("source", "").field("lang", "pause").endObject(); } mapping.endObject(); } @@ -117,7 +126,7 @@ public class CrossClustersCancellationIT extends AbstractMultiClustersTestCase { client(LOCAL_CLUSTER).admin().indices().prepareCreate("test").setMapping(mapping).get(); BulkRequestBuilder bulk = client(LOCAL_CLUSTER).prepareBulk("test").setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); for (int i = 0; i < numDocs; i++) { - bulk.add(new IndexRequest().source("const", i)); + bulk.add(new IndexRequest().source("foo", i)); } bulk.get(); } @@ -276,7 +285,7 @@ public class CrossClustersCancellationIT extends AbstractMultiClustersTestCase { } Exception error = expectThrows(Exception.class, requestFuture::actionGet); - assertThat(error.getMessage(), containsString("remote failed")); + assertThat(error, instanceOf(TaskCancelledException.class)); } // Check that closing remote node with skip_unavailable=true produces partial @@ -305,7 +314,7 @@ public class CrossClustersCancellationIT extends AbstractMultiClustersTestCase { List> values = getValuesList(resp); assertThat(values.get(0).size(), equalTo(1)); // We can't be sure of the exact value here as we don't know if any data from remote came in, but all local data should be there - assertThat((long) values.get(0).get(0), greaterThanOrEqualTo(45L)); + assertThat((long) values.get(0).get(0), greaterThanOrEqualTo(10L)); EsqlExecutionInfo.Cluster cluster = executionInfo.getCluster(REMOTE_CLUSTER); EsqlExecutionInfo.Cluster localCluster = executionInfo.getCluster(LOCAL_CLUSTER); 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/CrossClusterEnrichIT.java similarity index 99% rename from x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersEnrichIT.java rename to x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterEnrichIT.java index 51ad4a0d2053..d48f8af9c97e 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/CrossClusterEnrichIT.java @@ -27,7 +27,7 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo; -public class CrossClustersEnrichIT extends AbstractEnrichBasedCrossClusterTestCase { +public class CrossClusterEnrichIT extends AbstractEnrichBasedCrossClusterTestCase { @Override protected Collection> nodePlugins(String clusterAlias) { diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersQueriesWithInvalidLicenseIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueriesWithInvalidLicenseIT.java similarity index 99% rename from x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersQueriesWithInvalidLicenseIT.java rename to x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueriesWithInvalidLicenseIT.java index a9c8190976a0..be19180e1b4a 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersQueriesWithInvalidLicenseIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueriesWithInvalidLicenseIT.java @@ -27,7 +27,7 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; -public class CrossClustersQueriesWithInvalidLicenseIT extends AbstractEnrichBasedCrossClusterTestCase { +public class CrossClusterQueriesWithInvalidLicenseIT extends AbstractEnrichBasedCrossClusterTestCase { private static final String LICENSE_ERROR_MESSAGE = "A valid Enterprise license is required to run ES|QL cross-cluster searches."; diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersUsageTelemetryIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterUsageTelemetryIT.java similarity index 99% rename from x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersUsageTelemetryIT.java rename to x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterUsageTelemetryIT.java index 29fbc19b7274..fdfbe9c6bf9d 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersUsageTelemetryIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterUsageTelemetryIT.java @@ -34,7 +34,7 @@ import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertResp import static org.elasticsearch.xpack.esql.action.EsqlAsyncTestUtils.deleteAsyncId; import static org.hamcrest.Matchers.equalTo; -public class CrossClustersUsageTelemetryIT extends AbstractCrossClustersUsageTelemetryIT { +public class CrossClusterUsageTelemetryIT extends AbstractCrossClusterUsageTelemetryIT { private static final String INDEX_WITH_RUNTIME_MAPPING = "blocking"; @Override diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersUsageTelemetryNoLicenseIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterUsageTelemetryNoLicenseIT.java similarity index 94% rename from x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersUsageTelemetryNoLicenseIT.java rename to x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterUsageTelemetryNoLicenseIT.java index 5736c485aec1..70a93f4e3512 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClustersUsageTelemetryNoLicenseIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterUsageTelemetryNoLicenseIT.java @@ -17,7 +17,7 @@ import java.util.Map; import static org.hamcrest.Matchers.equalTo; -public class CrossClustersUsageTelemetryNoLicenseIT extends AbstractCrossClustersUsageTelemetryIT { +public class CrossClusterUsageTelemetryNoLicenseIT extends AbstractCrossClusterUsageTelemetryIT { @Override protected Collection> nodePlugins(String clusterAlias) { diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/FailingPauseFieldPlugin.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/FailingPauseFieldPlugin.java index 010931432e2e..ad21a700d764 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/FailingPauseFieldPlugin.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/FailingPauseFieldPlugin.java @@ -29,6 +29,10 @@ public class FailingPauseFieldPlugin extends AbstractPauseFieldPlugin { startEmitting = new CountDownLatch(1); } + public static void release() { + allowEmitting.countDown(); + } + @Override public void onStartExecute() { startEmitting.countDown(); diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/SimplePauseFieldPlugin.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/SimplePauseFieldPlugin.java index a8a2d27e8856..7802383f8e18 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/SimplePauseFieldPlugin.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/SimplePauseFieldPlugin.java @@ -24,6 +24,10 @@ public class SimplePauseFieldPlugin extends AbstractPauseFieldPlugin { startEmitting = new CountDownLatch(1); } + public static void release() { + allowEmitting.countDown(); + } + @Override public void onStartExecute() { startEmitting.countDown(); diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchFunctionIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchFunctionIT.java index 2da9bee3701d..4ec309ff05ce 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchFunctionIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchFunctionIT.java @@ -13,7 +13,6 @@ import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.xpack.esql.VerificationException; import org.elasticsearch.xpack.esql.action.AbstractEsqlIntegTestCase; -import org.elasticsearch.xpack.esql.action.EsqlCapabilities; import org.junit.Before; import java.util.List; @@ -105,7 +104,6 @@ public class MatchFunctionIT extends AbstractEsqlIntegTestCase { } public void testWhereMatchWithScoring() { - assumeTrue("'METADATA _score' is disabled", EsqlCapabilities.Cap.METADATA_SCORE.isEnabled()); var query = """ FROM test METADATA _score @@ -122,7 +120,7 @@ public class MatchFunctionIT extends AbstractEsqlIntegTestCase { } public void testWhereMatchWithScoringDifferentSort() { - assumeTrue("'METADATA _score' is disabled", EsqlCapabilities.Cap.METADATA_SCORE.isEnabled()); + var query = """ FROM test METADATA _score @@ -139,7 +137,6 @@ public class MatchFunctionIT extends AbstractEsqlIntegTestCase { } public void testWhereMatchWithScoringSortScore() { - assumeTrue("'METADATA _score' is disabled", EsqlCapabilities.Cap.METADATA_SCORE.isEnabled()); var query = """ FROM test METADATA _score @@ -156,7 +153,6 @@ public class MatchFunctionIT extends AbstractEsqlIntegTestCase { } public void testWhereMatchWithScoringNoSort() { - assumeTrue("'METADATA _score' is disabled", EsqlCapabilities.Cap.METADATA_SCORE.isEnabled()); var query = """ FROM test METADATA _score diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchOperatorIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchOperatorIT.java index dbe115cc6617..c978dead8f4f 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchOperatorIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchOperatorIT.java @@ -13,7 +13,6 @@ import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.xpack.esql.VerificationException; import org.elasticsearch.xpack.esql.action.AbstractEsqlIntegTestCase; -import org.elasticsearch.xpack.esql.action.EsqlCapabilities; import org.junit.Before; import java.util.List; @@ -106,7 +105,6 @@ public class MatchOperatorIT extends AbstractEsqlIntegTestCase { } public void testWhereMatchWithScoring() { - assumeTrue("'METADATA _score' is disabled", EsqlCapabilities.Cap.METADATA_SCORE.isEnabled()); var query = """ FROM test METADATA _score @@ -123,7 +121,6 @@ public class MatchOperatorIT extends AbstractEsqlIntegTestCase { } public void testWhereMatchWithScoringDifferentSort() { - assumeTrue("'METADATA _score' is disabled", EsqlCapabilities.Cap.METADATA_SCORE.isEnabled()); var query = """ FROM test METADATA _score @@ -140,7 +137,6 @@ public class MatchOperatorIT extends AbstractEsqlIntegTestCase { } public void testWhereMatchWithScoringNoSort() { - assumeTrue("'METADATA _score' is disabled", EsqlCapabilities.Cap.METADATA_SCORE.isEnabled()); var query = """ FROM test METADATA _score diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/QueryStringIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/QueryStringIT.java index a3d1ac931528..97a98da6e829 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/QueryStringIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/QueryStringIT.java @@ -13,7 +13,6 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.query.QueryShardException; import org.elasticsearch.xpack.esql.VerificationException; import org.elasticsearch.xpack.esql.action.AbstractEsqlIntegTestCase; -import org.elasticsearch.xpack.esql.action.EsqlCapabilities; import org.junit.Before; import java.util.List; @@ -140,7 +139,6 @@ public class QueryStringIT extends AbstractEsqlIntegTestCase { } public void testWhereQstrWithScoring() { - assumeTrue("'METADATA _score' is disabled", EsqlCapabilities.Cap.METADATA_SCORE.isEnabled()); var query = """ FROM test METADATA _score @@ -165,7 +163,6 @@ public class QueryStringIT extends AbstractEsqlIntegTestCase { } public void testWhereQstrWithScoringSorted() { - assumeTrue("'METADATA _score' is disabled", EsqlCapabilities.Cap.METADATA_SCORE.isEnabled()); var query = """ FROM test METADATA _score @@ -191,7 +188,6 @@ public class QueryStringIT extends AbstractEsqlIntegTestCase { } public void testWhereQstrWithScoringNoSort() { - assumeTrue("'METADATA _score' is disabled", EsqlCapabilities.Cap.METADATA_SCORE.isEnabled()); var query = """ FROM test METADATA _score @@ -215,7 +211,6 @@ public class QueryStringIT extends AbstractEsqlIntegTestCase { } public void testWhereQstrWithNonPushableAndScoring() { - assumeTrue("'METADATA _score' is disabled", EsqlCapabilities.Cap.METADATA_SCORE.isEnabled()); var query = """ FROM test METADATA _score diff --git a/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.g4 b/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.g4 index e8879f9cfdaa..9f900200d5b2 100644 --- a/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.g4 +++ b/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.g4 @@ -85,13 +85,14 @@ JOIN_LOOKUP : 'lookup' -> pushMode(JOIN_MODE); // Once the command has been stabilized, remove the DEV_ prefix and the {}? conditional and move the command to the // main section while preserving alphabetical order: // MYCOMMAND : 'mycommand' -> ... -DEV_INLINESTATS : {this.isDevVersion()}? 'inlinestats' -> pushMode(EXPRESSION_MODE); -DEV_LOOKUP : {this.isDevVersion()}? 'lookup_🐔' -> pushMode(LOOKUP_MODE); -DEV_METRICS : {this.isDevVersion()}? 'metrics' -> pushMode(METRICS_MODE); +DEV_CHANGE_POINT : {this.isDevVersion()}? 'change_point' -> pushMode(CHANGE_POINT_MODE); +DEV_INLINESTATS : {this.isDevVersion()}? 'inlinestats' -> pushMode(EXPRESSION_MODE); +DEV_LOOKUP : {this.isDevVersion()}? 'lookup_🐔' -> pushMode(LOOKUP_MODE); +DEV_METRICS : {this.isDevVersion()}? 'metrics' -> pushMode(METRICS_MODE); // list of all JOIN commands -DEV_JOIN_FULL : {this.isDevVersion()}? 'full' -> pushMode(JOIN_MODE); -DEV_JOIN_LEFT : {this.isDevVersion()}? 'left' -> pushMode(JOIN_MODE); -DEV_JOIN_RIGHT : {this.isDevVersion()}? 'right' -> pushMode(JOIN_MODE); +DEV_JOIN_FULL : {this.isDevVersion()}? 'full' -> pushMode(JOIN_MODE); +DEV_JOIN_LEFT : {this.isDevVersion()}? 'left' -> pushMode(JOIN_MODE); +DEV_JOIN_RIGHT : {this.isDevVersion()}? 'right' -> pushMode(JOIN_MODE); // @@ -314,8 +315,8 @@ mode PROJECT_MODE; PROJECT_PIPE : PIPE -> type(PIPE), popMode; PROJECT_DOT: DOT -> type(DOT); PROJECT_COMMA : COMMA -> type(COMMA); -PROJECT_PARAM : {this.isDevVersion()}? PARAM -> type(PARAM); -PROJECT_NAMED_OR_POSITIONAL_PARAM : {this.isDevVersion()}? NAMED_OR_POSITIONAL_PARAM -> type(NAMED_OR_POSITIONAL_PARAM); +PROJECT_PARAM : PARAM -> type(PARAM); +PROJECT_NAMED_OR_POSITIONAL_PARAM : NAMED_OR_POSITIONAL_PARAM -> type(NAMED_OR_POSITIONAL_PARAM); fragment UNQUOTED_ID_BODY_WITH_PATTERN : (LETTER | DIGIT | UNDERSCORE | ASTERISK) @@ -349,8 +350,8 @@ RENAME_PIPE : PIPE -> type(PIPE), popMode; RENAME_ASSIGN : ASSIGN -> type(ASSIGN); RENAME_COMMA : COMMA -> type(COMMA); RENAME_DOT: DOT -> type(DOT); -RENAME_PARAM : {this.isDevVersion()}? PARAM -> type(PARAM); -RENAME_NAMED_OR_POSITIONAL_PARAM : {this.isDevVersion()}? NAMED_OR_POSITIONAL_PARAM -> type(NAMED_OR_POSITIONAL_PARAM); +RENAME_PARAM : PARAM -> type(PARAM); +RENAME_NAMED_OR_POSITIONAL_PARAM : NAMED_OR_POSITIONAL_PARAM -> type(NAMED_OR_POSITIONAL_PARAM); AS : 'as'; @@ -422,8 +423,8 @@ ENRICH_FIELD_QUOTED_IDENTIFIER : QUOTED_IDENTIFIER -> type(QUOTED_IDENTIFIER) ; -ENRICH_FIELD_PARAM : {this.isDevVersion()}? PARAM -> type(PARAM); -ENRICH_FIELD_NAMED_OR_POSITIONAL_PARAM : {this.isDevVersion()}? NAMED_OR_POSITIONAL_PARAM -> type(NAMED_OR_POSITIONAL_PARAM); +ENRICH_FIELD_PARAM : PARAM -> type(PARAM); +ENRICH_FIELD_NAMED_OR_POSITIONAL_PARAM : NAMED_OR_POSITIONAL_PARAM -> type(NAMED_OR_POSITIONAL_PARAM); ENRICH_FIELD_LINE_COMMENT : LINE_COMMENT -> channel(HIDDEN) @@ -440,8 +441,8 @@ ENRICH_FIELD_WS mode MVEXPAND_MODE; MVEXPAND_PIPE : PIPE -> type(PIPE), popMode; MVEXPAND_DOT: DOT -> type(DOT); -MVEXPAND_PARAM : {this.isDevVersion()}? PARAM -> type(PARAM); -MVEXPAND_NAMED_OR_POSITIONAL_PARAM : {this.isDevVersion()}? NAMED_OR_POSITIONAL_PARAM -> type(NAMED_OR_POSITIONAL_PARAM); +MVEXPAND_PARAM : PARAM -> type(PARAM); +MVEXPAND_NAMED_OR_POSITIONAL_PARAM : NAMED_OR_POSITIONAL_PARAM -> type(NAMED_OR_POSITIONAL_PARAM); MVEXPAND_QUOTED_IDENTIFIER : QUOTED_IDENTIFIER -> type(QUOTED_IDENTIFIER) @@ -638,3 +639,19 @@ CLOSING_METRICS_BY CLOSING_METRICS_PIPE : PIPE -> type(PIPE), popMode ; + +/// +/// CHANGE_POINT command +/// +mode CHANGE_POINT_MODE; + +CHANGE_POINT_PIPE : PIPE -> type(PIPE), popMode; +CHANGE_POINT_ON : ON -> type(ON); +CHANGE_POINT_AS : AS -> type(AS); +CHANGE_POINT_DOT: DOT -> type(DOT); +CHANGE_POINT_COMMA: COMMA -> type(COMMA); +CHANGE_POINT_QUOTED_IDENTIFIER: QUOTED_IDENTIFIER -> type(QUOTED_IDENTIFIER); +CHANGE_POINT_UNQUOTED_IDENTIFIER: UNQUOTED_IDENTIFIER -> type(UNQUOTED_IDENTIFIER); +CHANGE_POINT_LINE_COMMENT: LINE_COMMENT -> channel(HIDDEN); +CHANGE_POINT_MULTILINE_COMMENT: MULTILINE_COMMENT -> channel(HIDDEN); +CHANGE_POINT_WS: WS -> channel(HIDDEN); diff --git a/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.tokens b/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.tokens index 02af324872fc..7ab99c293bc9 100644 --- a/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.tokens +++ b/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.tokens @@ -15,119 +15,123 @@ SORT=14 STATS=15 WHERE=16 JOIN_LOOKUP=17 -DEV_INLINESTATS=18 -DEV_LOOKUP=19 -DEV_METRICS=20 -DEV_JOIN_FULL=21 -DEV_JOIN_LEFT=22 -DEV_JOIN_RIGHT=23 -UNKNOWN_CMD=24 -LINE_COMMENT=25 -MULTILINE_COMMENT=26 -WS=27 -PIPE=28 -QUOTED_STRING=29 -INTEGER_LITERAL=30 -DECIMAL_LITERAL=31 -BY=32 -AND=33 -ASC=34 -ASSIGN=35 -CAST_OP=36 -COLON=37 -COMMA=38 -DESC=39 -DOT=40 -FALSE=41 -FIRST=42 -IN=43 -IS=44 -LAST=45 -LIKE=46 -LP=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 -LEFT_BRACES=68 -RIGHT_BRACES=69 -NAMED_OR_POSITIONAL_PARAM=70 -OPENING_BRACKET=71 -CLOSING_BRACKET=72 -UNQUOTED_IDENTIFIER=73 -QUOTED_IDENTIFIER=74 -EXPR_LINE_COMMENT=75 -EXPR_MULTILINE_COMMENT=76 -EXPR_WS=77 -EXPLAIN_WS=78 -EXPLAIN_LINE_COMMENT=79 -EXPLAIN_MULTILINE_COMMENT=80 -METADATA=81 -UNQUOTED_SOURCE=82 -FROM_LINE_COMMENT=83 -FROM_MULTILINE_COMMENT=84 -FROM_WS=85 -ID_PATTERN=86 -PROJECT_LINE_COMMENT=87 -PROJECT_MULTILINE_COMMENT=88 -PROJECT_WS=89 -AS=90 -RENAME_LINE_COMMENT=91 -RENAME_MULTILINE_COMMENT=92 -RENAME_WS=93 -ON=94 -WITH=95 -ENRICH_POLICY_NAME=96 -ENRICH_LINE_COMMENT=97 -ENRICH_MULTILINE_COMMENT=98 -ENRICH_WS=99 -ENRICH_FIELD_LINE_COMMENT=100 -ENRICH_FIELD_MULTILINE_COMMENT=101 -ENRICH_FIELD_WS=102 -MVEXPAND_LINE_COMMENT=103 -MVEXPAND_MULTILINE_COMMENT=104 -MVEXPAND_WS=105 -INFO=106 -SHOW_LINE_COMMENT=107 -SHOW_MULTILINE_COMMENT=108 -SHOW_WS=109 -SETTING=110 -SETTING_LINE_COMMENT=111 -SETTTING_MULTILINE_COMMENT=112 -SETTING_WS=113 -LOOKUP_LINE_COMMENT=114 -LOOKUP_MULTILINE_COMMENT=115 -LOOKUP_WS=116 -LOOKUP_FIELD_LINE_COMMENT=117 -LOOKUP_FIELD_MULTILINE_COMMENT=118 -LOOKUP_FIELD_WS=119 -JOIN=120 -USING=121 -JOIN_LINE_COMMENT=122 -JOIN_MULTILINE_COMMENT=123 -JOIN_WS=124 -METRICS_LINE_COMMENT=125 -METRICS_MULTILINE_COMMENT=126 -METRICS_WS=127 -CLOSING_METRICS_LINE_COMMENT=128 -CLOSING_METRICS_MULTILINE_COMMENT=129 -CLOSING_METRICS_WS=130 +DEV_CHANGE_POINT=18 +DEV_INLINESTATS=19 +DEV_LOOKUP=20 +DEV_METRICS=21 +DEV_JOIN_FULL=22 +DEV_JOIN_LEFT=23 +DEV_JOIN_RIGHT=24 +UNKNOWN_CMD=25 +LINE_COMMENT=26 +MULTILINE_COMMENT=27 +WS=28 +PIPE=29 +QUOTED_STRING=30 +INTEGER_LITERAL=31 +DECIMAL_LITERAL=32 +BY=33 +AND=34 +ASC=35 +ASSIGN=36 +CAST_OP=37 +COLON=38 +COMMA=39 +DESC=40 +DOT=41 +FALSE=42 +FIRST=43 +IN=44 +IS=45 +LAST=46 +LIKE=47 +LP=48 +NOT=49 +NULL=50 +NULLS=51 +OR=52 +PARAM=53 +RLIKE=54 +RP=55 +TRUE=56 +EQ=57 +CIEQ=58 +NEQ=59 +LT=60 +LTE=61 +GT=62 +GTE=63 +PLUS=64 +MINUS=65 +ASTERISK=66 +SLASH=67 +PERCENT=68 +LEFT_BRACES=69 +RIGHT_BRACES=70 +NAMED_OR_POSITIONAL_PARAM=71 +OPENING_BRACKET=72 +CLOSING_BRACKET=73 +UNQUOTED_IDENTIFIER=74 +QUOTED_IDENTIFIER=75 +EXPR_LINE_COMMENT=76 +EXPR_MULTILINE_COMMENT=77 +EXPR_WS=78 +EXPLAIN_WS=79 +EXPLAIN_LINE_COMMENT=80 +EXPLAIN_MULTILINE_COMMENT=81 +METADATA=82 +UNQUOTED_SOURCE=83 +FROM_LINE_COMMENT=84 +FROM_MULTILINE_COMMENT=85 +FROM_WS=86 +ID_PATTERN=87 +PROJECT_LINE_COMMENT=88 +PROJECT_MULTILINE_COMMENT=89 +PROJECT_WS=90 +AS=91 +RENAME_LINE_COMMENT=92 +RENAME_MULTILINE_COMMENT=93 +RENAME_WS=94 +ON=95 +WITH=96 +ENRICH_POLICY_NAME=97 +ENRICH_LINE_COMMENT=98 +ENRICH_MULTILINE_COMMENT=99 +ENRICH_WS=100 +ENRICH_FIELD_LINE_COMMENT=101 +ENRICH_FIELD_MULTILINE_COMMENT=102 +ENRICH_FIELD_WS=103 +MVEXPAND_LINE_COMMENT=104 +MVEXPAND_MULTILINE_COMMENT=105 +MVEXPAND_WS=106 +INFO=107 +SHOW_LINE_COMMENT=108 +SHOW_MULTILINE_COMMENT=109 +SHOW_WS=110 +SETTING=111 +SETTING_LINE_COMMENT=112 +SETTTING_MULTILINE_COMMENT=113 +SETTING_WS=114 +LOOKUP_LINE_COMMENT=115 +LOOKUP_MULTILINE_COMMENT=116 +LOOKUP_WS=117 +LOOKUP_FIELD_LINE_COMMENT=118 +LOOKUP_FIELD_MULTILINE_COMMENT=119 +LOOKUP_FIELD_WS=120 +JOIN=121 +USING=122 +JOIN_LINE_COMMENT=123 +JOIN_MULTILINE_COMMENT=124 +JOIN_WS=125 +METRICS_LINE_COMMENT=126 +METRICS_MULTILINE_COMMENT=127 +METRICS_WS=128 +CLOSING_METRICS_LINE_COMMENT=129 +CLOSING_METRICS_MULTILINE_COMMENT=130 +CLOSING_METRICS_WS=131 +CHANGE_POINT_LINE_COMMENT=132 +CHANGE_POINT_MULTILINE_COMMENT=133 +CHANGE_POINT_WS=134 'dissect'=1 'drop'=2 'enrich'=3 @@ -145,50 +149,50 @@ CLOSING_METRICS_WS=130 'stats'=15 'where'=16 'lookup'=17 -'|'=28 -'by'=32 -'and'=33 -'asc'=34 -'='=35 -'::'=36 -':'=37 -','=38 -'desc'=39 -'.'=40 -'false'=41 -'first'=42 -'in'=43 -'is'=44 -'last'=45 -'like'=46 -'('=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 -'{'=68 -'}'=69 -']'=72 -'metadata'=81 -'as'=90 -'on'=94 -'with'=95 -'info'=106 -'join'=120 -'USING'=121 +'|'=29 +'by'=33 +'and'=34 +'asc'=35 +'='=36 +'::'=37 +':'=38 +','=39 +'desc'=40 +'.'=41 +'false'=42 +'first'=43 +'in'=44 +'is'=45 +'last'=46 +'like'=47 +'('=48 +'not'=49 +'null'=50 +'nulls'=51 +'or'=52 +'?'=53 +'rlike'=54 +')'=55 +'true'=56 +'=='=57 +'=~'=58 +'!='=59 +'<'=60 +'<='=61 +'>'=62 +'>='=63 +'+'=64 +'-'=65 +'*'=66 +'/'=67 +'%'=68 +'{'=69 +'}'=70 +']'=73 +'metadata'=82 +'as'=91 +'on'=95 +'with'=96 +'info'=107 +'join'=121 +'USING'=122 diff --git a/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4 b/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4 index 9ea0d67b3801..3e30dd0cb4a0 100644 --- a/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4 +++ b/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4 @@ -55,6 +55,7 @@ processingCommand // in development | {this.isDevVersion()}? inlinestatsCommand | {this.isDevVersion()}? lookupCommand + | {this.isDevVersion()}? changePointCommand ; whereCommand @@ -143,6 +144,7 @@ indexPattern clusterString : UNQUOTED_SOURCE + | QUOTED_STRING ; indexString @@ -193,7 +195,7 @@ identifier identifierPattern : ID_PATTERN - | {this.isDevVersion()}? parameter + | parameter ; constant @@ -216,7 +218,7 @@ parameter identifierOrParameter : identifier - | {this.isDevVersion()}? parameter + | parameter ; limitCommand @@ -338,3 +340,7 @@ joinCondition joinPredicate : valueExpression ; + +changePointCommand + : DEV_CHANGE_POINT value=qualifiedName (ON key=qualifiedName)? (AS targetType=qualifiedName COMMA targetPvalue=qualifiedName)? + ; diff --git a/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.tokens b/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.tokens index 02af324872fc..7ab99c293bc9 100644 --- a/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.tokens +++ b/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.tokens @@ -15,119 +15,123 @@ SORT=14 STATS=15 WHERE=16 JOIN_LOOKUP=17 -DEV_INLINESTATS=18 -DEV_LOOKUP=19 -DEV_METRICS=20 -DEV_JOIN_FULL=21 -DEV_JOIN_LEFT=22 -DEV_JOIN_RIGHT=23 -UNKNOWN_CMD=24 -LINE_COMMENT=25 -MULTILINE_COMMENT=26 -WS=27 -PIPE=28 -QUOTED_STRING=29 -INTEGER_LITERAL=30 -DECIMAL_LITERAL=31 -BY=32 -AND=33 -ASC=34 -ASSIGN=35 -CAST_OP=36 -COLON=37 -COMMA=38 -DESC=39 -DOT=40 -FALSE=41 -FIRST=42 -IN=43 -IS=44 -LAST=45 -LIKE=46 -LP=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 -LEFT_BRACES=68 -RIGHT_BRACES=69 -NAMED_OR_POSITIONAL_PARAM=70 -OPENING_BRACKET=71 -CLOSING_BRACKET=72 -UNQUOTED_IDENTIFIER=73 -QUOTED_IDENTIFIER=74 -EXPR_LINE_COMMENT=75 -EXPR_MULTILINE_COMMENT=76 -EXPR_WS=77 -EXPLAIN_WS=78 -EXPLAIN_LINE_COMMENT=79 -EXPLAIN_MULTILINE_COMMENT=80 -METADATA=81 -UNQUOTED_SOURCE=82 -FROM_LINE_COMMENT=83 -FROM_MULTILINE_COMMENT=84 -FROM_WS=85 -ID_PATTERN=86 -PROJECT_LINE_COMMENT=87 -PROJECT_MULTILINE_COMMENT=88 -PROJECT_WS=89 -AS=90 -RENAME_LINE_COMMENT=91 -RENAME_MULTILINE_COMMENT=92 -RENAME_WS=93 -ON=94 -WITH=95 -ENRICH_POLICY_NAME=96 -ENRICH_LINE_COMMENT=97 -ENRICH_MULTILINE_COMMENT=98 -ENRICH_WS=99 -ENRICH_FIELD_LINE_COMMENT=100 -ENRICH_FIELD_MULTILINE_COMMENT=101 -ENRICH_FIELD_WS=102 -MVEXPAND_LINE_COMMENT=103 -MVEXPAND_MULTILINE_COMMENT=104 -MVEXPAND_WS=105 -INFO=106 -SHOW_LINE_COMMENT=107 -SHOW_MULTILINE_COMMENT=108 -SHOW_WS=109 -SETTING=110 -SETTING_LINE_COMMENT=111 -SETTTING_MULTILINE_COMMENT=112 -SETTING_WS=113 -LOOKUP_LINE_COMMENT=114 -LOOKUP_MULTILINE_COMMENT=115 -LOOKUP_WS=116 -LOOKUP_FIELD_LINE_COMMENT=117 -LOOKUP_FIELD_MULTILINE_COMMENT=118 -LOOKUP_FIELD_WS=119 -JOIN=120 -USING=121 -JOIN_LINE_COMMENT=122 -JOIN_MULTILINE_COMMENT=123 -JOIN_WS=124 -METRICS_LINE_COMMENT=125 -METRICS_MULTILINE_COMMENT=126 -METRICS_WS=127 -CLOSING_METRICS_LINE_COMMENT=128 -CLOSING_METRICS_MULTILINE_COMMENT=129 -CLOSING_METRICS_WS=130 +DEV_CHANGE_POINT=18 +DEV_INLINESTATS=19 +DEV_LOOKUP=20 +DEV_METRICS=21 +DEV_JOIN_FULL=22 +DEV_JOIN_LEFT=23 +DEV_JOIN_RIGHT=24 +UNKNOWN_CMD=25 +LINE_COMMENT=26 +MULTILINE_COMMENT=27 +WS=28 +PIPE=29 +QUOTED_STRING=30 +INTEGER_LITERAL=31 +DECIMAL_LITERAL=32 +BY=33 +AND=34 +ASC=35 +ASSIGN=36 +CAST_OP=37 +COLON=38 +COMMA=39 +DESC=40 +DOT=41 +FALSE=42 +FIRST=43 +IN=44 +IS=45 +LAST=46 +LIKE=47 +LP=48 +NOT=49 +NULL=50 +NULLS=51 +OR=52 +PARAM=53 +RLIKE=54 +RP=55 +TRUE=56 +EQ=57 +CIEQ=58 +NEQ=59 +LT=60 +LTE=61 +GT=62 +GTE=63 +PLUS=64 +MINUS=65 +ASTERISK=66 +SLASH=67 +PERCENT=68 +LEFT_BRACES=69 +RIGHT_BRACES=70 +NAMED_OR_POSITIONAL_PARAM=71 +OPENING_BRACKET=72 +CLOSING_BRACKET=73 +UNQUOTED_IDENTIFIER=74 +QUOTED_IDENTIFIER=75 +EXPR_LINE_COMMENT=76 +EXPR_MULTILINE_COMMENT=77 +EXPR_WS=78 +EXPLAIN_WS=79 +EXPLAIN_LINE_COMMENT=80 +EXPLAIN_MULTILINE_COMMENT=81 +METADATA=82 +UNQUOTED_SOURCE=83 +FROM_LINE_COMMENT=84 +FROM_MULTILINE_COMMENT=85 +FROM_WS=86 +ID_PATTERN=87 +PROJECT_LINE_COMMENT=88 +PROJECT_MULTILINE_COMMENT=89 +PROJECT_WS=90 +AS=91 +RENAME_LINE_COMMENT=92 +RENAME_MULTILINE_COMMENT=93 +RENAME_WS=94 +ON=95 +WITH=96 +ENRICH_POLICY_NAME=97 +ENRICH_LINE_COMMENT=98 +ENRICH_MULTILINE_COMMENT=99 +ENRICH_WS=100 +ENRICH_FIELD_LINE_COMMENT=101 +ENRICH_FIELD_MULTILINE_COMMENT=102 +ENRICH_FIELD_WS=103 +MVEXPAND_LINE_COMMENT=104 +MVEXPAND_MULTILINE_COMMENT=105 +MVEXPAND_WS=106 +INFO=107 +SHOW_LINE_COMMENT=108 +SHOW_MULTILINE_COMMENT=109 +SHOW_WS=110 +SETTING=111 +SETTING_LINE_COMMENT=112 +SETTTING_MULTILINE_COMMENT=113 +SETTING_WS=114 +LOOKUP_LINE_COMMENT=115 +LOOKUP_MULTILINE_COMMENT=116 +LOOKUP_WS=117 +LOOKUP_FIELD_LINE_COMMENT=118 +LOOKUP_FIELD_MULTILINE_COMMENT=119 +LOOKUP_FIELD_WS=120 +JOIN=121 +USING=122 +JOIN_LINE_COMMENT=123 +JOIN_MULTILINE_COMMENT=124 +JOIN_WS=125 +METRICS_LINE_COMMENT=126 +METRICS_MULTILINE_COMMENT=127 +METRICS_WS=128 +CLOSING_METRICS_LINE_COMMENT=129 +CLOSING_METRICS_MULTILINE_COMMENT=130 +CLOSING_METRICS_WS=131 +CHANGE_POINT_LINE_COMMENT=132 +CHANGE_POINT_MULTILINE_COMMENT=133 +CHANGE_POINT_WS=134 'dissect'=1 'drop'=2 'enrich'=3 @@ -145,50 +149,50 @@ CLOSING_METRICS_WS=130 'stats'=15 'where'=16 'lookup'=17 -'|'=28 -'by'=32 -'and'=33 -'asc'=34 -'='=35 -'::'=36 -':'=37 -','=38 -'desc'=39 -'.'=40 -'false'=41 -'first'=42 -'in'=43 -'is'=44 -'last'=45 -'like'=46 -'('=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 -'{'=68 -'}'=69 -']'=72 -'metadata'=81 -'as'=90 -'on'=94 -'with'=95 -'info'=106 -'join'=120 -'USING'=121 +'|'=29 +'by'=33 +'and'=34 +'asc'=35 +'='=36 +'::'=37 +':'=38 +','=39 +'desc'=40 +'.'=41 +'false'=42 +'first'=43 +'in'=44 +'is'=45 +'last'=46 +'like'=47 +'('=48 +'not'=49 +'null'=50 +'nulls'=51 +'or'=52 +'?'=53 +'rlike'=54 +')'=55 +'true'=56 +'=='=57 +'=~'=58 +'!='=59 +'<'=60 +'<='=61 +'>'=62 +'>='=63 +'+'=64 +'-'=65 +'*'=66 +'/'=67 +'%'=68 +'{'=69 +'}'=70 +']'=73 +'metadata'=82 +'as'=91 +'on'=95 +'with'=96 +'info'=107 +'join'=121 +'USING'=122 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 b7ec21b96be3..0b9b0995d3ba 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 @@ -675,7 +675,7 @@ public class EsqlCapabilities { /** * Support simplified syntax for named parameters for field and function names. */ - NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX(Build.current().isSnapshot()), + NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX(), /** * Fix pushdown of LIMIT past MV_EXPAND @@ -791,7 +791,24 @@ public class EsqlCapabilities { /** * Support for aggregate_metric_double type */ - AGGREGATE_METRIC_DOUBLE(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG.isEnabled()); + AGGREGATE_METRIC_DOUBLE(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG), + + /** + * Support for partial subset of metrics in aggregate_metric_double type + */ + AGGREGATE_METRIC_DOUBLE_PARTIAL_SUBMETRICS(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG), + + /** + * Support change point detection "CHANGE_POINT". + */ + CHANGE_POINT(Build.current().isSnapshot()), + + /** + * Fix for https://github.com/elastic/elasticsearch/issues/120817 + * and https://github.com/elastic/elasticsearch/issues/120803 + * Support for queries that have multiple SORTs that cannot become TopN + */ + REMOVE_REDUNDANT_SORT; private final boolean enabled; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/RequestXContent.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/RequestXContent.java index d8904288523a..e77d7b41aaca 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/RequestXContent.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/RequestXContent.java @@ -171,8 +171,7 @@ final class RequestXContent { String paramName = entry.getKey(); checkParamNameValidity(paramName, errors, loc); - if (EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - && entry.getValue() instanceof Map value) {// parameter specified as a key:value pair + if (entry.getValue() instanceof Map value) {// parameter specified as a key:value pair checkParamValueSize(paramName, value, loc, errors); for (Object keyName : value.keySet()) { classification = getParamClassification(keyName.toString(), errors, loc); diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/EnrichLookupOperator.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/EnrichLookupOperator.java index 8083d67e5a19..0dc8c76b39f5 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/EnrichLookupOperator.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/EnrichLookupOperator.java @@ -175,8 +175,8 @@ public final class EnrichLookupOperator extends AsyncOperator { } @Override - protected Operator.Status status(long receivedPages, long completedPages, long totalTimeInMillis) { - return new EnrichLookupOperator.Status(receivedPages, completedPages, totalTimeInMillis, totalTerms); + protected Operator.Status status(long receivedPages, long completedPages, long processNanos) { + return new EnrichLookupOperator.Status(receivedPages, completedPages, processNanos, totalTerms); } public static class Status extends AsyncOperator.Status { @@ -188,8 +188,8 @@ public final class EnrichLookupOperator extends AsyncOperator { final long totalTerms; - Status(long receivedPages, long completedPages, long totalTimeInMillis, long totalTerms) { - super(receivedPages, completedPages, totalTimeInMillis); + Status(long receivedPages, long completedPages, long processNanos, long totalTerms) { + super(receivedPages, completedPages, processNanos); this.totalTerms = totalTerms; } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/LookupFromIndexOperator.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/LookupFromIndexOperator.java index e966b1346e28..f5a9b91790ce 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/LookupFromIndexOperator.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/LookupFromIndexOperator.java @@ -217,8 +217,8 @@ public final class LookupFromIndexOperator extends AsyncOperator constructor = constructorFor(def.clazz()); if (constructor == null) { - return new FunctionDescription(def.name(), List.of(), null, null, false, false); + return new FunctionDescription(def.name(), List.of(), null, null, false, FunctionType.SCALAR); } FunctionInfo functionInfo = functionInfo(def); String functionDescription = functionInfo == null ? "" : functionInfo.description().replace('\n', ' '); @@ -635,7 +635,6 @@ public class EsqlFunctionRegistry { List args = new ArrayList<>(params.length); boolean variadic = false; - boolean isAggregation = functionInfo != null && functionInfo.isAggregation(); for (int i = 1; i < params.length; i++) { // skipping 1st argument, the source if (Configuration.class.isAssignableFrom(params[i].getType()) == false) { variadic |= List.class.isAssignableFrom(params[i].getType()); @@ -648,7 +647,7 @@ public class EsqlFunctionRegistry { } } } - return new FunctionDescription(def.name(), args, returnType, functionDescription, variadic, isAggregation); + return new FunctionDescription(def.name(), args, returnType, functionDescription, variadic, functionInfo.type()); } public static ArgSignature param(Param param) { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionDoc.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionDoc.java deleted file mode 100644 index f6514c2a44ec..000000000000 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionDoc.java +++ /dev/null @@ -1,37 +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.expression.function; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE }) -public @interface FunctionDoc { - enum FunctionType { - AGGREGATE, - DATE_TIME, - MATH, - STRING, - } - - FunctionType type(); - - String description(); - - String synopsis(); - - String[] arguments() default {}; - - String output(); - - String examples(); - -} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionInfo.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionInfo.java index f3cdd324769e..5c5c2f26279a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionInfo.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionInfo.java @@ -66,9 +66,9 @@ public @interface FunctionInfo { String appendix() default ""; /** - * Is this an aggregation (true) or a scalar function (false). + * The position the function can appear in the language. */ - boolean isAggregation() default false; + FunctionType type() default FunctionType.SCALAR; /** * Examples of using this function that are rendered in the docs. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionType.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionType.java new file mode 100644 index 000000000000..876ac48eacaf --- /dev/null +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionType.java @@ -0,0 +1,29 @@ +/* + * 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; + +/** + * The position the function can appear in the language. + */ +public enum FunctionType { + /** + * Functions that can appear anywhere. For example, {@code LENGTH} in + * {@code | STATS MAX(LENGTH(string))} and {@code | EVAL l = LENGTH(string)}. + */ + SCALAR, + /** + * Functions that can only appear in the "aggregate" position of a {@code STATS}. + * For example, {@code MAX} in {@code | STATS MAX(LENGTH(string))}. + */ + AGGREGATE, + /** + * Functions that can only appear in the "grouping" position of a {@code STATS}. + * For example, {@code CATEGORIZE} in {@code | STATS MAX(a) BY CATEGORIZE(message)}. + */ + GROUPING, +} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Avg.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Avg.java index 82c0f9d24899..41feee0e6366 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Avg.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Avg.java @@ -17,6 +17,7 @@ import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvAvg; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Div; @@ -34,7 +35,7 @@ public class Avg extends AggregateFunction implements SurrogateExpression { @FunctionInfo( returnType = "double", description = "The average of a numeric field.", - isAggregation = true, + type = FunctionType.AGGREGATE, examples = { @Example(file = "stats", tag = "avg"), @Example( diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Count.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Count.java index 5ce43c7b3872..1d6a88ddcec3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Count.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Count.java @@ -22,6 +22,7 @@ import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.FromAggregateMetricDouble; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvCount; @@ -42,7 +43,7 @@ public class Count extends AggregateFunction implements ToAggregator, SurrogateE @FunctionInfo( returnType = "long", description = "Returns the total number (count) of input values.", - isAggregation = true, + type = FunctionType.AGGREGATE, examples = { @Example(file = "stats", tag = "count"), @Example(description = "To count the number of rows, use `COUNT()` or `COUNT(*)`", file = "docs", tag = "countAll"), @@ -126,8 +127,8 @@ public class Count extends AggregateFunction implements ToAggregator, SurrogateE } @Override - public AggregatorFunctionSupplier supplier(List inputChannels) { - return CountAggregatorFunction.supplier(inputChannels); + public AggregatorFunctionSupplier supplier() { + return CountAggregatorFunction.supplier(); } @Override diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java index 3170ae8f132c..f97ead54c7be 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java @@ -28,6 +28,7 @@ import org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.OptionalArgument; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToLong; @@ -40,7 +41,7 @@ import org.elasticsearch.xpack.esql.planner.ToAggregator; import java.io.IOException; import java.util.List; import java.util.Map; -import java.util.function.BiFunction; +import java.util.function.Function; import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; @@ -56,9 +57,9 @@ public class CountDistinct extends AggregateFunction implements OptionalArgument CountDistinct::new ); - private static final Map, Integer, AggregatorFunctionSupplier>> SUPPLIERS = Map.ofEntries( + private static final Map> SUPPLIERS = Map.ofEntries( // Booleans ignore the precision because there are only two possible values anyway - Map.entry(DataType.BOOLEAN, (inputChannels, precision) -> new CountDistinctBooleanAggregatorFunctionSupplier(inputChannels)), + Map.entry(DataType.BOOLEAN, (precision) -> new CountDistinctBooleanAggregatorFunctionSupplier()), Map.entry(DataType.LONG, CountDistinctLongAggregatorFunctionSupplier::new), Map.entry(DataType.DATETIME, CountDistinctLongAggregatorFunctionSupplier::new), Map.entry(DataType.DATE_NANOS, CountDistinctLongAggregatorFunctionSupplier::new), @@ -101,7 +102,7 @@ public class CountDistinct extends AggregateFunction implements OptionalArgument maximum supported value is 40000, thresholds above this number will have the same effect as a threshold of 40000. The default value is `3000`. """, - isAggregation = true, + type = FunctionType.AGGREGATE, examples = { @Example(file = "stats_count_distinct", tag = "count-distinct"), @Example( @@ -209,7 +210,7 @@ public class CountDistinct extends AggregateFunction implements OptionalArgument } @Override - public AggregatorFunctionSupplier supplier(List inputChannels) { + public AggregatorFunctionSupplier supplier() { DataType type = field().dataType(); int precision = this.precision == null ? DEFAULT_PRECISION @@ -218,7 +219,7 @@ public class CountDistinct extends AggregateFunction implements OptionalArgument // If the type checking did its job, this should never happen throw EsqlIllegalArgumentException.illegalDataType(type); } - return SUPPLIERS.get(type).apply(inputChannels, precision); + return SUPPLIERS.get(type).apply(precision); } @Override diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/FromPartial.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/FromPartial.java index a67b87c7617c..bb9ed1780053 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/FromPartial.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/FromPartial.java @@ -19,6 +19,7 @@ import org.elasticsearch.compute.aggregation.FromPartialAggregatorFunction; import org.elasticsearch.compute.aggregation.FromPartialGroupingAggregatorFunction; import org.elasticsearch.compute.aggregation.GroupingAggregator; import org.elasticsearch.compute.aggregation.GroupingAggregatorFunction; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.xpack.esql.core.expression.AttributeSet; import org.elasticsearch.xpack.esql.core.expression.Expression; @@ -110,38 +111,44 @@ public class FromPartial extends AggregateFunction implements ToAggregator { } @Override - public AggregatorFunctionSupplier supplier(List inputChannels) { - final ToAggregator toAggregator = (ToAggregator) function; - if (inputChannels.size() != 1) { - assert false : "from_partial aggregation requires exactly one input channel; got " + inputChannels; - throw new IllegalArgumentException("from_partial aggregation requires exactly one input channel; got " + inputChannels); - } - final int inputChannel = inputChannels.get(0); + public AggregatorFunctionSupplier supplier() { + final AggregatorFunctionSupplier supplier = ((ToAggregator) function).supplier(); return new AggregatorFunctionSupplier() { @Override - public AggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return FromPartialAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return FromPartialGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public AggregatorFunction aggregator(DriverContext driverContext, List channels) { assert false : "aggregatorFactory() is override"; throw new UnsupportedOperationException(); } @Override - public GroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public GroupingAggregatorFunction groupingAggregator(DriverContext driverContext, List channels) { assert false : "groupingAggregatorFactory() is override"; throw new UnsupportedOperationException(); } @Override - public Aggregator.Factory aggregatorFactory(AggregatorMode mode) { - final AggregatorFunctionSupplier supplier; - try (var dummy = toAggregator.supplier(inputChannels).aggregator(DriverContext.getLocalDriver())) { - var intermediateChannels = IntStream.range(0, dummy.intermediateBlockCount()).boxed().toList(); - supplier = toAggregator.supplier(intermediateChannels); + public Aggregator.Factory aggregatorFactory(AggregatorMode mode, List channels) { + if (channels.size() != 1) { + assert false : "from_partial aggregation requires exactly one input channel; got " + channels; + throw new IllegalArgumentException("from_partial aggregation requires exactly one input channel; got " + channels); } + final int inputChannel = channels.get(0); + var intermediateChannels = IntStream.range(0, supplier.nonGroupingIntermediateStateDesc().size()).boxed().toList(); return new Aggregator.Factory() { @Override public Aggregator apply(DriverContext driverContext) { // use groupingAggregator since we can receive intermediate output from a grouping aggregate - final var groupingAggregator = supplier.groupingAggregator(driverContext); + final var groupingAggregator = supplier.groupingAggregator(driverContext, intermediateChannels); return new Aggregator(new FromPartialAggregatorFunction(driverContext, groupingAggregator, inputChannel), mode); } @@ -153,16 +160,17 @@ public class FromPartial extends AggregateFunction implements ToAggregator { } @Override - public GroupingAggregator.Factory groupingAggregatorFactory(AggregatorMode mode) { - final AggregatorFunctionSupplier supplier; - try (var dummy = toAggregator.supplier(inputChannels).aggregator(DriverContext.getLocalDriver())) { - var intermediateChannels = IntStream.range(0, dummy.intermediateBlockCount()).boxed().toList(); - supplier = toAggregator.supplier(intermediateChannels); + public GroupingAggregator.Factory groupingAggregatorFactory(AggregatorMode mode, List channels) { + if (channels.size() != 1) { + assert false : "from_partial aggregation requires exactly one input channel; got " + channels; + throw new IllegalArgumentException("from_partial aggregation requires exactly one input channel; got " + channels); } + final int inputChannel = channels.get(0); + var intermediateChannels = IntStream.range(0, supplier.nonGroupingIntermediateStateDesc().size()).boxed().toList(); return new GroupingAggregator.Factory() { @Override public GroupingAggregator apply(DriverContext driverContext) { - final GroupingAggregatorFunction aggregator = supplier.groupingAggregator(driverContext); + final GroupingAggregatorFunction aggregator = supplier.groupingAggregator(driverContext, intermediateChannels); return new GroupingAggregator(new FromPartialGroupingAggregatorFunction(aggregator, inputChannel), mode); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Max.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Max.java index 6a8ce792ec8c..be08627a4fd6 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Max.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Max.java @@ -27,6 +27,7 @@ import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.FromAggregateMetricDouble; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvMax; @@ -35,7 +36,7 @@ import org.elasticsearch.xpack.esql.planner.ToAggregator; import java.io.IOException; import java.util.List; import java.util.Map; -import java.util.function.Function; +import java.util.function.Supplier; import static java.util.Collections.emptyList; import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; @@ -43,7 +44,7 @@ import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.Param public class Max extends AggregateFunction implements ToAggregator, SurrogateExpression { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "Max", Max::new); - private static final Map, AggregatorFunctionSupplier>> SUPPLIERS = Map.ofEntries( + private static final Map> SUPPLIERS = Map.ofEntries( Map.entry(DataType.BOOLEAN, MaxBooleanAggregatorFunctionSupplier::new), Map.entry(DataType.LONG, MaxLongAggregatorFunctionSupplier::new), Map.entry(DataType.DATETIME, MaxLongAggregatorFunctionSupplier::new), @@ -60,7 +61,7 @@ public class Max extends AggregateFunction implements ToAggregator, SurrogateExp @FunctionInfo( returnType = { "boolean", "double", "integer", "long", "date", "date_nanos", "ip", "keyword", "long", "version" }, description = "The maximum value of a field.", - isAggregation = true, + type = FunctionType.AGGREGATE, examples = { @Example(file = "stats", tag = "max"), @Example( @@ -141,13 +142,13 @@ public class Max extends AggregateFunction implements ToAggregator, SurrogateExp } @Override - public final AggregatorFunctionSupplier supplier(List inputChannels) { + public final AggregatorFunctionSupplier supplier() { DataType type = field().dataType(); if (SUPPLIERS.containsKey(type) == false) { // If the type checking did its job, this should never happen throw EsqlIllegalArgumentException.illegalDataType(type); } - return SUPPLIERS.get(type).apply(inputChannels); + return SUPPLIERS.get(type).get(); } @Override diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Median.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Median.java index c47fa612c1c4..41f3ea0efea0 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Median.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Median.java @@ -18,6 +18,7 @@ import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToDouble; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvMedian; @@ -44,7 +45,7 @@ public class Median extends AggregateFunction implements SurrogateExpression { `MEDIAN` is also {wikipedia}/Nondeterministic_algorithm[non-deterministic]. This means you can get slightly different results using the same data. ====""", - isAggregation = true, + type = FunctionType.AGGREGATE, examples = { @Example(file = "stats_percentile", tag = "median"), @Example( diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/MedianAbsoluteDeviation.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/MedianAbsoluteDeviation.java index 42960cafdfd3..5c7db4e31502 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/MedianAbsoluteDeviation.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/MedianAbsoluteDeviation.java @@ -20,6 +20,7 @@ import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToDouble; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvMedianAbsoluteDeviation; @@ -54,7 +55,7 @@ public class MedianAbsoluteDeviation extends NumericAggregate implements Surroga `MEDIAN_ABSOLUTE_DEVIATION` is also {wikipedia}/Nondeterministic_algorithm[non-deterministic]. This means you can get slightly different results using the same data. ====""", - isAggregation = true, + type = FunctionType.AGGREGATE, examples = { @Example(file = "median_absolute_deviation", tag = "median-absolute-deviation"), @Example( @@ -99,18 +100,18 @@ public class MedianAbsoluteDeviation extends NumericAggregate implements Surroga } @Override - protected AggregatorFunctionSupplier longSupplier(List inputChannels) { - return new MedianAbsoluteDeviationLongAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier longSupplier() { + return new MedianAbsoluteDeviationLongAggregatorFunctionSupplier(); } @Override - protected AggregatorFunctionSupplier intSupplier(List inputChannels) { - return new MedianAbsoluteDeviationIntAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier intSupplier() { + return new MedianAbsoluteDeviationIntAggregatorFunctionSupplier(); } @Override - protected AggregatorFunctionSupplier doubleSupplier(List inputChannels) { - return new MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier doubleSupplier() { + return new MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Min.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Min.java index f2ae1292e47e..1b1c4ea7b029 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Min.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Min.java @@ -27,6 +27,7 @@ import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.FromAggregateMetricDouble; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvMin; @@ -35,7 +36,7 @@ import org.elasticsearch.xpack.esql.planner.ToAggregator; import java.io.IOException; import java.util.List; import java.util.Map; -import java.util.function.Function; +import java.util.function.Supplier; import static java.util.Collections.emptyList; import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; @@ -43,7 +44,7 @@ import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.Param public class Min extends AggregateFunction implements ToAggregator, SurrogateExpression { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "Min", Min::new); - private static final Map, AggregatorFunctionSupplier>> SUPPLIERS = Map.ofEntries( + private static final Map> SUPPLIERS = Map.ofEntries( Map.entry(DataType.BOOLEAN, MinBooleanAggregatorFunctionSupplier::new), Map.entry(DataType.LONG, MinLongAggregatorFunctionSupplier::new), Map.entry(DataType.DATETIME, MinLongAggregatorFunctionSupplier::new), @@ -60,7 +61,7 @@ public class Min extends AggregateFunction implements ToAggregator, SurrogateExp @FunctionInfo( returnType = { "boolean", "double", "integer", "long", "date", "date_nanos", "ip", "keyword", "long", "version" }, description = "The minimum value of a field.", - isAggregation = true, + type = FunctionType.AGGREGATE, examples = { @Example(file = "stats", tag = "min"), @Example( @@ -141,13 +142,13 @@ public class Min extends AggregateFunction implements ToAggregator, SurrogateExp } @Override - public final AggregatorFunctionSupplier supplier(List inputChannels) { + public final AggregatorFunctionSupplier supplier() { DataType type = field().dataType(); if (SUPPLIERS.containsKey(type) == false) { // If the type checking did its job, this should never happen throw EsqlIllegalArgumentException.illegalDataType(type); } - return SUPPLIERS.get(type).apply(inputChannels); + return SUPPLIERS.get(type).get(); } @Override diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/NumericAggregate.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/NumericAggregate.java index 5c639c465c64..3289e1aded4e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/NumericAggregate.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/NumericAggregate.java @@ -92,26 +92,26 @@ public abstract class NumericAggregate extends AggregateFunction implements ToAg } @Override - public final AggregatorFunctionSupplier supplier(List inputChannels) { + public final AggregatorFunctionSupplier supplier() { DataType type = field().dataType(); if (supportsDates() && type == DataType.DATETIME) { - return longSupplier(inputChannels); + return longSupplier(); } if (type == DataType.LONG) { - return longSupplier(inputChannels); + return longSupplier(); } if (type == DataType.INTEGER) { - return intSupplier(inputChannels); + return intSupplier(); } if (type == DataType.DOUBLE) { - return doubleSupplier(inputChannels); + return doubleSupplier(); } throw EsqlIllegalArgumentException.illegalDataType(type); } - protected abstract AggregatorFunctionSupplier longSupplier(List inputChannels); + protected abstract AggregatorFunctionSupplier longSupplier(); - protected abstract AggregatorFunctionSupplier intSupplier(List inputChannels); + protected abstract AggregatorFunctionSupplier intSupplier(); - protected abstract AggregatorFunctionSupplier doubleSupplier(List inputChannels); + protected abstract AggregatorFunctionSupplier doubleSupplier(); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java index 8c943c991d50..fb61db603486 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java @@ -24,6 +24,7 @@ import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToDouble; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvPercentile; @@ -65,7 +66,7 @@ public class Percentile extends NumericAggregate implements SurrogateExpression This means you can get slightly different results using the same data. ==== """, - isAggregation = true, + type = FunctionType.AGGREGATE, examples = { @Example(file = "stats_percentile", tag = "percentile"), @Example( @@ -156,18 +157,18 @@ public class Percentile extends NumericAggregate implements SurrogateExpression } @Override - protected AggregatorFunctionSupplier longSupplier(List inputChannels) { - return new PercentileLongAggregatorFunctionSupplier(inputChannels, percentileValue()); + protected AggregatorFunctionSupplier longSupplier() { + return new PercentileLongAggregatorFunctionSupplier(percentileValue()); } @Override - protected AggregatorFunctionSupplier intSupplier(List inputChannels) { - return new PercentileIntAggregatorFunctionSupplier(inputChannels, percentileValue()); + protected AggregatorFunctionSupplier intSupplier() { + return new PercentileIntAggregatorFunctionSupplier(percentileValue()); } @Override - protected AggregatorFunctionSupplier doubleSupplier(List inputChannels) { - return new PercentileDoubleAggregatorFunctionSupplier(inputChannels, percentileValue()); + protected AggregatorFunctionSupplier doubleSupplier() { + return new PercentileDoubleAggregatorFunctionSupplier(percentileValue()); } private int percentileValue() { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Rate.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Rate.java index 85ae65b6c5dc..ae385da4c86e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Rate.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Rate.java @@ -25,6 +25,7 @@ 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.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.OptionalArgument; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput; @@ -49,7 +50,7 @@ public class Rate extends AggregateFunction implements OptionalArgument, ToAggre @FunctionInfo( returnType = { "double" }, description = "compute the rate of a counter field. Available in METRICS command only", - isAggregation = true + type = FunctionType.AGGREGATE ) public Rate( Source source, @@ -168,16 +169,13 @@ public class Rate extends AggregateFunction implements OptionalArgument, ToAggre } @Override - public AggregatorFunctionSupplier supplier(List inputChannels) { - if (inputChannels.size() != 2 && inputChannels.size() != 3) { - throw new IllegalArgumentException("rate requires two for raw input or three channels for partial input; got " + inputChannels); - } + public AggregatorFunctionSupplier supplier() { final long unitInMillis = unitInMillis(); final DataType type = field().dataType(); return switch (type) { - case COUNTER_LONG -> new RateLongAggregatorFunctionSupplier(inputChannels, unitInMillis); - case COUNTER_INTEGER -> new RateIntAggregatorFunctionSupplier(inputChannels, unitInMillis); - case COUNTER_DOUBLE -> new RateDoubleAggregatorFunctionSupplier(inputChannels, unitInMillis); + case COUNTER_LONG -> new RateLongAggregatorFunctionSupplier(unitInMillis); + case COUNTER_INTEGER -> new RateIntAggregatorFunctionSupplier(unitInMillis); + case COUNTER_DOUBLE -> new RateDoubleAggregatorFunctionSupplier(unitInMillis); default -> throw EsqlIllegalArgumentException.illegalDataType(type); }; } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialCentroid.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialCentroid.java index fad308e38cb2..70f264129a06 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialCentroid.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialCentroid.java @@ -22,6 +22,7 @@ import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.ToAggregator; @@ -45,7 +46,7 @@ public class SpatialCentroid extends SpatialAggregateFunction implements ToAggre @FunctionInfo( returnType = { "geo_point", "cartesian_point" }, description = "Calculate the spatial centroid over a field with spatial point geometry type.", - isAggregation = true, + type = FunctionType.AGGREGATE, examples = @Example(file = "spatial", tag = "st_centroid_agg-airports") ) public SpatialCentroid(Source source, @Param(name = "field", type = { "geo_point", "cartesian_point" }) Expression field) { @@ -98,16 +99,16 @@ public class SpatialCentroid extends SpatialAggregateFunction implements ToAggre } @Override - public AggregatorFunctionSupplier supplier(List inputChannels) { + public AggregatorFunctionSupplier supplier() { DataType type = field().dataType(); return switch (type) { case DataType.GEO_POINT -> switch (fieldExtractPreference) { - case DOC_VALUES -> new SpatialCentroidGeoPointDocValuesAggregatorFunctionSupplier(inputChannels); - case NONE, EXTRACT_SPATIAL_BOUNDS -> new SpatialCentroidGeoPointSourceValuesAggregatorFunctionSupplier(inputChannels); + case DOC_VALUES -> new SpatialCentroidGeoPointDocValuesAggregatorFunctionSupplier(); + case NONE, EXTRACT_SPATIAL_BOUNDS -> new SpatialCentroidGeoPointSourceValuesAggregatorFunctionSupplier(); }; case DataType.CARTESIAN_POINT -> switch (fieldExtractPreference) { - case DOC_VALUES -> new SpatialCentroidCartesianPointDocValuesAggregatorFunctionSupplier(inputChannels); - case NONE, EXTRACT_SPATIAL_BOUNDS -> new SpatialCentroidCartesianPointSourceValuesAggregatorFunctionSupplier(inputChannels); + case DOC_VALUES -> new SpatialCentroidCartesianPointDocValuesAggregatorFunctionSupplier(); + case NONE, EXTRACT_SPATIAL_BOUNDS -> new SpatialCentroidCartesianPointSourceValuesAggregatorFunctionSupplier(); }; default -> throw EsqlIllegalArgumentException.illegalDataType(type); }; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialExtent.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialExtent.java index 5d56fe1e1169..419c1a8416c9 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialExtent.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialExtent.java @@ -26,6 +26,7 @@ import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.ToAggregator; @@ -48,7 +49,7 @@ public final class SpatialExtent extends SpatialAggregateFunction implements ToA @FunctionInfo( returnType = { "geo_shape", "cartesian_shape" }, description = "Calculate the spatial extent over a field with geometry type. Returns a bounding box for all values of the field.", - isAggregation = true, + type = FunctionType.AGGREGATE, examples = @Example(file = "spatial", tag = "st_extent_agg-airports") ) public SpatialExtent( @@ -102,25 +103,25 @@ public final class SpatialExtent extends SpatialAggregateFunction implements ToA } @Override - public AggregatorFunctionSupplier supplier(List inputChannels) { + public AggregatorFunctionSupplier supplier() { DataType type = field().dataType(); return switch (type) { case DataType.GEO_POINT -> switch (fieldExtractPreference) { - case DOC_VALUES -> new SpatialExtentGeoPointDocValuesAggregatorFunctionSupplier(inputChannels); - case NONE, EXTRACT_SPATIAL_BOUNDS -> new SpatialExtentGeoPointSourceValuesAggregatorFunctionSupplier(inputChannels); + case DOC_VALUES -> new SpatialExtentGeoPointDocValuesAggregatorFunctionSupplier(); + case NONE, EXTRACT_SPATIAL_BOUNDS -> new SpatialExtentGeoPointSourceValuesAggregatorFunctionSupplier(); }; case DataType.CARTESIAN_POINT -> switch (fieldExtractPreference) { - case DOC_VALUES -> new SpatialExtentCartesianPointDocValuesAggregatorFunctionSupplier(inputChannels); - case NONE, EXTRACT_SPATIAL_BOUNDS -> new SpatialExtentCartesianPointSourceValuesAggregatorFunctionSupplier(inputChannels); + case DOC_VALUES -> new SpatialExtentCartesianPointDocValuesAggregatorFunctionSupplier(); + case NONE, EXTRACT_SPATIAL_BOUNDS -> new SpatialExtentCartesianPointSourceValuesAggregatorFunctionSupplier(); }; case DataType.GEO_SHAPE -> switch (fieldExtractPreference) { - case EXTRACT_SPATIAL_BOUNDS -> new SpatialExtentGeoShapeDocValuesAggregatorFunctionSupplier(inputChannels); - case NONE -> new SpatialExtentGeoShapeSourceValuesAggregatorFunctionSupplier(inputChannels); + case EXTRACT_SPATIAL_BOUNDS -> new SpatialExtentGeoShapeDocValuesAggregatorFunctionSupplier(); + case NONE -> new SpatialExtentGeoShapeSourceValuesAggregatorFunctionSupplier(); case DOC_VALUES -> throw new EsqlIllegalArgumentException("Illegal field extract preference: " + fieldExtractPreference); }; case DataType.CARTESIAN_SHAPE -> switch (fieldExtractPreference) { - case EXTRACT_SPATIAL_BOUNDS -> new SpatialExtentCartesianShapeDocValuesAggregatorFunctionSupplier(inputChannels); - case NONE -> new SpatialExtentCartesianShapeSourceValuesAggregatorFunctionSupplier(inputChannels); + case EXTRACT_SPATIAL_BOUNDS -> new SpatialExtentCartesianShapeDocValuesAggregatorFunctionSupplier(); + case NONE -> new SpatialExtentCartesianShapeSourceValuesAggregatorFunctionSupplier(); case DOC_VALUES -> throw new EsqlIllegalArgumentException("Illegal field extract preference: " + fieldExtractPreference); }; default -> throw EsqlIllegalArgumentException.illegalDataType(type); diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/StdDev.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/StdDev.java index 189b6a81912c..19365c3166d1 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/StdDev.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/StdDev.java @@ -21,6 +21,7 @@ import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.ToAggregator; @@ -37,7 +38,7 @@ public class StdDev extends AggregateFunction implements ToAggregator { @FunctionInfo( returnType = "double", description = "The standard deviation of a numeric field.", - isAggregation = true, + type = FunctionType.AGGREGATE, examples = { @Example(file = "stats", tag = "stdev"), @Example( @@ -96,16 +97,16 @@ public class StdDev extends AggregateFunction implements ToAggregator { } @Override - public final AggregatorFunctionSupplier supplier(List inputChannels) { + public final AggregatorFunctionSupplier supplier() { DataType type = field().dataType(); if (type == DataType.LONG) { - return new StdDevLongAggregatorFunctionSupplier(inputChannels); + return new StdDevLongAggregatorFunctionSupplier(); } if (type == DataType.INTEGER) { - return new StdDevIntAggregatorFunctionSupplier(inputChannels); + return new StdDevIntAggregatorFunctionSupplier(); } if (type == DataType.DOUBLE) { - return new StdDevDoubleAggregatorFunctionSupplier(inputChannels); + return new StdDevDoubleAggregatorFunctionSupplier(); } throw EsqlIllegalArgumentException.illegalDataType(type); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sum.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sum.java index 1c69edb9f0da..f8fe28d85a92 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sum.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sum.java @@ -23,6 +23,7 @@ import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.FromAggregateMetricDouble; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvSum; @@ -48,7 +49,7 @@ public class Sum extends NumericAggregate implements SurrogateExpression { @FunctionInfo( returnType = { "long", "double" }, description = "The sum of a numeric expression.", - isAggregation = true, + type = FunctionType.AGGREGATE, examples = { @Example(file = "stats", tag = "sum"), @Example( @@ -98,18 +99,18 @@ public class Sum extends NumericAggregate implements SurrogateExpression { } @Override - protected AggregatorFunctionSupplier longSupplier(List inputChannels) { - return new SumLongAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier longSupplier() { + return new SumLongAggregatorFunctionSupplier(); } @Override - protected AggregatorFunctionSupplier intSupplier(List inputChannels) { - return new SumIntAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier intSupplier() { + return new SumIntAggregatorFunctionSupplier(); } @Override - protected AggregatorFunctionSupplier doubleSupplier(List inputChannels) { - return new SumDoubleAggregatorFunctionSupplier(inputChannels); + protected AggregatorFunctionSupplier doubleSupplier() { + return new SumDoubleAggregatorFunctionSupplier(); } @Override diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/ToPartial.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/ToPartial.java index a2856f60e4c5..04dadb5e3bb9 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/ToPartial.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/ToPartial.java @@ -18,6 +18,7 @@ import org.elasticsearch.compute.aggregation.AggregatorMode; import org.elasticsearch.compute.aggregation.FromPartialGroupingAggregatorFunction; import org.elasticsearch.compute.aggregation.GroupingAggregator; import org.elasticsearch.compute.aggregation.GroupingAggregatorFunction; +import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.aggregation.ToPartialAggregatorFunction; import org.elasticsearch.compute.aggregation.ToPartialGroupingAggregatorFunction; import org.elasticsearch.compute.operator.DriverContext; @@ -127,37 +128,41 @@ public class ToPartial extends AggregateFunction implements ToAggregator { } @Override - public AggregatorFunctionSupplier supplier(List inputChannels) { - final ToAggregator toAggregator = (ToAggregator) function; + public AggregatorFunctionSupplier supplier() { + final AggregatorFunctionSupplier supplier = ((ToAggregator) function).supplier(); return new AggregatorFunctionSupplier() { @Override - public AggregatorFunction aggregator(DriverContext driverContext) { + public List nonGroupingIntermediateStateDesc() { + return ToPartialAggregatorFunction.intermediateStateDesc(); + } + + @Override + public List groupingIntermediateStateDesc() { + return ToPartialGroupingAggregatorFunction.intermediateStateDesc(); + } + + @Override + public AggregatorFunction aggregator(DriverContext driverContext, List channels) { assert false : "aggregatorFactory() is override"; throw new UnsupportedOperationException(); } @Override - public GroupingAggregatorFunction groupingAggregator(DriverContext driverContext) { + public GroupingAggregatorFunction groupingAggregator(DriverContext driverContext, List channels) { assert false : "groupingAggregatorFactory() is override"; throw new UnsupportedOperationException(); } @Override - public Aggregator.Factory aggregatorFactory(AggregatorMode mode) { - final AggregatorFunctionSupplier supplier; - if (mode.isInputPartial()) { - try (var dummy = toAggregator.supplier(inputChannels).aggregator(DriverContext.getLocalDriver())) { - var intermediateChannels = IntStream.range(0, dummy.intermediateBlockCount()).boxed().toList(); - supplier = toAggregator.supplier(intermediateChannels); - } - } else { - supplier = toAggregator.supplier(inputChannels); - } + public Aggregator.Factory aggregatorFactory(AggregatorMode mode, List channels) { + List intermediateChannels = mode.isInputPartial() + ? IntStream.range(0, supplier.nonGroupingIntermediateStateDesc().size()).boxed().toList() + : channels; return new Aggregator.Factory() { @Override public Aggregator apply(DriverContext driverContext) { - final AggregatorFunction aggregatorFunction = supplier.aggregator(driverContext); - return new Aggregator(new ToPartialAggregatorFunction(aggregatorFunction, inputChannels), mode); + final AggregatorFunction aggregatorFunction = supplier.aggregator(driverContext, intermediateChannels); + return new Aggregator(new ToPartialAggregatorFunction(aggregatorFunction, channels), mode); } @Override @@ -168,21 +173,18 @@ public class ToPartial extends AggregateFunction implements ToAggregator { } @Override - public GroupingAggregator.Factory groupingAggregatorFactory(AggregatorMode mode) { - final AggregatorFunctionSupplier supplier; - if (mode.isInputPartial()) { - try (var dummy = toAggregator.supplier(inputChannels).aggregator(DriverContext.getLocalDriver())) { - var intermediateChannels = IntStream.range(0, dummy.intermediateBlockCount()).boxed().toList(); - supplier = toAggregator.supplier(intermediateChannels); - } - } else { - supplier = toAggregator.supplier(inputChannels); - } + public GroupingAggregator.Factory groupingAggregatorFactory(AggregatorMode mode, List channels) { + List intermediateChannels = mode.isInputPartial() + ? IntStream.range(0, supplier.nonGroupingIntermediateStateDesc().size()).boxed().toList() + : channels; return new GroupingAggregator.Factory() { @Override public GroupingAggregator apply(DriverContext driverContext) { - final GroupingAggregatorFunction aggregatorFunction = supplier.groupingAggregator(driverContext); - return new GroupingAggregator(new ToPartialGroupingAggregatorFunction(aggregatorFunction, inputChannels), mode); + final GroupingAggregatorFunction aggregatorFunction = supplier.groupingAggregator( + driverContext, + intermediateChannels + ); + return new GroupingAggregator(new ToPartialGroupingAggregatorFunction(aggregatorFunction, channels), mode); } @Override diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Top.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Top.java index 9be8c94266ee..f31153d228e7 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Top.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Top.java @@ -29,6 +29,7 @@ import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput; import org.elasticsearch.xpack.esql.planner.ToAggregator; @@ -54,7 +55,7 @@ public class Top extends AggregateFunction implements ToAggregator, SurrogateExp @FunctionInfo( returnType = { "boolean", "double", "integer", "long", "date", "ip", "keyword" }, description = "Collects the top values for a field. Includes repeated values.", - isAggregation = true, + type = FunctionType.AGGREGATE, examples = @Example(file = "stats_top", tag = "top") ) public Top( @@ -188,25 +189,25 @@ public class Top extends AggregateFunction implements ToAggregator, SurrogateExp } @Override - public AggregatorFunctionSupplier supplier(List inputChannels) { + public AggregatorFunctionSupplier supplier() { DataType type = field().dataType(); if (type == DataType.LONG || type == DataType.DATETIME) { - return new TopLongAggregatorFunctionSupplier(inputChannels, limitValue(), orderValue()); + return new TopLongAggregatorFunctionSupplier(limitValue(), orderValue()); } if (type == DataType.INTEGER) { - return new TopIntAggregatorFunctionSupplier(inputChannels, limitValue(), orderValue()); + return new TopIntAggregatorFunctionSupplier(limitValue(), orderValue()); } if (type == DataType.DOUBLE) { - return new TopDoubleAggregatorFunctionSupplier(inputChannels, limitValue(), orderValue()); + return new TopDoubleAggregatorFunctionSupplier(limitValue(), orderValue()); } if (type == DataType.BOOLEAN) { - return new TopBooleanAggregatorFunctionSupplier(inputChannels, limitValue(), orderValue()); + return new TopBooleanAggregatorFunctionSupplier(limitValue(), orderValue()); } if (type == DataType.IP) { - return new TopIpAggregatorFunctionSupplier(inputChannels, limitValue(), orderValue()); + return new TopIpAggregatorFunctionSupplier(limitValue(), orderValue()); } if (DataType.isString(type)) { - return new TopBytesRefAggregatorFunctionSupplier(inputChannels, limitValue(), orderValue()); + return new TopBytesRefAggregatorFunctionSupplier(limitValue(), orderValue()); } throw EsqlIllegalArgumentException.illegalDataType(type); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java index 5260b3e8fa27..4dbe0e93b501 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java @@ -24,13 +24,14 @@ import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.ToAggregator; import java.io.IOException; import java.util.List; import java.util.Map; -import java.util.function.Function; +import java.util.function.Supplier; import static java.util.Collections.emptyList; import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; @@ -38,7 +39,7 @@ import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.Param public class Values extends AggregateFunction implements ToAggregator { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "Values", Values::new); - private static final Map, AggregatorFunctionSupplier>> SUPPLIERS = Map.ofEntries( + private static final Map> SUPPLIERS = Map.ofEntries( Map.entry(DataType.INTEGER, ValuesIntAggregatorFunctionSupplier::new), Map.entry(DataType.LONG, ValuesLongAggregatorFunctionSupplier::new), Map.entry(DataType.DATETIME, ValuesLongAggregatorFunctionSupplier::new), @@ -66,7 +67,7 @@ public class Values extends AggregateFunction implements ToAggregator { collects too many values it will fail the query with a <>. ====""", - isAggregation = true, + type = FunctionType.AGGREGATE, examples = @Example(file = "string", tag = "values-grouped") ) public Values( @@ -124,12 +125,12 @@ public class Values extends AggregateFunction implements ToAggregator { } @Override - public AggregatorFunctionSupplier supplier(List inputChannels) { + public AggregatorFunctionSupplier supplier() { DataType type = field().dataType(); if (SUPPLIERS.containsKey(type) == false) { // If the type checking did its job, this should never happen throw EsqlIllegalArgumentException.illegalDataType(type); } - return SUPPLIERS.get(type).apply(inputChannels); + return SUPPLIERS.get(type).get(); } } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/WeightedAvg.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/WeightedAvg.java index bab65653ba57..c58bc997527b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/WeightedAvg.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/WeightedAvg.java @@ -20,6 +20,7 @@ import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvAvg; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Div; @@ -48,7 +49,7 @@ public class WeightedAvg extends AggregateFunction implements SurrogateExpressio @FunctionInfo( returnType = "double", description = "The weighted average of a numeric expression.", - isAggregation = true, + type = FunctionType.AGGREGATE, examples = @Example(file = "stats", tag = "weighted-avg") ) public WeightedAvg( diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/package-info.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/package-info.java index 9f08401a42dd..411538688220 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/package-info.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/package-info.java @@ -85,10 +85,6 @@ * To introduce your aggregation to the engine: *
    *
  • - * Add it to {@code org.elasticsearch.xpack.esql.planner.AggregateMapper}. - * Check all usages of other aggregations there, and replicate the logic. - *
  • - *
  • * Implement serialization for your aggregation by implementing * {@link org.elasticsearch.common.io.stream.NamedWriteable#getWriteableName}, * {@link org.elasticsearch.common.io.stream.NamedWriteable#writeTo}, @@ -97,7 +93,7 @@ * {@link org.elasticsearch.xpack.esql.expression.function.aggregate.AggregateWritables#getNamedWriteables}. *
  • *
  • - * Do the same with {@link org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry}. + * Add it to {@link org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry}. *
  • *
* @@ -105,8 +101,84 @@ * *

Creating aggregators for your function

*

- * Aggregators contain the core logic of your aggregation. That is, how to combine values, what to store, how to process data, etc. + * Aggregators contain the core logic of how to combine values, what to store, how to process data, etc. + * Currently, we rely on code generation (per aggregation per type) in order to implement such functionality. + * This approach was picked for performance reasons (namely to avoid virtual method calls and boxing types). + * As a result we could not rely on interfaces implementation and generics. *

+ *

+ * In order to implement aggregation logic create your class (typically named "${FunctionName}${Type}Aggregator"). + * It must be placed in `org.elasticsearch.compute.aggregation` in order to be picked up by code generation. + * Annotate it with {@link org.elasticsearch.compute.ann.Aggregator} and {@link org.elasticsearch.compute.ann.GroupingAggregator} + * The first one is responsible for an entire data set aggregation, while the second one is responsible for grouping within buckets. + *

+ *

Before you start implementing it, please note that:

+ *
    + *
  • All methods must be public static
  • + *
  • + * {@code init/initSingle/initGrouping} could have optional {@link org.elasticsearch.common.util.BigArrays} or + * {@link org.elasticsearch.compute.operator.DriverContext} arguments that are going to be injected automatically. + * It is also possible to declare any number of arbitrary arguments that must be provided via generated Supplier. + *
  • + *
  • + * {@code combine, combineStates, combineIntermediate, evaluateFinal} methods (see below) could be generated automatically + * when both input type I and mutable accumulator state AggregatorState and GroupingAggregatorState are primitive (DOUBLE, INT). + *
  • + *
  • + * Code generation expects at least one IntermediateState field that is going to be used to keep + * the serialized state of the aggregation (eg AggregatorState and GroupingAggregatorState). + * It must be defined even if you rely on autogenerated implementation for the primitive types. + *
  • + *
+ *

Aggregation expects:

+ *
    + *
  • + * type AggregatorState (a mutable state used to accumulate result of the aggregation) to be public, not inner and implements + * {@link org.elasticsearch.compute.aggregation.AggregatorState} + *
  • + *
  • type I (input to your aggregation function), usually primitive types and {@link org.apache.lucene.util.BytesRef}
  • + *
  • {@code AggregatorState init()} or {@code AggregatorState initSingle()} returns empty initialized aggregation state
  • + *
  • + * {@code void combine(AggregatorState state, I input)} or {@code AggregatorState combine(AggregatorState state, I input)} + * adds input entry to the aggregation state + *
  • + *
  • + * {@code void combineIntermediate(AggregatorState state, intermediate states)} adds serialized aggregation state + * to the current aggregation state (used to combine results across different nodes) + *
  • + *
  • + * {@code Block evaluateFinal(AggregatorState state, DriverContext)} converts the inner state of the aggregation to the result + * column + *
  • + *
+ *

Grouping aggregation expects:

+ *
    + *
  • + * type GroupingAggregatorState (a mutable state used to accumulate result of the grouping aggregation) to be public, + * not inner and implements {@link org.elasticsearch.compute.aggregation.GroupingAggregatorState} + *
  • + *
  • type I (input to your aggregation function), usually primitive types and {@link org.apache.lucene.util.BytesRef}
  • + *
  • + * {@code GroupingAggregatorState init()} or {@code GroupingAggregatorState initGrouping()} returns empty initialized grouping + * aggregation state + *
  • + *
  • + * {@code void combine(GroupingAggregatorState state, int groupId, I input)} adds input entry to the corresponding group (bucket) + * of the grouping aggregation state + *
  • + *
  • + * {@code void combineStates(GroupingAggregatorState targetState, int targetGroupId, GS otherState, int otherGroupId)} + * merges other grouped aggregation state into the first one + *
  • + *
  • + * {@code void combineIntermediate(GroupingAggregatorState current, int groupId, intermediate states)} adds serialized + * aggregation state to the current grouped aggregation state (used to combine results across different nodes) + *
  • + *
  • + * {@code Block evaluateFinal(GroupingAggregatorState state, IntVectorSelected, DriverContext)} converts the inner state + * of the grouping aggregation to the result column + *
  • + *
*
    *
  1. * Copy an existing aggregator to use as a base. You'll usually make one per type. Check other classes to see the naming pattern. @@ -117,31 +189,8 @@ *

    *
  2. *
  3. - * The methods in the aggregator will define how it will work: - *
      - *
    • - * Adding the `type init()` method will autogenerate the code to manage the state, using your returned value - * as the initial value for each group. - *
    • - *
    • - * Adding the `type initSingle()` or `type initGrouping()` methods will use the state object you return there instead. - *

      - * You will also have to provide `evaluateIntermediate()` and `evaluateFinal()` methods this way. - *

      - *
    • - *
    - * Depending on the way you use, adapt your `combine*()` methods to receive one or other type as their first parameters. - *
  4. - *
  5. - * If it's also a {@link org.elasticsearch.compute.ann.GroupingAggregator}, you should provide the same methods as commented before: - *
      - *
    • - * Add an `initGrouping()`, unless you're using the `init()` method - *
    • - *
    • - * Add all the other methods, with the state parameter of the type of your `initGrouping()`. - *
    • - *
    + * Implement (or create an empty) methods according to the above list. + * Also check {@link org.elasticsearch.compute.ann.Aggregator} JavaDoc as it contains generated method usage. *
  6. *
  7. * Make a test for your aggregator. @@ -152,16 +201,8 @@ *

    *
  8. *
  9. - * Check the Javadoc of the {@link org.elasticsearch.compute.ann.Aggregator} - * and {@link org.elasticsearch.compute.ann.GroupingAggregator} annotations. - * Add/Modify them on your aggregator. - *
  10. - *
  11. - * The {@link org.elasticsearch.compute.ann.Aggregator} JavaDoc explains the static methods you should add. - *
  12. - *
  13. - * After implementing the required methods (Even if they have a dummy implementation), - * run the CsvTests to generate some extra required classes. + * Code generation is triggered when running the tests. + * Run the CsvTests to generate the code. Generated code should include: *

    * One of them will be the {@code AggregatorFunctionSupplier} for your aggregator. * Find it by its name ({@code AggregatorFunctionSupplier}), diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Bucket.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Bucket.java index 90b35e469ddc..ac54e3d6484d 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Bucket.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Bucket.java @@ -27,6 +27,7 @@ import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.TwoOptionalArguments; import org.elasticsearch.xpack.esql.expression.function.scalar.date.DateTrunc; @@ -175,7 +176,8 @@ public class Bucket extends GroupingFunction implements PostOptimizationVerifica inserting a negative offset of `1 hour` to buckets of `1 year` looks like this:""", file = "bucket", tag = "bucketWithOffset" - ) } + ) }, + type = FunctionType.GROUPING ) public Bucket( Source source, diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Categorize.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Categorize.java index 570ce7a96dd6..6cad20b4e28b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Categorize.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Categorize.java @@ -18,6 +18,7 @@ import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput; @@ -60,7 +61,8 @@ public class Categorize extends GroupingFunction { tag = "docsCategorize", description = "This example categorizes server logs messages into categories and aggregates their counts. " ) }, - preview = true + preview = true, + type = FunctionType.GROUPING ) public Categorize( Source source, diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java index 36150083daec..bc32945d73eb 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java @@ -10,7 +10,6 @@ package org.elasticsearch.xpack.esql.optimizer; import org.elasticsearch.xpack.esql.VerificationException; import org.elasticsearch.xpack.esql.common.Failures; import org.elasticsearch.xpack.esql.core.type.DataType; -import org.elasticsearch.xpack.esql.optimizer.rules.logical.AddDefaultTopN; import org.elasticsearch.xpack.esql.optimizer.rules.logical.BooleanFunctionEqualsElimination; import org.elasticsearch.xpack.esql.optimizer.rules.logical.BooleanSimplification; import org.elasticsearch.xpack.esql.optimizer.rules.logical.CombineBinaryComparisons; @@ -32,7 +31,7 @@ import org.elasticsearch.xpack.esql.optimizer.rules.logical.PruneColumns; import org.elasticsearch.xpack.esql.optimizer.rules.logical.PruneEmptyPlans; import org.elasticsearch.xpack.esql.optimizer.rules.logical.PruneFilters; import org.elasticsearch.xpack.esql.optimizer.rules.logical.PruneLiteralsInOrderBy; -import org.elasticsearch.xpack.esql.optimizer.rules.logical.PruneOrderByBeforeStats; +import org.elasticsearch.xpack.esql.optimizer.rules.logical.PruneRedundantOrderBy; import org.elasticsearch.xpack.esql.optimizer.rules.logical.PruneRedundantSortClauses; import org.elasticsearch.xpack.esql.optimizer.rules.logical.PushDownAndCombineFilters; import org.elasticsearch.xpack.esql.optimizer.rules.logical.PushDownAndCombineLimits; @@ -116,10 +115,9 @@ public class LogicalPlanOptimizer extends ParameterizedRuleExecutor> rules() { var skip = new Batch<>("Skip Compute", new SkipQueryOnLimitZero()); - var defaultTopN = new Batch<>("Add default TopN", new AddDefaultTopN()); var label = new Batch<>("Set as Optimized", Limiter.ONCE, new SetAsOptimized()); - return asList(substitutions(), operators(), skip, cleanup(), defaultTopN, label); + return asList(substitutions(), operators(), skip, cleanup(), label); } protected static Batch substitutions() { @@ -189,7 +187,7 @@ public class LogicalPlanOptimizer extends ParameterizedRuleExecutor { if (ex instanceof PostOptimizationVerificationAware va) { va.postOptimizationVerification(failures); diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/AddDefaultTopN.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/AddDefaultTopN.java deleted file mode 100644 index ef091686a4b3..000000000000 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/AddDefaultTopN.java +++ /dev/null @@ -1,54 +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.optimizer.rules.logical; - -import org.elasticsearch.xpack.esql.core.expression.Literal; -import org.elasticsearch.xpack.esql.core.type.DataType; -import org.elasticsearch.xpack.esql.optimizer.LogicalOptimizerContext; -import org.elasticsearch.xpack.esql.plan.logical.EsRelation; -import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.esql.plan.logical.OrderBy; -import org.elasticsearch.xpack.esql.plan.logical.TopN; -import org.elasticsearch.xpack.esql.plan.logical.UnaryPlan; - -/** - * This adds an explicit TopN node to a plan that only has an OrderBy right before Lucene. - * To date, the only known use case that "needs" this is a query of the form - * from test - * | sort emp_no - * | mv_expand first_name - * | rename first_name AS x - * | where x LIKE "*a*" - * | limit 15 - *

    - * or - *

    - * from test - * | sort emp_no - * | mv_expand first_name - * | sort first_name - * | limit 15 - *

    - * {@link PushDownAndCombineLimits} will copy the "limit 15" after "sort emp_no" if there is no filter on the expanded values - * OR if there is no sort between "limit" and "mv_expand". - * But, since this type of query has such a filter, the "sort emp_no" will have no limit when it reaches the current rule. - */ -public final class AddDefaultTopN extends OptimizerRules.ParameterizedOptimizerRule { - public AddDefaultTopN() { - super(OptimizerRules.TransformDirection.DOWN); - } - - @Override - protected LogicalPlan rule(LogicalPlan plan, LogicalOptimizerContext context) { - if (plan instanceof UnaryPlan unary && unary.child() instanceof OrderBy order && order.child() instanceof EsRelation relation) { - var limit = new Literal(plan.source(), context.configuration().resultTruncationMaxSize(), DataType.INTEGER); - return unary.replaceChild(new TopN(plan.source(), relation, order.order(), limit)); - } - return plan; - } -} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PruneOrderByBeforeStats.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PruneOrderByBeforeStats.java deleted file mode 100644 index 24fb8971487d..000000000000 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PruneOrderByBeforeStats.java +++ /dev/null @@ -1,47 +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.optimizer.rules.logical; - -import org.elasticsearch.xpack.esql.plan.logical.Aggregate; -import org.elasticsearch.xpack.esql.plan.logical.Enrich; -import org.elasticsearch.xpack.esql.plan.logical.Eval; -import org.elasticsearch.xpack.esql.plan.logical.Filter; -import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.esql.plan.logical.OrderBy; -import org.elasticsearch.xpack.esql.plan.logical.Project; -import org.elasticsearch.xpack.esql.plan.logical.RegexExtract; -import org.elasticsearch.xpack.esql.plan.logical.UnaryPlan; - -public final class PruneOrderByBeforeStats extends OptimizerRules.OptimizerRule { - - @Override - protected LogicalPlan rule(Aggregate agg) { - OrderBy order = findPullableOrderBy(agg.child()); - - LogicalPlan p = agg; - if (order != null) { - p = agg.transformDown(OrderBy.class, o -> o == order ? order.child() : o); - } - return p; - } - - private static OrderBy findPullableOrderBy(LogicalPlan plan) { - OrderBy pullable = null; - if (plan instanceof OrderBy o) { - pullable = o; - } else if (plan instanceof Eval - || plan instanceof Filter - || plan instanceof Project - || plan instanceof RegexExtract - || plan instanceof Enrich) { - pullable = findPullableOrderBy(((UnaryPlan) plan).child()); - } - return pullable; - } - -} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PruneRedundantOrderBy.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PruneRedundantOrderBy.java new file mode 100644 index 000000000000..2495f72864d1 --- /dev/null +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PruneRedundantOrderBy.java @@ -0,0 +1,82 @@ +/* + * 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.optimizer.rules.logical; + +import org.elasticsearch.xpack.esql.plan.logical.Aggregate; +import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.plan.logical.OrderBy; +import org.elasticsearch.xpack.esql.plan.logical.SortAgnostic; +import org.elasticsearch.xpack.esql.plan.logical.TopN; +import org.elasticsearch.xpack.esql.plan.logical.UnaryPlan; + +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.Deque; +import java.util.IdentityHashMap; +import java.util.Set; + +/** + * SORT cannot be executed without a LIMIT, as ES|QL doesn't support unbounded sort (yet). + *

    + * The planner tries to push down LIMIT and transform all the unbounded sorts into a TopN. + * In some cases it's not possible though, eg. + *

    + * from test | sort x | lookup join lookup on x | sort y + *

    + * from test | sort x | mv_expand x | sort y + *

    + * "sort y" will become a TopN due to the addition of the default Limit, but "sort x" will remain unbounded, + * so the query could not be executed. + *

    + * In most cases though, following commands can make the previous SORTs redundant, + * because it will re-sort previously sorted results (eg. if there is another SORT) + * or because the order will be scrambled by another command (eg. a STATS) + *

    + * This rule finds and prunes redundant SORTs, attempting to make the plan executable. + */ +public class PruneRedundantOrderBy extends OptimizerRules.OptimizerRule { + + @Override + protected LogicalPlan rule(LogicalPlan plan) { + if (plan instanceof OrderBy || plan instanceof TopN || plan instanceof Aggregate) { + Set redundant = findRedundantSort(((UnaryPlan) plan).child()); + if (redundant.isEmpty()) { + return plan; + } + return plan.transformDown(p -> redundant.contains(p) ? ((UnaryPlan) p).child() : p); + } else { + return plan; + } + } + + /** + * breadth-first recursion to find redundant SORTs in the children tree. + * Returns an identity set (we need to compare and prune the exact instances) + */ + private Set findRedundantSort(LogicalPlan plan) { + Set result = Collections.newSetFromMap(new IdentityHashMap<>()); + + Deque toCheck = new ArrayDeque<>(); + toCheck.push(plan); + + while (true) { + if (toCheck.isEmpty()) { + return result; + } + LogicalPlan p = toCheck.pop(); + if (p instanceof OrderBy ob) { + result.add(ob); + toCheck.push(ob.child()); + } else if (p instanceof SortAgnostic) { + for (LogicalPlan child : p.children()) { + toCheck.push(child); + } + } + } + } +} 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 f0df3817ac65..9afa5dcbb095 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 @@ -27,6 +27,7 @@ null null null null +null '|' null null @@ -130,6 +131,9 @@ null null null null +null +null +null token symbolic names: null @@ -150,6 +154,7 @@ SORT STATS WHERE JOIN_LOOKUP +DEV_CHANGE_POINT DEV_INLINESTATS DEV_LOOKUP DEV_METRICS @@ -263,6 +268,9 @@ METRICS_WS CLOSING_METRICS_LINE_COMMENT CLOSING_METRICS_MULTILINE_COMMENT CLOSING_METRICS_WS +CHANGE_POINT_LINE_COMMENT +CHANGE_POINT_MULTILINE_COMMENT +CHANGE_POINT_WS rule names: DISSECT @@ -282,6 +290,7 @@ SORT STATS WHERE JOIN_LOOKUP +DEV_CHANGE_POINT DEV_INLINESTATS DEV_LOOKUP DEV_METRICS @@ -482,6 +491,16 @@ CLOSING_METRICS_QUOTED_IDENTIFIER CLOSING_METRICS_UNQUOTED_IDENTIFIER CLOSING_METRICS_BY CLOSING_METRICS_PIPE +CHANGE_POINT_PIPE +CHANGE_POINT_ON +CHANGE_POINT_AS +CHANGE_POINT_DOT +CHANGE_POINT_COMMA +CHANGE_POINT_QUOTED_IDENTIFIER +CHANGE_POINT_UNQUOTED_IDENTIFIER +CHANGE_POINT_LINE_COMMENT +CHANGE_POINT_MULTILINE_COMMENT +CHANGE_POINT_WS channel names: DEFAULT_TOKEN_CHANNEL @@ -504,6 +523,7 @@ LOOKUP_FIELD_MODE JOIN_MODE METRICS_MODE CLOSING_METRICS_MODE +CHANGE_POINT_MODE atn: -[4, 0, 130, 1617, 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, 2, 189, 7, 189, 2, 190, 7, 190, 2, 191, 7, 191, 2, 192, 7, 192, 2, 193, 7, 193, 2, 194, 7, 194, 2, 195, 7, 195, 2, 196, 7, 196, 2, 197, 7, 197, 2, 198, 7, 198, 2, 199, 7, 199, 2, 200, 7, 200, 2, 201, 7, 201, 2, 202, 7, 202, 2, 203, 7, 203, 2, 204, 7, 204, 2, 205, 7, 205, 2, 206, 7, 206, 2, 207, 7, 207, 2, 208, 7, 208, 2, 209, 7, 209, 2, 210, 7, 210, 2, 211, 7, 211, 2, 212, 7, 212, 2, 213, 7, 213, 2, 214, 7, 214, 2, 215, 7, 215, 2, 216, 7, 216, 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, 8, 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, 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, 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, 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, 15, 1, 15, 1, 16, 1, 16, 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, 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, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 4, 23, 653, 8, 23, 11, 23, 12, 23, 654, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 663, 8, 24, 10, 24, 12, 24, 666, 9, 24, 1, 24, 3, 24, 669, 8, 24, 1, 24, 3, 24, 672, 8, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 5, 25, 681, 8, 25, 10, 25, 12, 25, 684, 9, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 4, 26, 692, 8, 26, 11, 26, 12, 26, 693, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 32, 1, 32, 3, 32, 713, 8, 32, 1, 32, 4, 32, 716, 8, 32, 11, 32, 12, 32, 717, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 3, 35, 727, 8, 35, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 3, 37, 734, 8, 37, 1, 38, 1, 38, 1, 38, 5, 38, 739, 8, 38, 10, 38, 12, 38, 742, 9, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 750, 8, 38, 10, 38, 12, 38, 753, 9, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 3, 38, 760, 8, 38, 1, 38, 3, 38, 763, 8, 38, 3, 38, 765, 8, 38, 1, 39, 4, 39, 768, 8, 39, 11, 39, 12, 39, 769, 1, 40, 4, 40, 773, 8, 40, 11, 40, 12, 40, 774, 1, 40, 1, 40, 5, 40, 779, 8, 40, 10, 40, 12, 40, 782, 9, 40, 1, 40, 1, 40, 4, 40, 786, 8, 40, 11, 40, 12, 40, 787, 1, 40, 4, 40, 791, 8, 40, 11, 40, 12, 40, 792, 1, 40, 1, 40, 5, 40, 797, 8, 40, 10, 40, 12, 40, 800, 9, 40, 3, 40, 802, 8, 40, 1, 40, 1, 40, 1, 40, 1, 40, 4, 40, 808, 8, 40, 11, 40, 12, 40, 809, 1, 40, 1, 40, 3, 40, 814, 8, 40, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 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, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 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, 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, 80, 1, 80, 1, 80, 3, 80, 946, 8, 80, 1, 80, 5, 80, 949, 8, 80, 10, 80, 12, 80, 952, 9, 80, 1, 80, 1, 80, 4, 80, 956, 8, 80, 11, 80, 12, 80, 957, 3, 80, 960, 8, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 5, 83, 974, 8, 83, 10, 83, 12, 83, 977, 9, 83, 1, 83, 1, 83, 3, 83, 981, 8, 83, 1, 83, 4, 83, 984, 8, 83, 11, 83, 12, 83, 985, 3, 83, 988, 8, 83, 1, 84, 1, 84, 4, 84, 992, 8, 84, 11, 84, 12, 84, 993, 1, 84, 1, 84, 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, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 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, 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, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 101, 3, 101, 1071, 8, 101, 1, 102, 4, 102, 1074, 8, 102, 11, 102, 12, 102, 1075, 1, 103, 1, 103, 1, 103, 1, 103, 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, 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, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 3, 113, 1125, 8, 113, 1, 114, 1, 114, 3, 114, 1129, 8, 114, 1, 114, 5, 114, 1132, 8, 114, 10, 114, 12, 114, 1135, 9, 114, 1, 114, 1, 114, 3, 114, 1139, 8, 114, 1, 114, 4, 114, 1142, 8, 114, 11, 114, 12, 114, 1143, 3, 114, 1146, 8, 114, 1, 115, 1, 115, 4, 115, 1150, 8, 115, 11, 115, 12, 115, 1151, 1, 116, 1, 116, 1, 116, 1, 116, 1, 117, 1, 117, 1, 117, 1, 117, 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, 121, 1, 121, 1, 121, 1, 121, 1, 122, 1, 122, 1, 122, 1, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 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, 129, 1, 129, 1, 129, 1, 129, 1, 130, 1, 130, 1, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 131, 1, 131, 1, 131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 132, 1, 133, 1, 133, 1, 133, 1, 133, 1, 133, 1, 133, 1, 133, 1, 134, 1, 134, 1, 135, 4, 135, 1237, 8, 135, 11, 135, 12, 135, 1238, 1, 135, 1, 135, 3, 135, 1243, 8, 135, 1, 135, 4, 135, 1246, 8, 135, 11, 135, 12, 135, 1247, 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, 139, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 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, 145, 1, 145, 1, 145, 1, 145, 1, 146, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 148, 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, 152, 1, 153, 1, 153, 1, 153, 1, 153, 1, 154, 1, 154, 1, 154, 1, 154, 1, 154, 1, 155, 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, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 162, 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, 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, 168, 4, 168, 1393, 8, 168, 11, 168, 12, 168, 1394, 1, 169, 1, 169, 1, 169, 1, 169, 1, 170, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 172, 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, 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, 182, 1, 182, 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, 186, 1, 186, 1, 186, 1, 186, 1, 187, 1, 187, 1, 187, 1, 187, 1, 188, 1, 188, 1, 188, 1, 188, 1, 189, 1, 189, 1, 189, 1, 189, 1, 189, 1, 190, 1, 190, 1, 190, 1, 190, 1, 190, 1, 191, 1, 191, 1, 191, 1, 191, 1, 192, 1, 192, 1, 192, 1, 192, 1, 192, 1, 192, 1, 193, 1, 193, 1, 193, 1, 193, 1, 193, 1, 193, 1, 193, 1, 193, 1, 193, 1, 194, 1, 194, 1, 194, 1, 194, 1, 195, 1, 195, 1, 195, 1, 195, 1, 196, 1, 196, 1, 196, 1, 196, 1, 197, 1, 197, 1, 197, 1, 197, 1, 198, 1, 198, 1, 198, 1, 198, 1, 199, 1, 199, 1, 199, 1, 199, 1, 200, 1, 200, 1, 200, 1, 200, 1, 201, 1, 201, 1, 201, 1, 201, 1, 202, 1, 202, 1, 202, 1, 202, 1, 202, 1, 203, 1, 203, 1, 203, 1, 203, 1, 203, 1, 203, 1, 204, 1, 204, 1, 204, 1, 204, 1, 204, 1, 204, 1, 205, 1, 205, 1, 205, 1, 205, 1, 206, 1, 206, 1, 206, 1, 206, 1, 207, 1, 207, 1, 207, 1, 207, 1, 208, 1, 208, 1, 208, 1, 208, 1, 208, 1, 208, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 210, 1, 210, 1, 210, 1, 210, 1, 211, 1, 211, 1, 211, 1, 211, 1, 212, 1, 212, 1, 212, 1, 212, 1, 213, 1, 213, 1, 213, 1, 213, 1, 213, 1, 213, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 215, 1, 215, 1, 215, 1, 215, 1, 215, 1, 215, 1, 216, 1, 216, 1, 216, 1, 216, 1, 216, 2, 682, 751, 0, 217, 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, 25, 66, 26, 68, 27, 70, 28, 72, 0, 74, 0, 76, 0, 78, 0, 80, 0, 82, 0, 84, 0, 86, 0, 88, 0, 90, 0, 92, 29, 94, 30, 96, 31, 98, 32, 100, 33, 102, 34, 104, 35, 106, 36, 108, 37, 110, 38, 112, 39, 114, 40, 116, 41, 118, 42, 120, 43, 122, 44, 124, 45, 126, 46, 128, 47, 130, 48, 132, 49, 134, 50, 136, 51, 138, 52, 140, 53, 142, 54, 144, 55, 146, 56, 148, 57, 150, 58, 152, 59, 154, 60, 156, 61, 158, 62, 160, 63, 162, 64, 164, 65, 166, 66, 168, 67, 170, 68, 172, 69, 174, 0, 176, 70, 178, 71, 180, 72, 182, 73, 184, 0, 186, 74, 188, 75, 190, 76, 192, 77, 194, 0, 196, 0, 198, 78, 200, 79, 202, 80, 204, 0, 206, 0, 208, 0, 210, 0, 212, 0, 214, 0, 216, 81, 218, 0, 220, 82, 222, 0, 224, 0, 226, 83, 228, 84, 230, 85, 232, 0, 234, 0, 236, 0, 238, 0, 240, 0, 242, 0, 244, 0, 246, 86, 248, 87, 250, 88, 252, 89, 254, 0, 256, 0, 258, 0, 260, 0, 262, 0, 264, 0, 266, 90, 268, 0, 270, 91, 272, 92, 274, 93, 276, 0, 278, 0, 280, 94, 282, 95, 284, 0, 286, 96, 288, 0, 290, 97, 292, 98, 294, 99, 296, 0, 298, 0, 300, 0, 302, 0, 304, 0, 306, 0, 308, 0, 310, 0, 312, 0, 314, 100, 316, 101, 318, 102, 320, 0, 322, 0, 324, 0, 326, 0, 328, 0, 330, 0, 332, 103, 334, 104, 336, 105, 338, 0, 340, 106, 342, 107, 344, 108, 346, 109, 348, 0, 350, 0, 352, 110, 354, 111, 356, 112, 358, 113, 360, 0, 362, 0, 364, 0, 366, 0, 368, 0, 370, 0, 372, 0, 374, 114, 376, 115, 378, 116, 380, 0, 382, 0, 384, 0, 386, 0, 388, 117, 390, 118, 392, 119, 394, 0, 396, 120, 398, 0, 400, 0, 402, 121, 404, 0, 406, 0, 408, 0, 410, 0, 412, 0, 414, 122, 416, 123, 418, 124, 420, 0, 422, 0, 424, 0, 426, 125, 428, 126, 430, 127, 432, 0, 434, 0, 436, 128, 438, 129, 440, 130, 442, 0, 444, 0, 446, 0, 448, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 36, 2, 0, 68, 68, 100, 100, 2, 0, 73, 73, 105, 105, 2, 0, 83, 83, 115, 115, 2, 0, 69, 69, 101, 101, 2, 0, 67, 67, 99, 99, 2, 0, 84, 84, 116, 116, 2, 0, 82, 82, 114, 114, 2, 0, 79, 79, 111, 111, 2, 0, 80, 80, 112, 112, 2, 0, 78, 78, 110, 110, 2, 0, 72, 72, 104, 104, 2, 0, 86, 86, 118, 118, 2, 0, 65, 65, 97, 97, 2, 0, 76, 76, 108, 108, 2, 0, 88, 88, 120, 120, 2, 0, 70, 70, 102, 102, 2, 0, 77, 77, 109, 109, 2, 0, 71, 71, 103, 103, 2, 0, 75, 75, 107, 107, 2, 0, 87, 87, 119, 119, 2, 0, 85, 85, 117, 117, 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, 1, 0, 48, 57, 2, 0, 65, 90, 97, 122, 8, 0, 34, 34, 78, 78, 82, 82, 84, 84, 92, 92, 110, 110, 114, 114, 116, 116, 4, 0, 10, 10, 13, 13, 34, 34, 92, 92, 2, 0, 43, 43, 45, 45, 1, 0, 96, 96, 2, 0, 66, 66, 98, 98, 2, 0, 89, 89, 121, 121, 11, 0, 9, 10, 13, 13, 32, 32, 34, 34, 44, 44, 47, 47, 58, 58, 61, 61, 91, 91, 93, 93, 124, 124, 2, 0, 42, 42, 47, 47, 11, 0, 9, 10, 13, 13, 32, 32, 34, 35, 44, 44, 47, 47, 58, 58, 60, 60, 62, 63, 92, 92, 124, 124, 2, 0, 74, 74, 106, 106, 1644, 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, 64, 1, 0, 0, 0, 0, 66, 1, 0, 0, 0, 0, 68, 1, 0, 0, 0, 1, 70, 1, 0, 0, 0, 1, 92, 1, 0, 0, 0, 1, 94, 1, 0, 0, 0, 1, 96, 1, 0, 0, 0, 1, 98, 1, 0, 0, 0, 1, 100, 1, 0, 0, 0, 1, 102, 1, 0, 0, 0, 1, 104, 1, 0, 0, 0, 1, 106, 1, 0, 0, 0, 1, 108, 1, 0, 0, 0, 1, 110, 1, 0, 0, 0, 1, 112, 1, 0, 0, 0, 1, 114, 1, 0, 0, 0, 1, 116, 1, 0, 0, 0, 1, 118, 1, 0, 0, 0, 1, 120, 1, 0, 0, 0, 1, 122, 1, 0, 0, 0, 1, 124, 1, 0, 0, 0, 1, 126, 1, 0, 0, 0, 1, 128, 1, 0, 0, 0, 1, 130, 1, 0, 0, 0, 1, 132, 1, 0, 0, 0, 1, 134, 1, 0, 0, 0, 1, 136, 1, 0, 0, 0, 1, 138, 1, 0, 0, 0, 1, 140, 1, 0, 0, 0, 1, 142, 1, 0, 0, 0, 1, 144, 1, 0, 0, 0, 1, 146, 1, 0, 0, 0, 1, 148, 1, 0, 0, 0, 1, 150, 1, 0, 0, 0, 1, 152, 1, 0, 0, 0, 1, 154, 1, 0, 0, 0, 1, 156, 1, 0, 0, 0, 1, 158, 1, 0, 0, 0, 1, 160, 1, 0, 0, 0, 1, 162, 1, 0, 0, 0, 1, 164, 1, 0, 0, 0, 1, 166, 1, 0, 0, 0, 1, 168, 1, 0, 0, 0, 1, 170, 1, 0, 0, 0, 1, 172, 1, 0, 0, 0, 1, 174, 1, 0, 0, 0, 1, 176, 1, 0, 0, 0, 1, 178, 1, 0, 0, 0, 1, 180, 1, 0, 0, 0, 1, 182, 1, 0, 0, 0, 1, 186, 1, 0, 0, 0, 1, 188, 1, 0, 0, 0, 1, 190, 1, 0, 0, 0, 1, 192, 1, 0, 0, 0, 2, 194, 1, 0, 0, 0, 2, 196, 1, 0, 0, 0, 2, 198, 1, 0, 0, 0, 2, 200, 1, 0, 0, 0, 2, 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, 3, 214, 1, 0, 0, 0, 3, 216, 1, 0, 0, 0, 3, 220, 1, 0, 0, 0, 3, 222, 1, 0, 0, 0, 3, 224, 1, 0, 0, 0, 3, 226, 1, 0, 0, 0, 3, 228, 1, 0, 0, 0, 3, 230, 1, 0, 0, 0, 4, 232, 1, 0, 0, 0, 4, 234, 1, 0, 0, 0, 4, 236, 1, 0, 0, 0, 4, 238, 1, 0, 0, 0, 4, 240, 1, 0, 0, 0, 4, 246, 1, 0, 0, 0, 4, 248, 1, 0, 0, 0, 4, 250, 1, 0, 0, 0, 4, 252, 1, 0, 0, 0, 5, 254, 1, 0, 0, 0, 5, 256, 1, 0, 0, 0, 5, 258, 1, 0, 0, 0, 5, 260, 1, 0, 0, 0, 5, 262, 1, 0, 0, 0, 5, 264, 1, 0, 0, 0, 5, 266, 1, 0, 0, 0, 5, 268, 1, 0, 0, 0, 5, 270, 1, 0, 0, 0, 5, 272, 1, 0, 0, 0, 5, 274, 1, 0, 0, 0, 6, 276, 1, 0, 0, 0, 6, 278, 1, 0, 0, 0, 6, 280, 1, 0, 0, 0, 6, 282, 1, 0, 0, 0, 6, 286, 1, 0, 0, 0, 6, 288, 1, 0, 0, 0, 6, 290, 1, 0, 0, 0, 6, 292, 1, 0, 0, 0, 6, 294, 1, 0, 0, 0, 7, 296, 1, 0, 0, 0, 7, 298, 1, 0, 0, 0, 7, 300, 1, 0, 0, 0, 7, 302, 1, 0, 0, 0, 7, 304, 1, 0, 0, 0, 7, 306, 1, 0, 0, 0, 7, 308, 1, 0, 0, 0, 7, 310, 1, 0, 0, 0, 7, 312, 1, 0, 0, 0, 7, 314, 1, 0, 0, 0, 7, 316, 1, 0, 0, 0, 7, 318, 1, 0, 0, 0, 8, 320, 1, 0, 0, 0, 8, 322, 1, 0, 0, 0, 8, 324, 1, 0, 0, 0, 8, 326, 1, 0, 0, 0, 8, 328, 1, 0, 0, 0, 8, 330, 1, 0, 0, 0, 8, 332, 1, 0, 0, 0, 8, 334, 1, 0, 0, 0, 8, 336, 1, 0, 0, 0, 9, 338, 1, 0, 0, 0, 9, 340, 1, 0, 0, 0, 9, 342, 1, 0, 0, 0, 9, 344, 1, 0, 0, 0, 9, 346, 1, 0, 0, 0, 10, 348, 1, 0, 0, 0, 10, 350, 1, 0, 0, 0, 10, 352, 1, 0, 0, 0, 10, 354, 1, 0, 0, 0, 10, 356, 1, 0, 0, 0, 10, 358, 1, 0, 0, 0, 11, 360, 1, 0, 0, 0, 11, 362, 1, 0, 0, 0, 11, 364, 1, 0, 0, 0, 11, 366, 1, 0, 0, 0, 11, 368, 1, 0, 0, 0, 11, 370, 1, 0, 0, 0, 11, 372, 1, 0, 0, 0, 11, 374, 1, 0, 0, 0, 11, 376, 1, 0, 0, 0, 11, 378, 1, 0, 0, 0, 12, 380, 1, 0, 0, 0, 12, 382, 1, 0, 0, 0, 12, 384, 1, 0, 0, 0, 12, 386, 1, 0, 0, 0, 12, 388, 1, 0, 0, 0, 12, 390, 1, 0, 0, 0, 12, 392, 1, 0, 0, 0, 13, 394, 1, 0, 0, 0, 13, 396, 1, 0, 0, 0, 13, 398, 1, 0, 0, 0, 13, 400, 1, 0, 0, 0, 13, 402, 1, 0, 0, 0, 13, 404, 1, 0, 0, 0, 13, 406, 1, 0, 0, 0, 13, 408, 1, 0, 0, 0, 13, 410, 1, 0, 0, 0, 13, 412, 1, 0, 0, 0, 13, 414, 1, 0, 0, 0, 13, 416, 1, 0, 0, 0, 13, 418, 1, 0, 0, 0, 14, 420, 1, 0, 0, 0, 14, 422, 1, 0, 0, 0, 14, 424, 1, 0, 0, 0, 14, 426, 1, 0, 0, 0, 14, 428, 1, 0, 0, 0, 14, 430, 1, 0, 0, 0, 15, 432, 1, 0, 0, 0, 15, 434, 1, 0, 0, 0, 15, 436, 1, 0, 0, 0, 15, 438, 1, 0, 0, 0, 15, 440, 1, 0, 0, 0, 15, 442, 1, 0, 0, 0, 15, 444, 1, 0, 0, 0, 15, 446, 1, 0, 0, 0, 15, 448, 1, 0, 0, 0, 16, 450, 1, 0, 0, 0, 18, 460, 1, 0, 0, 0, 20, 467, 1, 0, 0, 0, 22, 476, 1, 0, 0, 0, 24, 483, 1, 0, 0, 0, 26, 493, 1, 0, 0, 0, 28, 500, 1, 0, 0, 0, 30, 507, 1, 0, 0, 0, 32, 514, 1, 0, 0, 0, 34, 522, 1, 0, 0, 0, 36, 534, 1, 0, 0, 0, 38, 543, 1, 0, 0, 0, 40, 549, 1, 0, 0, 0, 42, 556, 1, 0, 0, 0, 44, 563, 1, 0, 0, 0, 46, 571, 1, 0, 0, 0, 48, 579, 1, 0, 0, 0, 50, 588, 1, 0, 0, 0, 52, 603, 1, 0, 0, 0, 54, 615, 1, 0, 0, 0, 56, 626, 1, 0, 0, 0, 58, 634, 1, 0, 0, 0, 60, 642, 1, 0, 0, 0, 62, 652, 1, 0, 0, 0, 64, 658, 1, 0, 0, 0, 66, 675, 1, 0, 0, 0, 68, 691, 1, 0, 0, 0, 70, 697, 1, 0, 0, 0, 72, 701, 1, 0, 0, 0, 74, 703, 1, 0, 0, 0, 76, 705, 1, 0, 0, 0, 78, 708, 1, 0, 0, 0, 80, 710, 1, 0, 0, 0, 82, 719, 1, 0, 0, 0, 84, 721, 1, 0, 0, 0, 86, 726, 1, 0, 0, 0, 88, 728, 1, 0, 0, 0, 90, 733, 1, 0, 0, 0, 92, 764, 1, 0, 0, 0, 94, 767, 1, 0, 0, 0, 96, 813, 1, 0, 0, 0, 98, 815, 1, 0, 0, 0, 100, 818, 1, 0, 0, 0, 102, 822, 1, 0, 0, 0, 104, 826, 1, 0, 0, 0, 106, 828, 1, 0, 0, 0, 108, 831, 1, 0, 0, 0, 110, 833, 1, 0, 0, 0, 112, 835, 1, 0, 0, 0, 114, 840, 1, 0, 0, 0, 116, 842, 1, 0, 0, 0, 118, 848, 1, 0, 0, 0, 120, 854, 1, 0, 0, 0, 122, 857, 1, 0, 0, 0, 124, 860, 1, 0, 0, 0, 126, 865, 1, 0, 0, 0, 128, 870, 1, 0, 0, 0, 130, 872, 1, 0, 0, 0, 132, 876, 1, 0, 0, 0, 134, 881, 1, 0, 0, 0, 136, 887, 1, 0, 0, 0, 138, 890, 1, 0, 0, 0, 140, 892, 1, 0, 0, 0, 142, 898, 1, 0, 0, 0, 144, 900, 1, 0, 0, 0, 146, 905, 1, 0, 0, 0, 148, 908, 1, 0, 0, 0, 150, 911, 1, 0, 0, 0, 152, 914, 1, 0, 0, 0, 154, 916, 1, 0, 0, 0, 156, 919, 1, 0, 0, 0, 158, 921, 1, 0, 0, 0, 160, 924, 1, 0, 0, 0, 162, 926, 1, 0, 0, 0, 164, 928, 1, 0, 0, 0, 166, 930, 1, 0, 0, 0, 168, 932, 1, 0, 0, 0, 170, 934, 1, 0, 0, 0, 172, 936, 1, 0, 0, 0, 174, 938, 1, 0, 0, 0, 176, 959, 1, 0, 0, 0, 178, 961, 1, 0, 0, 0, 180, 966, 1, 0, 0, 0, 182, 987, 1, 0, 0, 0, 184, 989, 1, 0, 0, 0, 186, 997, 1, 0, 0, 0, 188, 999, 1, 0, 0, 0, 190, 1003, 1, 0, 0, 0, 192, 1007, 1, 0, 0, 0, 194, 1011, 1, 0, 0, 0, 196, 1016, 1, 0, 0, 0, 198, 1021, 1, 0, 0, 0, 200, 1025, 1, 0, 0, 0, 202, 1029, 1, 0, 0, 0, 204, 1033, 1, 0, 0, 0, 206, 1038, 1, 0, 0, 0, 208, 1042, 1, 0, 0, 0, 210, 1046, 1, 0, 0, 0, 212, 1050, 1, 0, 0, 0, 214, 1054, 1, 0, 0, 0, 216, 1058, 1, 0, 0, 0, 218, 1070, 1, 0, 0, 0, 220, 1073, 1, 0, 0, 0, 222, 1077, 1, 0, 0, 0, 224, 1081, 1, 0, 0, 0, 226, 1085, 1, 0, 0, 0, 228, 1089, 1, 0, 0, 0, 230, 1093, 1, 0, 0, 0, 232, 1097, 1, 0, 0, 0, 234, 1102, 1, 0, 0, 0, 236, 1106, 1, 0, 0, 0, 238, 1110, 1, 0, 0, 0, 240, 1115, 1, 0, 0, 0, 242, 1124, 1, 0, 0, 0, 244, 1145, 1, 0, 0, 0, 246, 1149, 1, 0, 0, 0, 248, 1153, 1, 0, 0, 0, 250, 1157, 1, 0, 0, 0, 252, 1161, 1, 0, 0, 0, 254, 1165, 1, 0, 0, 0, 256, 1170, 1, 0, 0, 0, 258, 1174, 1, 0, 0, 0, 260, 1178, 1, 0, 0, 0, 262, 1182, 1, 0, 0, 0, 264, 1187, 1, 0, 0, 0, 266, 1192, 1, 0, 0, 0, 268, 1195, 1, 0, 0, 0, 270, 1199, 1, 0, 0, 0, 272, 1203, 1, 0, 0, 0, 274, 1207, 1, 0, 0, 0, 276, 1211, 1, 0, 0, 0, 278, 1216, 1, 0, 0, 0, 280, 1221, 1, 0, 0, 0, 282, 1226, 1, 0, 0, 0, 284, 1233, 1, 0, 0, 0, 286, 1242, 1, 0, 0, 0, 288, 1249, 1, 0, 0, 0, 290, 1253, 1, 0, 0, 0, 292, 1257, 1, 0, 0, 0, 294, 1261, 1, 0, 0, 0, 296, 1265, 1, 0, 0, 0, 298, 1271, 1, 0, 0, 0, 300, 1275, 1, 0, 0, 0, 302, 1279, 1, 0, 0, 0, 304, 1283, 1, 0, 0, 0, 306, 1287, 1, 0, 0, 0, 308, 1291, 1, 0, 0, 0, 310, 1295, 1, 0, 0, 0, 312, 1300, 1, 0, 0, 0, 314, 1305, 1, 0, 0, 0, 316, 1309, 1, 0, 0, 0, 318, 1313, 1, 0, 0, 0, 320, 1317, 1, 0, 0, 0, 322, 1322, 1, 0, 0, 0, 324, 1326, 1, 0, 0, 0, 326, 1331, 1, 0, 0, 0, 328, 1336, 1, 0, 0, 0, 330, 1340, 1, 0, 0, 0, 332, 1344, 1, 0, 0, 0, 334, 1348, 1, 0, 0, 0, 336, 1352, 1, 0, 0, 0, 338, 1356, 1, 0, 0, 0, 340, 1361, 1, 0, 0, 0, 342, 1366, 1, 0, 0, 0, 344, 1370, 1, 0, 0, 0, 346, 1374, 1, 0, 0, 0, 348, 1378, 1, 0, 0, 0, 350, 1383, 1, 0, 0, 0, 352, 1392, 1, 0, 0, 0, 354, 1396, 1, 0, 0, 0, 356, 1400, 1, 0, 0, 0, 358, 1404, 1, 0, 0, 0, 360, 1408, 1, 0, 0, 0, 362, 1413, 1, 0, 0, 0, 364, 1417, 1, 0, 0, 0, 366, 1421, 1, 0, 0, 0, 368, 1425, 1, 0, 0, 0, 370, 1430, 1, 0, 0, 0, 372, 1434, 1, 0, 0, 0, 374, 1438, 1, 0, 0, 0, 376, 1442, 1, 0, 0, 0, 378, 1446, 1, 0, 0, 0, 380, 1450, 1, 0, 0, 0, 382, 1456, 1, 0, 0, 0, 384, 1460, 1, 0, 0, 0, 386, 1464, 1, 0, 0, 0, 388, 1468, 1, 0, 0, 0, 390, 1472, 1, 0, 0, 0, 392, 1476, 1, 0, 0, 0, 394, 1480, 1, 0, 0, 0, 396, 1485, 1, 0, 0, 0, 398, 1490, 1, 0, 0, 0, 400, 1494, 1, 0, 0, 0, 402, 1500, 1, 0, 0, 0, 404, 1509, 1, 0, 0, 0, 406, 1513, 1, 0, 0, 0, 408, 1517, 1, 0, 0, 0, 410, 1521, 1, 0, 0, 0, 412, 1525, 1, 0, 0, 0, 414, 1529, 1, 0, 0, 0, 416, 1533, 1, 0, 0, 0, 418, 1537, 1, 0, 0, 0, 420, 1541, 1, 0, 0, 0, 422, 1546, 1, 0, 0, 0, 424, 1552, 1, 0, 0, 0, 426, 1558, 1, 0, 0, 0, 428, 1562, 1, 0, 0, 0, 430, 1566, 1, 0, 0, 0, 432, 1570, 1, 0, 0, 0, 434, 1576, 1, 0, 0, 0, 436, 1582, 1, 0, 0, 0, 438, 1586, 1, 0, 0, 0, 440, 1590, 1, 0, 0, 0, 442, 1594, 1, 0, 0, 0, 444, 1600, 1, 0, 0, 0, 446, 1606, 1, 0, 0, 0, 448, 1612, 1, 0, 0, 0, 450, 451, 7, 0, 0, 0, 451, 452, 7, 1, 0, 0, 452, 453, 7, 2, 0, 0, 453, 454, 7, 2, 0, 0, 454, 455, 7, 3, 0, 0, 455, 456, 7, 4, 0, 0, 456, 457, 7, 5, 0, 0, 457, 458, 1, 0, 0, 0, 458, 459, 6, 0, 0, 0, 459, 17, 1, 0, 0, 0, 460, 461, 7, 0, 0, 0, 461, 462, 7, 6, 0, 0, 462, 463, 7, 7, 0, 0, 463, 464, 7, 8, 0, 0, 464, 465, 1, 0, 0, 0, 465, 466, 6, 1, 1, 0, 466, 19, 1, 0, 0, 0, 467, 468, 7, 3, 0, 0, 468, 469, 7, 9, 0, 0, 469, 470, 7, 6, 0, 0, 470, 471, 7, 1, 0, 0, 471, 472, 7, 4, 0, 0, 472, 473, 7, 10, 0, 0, 473, 474, 1, 0, 0, 0, 474, 475, 6, 2, 2, 0, 475, 21, 1, 0, 0, 0, 476, 477, 7, 3, 0, 0, 477, 478, 7, 11, 0, 0, 478, 479, 7, 12, 0, 0, 479, 480, 7, 13, 0, 0, 480, 481, 1, 0, 0, 0, 481, 482, 6, 3, 0, 0, 482, 23, 1, 0, 0, 0, 483, 484, 7, 3, 0, 0, 484, 485, 7, 14, 0, 0, 485, 486, 7, 8, 0, 0, 486, 487, 7, 13, 0, 0, 487, 488, 7, 12, 0, 0, 488, 489, 7, 1, 0, 0, 489, 490, 7, 9, 0, 0, 490, 491, 1, 0, 0, 0, 491, 492, 6, 4, 3, 0, 492, 25, 1, 0, 0, 0, 493, 494, 7, 15, 0, 0, 494, 495, 7, 6, 0, 0, 495, 496, 7, 7, 0, 0, 496, 497, 7, 16, 0, 0, 497, 498, 1, 0, 0, 0, 498, 499, 6, 5, 4, 0, 499, 27, 1, 0, 0, 0, 500, 501, 7, 17, 0, 0, 501, 502, 7, 6, 0, 0, 502, 503, 7, 7, 0, 0, 503, 504, 7, 18, 0, 0, 504, 505, 1, 0, 0, 0, 505, 506, 6, 6, 0, 0, 506, 29, 1, 0, 0, 0, 507, 508, 7, 18, 0, 0, 508, 509, 7, 3, 0, 0, 509, 510, 7, 3, 0, 0, 510, 511, 7, 8, 0, 0, 511, 512, 1, 0, 0, 0, 512, 513, 6, 7, 1, 0, 513, 31, 1, 0, 0, 0, 514, 515, 7, 13, 0, 0, 515, 516, 7, 1, 0, 0, 516, 517, 7, 16, 0, 0, 517, 518, 7, 1, 0, 0, 518, 519, 7, 5, 0, 0, 519, 520, 1, 0, 0, 0, 520, 521, 6, 8, 0, 0, 521, 33, 1, 0, 0, 0, 522, 523, 7, 16, 0, 0, 523, 524, 7, 11, 0, 0, 524, 525, 5, 95, 0, 0, 525, 526, 7, 3, 0, 0, 526, 527, 7, 14, 0, 0, 527, 528, 7, 8, 0, 0, 528, 529, 7, 12, 0, 0, 529, 530, 7, 9, 0, 0, 530, 531, 7, 0, 0, 0, 531, 532, 1, 0, 0, 0, 532, 533, 6, 9, 5, 0, 533, 35, 1, 0, 0, 0, 534, 535, 7, 6, 0, 0, 535, 536, 7, 3, 0, 0, 536, 537, 7, 9, 0, 0, 537, 538, 7, 12, 0, 0, 538, 539, 7, 16, 0, 0, 539, 540, 7, 3, 0, 0, 540, 541, 1, 0, 0, 0, 541, 542, 6, 10, 6, 0, 542, 37, 1, 0, 0, 0, 543, 544, 7, 6, 0, 0, 544, 545, 7, 7, 0, 0, 545, 546, 7, 19, 0, 0, 546, 547, 1, 0, 0, 0, 547, 548, 6, 11, 0, 0, 548, 39, 1, 0, 0, 0, 549, 550, 7, 2, 0, 0, 550, 551, 7, 10, 0, 0, 551, 552, 7, 7, 0, 0, 552, 553, 7, 19, 0, 0, 553, 554, 1, 0, 0, 0, 554, 555, 6, 12, 7, 0, 555, 41, 1, 0, 0, 0, 556, 557, 7, 2, 0, 0, 557, 558, 7, 7, 0, 0, 558, 559, 7, 6, 0, 0, 559, 560, 7, 5, 0, 0, 560, 561, 1, 0, 0, 0, 561, 562, 6, 13, 0, 0, 562, 43, 1, 0, 0, 0, 563, 564, 7, 2, 0, 0, 564, 565, 7, 5, 0, 0, 565, 566, 7, 12, 0, 0, 566, 567, 7, 5, 0, 0, 567, 568, 7, 2, 0, 0, 568, 569, 1, 0, 0, 0, 569, 570, 6, 14, 0, 0, 570, 45, 1, 0, 0, 0, 571, 572, 7, 19, 0, 0, 572, 573, 7, 10, 0, 0, 573, 574, 7, 3, 0, 0, 574, 575, 7, 6, 0, 0, 575, 576, 7, 3, 0, 0, 576, 577, 1, 0, 0, 0, 577, 578, 6, 15, 0, 0, 578, 47, 1, 0, 0, 0, 579, 580, 7, 13, 0, 0, 580, 581, 7, 7, 0, 0, 581, 582, 7, 7, 0, 0, 582, 583, 7, 18, 0, 0, 583, 584, 7, 20, 0, 0, 584, 585, 7, 8, 0, 0, 585, 586, 1, 0, 0, 0, 586, 587, 6, 16, 8, 0, 587, 49, 1, 0, 0, 0, 588, 589, 4, 17, 0, 0, 589, 590, 7, 1, 0, 0, 590, 591, 7, 9, 0, 0, 591, 592, 7, 13, 0, 0, 592, 593, 7, 1, 0, 0, 593, 594, 7, 9, 0, 0, 594, 595, 7, 3, 0, 0, 595, 596, 7, 2, 0, 0, 596, 597, 7, 5, 0, 0, 597, 598, 7, 12, 0, 0, 598, 599, 7, 5, 0, 0, 599, 600, 7, 2, 0, 0, 600, 601, 1, 0, 0, 0, 601, 602, 6, 17, 0, 0, 602, 51, 1, 0, 0, 0, 603, 604, 4, 18, 1, 0, 604, 605, 7, 13, 0, 0, 605, 606, 7, 7, 0, 0, 606, 607, 7, 7, 0, 0, 607, 608, 7, 18, 0, 0, 608, 609, 7, 20, 0, 0, 609, 610, 7, 8, 0, 0, 610, 611, 5, 95, 0, 0, 611, 612, 5, 128020, 0, 0, 612, 613, 1, 0, 0, 0, 613, 614, 6, 18, 9, 0, 614, 53, 1, 0, 0, 0, 615, 616, 4, 19, 2, 0, 616, 617, 7, 16, 0, 0, 617, 618, 7, 3, 0, 0, 618, 619, 7, 5, 0, 0, 619, 620, 7, 6, 0, 0, 620, 621, 7, 1, 0, 0, 621, 622, 7, 4, 0, 0, 622, 623, 7, 2, 0, 0, 623, 624, 1, 0, 0, 0, 624, 625, 6, 19, 10, 0, 625, 55, 1, 0, 0, 0, 626, 627, 4, 20, 3, 0, 627, 628, 7, 15, 0, 0, 628, 629, 7, 20, 0, 0, 629, 630, 7, 13, 0, 0, 630, 631, 7, 13, 0, 0, 631, 632, 1, 0, 0, 0, 632, 633, 6, 20, 8, 0, 633, 57, 1, 0, 0, 0, 634, 635, 4, 21, 4, 0, 635, 636, 7, 13, 0, 0, 636, 637, 7, 3, 0, 0, 637, 638, 7, 15, 0, 0, 638, 639, 7, 5, 0, 0, 639, 640, 1, 0, 0, 0, 640, 641, 6, 21, 8, 0, 641, 59, 1, 0, 0, 0, 642, 643, 4, 22, 5, 0, 643, 644, 7, 6, 0, 0, 644, 645, 7, 1, 0, 0, 645, 646, 7, 17, 0, 0, 646, 647, 7, 10, 0, 0, 647, 648, 7, 5, 0, 0, 648, 649, 1, 0, 0, 0, 649, 650, 6, 22, 8, 0, 650, 61, 1, 0, 0, 0, 651, 653, 8, 21, 0, 0, 652, 651, 1, 0, 0, 0, 653, 654, 1, 0, 0, 0, 654, 652, 1, 0, 0, 0, 654, 655, 1, 0, 0, 0, 655, 656, 1, 0, 0, 0, 656, 657, 6, 23, 0, 0, 657, 63, 1, 0, 0, 0, 658, 659, 5, 47, 0, 0, 659, 660, 5, 47, 0, 0, 660, 664, 1, 0, 0, 0, 661, 663, 8, 22, 0, 0, 662, 661, 1, 0, 0, 0, 663, 666, 1, 0, 0, 0, 664, 662, 1, 0, 0, 0, 664, 665, 1, 0, 0, 0, 665, 668, 1, 0, 0, 0, 666, 664, 1, 0, 0, 0, 667, 669, 5, 13, 0, 0, 668, 667, 1, 0, 0, 0, 668, 669, 1, 0, 0, 0, 669, 671, 1, 0, 0, 0, 670, 672, 5, 10, 0, 0, 671, 670, 1, 0, 0, 0, 671, 672, 1, 0, 0, 0, 672, 673, 1, 0, 0, 0, 673, 674, 6, 24, 11, 0, 674, 65, 1, 0, 0, 0, 675, 676, 5, 47, 0, 0, 676, 677, 5, 42, 0, 0, 677, 682, 1, 0, 0, 0, 678, 681, 3, 66, 25, 0, 679, 681, 9, 0, 0, 0, 680, 678, 1, 0, 0, 0, 680, 679, 1, 0, 0, 0, 681, 684, 1, 0, 0, 0, 682, 683, 1, 0, 0, 0, 682, 680, 1, 0, 0, 0, 683, 685, 1, 0, 0, 0, 684, 682, 1, 0, 0, 0, 685, 686, 5, 42, 0, 0, 686, 687, 5, 47, 0, 0, 687, 688, 1, 0, 0, 0, 688, 689, 6, 25, 11, 0, 689, 67, 1, 0, 0, 0, 690, 692, 7, 23, 0, 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, 695, 1, 0, 0, 0, 695, 696, 6, 26, 11, 0, 696, 69, 1, 0, 0, 0, 697, 698, 5, 124, 0, 0, 698, 699, 1, 0, 0, 0, 699, 700, 6, 27, 12, 0, 700, 71, 1, 0, 0, 0, 701, 702, 7, 24, 0, 0, 702, 73, 1, 0, 0, 0, 703, 704, 7, 25, 0, 0, 704, 75, 1, 0, 0, 0, 705, 706, 5, 92, 0, 0, 706, 707, 7, 26, 0, 0, 707, 77, 1, 0, 0, 0, 708, 709, 8, 27, 0, 0, 709, 79, 1, 0, 0, 0, 710, 712, 7, 3, 0, 0, 711, 713, 7, 28, 0, 0, 712, 711, 1, 0, 0, 0, 712, 713, 1, 0, 0, 0, 713, 715, 1, 0, 0, 0, 714, 716, 3, 72, 28, 0, 715, 714, 1, 0, 0, 0, 716, 717, 1, 0, 0, 0, 717, 715, 1, 0, 0, 0, 717, 718, 1, 0, 0, 0, 718, 81, 1, 0, 0, 0, 719, 720, 5, 64, 0, 0, 720, 83, 1, 0, 0, 0, 721, 722, 5, 96, 0, 0, 722, 85, 1, 0, 0, 0, 723, 727, 8, 29, 0, 0, 724, 725, 5, 96, 0, 0, 725, 727, 5, 96, 0, 0, 726, 723, 1, 0, 0, 0, 726, 724, 1, 0, 0, 0, 727, 87, 1, 0, 0, 0, 728, 729, 5, 95, 0, 0, 729, 89, 1, 0, 0, 0, 730, 734, 3, 74, 29, 0, 731, 734, 3, 72, 28, 0, 732, 734, 3, 88, 36, 0, 733, 730, 1, 0, 0, 0, 733, 731, 1, 0, 0, 0, 733, 732, 1, 0, 0, 0, 734, 91, 1, 0, 0, 0, 735, 740, 5, 34, 0, 0, 736, 739, 3, 76, 30, 0, 737, 739, 3, 78, 31, 0, 738, 736, 1, 0, 0, 0, 738, 737, 1, 0, 0, 0, 739, 742, 1, 0, 0, 0, 740, 738, 1, 0, 0, 0, 740, 741, 1, 0, 0, 0, 741, 743, 1, 0, 0, 0, 742, 740, 1, 0, 0, 0, 743, 765, 5, 34, 0, 0, 744, 745, 5, 34, 0, 0, 745, 746, 5, 34, 0, 0, 746, 747, 5, 34, 0, 0, 747, 751, 1, 0, 0, 0, 748, 750, 8, 22, 0, 0, 749, 748, 1, 0, 0, 0, 750, 753, 1, 0, 0, 0, 751, 752, 1, 0, 0, 0, 751, 749, 1, 0, 0, 0, 752, 754, 1, 0, 0, 0, 753, 751, 1, 0, 0, 0, 754, 755, 5, 34, 0, 0, 755, 756, 5, 34, 0, 0, 756, 757, 5, 34, 0, 0, 757, 759, 1, 0, 0, 0, 758, 760, 5, 34, 0, 0, 759, 758, 1, 0, 0, 0, 759, 760, 1, 0, 0, 0, 760, 762, 1, 0, 0, 0, 761, 763, 5, 34, 0, 0, 762, 761, 1, 0, 0, 0, 762, 763, 1, 0, 0, 0, 763, 765, 1, 0, 0, 0, 764, 735, 1, 0, 0, 0, 764, 744, 1, 0, 0, 0, 765, 93, 1, 0, 0, 0, 766, 768, 3, 72, 28, 0, 767, 766, 1, 0, 0, 0, 768, 769, 1, 0, 0, 0, 769, 767, 1, 0, 0, 0, 769, 770, 1, 0, 0, 0, 770, 95, 1, 0, 0, 0, 771, 773, 3, 72, 28, 0, 772, 771, 1, 0, 0, 0, 773, 774, 1, 0, 0, 0, 774, 772, 1, 0, 0, 0, 774, 775, 1, 0, 0, 0, 775, 776, 1, 0, 0, 0, 776, 780, 3, 114, 49, 0, 777, 779, 3, 72, 28, 0, 778, 777, 1, 0, 0, 0, 779, 782, 1, 0, 0, 0, 780, 778, 1, 0, 0, 0, 780, 781, 1, 0, 0, 0, 781, 814, 1, 0, 0, 0, 782, 780, 1, 0, 0, 0, 783, 785, 3, 114, 49, 0, 784, 786, 3, 72, 28, 0, 785, 784, 1, 0, 0, 0, 786, 787, 1, 0, 0, 0, 787, 785, 1, 0, 0, 0, 787, 788, 1, 0, 0, 0, 788, 814, 1, 0, 0, 0, 789, 791, 3, 72, 28, 0, 790, 789, 1, 0, 0, 0, 791, 792, 1, 0, 0, 0, 792, 790, 1, 0, 0, 0, 792, 793, 1, 0, 0, 0, 793, 801, 1, 0, 0, 0, 794, 798, 3, 114, 49, 0, 795, 797, 3, 72, 28, 0, 796, 795, 1, 0, 0, 0, 797, 800, 1, 0, 0, 0, 798, 796, 1, 0, 0, 0, 798, 799, 1, 0, 0, 0, 799, 802, 1, 0, 0, 0, 800, 798, 1, 0, 0, 0, 801, 794, 1, 0, 0, 0, 801, 802, 1, 0, 0, 0, 802, 803, 1, 0, 0, 0, 803, 804, 3, 80, 32, 0, 804, 814, 1, 0, 0, 0, 805, 807, 3, 114, 49, 0, 806, 808, 3, 72, 28, 0, 807, 806, 1, 0, 0, 0, 808, 809, 1, 0, 0, 0, 809, 807, 1, 0, 0, 0, 809, 810, 1, 0, 0, 0, 810, 811, 1, 0, 0, 0, 811, 812, 3, 80, 32, 0, 812, 814, 1, 0, 0, 0, 813, 772, 1, 0, 0, 0, 813, 783, 1, 0, 0, 0, 813, 790, 1, 0, 0, 0, 813, 805, 1, 0, 0, 0, 814, 97, 1, 0, 0, 0, 815, 816, 7, 30, 0, 0, 816, 817, 7, 31, 0, 0, 817, 99, 1, 0, 0, 0, 818, 819, 7, 12, 0, 0, 819, 820, 7, 9, 0, 0, 820, 821, 7, 0, 0, 0, 821, 101, 1, 0, 0, 0, 822, 823, 7, 12, 0, 0, 823, 824, 7, 2, 0, 0, 824, 825, 7, 4, 0, 0, 825, 103, 1, 0, 0, 0, 826, 827, 5, 61, 0, 0, 827, 105, 1, 0, 0, 0, 828, 829, 5, 58, 0, 0, 829, 830, 5, 58, 0, 0, 830, 107, 1, 0, 0, 0, 831, 832, 5, 58, 0, 0, 832, 109, 1, 0, 0, 0, 833, 834, 5, 44, 0, 0, 834, 111, 1, 0, 0, 0, 835, 836, 7, 0, 0, 0, 836, 837, 7, 3, 0, 0, 837, 838, 7, 2, 0, 0, 838, 839, 7, 4, 0, 0, 839, 113, 1, 0, 0, 0, 840, 841, 5, 46, 0, 0, 841, 115, 1, 0, 0, 0, 842, 843, 7, 15, 0, 0, 843, 844, 7, 12, 0, 0, 844, 845, 7, 13, 0, 0, 845, 846, 7, 2, 0, 0, 846, 847, 7, 3, 0, 0, 847, 117, 1, 0, 0, 0, 848, 849, 7, 15, 0, 0, 849, 850, 7, 1, 0, 0, 850, 851, 7, 6, 0, 0, 851, 852, 7, 2, 0, 0, 852, 853, 7, 5, 0, 0, 853, 119, 1, 0, 0, 0, 854, 855, 7, 1, 0, 0, 855, 856, 7, 9, 0, 0, 856, 121, 1, 0, 0, 0, 857, 858, 7, 1, 0, 0, 858, 859, 7, 2, 0, 0, 859, 123, 1, 0, 0, 0, 860, 861, 7, 13, 0, 0, 861, 862, 7, 12, 0, 0, 862, 863, 7, 2, 0, 0, 863, 864, 7, 5, 0, 0, 864, 125, 1, 0, 0, 0, 865, 866, 7, 13, 0, 0, 866, 867, 7, 1, 0, 0, 867, 868, 7, 18, 0, 0, 868, 869, 7, 3, 0, 0, 869, 127, 1, 0, 0, 0, 870, 871, 5, 40, 0, 0, 871, 129, 1, 0, 0, 0, 872, 873, 7, 9, 0, 0, 873, 874, 7, 7, 0, 0, 874, 875, 7, 5, 0, 0, 875, 131, 1, 0, 0, 0, 876, 877, 7, 9, 0, 0, 877, 878, 7, 20, 0, 0, 878, 879, 7, 13, 0, 0, 879, 880, 7, 13, 0, 0, 880, 133, 1, 0, 0, 0, 881, 882, 7, 9, 0, 0, 882, 883, 7, 20, 0, 0, 883, 884, 7, 13, 0, 0, 884, 885, 7, 13, 0, 0, 885, 886, 7, 2, 0, 0, 886, 135, 1, 0, 0, 0, 887, 888, 7, 7, 0, 0, 888, 889, 7, 6, 0, 0, 889, 137, 1, 0, 0, 0, 890, 891, 5, 63, 0, 0, 891, 139, 1, 0, 0, 0, 892, 893, 7, 6, 0, 0, 893, 894, 7, 13, 0, 0, 894, 895, 7, 1, 0, 0, 895, 896, 7, 18, 0, 0, 896, 897, 7, 3, 0, 0, 897, 141, 1, 0, 0, 0, 898, 899, 5, 41, 0, 0, 899, 143, 1, 0, 0, 0, 900, 901, 7, 5, 0, 0, 901, 902, 7, 6, 0, 0, 902, 903, 7, 20, 0, 0, 903, 904, 7, 3, 0, 0, 904, 145, 1, 0, 0, 0, 905, 906, 5, 61, 0, 0, 906, 907, 5, 61, 0, 0, 907, 147, 1, 0, 0, 0, 908, 909, 5, 61, 0, 0, 909, 910, 5, 126, 0, 0, 910, 149, 1, 0, 0, 0, 911, 912, 5, 33, 0, 0, 912, 913, 5, 61, 0, 0, 913, 151, 1, 0, 0, 0, 914, 915, 5, 60, 0, 0, 915, 153, 1, 0, 0, 0, 916, 917, 5, 60, 0, 0, 917, 918, 5, 61, 0, 0, 918, 155, 1, 0, 0, 0, 919, 920, 5, 62, 0, 0, 920, 157, 1, 0, 0, 0, 921, 922, 5, 62, 0, 0, 922, 923, 5, 61, 0, 0, 923, 159, 1, 0, 0, 0, 924, 925, 5, 43, 0, 0, 925, 161, 1, 0, 0, 0, 926, 927, 5, 45, 0, 0, 927, 163, 1, 0, 0, 0, 928, 929, 5, 42, 0, 0, 929, 165, 1, 0, 0, 0, 930, 931, 5, 47, 0, 0, 931, 167, 1, 0, 0, 0, 932, 933, 5, 37, 0, 0, 933, 169, 1, 0, 0, 0, 934, 935, 5, 123, 0, 0, 935, 171, 1, 0, 0, 0, 936, 937, 5, 125, 0, 0, 937, 173, 1, 0, 0, 0, 938, 939, 3, 46, 15, 0, 939, 940, 1, 0, 0, 0, 940, 941, 6, 79, 13, 0, 941, 175, 1, 0, 0, 0, 942, 945, 3, 138, 61, 0, 943, 946, 3, 74, 29, 0, 944, 946, 3, 88, 36, 0, 945, 943, 1, 0, 0, 0, 945, 944, 1, 0, 0, 0, 946, 950, 1, 0, 0, 0, 947, 949, 3, 90, 37, 0, 948, 947, 1, 0, 0, 0, 949, 952, 1, 0, 0, 0, 950, 948, 1, 0, 0, 0, 950, 951, 1, 0, 0, 0, 951, 960, 1, 0, 0, 0, 952, 950, 1, 0, 0, 0, 953, 955, 3, 138, 61, 0, 954, 956, 3, 72, 28, 0, 955, 954, 1, 0, 0, 0, 956, 957, 1, 0, 0, 0, 957, 955, 1, 0, 0, 0, 957, 958, 1, 0, 0, 0, 958, 960, 1, 0, 0, 0, 959, 942, 1, 0, 0, 0, 959, 953, 1, 0, 0, 0, 960, 177, 1, 0, 0, 0, 961, 962, 5, 91, 0, 0, 962, 963, 1, 0, 0, 0, 963, 964, 6, 81, 0, 0, 964, 965, 6, 81, 0, 0, 965, 179, 1, 0, 0, 0, 966, 967, 5, 93, 0, 0, 967, 968, 1, 0, 0, 0, 968, 969, 6, 82, 12, 0, 969, 970, 6, 82, 12, 0, 970, 181, 1, 0, 0, 0, 971, 975, 3, 74, 29, 0, 972, 974, 3, 90, 37, 0, 973, 972, 1, 0, 0, 0, 974, 977, 1, 0, 0, 0, 975, 973, 1, 0, 0, 0, 975, 976, 1, 0, 0, 0, 976, 988, 1, 0, 0, 0, 977, 975, 1, 0, 0, 0, 978, 981, 3, 88, 36, 0, 979, 981, 3, 82, 33, 0, 980, 978, 1, 0, 0, 0, 980, 979, 1, 0, 0, 0, 981, 983, 1, 0, 0, 0, 982, 984, 3, 90, 37, 0, 983, 982, 1, 0, 0, 0, 984, 985, 1, 0, 0, 0, 985, 983, 1, 0, 0, 0, 985, 986, 1, 0, 0, 0, 986, 988, 1, 0, 0, 0, 987, 971, 1, 0, 0, 0, 987, 980, 1, 0, 0, 0, 988, 183, 1, 0, 0, 0, 989, 991, 3, 84, 34, 0, 990, 992, 3, 86, 35, 0, 991, 990, 1, 0, 0, 0, 992, 993, 1, 0, 0, 0, 993, 991, 1, 0, 0, 0, 993, 994, 1, 0, 0, 0, 994, 995, 1, 0, 0, 0, 995, 996, 3, 84, 34, 0, 996, 185, 1, 0, 0, 0, 997, 998, 3, 184, 84, 0, 998, 187, 1, 0, 0, 0, 999, 1000, 3, 64, 24, 0, 1000, 1001, 1, 0, 0, 0, 1001, 1002, 6, 86, 11, 0, 1002, 189, 1, 0, 0, 0, 1003, 1004, 3, 66, 25, 0, 1004, 1005, 1, 0, 0, 0, 1005, 1006, 6, 87, 11, 0, 1006, 191, 1, 0, 0, 0, 1007, 1008, 3, 68, 26, 0, 1008, 1009, 1, 0, 0, 0, 1009, 1010, 6, 88, 11, 0, 1010, 193, 1, 0, 0, 0, 1011, 1012, 3, 178, 81, 0, 1012, 1013, 1, 0, 0, 0, 1013, 1014, 6, 89, 14, 0, 1014, 1015, 6, 89, 15, 0, 1015, 195, 1, 0, 0, 0, 1016, 1017, 3, 70, 27, 0, 1017, 1018, 1, 0, 0, 0, 1018, 1019, 6, 90, 16, 0, 1019, 1020, 6, 90, 12, 0, 1020, 197, 1, 0, 0, 0, 1021, 1022, 3, 68, 26, 0, 1022, 1023, 1, 0, 0, 0, 1023, 1024, 6, 91, 11, 0, 1024, 199, 1, 0, 0, 0, 1025, 1026, 3, 64, 24, 0, 1026, 1027, 1, 0, 0, 0, 1027, 1028, 6, 92, 11, 0, 1028, 201, 1, 0, 0, 0, 1029, 1030, 3, 66, 25, 0, 1030, 1031, 1, 0, 0, 0, 1031, 1032, 6, 93, 11, 0, 1032, 203, 1, 0, 0, 0, 1033, 1034, 3, 70, 27, 0, 1034, 1035, 1, 0, 0, 0, 1035, 1036, 6, 94, 16, 0, 1036, 1037, 6, 94, 12, 0, 1037, 205, 1, 0, 0, 0, 1038, 1039, 3, 178, 81, 0, 1039, 1040, 1, 0, 0, 0, 1040, 1041, 6, 95, 14, 0, 1041, 207, 1, 0, 0, 0, 1042, 1043, 3, 180, 82, 0, 1043, 1044, 1, 0, 0, 0, 1044, 1045, 6, 96, 17, 0, 1045, 209, 1, 0, 0, 0, 1046, 1047, 3, 108, 46, 0, 1047, 1048, 1, 0, 0, 0, 1048, 1049, 6, 97, 18, 0, 1049, 211, 1, 0, 0, 0, 1050, 1051, 3, 110, 47, 0, 1051, 1052, 1, 0, 0, 0, 1052, 1053, 6, 98, 19, 0, 1053, 213, 1, 0, 0, 0, 1054, 1055, 3, 104, 44, 0, 1055, 1056, 1, 0, 0, 0, 1056, 1057, 6, 99, 20, 0, 1057, 215, 1, 0, 0, 0, 1058, 1059, 7, 16, 0, 0, 1059, 1060, 7, 3, 0, 0, 1060, 1061, 7, 5, 0, 0, 1061, 1062, 7, 12, 0, 0, 1062, 1063, 7, 0, 0, 0, 1063, 1064, 7, 12, 0, 0, 1064, 1065, 7, 5, 0, 0, 1065, 1066, 7, 12, 0, 0, 1066, 217, 1, 0, 0, 0, 1067, 1071, 8, 32, 0, 0, 1068, 1069, 5, 47, 0, 0, 1069, 1071, 8, 33, 0, 0, 1070, 1067, 1, 0, 0, 0, 1070, 1068, 1, 0, 0, 0, 1071, 219, 1, 0, 0, 0, 1072, 1074, 3, 218, 101, 0, 1073, 1072, 1, 0, 0, 0, 1074, 1075, 1, 0, 0, 0, 1075, 1073, 1, 0, 0, 0, 1075, 1076, 1, 0, 0, 0, 1076, 221, 1, 0, 0, 0, 1077, 1078, 3, 220, 102, 0, 1078, 1079, 1, 0, 0, 0, 1079, 1080, 6, 103, 21, 0, 1080, 223, 1, 0, 0, 0, 1081, 1082, 3, 92, 38, 0, 1082, 1083, 1, 0, 0, 0, 1083, 1084, 6, 104, 22, 0, 1084, 225, 1, 0, 0, 0, 1085, 1086, 3, 64, 24, 0, 1086, 1087, 1, 0, 0, 0, 1087, 1088, 6, 105, 11, 0, 1088, 227, 1, 0, 0, 0, 1089, 1090, 3, 66, 25, 0, 1090, 1091, 1, 0, 0, 0, 1091, 1092, 6, 106, 11, 0, 1092, 229, 1, 0, 0, 0, 1093, 1094, 3, 68, 26, 0, 1094, 1095, 1, 0, 0, 0, 1095, 1096, 6, 107, 11, 0, 1096, 231, 1, 0, 0, 0, 1097, 1098, 3, 70, 27, 0, 1098, 1099, 1, 0, 0, 0, 1099, 1100, 6, 108, 16, 0, 1100, 1101, 6, 108, 12, 0, 1101, 233, 1, 0, 0, 0, 1102, 1103, 3, 114, 49, 0, 1103, 1104, 1, 0, 0, 0, 1104, 1105, 6, 109, 23, 0, 1105, 235, 1, 0, 0, 0, 1106, 1107, 3, 110, 47, 0, 1107, 1108, 1, 0, 0, 0, 1108, 1109, 6, 110, 19, 0, 1109, 237, 1, 0, 0, 0, 1110, 1111, 4, 111, 6, 0, 1111, 1112, 3, 138, 61, 0, 1112, 1113, 1, 0, 0, 0, 1113, 1114, 6, 111, 24, 0, 1114, 239, 1, 0, 0, 0, 1115, 1116, 4, 112, 7, 0, 1116, 1117, 3, 176, 80, 0, 1117, 1118, 1, 0, 0, 0, 1118, 1119, 6, 112, 25, 0, 1119, 241, 1, 0, 0, 0, 1120, 1125, 3, 74, 29, 0, 1121, 1125, 3, 72, 28, 0, 1122, 1125, 3, 88, 36, 0, 1123, 1125, 3, 164, 74, 0, 1124, 1120, 1, 0, 0, 0, 1124, 1121, 1, 0, 0, 0, 1124, 1122, 1, 0, 0, 0, 1124, 1123, 1, 0, 0, 0, 1125, 243, 1, 0, 0, 0, 1126, 1129, 3, 74, 29, 0, 1127, 1129, 3, 164, 74, 0, 1128, 1126, 1, 0, 0, 0, 1128, 1127, 1, 0, 0, 0, 1129, 1133, 1, 0, 0, 0, 1130, 1132, 3, 242, 113, 0, 1131, 1130, 1, 0, 0, 0, 1132, 1135, 1, 0, 0, 0, 1133, 1131, 1, 0, 0, 0, 1133, 1134, 1, 0, 0, 0, 1134, 1146, 1, 0, 0, 0, 1135, 1133, 1, 0, 0, 0, 1136, 1139, 3, 88, 36, 0, 1137, 1139, 3, 82, 33, 0, 1138, 1136, 1, 0, 0, 0, 1138, 1137, 1, 0, 0, 0, 1139, 1141, 1, 0, 0, 0, 1140, 1142, 3, 242, 113, 0, 1141, 1140, 1, 0, 0, 0, 1142, 1143, 1, 0, 0, 0, 1143, 1141, 1, 0, 0, 0, 1143, 1144, 1, 0, 0, 0, 1144, 1146, 1, 0, 0, 0, 1145, 1128, 1, 0, 0, 0, 1145, 1138, 1, 0, 0, 0, 1146, 245, 1, 0, 0, 0, 1147, 1150, 3, 244, 114, 0, 1148, 1150, 3, 184, 84, 0, 1149, 1147, 1, 0, 0, 0, 1149, 1148, 1, 0, 0, 0, 1150, 1151, 1, 0, 0, 0, 1151, 1149, 1, 0, 0, 0, 1151, 1152, 1, 0, 0, 0, 1152, 247, 1, 0, 0, 0, 1153, 1154, 3, 64, 24, 0, 1154, 1155, 1, 0, 0, 0, 1155, 1156, 6, 116, 11, 0, 1156, 249, 1, 0, 0, 0, 1157, 1158, 3, 66, 25, 0, 1158, 1159, 1, 0, 0, 0, 1159, 1160, 6, 117, 11, 0, 1160, 251, 1, 0, 0, 0, 1161, 1162, 3, 68, 26, 0, 1162, 1163, 1, 0, 0, 0, 1163, 1164, 6, 118, 11, 0, 1164, 253, 1, 0, 0, 0, 1165, 1166, 3, 70, 27, 0, 1166, 1167, 1, 0, 0, 0, 1167, 1168, 6, 119, 16, 0, 1168, 1169, 6, 119, 12, 0, 1169, 255, 1, 0, 0, 0, 1170, 1171, 3, 104, 44, 0, 1171, 1172, 1, 0, 0, 0, 1172, 1173, 6, 120, 20, 0, 1173, 257, 1, 0, 0, 0, 1174, 1175, 3, 110, 47, 0, 1175, 1176, 1, 0, 0, 0, 1176, 1177, 6, 121, 19, 0, 1177, 259, 1, 0, 0, 0, 1178, 1179, 3, 114, 49, 0, 1179, 1180, 1, 0, 0, 0, 1180, 1181, 6, 122, 23, 0, 1181, 261, 1, 0, 0, 0, 1182, 1183, 4, 123, 8, 0, 1183, 1184, 3, 138, 61, 0, 1184, 1185, 1, 0, 0, 0, 1185, 1186, 6, 123, 24, 0, 1186, 263, 1, 0, 0, 0, 1187, 1188, 4, 124, 9, 0, 1188, 1189, 3, 176, 80, 0, 1189, 1190, 1, 0, 0, 0, 1190, 1191, 6, 124, 25, 0, 1191, 265, 1, 0, 0, 0, 1192, 1193, 7, 12, 0, 0, 1193, 1194, 7, 2, 0, 0, 1194, 267, 1, 0, 0, 0, 1195, 1196, 3, 246, 115, 0, 1196, 1197, 1, 0, 0, 0, 1197, 1198, 6, 126, 26, 0, 1198, 269, 1, 0, 0, 0, 1199, 1200, 3, 64, 24, 0, 1200, 1201, 1, 0, 0, 0, 1201, 1202, 6, 127, 11, 0, 1202, 271, 1, 0, 0, 0, 1203, 1204, 3, 66, 25, 0, 1204, 1205, 1, 0, 0, 0, 1205, 1206, 6, 128, 11, 0, 1206, 273, 1, 0, 0, 0, 1207, 1208, 3, 68, 26, 0, 1208, 1209, 1, 0, 0, 0, 1209, 1210, 6, 129, 11, 0, 1210, 275, 1, 0, 0, 0, 1211, 1212, 3, 70, 27, 0, 1212, 1213, 1, 0, 0, 0, 1213, 1214, 6, 130, 16, 0, 1214, 1215, 6, 130, 12, 0, 1215, 277, 1, 0, 0, 0, 1216, 1217, 3, 178, 81, 0, 1217, 1218, 1, 0, 0, 0, 1218, 1219, 6, 131, 14, 0, 1219, 1220, 6, 131, 27, 0, 1220, 279, 1, 0, 0, 0, 1221, 1222, 7, 7, 0, 0, 1222, 1223, 7, 9, 0, 0, 1223, 1224, 1, 0, 0, 0, 1224, 1225, 6, 132, 28, 0, 1225, 281, 1, 0, 0, 0, 1226, 1227, 7, 19, 0, 0, 1227, 1228, 7, 1, 0, 0, 1228, 1229, 7, 5, 0, 0, 1229, 1230, 7, 10, 0, 0, 1230, 1231, 1, 0, 0, 0, 1231, 1232, 6, 133, 28, 0, 1232, 283, 1, 0, 0, 0, 1233, 1234, 8, 34, 0, 0, 1234, 285, 1, 0, 0, 0, 1235, 1237, 3, 284, 134, 0, 1236, 1235, 1, 0, 0, 0, 1237, 1238, 1, 0, 0, 0, 1238, 1236, 1, 0, 0, 0, 1238, 1239, 1, 0, 0, 0, 1239, 1240, 1, 0, 0, 0, 1240, 1241, 3, 108, 46, 0, 1241, 1243, 1, 0, 0, 0, 1242, 1236, 1, 0, 0, 0, 1242, 1243, 1, 0, 0, 0, 1243, 1245, 1, 0, 0, 0, 1244, 1246, 3, 284, 134, 0, 1245, 1244, 1, 0, 0, 0, 1246, 1247, 1, 0, 0, 0, 1247, 1245, 1, 0, 0, 0, 1247, 1248, 1, 0, 0, 0, 1248, 287, 1, 0, 0, 0, 1249, 1250, 3, 286, 135, 0, 1250, 1251, 1, 0, 0, 0, 1251, 1252, 6, 136, 29, 0, 1252, 289, 1, 0, 0, 0, 1253, 1254, 3, 64, 24, 0, 1254, 1255, 1, 0, 0, 0, 1255, 1256, 6, 137, 11, 0, 1256, 291, 1, 0, 0, 0, 1257, 1258, 3, 66, 25, 0, 1258, 1259, 1, 0, 0, 0, 1259, 1260, 6, 138, 11, 0, 1260, 293, 1, 0, 0, 0, 1261, 1262, 3, 68, 26, 0, 1262, 1263, 1, 0, 0, 0, 1263, 1264, 6, 139, 11, 0, 1264, 295, 1, 0, 0, 0, 1265, 1266, 3, 70, 27, 0, 1266, 1267, 1, 0, 0, 0, 1267, 1268, 6, 140, 16, 0, 1268, 1269, 6, 140, 12, 0, 1269, 1270, 6, 140, 12, 0, 1270, 297, 1, 0, 0, 0, 1271, 1272, 3, 104, 44, 0, 1272, 1273, 1, 0, 0, 0, 1273, 1274, 6, 141, 20, 0, 1274, 299, 1, 0, 0, 0, 1275, 1276, 3, 110, 47, 0, 1276, 1277, 1, 0, 0, 0, 1277, 1278, 6, 142, 19, 0, 1278, 301, 1, 0, 0, 0, 1279, 1280, 3, 114, 49, 0, 1280, 1281, 1, 0, 0, 0, 1281, 1282, 6, 143, 23, 0, 1282, 303, 1, 0, 0, 0, 1283, 1284, 3, 282, 133, 0, 1284, 1285, 1, 0, 0, 0, 1285, 1286, 6, 144, 30, 0, 1286, 305, 1, 0, 0, 0, 1287, 1288, 3, 246, 115, 0, 1288, 1289, 1, 0, 0, 0, 1289, 1290, 6, 145, 26, 0, 1290, 307, 1, 0, 0, 0, 1291, 1292, 3, 186, 85, 0, 1292, 1293, 1, 0, 0, 0, 1293, 1294, 6, 146, 31, 0, 1294, 309, 1, 0, 0, 0, 1295, 1296, 4, 147, 10, 0, 1296, 1297, 3, 138, 61, 0, 1297, 1298, 1, 0, 0, 0, 1298, 1299, 6, 147, 24, 0, 1299, 311, 1, 0, 0, 0, 1300, 1301, 4, 148, 11, 0, 1301, 1302, 3, 176, 80, 0, 1302, 1303, 1, 0, 0, 0, 1303, 1304, 6, 148, 25, 0, 1304, 313, 1, 0, 0, 0, 1305, 1306, 3, 64, 24, 0, 1306, 1307, 1, 0, 0, 0, 1307, 1308, 6, 149, 11, 0, 1308, 315, 1, 0, 0, 0, 1309, 1310, 3, 66, 25, 0, 1310, 1311, 1, 0, 0, 0, 1311, 1312, 6, 150, 11, 0, 1312, 317, 1, 0, 0, 0, 1313, 1314, 3, 68, 26, 0, 1314, 1315, 1, 0, 0, 0, 1315, 1316, 6, 151, 11, 0, 1316, 319, 1, 0, 0, 0, 1317, 1318, 3, 70, 27, 0, 1318, 1319, 1, 0, 0, 0, 1319, 1320, 6, 152, 16, 0, 1320, 1321, 6, 152, 12, 0, 1321, 321, 1, 0, 0, 0, 1322, 1323, 3, 114, 49, 0, 1323, 1324, 1, 0, 0, 0, 1324, 1325, 6, 153, 23, 0, 1325, 323, 1, 0, 0, 0, 1326, 1327, 4, 154, 12, 0, 1327, 1328, 3, 138, 61, 0, 1328, 1329, 1, 0, 0, 0, 1329, 1330, 6, 154, 24, 0, 1330, 325, 1, 0, 0, 0, 1331, 1332, 4, 155, 13, 0, 1332, 1333, 3, 176, 80, 0, 1333, 1334, 1, 0, 0, 0, 1334, 1335, 6, 155, 25, 0, 1335, 327, 1, 0, 0, 0, 1336, 1337, 3, 186, 85, 0, 1337, 1338, 1, 0, 0, 0, 1338, 1339, 6, 156, 31, 0, 1339, 329, 1, 0, 0, 0, 1340, 1341, 3, 182, 83, 0, 1341, 1342, 1, 0, 0, 0, 1342, 1343, 6, 157, 32, 0, 1343, 331, 1, 0, 0, 0, 1344, 1345, 3, 64, 24, 0, 1345, 1346, 1, 0, 0, 0, 1346, 1347, 6, 158, 11, 0, 1347, 333, 1, 0, 0, 0, 1348, 1349, 3, 66, 25, 0, 1349, 1350, 1, 0, 0, 0, 1350, 1351, 6, 159, 11, 0, 1351, 335, 1, 0, 0, 0, 1352, 1353, 3, 68, 26, 0, 1353, 1354, 1, 0, 0, 0, 1354, 1355, 6, 160, 11, 0, 1355, 337, 1, 0, 0, 0, 1356, 1357, 3, 70, 27, 0, 1357, 1358, 1, 0, 0, 0, 1358, 1359, 6, 161, 16, 0, 1359, 1360, 6, 161, 12, 0, 1360, 339, 1, 0, 0, 0, 1361, 1362, 7, 1, 0, 0, 1362, 1363, 7, 9, 0, 0, 1363, 1364, 7, 15, 0, 0, 1364, 1365, 7, 7, 0, 0, 1365, 341, 1, 0, 0, 0, 1366, 1367, 3, 64, 24, 0, 1367, 1368, 1, 0, 0, 0, 1368, 1369, 6, 163, 11, 0, 1369, 343, 1, 0, 0, 0, 1370, 1371, 3, 66, 25, 0, 1371, 1372, 1, 0, 0, 0, 1372, 1373, 6, 164, 11, 0, 1373, 345, 1, 0, 0, 0, 1374, 1375, 3, 68, 26, 0, 1375, 1376, 1, 0, 0, 0, 1376, 1377, 6, 165, 11, 0, 1377, 347, 1, 0, 0, 0, 1378, 1379, 3, 180, 82, 0, 1379, 1380, 1, 0, 0, 0, 1380, 1381, 6, 166, 17, 0, 1381, 1382, 6, 166, 12, 0, 1382, 349, 1, 0, 0, 0, 1383, 1384, 3, 108, 46, 0, 1384, 1385, 1, 0, 0, 0, 1385, 1386, 6, 167, 18, 0, 1386, 351, 1, 0, 0, 0, 1387, 1393, 3, 82, 33, 0, 1388, 1393, 3, 72, 28, 0, 1389, 1393, 3, 114, 49, 0, 1390, 1393, 3, 74, 29, 0, 1391, 1393, 3, 88, 36, 0, 1392, 1387, 1, 0, 0, 0, 1392, 1388, 1, 0, 0, 0, 1392, 1389, 1, 0, 0, 0, 1392, 1390, 1, 0, 0, 0, 1392, 1391, 1, 0, 0, 0, 1393, 1394, 1, 0, 0, 0, 1394, 1392, 1, 0, 0, 0, 1394, 1395, 1, 0, 0, 0, 1395, 353, 1, 0, 0, 0, 1396, 1397, 3, 64, 24, 0, 1397, 1398, 1, 0, 0, 0, 1398, 1399, 6, 169, 11, 0, 1399, 355, 1, 0, 0, 0, 1400, 1401, 3, 66, 25, 0, 1401, 1402, 1, 0, 0, 0, 1402, 1403, 6, 170, 11, 0, 1403, 357, 1, 0, 0, 0, 1404, 1405, 3, 68, 26, 0, 1405, 1406, 1, 0, 0, 0, 1406, 1407, 6, 171, 11, 0, 1407, 359, 1, 0, 0, 0, 1408, 1409, 3, 70, 27, 0, 1409, 1410, 1, 0, 0, 0, 1410, 1411, 6, 172, 16, 0, 1411, 1412, 6, 172, 12, 0, 1412, 361, 1, 0, 0, 0, 1413, 1414, 3, 108, 46, 0, 1414, 1415, 1, 0, 0, 0, 1415, 1416, 6, 173, 18, 0, 1416, 363, 1, 0, 0, 0, 1417, 1418, 3, 110, 47, 0, 1418, 1419, 1, 0, 0, 0, 1419, 1420, 6, 174, 19, 0, 1420, 365, 1, 0, 0, 0, 1421, 1422, 3, 114, 49, 0, 1422, 1423, 1, 0, 0, 0, 1423, 1424, 6, 175, 23, 0, 1424, 367, 1, 0, 0, 0, 1425, 1426, 3, 280, 132, 0, 1426, 1427, 1, 0, 0, 0, 1427, 1428, 6, 176, 33, 0, 1428, 1429, 6, 176, 34, 0, 1429, 369, 1, 0, 0, 0, 1430, 1431, 3, 220, 102, 0, 1431, 1432, 1, 0, 0, 0, 1432, 1433, 6, 177, 21, 0, 1433, 371, 1, 0, 0, 0, 1434, 1435, 3, 92, 38, 0, 1435, 1436, 1, 0, 0, 0, 1436, 1437, 6, 178, 22, 0, 1437, 373, 1, 0, 0, 0, 1438, 1439, 3, 64, 24, 0, 1439, 1440, 1, 0, 0, 0, 1440, 1441, 6, 179, 11, 0, 1441, 375, 1, 0, 0, 0, 1442, 1443, 3, 66, 25, 0, 1443, 1444, 1, 0, 0, 0, 1444, 1445, 6, 180, 11, 0, 1445, 377, 1, 0, 0, 0, 1446, 1447, 3, 68, 26, 0, 1447, 1448, 1, 0, 0, 0, 1448, 1449, 6, 181, 11, 0, 1449, 379, 1, 0, 0, 0, 1450, 1451, 3, 70, 27, 0, 1451, 1452, 1, 0, 0, 0, 1452, 1453, 6, 182, 16, 0, 1453, 1454, 6, 182, 12, 0, 1454, 1455, 6, 182, 12, 0, 1455, 381, 1, 0, 0, 0, 1456, 1457, 3, 110, 47, 0, 1457, 1458, 1, 0, 0, 0, 1458, 1459, 6, 183, 19, 0, 1459, 383, 1, 0, 0, 0, 1460, 1461, 3, 114, 49, 0, 1461, 1462, 1, 0, 0, 0, 1462, 1463, 6, 184, 23, 0, 1463, 385, 1, 0, 0, 0, 1464, 1465, 3, 246, 115, 0, 1465, 1466, 1, 0, 0, 0, 1466, 1467, 6, 185, 26, 0, 1467, 387, 1, 0, 0, 0, 1468, 1469, 3, 64, 24, 0, 1469, 1470, 1, 0, 0, 0, 1470, 1471, 6, 186, 11, 0, 1471, 389, 1, 0, 0, 0, 1472, 1473, 3, 66, 25, 0, 1473, 1474, 1, 0, 0, 0, 1474, 1475, 6, 187, 11, 0, 1475, 391, 1, 0, 0, 0, 1476, 1477, 3, 68, 26, 0, 1477, 1478, 1, 0, 0, 0, 1478, 1479, 6, 188, 11, 0, 1479, 393, 1, 0, 0, 0, 1480, 1481, 3, 70, 27, 0, 1481, 1482, 1, 0, 0, 0, 1482, 1483, 6, 189, 16, 0, 1483, 1484, 6, 189, 12, 0, 1484, 395, 1, 0, 0, 0, 1485, 1486, 7, 35, 0, 0, 1486, 1487, 7, 7, 0, 0, 1487, 1488, 7, 1, 0, 0, 1488, 1489, 7, 9, 0, 0, 1489, 397, 1, 0, 0, 0, 1490, 1491, 3, 266, 125, 0, 1491, 1492, 1, 0, 0, 0, 1492, 1493, 6, 191, 35, 0, 1493, 399, 1, 0, 0, 0, 1494, 1495, 3, 280, 132, 0, 1495, 1496, 1, 0, 0, 0, 1496, 1497, 6, 192, 33, 0, 1497, 1498, 6, 192, 12, 0, 1498, 1499, 6, 192, 0, 0, 1499, 401, 1, 0, 0, 0, 1500, 1501, 7, 20, 0, 0, 1501, 1502, 7, 2, 0, 0, 1502, 1503, 7, 1, 0, 0, 1503, 1504, 7, 9, 0, 0, 1504, 1505, 7, 17, 0, 0, 1505, 1506, 1, 0, 0, 0, 1506, 1507, 6, 193, 12, 0, 1507, 1508, 6, 193, 0, 0, 1508, 403, 1, 0, 0, 0, 1509, 1510, 3, 220, 102, 0, 1510, 1511, 1, 0, 0, 0, 1511, 1512, 6, 194, 21, 0, 1512, 405, 1, 0, 0, 0, 1513, 1514, 3, 92, 38, 0, 1514, 1515, 1, 0, 0, 0, 1515, 1516, 6, 195, 22, 0, 1516, 407, 1, 0, 0, 0, 1517, 1518, 3, 108, 46, 0, 1518, 1519, 1, 0, 0, 0, 1519, 1520, 6, 196, 18, 0, 1520, 409, 1, 0, 0, 0, 1521, 1522, 3, 182, 83, 0, 1522, 1523, 1, 0, 0, 0, 1523, 1524, 6, 197, 32, 0, 1524, 411, 1, 0, 0, 0, 1525, 1526, 3, 186, 85, 0, 1526, 1527, 1, 0, 0, 0, 1527, 1528, 6, 198, 31, 0, 1528, 413, 1, 0, 0, 0, 1529, 1530, 3, 64, 24, 0, 1530, 1531, 1, 0, 0, 0, 1531, 1532, 6, 199, 11, 0, 1532, 415, 1, 0, 0, 0, 1533, 1534, 3, 66, 25, 0, 1534, 1535, 1, 0, 0, 0, 1535, 1536, 6, 200, 11, 0, 1536, 417, 1, 0, 0, 0, 1537, 1538, 3, 68, 26, 0, 1538, 1539, 1, 0, 0, 0, 1539, 1540, 6, 201, 11, 0, 1540, 419, 1, 0, 0, 0, 1541, 1542, 3, 70, 27, 0, 1542, 1543, 1, 0, 0, 0, 1543, 1544, 6, 202, 16, 0, 1544, 1545, 6, 202, 12, 0, 1545, 421, 1, 0, 0, 0, 1546, 1547, 3, 220, 102, 0, 1547, 1548, 1, 0, 0, 0, 1548, 1549, 6, 203, 21, 0, 1549, 1550, 6, 203, 12, 0, 1550, 1551, 6, 203, 36, 0, 1551, 423, 1, 0, 0, 0, 1552, 1553, 3, 92, 38, 0, 1553, 1554, 1, 0, 0, 0, 1554, 1555, 6, 204, 22, 0, 1555, 1556, 6, 204, 12, 0, 1556, 1557, 6, 204, 36, 0, 1557, 425, 1, 0, 0, 0, 1558, 1559, 3, 64, 24, 0, 1559, 1560, 1, 0, 0, 0, 1560, 1561, 6, 205, 11, 0, 1561, 427, 1, 0, 0, 0, 1562, 1563, 3, 66, 25, 0, 1563, 1564, 1, 0, 0, 0, 1564, 1565, 6, 206, 11, 0, 1565, 429, 1, 0, 0, 0, 1566, 1567, 3, 68, 26, 0, 1567, 1568, 1, 0, 0, 0, 1568, 1569, 6, 207, 11, 0, 1569, 431, 1, 0, 0, 0, 1570, 1571, 3, 108, 46, 0, 1571, 1572, 1, 0, 0, 0, 1572, 1573, 6, 208, 18, 0, 1573, 1574, 6, 208, 12, 0, 1574, 1575, 6, 208, 10, 0, 1575, 433, 1, 0, 0, 0, 1576, 1577, 3, 110, 47, 0, 1577, 1578, 1, 0, 0, 0, 1578, 1579, 6, 209, 19, 0, 1579, 1580, 6, 209, 12, 0, 1580, 1581, 6, 209, 10, 0, 1581, 435, 1, 0, 0, 0, 1582, 1583, 3, 64, 24, 0, 1583, 1584, 1, 0, 0, 0, 1584, 1585, 6, 210, 11, 0, 1585, 437, 1, 0, 0, 0, 1586, 1587, 3, 66, 25, 0, 1587, 1588, 1, 0, 0, 0, 1588, 1589, 6, 211, 11, 0, 1589, 439, 1, 0, 0, 0, 1590, 1591, 3, 68, 26, 0, 1591, 1592, 1, 0, 0, 0, 1592, 1593, 6, 212, 11, 0, 1593, 441, 1, 0, 0, 0, 1594, 1595, 3, 186, 85, 0, 1595, 1596, 1, 0, 0, 0, 1596, 1597, 6, 213, 12, 0, 1597, 1598, 6, 213, 0, 0, 1598, 1599, 6, 213, 31, 0, 1599, 443, 1, 0, 0, 0, 1600, 1601, 3, 182, 83, 0, 1601, 1602, 1, 0, 0, 0, 1602, 1603, 6, 214, 12, 0, 1603, 1604, 6, 214, 0, 0, 1604, 1605, 6, 214, 32, 0, 1605, 445, 1, 0, 0, 0, 1606, 1607, 3, 98, 41, 0, 1607, 1608, 1, 0, 0, 0, 1608, 1609, 6, 215, 12, 0, 1609, 1610, 6, 215, 0, 0, 1610, 1611, 6, 215, 37, 0, 1611, 447, 1, 0, 0, 0, 1612, 1613, 3, 70, 27, 0, 1613, 1614, 1, 0, 0, 0, 1614, 1615, 6, 216, 16, 0, 1615, 1616, 6, 216, 12, 0, 1616, 449, 1, 0, 0, 0, 66, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 654, 664, 668, 671, 680, 682, 693, 712, 717, 726, 733, 738, 740, 751, 759, 762, 764, 769, 774, 780, 787, 792, 798, 801, 809, 813, 945, 950, 957, 959, 975, 980, 985, 987, 993, 1070, 1075, 1124, 1128, 1133, 1138, 1143, 1145, 1149, 1151, 1238, 1242, 1247, 1392, 1394, 38, 5, 1, 0, 5, 4, 0, 5, 6, 0, 5, 2, 0, 5, 3, 0, 5, 8, 0, 5, 5, 0, 5, 9, 0, 5, 13, 0, 5, 11, 0, 5, 14, 0, 0, 1, 0, 4, 0, 0, 7, 16, 0, 7, 71, 0, 5, 0, 0, 7, 28, 0, 7, 72, 0, 7, 37, 0, 7, 38, 0, 7, 35, 0, 7, 82, 0, 7, 29, 0, 7, 40, 0, 7, 52, 0, 7, 70, 0, 7, 86, 0, 5, 10, 0, 5, 7, 0, 7, 96, 0, 7, 95, 0, 7, 74, 0, 7, 73, 0, 7, 94, 0, 5, 12, 0, 7, 90, 0, 5, 15, 0, 7, 32, 0] \ No newline at end of file +[4, 0, 134, 1689, 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, 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, 2, 189, 7, 189, 2, 190, 7, 190, 2, 191, 7, 191, 2, 192, 7, 192, 2, 193, 7, 193, 2, 194, 7, 194, 2, 195, 7, 195, 2, 196, 7, 196, 2, 197, 7, 197, 2, 198, 7, 198, 2, 199, 7, 199, 2, 200, 7, 200, 2, 201, 7, 201, 2, 202, 7, 202, 2, 203, 7, 203, 2, 204, 7, 204, 2, 205, 7, 205, 2, 206, 7, 206, 2, 207, 7, 207, 2, 208, 7, 208, 2, 209, 7, 209, 2, 210, 7, 210, 2, 211, 7, 211, 2, 212, 7, 212, 2, 213, 7, 213, 2, 214, 7, 214, 2, 215, 7, 215, 2, 216, 7, 216, 2, 217, 7, 217, 2, 218, 7, 218, 2, 219, 7, 219, 2, 220, 7, 220, 2, 221, 7, 221, 2, 222, 7, 222, 2, 223, 7, 223, 2, 224, 7, 224, 2, 225, 7, 225, 2, 226, 7, 226, 2, 227, 7, 227, 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, 8, 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, 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, 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, 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, 15, 1, 15, 1, 16, 1, 16, 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, 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, 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, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 4, 24, 692, 8, 24, 11, 24, 12, 24, 693, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 5, 25, 702, 8, 25, 10, 25, 12, 25, 705, 9, 25, 1, 25, 3, 25, 708, 8, 25, 1, 25, 3, 25, 711, 8, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 5, 26, 720, 8, 26, 10, 26, 12, 26, 723, 9, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 4, 27, 731, 8, 27, 11, 27, 12, 27, 732, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 1, 33, 3, 33, 752, 8, 33, 1, 33, 4, 33, 755, 8, 33, 11, 33, 12, 33, 756, 1, 34, 1, 34, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 3, 36, 766, 8, 36, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 3, 38, 773, 8, 38, 1, 39, 1, 39, 1, 39, 5, 39, 778, 8, 39, 10, 39, 12, 39, 781, 9, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 5, 39, 789, 8, 39, 10, 39, 12, 39, 792, 9, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 799, 8, 39, 1, 39, 3, 39, 802, 8, 39, 3, 39, 804, 8, 39, 1, 40, 4, 40, 807, 8, 40, 11, 40, 12, 40, 808, 1, 41, 4, 41, 812, 8, 41, 11, 41, 12, 41, 813, 1, 41, 1, 41, 5, 41, 818, 8, 41, 10, 41, 12, 41, 821, 9, 41, 1, 41, 1, 41, 4, 41, 825, 8, 41, 11, 41, 12, 41, 826, 1, 41, 4, 41, 830, 8, 41, 11, 41, 12, 41, 831, 1, 41, 1, 41, 5, 41, 836, 8, 41, 10, 41, 12, 41, 839, 9, 41, 3, 41, 841, 8, 41, 1, 41, 1, 41, 1, 41, 1, 41, 4, 41, 847, 8, 41, 11, 41, 12, 41, 848, 1, 41, 1, 41, 3, 41, 853, 8, 41, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 58, 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, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 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, 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, 81, 1, 81, 1, 81, 3, 81, 985, 8, 81, 1, 81, 5, 81, 988, 8, 81, 10, 81, 12, 81, 991, 9, 81, 1, 81, 1, 81, 4, 81, 995, 8, 81, 11, 81, 12, 81, 996, 3, 81, 999, 8, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 5, 84, 1013, 8, 84, 10, 84, 12, 84, 1016, 9, 84, 1, 84, 1, 84, 3, 84, 1020, 8, 84, 1, 84, 4, 84, 1023, 8, 84, 11, 84, 12, 84, 1024, 3, 84, 1027, 8, 84, 1, 85, 1, 85, 4, 85, 1031, 8, 85, 11, 85, 12, 85, 1032, 1, 85, 1, 85, 1, 86, 1, 86, 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, 90, 1, 91, 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, 95, 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, 100, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 102, 3, 102, 1110, 8, 102, 1, 103, 4, 103, 1113, 8, 103, 11, 103, 12, 103, 1114, 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, 108, 1, 108, 1, 108, 1, 108, 1, 109, 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, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 1, 114, 1, 114, 1, 114, 3, 114, 1162, 8, 114, 1, 115, 1, 115, 3, 115, 1166, 8, 115, 1, 115, 5, 115, 1169, 8, 115, 10, 115, 12, 115, 1172, 9, 115, 1, 115, 1, 115, 3, 115, 1176, 8, 115, 1, 115, 4, 115, 1179, 8, 115, 11, 115, 12, 115, 1180, 3, 115, 1183, 8, 115, 1, 116, 1, 116, 4, 116, 1187, 8, 116, 11, 116, 12, 116, 1188, 1, 117, 1, 117, 1, 117, 1, 117, 1, 118, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1, 119, 1, 119, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 121, 1, 121, 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, 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, 131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 132, 1, 133, 1, 133, 1, 133, 1, 133, 1, 133, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 135, 1, 135, 1, 136, 4, 136, 1272, 8, 136, 11, 136, 12, 136, 1273, 1, 136, 1, 136, 3, 136, 1278, 8, 136, 1, 136, 4, 136, 1281, 8, 136, 11, 136, 12, 136, 1282, 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, 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, 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, 161, 1, 161, 1, 161, 1, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 163, 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, 166, 1, 166, 1, 166, 1, 166, 1, 167, 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, 4, 169, 1424, 8, 169, 11, 169, 12, 169, 1425, 1, 170, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 173, 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, 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, 182, 1, 182, 1, 182, 1, 182, 1, 183, 1, 183, 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, 186, 1, 186, 1, 186, 1, 186, 1, 187, 1, 187, 1, 187, 1, 187, 1, 188, 1, 188, 1, 188, 1, 188, 1, 189, 1, 189, 1, 189, 1, 189, 1, 190, 1, 190, 1, 190, 1, 190, 1, 190, 1, 191, 1, 191, 1, 191, 1, 191, 1, 191, 1, 192, 1, 192, 1, 192, 1, 192, 1, 193, 1, 193, 1, 193, 1, 193, 1, 193, 1, 193, 1, 194, 1, 194, 1, 194, 1, 194, 1, 194, 1, 194, 1, 194, 1, 194, 1, 194, 1, 195, 1, 195, 1, 195, 1, 195, 1, 196, 1, 196, 1, 196, 1, 196, 1, 197, 1, 197, 1, 197, 1, 197, 1, 198, 1, 198, 1, 198, 1, 198, 1, 199, 1, 199, 1, 199, 1, 199, 1, 200, 1, 200, 1, 200, 1, 200, 1, 201, 1, 201, 1, 201, 1, 201, 1, 202, 1, 202, 1, 202, 1, 202, 1, 203, 1, 203, 1, 203, 1, 203, 1, 203, 1, 204, 1, 204, 1, 204, 1, 204, 1, 204, 1, 204, 1, 205, 1, 205, 1, 205, 1, 205, 1, 205, 1, 205, 1, 206, 1, 206, 1, 206, 1, 206, 1, 207, 1, 207, 1, 207, 1, 207, 1, 208, 1, 208, 1, 208, 1, 208, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 210, 1, 210, 1, 210, 1, 210, 1, 210, 1, 210, 1, 211, 1, 211, 1, 211, 1, 211, 1, 212, 1, 212, 1, 212, 1, 212, 1, 213, 1, 213, 1, 213, 1, 213, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 215, 1, 215, 1, 215, 1, 215, 1, 215, 1, 215, 1, 216, 1, 216, 1, 216, 1, 216, 1, 216, 1, 216, 1, 217, 1, 217, 1, 217, 1, 217, 1, 217, 1, 218, 1, 218, 1, 218, 1, 218, 1, 218, 1, 219, 1, 219, 1, 219, 1, 219, 1, 220, 1, 220, 1, 220, 1, 220, 1, 221, 1, 221, 1, 221, 1, 221, 1, 222, 1, 222, 1, 222, 1, 222, 1, 223, 1, 223, 1, 223, 1, 223, 1, 224, 1, 224, 1, 224, 1, 224, 1, 225, 1, 225, 1, 225, 1, 225, 1, 226, 1, 226, 1, 226, 1, 226, 1, 227, 1, 227, 1, 227, 1, 227, 2, 721, 790, 0, 228, 17, 1, 19, 2, 21, 3, 23, 4, 25, 5, 27, 6, 29, 7, 31, 8, 33, 9, 35, 10, 37, 11, 39, 12, 41, 13, 43, 14, 45, 15, 47, 16, 49, 17, 51, 18, 53, 19, 55, 20, 57, 21, 59, 22, 61, 23, 63, 24, 65, 25, 67, 26, 69, 27, 71, 28, 73, 29, 75, 0, 77, 0, 79, 0, 81, 0, 83, 0, 85, 0, 87, 0, 89, 0, 91, 0, 93, 0, 95, 30, 97, 31, 99, 32, 101, 33, 103, 34, 105, 35, 107, 36, 109, 37, 111, 38, 113, 39, 115, 40, 117, 41, 119, 42, 121, 43, 123, 44, 125, 45, 127, 46, 129, 47, 131, 48, 133, 49, 135, 50, 137, 51, 139, 52, 141, 53, 143, 54, 145, 55, 147, 56, 149, 57, 151, 58, 153, 59, 155, 60, 157, 61, 159, 62, 161, 63, 163, 64, 165, 65, 167, 66, 169, 67, 171, 68, 173, 69, 175, 70, 177, 0, 179, 71, 181, 72, 183, 73, 185, 74, 187, 0, 189, 75, 191, 76, 193, 77, 195, 78, 197, 0, 199, 0, 201, 79, 203, 80, 205, 81, 207, 0, 209, 0, 211, 0, 213, 0, 215, 0, 217, 0, 219, 82, 221, 0, 223, 83, 225, 0, 227, 0, 229, 84, 231, 85, 233, 86, 235, 0, 237, 0, 239, 0, 241, 0, 243, 0, 245, 0, 247, 0, 249, 87, 251, 88, 253, 89, 255, 90, 257, 0, 259, 0, 261, 0, 263, 0, 265, 0, 267, 0, 269, 91, 271, 0, 273, 92, 275, 93, 277, 94, 279, 0, 281, 0, 283, 95, 285, 96, 287, 0, 289, 97, 291, 0, 293, 98, 295, 99, 297, 100, 299, 0, 301, 0, 303, 0, 305, 0, 307, 0, 309, 0, 311, 0, 313, 0, 315, 0, 317, 101, 319, 102, 321, 103, 323, 0, 325, 0, 327, 0, 329, 0, 331, 0, 333, 0, 335, 104, 337, 105, 339, 106, 341, 0, 343, 107, 345, 108, 347, 109, 349, 110, 351, 0, 353, 0, 355, 111, 357, 112, 359, 113, 361, 114, 363, 0, 365, 0, 367, 0, 369, 0, 371, 0, 373, 0, 375, 0, 377, 115, 379, 116, 381, 117, 383, 0, 385, 0, 387, 0, 389, 0, 391, 118, 393, 119, 395, 120, 397, 0, 399, 121, 401, 0, 403, 0, 405, 122, 407, 0, 409, 0, 411, 0, 413, 0, 415, 0, 417, 123, 419, 124, 421, 125, 423, 0, 425, 0, 427, 0, 429, 126, 431, 127, 433, 128, 435, 0, 437, 0, 439, 129, 441, 130, 443, 131, 445, 0, 447, 0, 449, 0, 451, 0, 453, 0, 455, 0, 457, 0, 459, 0, 461, 0, 463, 0, 465, 0, 467, 132, 469, 133, 471, 134, 17, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 36, 2, 0, 68, 68, 100, 100, 2, 0, 73, 73, 105, 105, 2, 0, 83, 83, 115, 115, 2, 0, 69, 69, 101, 101, 2, 0, 67, 67, 99, 99, 2, 0, 84, 84, 116, 116, 2, 0, 82, 82, 114, 114, 2, 0, 79, 79, 111, 111, 2, 0, 80, 80, 112, 112, 2, 0, 78, 78, 110, 110, 2, 0, 72, 72, 104, 104, 2, 0, 86, 86, 118, 118, 2, 0, 65, 65, 97, 97, 2, 0, 76, 76, 108, 108, 2, 0, 88, 88, 120, 120, 2, 0, 70, 70, 102, 102, 2, 0, 77, 77, 109, 109, 2, 0, 71, 71, 103, 103, 2, 0, 75, 75, 107, 107, 2, 0, 87, 87, 119, 119, 2, 0, 85, 85, 117, 117, 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, 1, 0, 48, 57, 2, 0, 65, 90, 97, 122, 8, 0, 34, 34, 78, 78, 82, 82, 84, 84, 92, 92, 110, 110, 114, 114, 116, 116, 4, 0, 10, 10, 13, 13, 34, 34, 92, 92, 2, 0, 43, 43, 45, 45, 1, 0, 96, 96, 2, 0, 66, 66, 98, 98, 2, 0, 89, 89, 121, 121, 11, 0, 9, 10, 13, 13, 32, 32, 34, 34, 44, 44, 47, 47, 58, 58, 61, 61, 91, 91, 93, 93, 124, 124, 2, 0, 42, 42, 47, 47, 11, 0, 9, 10, 13, 13, 32, 32, 34, 35, 44, 44, 47, 47, 58, 58, 60, 60, 62, 63, 92, 92, 124, 124, 2, 0, 74, 74, 106, 106, 1715, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 1, 73, 1, 0, 0, 0, 1, 95, 1, 0, 0, 0, 1, 97, 1, 0, 0, 0, 1, 99, 1, 0, 0, 0, 1, 101, 1, 0, 0, 0, 1, 103, 1, 0, 0, 0, 1, 105, 1, 0, 0, 0, 1, 107, 1, 0, 0, 0, 1, 109, 1, 0, 0, 0, 1, 111, 1, 0, 0, 0, 1, 113, 1, 0, 0, 0, 1, 115, 1, 0, 0, 0, 1, 117, 1, 0, 0, 0, 1, 119, 1, 0, 0, 0, 1, 121, 1, 0, 0, 0, 1, 123, 1, 0, 0, 0, 1, 125, 1, 0, 0, 0, 1, 127, 1, 0, 0, 0, 1, 129, 1, 0, 0, 0, 1, 131, 1, 0, 0, 0, 1, 133, 1, 0, 0, 0, 1, 135, 1, 0, 0, 0, 1, 137, 1, 0, 0, 0, 1, 139, 1, 0, 0, 0, 1, 141, 1, 0, 0, 0, 1, 143, 1, 0, 0, 0, 1, 145, 1, 0, 0, 0, 1, 147, 1, 0, 0, 0, 1, 149, 1, 0, 0, 0, 1, 151, 1, 0, 0, 0, 1, 153, 1, 0, 0, 0, 1, 155, 1, 0, 0, 0, 1, 157, 1, 0, 0, 0, 1, 159, 1, 0, 0, 0, 1, 161, 1, 0, 0, 0, 1, 163, 1, 0, 0, 0, 1, 165, 1, 0, 0, 0, 1, 167, 1, 0, 0, 0, 1, 169, 1, 0, 0, 0, 1, 171, 1, 0, 0, 0, 1, 173, 1, 0, 0, 0, 1, 175, 1, 0, 0, 0, 1, 177, 1, 0, 0, 0, 1, 179, 1, 0, 0, 0, 1, 181, 1, 0, 0, 0, 1, 183, 1, 0, 0, 0, 1, 185, 1, 0, 0, 0, 1, 189, 1, 0, 0, 0, 1, 191, 1, 0, 0, 0, 1, 193, 1, 0, 0, 0, 1, 195, 1, 0, 0, 0, 2, 197, 1, 0, 0, 0, 2, 199, 1, 0, 0, 0, 2, 201, 1, 0, 0, 0, 2, 203, 1, 0, 0, 0, 2, 205, 1, 0, 0, 0, 3, 207, 1, 0, 0, 0, 3, 209, 1, 0, 0, 0, 3, 211, 1, 0, 0, 0, 3, 213, 1, 0, 0, 0, 3, 215, 1, 0, 0, 0, 3, 217, 1, 0, 0, 0, 3, 219, 1, 0, 0, 0, 3, 223, 1, 0, 0, 0, 3, 225, 1, 0, 0, 0, 3, 227, 1, 0, 0, 0, 3, 229, 1, 0, 0, 0, 3, 231, 1, 0, 0, 0, 3, 233, 1, 0, 0, 0, 4, 235, 1, 0, 0, 0, 4, 237, 1, 0, 0, 0, 4, 239, 1, 0, 0, 0, 4, 241, 1, 0, 0, 0, 4, 243, 1, 0, 0, 0, 4, 249, 1, 0, 0, 0, 4, 251, 1, 0, 0, 0, 4, 253, 1, 0, 0, 0, 4, 255, 1, 0, 0, 0, 5, 257, 1, 0, 0, 0, 5, 259, 1, 0, 0, 0, 5, 261, 1, 0, 0, 0, 5, 263, 1, 0, 0, 0, 5, 265, 1, 0, 0, 0, 5, 267, 1, 0, 0, 0, 5, 269, 1, 0, 0, 0, 5, 271, 1, 0, 0, 0, 5, 273, 1, 0, 0, 0, 5, 275, 1, 0, 0, 0, 5, 277, 1, 0, 0, 0, 6, 279, 1, 0, 0, 0, 6, 281, 1, 0, 0, 0, 6, 283, 1, 0, 0, 0, 6, 285, 1, 0, 0, 0, 6, 289, 1, 0, 0, 0, 6, 291, 1, 0, 0, 0, 6, 293, 1, 0, 0, 0, 6, 295, 1, 0, 0, 0, 6, 297, 1, 0, 0, 0, 7, 299, 1, 0, 0, 0, 7, 301, 1, 0, 0, 0, 7, 303, 1, 0, 0, 0, 7, 305, 1, 0, 0, 0, 7, 307, 1, 0, 0, 0, 7, 309, 1, 0, 0, 0, 7, 311, 1, 0, 0, 0, 7, 313, 1, 0, 0, 0, 7, 315, 1, 0, 0, 0, 7, 317, 1, 0, 0, 0, 7, 319, 1, 0, 0, 0, 7, 321, 1, 0, 0, 0, 8, 323, 1, 0, 0, 0, 8, 325, 1, 0, 0, 0, 8, 327, 1, 0, 0, 0, 8, 329, 1, 0, 0, 0, 8, 331, 1, 0, 0, 0, 8, 333, 1, 0, 0, 0, 8, 335, 1, 0, 0, 0, 8, 337, 1, 0, 0, 0, 8, 339, 1, 0, 0, 0, 9, 341, 1, 0, 0, 0, 9, 343, 1, 0, 0, 0, 9, 345, 1, 0, 0, 0, 9, 347, 1, 0, 0, 0, 9, 349, 1, 0, 0, 0, 10, 351, 1, 0, 0, 0, 10, 353, 1, 0, 0, 0, 10, 355, 1, 0, 0, 0, 10, 357, 1, 0, 0, 0, 10, 359, 1, 0, 0, 0, 10, 361, 1, 0, 0, 0, 11, 363, 1, 0, 0, 0, 11, 365, 1, 0, 0, 0, 11, 367, 1, 0, 0, 0, 11, 369, 1, 0, 0, 0, 11, 371, 1, 0, 0, 0, 11, 373, 1, 0, 0, 0, 11, 375, 1, 0, 0, 0, 11, 377, 1, 0, 0, 0, 11, 379, 1, 0, 0, 0, 11, 381, 1, 0, 0, 0, 12, 383, 1, 0, 0, 0, 12, 385, 1, 0, 0, 0, 12, 387, 1, 0, 0, 0, 12, 389, 1, 0, 0, 0, 12, 391, 1, 0, 0, 0, 12, 393, 1, 0, 0, 0, 12, 395, 1, 0, 0, 0, 13, 397, 1, 0, 0, 0, 13, 399, 1, 0, 0, 0, 13, 401, 1, 0, 0, 0, 13, 403, 1, 0, 0, 0, 13, 405, 1, 0, 0, 0, 13, 407, 1, 0, 0, 0, 13, 409, 1, 0, 0, 0, 13, 411, 1, 0, 0, 0, 13, 413, 1, 0, 0, 0, 13, 415, 1, 0, 0, 0, 13, 417, 1, 0, 0, 0, 13, 419, 1, 0, 0, 0, 13, 421, 1, 0, 0, 0, 14, 423, 1, 0, 0, 0, 14, 425, 1, 0, 0, 0, 14, 427, 1, 0, 0, 0, 14, 429, 1, 0, 0, 0, 14, 431, 1, 0, 0, 0, 14, 433, 1, 0, 0, 0, 15, 435, 1, 0, 0, 0, 15, 437, 1, 0, 0, 0, 15, 439, 1, 0, 0, 0, 15, 441, 1, 0, 0, 0, 15, 443, 1, 0, 0, 0, 15, 445, 1, 0, 0, 0, 15, 447, 1, 0, 0, 0, 15, 449, 1, 0, 0, 0, 15, 451, 1, 0, 0, 0, 16, 453, 1, 0, 0, 0, 16, 455, 1, 0, 0, 0, 16, 457, 1, 0, 0, 0, 16, 459, 1, 0, 0, 0, 16, 461, 1, 0, 0, 0, 16, 463, 1, 0, 0, 0, 16, 465, 1, 0, 0, 0, 16, 467, 1, 0, 0, 0, 16, 469, 1, 0, 0, 0, 16, 471, 1, 0, 0, 0, 17, 473, 1, 0, 0, 0, 19, 483, 1, 0, 0, 0, 21, 490, 1, 0, 0, 0, 23, 499, 1, 0, 0, 0, 25, 506, 1, 0, 0, 0, 27, 516, 1, 0, 0, 0, 29, 523, 1, 0, 0, 0, 31, 530, 1, 0, 0, 0, 33, 537, 1, 0, 0, 0, 35, 545, 1, 0, 0, 0, 37, 557, 1, 0, 0, 0, 39, 566, 1, 0, 0, 0, 41, 572, 1, 0, 0, 0, 43, 579, 1, 0, 0, 0, 45, 586, 1, 0, 0, 0, 47, 594, 1, 0, 0, 0, 49, 602, 1, 0, 0, 0, 51, 611, 1, 0, 0, 0, 53, 627, 1, 0, 0, 0, 55, 642, 1, 0, 0, 0, 57, 654, 1, 0, 0, 0, 59, 665, 1, 0, 0, 0, 61, 673, 1, 0, 0, 0, 63, 681, 1, 0, 0, 0, 65, 691, 1, 0, 0, 0, 67, 697, 1, 0, 0, 0, 69, 714, 1, 0, 0, 0, 71, 730, 1, 0, 0, 0, 73, 736, 1, 0, 0, 0, 75, 740, 1, 0, 0, 0, 77, 742, 1, 0, 0, 0, 79, 744, 1, 0, 0, 0, 81, 747, 1, 0, 0, 0, 83, 749, 1, 0, 0, 0, 85, 758, 1, 0, 0, 0, 87, 760, 1, 0, 0, 0, 89, 765, 1, 0, 0, 0, 91, 767, 1, 0, 0, 0, 93, 772, 1, 0, 0, 0, 95, 803, 1, 0, 0, 0, 97, 806, 1, 0, 0, 0, 99, 852, 1, 0, 0, 0, 101, 854, 1, 0, 0, 0, 103, 857, 1, 0, 0, 0, 105, 861, 1, 0, 0, 0, 107, 865, 1, 0, 0, 0, 109, 867, 1, 0, 0, 0, 111, 870, 1, 0, 0, 0, 113, 872, 1, 0, 0, 0, 115, 874, 1, 0, 0, 0, 117, 879, 1, 0, 0, 0, 119, 881, 1, 0, 0, 0, 121, 887, 1, 0, 0, 0, 123, 893, 1, 0, 0, 0, 125, 896, 1, 0, 0, 0, 127, 899, 1, 0, 0, 0, 129, 904, 1, 0, 0, 0, 131, 909, 1, 0, 0, 0, 133, 911, 1, 0, 0, 0, 135, 915, 1, 0, 0, 0, 137, 920, 1, 0, 0, 0, 139, 926, 1, 0, 0, 0, 141, 929, 1, 0, 0, 0, 143, 931, 1, 0, 0, 0, 145, 937, 1, 0, 0, 0, 147, 939, 1, 0, 0, 0, 149, 944, 1, 0, 0, 0, 151, 947, 1, 0, 0, 0, 153, 950, 1, 0, 0, 0, 155, 953, 1, 0, 0, 0, 157, 955, 1, 0, 0, 0, 159, 958, 1, 0, 0, 0, 161, 960, 1, 0, 0, 0, 163, 963, 1, 0, 0, 0, 165, 965, 1, 0, 0, 0, 167, 967, 1, 0, 0, 0, 169, 969, 1, 0, 0, 0, 171, 971, 1, 0, 0, 0, 173, 973, 1, 0, 0, 0, 175, 975, 1, 0, 0, 0, 177, 977, 1, 0, 0, 0, 179, 998, 1, 0, 0, 0, 181, 1000, 1, 0, 0, 0, 183, 1005, 1, 0, 0, 0, 185, 1026, 1, 0, 0, 0, 187, 1028, 1, 0, 0, 0, 189, 1036, 1, 0, 0, 0, 191, 1038, 1, 0, 0, 0, 193, 1042, 1, 0, 0, 0, 195, 1046, 1, 0, 0, 0, 197, 1050, 1, 0, 0, 0, 199, 1055, 1, 0, 0, 0, 201, 1060, 1, 0, 0, 0, 203, 1064, 1, 0, 0, 0, 205, 1068, 1, 0, 0, 0, 207, 1072, 1, 0, 0, 0, 209, 1077, 1, 0, 0, 0, 211, 1081, 1, 0, 0, 0, 213, 1085, 1, 0, 0, 0, 215, 1089, 1, 0, 0, 0, 217, 1093, 1, 0, 0, 0, 219, 1097, 1, 0, 0, 0, 221, 1109, 1, 0, 0, 0, 223, 1112, 1, 0, 0, 0, 225, 1116, 1, 0, 0, 0, 227, 1120, 1, 0, 0, 0, 229, 1124, 1, 0, 0, 0, 231, 1128, 1, 0, 0, 0, 233, 1132, 1, 0, 0, 0, 235, 1136, 1, 0, 0, 0, 237, 1141, 1, 0, 0, 0, 239, 1145, 1, 0, 0, 0, 241, 1149, 1, 0, 0, 0, 243, 1153, 1, 0, 0, 0, 245, 1161, 1, 0, 0, 0, 247, 1182, 1, 0, 0, 0, 249, 1186, 1, 0, 0, 0, 251, 1190, 1, 0, 0, 0, 253, 1194, 1, 0, 0, 0, 255, 1198, 1, 0, 0, 0, 257, 1202, 1, 0, 0, 0, 259, 1207, 1, 0, 0, 0, 261, 1211, 1, 0, 0, 0, 263, 1215, 1, 0, 0, 0, 265, 1219, 1, 0, 0, 0, 267, 1223, 1, 0, 0, 0, 269, 1227, 1, 0, 0, 0, 271, 1230, 1, 0, 0, 0, 273, 1234, 1, 0, 0, 0, 275, 1238, 1, 0, 0, 0, 277, 1242, 1, 0, 0, 0, 279, 1246, 1, 0, 0, 0, 281, 1251, 1, 0, 0, 0, 283, 1256, 1, 0, 0, 0, 285, 1261, 1, 0, 0, 0, 287, 1268, 1, 0, 0, 0, 289, 1277, 1, 0, 0, 0, 291, 1284, 1, 0, 0, 0, 293, 1288, 1, 0, 0, 0, 295, 1292, 1, 0, 0, 0, 297, 1296, 1, 0, 0, 0, 299, 1300, 1, 0, 0, 0, 301, 1306, 1, 0, 0, 0, 303, 1310, 1, 0, 0, 0, 305, 1314, 1, 0, 0, 0, 307, 1318, 1, 0, 0, 0, 309, 1322, 1, 0, 0, 0, 311, 1326, 1, 0, 0, 0, 313, 1330, 1, 0, 0, 0, 315, 1334, 1, 0, 0, 0, 317, 1338, 1, 0, 0, 0, 319, 1342, 1, 0, 0, 0, 321, 1346, 1, 0, 0, 0, 323, 1350, 1, 0, 0, 0, 325, 1355, 1, 0, 0, 0, 327, 1359, 1, 0, 0, 0, 329, 1363, 1, 0, 0, 0, 331, 1367, 1, 0, 0, 0, 333, 1371, 1, 0, 0, 0, 335, 1375, 1, 0, 0, 0, 337, 1379, 1, 0, 0, 0, 339, 1383, 1, 0, 0, 0, 341, 1387, 1, 0, 0, 0, 343, 1392, 1, 0, 0, 0, 345, 1397, 1, 0, 0, 0, 347, 1401, 1, 0, 0, 0, 349, 1405, 1, 0, 0, 0, 351, 1409, 1, 0, 0, 0, 353, 1414, 1, 0, 0, 0, 355, 1423, 1, 0, 0, 0, 357, 1427, 1, 0, 0, 0, 359, 1431, 1, 0, 0, 0, 361, 1435, 1, 0, 0, 0, 363, 1439, 1, 0, 0, 0, 365, 1444, 1, 0, 0, 0, 367, 1448, 1, 0, 0, 0, 369, 1452, 1, 0, 0, 0, 371, 1456, 1, 0, 0, 0, 373, 1461, 1, 0, 0, 0, 375, 1465, 1, 0, 0, 0, 377, 1469, 1, 0, 0, 0, 379, 1473, 1, 0, 0, 0, 381, 1477, 1, 0, 0, 0, 383, 1481, 1, 0, 0, 0, 385, 1487, 1, 0, 0, 0, 387, 1491, 1, 0, 0, 0, 389, 1495, 1, 0, 0, 0, 391, 1499, 1, 0, 0, 0, 393, 1503, 1, 0, 0, 0, 395, 1507, 1, 0, 0, 0, 397, 1511, 1, 0, 0, 0, 399, 1516, 1, 0, 0, 0, 401, 1521, 1, 0, 0, 0, 403, 1525, 1, 0, 0, 0, 405, 1531, 1, 0, 0, 0, 407, 1540, 1, 0, 0, 0, 409, 1544, 1, 0, 0, 0, 411, 1548, 1, 0, 0, 0, 413, 1552, 1, 0, 0, 0, 415, 1556, 1, 0, 0, 0, 417, 1560, 1, 0, 0, 0, 419, 1564, 1, 0, 0, 0, 421, 1568, 1, 0, 0, 0, 423, 1572, 1, 0, 0, 0, 425, 1577, 1, 0, 0, 0, 427, 1583, 1, 0, 0, 0, 429, 1589, 1, 0, 0, 0, 431, 1593, 1, 0, 0, 0, 433, 1597, 1, 0, 0, 0, 435, 1601, 1, 0, 0, 0, 437, 1607, 1, 0, 0, 0, 439, 1613, 1, 0, 0, 0, 441, 1617, 1, 0, 0, 0, 443, 1621, 1, 0, 0, 0, 445, 1625, 1, 0, 0, 0, 447, 1631, 1, 0, 0, 0, 449, 1637, 1, 0, 0, 0, 451, 1643, 1, 0, 0, 0, 453, 1648, 1, 0, 0, 0, 455, 1653, 1, 0, 0, 0, 457, 1657, 1, 0, 0, 0, 459, 1661, 1, 0, 0, 0, 461, 1665, 1, 0, 0, 0, 463, 1669, 1, 0, 0, 0, 465, 1673, 1, 0, 0, 0, 467, 1677, 1, 0, 0, 0, 469, 1681, 1, 0, 0, 0, 471, 1685, 1, 0, 0, 0, 473, 474, 7, 0, 0, 0, 474, 475, 7, 1, 0, 0, 475, 476, 7, 2, 0, 0, 476, 477, 7, 2, 0, 0, 477, 478, 7, 3, 0, 0, 478, 479, 7, 4, 0, 0, 479, 480, 7, 5, 0, 0, 480, 481, 1, 0, 0, 0, 481, 482, 6, 0, 0, 0, 482, 18, 1, 0, 0, 0, 483, 484, 7, 0, 0, 0, 484, 485, 7, 6, 0, 0, 485, 486, 7, 7, 0, 0, 486, 487, 7, 8, 0, 0, 487, 488, 1, 0, 0, 0, 488, 489, 6, 1, 1, 0, 489, 20, 1, 0, 0, 0, 490, 491, 7, 3, 0, 0, 491, 492, 7, 9, 0, 0, 492, 493, 7, 6, 0, 0, 493, 494, 7, 1, 0, 0, 494, 495, 7, 4, 0, 0, 495, 496, 7, 10, 0, 0, 496, 497, 1, 0, 0, 0, 497, 498, 6, 2, 2, 0, 498, 22, 1, 0, 0, 0, 499, 500, 7, 3, 0, 0, 500, 501, 7, 11, 0, 0, 501, 502, 7, 12, 0, 0, 502, 503, 7, 13, 0, 0, 503, 504, 1, 0, 0, 0, 504, 505, 6, 3, 0, 0, 505, 24, 1, 0, 0, 0, 506, 507, 7, 3, 0, 0, 507, 508, 7, 14, 0, 0, 508, 509, 7, 8, 0, 0, 509, 510, 7, 13, 0, 0, 510, 511, 7, 12, 0, 0, 511, 512, 7, 1, 0, 0, 512, 513, 7, 9, 0, 0, 513, 514, 1, 0, 0, 0, 514, 515, 6, 4, 3, 0, 515, 26, 1, 0, 0, 0, 516, 517, 7, 15, 0, 0, 517, 518, 7, 6, 0, 0, 518, 519, 7, 7, 0, 0, 519, 520, 7, 16, 0, 0, 520, 521, 1, 0, 0, 0, 521, 522, 6, 5, 4, 0, 522, 28, 1, 0, 0, 0, 523, 524, 7, 17, 0, 0, 524, 525, 7, 6, 0, 0, 525, 526, 7, 7, 0, 0, 526, 527, 7, 18, 0, 0, 527, 528, 1, 0, 0, 0, 528, 529, 6, 6, 0, 0, 529, 30, 1, 0, 0, 0, 530, 531, 7, 18, 0, 0, 531, 532, 7, 3, 0, 0, 532, 533, 7, 3, 0, 0, 533, 534, 7, 8, 0, 0, 534, 535, 1, 0, 0, 0, 535, 536, 6, 7, 1, 0, 536, 32, 1, 0, 0, 0, 537, 538, 7, 13, 0, 0, 538, 539, 7, 1, 0, 0, 539, 540, 7, 16, 0, 0, 540, 541, 7, 1, 0, 0, 541, 542, 7, 5, 0, 0, 542, 543, 1, 0, 0, 0, 543, 544, 6, 8, 0, 0, 544, 34, 1, 0, 0, 0, 545, 546, 7, 16, 0, 0, 546, 547, 7, 11, 0, 0, 547, 548, 5, 95, 0, 0, 548, 549, 7, 3, 0, 0, 549, 550, 7, 14, 0, 0, 550, 551, 7, 8, 0, 0, 551, 552, 7, 12, 0, 0, 552, 553, 7, 9, 0, 0, 553, 554, 7, 0, 0, 0, 554, 555, 1, 0, 0, 0, 555, 556, 6, 9, 5, 0, 556, 36, 1, 0, 0, 0, 557, 558, 7, 6, 0, 0, 558, 559, 7, 3, 0, 0, 559, 560, 7, 9, 0, 0, 560, 561, 7, 12, 0, 0, 561, 562, 7, 16, 0, 0, 562, 563, 7, 3, 0, 0, 563, 564, 1, 0, 0, 0, 564, 565, 6, 10, 6, 0, 565, 38, 1, 0, 0, 0, 566, 567, 7, 6, 0, 0, 567, 568, 7, 7, 0, 0, 568, 569, 7, 19, 0, 0, 569, 570, 1, 0, 0, 0, 570, 571, 6, 11, 0, 0, 571, 40, 1, 0, 0, 0, 572, 573, 7, 2, 0, 0, 573, 574, 7, 10, 0, 0, 574, 575, 7, 7, 0, 0, 575, 576, 7, 19, 0, 0, 576, 577, 1, 0, 0, 0, 577, 578, 6, 12, 7, 0, 578, 42, 1, 0, 0, 0, 579, 580, 7, 2, 0, 0, 580, 581, 7, 7, 0, 0, 581, 582, 7, 6, 0, 0, 582, 583, 7, 5, 0, 0, 583, 584, 1, 0, 0, 0, 584, 585, 6, 13, 0, 0, 585, 44, 1, 0, 0, 0, 586, 587, 7, 2, 0, 0, 587, 588, 7, 5, 0, 0, 588, 589, 7, 12, 0, 0, 589, 590, 7, 5, 0, 0, 590, 591, 7, 2, 0, 0, 591, 592, 1, 0, 0, 0, 592, 593, 6, 14, 0, 0, 593, 46, 1, 0, 0, 0, 594, 595, 7, 19, 0, 0, 595, 596, 7, 10, 0, 0, 596, 597, 7, 3, 0, 0, 597, 598, 7, 6, 0, 0, 598, 599, 7, 3, 0, 0, 599, 600, 1, 0, 0, 0, 600, 601, 6, 15, 0, 0, 601, 48, 1, 0, 0, 0, 602, 603, 7, 13, 0, 0, 603, 604, 7, 7, 0, 0, 604, 605, 7, 7, 0, 0, 605, 606, 7, 18, 0, 0, 606, 607, 7, 20, 0, 0, 607, 608, 7, 8, 0, 0, 608, 609, 1, 0, 0, 0, 609, 610, 6, 16, 8, 0, 610, 50, 1, 0, 0, 0, 611, 612, 4, 17, 0, 0, 612, 613, 7, 4, 0, 0, 613, 614, 7, 10, 0, 0, 614, 615, 7, 12, 0, 0, 615, 616, 7, 9, 0, 0, 616, 617, 7, 17, 0, 0, 617, 618, 7, 3, 0, 0, 618, 619, 5, 95, 0, 0, 619, 620, 7, 8, 0, 0, 620, 621, 7, 7, 0, 0, 621, 622, 7, 1, 0, 0, 622, 623, 7, 9, 0, 0, 623, 624, 7, 5, 0, 0, 624, 625, 1, 0, 0, 0, 625, 626, 6, 17, 9, 0, 626, 52, 1, 0, 0, 0, 627, 628, 4, 18, 1, 0, 628, 629, 7, 1, 0, 0, 629, 630, 7, 9, 0, 0, 630, 631, 7, 13, 0, 0, 631, 632, 7, 1, 0, 0, 632, 633, 7, 9, 0, 0, 633, 634, 7, 3, 0, 0, 634, 635, 7, 2, 0, 0, 635, 636, 7, 5, 0, 0, 636, 637, 7, 12, 0, 0, 637, 638, 7, 5, 0, 0, 638, 639, 7, 2, 0, 0, 639, 640, 1, 0, 0, 0, 640, 641, 6, 18, 0, 0, 641, 54, 1, 0, 0, 0, 642, 643, 4, 19, 2, 0, 643, 644, 7, 13, 0, 0, 644, 645, 7, 7, 0, 0, 645, 646, 7, 7, 0, 0, 646, 647, 7, 18, 0, 0, 647, 648, 7, 20, 0, 0, 648, 649, 7, 8, 0, 0, 649, 650, 5, 95, 0, 0, 650, 651, 5, 128020, 0, 0, 651, 652, 1, 0, 0, 0, 652, 653, 6, 19, 10, 0, 653, 56, 1, 0, 0, 0, 654, 655, 4, 20, 3, 0, 655, 656, 7, 16, 0, 0, 656, 657, 7, 3, 0, 0, 657, 658, 7, 5, 0, 0, 658, 659, 7, 6, 0, 0, 659, 660, 7, 1, 0, 0, 660, 661, 7, 4, 0, 0, 661, 662, 7, 2, 0, 0, 662, 663, 1, 0, 0, 0, 663, 664, 6, 20, 11, 0, 664, 58, 1, 0, 0, 0, 665, 666, 4, 21, 4, 0, 666, 667, 7, 15, 0, 0, 667, 668, 7, 20, 0, 0, 668, 669, 7, 13, 0, 0, 669, 670, 7, 13, 0, 0, 670, 671, 1, 0, 0, 0, 671, 672, 6, 21, 8, 0, 672, 60, 1, 0, 0, 0, 673, 674, 4, 22, 5, 0, 674, 675, 7, 13, 0, 0, 675, 676, 7, 3, 0, 0, 676, 677, 7, 15, 0, 0, 677, 678, 7, 5, 0, 0, 678, 679, 1, 0, 0, 0, 679, 680, 6, 22, 8, 0, 680, 62, 1, 0, 0, 0, 681, 682, 4, 23, 6, 0, 682, 683, 7, 6, 0, 0, 683, 684, 7, 1, 0, 0, 684, 685, 7, 17, 0, 0, 685, 686, 7, 10, 0, 0, 686, 687, 7, 5, 0, 0, 687, 688, 1, 0, 0, 0, 688, 689, 6, 23, 8, 0, 689, 64, 1, 0, 0, 0, 690, 692, 8, 21, 0, 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, 695, 1, 0, 0, 0, 695, 696, 6, 24, 0, 0, 696, 66, 1, 0, 0, 0, 697, 698, 5, 47, 0, 0, 698, 699, 5, 47, 0, 0, 699, 703, 1, 0, 0, 0, 700, 702, 8, 22, 0, 0, 701, 700, 1, 0, 0, 0, 702, 705, 1, 0, 0, 0, 703, 701, 1, 0, 0, 0, 703, 704, 1, 0, 0, 0, 704, 707, 1, 0, 0, 0, 705, 703, 1, 0, 0, 0, 706, 708, 5, 13, 0, 0, 707, 706, 1, 0, 0, 0, 707, 708, 1, 0, 0, 0, 708, 710, 1, 0, 0, 0, 709, 711, 5, 10, 0, 0, 710, 709, 1, 0, 0, 0, 710, 711, 1, 0, 0, 0, 711, 712, 1, 0, 0, 0, 712, 713, 6, 25, 12, 0, 713, 68, 1, 0, 0, 0, 714, 715, 5, 47, 0, 0, 715, 716, 5, 42, 0, 0, 716, 721, 1, 0, 0, 0, 717, 720, 3, 69, 26, 0, 718, 720, 9, 0, 0, 0, 719, 717, 1, 0, 0, 0, 719, 718, 1, 0, 0, 0, 720, 723, 1, 0, 0, 0, 721, 722, 1, 0, 0, 0, 721, 719, 1, 0, 0, 0, 722, 724, 1, 0, 0, 0, 723, 721, 1, 0, 0, 0, 724, 725, 5, 42, 0, 0, 725, 726, 5, 47, 0, 0, 726, 727, 1, 0, 0, 0, 727, 728, 6, 26, 12, 0, 728, 70, 1, 0, 0, 0, 729, 731, 7, 23, 0, 0, 730, 729, 1, 0, 0, 0, 731, 732, 1, 0, 0, 0, 732, 730, 1, 0, 0, 0, 732, 733, 1, 0, 0, 0, 733, 734, 1, 0, 0, 0, 734, 735, 6, 27, 12, 0, 735, 72, 1, 0, 0, 0, 736, 737, 5, 124, 0, 0, 737, 738, 1, 0, 0, 0, 738, 739, 6, 28, 13, 0, 739, 74, 1, 0, 0, 0, 740, 741, 7, 24, 0, 0, 741, 76, 1, 0, 0, 0, 742, 743, 7, 25, 0, 0, 743, 78, 1, 0, 0, 0, 744, 745, 5, 92, 0, 0, 745, 746, 7, 26, 0, 0, 746, 80, 1, 0, 0, 0, 747, 748, 8, 27, 0, 0, 748, 82, 1, 0, 0, 0, 749, 751, 7, 3, 0, 0, 750, 752, 7, 28, 0, 0, 751, 750, 1, 0, 0, 0, 751, 752, 1, 0, 0, 0, 752, 754, 1, 0, 0, 0, 753, 755, 3, 75, 29, 0, 754, 753, 1, 0, 0, 0, 755, 756, 1, 0, 0, 0, 756, 754, 1, 0, 0, 0, 756, 757, 1, 0, 0, 0, 757, 84, 1, 0, 0, 0, 758, 759, 5, 64, 0, 0, 759, 86, 1, 0, 0, 0, 760, 761, 5, 96, 0, 0, 761, 88, 1, 0, 0, 0, 762, 766, 8, 29, 0, 0, 763, 764, 5, 96, 0, 0, 764, 766, 5, 96, 0, 0, 765, 762, 1, 0, 0, 0, 765, 763, 1, 0, 0, 0, 766, 90, 1, 0, 0, 0, 767, 768, 5, 95, 0, 0, 768, 92, 1, 0, 0, 0, 769, 773, 3, 77, 30, 0, 770, 773, 3, 75, 29, 0, 771, 773, 3, 91, 37, 0, 772, 769, 1, 0, 0, 0, 772, 770, 1, 0, 0, 0, 772, 771, 1, 0, 0, 0, 773, 94, 1, 0, 0, 0, 774, 779, 5, 34, 0, 0, 775, 778, 3, 79, 31, 0, 776, 778, 3, 81, 32, 0, 777, 775, 1, 0, 0, 0, 777, 776, 1, 0, 0, 0, 778, 781, 1, 0, 0, 0, 779, 777, 1, 0, 0, 0, 779, 780, 1, 0, 0, 0, 780, 782, 1, 0, 0, 0, 781, 779, 1, 0, 0, 0, 782, 804, 5, 34, 0, 0, 783, 784, 5, 34, 0, 0, 784, 785, 5, 34, 0, 0, 785, 786, 5, 34, 0, 0, 786, 790, 1, 0, 0, 0, 787, 789, 8, 22, 0, 0, 788, 787, 1, 0, 0, 0, 789, 792, 1, 0, 0, 0, 790, 791, 1, 0, 0, 0, 790, 788, 1, 0, 0, 0, 791, 793, 1, 0, 0, 0, 792, 790, 1, 0, 0, 0, 793, 794, 5, 34, 0, 0, 794, 795, 5, 34, 0, 0, 795, 796, 5, 34, 0, 0, 796, 798, 1, 0, 0, 0, 797, 799, 5, 34, 0, 0, 798, 797, 1, 0, 0, 0, 798, 799, 1, 0, 0, 0, 799, 801, 1, 0, 0, 0, 800, 802, 5, 34, 0, 0, 801, 800, 1, 0, 0, 0, 801, 802, 1, 0, 0, 0, 802, 804, 1, 0, 0, 0, 803, 774, 1, 0, 0, 0, 803, 783, 1, 0, 0, 0, 804, 96, 1, 0, 0, 0, 805, 807, 3, 75, 29, 0, 806, 805, 1, 0, 0, 0, 807, 808, 1, 0, 0, 0, 808, 806, 1, 0, 0, 0, 808, 809, 1, 0, 0, 0, 809, 98, 1, 0, 0, 0, 810, 812, 3, 75, 29, 0, 811, 810, 1, 0, 0, 0, 812, 813, 1, 0, 0, 0, 813, 811, 1, 0, 0, 0, 813, 814, 1, 0, 0, 0, 814, 815, 1, 0, 0, 0, 815, 819, 3, 117, 50, 0, 816, 818, 3, 75, 29, 0, 817, 816, 1, 0, 0, 0, 818, 821, 1, 0, 0, 0, 819, 817, 1, 0, 0, 0, 819, 820, 1, 0, 0, 0, 820, 853, 1, 0, 0, 0, 821, 819, 1, 0, 0, 0, 822, 824, 3, 117, 50, 0, 823, 825, 3, 75, 29, 0, 824, 823, 1, 0, 0, 0, 825, 826, 1, 0, 0, 0, 826, 824, 1, 0, 0, 0, 826, 827, 1, 0, 0, 0, 827, 853, 1, 0, 0, 0, 828, 830, 3, 75, 29, 0, 829, 828, 1, 0, 0, 0, 830, 831, 1, 0, 0, 0, 831, 829, 1, 0, 0, 0, 831, 832, 1, 0, 0, 0, 832, 840, 1, 0, 0, 0, 833, 837, 3, 117, 50, 0, 834, 836, 3, 75, 29, 0, 835, 834, 1, 0, 0, 0, 836, 839, 1, 0, 0, 0, 837, 835, 1, 0, 0, 0, 837, 838, 1, 0, 0, 0, 838, 841, 1, 0, 0, 0, 839, 837, 1, 0, 0, 0, 840, 833, 1, 0, 0, 0, 840, 841, 1, 0, 0, 0, 841, 842, 1, 0, 0, 0, 842, 843, 3, 83, 33, 0, 843, 853, 1, 0, 0, 0, 844, 846, 3, 117, 50, 0, 845, 847, 3, 75, 29, 0, 846, 845, 1, 0, 0, 0, 847, 848, 1, 0, 0, 0, 848, 846, 1, 0, 0, 0, 848, 849, 1, 0, 0, 0, 849, 850, 1, 0, 0, 0, 850, 851, 3, 83, 33, 0, 851, 853, 1, 0, 0, 0, 852, 811, 1, 0, 0, 0, 852, 822, 1, 0, 0, 0, 852, 829, 1, 0, 0, 0, 852, 844, 1, 0, 0, 0, 853, 100, 1, 0, 0, 0, 854, 855, 7, 30, 0, 0, 855, 856, 7, 31, 0, 0, 856, 102, 1, 0, 0, 0, 857, 858, 7, 12, 0, 0, 858, 859, 7, 9, 0, 0, 859, 860, 7, 0, 0, 0, 860, 104, 1, 0, 0, 0, 861, 862, 7, 12, 0, 0, 862, 863, 7, 2, 0, 0, 863, 864, 7, 4, 0, 0, 864, 106, 1, 0, 0, 0, 865, 866, 5, 61, 0, 0, 866, 108, 1, 0, 0, 0, 867, 868, 5, 58, 0, 0, 868, 869, 5, 58, 0, 0, 869, 110, 1, 0, 0, 0, 870, 871, 5, 58, 0, 0, 871, 112, 1, 0, 0, 0, 872, 873, 5, 44, 0, 0, 873, 114, 1, 0, 0, 0, 874, 875, 7, 0, 0, 0, 875, 876, 7, 3, 0, 0, 876, 877, 7, 2, 0, 0, 877, 878, 7, 4, 0, 0, 878, 116, 1, 0, 0, 0, 879, 880, 5, 46, 0, 0, 880, 118, 1, 0, 0, 0, 881, 882, 7, 15, 0, 0, 882, 883, 7, 12, 0, 0, 883, 884, 7, 13, 0, 0, 884, 885, 7, 2, 0, 0, 885, 886, 7, 3, 0, 0, 886, 120, 1, 0, 0, 0, 887, 888, 7, 15, 0, 0, 888, 889, 7, 1, 0, 0, 889, 890, 7, 6, 0, 0, 890, 891, 7, 2, 0, 0, 891, 892, 7, 5, 0, 0, 892, 122, 1, 0, 0, 0, 893, 894, 7, 1, 0, 0, 894, 895, 7, 9, 0, 0, 895, 124, 1, 0, 0, 0, 896, 897, 7, 1, 0, 0, 897, 898, 7, 2, 0, 0, 898, 126, 1, 0, 0, 0, 899, 900, 7, 13, 0, 0, 900, 901, 7, 12, 0, 0, 901, 902, 7, 2, 0, 0, 902, 903, 7, 5, 0, 0, 903, 128, 1, 0, 0, 0, 904, 905, 7, 13, 0, 0, 905, 906, 7, 1, 0, 0, 906, 907, 7, 18, 0, 0, 907, 908, 7, 3, 0, 0, 908, 130, 1, 0, 0, 0, 909, 910, 5, 40, 0, 0, 910, 132, 1, 0, 0, 0, 911, 912, 7, 9, 0, 0, 912, 913, 7, 7, 0, 0, 913, 914, 7, 5, 0, 0, 914, 134, 1, 0, 0, 0, 915, 916, 7, 9, 0, 0, 916, 917, 7, 20, 0, 0, 917, 918, 7, 13, 0, 0, 918, 919, 7, 13, 0, 0, 919, 136, 1, 0, 0, 0, 920, 921, 7, 9, 0, 0, 921, 922, 7, 20, 0, 0, 922, 923, 7, 13, 0, 0, 923, 924, 7, 13, 0, 0, 924, 925, 7, 2, 0, 0, 925, 138, 1, 0, 0, 0, 926, 927, 7, 7, 0, 0, 927, 928, 7, 6, 0, 0, 928, 140, 1, 0, 0, 0, 929, 930, 5, 63, 0, 0, 930, 142, 1, 0, 0, 0, 931, 932, 7, 6, 0, 0, 932, 933, 7, 13, 0, 0, 933, 934, 7, 1, 0, 0, 934, 935, 7, 18, 0, 0, 935, 936, 7, 3, 0, 0, 936, 144, 1, 0, 0, 0, 937, 938, 5, 41, 0, 0, 938, 146, 1, 0, 0, 0, 939, 940, 7, 5, 0, 0, 940, 941, 7, 6, 0, 0, 941, 942, 7, 20, 0, 0, 942, 943, 7, 3, 0, 0, 943, 148, 1, 0, 0, 0, 944, 945, 5, 61, 0, 0, 945, 946, 5, 61, 0, 0, 946, 150, 1, 0, 0, 0, 947, 948, 5, 61, 0, 0, 948, 949, 5, 126, 0, 0, 949, 152, 1, 0, 0, 0, 950, 951, 5, 33, 0, 0, 951, 952, 5, 61, 0, 0, 952, 154, 1, 0, 0, 0, 953, 954, 5, 60, 0, 0, 954, 156, 1, 0, 0, 0, 955, 956, 5, 60, 0, 0, 956, 957, 5, 61, 0, 0, 957, 158, 1, 0, 0, 0, 958, 959, 5, 62, 0, 0, 959, 160, 1, 0, 0, 0, 960, 961, 5, 62, 0, 0, 961, 962, 5, 61, 0, 0, 962, 162, 1, 0, 0, 0, 963, 964, 5, 43, 0, 0, 964, 164, 1, 0, 0, 0, 965, 966, 5, 45, 0, 0, 966, 166, 1, 0, 0, 0, 967, 968, 5, 42, 0, 0, 968, 168, 1, 0, 0, 0, 969, 970, 5, 47, 0, 0, 970, 170, 1, 0, 0, 0, 971, 972, 5, 37, 0, 0, 972, 172, 1, 0, 0, 0, 973, 974, 5, 123, 0, 0, 974, 174, 1, 0, 0, 0, 975, 976, 5, 125, 0, 0, 976, 176, 1, 0, 0, 0, 977, 978, 3, 47, 15, 0, 978, 979, 1, 0, 0, 0, 979, 980, 6, 80, 14, 0, 980, 178, 1, 0, 0, 0, 981, 984, 3, 141, 62, 0, 982, 985, 3, 77, 30, 0, 983, 985, 3, 91, 37, 0, 984, 982, 1, 0, 0, 0, 984, 983, 1, 0, 0, 0, 985, 989, 1, 0, 0, 0, 986, 988, 3, 93, 38, 0, 987, 986, 1, 0, 0, 0, 988, 991, 1, 0, 0, 0, 989, 987, 1, 0, 0, 0, 989, 990, 1, 0, 0, 0, 990, 999, 1, 0, 0, 0, 991, 989, 1, 0, 0, 0, 992, 994, 3, 141, 62, 0, 993, 995, 3, 75, 29, 0, 994, 993, 1, 0, 0, 0, 995, 996, 1, 0, 0, 0, 996, 994, 1, 0, 0, 0, 996, 997, 1, 0, 0, 0, 997, 999, 1, 0, 0, 0, 998, 981, 1, 0, 0, 0, 998, 992, 1, 0, 0, 0, 999, 180, 1, 0, 0, 0, 1000, 1001, 5, 91, 0, 0, 1001, 1002, 1, 0, 0, 0, 1002, 1003, 6, 82, 0, 0, 1003, 1004, 6, 82, 0, 0, 1004, 182, 1, 0, 0, 0, 1005, 1006, 5, 93, 0, 0, 1006, 1007, 1, 0, 0, 0, 1007, 1008, 6, 83, 13, 0, 1008, 1009, 6, 83, 13, 0, 1009, 184, 1, 0, 0, 0, 1010, 1014, 3, 77, 30, 0, 1011, 1013, 3, 93, 38, 0, 1012, 1011, 1, 0, 0, 0, 1013, 1016, 1, 0, 0, 0, 1014, 1012, 1, 0, 0, 0, 1014, 1015, 1, 0, 0, 0, 1015, 1027, 1, 0, 0, 0, 1016, 1014, 1, 0, 0, 0, 1017, 1020, 3, 91, 37, 0, 1018, 1020, 3, 85, 34, 0, 1019, 1017, 1, 0, 0, 0, 1019, 1018, 1, 0, 0, 0, 1020, 1022, 1, 0, 0, 0, 1021, 1023, 3, 93, 38, 0, 1022, 1021, 1, 0, 0, 0, 1023, 1024, 1, 0, 0, 0, 1024, 1022, 1, 0, 0, 0, 1024, 1025, 1, 0, 0, 0, 1025, 1027, 1, 0, 0, 0, 1026, 1010, 1, 0, 0, 0, 1026, 1019, 1, 0, 0, 0, 1027, 186, 1, 0, 0, 0, 1028, 1030, 3, 87, 35, 0, 1029, 1031, 3, 89, 36, 0, 1030, 1029, 1, 0, 0, 0, 1031, 1032, 1, 0, 0, 0, 1032, 1030, 1, 0, 0, 0, 1032, 1033, 1, 0, 0, 0, 1033, 1034, 1, 0, 0, 0, 1034, 1035, 3, 87, 35, 0, 1035, 188, 1, 0, 0, 0, 1036, 1037, 3, 187, 85, 0, 1037, 190, 1, 0, 0, 0, 1038, 1039, 3, 67, 25, 0, 1039, 1040, 1, 0, 0, 0, 1040, 1041, 6, 87, 12, 0, 1041, 192, 1, 0, 0, 0, 1042, 1043, 3, 69, 26, 0, 1043, 1044, 1, 0, 0, 0, 1044, 1045, 6, 88, 12, 0, 1045, 194, 1, 0, 0, 0, 1046, 1047, 3, 71, 27, 0, 1047, 1048, 1, 0, 0, 0, 1048, 1049, 6, 89, 12, 0, 1049, 196, 1, 0, 0, 0, 1050, 1051, 3, 181, 82, 0, 1051, 1052, 1, 0, 0, 0, 1052, 1053, 6, 90, 15, 0, 1053, 1054, 6, 90, 16, 0, 1054, 198, 1, 0, 0, 0, 1055, 1056, 3, 73, 28, 0, 1056, 1057, 1, 0, 0, 0, 1057, 1058, 6, 91, 17, 0, 1058, 1059, 6, 91, 13, 0, 1059, 200, 1, 0, 0, 0, 1060, 1061, 3, 71, 27, 0, 1061, 1062, 1, 0, 0, 0, 1062, 1063, 6, 92, 12, 0, 1063, 202, 1, 0, 0, 0, 1064, 1065, 3, 67, 25, 0, 1065, 1066, 1, 0, 0, 0, 1066, 1067, 6, 93, 12, 0, 1067, 204, 1, 0, 0, 0, 1068, 1069, 3, 69, 26, 0, 1069, 1070, 1, 0, 0, 0, 1070, 1071, 6, 94, 12, 0, 1071, 206, 1, 0, 0, 0, 1072, 1073, 3, 73, 28, 0, 1073, 1074, 1, 0, 0, 0, 1074, 1075, 6, 95, 17, 0, 1075, 1076, 6, 95, 13, 0, 1076, 208, 1, 0, 0, 0, 1077, 1078, 3, 181, 82, 0, 1078, 1079, 1, 0, 0, 0, 1079, 1080, 6, 96, 15, 0, 1080, 210, 1, 0, 0, 0, 1081, 1082, 3, 183, 83, 0, 1082, 1083, 1, 0, 0, 0, 1083, 1084, 6, 97, 18, 0, 1084, 212, 1, 0, 0, 0, 1085, 1086, 3, 111, 47, 0, 1086, 1087, 1, 0, 0, 0, 1087, 1088, 6, 98, 19, 0, 1088, 214, 1, 0, 0, 0, 1089, 1090, 3, 113, 48, 0, 1090, 1091, 1, 0, 0, 0, 1091, 1092, 6, 99, 20, 0, 1092, 216, 1, 0, 0, 0, 1093, 1094, 3, 107, 45, 0, 1094, 1095, 1, 0, 0, 0, 1095, 1096, 6, 100, 21, 0, 1096, 218, 1, 0, 0, 0, 1097, 1098, 7, 16, 0, 0, 1098, 1099, 7, 3, 0, 0, 1099, 1100, 7, 5, 0, 0, 1100, 1101, 7, 12, 0, 0, 1101, 1102, 7, 0, 0, 0, 1102, 1103, 7, 12, 0, 0, 1103, 1104, 7, 5, 0, 0, 1104, 1105, 7, 12, 0, 0, 1105, 220, 1, 0, 0, 0, 1106, 1110, 8, 32, 0, 0, 1107, 1108, 5, 47, 0, 0, 1108, 1110, 8, 33, 0, 0, 1109, 1106, 1, 0, 0, 0, 1109, 1107, 1, 0, 0, 0, 1110, 222, 1, 0, 0, 0, 1111, 1113, 3, 221, 102, 0, 1112, 1111, 1, 0, 0, 0, 1113, 1114, 1, 0, 0, 0, 1114, 1112, 1, 0, 0, 0, 1114, 1115, 1, 0, 0, 0, 1115, 224, 1, 0, 0, 0, 1116, 1117, 3, 223, 103, 0, 1117, 1118, 1, 0, 0, 0, 1118, 1119, 6, 104, 22, 0, 1119, 226, 1, 0, 0, 0, 1120, 1121, 3, 95, 39, 0, 1121, 1122, 1, 0, 0, 0, 1122, 1123, 6, 105, 23, 0, 1123, 228, 1, 0, 0, 0, 1124, 1125, 3, 67, 25, 0, 1125, 1126, 1, 0, 0, 0, 1126, 1127, 6, 106, 12, 0, 1127, 230, 1, 0, 0, 0, 1128, 1129, 3, 69, 26, 0, 1129, 1130, 1, 0, 0, 0, 1130, 1131, 6, 107, 12, 0, 1131, 232, 1, 0, 0, 0, 1132, 1133, 3, 71, 27, 0, 1133, 1134, 1, 0, 0, 0, 1134, 1135, 6, 108, 12, 0, 1135, 234, 1, 0, 0, 0, 1136, 1137, 3, 73, 28, 0, 1137, 1138, 1, 0, 0, 0, 1138, 1139, 6, 109, 17, 0, 1139, 1140, 6, 109, 13, 0, 1140, 236, 1, 0, 0, 0, 1141, 1142, 3, 117, 50, 0, 1142, 1143, 1, 0, 0, 0, 1143, 1144, 6, 110, 24, 0, 1144, 238, 1, 0, 0, 0, 1145, 1146, 3, 113, 48, 0, 1146, 1147, 1, 0, 0, 0, 1147, 1148, 6, 111, 20, 0, 1148, 240, 1, 0, 0, 0, 1149, 1150, 3, 141, 62, 0, 1150, 1151, 1, 0, 0, 0, 1151, 1152, 6, 112, 25, 0, 1152, 242, 1, 0, 0, 0, 1153, 1154, 3, 179, 81, 0, 1154, 1155, 1, 0, 0, 0, 1155, 1156, 6, 113, 26, 0, 1156, 244, 1, 0, 0, 0, 1157, 1162, 3, 77, 30, 0, 1158, 1162, 3, 75, 29, 0, 1159, 1162, 3, 91, 37, 0, 1160, 1162, 3, 167, 75, 0, 1161, 1157, 1, 0, 0, 0, 1161, 1158, 1, 0, 0, 0, 1161, 1159, 1, 0, 0, 0, 1161, 1160, 1, 0, 0, 0, 1162, 246, 1, 0, 0, 0, 1163, 1166, 3, 77, 30, 0, 1164, 1166, 3, 167, 75, 0, 1165, 1163, 1, 0, 0, 0, 1165, 1164, 1, 0, 0, 0, 1166, 1170, 1, 0, 0, 0, 1167, 1169, 3, 245, 114, 0, 1168, 1167, 1, 0, 0, 0, 1169, 1172, 1, 0, 0, 0, 1170, 1168, 1, 0, 0, 0, 1170, 1171, 1, 0, 0, 0, 1171, 1183, 1, 0, 0, 0, 1172, 1170, 1, 0, 0, 0, 1173, 1176, 3, 91, 37, 0, 1174, 1176, 3, 85, 34, 0, 1175, 1173, 1, 0, 0, 0, 1175, 1174, 1, 0, 0, 0, 1176, 1178, 1, 0, 0, 0, 1177, 1179, 3, 245, 114, 0, 1178, 1177, 1, 0, 0, 0, 1179, 1180, 1, 0, 0, 0, 1180, 1178, 1, 0, 0, 0, 1180, 1181, 1, 0, 0, 0, 1181, 1183, 1, 0, 0, 0, 1182, 1165, 1, 0, 0, 0, 1182, 1175, 1, 0, 0, 0, 1183, 248, 1, 0, 0, 0, 1184, 1187, 3, 247, 115, 0, 1185, 1187, 3, 187, 85, 0, 1186, 1184, 1, 0, 0, 0, 1186, 1185, 1, 0, 0, 0, 1187, 1188, 1, 0, 0, 0, 1188, 1186, 1, 0, 0, 0, 1188, 1189, 1, 0, 0, 0, 1189, 250, 1, 0, 0, 0, 1190, 1191, 3, 67, 25, 0, 1191, 1192, 1, 0, 0, 0, 1192, 1193, 6, 117, 12, 0, 1193, 252, 1, 0, 0, 0, 1194, 1195, 3, 69, 26, 0, 1195, 1196, 1, 0, 0, 0, 1196, 1197, 6, 118, 12, 0, 1197, 254, 1, 0, 0, 0, 1198, 1199, 3, 71, 27, 0, 1199, 1200, 1, 0, 0, 0, 1200, 1201, 6, 119, 12, 0, 1201, 256, 1, 0, 0, 0, 1202, 1203, 3, 73, 28, 0, 1203, 1204, 1, 0, 0, 0, 1204, 1205, 6, 120, 17, 0, 1205, 1206, 6, 120, 13, 0, 1206, 258, 1, 0, 0, 0, 1207, 1208, 3, 107, 45, 0, 1208, 1209, 1, 0, 0, 0, 1209, 1210, 6, 121, 21, 0, 1210, 260, 1, 0, 0, 0, 1211, 1212, 3, 113, 48, 0, 1212, 1213, 1, 0, 0, 0, 1213, 1214, 6, 122, 20, 0, 1214, 262, 1, 0, 0, 0, 1215, 1216, 3, 117, 50, 0, 1216, 1217, 1, 0, 0, 0, 1217, 1218, 6, 123, 24, 0, 1218, 264, 1, 0, 0, 0, 1219, 1220, 3, 141, 62, 0, 1220, 1221, 1, 0, 0, 0, 1221, 1222, 6, 124, 25, 0, 1222, 266, 1, 0, 0, 0, 1223, 1224, 3, 179, 81, 0, 1224, 1225, 1, 0, 0, 0, 1225, 1226, 6, 125, 26, 0, 1226, 268, 1, 0, 0, 0, 1227, 1228, 7, 12, 0, 0, 1228, 1229, 7, 2, 0, 0, 1229, 270, 1, 0, 0, 0, 1230, 1231, 3, 249, 116, 0, 1231, 1232, 1, 0, 0, 0, 1232, 1233, 6, 127, 27, 0, 1233, 272, 1, 0, 0, 0, 1234, 1235, 3, 67, 25, 0, 1235, 1236, 1, 0, 0, 0, 1236, 1237, 6, 128, 12, 0, 1237, 274, 1, 0, 0, 0, 1238, 1239, 3, 69, 26, 0, 1239, 1240, 1, 0, 0, 0, 1240, 1241, 6, 129, 12, 0, 1241, 276, 1, 0, 0, 0, 1242, 1243, 3, 71, 27, 0, 1243, 1244, 1, 0, 0, 0, 1244, 1245, 6, 130, 12, 0, 1245, 278, 1, 0, 0, 0, 1246, 1247, 3, 73, 28, 0, 1247, 1248, 1, 0, 0, 0, 1248, 1249, 6, 131, 17, 0, 1249, 1250, 6, 131, 13, 0, 1250, 280, 1, 0, 0, 0, 1251, 1252, 3, 181, 82, 0, 1252, 1253, 1, 0, 0, 0, 1253, 1254, 6, 132, 15, 0, 1254, 1255, 6, 132, 28, 0, 1255, 282, 1, 0, 0, 0, 1256, 1257, 7, 7, 0, 0, 1257, 1258, 7, 9, 0, 0, 1258, 1259, 1, 0, 0, 0, 1259, 1260, 6, 133, 29, 0, 1260, 284, 1, 0, 0, 0, 1261, 1262, 7, 19, 0, 0, 1262, 1263, 7, 1, 0, 0, 1263, 1264, 7, 5, 0, 0, 1264, 1265, 7, 10, 0, 0, 1265, 1266, 1, 0, 0, 0, 1266, 1267, 6, 134, 29, 0, 1267, 286, 1, 0, 0, 0, 1268, 1269, 8, 34, 0, 0, 1269, 288, 1, 0, 0, 0, 1270, 1272, 3, 287, 135, 0, 1271, 1270, 1, 0, 0, 0, 1272, 1273, 1, 0, 0, 0, 1273, 1271, 1, 0, 0, 0, 1273, 1274, 1, 0, 0, 0, 1274, 1275, 1, 0, 0, 0, 1275, 1276, 3, 111, 47, 0, 1276, 1278, 1, 0, 0, 0, 1277, 1271, 1, 0, 0, 0, 1277, 1278, 1, 0, 0, 0, 1278, 1280, 1, 0, 0, 0, 1279, 1281, 3, 287, 135, 0, 1280, 1279, 1, 0, 0, 0, 1281, 1282, 1, 0, 0, 0, 1282, 1280, 1, 0, 0, 0, 1282, 1283, 1, 0, 0, 0, 1283, 290, 1, 0, 0, 0, 1284, 1285, 3, 289, 136, 0, 1285, 1286, 1, 0, 0, 0, 1286, 1287, 6, 137, 30, 0, 1287, 292, 1, 0, 0, 0, 1288, 1289, 3, 67, 25, 0, 1289, 1290, 1, 0, 0, 0, 1290, 1291, 6, 138, 12, 0, 1291, 294, 1, 0, 0, 0, 1292, 1293, 3, 69, 26, 0, 1293, 1294, 1, 0, 0, 0, 1294, 1295, 6, 139, 12, 0, 1295, 296, 1, 0, 0, 0, 1296, 1297, 3, 71, 27, 0, 1297, 1298, 1, 0, 0, 0, 1298, 1299, 6, 140, 12, 0, 1299, 298, 1, 0, 0, 0, 1300, 1301, 3, 73, 28, 0, 1301, 1302, 1, 0, 0, 0, 1302, 1303, 6, 141, 17, 0, 1303, 1304, 6, 141, 13, 0, 1304, 1305, 6, 141, 13, 0, 1305, 300, 1, 0, 0, 0, 1306, 1307, 3, 107, 45, 0, 1307, 1308, 1, 0, 0, 0, 1308, 1309, 6, 142, 21, 0, 1309, 302, 1, 0, 0, 0, 1310, 1311, 3, 113, 48, 0, 1311, 1312, 1, 0, 0, 0, 1312, 1313, 6, 143, 20, 0, 1313, 304, 1, 0, 0, 0, 1314, 1315, 3, 117, 50, 0, 1315, 1316, 1, 0, 0, 0, 1316, 1317, 6, 144, 24, 0, 1317, 306, 1, 0, 0, 0, 1318, 1319, 3, 285, 134, 0, 1319, 1320, 1, 0, 0, 0, 1320, 1321, 6, 145, 31, 0, 1321, 308, 1, 0, 0, 0, 1322, 1323, 3, 249, 116, 0, 1323, 1324, 1, 0, 0, 0, 1324, 1325, 6, 146, 27, 0, 1325, 310, 1, 0, 0, 0, 1326, 1327, 3, 189, 86, 0, 1327, 1328, 1, 0, 0, 0, 1328, 1329, 6, 147, 32, 0, 1329, 312, 1, 0, 0, 0, 1330, 1331, 3, 141, 62, 0, 1331, 1332, 1, 0, 0, 0, 1332, 1333, 6, 148, 25, 0, 1333, 314, 1, 0, 0, 0, 1334, 1335, 3, 179, 81, 0, 1335, 1336, 1, 0, 0, 0, 1336, 1337, 6, 149, 26, 0, 1337, 316, 1, 0, 0, 0, 1338, 1339, 3, 67, 25, 0, 1339, 1340, 1, 0, 0, 0, 1340, 1341, 6, 150, 12, 0, 1341, 318, 1, 0, 0, 0, 1342, 1343, 3, 69, 26, 0, 1343, 1344, 1, 0, 0, 0, 1344, 1345, 6, 151, 12, 0, 1345, 320, 1, 0, 0, 0, 1346, 1347, 3, 71, 27, 0, 1347, 1348, 1, 0, 0, 0, 1348, 1349, 6, 152, 12, 0, 1349, 322, 1, 0, 0, 0, 1350, 1351, 3, 73, 28, 0, 1351, 1352, 1, 0, 0, 0, 1352, 1353, 6, 153, 17, 0, 1353, 1354, 6, 153, 13, 0, 1354, 324, 1, 0, 0, 0, 1355, 1356, 3, 117, 50, 0, 1356, 1357, 1, 0, 0, 0, 1357, 1358, 6, 154, 24, 0, 1358, 326, 1, 0, 0, 0, 1359, 1360, 3, 141, 62, 0, 1360, 1361, 1, 0, 0, 0, 1361, 1362, 6, 155, 25, 0, 1362, 328, 1, 0, 0, 0, 1363, 1364, 3, 179, 81, 0, 1364, 1365, 1, 0, 0, 0, 1365, 1366, 6, 156, 26, 0, 1366, 330, 1, 0, 0, 0, 1367, 1368, 3, 189, 86, 0, 1368, 1369, 1, 0, 0, 0, 1369, 1370, 6, 157, 32, 0, 1370, 332, 1, 0, 0, 0, 1371, 1372, 3, 185, 84, 0, 1372, 1373, 1, 0, 0, 0, 1373, 1374, 6, 158, 33, 0, 1374, 334, 1, 0, 0, 0, 1375, 1376, 3, 67, 25, 0, 1376, 1377, 1, 0, 0, 0, 1377, 1378, 6, 159, 12, 0, 1378, 336, 1, 0, 0, 0, 1379, 1380, 3, 69, 26, 0, 1380, 1381, 1, 0, 0, 0, 1381, 1382, 6, 160, 12, 0, 1382, 338, 1, 0, 0, 0, 1383, 1384, 3, 71, 27, 0, 1384, 1385, 1, 0, 0, 0, 1385, 1386, 6, 161, 12, 0, 1386, 340, 1, 0, 0, 0, 1387, 1388, 3, 73, 28, 0, 1388, 1389, 1, 0, 0, 0, 1389, 1390, 6, 162, 17, 0, 1390, 1391, 6, 162, 13, 0, 1391, 342, 1, 0, 0, 0, 1392, 1393, 7, 1, 0, 0, 1393, 1394, 7, 9, 0, 0, 1394, 1395, 7, 15, 0, 0, 1395, 1396, 7, 7, 0, 0, 1396, 344, 1, 0, 0, 0, 1397, 1398, 3, 67, 25, 0, 1398, 1399, 1, 0, 0, 0, 1399, 1400, 6, 164, 12, 0, 1400, 346, 1, 0, 0, 0, 1401, 1402, 3, 69, 26, 0, 1402, 1403, 1, 0, 0, 0, 1403, 1404, 6, 165, 12, 0, 1404, 348, 1, 0, 0, 0, 1405, 1406, 3, 71, 27, 0, 1406, 1407, 1, 0, 0, 0, 1407, 1408, 6, 166, 12, 0, 1408, 350, 1, 0, 0, 0, 1409, 1410, 3, 183, 83, 0, 1410, 1411, 1, 0, 0, 0, 1411, 1412, 6, 167, 18, 0, 1412, 1413, 6, 167, 13, 0, 1413, 352, 1, 0, 0, 0, 1414, 1415, 3, 111, 47, 0, 1415, 1416, 1, 0, 0, 0, 1416, 1417, 6, 168, 19, 0, 1417, 354, 1, 0, 0, 0, 1418, 1424, 3, 85, 34, 0, 1419, 1424, 3, 75, 29, 0, 1420, 1424, 3, 117, 50, 0, 1421, 1424, 3, 77, 30, 0, 1422, 1424, 3, 91, 37, 0, 1423, 1418, 1, 0, 0, 0, 1423, 1419, 1, 0, 0, 0, 1423, 1420, 1, 0, 0, 0, 1423, 1421, 1, 0, 0, 0, 1423, 1422, 1, 0, 0, 0, 1424, 1425, 1, 0, 0, 0, 1425, 1423, 1, 0, 0, 0, 1425, 1426, 1, 0, 0, 0, 1426, 356, 1, 0, 0, 0, 1427, 1428, 3, 67, 25, 0, 1428, 1429, 1, 0, 0, 0, 1429, 1430, 6, 170, 12, 0, 1430, 358, 1, 0, 0, 0, 1431, 1432, 3, 69, 26, 0, 1432, 1433, 1, 0, 0, 0, 1433, 1434, 6, 171, 12, 0, 1434, 360, 1, 0, 0, 0, 1435, 1436, 3, 71, 27, 0, 1436, 1437, 1, 0, 0, 0, 1437, 1438, 6, 172, 12, 0, 1438, 362, 1, 0, 0, 0, 1439, 1440, 3, 73, 28, 0, 1440, 1441, 1, 0, 0, 0, 1441, 1442, 6, 173, 17, 0, 1442, 1443, 6, 173, 13, 0, 1443, 364, 1, 0, 0, 0, 1444, 1445, 3, 111, 47, 0, 1445, 1446, 1, 0, 0, 0, 1446, 1447, 6, 174, 19, 0, 1447, 366, 1, 0, 0, 0, 1448, 1449, 3, 113, 48, 0, 1449, 1450, 1, 0, 0, 0, 1450, 1451, 6, 175, 20, 0, 1451, 368, 1, 0, 0, 0, 1452, 1453, 3, 117, 50, 0, 1453, 1454, 1, 0, 0, 0, 1454, 1455, 6, 176, 24, 0, 1455, 370, 1, 0, 0, 0, 1456, 1457, 3, 283, 133, 0, 1457, 1458, 1, 0, 0, 0, 1458, 1459, 6, 177, 34, 0, 1459, 1460, 6, 177, 35, 0, 1460, 372, 1, 0, 0, 0, 1461, 1462, 3, 223, 103, 0, 1462, 1463, 1, 0, 0, 0, 1463, 1464, 6, 178, 22, 0, 1464, 374, 1, 0, 0, 0, 1465, 1466, 3, 95, 39, 0, 1466, 1467, 1, 0, 0, 0, 1467, 1468, 6, 179, 23, 0, 1468, 376, 1, 0, 0, 0, 1469, 1470, 3, 67, 25, 0, 1470, 1471, 1, 0, 0, 0, 1471, 1472, 6, 180, 12, 0, 1472, 378, 1, 0, 0, 0, 1473, 1474, 3, 69, 26, 0, 1474, 1475, 1, 0, 0, 0, 1475, 1476, 6, 181, 12, 0, 1476, 380, 1, 0, 0, 0, 1477, 1478, 3, 71, 27, 0, 1478, 1479, 1, 0, 0, 0, 1479, 1480, 6, 182, 12, 0, 1480, 382, 1, 0, 0, 0, 1481, 1482, 3, 73, 28, 0, 1482, 1483, 1, 0, 0, 0, 1483, 1484, 6, 183, 17, 0, 1484, 1485, 6, 183, 13, 0, 1485, 1486, 6, 183, 13, 0, 1486, 384, 1, 0, 0, 0, 1487, 1488, 3, 113, 48, 0, 1488, 1489, 1, 0, 0, 0, 1489, 1490, 6, 184, 20, 0, 1490, 386, 1, 0, 0, 0, 1491, 1492, 3, 117, 50, 0, 1492, 1493, 1, 0, 0, 0, 1493, 1494, 6, 185, 24, 0, 1494, 388, 1, 0, 0, 0, 1495, 1496, 3, 249, 116, 0, 1496, 1497, 1, 0, 0, 0, 1497, 1498, 6, 186, 27, 0, 1498, 390, 1, 0, 0, 0, 1499, 1500, 3, 67, 25, 0, 1500, 1501, 1, 0, 0, 0, 1501, 1502, 6, 187, 12, 0, 1502, 392, 1, 0, 0, 0, 1503, 1504, 3, 69, 26, 0, 1504, 1505, 1, 0, 0, 0, 1505, 1506, 6, 188, 12, 0, 1506, 394, 1, 0, 0, 0, 1507, 1508, 3, 71, 27, 0, 1508, 1509, 1, 0, 0, 0, 1509, 1510, 6, 189, 12, 0, 1510, 396, 1, 0, 0, 0, 1511, 1512, 3, 73, 28, 0, 1512, 1513, 1, 0, 0, 0, 1513, 1514, 6, 190, 17, 0, 1514, 1515, 6, 190, 13, 0, 1515, 398, 1, 0, 0, 0, 1516, 1517, 7, 35, 0, 0, 1517, 1518, 7, 7, 0, 0, 1518, 1519, 7, 1, 0, 0, 1519, 1520, 7, 9, 0, 0, 1520, 400, 1, 0, 0, 0, 1521, 1522, 3, 269, 126, 0, 1522, 1523, 1, 0, 0, 0, 1523, 1524, 6, 192, 36, 0, 1524, 402, 1, 0, 0, 0, 1525, 1526, 3, 283, 133, 0, 1526, 1527, 1, 0, 0, 0, 1527, 1528, 6, 193, 34, 0, 1528, 1529, 6, 193, 13, 0, 1529, 1530, 6, 193, 0, 0, 1530, 404, 1, 0, 0, 0, 1531, 1532, 7, 20, 0, 0, 1532, 1533, 7, 2, 0, 0, 1533, 1534, 7, 1, 0, 0, 1534, 1535, 7, 9, 0, 0, 1535, 1536, 7, 17, 0, 0, 1536, 1537, 1, 0, 0, 0, 1537, 1538, 6, 194, 13, 0, 1538, 1539, 6, 194, 0, 0, 1539, 406, 1, 0, 0, 0, 1540, 1541, 3, 223, 103, 0, 1541, 1542, 1, 0, 0, 0, 1542, 1543, 6, 195, 22, 0, 1543, 408, 1, 0, 0, 0, 1544, 1545, 3, 95, 39, 0, 1545, 1546, 1, 0, 0, 0, 1546, 1547, 6, 196, 23, 0, 1547, 410, 1, 0, 0, 0, 1548, 1549, 3, 111, 47, 0, 1549, 1550, 1, 0, 0, 0, 1550, 1551, 6, 197, 19, 0, 1551, 412, 1, 0, 0, 0, 1552, 1553, 3, 185, 84, 0, 1553, 1554, 1, 0, 0, 0, 1554, 1555, 6, 198, 33, 0, 1555, 414, 1, 0, 0, 0, 1556, 1557, 3, 189, 86, 0, 1557, 1558, 1, 0, 0, 0, 1558, 1559, 6, 199, 32, 0, 1559, 416, 1, 0, 0, 0, 1560, 1561, 3, 67, 25, 0, 1561, 1562, 1, 0, 0, 0, 1562, 1563, 6, 200, 12, 0, 1563, 418, 1, 0, 0, 0, 1564, 1565, 3, 69, 26, 0, 1565, 1566, 1, 0, 0, 0, 1566, 1567, 6, 201, 12, 0, 1567, 420, 1, 0, 0, 0, 1568, 1569, 3, 71, 27, 0, 1569, 1570, 1, 0, 0, 0, 1570, 1571, 6, 202, 12, 0, 1571, 422, 1, 0, 0, 0, 1572, 1573, 3, 73, 28, 0, 1573, 1574, 1, 0, 0, 0, 1574, 1575, 6, 203, 17, 0, 1575, 1576, 6, 203, 13, 0, 1576, 424, 1, 0, 0, 0, 1577, 1578, 3, 223, 103, 0, 1578, 1579, 1, 0, 0, 0, 1579, 1580, 6, 204, 22, 0, 1580, 1581, 6, 204, 13, 0, 1581, 1582, 6, 204, 37, 0, 1582, 426, 1, 0, 0, 0, 1583, 1584, 3, 95, 39, 0, 1584, 1585, 1, 0, 0, 0, 1585, 1586, 6, 205, 23, 0, 1586, 1587, 6, 205, 13, 0, 1587, 1588, 6, 205, 37, 0, 1588, 428, 1, 0, 0, 0, 1589, 1590, 3, 67, 25, 0, 1590, 1591, 1, 0, 0, 0, 1591, 1592, 6, 206, 12, 0, 1592, 430, 1, 0, 0, 0, 1593, 1594, 3, 69, 26, 0, 1594, 1595, 1, 0, 0, 0, 1595, 1596, 6, 207, 12, 0, 1596, 432, 1, 0, 0, 0, 1597, 1598, 3, 71, 27, 0, 1598, 1599, 1, 0, 0, 0, 1599, 1600, 6, 208, 12, 0, 1600, 434, 1, 0, 0, 0, 1601, 1602, 3, 111, 47, 0, 1602, 1603, 1, 0, 0, 0, 1603, 1604, 6, 209, 19, 0, 1604, 1605, 6, 209, 13, 0, 1605, 1606, 6, 209, 11, 0, 1606, 436, 1, 0, 0, 0, 1607, 1608, 3, 113, 48, 0, 1608, 1609, 1, 0, 0, 0, 1609, 1610, 6, 210, 20, 0, 1610, 1611, 6, 210, 13, 0, 1611, 1612, 6, 210, 11, 0, 1612, 438, 1, 0, 0, 0, 1613, 1614, 3, 67, 25, 0, 1614, 1615, 1, 0, 0, 0, 1615, 1616, 6, 211, 12, 0, 1616, 440, 1, 0, 0, 0, 1617, 1618, 3, 69, 26, 0, 1618, 1619, 1, 0, 0, 0, 1619, 1620, 6, 212, 12, 0, 1620, 442, 1, 0, 0, 0, 1621, 1622, 3, 71, 27, 0, 1622, 1623, 1, 0, 0, 0, 1623, 1624, 6, 213, 12, 0, 1624, 444, 1, 0, 0, 0, 1625, 1626, 3, 189, 86, 0, 1626, 1627, 1, 0, 0, 0, 1627, 1628, 6, 214, 13, 0, 1628, 1629, 6, 214, 0, 0, 1629, 1630, 6, 214, 32, 0, 1630, 446, 1, 0, 0, 0, 1631, 1632, 3, 185, 84, 0, 1632, 1633, 1, 0, 0, 0, 1633, 1634, 6, 215, 13, 0, 1634, 1635, 6, 215, 0, 0, 1635, 1636, 6, 215, 33, 0, 1636, 448, 1, 0, 0, 0, 1637, 1638, 3, 101, 42, 0, 1638, 1639, 1, 0, 0, 0, 1639, 1640, 6, 216, 13, 0, 1640, 1641, 6, 216, 0, 0, 1641, 1642, 6, 216, 38, 0, 1642, 450, 1, 0, 0, 0, 1643, 1644, 3, 73, 28, 0, 1644, 1645, 1, 0, 0, 0, 1645, 1646, 6, 217, 17, 0, 1646, 1647, 6, 217, 13, 0, 1647, 452, 1, 0, 0, 0, 1648, 1649, 3, 73, 28, 0, 1649, 1650, 1, 0, 0, 0, 1650, 1651, 6, 218, 17, 0, 1651, 1652, 6, 218, 13, 0, 1652, 454, 1, 0, 0, 0, 1653, 1654, 3, 283, 133, 0, 1654, 1655, 1, 0, 0, 0, 1655, 1656, 6, 219, 34, 0, 1656, 456, 1, 0, 0, 0, 1657, 1658, 3, 269, 126, 0, 1658, 1659, 1, 0, 0, 0, 1659, 1660, 6, 220, 36, 0, 1660, 458, 1, 0, 0, 0, 1661, 1662, 3, 117, 50, 0, 1662, 1663, 1, 0, 0, 0, 1663, 1664, 6, 221, 24, 0, 1664, 460, 1, 0, 0, 0, 1665, 1666, 3, 113, 48, 0, 1666, 1667, 1, 0, 0, 0, 1667, 1668, 6, 222, 20, 0, 1668, 462, 1, 0, 0, 0, 1669, 1670, 3, 189, 86, 0, 1670, 1671, 1, 0, 0, 0, 1671, 1672, 6, 223, 32, 0, 1672, 464, 1, 0, 0, 0, 1673, 1674, 3, 185, 84, 0, 1674, 1675, 1, 0, 0, 0, 1675, 1676, 6, 224, 33, 0, 1676, 466, 1, 0, 0, 0, 1677, 1678, 3, 67, 25, 0, 1678, 1679, 1, 0, 0, 0, 1679, 1680, 6, 225, 12, 0, 1680, 468, 1, 0, 0, 0, 1681, 1682, 3, 69, 26, 0, 1682, 1683, 1, 0, 0, 0, 1683, 1684, 6, 226, 12, 0, 1684, 470, 1, 0, 0, 0, 1685, 1686, 3, 71, 27, 0, 1686, 1687, 1, 0, 0, 0, 1687, 1688, 6, 227, 12, 0, 1688, 472, 1, 0, 0, 0, 67, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 693, 703, 707, 710, 719, 721, 732, 751, 756, 765, 772, 777, 779, 790, 798, 801, 803, 808, 813, 819, 826, 831, 837, 840, 848, 852, 984, 989, 996, 998, 1014, 1019, 1024, 1026, 1032, 1109, 1114, 1161, 1165, 1170, 1175, 1180, 1182, 1186, 1188, 1273, 1277, 1282, 1423, 1425, 39, 5, 1, 0, 5, 4, 0, 5, 6, 0, 5, 2, 0, 5, 3, 0, 5, 8, 0, 5, 5, 0, 5, 9, 0, 5, 13, 0, 5, 16, 0, 5, 11, 0, 5, 14, 0, 0, 1, 0, 4, 0, 0, 7, 16, 0, 7, 72, 0, 5, 0, 0, 7, 29, 0, 7, 73, 0, 7, 38, 0, 7, 39, 0, 7, 36, 0, 7, 83, 0, 7, 30, 0, 7, 41, 0, 7, 53, 0, 7, 71, 0, 7, 87, 0, 5, 10, 0, 5, 7, 0, 7, 97, 0, 7, 96, 0, 7, 75, 0, 7, 74, 0, 7, 95, 0, 5, 12, 0, 7, 91, 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 aada45659c53..e4f8699993da 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 @@ -27,35 +27,37 @@ public class EsqlBaseLexer extends LexerConfig { public static final int DISSECT=1, DROP=2, ENRICH=3, EVAL=4, EXPLAIN=5, FROM=6, GROK=7, KEEP=8, LIMIT=9, MV_EXPAND=10, RENAME=11, ROW=12, SHOW=13, SORT=14, STATS=15, - WHERE=16, JOIN_LOOKUP=17, DEV_INLINESTATS=18, DEV_LOOKUP=19, DEV_METRICS=20, - DEV_JOIN_FULL=21, DEV_JOIN_LEFT=22, DEV_JOIN_RIGHT=23, UNKNOWN_CMD=24, - LINE_COMMENT=25, MULTILINE_COMMENT=26, WS=27, PIPE=28, QUOTED_STRING=29, - INTEGER_LITERAL=30, DECIMAL_LITERAL=31, BY=32, AND=33, ASC=34, ASSIGN=35, - CAST_OP=36, COLON=37, COMMA=38, DESC=39, DOT=40, FALSE=41, FIRST=42, IN=43, - IS=44, LAST=45, LIKE=46, LP=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, LEFT_BRACES=68, - RIGHT_BRACES=69, NAMED_OR_POSITIONAL_PARAM=70, OPENING_BRACKET=71, CLOSING_BRACKET=72, - UNQUOTED_IDENTIFIER=73, QUOTED_IDENTIFIER=74, EXPR_LINE_COMMENT=75, EXPR_MULTILINE_COMMENT=76, - EXPR_WS=77, EXPLAIN_WS=78, EXPLAIN_LINE_COMMENT=79, EXPLAIN_MULTILINE_COMMENT=80, - METADATA=81, UNQUOTED_SOURCE=82, FROM_LINE_COMMENT=83, FROM_MULTILINE_COMMENT=84, - FROM_WS=85, ID_PATTERN=86, PROJECT_LINE_COMMENT=87, PROJECT_MULTILINE_COMMENT=88, - PROJECT_WS=89, AS=90, RENAME_LINE_COMMENT=91, RENAME_MULTILINE_COMMENT=92, - RENAME_WS=93, ON=94, WITH=95, ENRICH_POLICY_NAME=96, ENRICH_LINE_COMMENT=97, - ENRICH_MULTILINE_COMMENT=98, ENRICH_WS=99, ENRICH_FIELD_LINE_COMMENT=100, - ENRICH_FIELD_MULTILINE_COMMENT=101, ENRICH_FIELD_WS=102, MVEXPAND_LINE_COMMENT=103, - MVEXPAND_MULTILINE_COMMENT=104, MVEXPAND_WS=105, INFO=106, SHOW_LINE_COMMENT=107, - SHOW_MULTILINE_COMMENT=108, SHOW_WS=109, SETTING=110, SETTING_LINE_COMMENT=111, - SETTTING_MULTILINE_COMMENT=112, SETTING_WS=113, LOOKUP_LINE_COMMENT=114, - LOOKUP_MULTILINE_COMMENT=115, LOOKUP_WS=116, LOOKUP_FIELD_LINE_COMMENT=117, - LOOKUP_FIELD_MULTILINE_COMMENT=118, LOOKUP_FIELD_WS=119, JOIN=120, USING=121, - JOIN_LINE_COMMENT=122, JOIN_MULTILINE_COMMENT=123, JOIN_WS=124, METRICS_LINE_COMMENT=125, - METRICS_MULTILINE_COMMENT=126, METRICS_WS=127, CLOSING_METRICS_LINE_COMMENT=128, - CLOSING_METRICS_MULTILINE_COMMENT=129, CLOSING_METRICS_WS=130; + WHERE=16, JOIN_LOOKUP=17, DEV_CHANGE_POINT=18, DEV_INLINESTATS=19, DEV_LOOKUP=20, + DEV_METRICS=21, DEV_JOIN_FULL=22, DEV_JOIN_LEFT=23, DEV_JOIN_RIGHT=24, + UNKNOWN_CMD=25, LINE_COMMENT=26, MULTILINE_COMMENT=27, WS=28, PIPE=29, + QUOTED_STRING=30, INTEGER_LITERAL=31, DECIMAL_LITERAL=32, BY=33, AND=34, + ASC=35, ASSIGN=36, CAST_OP=37, COLON=38, COMMA=39, DESC=40, DOT=41, FALSE=42, + FIRST=43, IN=44, IS=45, LAST=46, LIKE=47, LP=48, NOT=49, NULL=50, NULLS=51, + OR=52, PARAM=53, RLIKE=54, RP=55, TRUE=56, EQ=57, CIEQ=58, NEQ=59, LT=60, + LTE=61, GT=62, GTE=63, PLUS=64, MINUS=65, ASTERISK=66, SLASH=67, PERCENT=68, + LEFT_BRACES=69, RIGHT_BRACES=70, NAMED_OR_POSITIONAL_PARAM=71, OPENING_BRACKET=72, + CLOSING_BRACKET=73, UNQUOTED_IDENTIFIER=74, QUOTED_IDENTIFIER=75, EXPR_LINE_COMMENT=76, + EXPR_MULTILINE_COMMENT=77, EXPR_WS=78, EXPLAIN_WS=79, EXPLAIN_LINE_COMMENT=80, + EXPLAIN_MULTILINE_COMMENT=81, METADATA=82, UNQUOTED_SOURCE=83, FROM_LINE_COMMENT=84, + FROM_MULTILINE_COMMENT=85, FROM_WS=86, ID_PATTERN=87, PROJECT_LINE_COMMENT=88, + PROJECT_MULTILINE_COMMENT=89, PROJECT_WS=90, AS=91, RENAME_LINE_COMMENT=92, + RENAME_MULTILINE_COMMENT=93, RENAME_WS=94, ON=95, WITH=96, ENRICH_POLICY_NAME=97, + ENRICH_LINE_COMMENT=98, ENRICH_MULTILINE_COMMENT=99, ENRICH_WS=100, ENRICH_FIELD_LINE_COMMENT=101, + ENRICH_FIELD_MULTILINE_COMMENT=102, ENRICH_FIELD_WS=103, MVEXPAND_LINE_COMMENT=104, + MVEXPAND_MULTILINE_COMMENT=105, MVEXPAND_WS=106, INFO=107, SHOW_LINE_COMMENT=108, + SHOW_MULTILINE_COMMENT=109, SHOW_WS=110, SETTING=111, SETTING_LINE_COMMENT=112, + SETTTING_MULTILINE_COMMENT=113, SETTING_WS=114, LOOKUP_LINE_COMMENT=115, + LOOKUP_MULTILINE_COMMENT=116, LOOKUP_WS=117, LOOKUP_FIELD_LINE_COMMENT=118, + LOOKUP_FIELD_MULTILINE_COMMENT=119, LOOKUP_FIELD_WS=120, JOIN=121, USING=122, + JOIN_LINE_COMMENT=123, JOIN_MULTILINE_COMMENT=124, JOIN_WS=125, METRICS_LINE_COMMENT=126, + METRICS_MULTILINE_COMMENT=127, METRICS_WS=128, CLOSING_METRICS_LINE_COMMENT=129, + CLOSING_METRICS_MULTILINE_COMMENT=130, CLOSING_METRICS_WS=131, CHANGE_POINT_LINE_COMMENT=132, + CHANGE_POINT_MULTILINE_COMMENT=133, CHANGE_POINT_WS=134; public static final int EXPRESSION_MODE=1, EXPLAIN_MODE=2, FROM_MODE=3, PROJECT_MODE=4, RENAME_MODE=5, ENRICH_MODE=6, ENRICH_FIELD_MODE=7, MVEXPAND_MODE=8, SHOW_MODE=9, SETTING_MODE=10, - LOOKUP_MODE=11, LOOKUP_FIELD_MODE=12, JOIN_MODE=13, METRICS_MODE=14, CLOSING_METRICS_MODE=15; + LOOKUP_MODE=11, LOOKUP_FIELD_MODE=12, JOIN_MODE=13, METRICS_MODE=14, CLOSING_METRICS_MODE=15, + CHANGE_POINT_MODE=16; public static String[] channelNames = { "DEFAULT_TOKEN_CHANNEL", "HIDDEN" }; @@ -64,31 +66,31 @@ public class EsqlBaseLexer extends LexerConfig { "DEFAULT_MODE", "EXPRESSION_MODE", "EXPLAIN_MODE", "FROM_MODE", "PROJECT_MODE", "RENAME_MODE", "ENRICH_MODE", "ENRICH_FIELD_MODE", "MVEXPAND_MODE", "SHOW_MODE", "SETTING_MODE", "LOOKUP_MODE", "LOOKUP_FIELD_MODE", "JOIN_MODE", "METRICS_MODE", - "CLOSING_METRICS_MODE" + "CLOSING_METRICS_MODE", "CHANGE_POINT_MODE" }; private static String[] makeRuleNames() { return new String[] { "DISSECT", "DROP", "ENRICH", "EVAL", "EXPLAIN", "FROM", "GROK", "KEEP", "LIMIT", "MV_EXPAND", "RENAME", "ROW", "SHOW", "SORT", "STATS", "WHERE", - "JOIN_LOOKUP", "DEV_INLINESTATS", "DEV_LOOKUP", "DEV_METRICS", "DEV_JOIN_FULL", - "DEV_JOIN_LEFT", "DEV_JOIN_RIGHT", "UNKNOWN_CMD", "LINE_COMMENT", "MULTILINE_COMMENT", - "WS", "PIPE", "DIGIT", "LETTER", "ESCAPE_SEQUENCE", "UNESCAPED_CHARS", - "EXPONENT", "ASPERAND", "BACKQUOTE", "BACKQUOTE_BLOCK", "UNDERSCORE", - "UNQUOTED_ID_BODY", "QUOTED_STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", - "BY", "AND", "ASC", "ASSIGN", "CAST_OP", "COLON", "COMMA", "DESC", "DOT", - "FALSE", "FIRST", "IN", "IS", "LAST", "LIKE", "LP", "NOT", "NULL", "NULLS", - "OR", "PARAM", "RLIKE", "RP", "TRUE", "EQ", "CIEQ", "NEQ", "LT", "LTE", - "GT", "GTE", "PLUS", "MINUS", "ASTERISK", "SLASH", "PERCENT", "LEFT_BRACES", - "RIGHT_BRACES", "NESTED_WHERE", "NAMED_OR_POSITIONAL_PARAM", "OPENING_BRACKET", - "CLOSING_BRACKET", "UNQUOTED_IDENTIFIER", "QUOTED_ID", "QUOTED_IDENTIFIER", - "EXPR_LINE_COMMENT", "EXPR_MULTILINE_COMMENT", "EXPR_WS", "EXPLAIN_OPENING_BRACKET", - "EXPLAIN_PIPE", "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", "EXPLAIN_MULTILINE_COMMENT", - "FROM_PIPE", "FROM_OPENING_BRACKET", "FROM_CLOSING_BRACKET", "FROM_COLON", - "FROM_COMMA", "FROM_ASSIGN", "METADATA", "UNQUOTED_SOURCE_PART", "UNQUOTED_SOURCE", - "FROM_UNQUOTED_SOURCE", "FROM_QUOTED_SOURCE", "FROM_LINE_COMMENT", "FROM_MULTILINE_COMMENT", - "FROM_WS", "PROJECT_PIPE", "PROJECT_DOT", "PROJECT_COMMA", "PROJECT_PARAM", - "PROJECT_NAMED_OR_POSITIONAL_PARAM", "UNQUOTED_ID_BODY_WITH_PATTERN", + "JOIN_LOOKUP", "DEV_CHANGE_POINT", "DEV_INLINESTATS", "DEV_LOOKUP", "DEV_METRICS", + "DEV_JOIN_FULL", "DEV_JOIN_LEFT", "DEV_JOIN_RIGHT", "UNKNOWN_CMD", "LINE_COMMENT", + "MULTILINE_COMMENT", "WS", "PIPE", "DIGIT", "LETTER", "ESCAPE_SEQUENCE", + "UNESCAPED_CHARS", "EXPONENT", "ASPERAND", "BACKQUOTE", "BACKQUOTE_BLOCK", + "UNDERSCORE", "UNQUOTED_ID_BODY", "QUOTED_STRING", "INTEGER_LITERAL", + "DECIMAL_LITERAL", "BY", "AND", "ASC", "ASSIGN", "CAST_OP", "COLON", + "COMMA", "DESC", "DOT", "FALSE", "FIRST", "IN", "IS", "LAST", "LIKE", + "LP", "NOT", "NULL", "NULLS", "OR", "PARAM", "RLIKE", "RP", "TRUE", "EQ", + "CIEQ", "NEQ", "LT", "LTE", "GT", "GTE", "PLUS", "MINUS", "ASTERISK", + "SLASH", "PERCENT", "LEFT_BRACES", "RIGHT_BRACES", "NESTED_WHERE", "NAMED_OR_POSITIONAL_PARAM", + "OPENING_BRACKET", "CLOSING_BRACKET", "UNQUOTED_IDENTIFIER", "QUOTED_ID", + "QUOTED_IDENTIFIER", "EXPR_LINE_COMMENT", "EXPR_MULTILINE_COMMENT", "EXPR_WS", + "EXPLAIN_OPENING_BRACKET", "EXPLAIN_PIPE", "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", + "EXPLAIN_MULTILINE_COMMENT", "FROM_PIPE", "FROM_OPENING_BRACKET", "FROM_CLOSING_BRACKET", + "FROM_COLON", "FROM_COMMA", "FROM_ASSIGN", "METADATA", "UNQUOTED_SOURCE_PART", + "UNQUOTED_SOURCE", "FROM_UNQUOTED_SOURCE", "FROM_QUOTED_SOURCE", "FROM_LINE_COMMENT", + "FROM_MULTILINE_COMMENT", "FROM_WS", "PROJECT_PIPE", "PROJECT_DOT", "PROJECT_COMMA", + "PROJECT_PARAM", "PROJECT_NAMED_OR_POSITIONAL_PARAM", "UNQUOTED_ID_BODY_WITH_PATTERN", "UNQUOTED_ID_PATTERN", "ID_PATTERN", "PROJECT_LINE_COMMENT", "PROJECT_MULTILINE_COMMENT", "PROJECT_WS", "RENAME_PIPE", "RENAME_ASSIGN", "RENAME_COMMA", "RENAME_DOT", "RENAME_PARAM", "RENAME_NAMED_OR_POSITIONAL_PARAM", "AS", "RENAME_ID_PATTERN", @@ -115,7 +117,10 @@ public class EsqlBaseLexer extends LexerConfig { "METRICS_QUOTED_SOURCE", "METRICS_LINE_COMMENT", "METRICS_MULTILINE_COMMENT", "METRICS_WS", "CLOSING_METRICS_COLON", "CLOSING_METRICS_COMMA", "CLOSING_METRICS_LINE_COMMENT", "CLOSING_METRICS_MULTILINE_COMMENT", "CLOSING_METRICS_WS", "CLOSING_METRICS_QUOTED_IDENTIFIER", - "CLOSING_METRICS_UNQUOTED_IDENTIFIER", "CLOSING_METRICS_BY", "CLOSING_METRICS_PIPE" + "CLOSING_METRICS_UNQUOTED_IDENTIFIER", "CLOSING_METRICS_BY", "CLOSING_METRICS_PIPE", + "CHANGE_POINT_PIPE", "CHANGE_POINT_ON", "CHANGE_POINT_AS", "CHANGE_POINT_DOT", + "CHANGE_POINT_COMMA", "CHANGE_POINT_QUOTED_IDENTIFIER", "CHANGE_POINT_UNQUOTED_IDENTIFIER", + "CHANGE_POINT_LINE_COMMENT", "CHANGE_POINT_MULTILINE_COMMENT", "CHANGE_POINT_WS" }; } public static final String[] ruleNames = makeRuleNames(); @@ -125,16 +130,16 @@ public class EsqlBaseLexer extends LexerConfig { null, "'dissect'", "'drop'", "'enrich'", "'eval'", "'explain'", "'from'", "'grok'", "'keep'", "'limit'", "'mv_expand'", "'rename'", "'row'", "'show'", "'sort'", "'stats'", "'where'", "'lookup'", null, null, null, null, null, - null, null, null, null, null, "'|'", null, null, null, "'by'", "'and'", - "'asc'", "'='", "'::'", "':'", "','", "'desc'", "'.'", "'false'", "'first'", - "'in'", "'is'", "'last'", "'like'", "'('", "'not'", "'null'", "'nulls'", - "'or'", "'?'", "'rlike'", "')'", "'true'", "'=='", "'=~'", "'!='", "'<'", - "'<='", "'>'", "'>='", "'+'", "'-'", "'*'", "'/'", "'%'", "'{'", "'}'", - null, null, "']'", null, null, null, null, null, null, null, null, "'metadata'", - null, 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, null, null, null, null, null, null, - null, null, null, null, "'join'", "'USING'" + null, null, null, null, null, null, "'|'", null, null, null, "'by'", + "'and'", "'asc'", "'='", "'::'", "':'", "','", "'desc'", "'.'", "'false'", + "'first'", "'in'", "'is'", "'last'", "'like'", "'('", "'not'", "'null'", + "'nulls'", "'or'", "'?'", "'rlike'", "')'", "'true'", "'=='", "'=~'", + "'!='", "'<'", "'<='", "'>'", "'>='", "'+'", "'-'", "'*'", "'/'", "'%'", + "'{'", "'}'", null, null, "']'", null, null, null, null, null, null, + null, null, "'metadata'", null, 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, null, null, + null, null, null, null, null, null, null, null, "'join'", "'USING'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); @@ -142,9 +147,9 @@ public class EsqlBaseLexer extends LexerConfig { return new String[] { null, "DISSECT", "DROP", "ENRICH", "EVAL", "EXPLAIN", "FROM", "GROK", "KEEP", "LIMIT", "MV_EXPAND", "RENAME", "ROW", "SHOW", "SORT", "STATS", - "WHERE", "JOIN_LOOKUP", "DEV_INLINESTATS", "DEV_LOOKUP", "DEV_METRICS", - "DEV_JOIN_FULL", "DEV_JOIN_LEFT", "DEV_JOIN_RIGHT", "UNKNOWN_CMD", "LINE_COMMENT", - "MULTILINE_COMMENT", "WS", "PIPE", "QUOTED_STRING", "INTEGER_LITERAL", + "WHERE", "JOIN_LOOKUP", "DEV_CHANGE_POINT", "DEV_INLINESTATS", "DEV_LOOKUP", + "DEV_METRICS", "DEV_JOIN_FULL", "DEV_JOIN_LEFT", "DEV_JOIN_RIGHT", "UNKNOWN_CMD", + "LINE_COMMENT", "MULTILINE_COMMENT", "WS", "PIPE", "QUOTED_STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "AND", "ASC", "ASSIGN", "CAST_OP", "COLON", "COMMA", "DESC", "DOT", "FALSE", "FIRST", "IN", "IS", "LAST", "LIKE", "LP", "NOT", "NULL", "NULLS", "OR", "PARAM", "RLIKE", "RP", "TRUE", "EQ", @@ -165,7 +170,8 @@ public class EsqlBaseLexer extends LexerConfig { "LOOKUP_FIELD_LINE_COMMENT", "LOOKUP_FIELD_MULTILINE_COMMENT", "LOOKUP_FIELD_WS", "JOIN", "USING", "JOIN_LINE_COMMENT", "JOIN_MULTILINE_COMMENT", "JOIN_WS", "METRICS_LINE_COMMENT", "METRICS_MULTILINE_COMMENT", "METRICS_WS", "CLOSING_METRICS_LINE_COMMENT", - "CLOSING_METRICS_MULTILINE_COMMENT", "CLOSING_METRICS_WS" + "CLOSING_METRICS_MULTILINE_COMMENT", "CLOSING_METRICS_WS", "CHANGE_POINT_LINE_COMMENT", + "CHANGE_POINT_MULTILINE_COMMENT", "CHANGE_POINT_WS" }; } private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); @@ -231,1190 +237,1173 @@ public class EsqlBaseLexer extends LexerConfig { public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { switch (ruleIndex) { case 17: - return DEV_INLINESTATS_sempred((RuleContext)_localctx, predIndex); + return DEV_CHANGE_POINT_sempred((RuleContext)_localctx, predIndex); case 18: - return DEV_LOOKUP_sempred((RuleContext)_localctx, predIndex); + return DEV_INLINESTATS_sempred((RuleContext)_localctx, predIndex); case 19: - return DEV_METRICS_sempred((RuleContext)_localctx, predIndex); + return DEV_LOOKUP_sempred((RuleContext)_localctx, predIndex); case 20: - return DEV_JOIN_FULL_sempred((RuleContext)_localctx, predIndex); + return DEV_METRICS_sempred((RuleContext)_localctx, predIndex); case 21: - return DEV_JOIN_LEFT_sempred((RuleContext)_localctx, predIndex); + return DEV_JOIN_FULL_sempred((RuleContext)_localctx, predIndex); case 22: + return DEV_JOIN_LEFT_sempred((RuleContext)_localctx, predIndex); + case 23: return DEV_JOIN_RIGHT_sempred((RuleContext)_localctx, predIndex); - case 111: - return PROJECT_PARAM_sempred((RuleContext)_localctx, predIndex); - case 112: - return PROJECT_NAMED_OR_POSITIONAL_PARAM_sempred((RuleContext)_localctx, predIndex); - case 123: - return RENAME_PARAM_sempred((RuleContext)_localctx, predIndex); - case 124: - return RENAME_NAMED_OR_POSITIONAL_PARAM_sempred((RuleContext)_localctx, predIndex); - case 147: - return ENRICH_FIELD_PARAM_sempred((RuleContext)_localctx, predIndex); - case 148: - return ENRICH_FIELD_NAMED_OR_POSITIONAL_PARAM_sempred((RuleContext)_localctx, predIndex); - case 154: - return MVEXPAND_PARAM_sempred((RuleContext)_localctx, predIndex); - case 155: - return MVEXPAND_NAMED_OR_POSITIONAL_PARAM_sempred((RuleContext)_localctx, predIndex); } return true; } - private boolean DEV_INLINESTATS_sempred(RuleContext _localctx, int predIndex) { + private boolean DEV_CHANGE_POINT_sempred(RuleContext _localctx, int predIndex) { switch (predIndex) { case 0: return this.isDevVersion(); } return true; } - private boolean DEV_LOOKUP_sempred(RuleContext _localctx, int predIndex) { + private boolean DEV_INLINESTATS_sempred(RuleContext _localctx, int predIndex) { switch (predIndex) { case 1: return this.isDevVersion(); } return true; } - private boolean DEV_METRICS_sempred(RuleContext _localctx, int predIndex) { + private boolean DEV_LOOKUP_sempred(RuleContext _localctx, int predIndex) { switch (predIndex) { case 2: return this.isDevVersion(); } return true; } - private boolean DEV_JOIN_FULL_sempred(RuleContext _localctx, int predIndex) { + private boolean DEV_METRICS_sempred(RuleContext _localctx, int predIndex) { switch (predIndex) { case 3: return this.isDevVersion(); } return true; } - private boolean DEV_JOIN_LEFT_sempred(RuleContext _localctx, int predIndex) { + private boolean DEV_JOIN_FULL_sempred(RuleContext _localctx, int predIndex) { switch (predIndex) { case 4: return this.isDevVersion(); } return true; } - private boolean DEV_JOIN_RIGHT_sempred(RuleContext _localctx, int predIndex) { + private boolean DEV_JOIN_LEFT_sempred(RuleContext _localctx, int predIndex) { switch (predIndex) { case 5: return this.isDevVersion(); } return true; } - private boolean PROJECT_PARAM_sempred(RuleContext _localctx, int predIndex) { + private boolean DEV_JOIN_RIGHT_sempred(RuleContext _localctx, int predIndex) { switch (predIndex) { case 6: return this.isDevVersion(); } return true; } - private boolean PROJECT_NAMED_OR_POSITIONAL_PARAM_sempred(RuleContext _localctx, int predIndex) { - switch (predIndex) { - case 7: - return this.isDevVersion(); - } - return true; - } - private boolean RENAME_PARAM_sempred(RuleContext _localctx, int predIndex) { - switch (predIndex) { - case 8: - return this.isDevVersion(); - } - return true; - } - private boolean RENAME_NAMED_OR_POSITIONAL_PARAM_sempred(RuleContext _localctx, int predIndex) { - switch (predIndex) { - case 9: - return this.isDevVersion(); - } - return true; - } - private boolean ENRICH_FIELD_PARAM_sempred(RuleContext _localctx, int predIndex) { - switch (predIndex) { - case 10: - return this.isDevVersion(); - } - return true; - } - private boolean ENRICH_FIELD_NAMED_OR_POSITIONAL_PARAM_sempred(RuleContext _localctx, int predIndex) { - switch (predIndex) { - case 11: - return this.isDevVersion(); - } - return true; - } - private boolean MVEXPAND_PARAM_sempred(RuleContext _localctx, int predIndex) { - switch (predIndex) { - case 12: - return this.isDevVersion(); - } - return true; - } - private boolean MVEXPAND_NAMED_OR_POSITIONAL_PARAM_sempred(RuleContext _localctx, int predIndex) { - switch (predIndex) { - case 13: - return this.isDevVersion(); - } - return true; - } public static final String _serializedATN = - "\u0004\u0000\u0082\u0651\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+ + "\u0004\u0000\u0086\u0699\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\u0007"+ - "1\u00022\u00072\u00023\u00073\u00024\u00074\u00025\u00075\u00026\u0007"+ - "6\u00027\u00077\u00028\u00078\u00029\u00079\u0002:\u0007:\u0002;\u0007"+ - ";\u0002<\u0007<\u0002=\u0007=\u0002>\u0007>\u0002?\u0007?\u0002@\u0007"+ - "@\u0002A\u0007A\u0002B\u0007B\u0002C\u0007C\u0002D\u0007D\u0002E\u0007"+ - "E\u0002F\u0007F\u0002G\u0007G\u0002H\u0007H\u0002I\u0007I\u0002J\u0007"+ - "J\u0002K\u0007K\u0002L\u0007L\u0002M\u0007M\u0002N\u0007N\u0002O\u0007"+ - "O\u0002P\u0007P\u0002Q\u0007Q\u0002R\u0007R\u0002S\u0007S\u0002T\u0007"+ - "T\u0002U\u0007U\u0002V\u0007V\u0002W\u0007W\u0002X\u0007X\u0002Y\u0007"+ - "Y\u0002Z\u0007Z\u0002[\u0007[\u0002\\\u0007\\\u0002]\u0007]\u0002^\u0007"+ - "^\u0002_\u0007_\u0002`\u0007`\u0002a\u0007a\u0002b\u0007b\u0002c\u0007"+ - "c\u0002d\u0007d\u0002e\u0007e\u0002f\u0007f\u0002g\u0007g\u0002h\u0007"+ - "h\u0002i\u0007i\u0002j\u0007j\u0002k\u0007k\u0002l\u0007l\u0002m\u0007"+ - "m\u0002n\u0007n\u0002o\u0007o\u0002p\u0007p\u0002q\u0007q\u0002r\u0007"+ - "r\u0002s\u0007s\u0002t\u0007t\u0002u\u0007u\u0002v\u0007v\u0002w\u0007"+ - "w\u0002x\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\u0002\u00bd\u0007\u00bd\u0002\u00be\u0007\u00be\u0002\u00bf\u0007"+ - "\u00bf\u0002\u00c0\u0007\u00c0\u0002\u00c1\u0007\u00c1\u0002\u00c2\u0007"+ - "\u00c2\u0002\u00c3\u0007\u00c3\u0002\u00c4\u0007\u00c4\u0002\u00c5\u0007"+ - "\u00c5\u0002\u00c6\u0007\u00c6\u0002\u00c7\u0007\u00c7\u0002\u00c8\u0007"+ - "\u00c8\u0002\u00c9\u0007\u00c9\u0002\u00ca\u0007\u00ca\u0002\u00cb\u0007"+ - "\u00cb\u0002\u00cc\u0007\u00cc\u0002\u00cd\u0007\u00cd\u0002\u00ce\u0007"+ - "\u00ce\u0002\u00cf\u0007\u00cf\u0002\u00d0\u0007\u00d0\u0002\u00d1\u0007"+ - "\u00d1\u0002\u00d2\u0007\u00d2\u0002\u00d3\u0007\u00d3\u0002\u00d4\u0007"+ - "\u00d4\u0002\u00d5\u0007\u00d5\u0002\u00d6\u0007\u00d6\u0002\u00d7\u0007"+ - "\u00d7\u0002\u00d8\u0007\u00d8\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\b\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"+ - "\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\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"+ - "\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\u000f\u0001\u000f\u0001\u0010\u0001\u0010\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\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"+ - "\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0013\u0001\u0013\u0001"+ - "\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001"+ - "\u0013\u0001\u0013\u0001\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0001"+ - "\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0015\u0001"+ - "\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001"+ - "\u0015\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001"+ - "\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0004\u0017\u028d"+ - "\b\u0017\u000b\u0017\f\u0017\u028e\u0001\u0017\u0001\u0017\u0001\u0018"+ - "\u0001\u0018\u0001\u0018\u0001\u0018\u0005\u0018\u0297\b\u0018\n\u0018"+ - "\f\u0018\u029a\t\u0018\u0001\u0018\u0003\u0018\u029d\b\u0018\u0001\u0018"+ - "\u0003\u0018\u02a0\b\u0018\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019"+ - "\u0001\u0019\u0001\u0019\u0001\u0019\u0005\u0019\u02a9\b\u0019\n\u0019"+ - "\f\u0019\u02ac\t\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019"+ - "\u0001\u0019\u0001\u001a\u0004\u001a\u02b4\b\u001a\u000b\u001a\f\u001a"+ - "\u02b5\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001\u001b\u0001"+ - "\u001b\u0001\u001c\u0001\u001c\u0001\u001d\u0001\u001d\u0001\u001e\u0001"+ - "\u001e\u0001\u001e\u0001\u001f\u0001\u001f\u0001 \u0001 \u0003 \u02c9"+ - "\b \u0001 \u0004 \u02cc\b \u000b \f \u02cd\u0001!\u0001!\u0001\"\u0001"+ - "\"\u0001#\u0001#\u0001#\u0003#\u02d7\b#\u0001$\u0001$\u0001%\u0001%\u0001"+ - "%\u0003%\u02de\b%\u0001&\u0001&\u0001&\u0005&\u02e3\b&\n&\f&\u02e6\t&"+ - "\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0005&\u02ee\b&\n&\f&\u02f1"+ - "\t&\u0001&\u0001&\u0001&\u0001&\u0001&\u0003&\u02f8\b&\u0001&\u0003&\u02fb"+ - "\b&\u0003&\u02fd\b&\u0001\'\u0004\'\u0300\b\'\u000b\'\f\'\u0301\u0001"+ - "(\u0004(\u0305\b(\u000b(\f(\u0306\u0001(\u0001(\u0005(\u030b\b(\n(\f("+ - "\u030e\t(\u0001(\u0001(\u0004(\u0312\b(\u000b(\f(\u0313\u0001(\u0004("+ - "\u0317\b(\u000b(\f(\u0318\u0001(\u0001(\u0005(\u031d\b(\n(\f(\u0320\t"+ - "(\u0003(\u0322\b(\u0001(\u0001(\u0001(\u0001(\u0004(\u0328\b(\u000b(\f"+ - "(\u0329\u0001(\u0001(\u0003(\u032e\b(\u0001)\u0001)\u0001)\u0001*\u0001"+ - "*\u0001*\u0001*\u0001+\u0001+\u0001+\u0001+\u0001,\u0001,\u0001-\u0001"+ - "-\u0001-\u0001.\u0001.\u0001/\u0001/\u00010\u00010\u00010\u00010\u0001"+ - "0\u00011\u00011\u00012\u00012\u00012\u00012\u00012\u00012\u00013\u0001"+ - "3\u00013\u00013\u00013\u00013\u00014\u00014\u00014\u00015\u00015\u0001"+ - "5\u00016\u00016\u00016\u00016\u00016\u00017\u00017\u00017\u00017\u0001"+ - "7\u00018\u00018\u00019\u00019\u00019\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@\u0001A\u0001A\u0001A\u0001B\u0001"+ - "B\u0001B\u0001C\u0001C\u0001C\u0001D\u0001D\u0001E\u0001E\u0001E\u0001"+ - "F\u0001F\u0001G\u0001G\u0001G\u0001H\u0001H\u0001I\u0001I\u0001J\u0001"+ - "J\u0001K\u0001K\u0001L\u0001L\u0001M\u0001M\u0001N\u0001N\u0001O\u0001"+ - "O\u0001O\u0001O\u0001P\u0001P\u0001P\u0003P\u03b2\bP\u0001P\u0005P\u03b5"+ - "\bP\nP\fP\u03b8\tP\u0001P\u0001P\u0004P\u03bc\bP\u000bP\fP\u03bd\u0003"+ - "P\u03c0\bP\u0001Q\u0001Q\u0001Q\u0001Q\u0001Q\u0001R\u0001R\u0001R\u0001"+ - "R\u0001R\u0001S\u0001S\u0005S\u03ce\bS\nS\fS\u03d1\tS\u0001S\u0001S\u0003"+ - "S\u03d5\bS\u0001S\u0004S\u03d8\bS\u000bS\fS\u03d9\u0003S\u03dc\bS\u0001"+ - "T\u0001T\u0004T\u03e0\bT\u000bT\fT\u03e1\u0001T\u0001T\u0001U\u0001U\u0001"+ - "V\u0001V\u0001V\u0001V\u0001W\u0001W\u0001W\u0001W\u0001X\u0001X\u0001"+ - "X\u0001X\u0001Y\u0001Y\u0001Y\u0001Y\u0001Y\u0001Z\u0001Z\u0001Z\u0001"+ - "Z\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`\u0001a\u0001a\u0001a\u0001"+ - "a\u0001b\u0001b\u0001b\u0001b\u0001c\u0001c\u0001c\u0001c\u0001d\u0001"+ - "d\u0001d\u0001d\u0001d\u0001d\u0001d\u0001d\u0001d\u0001e\u0001e\u0001"+ - "e\u0003e\u042f\be\u0001f\u0004f\u0432\bf\u000bf\ff\u0433\u0001g\u0001"+ - "g\u0001g\u0001g\u0001h\u0001h\u0001h\u0001h\u0001i\u0001i\u0001i\u0001"+ - "i\u0001j\u0001j\u0001j\u0001j\u0001k\u0001k\u0001k\u0001k\u0001l\u0001"+ - "l\u0001l\u0001l\u0001l\u0001m\u0001m\u0001m\u0001m\u0001n\u0001n\u0001"+ - "n\u0001n\u0001o\u0001o\u0001o\u0001o\u0001o\u0001p\u0001p\u0001p\u0001"+ - "p\u0001p\u0001q\u0001q\u0001q\u0001q\u0003q\u0465\bq\u0001r\u0001r\u0003"+ - "r\u0469\br\u0001r\u0005r\u046c\br\nr\fr\u046f\tr\u0001r\u0001r\u0003r"+ - "\u0473\br\u0001r\u0004r\u0476\br\u000br\fr\u0477\u0003r\u047a\br\u0001"+ - "s\u0001s\u0004s\u047e\bs\u000bs\fs\u047f\u0001t\u0001t\u0001t\u0001t\u0001"+ - "u\u0001u\u0001u\u0001u\u0001v\u0001v\u0001v\u0001v\u0001w\u0001w\u0001"+ - "w\u0001w\u0001w\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\u007f\u0001\u007f\u0001\u007f\u0001\u007f\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\u0082\u0001"+ - "\u0083\u0001\u0083\u0001\u0083\u0001\u0083\u0001\u0083\u0001\u0084\u0001"+ - "\u0084\u0001\u0084\u0001\u0084\u0001\u0084\u0001\u0085\u0001\u0085\u0001"+ - "\u0085\u0001\u0085\u0001\u0085\u0001\u0085\u0001\u0085\u0001\u0086\u0001"+ - "\u0086\u0001\u0087\u0004\u0087\u04d5\b\u0087\u000b\u0087\f\u0087\u04d6"+ - "\u0001\u0087\u0001\u0087\u0003\u0087\u04db\b\u0087\u0001\u0087\u0004\u0087"+ - "\u04de\b\u0087\u000b\u0087\f\u0087\u04df\u0001\u0088\u0001\u0088\u0001"+ - "\u0088\u0001\u0088\u0001\u0089\u0001\u0089\u0001\u0089\u0001\u0089\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"+ - "\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"+ - "\u0091\u0001\u0091\u0001\u0091\u0001\u0091\u0001\u0092\u0001\u0092\u0001"+ - "\u0092\u0001\u0092\u0001\u0093\u0001\u0093\u0001\u0093\u0001\u0093\u0001"+ - "\u0093\u0001\u0094\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\u0097\u0001\u0097\u0001\u0097\u0001\u0097\u0001"+ - "\u0098\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\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\u00a1\u0001\u00a1\u0001\u00a1\u0001"+ - "\u00a1\u0001\u00a1\u0001\u00a2\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\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\u00a8\u0004\u00a8\u0571\b\u00a8\u000b\u00a8\f"+ - "\u00a8\u0572\u0001\u00a9\u0001\u00a9\u0001\u00a9\u0001\u00a9\u0001\u00aa"+ - "\u0001\u00aa\u0001\u00aa\u0001\u00aa\u0001\u00ab\u0001\u00ab\u0001\u00ab"+ - "\u0001\u00ab\u0001\u00ac\u0001\u00ac\u0001\u00ac\u0001\u00ac\u0001\u00ac"+ - "\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\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\u00b6\u0001\u00b6\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\u00ba\u0001\u00ba\u0001\u00ba\u0001\u00ba\u0001\u00bb"+ - "\u0001\u00bb\u0001\u00bb\u0001\u00bb\u0001\u00bc\u0001\u00bc\u0001\u00bc"+ - "\u0001\u00bc\u0001\u00bd\u0001\u00bd\u0001\u00bd\u0001\u00bd\u0001\u00bd"+ - "\u0001\u00be\u0001\u00be\u0001\u00be\u0001\u00be\u0001\u00be\u0001\u00bf"+ - "\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00c0\u0001\u00c0\u0001\u00c0"+ - "\u0001\u00c0\u0001\u00c0\u0001\u00c0\u0001\u00c1\u0001\u00c1\u0001\u00c1"+ - "\u0001\u00c1\u0001\u00c1\u0001\u00c1\u0001\u00c1\u0001\u00c1\u0001\u00c1"+ - "\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001\u00c3\u0001\u00c3"+ - "\u0001\u00c3\u0001\u00c3\u0001\u00c4\u0001\u00c4\u0001\u00c4\u0001\u00c4"+ - "\u0001\u00c5\u0001\u00c5\u0001\u00c5\u0001\u00c5\u0001\u00c6\u0001\u00c6"+ - "\u0001\u00c6\u0001\u00c6\u0001\u00c7\u0001\u00c7\u0001\u00c7\u0001\u00c7"+ - "\u0001\u00c8\u0001\u00c8\u0001\u00c8\u0001\u00c8\u0001\u00c9\u0001\u00c9"+ - "\u0001\u00c9\u0001\u00c9\u0001\u00ca\u0001\u00ca\u0001\u00ca\u0001\u00ca"+ - "\u0001\u00ca\u0001\u00cb\u0001\u00cb\u0001\u00cb\u0001\u00cb\u0001\u00cb"+ - "\u0001\u00cb\u0001\u00cc\u0001\u00cc\u0001\u00cc\u0001\u00cc\u0001\u00cc"+ - "\u0001\u00cc\u0001\u00cd\u0001\u00cd\u0001\u00cd\u0001\u00cd\u0001\u00ce"+ - "\u0001\u00ce\u0001\u00ce\u0001\u00ce\u0001\u00cf\u0001\u00cf\u0001\u00cf"+ - "\u0001\u00cf\u0001\u00d0\u0001\u00d0\u0001\u00d0\u0001\u00d0\u0001\u00d0"+ - "\u0001\u00d0\u0001\u00d1\u0001\u00d1\u0001\u00d1\u0001\u00d1\u0001\u00d1"+ - "\u0001\u00d1\u0001\u00d2\u0001\u00d2\u0001\u00d2\u0001\u00d2\u0001\u00d3"+ - "\u0001\u00d3\u0001\u00d3\u0001\u00d3\u0001\u00d4\u0001\u00d4\u0001\u00d4"+ - "\u0001\u00d4\u0001\u00d5\u0001\u00d5\u0001\u00d5\u0001\u00d5\u0001\u00d5"+ - "\u0001\u00d5\u0001\u00d6\u0001\u00d6\u0001\u00d6\u0001\u00d6\u0001\u00d6"+ - "\u0001\u00d6\u0001\u00d7\u0001\u00d7\u0001\u00d7\u0001\u00d7\u0001\u00d7"+ - "\u0001\u00d7\u0001\u00d8\u0001\u00d8\u0001\u00d8\u0001\u00d8\u0001\u00d8"+ - "\u0002\u02aa\u02ef\u0000\u00d9\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@\u0019B\u001aD\u001bF\u001cH\u0000J\u0000L\u0000N\u0000P\u0000"+ - "R\u0000T\u0000V\u0000X\u0000Z\u0000\\\u001d^\u001e`\u001fb d!f\"h#j$l"+ - "%n&p\'r(t)v*x+z,|-~.\u0080/\u00820\u00841\u00862\u00883\u008a4\u008c5"+ - "\u008e6\u00907\u00928\u00949\u0096:\u0098;\u009a<\u009c=\u009e>\u00a0"+ - "?\u00a2@\u00a4A\u00a6B\u00a8C\u00aaD\u00acE\u00ae\u0000\u00b0F\u00b2G"+ - "\u00b4H\u00b6I\u00b8\u0000\u00baJ\u00bcK\u00beL\u00c0M\u00c2\u0000\u00c4"+ - "\u0000\u00c6N\u00c8O\u00caP\u00cc\u0000\u00ce\u0000\u00d0\u0000\u00d2"+ - "\u0000\u00d4\u0000\u00d6\u0000\u00d8Q\u00da\u0000\u00dcR\u00de\u0000\u00e0"+ - "\u0000\u00e2S\u00e4T\u00e6U\u00e8\u0000\u00ea\u0000\u00ec\u0000\u00ee"+ - "\u0000\u00f0\u0000\u00f2\u0000\u00f4\u0000\u00f6V\u00f8W\u00faX\u00fc"+ - "Y\u00fe\u0000\u0100\u0000\u0102\u0000\u0104\u0000\u0106\u0000\u0108\u0000"+ - "\u010aZ\u010c\u0000\u010e[\u0110\\\u0112]\u0114\u0000\u0116\u0000\u0118"+ - "^\u011a_\u011c\u0000\u011e`\u0120\u0000\u0122a\u0124b\u0126c\u0128\u0000"+ - "\u012a\u0000\u012c\u0000\u012e\u0000\u0130\u0000\u0132\u0000\u0134\u0000"+ - "\u0136\u0000\u0138\u0000\u013ad\u013ce\u013ef\u0140\u0000\u0142\u0000"+ - "\u0144\u0000\u0146\u0000\u0148\u0000\u014a\u0000\u014cg\u014eh\u0150i"+ - "\u0152\u0000\u0154j\u0156k\u0158l\u015am\u015c\u0000\u015e\u0000\u0160"+ - "n\u0162o\u0164p\u0166q\u0168\u0000\u016a\u0000\u016c\u0000\u016e\u0000"+ - "\u0170\u0000\u0172\u0000\u0174\u0000\u0176r\u0178s\u017at\u017c\u0000"+ - "\u017e\u0000\u0180\u0000\u0182\u0000\u0184u\u0186v\u0188w\u018a\u0000"+ - "\u018cx\u018e\u0000\u0190\u0000\u0192y\u0194\u0000\u0196\u0000\u0198\u0000"+ - "\u019a\u0000\u019c\u0000\u019ez\u01a0{\u01a2|\u01a4\u0000\u01a6\u0000"+ - "\u01a8\u0000\u01aa}\u01ac~\u01ae\u007f\u01b0\u0000\u01b2\u0000\u01b4\u0080"+ - "\u01b6\u0081\u01b8\u0082\u01ba\u0000\u01bc\u0000\u01be\u0000\u01c0\u0000"+ - "\u0010\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r"+ - "\u000e\u000f$\u0002\u0000DDdd\u0002\u0000IIii\u0002\u0000SSss\u0002\u0000"+ - "EEee\u0002\u0000CCcc\u0002\u0000TTtt\u0002\u0000RRrr\u0002\u0000OOoo\u0002"+ - "\u0000PPpp\u0002\u0000NNnn\u0002\u0000HHhh\u0002\u0000VVvv\u0002\u0000"+ - "AAaa\u0002\u0000LLll\u0002\u0000XXxx\u0002\u0000FFff\u0002\u0000MMmm\u0002"+ - "\u0000GGgg\u0002\u0000KKkk\u0002\u0000WWww\u0002\u0000UUuu\u0006\u0000"+ - "\t\n\r\r //[[]]\u0002\u0000\n\n\r\r\u0003\u0000\t\n\r\r \u0001\u0000"+ - "09\u0002\u0000AZaz\b\u0000\"\"NNRRTT\\\\nnrrtt\u0004\u0000\n\n\r\r\"\""+ - "\\\\\u0002\u0000++--\u0001\u0000``\u0002\u0000BBbb\u0002\u0000YYyy\u000b"+ - "\u0000\t\n\r\r \"\",,//::==[[]]||\u0002\u0000**//\u000b\u0000\t\n\r\r"+ - " \"#,,//::<<>?\\\\||\u0002\u0000JJjj\u066c\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\u0000"+ - "4\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\u0000@\u0001\u0000\u0000\u0000\u0000"+ - "B\u0001\u0000\u0000\u0000\u0000D\u0001\u0000\u0000\u0000\u0001F\u0001"+ - "\u0000\u0000\u0000\u0001\\\u0001\u0000\u0000\u0000\u0001^\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\u0001j\u0001\u0000\u0000\u0000\u0001l\u0001\u0000"+ - "\u0000\u0000\u0001n\u0001\u0000\u0000\u0000\u0001p\u0001\u0000\u0000\u0000"+ - "\u0001r\u0001\u0000\u0000\u0000\u0001t\u0001\u0000\u0000\u0000\u0001v"+ - "\u0001\u0000\u0000\u0000\u0001x\u0001\u0000\u0000\u0000\u0001z\u0001\u0000"+ - "\u0000\u0000\u0001|\u0001\u0000\u0000\u0000\u0001~\u0001\u0000\u0000\u0000"+ - "\u0001\u0080\u0001\u0000\u0000\u0000\u0001\u0082\u0001\u0000\u0000\u0000"+ - "\u0001\u0084\u0001\u0000\u0000\u0000\u0001\u0086\u0001\u0000\u0000\u0000"+ - "\u0001\u0088\u0001\u0000\u0000\u0000\u0001\u008a\u0001\u0000\u0000\u0000"+ - "\u0001\u008c\u0001\u0000\u0000\u0000\u0001\u008e\u0001\u0000\u0000\u0000"+ - "\u0001\u0090\u0001\u0000\u0000\u0000\u0001\u0092\u0001\u0000\u0000\u0000"+ - "\u0001\u0094\u0001\u0000\u0000\u0000\u0001\u0096\u0001\u0000\u0000\u0000"+ - "\u0001\u0098\u0001\u0000\u0000\u0000\u0001\u009a\u0001\u0000\u0000\u0000"+ - "\u0001\u009c\u0001\u0000\u0000\u0000\u0001\u009e\u0001\u0000\u0000\u0000"+ - "\u0001\u00a0\u0001\u0000\u0000\u0000\u0001\u00a2\u0001\u0000\u0000\u0000"+ - "\u0001\u00a4\u0001\u0000\u0000\u0000\u0001\u00a6\u0001\u0000\u0000\u0000"+ - "\u0001\u00a8\u0001\u0000\u0000\u0000\u0001\u00aa\u0001\u0000\u0000\u0000"+ - "\u0001\u00ac\u0001\u0000\u0000\u0000\u0001\u00ae\u0001\u0000\u0000\u0000"+ - "\u0001\u00b0\u0001\u0000\u0000\u0000\u0001\u00b2\u0001\u0000\u0000\u0000"+ - "\u0001\u00b4\u0001\u0000\u0000\u0000\u0001\u00b6\u0001\u0000\u0000\u0000"+ - "\u0001\u00ba\u0001\u0000\u0000\u0000\u0001\u00bc\u0001\u0000\u0000\u0000"+ - "\u0001\u00be\u0001\u0000\u0000\u0000\u0001\u00c0\u0001\u0000\u0000\u0000"+ - "\u0002\u00c2\u0001\u0000\u0000\u0000\u0002\u00c4\u0001\u0000\u0000\u0000"+ - "\u0002\u00c6\u0001\u0000\u0000\u0000\u0002\u00c8\u0001\u0000\u0000\u0000"+ - "\u0002\u00ca\u0001\u0000\u0000\u0000\u0003\u00cc\u0001\u0000\u0000\u0000"+ - "\u0003\u00ce\u0001\u0000\u0000\u0000\u0003\u00d0\u0001\u0000\u0000\u0000"+ - "\u0003\u00d2\u0001\u0000\u0000\u0000\u0003\u00d4\u0001\u0000\u0000\u0000"+ - "\u0003\u00d6\u0001\u0000\u0000\u0000\u0003\u00d8\u0001\u0000\u0000\u0000"+ - "\u0003\u00dc\u0001\u0000\u0000\u0000\u0003\u00de\u0001\u0000\u0000\u0000"+ - "\u0003\u00e0\u0001\u0000\u0000\u0000\u0003\u00e2\u0001\u0000\u0000\u0000"+ - "\u0003\u00e4\u0001\u0000\u0000\u0000\u0003\u00e6\u0001\u0000\u0000\u0000"+ - "\u0004\u00e8\u0001\u0000\u0000\u0000\u0004\u00ea\u0001\u0000\u0000\u0000"+ - "\u0004\u00ec\u0001\u0000\u0000\u0000\u0004\u00ee\u0001\u0000\u0000\u0000"+ - "\u0004\u00f0\u0001\u0000\u0000\u0000\u0004\u00f6\u0001\u0000\u0000\u0000"+ - "\u0004\u00f8\u0001\u0000\u0000\u0000\u0004\u00fa\u0001\u0000\u0000\u0000"+ - "\u0004\u00fc\u0001\u0000\u0000\u0000\u0005\u00fe\u0001\u0000\u0000\u0000"+ - "\u0005\u0100\u0001\u0000\u0000\u0000\u0005\u0102\u0001\u0000\u0000\u0000"+ - "\u0005\u0104\u0001\u0000\u0000\u0000\u0005\u0106\u0001\u0000\u0000\u0000"+ - "\u0005\u0108\u0001\u0000\u0000\u0000\u0005\u010a\u0001\u0000\u0000\u0000"+ - "\u0005\u010c\u0001\u0000\u0000\u0000\u0005\u010e\u0001\u0000\u0000\u0000"+ - "\u0005\u0110\u0001\u0000\u0000\u0000\u0005\u0112\u0001\u0000\u0000\u0000"+ - "\u0006\u0114\u0001\u0000\u0000\u0000\u0006\u0116\u0001\u0000\u0000\u0000"+ - "\u0006\u0118\u0001\u0000\u0000\u0000\u0006\u011a\u0001\u0000\u0000\u0000"+ - "\u0006\u011e\u0001\u0000\u0000\u0000\u0006\u0120\u0001\u0000\u0000\u0000"+ - "\u0006\u0122\u0001\u0000\u0000\u0000\u0006\u0124\u0001\u0000\u0000\u0000"+ - "\u0006\u0126\u0001\u0000\u0000\u0000\u0007\u0128\u0001\u0000\u0000\u0000"+ - "\u0007\u012a\u0001\u0000\u0000\u0000\u0007\u012c\u0001\u0000\u0000\u0000"+ - "\u0007\u012e\u0001\u0000\u0000\u0000\u0007\u0130\u0001\u0000\u0000\u0000"+ - "\u0007\u0132\u0001\u0000\u0000\u0000\u0007\u0134\u0001\u0000\u0000\u0000"+ - "\u0007\u0136\u0001\u0000\u0000\u0000\u0007\u0138\u0001\u0000\u0000\u0000"+ - "\u0007\u013a\u0001\u0000\u0000\u0000\u0007\u013c\u0001\u0000\u0000\u0000"+ - "\u0007\u013e\u0001\u0000\u0000\u0000\b\u0140\u0001\u0000\u0000\u0000\b"+ - "\u0142\u0001\u0000\u0000\u0000\b\u0144\u0001\u0000\u0000\u0000\b\u0146"+ - "\u0001\u0000\u0000\u0000\b\u0148\u0001\u0000\u0000\u0000\b\u014a\u0001"+ - "\u0000\u0000\u0000\b\u014c\u0001\u0000\u0000\u0000\b\u014e\u0001\u0000"+ - "\u0000\u0000\b\u0150\u0001\u0000\u0000\u0000\t\u0152\u0001\u0000\u0000"+ - "\u0000\t\u0154\u0001\u0000\u0000\u0000\t\u0156\u0001\u0000\u0000\u0000"+ - "\t\u0158\u0001\u0000\u0000\u0000\t\u015a\u0001\u0000\u0000\u0000\n\u015c"+ - "\u0001\u0000\u0000\u0000\n\u015e\u0001\u0000\u0000\u0000\n\u0160\u0001"+ - "\u0000\u0000\u0000\n\u0162\u0001\u0000\u0000\u0000\n\u0164\u0001\u0000"+ - "\u0000\u0000\n\u0166\u0001\u0000\u0000\u0000\u000b\u0168\u0001\u0000\u0000"+ - "\u0000\u000b\u016a\u0001\u0000\u0000\u0000\u000b\u016c\u0001\u0000\u0000"+ - "\u0000\u000b\u016e\u0001\u0000\u0000\u0000\u000b\u0170\u0001\u0000\u0000"+ - "\u0000\u000b\u0172\u0001\u0000\u0000\u0000\u000b\u0174\u0001\u0000\u0000"+ - "\u0000\u000b\u0176\u0001\u0000\u0000\u0000\u000b\u0178\u0001\u0000\u0000"+ - "\u0000\u000b\u017a\u0001\u0000\u0000\u0000\f\u017c\u0001\u0000\u0000\u0000"+ - "\f\u017e\u0001\u0000\u0000\u0000\f\u0180\u0001\u0000\u0000\u0000\f\u0182"+ - "\u0001\u0000\u0000\u0000\f\u0184\u0001\u0000\u0000\u0000\f\u0186\u0001"+ - "\u0000\u0000\u0000\f\u0188\u0001\u0000\u0000\u0000\r\u018a\u0001\u0000"+ - "\u0000\u0000\r\u018c\u0001\u0000\u0000\u0000\r\u018e\u0001\u0000\u0000"+ - "\u0000\r\u0190\u0001\u0000\u0000\u0000\r\u0192\u0001\u0000\u0000\u0000"+ - "\r\u0194\u0001\u0000\u0000\u0000\r\u0196\u0001\u0000\u0000\u0000\r\u0198"+ - "\u0001\u0000\u0000\u0000\r\u019a\u0001\u0000\u0000\u0000\r\u019c\u0001"+ - "\u0000\u0000\u0000\r\u019e\u0001\u0000\u0000\u0000\r\u01a0\u0001\u0000"+ - "\u0000\u0000\r\u01a2\u0001\u0000\u0000\u0000\u000e\u01a4\u0001\u0000\u0000"+ - "\u0000\u000e\u01a6\u0001\u0000\u0000\u0000\u000e\u01a8\u0001\u0000\u0000"+ - "\u0000\u000e\u01aa\u0001\u0000\u0000\u0000\u000e\u01ac\u0001\u0000\u0000"+ - "\u0000\u000e\u01ae\u0001\u0000\u0000\u0000\u000f\u01b0\u0001\u0000\u0000"+ - "\u0000\u000f\u01b2\u0001\u0000\u0000\u0000\u000f\u01b4\u0001\u0000\u0000"+ - "\u0000\u000f\u01b6\u0001\u0000\u0000\u0000\u000f\u01b8\u0001\u0000\u0000"+ - "\u0000\u000f\u01ba\u0001\u0000\u0000\u0000\u000f\u01bc\u0001\u0000\u0000"+ - "\u0000\u000f\u01be\u0001\u0000\u0000\u0000\u000f\u01c0\u0001\u0000\u0000"+ - "\u0000\u0010\u01c2\u0001\u0000\u0000\u0000\u0012\u01cc\u0001\u0000\u0000"+ - "\u0000\u0014\u01d3\u0001\u0000\u0000\u0000\u0016\u01dc\u0001\u0000\u0000"+ - "\u0000\u0018\u01e3\u0001\u0000\u0000\u0000\u001a\u01ed\u0001\u0000\u0000"+ - "\u0000\u001c\u01f4\u0001\u0000\u0000\u0000\u001e\u01fb\u0001\u0000\u0000"+ - "\u0000 \u0202\u0001\u0000\u0000\u0000\"\u020a\u0001\u0000\u0000\u0000"+ - "$\u0216\u0001\u0000\u0000\u0000&\u021f\u0001\u0000\u0000\u0000(\u0225"+ - "\u0001\u0000\u0000\u0000*\u022c\u0001\u0000\u0000\u0000,\u0233\u0001\u0000"+ - "\u0000\u0000.\u023b\u0001\u0000\u0000\u00000\u0243\u0001\u0000\u0000\u0000"+ - "2\u024c\u0001\u0000\u0000\u00004\u025b\u0001\u0000\u0000\u00006\u0267"+ - "\u0001\u0000\u0000\u00008\u0272\u0001\u0000\u0000\u0000:\u027a\u0001\u0000"+ - "\u0000\u0000<\u0282\u0001\u0000\u0000\u0000>\u028c\u0001\u0000\u0000\u0000"+ - "@\u0292\u0001\u0000\u0000\u0000B\u02a3\u0001\u0000\u0000\u0000D\u02b3"+ - "\u0001\u0000\u0000\u0000F\u02b9\u0001\u0000\u0000\u0000H\u02bd\u0001\u0000"+ - "\u0000\u0000J\u02bf\u0001\u0000\u0000\u0000L\u02c1\u0001\u0000\u0000\u0000"+ - "N\u02c4\u0001\u0000\u0000\u0000P\u02c6\u0001\u0000\u0000\u0000R\u02cf"+ - "\u0001\u0000\u0000\u0000T\u02d1\u0001\u0000\u0000\u0000V\u02d6\u0001\u0000"+ - "\u0000\u0000X\u02d8\u0001\u0000\u0000\u0000Z\u02dd\u0001\u0000\u0000\u0000"+ - "\\\u02fc\u0001\u0000\u0000\u0000^\u02ff\u0001\u0000\u0000\u0000`\u032d"+ - "\u0001\u0000\u0000\u0000b\u032f\u0001\u0000\u0000\u0000d\u0332\u0001\u0000"+ - "\u0000\u0000f\u0336\u0001\u0000\u0000\u0000h\u033a\u0001\u0000\u0000\u0000"+ - "j\u033c\u0001\u0000\u0000\u0000l\u033f\u0001\u0000\u0000\u0000n\u0341"+ - "\u0001\u0000\u0000\u0000p\u0343\u0001\u0000\u0000\u0000r\u0348\u0001\u0000"+ - "\u0000\u0000t\u034a\u0001\u0000\u0000\u0000v\u0350\u0001\u0000\u0000\u0000"+ - "x\u0356\u0001\u0000\u0000\u0000z\u0359\u0001\u0000\u0000\u0000|\u035c"+ - "\u0001\u0000\u0000\u0000~\u0361\u0001\u0000\u0000\u0000\u0080\u0366\u0001"+ - "\u0000\u0000\u0000\u0082\u0368\u0001\u0000\u0000\u0000\u0084\u036c\u0001"+ - "\u0000\u0000\u0000\u0086\u0371\u0001\u0000\u0000\u0000\u0088\u0377\u0001"+ - "\u0000\u0000\u0000\u008a\u037a\u0001\u0000\u0000\u0000\u008c\u037c\u0001"+ - "\u0000\u0000\u0000\u008e\u0382\u0001\u0000\u0000\u0000\u0090\u0384\u0001"+ - "\u0000\u0000\u0000\u0092\u0389\u0001\u0000\u0000\u0000\u0094\u038c\u0001"+ - "\u0000\u0000\u0000\u0096\u038f\u0001\u0000\u0000\u0000\u0098\u0392\u0001"+ - "\u0000\u0000\u0000\u009a\u0394\u0001\u0000\u0000\u0000\u009c\u0397\u0001"+ - "\u0000\u0000\u0000\u009e\u0399\u0001\u0000\u0000\u0000\u00a0\u039c\u0001"+ - "\u0000\u0000\u0000\u00a2\u039e\u0001\u0000\u0000\u0000\u00a4\u03a0\u0001"+ - "\u0000\u0000\u0000\u00a6\u03a2\u0001\u0000\u0000\u0000\u00a8\u03a4\u0001"+ - "\u0000\u0000\u0000\u00aa\u03a6\u0001\u0000\u0000\u0000\u00ac\u03a8\u0001"+ - "\u0000\u0000\u0000\u00ae\u03aa\u0001\u0000\u0000\u0000\u00b0\u03bf\u0001"+ - "\u0000\u0000\u0000\u00b2\u03c1\u0001\u0000\u0000\u0000\u00b4\u03c6\u0001"+ - "\u0000\u0000\u0000\u00b6\u03db\u0001\u0000\u0000\u0000\u00b8\u03dd\u0001"+ - "\u0000\u0000\u0000\u00ba\u03e5\u0001\u0000\u0000\u0000\u00bc\u03e7\u0001"+ - "\u0000\u0000\u0000\u00be\u03eb\u0001\u0000\u0000\u0000\u00c0\u03ef\u0001"+ - "\u0000\u0000\u0000\u00c2\u03f3\u0001\u0000\u0000\u0000\u00c4\u03f8\u0001"+ - "\u0000\u0000\u0000\u00c6\u03fd\u0001\u0000\u0000\u0000\u00c8\u0401\u0001"+ - "\u0000\u0000\u0000\u00ca\u0405\u0001\u0000\u0000\u0000\u00cc\u0409\u0001"+ - "\u0000\u0000\u0000\u00ce\u040e\u0001\u0000\u0000\u0000\u00d0\u0412\u0001"+ - "\u0000\u0000\u0000\u00d2\u0416\u0001\u0000\u0000\u0000\u00d4\u041a\u0001"+ - "\u0000\u0000\u0000\u00d6\u041e\u0001\u0000\u0000\u0000\u00d8\u0422\u0001"+ - "\u0000\u0000\u0000\u00da\u042e\u0001\u0000\u0000\u0000\u00dc\u0431\u0001"+ - "\u0000\u0000\u0000\u00de\u0435\u0001\u0000\u0000\u0000\u00e0\u0439\u0001"+ - "\u0000\u0000\u0000\u00e2\u043d\u0001\u0000\u0000\u0000\u00e4\u0441\u0001"+ - "\u0000\u0000\u0000\u00e6\u0445\u0001\u0000\u0000\u0000\u00e8\u0449\u0001"+ - "\u0000\u0000\u0000\u00ea\u044e\u0001\u0000\u0000\u0000\u00ec\u0452\u0001"+ - "\u0000\u0000\u0000\u00ee\u0456\u0001\u0000\u0000\u0000\u00f0\u045b\u0001"+ - "\u0000\u0000\u0000\u00f2\u0464\u0001\u0000\u0000\u0000\u00f4\u0479\u0001"+ - "\u0000\u0000\u0000\u00f6\u047d\u0001\u0000\u0000\u0000\u00f8\u0481\u0001"+ - "\u0000\u0000\u0000\u00fa\u0485\u0001\u0000\u0000\u0000\u00fc\u0489\u0001"+ - "\u0000\u0000\u0000\u00fe\u048d\u0001\u0000\u0000\u0000\u0100\u0492\u0001"+ - "\u0000\u0000\u0000\u0102\u0496\u0001\u0000\u0000\u0000\u0104\u049a\u0001"+ - "\u0000\u0000\u0000\u0106\u049e\u0001\u0000\u0000\u0000\u0108\u04a3\u0001"+ - "\u0000\u0000\u0000\u010a\u04a8\u0001\u0000\u0000\u0000\u010c\u04ab\u0001"+ - "\u0000\u0000\u0000\u010e\u04af\u0001\u0000\u0000\u0000\u0110\u04b3\u0001"+ - "\u0000\u0000\u0000\u0112\u04b7\u0001\u0000\u0000\u0000\u0114\u04bb\u0001"+ - "\u0000\u0000\u0000\u0116\u04c0\u0001\u0000\u0000\u0000\u0118\u04c5\u0001"+ - "\u0000\u0000\u0000\u011a\u04ca\u0001\u0000\u0000\u0000\u011c\u04d1\u0001"+ - "\u0000\u0000\u0000\u011e\u04da\u0001\u0000\u0000\u0000\u0120\u04e1\u0001"+ - "\u0000\u0000\u0000\u0122\u04e5\u0001\u0000\u0000\u0000\u0124\u04e9\u0001"+ - "\u0000\u0000\u0000\u0126\u04ed\u0001\u0000\u0000\u0000\u0128\u04f1\u0001"+ - "\u0000\u0000\u0000\u012a\u04f7\u0001\u0000\u0000\u0000\u012c\u04fb\u0001"+ - "\u0000\u0000\u0000\u012e\u04ff\u0001\u0000\u0000\u0000\u0130\u0503\u0001"+ - "\u0000\u0000\u0000\u0132\u0507\u0001\u0000\u0000\u0000\u0134\u050b\u0001"+ - "\u0000\u0000\u0000\u0136\u050f\u0001\u0000\u0000\u0000\u0138\u0514\u0001"+ - "\u0000\u0000\u0000\u013a\u0519\u0001\u0000\u0000\u0000\u013c\u051d\u0001"+ - "\u0000\u0000\u0000\u013e\u0521\u0001\u0000\u0000\u0000\u0140\u0525\u0001"+ - "\u0000\u0000\u0000\u0142\u052a\u0001\u0000\u0000\u0000\u0144\u052e\u0001"+ - "\u0000\u0000\u0000\u0146\u0533\u0001\u0000\u0000\u0000\u0148\u0538\u0001"+ - "\u0000\u0000\u0000\u014a\u053c\u0001\u0000\u0000\u0000\u014c\u0540\u0001"+ - "\u0000\u0000\u0000\u014e\u0544\u0001\u0000\u0000\u0000\u0150\u0548\u0001"+ - "\u0000\u0000\u0000\u0152\u054c\u0001\u0000\u0000\u0000\u0154\u0551\u0001"+ - "\u0000\u0000\u0000\u0156\u0556\u0001\u0000\u0000\u0000\u0158\u055a\u0001"+ - "\u0000\u0000\u0000\u015a\u055e\u0001\u0000\u0000\u0000\u015c\u0562\u0001"+ - "\u0000\u0000\u0000\u015e\u0567\u0001\u0000\u0000\u0000\u0160\u0570\u0001"+ - "\u0000\u0000\u0000\u0162\u0574\u0001\u0000\u0000\u0000\u0164\u0578\u0001"+ - "\u0000\u0000\u0000\u0166\u057c\u0001\u0000\u0000\u0000\u0168\u0580\u0001"+ - "\u0000\u0000\u0000\u016a\u0585\u0001\u0000\u0000\u0000\u016c\u0589\u0001"+ - "\u0000\u0000\u0000\u016e\u058d\u0001\u0000\u0000\u0000\u0170\u0591\u0001"+ - "\u0000\u0000\u0000\u0172\u0596\u0001\u0000\u0000\u0000\u0174\u059a\u0001"+ - "\u0000\u0000\u0000\u0176\u059e\u0001\u0000\u0000\u0000\u0178\u05a2\u0001"+ - "\u0000\u0000\u0000\u017a\u05a6\u0001\u0000\u0000\u0000\u017c\u05aa\u0001"+ - "\u0000\u0000\u0000\u017e\u05b0\u0001\u0000\u0000\u0000\u0180\u05b4\u0001"+ - "\u0000\u0000\u0000\u0182\u05b8\u0001\u0000\u0000\u0000\u0184\u05bc\u0001"+ - "\u0000\u0000\u0000\u0186\u05c0\u0001\u0000\u0000\u0000\u0188\u05c4\u0001"+ - "\u0000\u0000\u0000\u018a\u05c8\u0001\u0000\u0000\u0000\u018c\u05cd\u0001"+ - "\u0000\u0000\u0000\u018e\u05d2\u0001\u0000\u0000\u0000\u0190\u05d6\u0001"+ - "\u0000\u0000\u0000\u0192\u05dc\u0001\u0000\u0000\u0000\u0194\u05e5\u0001"+ - "\u0000\u0000\u0000\u0196\u05e9\u0001\u0000\u0000\u0000\u0198\u05ed\u0001"+ - "\u0000\u0000\u0000\u019a\u05f1\u0001\u0000\u0000\u0000\u019c\u05f5\u0001"+ - "\u0000\u0000\u0000\u019e\u05f9\u0001\u0000\u0000\u0000\u01a0\u05fd\u0001"+ - "\u0000\u0000\u0000\u01a2\u0601\u0001\u0000\u0000\u0000\u01a4\u0605\u0001"+ - "\u0000\u0000\u0000\u01a6\u060a\u0001\u0000\u0000\u0000\u01a8\u0610\u0001"+ - "\u0000\u0000\u0000\u01aa\u0616\u0001\u0000\u0000\u0000\u01ac\u061a\u0001"+ - "\u0000\u0000\u0000\u01ae\u061e\u0001\u0000\u0000\u0000\u01b0\u0622\u0001"+ - "\u0000\u0000\u0000\u01b2\u0628\u0001\u0000\u0000\u0000\u01b4\u062e\u0001"+ - "\u0000\u0000\u0000\u01b6\u0632\u0001\u0000\u0000\u0000\u01b8\u0636\u0001"+ - "\u0000\u0000\u0000\u01ba\u063a\u0001\u0000\u0000\u0000\u01bc\u0640\u0001"+ - "\u0000\u0000\u0000\u01be\u0646\u0001\u0000\u0000\u0000\u01c0\u064c\u0001"+ - "\u0000\u0000\u0000\u01c2\u01c3\u0007\u0000\u0000\u0000\u01c3\u01c4\u0007"+ - "\u0001\u0000\u0000\u01c4\u01c5\u0007\u0002\u0000\u0000\u01c5\u01c6\u0007"+ - "\u0002\u0000\u0000\u01c6\u01c7\u0007\u0003\u0000\u0000\u01c7\u01c8\u0007"+ - "\u0004\u0000\u0000\u01c8\u01c9\u0007\u0005\u0000\u0000\u01c9\u01ca\u0001"+ - "\u0000\u0000\u0000\u01ca\u01cb\u0006\u0000\u0000\u0000\u01cb\u0011\u0001"+ - "\u0000\u0000\u0000\u01cc\u01cd\u0007\u0000\u0000\u0000\u01cd\u01ce\u0007"+ - "\u0006\u0000\u0000\u01ce\u01cf\u0007\u0007\u0000\u0000\u01cf\u01d0\u0007"+ - "\b\u0000\u0000\u01d0\u01d1\u0001\u0000\u0000\u0000\u01d1\u01d2\u0006\u0001"+ - "\u0001\u0000\u01d2\u0013\u0001\u0000\u0000\u0000\u01d3\u01d4\u0007\u0003"+ - "\u0000\u0000\u01d4\u01d5\u0007\t\u0000\u0000\u01d5\u01d6\u0007\u0006\u0000"+ - "\u0000\u01d6\u01d7\u0007\u0001\u0000\u0000\u01d7\u01d8\u0007\u0004\u0000"+ - "\u0000\u01d8\u01d9\u0007\n\u0000\u0000\u01d9\u01da\u0001\u0000\u0000\u0000"+ - "\u01da\u01db\u0006\u0002\u0002\u0000\u01db\u0015\u0001\u0000\u0000\u0000"+ - "\u01dc\u01dd\u0007\u0003\u0000\u0000\u01dd\u01de\u0007\u000b\u0000\u0000"+ - "\u01de\u01df\u0007\f\u0000\u0000\u01df\u01e0\u0007\r\u0000\u0000\u01e0"+ - "\u01e1\u0001\u0000\u0000\u0000\u01e1\u01e2\u0006\u0003\u0000\u0000\u01e2"+ - "\u0017\u0001\u0000\u0000\u0000\u01e3\u01e4\u0007\u0003\u0000\u0000\u01e4"+ - "\u01e5\u0007\u000e\u0000\u0000\u01e5\u01e6\u0007\b\u0000\u0000\u01e6\u01e7"+ - "\u0007\r\u0000\u0000\u01e7\u01e8\u0007\f\u0000\u0000\u01e8\u01e9\u0007"+ - "\u0001\u0000\u0000\u01e9\u01ea\u0007\t\u0000\u0000\u01ea\u01eb\u0001\u0000"+ - "\u0000\u0000\u01eb\u01ec\u0006\u0004\u0003\u0000\u01ec\u0019\u0001\u0000"+ - "\u0000\u0000\u01ed\u01ee\u0007\u000f\u0000\u0000\u01ee\u01ef\u0007\u0006"+ - "\u0000\u0000\u01ef\u01f0\u0007\u0007\u0000\u0000\u01f0\u01f1\u0007\u0010"+ - "\u0000\u0000\u01f1\u01f2\u0001\u0000\u0000\u0000\u01f2\u01f3\u0006\u0005"+ - "\u0004\u0000\u01f3\u001b\u0001\u0000\u0000\u0000\u01f4\u01f5\u0007\u0011"+ - "\u0000\u0000\u01f5\u01f6\u0007\u0006\u0000\u0000\u01f6\u01f7\u0007\u0007"+ - "\u0000\u0000\u01f7\u01f8\u0007\u0012\u0000\u0000\u01f8\u01f9\u0001\u0000"+ - "\u0000\u0000\u01f9\u01fa\u0006\u0006\u0000\u0000\u01fa\u001d\u0001\u0000"+ - "\u0000\u0000\u01fb\u01fc\u0007\u0012\u0000\u0000\u01fc\u01fd\u0007\u0003"+ - "\u0000\u0000\u01fd\u01fe\u0007\u0003\u0000\u0000\u01fe\u01ff\u0007\b\u0000"+ - "\u0000\u01ff\u0200\u0001\u0000\u0000\u0000\u0200\u0201\u0006\u0007\u0001"+ - "\u0000\u0201\u001f\u0001\u0000\u0000\u0000\u0202\u0203\u0007\r\u0000\u0000"+ - "\u0203\u0204\u0007\u0001\u0000\u0000\u0204\u0205\u0007\u0010\u0000\u0000"+ - "\u0205\u0206\u0007\u0001\u0000\u0000\u0206\u0207\u0007\u0005\u0000\u0000"+ - "\u0207\u0208\u0001\u0000\u0000\u0000\u0208\u0209\u0006\b\u0000\u0000\u0209"+ - "!\u0001\u0000\u0000\u0000\u020a\u020b\u0007\u0010\u0000\u0000\u020b\u020c"+ - "\u0007\u000b\u0000\u0000\u020c\u020d\u0005_\u0000\u0000\u020d\u020e\u0007"+ - "\u0003\u0000\u0000\u020e\u020f\u0007\u000e\u0000\u0000\u020f\u0210\u0007"+ - "\b\u0000\u0000\u0210\u0211\u0007\f\u0000\u0000\u0211\u0212\u0007\t\u0000"+ - "\u0000\u0212\u0213\u0007\u0000\u0000\u0000\u0213\u0214\u0001\u0000\u0000"+ - "\u0000\u0214\u0215\u0006\t\u0005\u0000\u0215#\u0001\u0000\u0000\u0000"+ - "\u0216\u0217\u0007\u0006\u0000\u0000\u0217\u0218\u0007\u0003\u0000\u0000"+ - "\u0218\u0219\u0007\t\u0000\u0000\u0219\u021a\u0007\f\u0000\u0000\u021a"+ - "\u021b\u0007\u0010\u0000\u0000\u021b\u021c\u0007\u0003\u0000\u0000\u021c"+ - "\u021d\u0001\u0000\u0000\u0000\u021d\u021e\u0006\n\u0006\u0000\u021e%"+ - "\u0001\u0000\u0000\u0000\u021f\u0220\u0007\u0006\u0000\u0000\u0220\u0221"+ - "\u0007\u0007\u0000\u0000\u0221\u0222\u0007\u0013\u0000\u0000\u0222\u0223"+ - "\u0001\u0000\u0000\u0000\u0223\u0224\u0006\u000b\u0000\u0000\u0224\'\u0001"+ - "\u0000\u0000\u0000\u0225\u0226\u0007\u0002\u0000\u0000\u0226\u0227\u0007"+ - "\n\u0000\u0000\u0227\u0228\u0007\u0007\u0000\u0000\u0228\u0229\u0007\u0013"+ - "\u0000\u0000\u0229\u022a\u0001\u0000\u0000\u0000\u022a\u022b\u0006\f\u0007"+ - "\u0000\u022b)\u0001\u0000\u0000\u0000\u022c\u022d\u0007\u0002\u0000\u0000"+ - "\u022d\u022e\u0007\u0007\u0000\u0000\u022e\u022f\u0007\u0006\u0000\u0000"+ - "\u022f\u0230\u0007\u0005\u0000\u0000\u0230\u0231\u0001\u0000\u0000\u0000"+ - "\u0231\u0232\u0006\r\u0000\u0000\u0232+\u0001\u0000\u0000\u0000\u0233"+ - "\u0234\u0007\u0002\u0000\u0000\u0234\u0235\u0007\u0005\u0000\u0000\u0235"+ - "\u0236\u0007\f\u0000\u0000\u0236\u0237\u0007\u0005\u0000\u0000\u0237\u0238"+ - "\u0007\u0002\u0000\u0000\u0238\u0239\u0001\u0000\u0000\u0000\u0239\u023a"+ - "\u0006\u000e\u0000\u0000\u023a-\u0001\u0000\u0000\u0000\u023b\u023c\u0007"+ - "\u0013\u0000\u0000\u023c\u023d\u0007\n\u0000\u0000\u023d\u023e\u0007\u0003"+ - "\u0000\u0000\u023e\u023f\u0007\u0006\u0000\u0000\u023f\u0240\u0007\u0003"+ - "\u0000\u0000\u0240\u0241\u0001\u0000\u0000\u0000\u0241\u0242\u0006\u000f"+ - "\u0000\u0000\u0242/\u0001\u0000\u0000\u0000\u0243\u0244\u0007\r\u0000"+ - "\u0000\u0244\u0245\u0007\u0007\u0000\u0000\u0245\u0246\u0007\u0007\u0000"+ - "\u0000\u0246\u0247\u0007\u0012\u0000\u0000\u0247\u0248\u0007\u0014\u0000"+ - "\u0000\u0248\u0249\u0007\b\u0000\u0000\u0249\u024a\u0001\u0000\u0000\u0000"+ - "\u024a\u024b\u0006\u0010\b\u0000\u024b1\u0001\u0000\u0000\u0000\u024c"+ - "\u024d\u0004\u0011\u0000\u0000\u024d\u024e\u0007\u0001\u0000\u0000\u024e"+ - "\u024f\u0007\t\u0000\u0000\u024f\u0250\u0007\r\u0000\u0000\u0250\u0251"+ - "\u0007\u0001\u0000\u0000\u0251\u0252\u0007\t\u0000\u0000\u0252\u0253\u0007"+ - "\u0003\u0000\u0000\u0253\u0254\u0007\u0002\u0000\u0000\u0254\u0255\u0007"+ - "\u0005\u0000\u0000\u0255\u0256\u0007\f\u0000\u0000\u0256\u0257\u0007\u0005"+ - "\u0000\u0000\u0257\u0258\u0007\u0002\u0000\u0000\u0258\u0259\u0001\u0000"+ - "\u0000\u0000\u0259\u025a\u0006\u0011\u0000\u0000\u025a3\u0001\u0000\u0000"+ - "\u0000\u025b\u025c\u0004\u0012\u0001\u0000\u025c\u025d\u0007\r\u0000\u0000"+ - "\u025d\u025e\u0007\u0007\u0000\u0000\u025e\u025f\u0007\u0007\u0000\u0000"+ - "\u025f\u0260\u0007\u0012\u0000\u0000\u0260\u0261\u0007\u0014\u0000\u0000"+ - "\u0261\u0262\u0007\b\u0000\u0000\u0262\u0263\u0005_\u0000\u0000\u0263"+ - "\u0264\u0005\u8001\uf414\u0000\u0000\u0264\u0265\u0001\u0000\u0000\u0000"+ - "\u0265\u0266\u0006\u0012\t\u0000\u02665\u0001\u0000\u0000\u0000\u0267"+ - "\u0268\u0004\u0013\u0002\u0000\u0268\u0269\u0007\u0010\u0000\u0000\u0269"+ - "\u026a\u0007\u0003\u0000\u0000\u026a\u026b\u0007\u0005\u0000\u0000\u026b"+ - "\u026c\u0007\u0006\u0000\u0000\u026c\u026d\u0007\u0001\u0000\u0000\u026d"+ - "\u026e\u0007\u0004\u0000\u0000\u026e\u026f\u0007\u0002\u0000\u0000\u026f"+ - "\u0270\u0001\u0000\u0000\u0000\u0270\u0271\u0006\u0013\n\u0000\u02717"+ - "\u0001\u0000\u0000\u0000\u0272\u0273\u0004\u0014\u0003\u0000\u0273\u0274"+ - "\u0007\u000f\u0000\u0000\u0274\u0275\u0007\u0014\u0000\u0000\u0275\u0276"+ - "\u0007\r\u0000\u0000\u0276\u0277\u0007\r\u0000\u0000\u0277\u0278\u0001"+ - "\u0000\u0000\u0000\u0278\u0279\u0006\u0014\b\u0000\u02799\u0001\u0000"+ - "\u0000\u0000\u027a\u027b\u0004\u0015\u0004\u0000\u027b\u027c\u0007\r\u0000"+ - "\u0000\u027c\u027d\u0007\u0003\u0000\u0000\u027d\u027e\u0007\u000f\u0000"+ - "\u0000\u027e\u027f\u0007\u0005\u0000\u0000\u027f\u0280\u0001\u0000\u0000"+ - "\u0000\u0280\u0281\u0006\u0015\b\u0000\u0281;\u0001\u0000\u0000\u0000"+ - "\u0282\u0283\u0004\u0016\u0005\u0000\u0283\u0284\u0007\u0006\u0000\u0000"+ - "\u0284\u0285\u0007\u0001\u0000\u0000\u0285\u0286\u0007\u0011\u0000\u0000"+ - "\u0286\u0287\u0007\n\u0000\u0000\u0287\u0288\u0007\u0005\u0000\u0000\u0288"+ - "\u0289\u0001\u0000\u0000\u0000\u0289\u028a\u0006\u0016\b\u0000\u028a="+ - "\u0001\u0000\u0000\u0000\u028b\u028d\b\u0015\u0000\u0000\u028c\u028b\u0001"+ - "\u0000\u0000\u0000\u028d\u028e\u0001\u0000\u0000\u0000\u028e\u028c\u0001"+ - "\u0000\u0000\u0000\u028e\u028f\u0001\u0000\u0000\u0000\u028f\u0290\u0001"+ - "\u0000\u0000\u0000\u0290\u0291\u0006\u0017\u0000\u0000\u0291?\u0001\u0000"+ - "\u0000\u0000\u0292\u0293\u0005/\u0000\u0000\u0293\u0294\u0005/\u0000\u0000"+ - "\u0294\u0298\u0001\u0000\u0000\u0000\u0295\u0297\b\u0016\u0000\u0000\u0296"+ - "\u0295\u0001\u0000\u0000\u0000\u0297\u029a\u0001\u0000\u0000\u0000\u0298"+ - "\u0296\u0001\u0000\u0000\u0000\u0298\u0299\u0001\u0000\u0000\u0000\u0299"+ - "\u029c\u0001\u0000\u0000\u0000\u029a\u0298\u0001\u0000\u0000\u0000\u029b"+ - "\u029d\u0005\r\u0000\u0000\u029c\u029b\u0001\u0000\u0000\u0000\u029c\u029d"+ - "\u0001\u0000\u0000\u0000\u029d\u029f\u0001\u0000\u0000\u0000\u029e\u02a0"+ - "\u0005\n\u0000\u0000\u029f\u029e\u0001\u0000\u0000\u0000\u029f\u02a0\u0001"+ - "\u0000\u0000\u0000\u02a0\u02a1\u0001\u0000\u0000\u0000\u02a1\u02a2\u0006"+ - "\u0018\u000b\u0000\u02a2A\u0001\u0000\u0000\u0000\u02a3\u02a4\u0005/\u0000"+ - "\u0000\u02a4\u02a5\u0005*\u0000\u0000\u02a5\u02aa\u0001\u0000\u0000\u0000"+ - "\u02a6\u02a9\u0003B\u0019\u0000\u02a7\u02a9\t\u0000\u0000\u0000\u02a8"+ - "\u02a6\u0001\u0000\u0000\u0000\u02a8\u02a7\u0001\u0000\u0000\u0000\u02a9"+ - "\u02ac\u0001\u0000\u0000\u0000\u02aa\u02ab\u0001\u0000\u0000\u0000\u02aa"+ - "\u02a8\u0001\u0000\u0000\u0000\u02ab\u02ad\u0001\u0000\u0000\u0000\u02ac"+ - "\u02aa\u0001\u0000\u0000\u0000\u02ad\u02ae\u0005*\u0000\u0000\u02ae\u02af"+ - "\u0005/\u0000\u0000\u02af\u02b0\u0001\u0000\u0000\u0000\u02b0\u02b1\u0006"+ - "\u0019\u000b\u0000\u02b1C\u0001\u0000\u0000\u0000\u02b2\u02b4\u0007\u0017"+ - "\u0000\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\u02b7\u0001\u0000\u0000\u0000\u02b7\u02b8\u0006\u001a"+ - "\u000b\u0000\u02b8E\u0001\u0000\u0000\u0000\u02b9\u02ba\u0005|\u0000\u0000"+ - "\u02ba\u02bb\u0001\u0000\u0000\u0000\u02bb\u02bc\u0006\u001b\f\u0000\u02bc"+ - "G\u0001\u0000\u0000\u0000\u02bd\u02be\u0007\u0018\u0000\u0000\u02beI\u0001"+ - "\u0000\u0000\u0000\u02bf\u02c0\u0007\u0019\u0000\u0000\u02c0K\u0001\u0000"+ - "\u0000\u0000\u02c1\u02c2\u0005\\\u0000\u0000\u02c2\u02c3\u0007\u001a\u0000"+ - "\u0000\u02c3M\u0001\u0000\u0000\u0000\u02c4\u02c5\b\u001b\u0000\u0000"+ - "\u02c5O\u0001\u0000\u0000\u0000\u02c6\u02c8\u0007\u0003\u0000\u0000\u02c7"+ - "\u02c9\u0007\u001c\u0000\u0000\u02c8\u02c7\u0001\u0000\u0000\u0000\u02c8"+ - "\u02c9\u0001\u0000\u0000\u0000\u02c9\u02cb\u0001\u0000\u0000\u0000\u02ca"+ - "\u02cc\u0003H\u001c\u0000\u02cb\u02ca\u0001\u0000\u0000\u0000\u02cc\u02cd"+ - "\u0001\u0000\u0000\u0000\u02cd\u02cb\u0001\u0000\u0000\u0000\u02cd\u02ce"+ - "\u0001\u0000\u0000\u0000\u02ceQ\u0001\u0000\u0000\u0000\u02cf\u02d0\u0005"+ - "@\u0000\u0000\u02d0S\u0001\u0000\u0000\u0000\u02d1\u02d2\u0005`\u0000"+ - "\u0000\u02d2U\u0001\u0000\u0000\u0000\u02d3\u02d7\b\u001d\u0000\u0000"+ - "\u02d4\u02d5\u0005`\u0000\u0000\u02d5\u02d7\u0005`\u0000\u0000\u02d6\u02d3"+ - "\u0001\u0000\u0000\u0000\u02d6\u02d4\u0001\u0000\u0000\u0000\u02d7W\u0001"+ - "\u0000\u0000\u0000\u02d8\u02d9\u0005_\u0000\u0000\u02d9Y\u0001\u0000\u0000"+ - "\u0000\u02da\u02de\u0003J\u001d\u0000\u02db\u02de\u0003H\u001c\u0000\u02dc"+ - "\u02de\u0003X$\u0000\u02dd\u02da\u0001\u0000\u0000\u0000\u02dd\u02db\u0001"+ - "\u0000\u0000\u0000\u02dd\u02dc\u0001\u0000\u0000\u0000\u02de[\u0001\u0000"+ - "\u0000\u0000\u02df\u02e4\u0005\"\u0000\u0000\u02e0\u02e3\u0003L\u001e"+ - "\u0000\u02e1\u02e3\u0003N\u001f\u0000\u02e2\u02e0\u0001\u0000\u0000\u0000"+ - "\u02e2\u02e1\u0001\u0000\u0000\u0000\u02e3\u02e6\u0001\u0000\u0000\u0000"+ - "\u02e4\u02e2\u0001\u0000\u0000\u0000\u02e4\u02e5\u0001\u0000\u0000\u0000"+ - "\u02e5\u02e7\u0001\u0000\u0000\u0000\u02e6\u02e4\u0001\u0000\u0000\u0000"+ - "\u02e7\u02fd\u0005\"\u0000\u0000\u02e8\u02e9\u0005\"\u0000\u0000\u02e9"+ - "\u02ea\u0005\"\u0000\u0000\u02ea\u02eb\u0005\"\u0000\u0000\u02eb\u02ef"+ - "\u0001\u0000\u0000\u0000\u02ec\u02ee\b\u0016\u0000\u0000\u02ed\u02ec\u0001"+ - "\u0000\u0000\u0000\u02ee\u02f1\u0001\u0000\u0000\u0000\u02ef\u02f0\u0001"+ - "\u0000\u0000\u0000\u02ef\u02ed\u0001\u0000\u0000\u0000\u02f0\u02f2\u0001"+ - "\u0000\u0000\u0000\u02f1\u02ef\u0001\u0000\u0000\u0000\u02f2\u02f3\u0005"+ - "\"\u0000\u0000\u02f3\u02f4\u0005\"\u0000\u0000\u02f4\u02f5\u0005\"\u0000"+ - "\u0000\u02f5\u02f7\u0001\u0000\u0000\u0000\u02f6\u02f8\u0005\"\u0000\u0000"+ - "\u02f7\u02f6\u0001\u0000\u0000\u0000\u02f7\u02f8\u0001\u0000\u0000\u0000"+ - "\u02f8\u02fa\u0001\u0000\u0000\u0000\u02f9\u02fb\u0005\"\u0000\u0000\u02fa"+ - "\u02f9\u0001\u0000\u0000\u0000\u02fa\u02fb\u0001\u0000\u0000\u0000\u02fb"+ - "\u02fd\u0001\u0000\u0000\u0000\u02fc\u02df\u0001\u0000\u0000\u0000\u02fc"+ - "\u02e8\u0001\u0000\u0000\u0000\u02fd]\u0001\u0000\u0000\u0000\u02fe\u0300"+ - "\u0003H\u001c\u0000\u02ff\u02fe\u0001\u0000\u0000\u0000\u0300\u0301\u0001"+ - "\u0000\u0000\u0000\u0301\u02ff\u0001\u0000\u0000\u0000\u0301\u0302\u0001"+ - "\u0000\u0000\u0000\u0302_\u0001\u0000\u0000\u0000\u0303\u0305\u0003H\u001c"+ - "\u0000\u0304\u0303\u0001\u0000\u0000\u0000\u0305\u0306\u0001\u0000\u0000"+ - "\u0000\u0306\u0304\u0001\u0000\u0000\u0000\u0306\u0307\u0001\u0000\u0000"+ - "\u0000\u0307\u0308\u0001\u0000\u0000\u0000\u0308\u030c\u0003r1\u0000\u0309"+ - "\u030b\u0003H\u001c\u0000\u030a\u0309\u0001\u0000\u0000\u0000\u030b\u030e"+ - "\u0001\u0000\u0000\u0000\u030c\u030a\u0001\u0000\u0000\u0000\u030c\u030d"+ - "\u0001\u0000\u0000\u0000\u030d\u032e\u0001\u0000\u0000\u0000\u030e\u030c"+ - "\u0001\u0000\u0000\u0000\u030f\u0311\u0003r1\u0000\u0310\u0312\u0003H"+ - "\u001c\u0000\u0311\u0310\u0001\u0000\u0000\u0000\u0312\u0313\u0001\u0000"+ - "\u0000\u0000\u0313\u0311\u0001\u0000\u0000\u0000\u0313\u0314\u0001\u0000"+ - "\u0000\u0000\u0314\u032e\u0001\u0000\u0000\u0000\u0315\u0317\u0003H\u001c"+ - "\u0000\u0316\u0315\u0001\u0000\u0000\u0000\u0317\u0318\u0001\u0000\u0000"+ - "\u0000\u0318\u0316\u0001\u0000\u0000\u0000\u0318\u0319\u0001\u0000\u0000"+ - "\u0000\u0319\u0321\u0001\u0000\u0000\u0000\u031a\u031e\u0003r1\u0000\u031b"+ - "\u031d\u0003H\u001c\u0000\u031c\u031b\u0001\u0000\u0000\u0000\u031d\u0320"+ - "\u0001\u0000\u0000\u0000\u031e\u031c\u0001\u0000\u0000\u0000\u031e\u031f"+ - "\u0001\u0000\u0000\u0000\u031f\u0322\u0001\u0000\u0000\u0000\u0320\u031e"+ - "\u0001\u0000\u0000\u0000\u0321\u031a\u0001\u0000\u0000\u0000\u0321\u0322"+ - "\u0001\u0000\u0000\u0000\u0322\u0323\u0001\u0000\u0000\u0000\u0323\u0324"+ - "\u0003P \u0000\u0324\u032e\u0001\u0000\u0000\u0000\u0325\u0327\u0003r"+ - "1\u0000\u0326\u0328\u0003H\u001c\u0000\u0327\u0326\u0001\u0000\u0000\u0000"+ - "\u0328\u0329\u0001\u0000\u0000\u0000\u0329\u0327\u0001\u0000\u0000\u0000"+ - "\u0329\u032a\u0001\u0000\u0000\u0000\u032a\u032b\u0001\u0000\u0000\u0000"+ - "\u032b\u032c\u0003P \u0000\u032c\u032e\u0001\u0000\u0000\u0000\u032d\u0304"+ - "\u0001\u0000\u0000\u0000\u032d\u030f\u0001\u0000\u0000\u0000\u032d\u0316"+ - "\u0001\u0000\u0000\u0000\u032d\u0325\u0001\u0000\u0000\u0000\u032ea\u0001"+ - "\u0000\u0000\u0000\u032f\u0330\u0007\u001e\u0000\u0000\u0330\u0331\u0007"+ - "\u001f\u0000\u0000\u0331c\u0001\u0000\u0000\u0000\u0332\u0333\u0007\f"+ - "\u0000\u0000\u0333\u0334\u0007\t\u0000\u0000\u0334\u0335\u0007\u0000\u0000"+ - "\u0000\u0335e\u0001\u0000\u0000\u0000\u0336\u0337\u0007\f\u0000\u0000"+ - "\u0337\u0338\u0007\u0002\u0000\u0000\u0338\u0339\u0007\u0004\u0000\u0000"+ - "\u0339g\u0001\u0000\u0000\u0000\u033a\u033b\u0005=\u0000\u0000\u033bi"+ - "\u0001\u0000\u0000\u0000\u033c\u033d\u0005:\u0000\u0000\u033d\u033e\u0005"+ - ":\u0000\u0000\u033ek\u0001\u0000\u0000\u0000\u033f\u0340\u0005:\u0000"+ - "\u0000\u0340m\u0001\u0000\u0000\u0000\u0341\u0342\u0005,\u0000\u0000\u0342"+ - "o\u0001\u0000\u0000\u0000\u0343\u0344\u0007\u0000\u0000\u0000\u0344\u0345"+ - "\u0007\u0003\u0000\u0000\u0345\u0346\u0007\u0002\u0000\u0000\u0346\u0347"+ - "\u0007\u0004\u0000\u0000\u0347q\u0001\u0000\u0000\u0000\u0348\u0349\u0005"+ - ".\u0000\u0000\u0349s\u0001\u0000\u0000\u0000\u034a\u034b\u0007\u000f\u0000"+ - "\u0000\u034b\u034c\u0007\f\u0000\u0000\u034c\u034d\u0007\r\u0000\u0000"+ - "\u034d\u034e\u0007\u0002\u0000\u0000\u034e\u034f\u0007\u0003\u0000\u0000"+ - "\u034fu\u0001\u0000\u0000\u0000\u0350\u0351\u0007\u000f\u0000\u0000\u0351"+ - "\u0352\u0007\u0001\u0000\u0000\u0352\u0353\u0007\u0006\u0000\u0000\u0353"+ - "\u0354\u0007\u0002\u0000\u0000\u0354\u0355\u0007\u0005\u0000\u0000\u0355"+ - "w\u0001\u0000\u0000\u0000\u0356\u0357\u0007\u0001\u0000\u0000\u0357\u0358"+ - "\u0007\t\u0000\u0000\u0358y\u0001\u0000\u0000\u0000\u0359\u035a\u0007"+ - "\u0001\u0000\u0000\u035a\u035b\u0007\u0002\u0000\u0000\u035b{\u0001\u0000"+ - "\u0000\u0000\u035c\u035d\u0007\r\u0000\u0000\u035d\u035e\u0007\f\u0000"+ - "\u0000\u035e\u035f\u0007\u0002\u0000\u0000\u035f\u0360\u0007\u0005\u0000"+ - "\u0000\u0360}\u0001\u0000\u0000\u0000\u0361\u0362\u0007\r\u0000\u0000"+ - "\u0362\u0363\u0007\u0001\u0000\u0000\u0363\u0364\u0007\u0012\u0000\u0000"+ - "\u0364\u0365\u0007\u0003\u0000\u0000\u0365\u007f\u0001\u0000\u0000\u0000"+ - "\u0366\u0367\u0005(\u0000\u0000\u0367\u0081\u0001\u0000\u0000\u0000\u0368"+ - "\u0369\u0007\t\u0000\u0000\u0369\u036a\u0007\u0007\u0000\u0000\u036a\u036b"+ - "\u0007\u0005\u0000\u0000\u036b\u0083\u0001\u0000\u0000\u0000\u036c\u036d"+ - "\u0007\t\u0000\u0000\u036d\u036e\u0007\u0014\u0000\u0000\u036e\u036f\u0007"+ - "\r\u0000\u0000\u036f\u0370\u0007\r\u0000\u0000\u0370\u0085\u0001\u0000"+ - "\u0000\u0000\u0371\u0372\u0007\t\u0000\u0000\u0372\u0373\u0007\u0014\u0000"+ - "\u0000\u0373\u0374\u0007\r\u0000\u0000\u0374\u0375\u0007\r\u0000\u0000"+ - "\u0375\u0376\u0007\u0002\u0000\u0000\u0376\u0087\u0001\u0000\u0000\u0000"+ - "\u0377\u0378\u0007\u0007\u0000\u0000\u0378\u0379\u0007\u0006\u0000\u0000"+ - "\u0379\u0089\u0001\u0000\u0000\u0000\u037a\u037b\u0005?\u0000\u0000\u037b"+ - "\u008b\u0001\u0000\u0000\u0000\u037c\u037d\u0007\u0006\u0000\u0000\u037d"+ - "\u037e\u0007\r\u0000\u0000\u037e\u037f\u0007\u0001\u0000\u0000\u037f\u0380"+ - "\u0007\u0012\u0000\u0000\u0380\u0381\u0007\u0003\u0000\u0000\u0381\u008d"+ - "\u0001\u0000\u0000\u0000\u0382\u0383\u0005)\u0000\u0000\u0383\u008f\u0001"+ - "\u0000\u0000\u0000\u0384\u0385\u0007\u0005\u0000\u0000\u0385\u0386\u0007"+ - "\u0006\u0000\u0000\u0386\u0387\u0007\u0014\u0000\u0000\u0387\u0388\u0007"+ - "\u0003\u0000\u0000\u0388\u0091\u0001\u0000\u0000\u0000\u0389\u038a\u0005"+ - "=\u0000\u0000\u038a\u038b\u0005=\u0000\u0000\u038b\u0093\u0001\u0000\u0000"+ - "\u0000\u038c\u038d\u0005=\u0000\u0000\u038d\u038e\u0005~\u0000\u0000\u038e"+ - "\u0095\u0001\u0000\u0000\u0000\u038f\u0390\u0005!\u0000\u0000\u0390\u0391"+ - "\u0005=\u0000\u0000\u0391\u0097\u0001\u0000\u0000\u0000\u0392\u0393\u0005"+ - "<\u0000\u0000\u0393\u0099\u0001\u0000\u0000\u0000\u0394\u0395\u0005<\u0000"+ - "\u0000\u0395\u0396\u0005=\u0000\u0000\u0396\u009b\u0001\u0000\u0000\u0000"+ - "\u0397\u0398\u0005>\u0000\u0000\u0398\u009d\u0001\u0000\u0000\u0000\u0399"+ - "\u039a\u0005>\u0000\u0000\u039a\u039b\u0005=\u0000\u0000\u039b\u009f\u0001"+ - "\u0000\u0000\u0000\u039c\u039d\u0005+\u0000\u0000\u039d\u00a1\u0001\u0000"+ - "\u0000\u0000\u039e\u039f\u0005-\u0000\u0000\u039f\u00a3\u0001\u0000\u0000"+ - "\u0000\u03a0\u03a1\u0005*\u0000\u0000\u03a1\u00a5\u0001\u0000\u0000\u0000"+ - "\u03a2\u03a3\u0005/\u0000\u0000\u03a3\u00a7\u0001\u0000\u0000\u0000\u03a4"+ - "\u03a5\u0005%\u0000\u0000\u03a5\u00a9\u0001\u0000\u0000\u0000\u03a6\u03a7"+ - "\u0005{\u0000\u0000\u03a7\u00ab\u0001\u0000\u0000\u0000\u03a8\u03a9\u0005"+ - "}\u0000\u0000\u03a9\u00ad\u0001\u0000\u0000\u0000\u03aa\u03ab\u0003.\u000f"+ - "\u0000\u03ab\u03ac\u0001\u0000\u0000\u0000\u03ac\u03ad\u0006O\r\u0000"+ - "\u03ad\u00af\u0001\u0000\u0000\u0000\u03ae\u03b1\u0003\u008a=\u0000\u03af"+ - "\u03b2\u0003J\u001d\u0000\u03b0\u03b2\u0003X$\u0000\u03b1\u03af\u0001"+ - "\u0000\u0000\u0000\u03b1\u03b0\u0001\u0000\u0000\u0000\u03b2\u03b6\u0001"+ - "\u0000\u0000\u0000\u03b3\u03b5\u0003Z%\u0000\u03b4\u03b3\u0001\u0000\u0000"+ - "\u0000\u03b5\u03b8\u0001\u0000\u0000\u0000\u03b6\u03b4\u0001\u0000\u0000"+ - "\u0000\u03b6\u03b7\u0001\u0000\u0000\u0000\u03b7\u03c0\u0001\u0000\u0000"+ - "\u0000\u03b8\u03b6\u0001\u0000\u0000\u0000\u03b9\u03bb\u0003\u008a=\u0000"+ - "\u03ba\u03bc\u0003H\u001c\u0000\u03bb\u03ba\u0001\u0000\u0000\u0000\u03bc"+ - "\u03bd\u0001\u0000\u0000\u0000\u03bd\u03bb\u0001\u0000\u0000\u0000\u03bd"+ - "\u03be\u0001\u0000\u0000\u0000\u03be\u03c0\u0001\u0000\u0000\u0000\u03bf"+ - "\u03ae\u0001\u0000\u0000\u0000\u03bf\u03b9\u0001\u0000\u0000\u0000\u03c0"+ - "\u00b1\u0001\u0000\u0000\u0000\u03c1\u03c2\u0005[\u0000\u0000\u03c2\u03c3"+ - "\u0001\u0000\u0000\u0000\u03c3\u03c4\u0006Q\u0000\u0000\u03c4\u03c5\u0006"+ - "Q\u0000\u0000\u03c5\u00b3\u0001\u0000\u0000\u0000\u03c6\u03c7\u0005]\u0000"+ - "\u0000\u03c7\u03c8\u0001\u0000\u0000\u0000\u03c8\u03c9\u0006R\f\u0000"+ - "\u03c9\u03ca\u0006R\f\u0000\u03ca\u00b5\u0001\u0000\u0000\u0000\u03cb"+ - "\u03cf\u0003J\u001d\u0000\u03cc\u03ce\u0003Z%\u0000\u03cd\u03cc\u0001"+ - "\u0000\u0000\u0000\u03ce\u03d1\u0001\u0000\u0000\u0000\u03cf\u03cd\u0001"+ - "\u0000\u0000\u0000\u03cf\u03d0\u0001\u0000\u0000\u0000\u03d0\u03dc\u0001"+ - "\u0000\u0000\u0000\u03d1\u03cf\u0001\u0000\u0000\u0000\u03d2\u03d5\u0003"+ - "X$\u0000\u03d3\u03d5\u0003R!\u0000\u03d4\u03d2\u0001\u0000\u0000\u0000"+ - "\u03d4\u03d3\u0001\u0000\u0000\u0000\u03d5\u03d7\u0001\u0000\u0000\u0000"+ - "\u03d6\u03d8\u0003Z%\u0000\u03d7\u03d6\u0001\u0000\u0000\u0000\u03d8\u03d9"+ - "\u0001\u0000\u0000\u0000\u03d9\u03d7\u0001\u0000\u0000\u0000\u03d9\u03da"+ - "\u0001\u0000\u0000\u0000\u03da\u03dc\u0001\u0000\u0000\u0000\u03db\u03cb"+ - "\u0001\u0000\u0000\u0000\u03db\u03d4\u0001\u0000\u0000\u0000\u03dc\u00b7"+ - "\u0001\u0000\u0000\u0000\u03dd\u03df\u0003T\"\u0000\u03de\u03e0\u0003"+ - "V#\u0000\u03df\u03de\u0001\u0000\u0000\u0000\u03e0\u03e1\u0001\u0000\u0000"+ - "\u0000\u03e1\u03df\u0001\u0000\u0000\u0000\u03e1\u03e2\u0001\u0000\u0000"+ - "\u0000\u03e2\u03e3\u0001\u0000\u0000\u0000\u03e3\u03e4\u0003T\"\u0000"+ - "\u03e4\u00b9\u0001\u0000\u0000\u0000\u03e5\u03e6\u0003\u00b8T\u0000\u03e6"+ - "\u00bb\u0001\u0000\u0000\u0000\u03e7\u03e8\u0003@\u0018\u0000\u03e8\u03e9"+ - "\u0001\u0000\u0000\u0000\u03e9\u03ea\u0006V\u000b\u0000\u03ea\u00bd\u0001"+ - "\u0000\u0000\u0000\u03eb\u03ec\u0003B\u0019\u0000\u03ec\u03ed\u0001\u0000"+ - "\u0000\u0000\u03ed\u03ee\u0006W\u000b\u0000\u03ee\u00bf\u0001\u0000\u0000"+ - "\u0000\u03ef\u03f0\u0003D\u001a\u0000\u03f0\u03f1\u0001\u0000\u0000\u0000"+ - "\u03f1\u03f2\u0006X\u000b\u0000\u03f2\u00c1\u0001\u0000\u0000\u0000\u03f3"+ - "\u03f4\u0003\u00b2Q\u0000\u03f4\u03f5\u0001\u0000\u0000\u0000\u03f5\u03f6"+ - "\u0006Y\u000e\u0000\u03f6\u03f7\u0006Y\u000f\u0000\u03f7\u00c3\u0001\u0000"+ - "\u0000\u0000\u03f8\u03f9\u0003F\u001b\u0000\u03f9\u03fa\u0001\u0000\u0000"+ - "\u0000\u03fa\u03fb\u0006Z\u0010\u0000\u03fb\u03fc\u0006Z\f\u0000\u03fc"+ - "\u00c5\u0001\u0000\u0000\u0000\u03fd\u03fe\u0003D\u001a\u0000\u03fe\u03ff"+ - "\u0001\u0000\u0000\u0000\u03ff\u0400\u0006[\u000b\u0000\u0400\u00c7\u0001"+ - "\u0000\u0000\u0000\u0401\u0402\u0003@\u0018\u0000\u0402\u0403\u0001\u0000"+ - "\u0000\u0000\u0403\u0404\u0006\\\u000b\u0000\u0404\u00c9\u0001\u0000\u0000"+ - "\u0000\u0405\u0406\u0003B\u0019\u0000\u0406\u0407\u0001\u0000\u0000\u0000"+ - "\u0407\u0408\u0006]\u000b\u0000\u0408\u00cb\u0001\u0000\u0000\u0000\u0409"+ - "\u040a\u0003F\u001b\u0000\u040a\u040b\u0001\u0000\u0000\u0000\u040b\u040c"+ - "\u0006^\u0010\u0000\u040c\u040d\u0006^\f\u0000\u040d\u00cd\u0001\u0000"+ - "\u0000\u0000\u040e\u040f\u0003\u00b2Q\u0000\u040f\u0410\u0001\u0000\u0000"+ - "\u0000\u0410\u0411\u0006_\u000e\u0000\u0411\u00cf\u0001\u0000\u0000\u0000"+ - "\u0412\u0413\u0003\u00b4R\u0000\u0413\u0414\u0001\u0000\u0000\u0000\u0414"+ - "\u0415\u0006`\u0011\u0000\u0415\u00d1\u0001\u0000\u0000\u0000\u0416\u0417"+ - "\u0003l.\u0000\u0417\u0418\u0001\u0000\u0000\u0000\u0418\u0419\u0006a"+ - "\u0012\u0000\u0419\u00d3\u0001\u0000\u0000\u0000\u041a\u041b\u0003n/\u0000"+ - "\u041b\u041c\u0001\u0000\u0000\u0000\u041c\u041d\u0006b\u0013\u0000\u041d"+ - "\u00d5\u0001\u0000\u0000\u0000\u041e\u041f\u0003h,\u0000\u041f\u0420\u0001"+ - "\u0000\u0000\u0000\u0420\u0421\u0006c\u0014\u0000\u0421\u00d7\u0001\u0000"+ - "\u0000\u0000\u0422\u0423\u0007\u0010\u0000\u0000\u0423\u0424\u0007\u0003"+ - "\u0000\u0000\u0424\u0425\u0007\u0005\u0000\u0000\u0425\u0426\u0007\f\u0000"+ - "\u0000\u0426\u0427\u0007\u0000\u0000\u0000\u0427\u0428\u0007\f\u0000\u0000"+ - "\u0428\u0429\u0007\u0005\u0000\u0000\u0429\u042a\u0007\f\u0000\u0000\u042a"+ - "\u00d9\u0001\u0000\u0000\u0000\u042b\u042f\b \u0000\u0000\u042c\u042d"+ - "\u0005/\u0000\u0000\u042d\u042f\b!\u0000\u0000\u042e\u042b\u0001\u0000"+ - "\u0000\u0000\u042e\u042c\u0001\u0000\u0000\u0000\u042f\u00db\u0001\u0000"+ - "\u0000\u0000\u0430\u0432\u0003\u00dae\u0000\u0431\u0430\u0001\u0000\u0000"+ - "\u0000\u0432\u0433\u0001\u0000\u0000\u0000\u0433\u0431\u0001\u0000\u0000"+ - "\u0000\u0433\u0434\u0001\u0000\u0000\u0000\u0434\u00dd\u0001\u0000\u0000"+ - "\u0000\u0435\u0436\u0003\u00dcf\u0000\u0436\u0437\u0001\u0000\u0000\u0000"+ - "\u0437\u0438\u0006g\u0015\u0000\u0438\u00df\u0001\u0000\u0000\u0000\u0439"+ - "\u043a\u0003\\&\u0000\u043a\u043b\u0001\u0000\u0000\u0000\u043b\u043c"+ - "\u0006h\u0016\u0000\u043c\u00e1\u0001\u0000\u0000\u0000\u043d\u043e\u0003"+ - "@\u0018\u0000\u043e\u043f\u0001\u0000\u0000\u0000\u043f\u0440\u0006i\u000b"+ - "\u0000\u0440\u00e3\u0001\u0000\u0000\u0000\u0441\u0442\u0003B\u0019\u0000"+ - "\u0442\u0443\u0001\u0000\u0000\u0000\u0443\u0444\u0006j\u000b\u0000\u0444"+ - "\u00e5\u0001\u0000\u0000\u0000\u0445\u0446\u0003D\u001a\u0000\u0446\u0447"+ - "\u0001\u0000\u0000\u0000\u0447\u0448\u0006k\u000b\u0000\u0448\u00e7\u0001"+ - "\u0000\u0000\u0000\u0449\u044a\u0003F\u001b\u0000\u044a\u044b\u0001\u0000"+ - "\u0000\u0000\u044b\u044c\u0006l\u0010\u0000\u044c\u044d\u0006l\f\u0000"+ - "\u044d\u00e9\u0001\u0000\u0000\u0000\u044e\u044f\u0003r1\u0000\u044f\u0450"+ - "\u0001\u0000\u0000\u0000\u0450\u0451\u0006m\u0017\u0000\u0451\u00eb\u0001"+ - "\u0000\u0000\u0000\u0452\u0453\u0003n/\u0000\u0453\u0454\u0001\u0000\u0000"+ - "\u0000\u0454\u0455\u0006n\u0013\u0000\u0455\u00ed\u0001\u0000\u0000\u0000"+ - "\u0456\u0457\u0004o\u0006\u0000\u0457\u0458\u0003\u008a=\u0000\u0458\u0459"+ - "\u0001\u0000\u0000\u0000\u0459\u045a\u0006o\u0018\u0000\u045a\u00ef\u0001"+ - "\u0000\u0000\u0000\u045b\u045c\u0004p\u0007\u0000\u045c\u045d\u0003\u00b0"+ - "P\u0000\u045d\u045e\u0001\u0000\u0000\u0000\u045e\u045f\u0006p\u0019\u0000"+ - "\u045f\u00f1\u0001\u0000\u0000\u0000\u0460\u0465\u0003J\u001d\u0000\u0461"+ - "\u0465\u0003H\u001c\u0000\u0462\u0465\u0003X$\u0000\u0463\u0465\u0003"+ - "\u00a4J\u0000\u0464\u0460\u0001\u0000\u0000\u0000\u0464\u0461\u0001\u0000"+ - "\u0000\u0000\u0464\u0462\u0001\u0000\u0000\u0000\u0464\u0463\u0001\u0000"+ - "\u0000\u0000\u0465\u00f3\u0001\u0000\u0000\u0000\u0466\u0469\u0003J\u001d"+ - "\u0000\u0467\u0469\u0003\u00a4J\u0000\u0468\u0466\u0001\u0000\u0000\u0000"+ - "\u0468\u0467\u0001\u0000\u0000\u0000\u0469\u046d\u0001\u0000\u0000\u0000"+ - "\u046a\u046c\u0003\u00f2q\u0000\u046b\u046a\u0001\u0000\u0000\u0000\u046c"+ - "\u046f\u0001\u0000\u0000\u0000\u046d\u046b\u0001\u0000\u0000\u0000\u046d"+ - "\u046e\u0001\u0000\u0000\u0000\u046e\u047a\u0001\u0000\u0000\u0000\u046f"+ - "\u046d\u0001\u0000\u0000\u0000\u0470\u0473\u0003X$\u0000\u0471\u0473\u0003"+ - "R!\u0000\u0472\u0470\u0001\u0000\u0000\u0000\u0472\u0471\u0001\u0000\u0000"+ - "\u0000\u0473\u0475\u0001\u0000\u0000\u0000\u0474\u0476\u0003\u00f2q\u0000"+ - "\u0475\u0474\u0001\u0000\u0000\u0000\u0476\u0477\u0001\u0000\u0000\u0000"+ - "\u0477\u0475\u0001\u0000\u0000\u0000\u0477\u0478\u0001\u0000\u0000\u0000"+ - "\u0478\u047a\u0001\u0000\u0000\u0000\u0479\u0468\u0001\u0000\u0000\u0000"+ - "\u0479\u0472\u0001\u0000\u0000\u0000\u047a\u00f5\u0001\u0000\u0000\u0000"+ - "\u047b\u047e\u0003\u00f4r\u0000\u047c\u047e\u0003\u00b8T\u0000\u047d\u047b"+ - "\u0001\u0000\u0000\u0000\u047d\u047c\u0001\u0000\u0000\u0000\u047e\u047f"+ - "\u0001\u0000\u0000\u0000\u047f\u047d\u0001\u0000\u0000\u0000\u047f\u0480"+ - "\u0001\u0000\u0000\u0000\u0480\u00f7\u0001\u0000\u0000\u0000\u0481\u0482"+ - "\u0003@\u0018\u0000\u0482\u0483\u0001\u0000\u0000\u0000\u0483\u0484\u0006"+ - "t\u000b\u0000\u0484\u00f9\u0001\u0000\u0000\u0000\u0485\u0486\u0003B\u0019"+ - "\u0000\u0486\u0487\u0001\u0000\u0000\u0000\u0487\u0488\u0006u\u000b\u0000"+ - "\u0488\u00fb\u0001\u0000\u0000\u0000\u0489\u048a\u0003D\u001a\u0000\u048a"+ - "\u048b\u0001\u0000\u0000\u0000\u048b\u048c\u0006v\u000b\u0000\u048c\u00fd"+ - "\u0001\u0000\u0000\u0000\u048d\u048e\u0003F\u001b\u0000\u048e\u048f\u0001"+ - "\u0000\u0000\u0000\u048f\u0490\u0006w\u0010\u0000\u0490\u0491\u0006w\f"+ - "\u0000\u0491\u00ff\u0001\u0000\u0000\u0000\u0492\u0493\u0003h,\u0000\u0493"+ - "\u0494\u0001\u0000\u0000\u0000\u0494\u0495\u0006x\u0014\u0000\u0495\u0101"+ - "\u0001\u0000\u0000\u0000\u0496\u0497\u0003n/\u0000\u0497\u0498\u0001\u0000"+ - "\u0000\u0000\u0498\u0499\u0006y\u0013\u0000\u0499\u0103\u0001\u0000\u0000"+ - "\u0000\u049a\u049b\u0003r1\u0000\u049b\u049c\u0001\u0000\u0000\u0000\u049c"+ - "\u049d\u0006z\u0017\u0000\u049d\u0105\u0001\u0000\u0000\u0000\u049e\u049f"+ - "\u0004{\b\u0000\u049f\u04a0\u0003\u008a=\u0000\u04a0\u04a1\u0001\u0000"+ - "\u0000\u0000\u04a1\u04a2\u0006{\u0018\u0000\u04a2\u0107\u0001\u0000\u0000"+ - "\u0000\u04a3\u04a4\u0004|\t\u0000\u04a4\u04a5\u0003\u00b0P\u0000\u04a5"+ - "\u04a6\u0001\u0000\u0000\u0000\u04a6\u04a7\u0006|\u0019\u0000\u04a7\u0109"+ - "\u0001\u0000\u0000\u0000\u04a8\u04a9\u0007\f\u0000\u0000\u04a9\u04aa\u0007"+ - "\u0002\u0000\u0000\u04aa\u010b\u0001\u0000\u0000\u0000\u04ab\u04ac\u0003"+ - "\u00f6s\u0000\u04ac\u04ad\u0001\u0000\u0000\u0000\u04ad\u04ae\u0006~\u001a"+ - "\u0000\u04ae\u010d\u0001\u0000\u0000\u0000\u04af\u04b0\u0003@\u0018\u0000"+ - "\u04b0\u04b1\u0001\u0000\u0000\u0000\u04b1\u04b2\u0006\u007f\u000b\u0000"+ - "\u04b2\u010f\u0001\u0000\u0000\u0000\u04b3\u04b4\u0003B\u0019\u0000\u04b4"+ - "\u04b5\u0001\u0000\u0000\u0000\u04b5\u04b6\u0006\u0080\u000b\u0000\u04b6"+ - "\u0111\u0001\u0000\u0000\u0000\u04b7\u04b8\u0003D\u001a\u0000\u04b8\u04b9"+ - "\u0001\u0000\u0000\u0000\u04b9\u04ba\u0006\u0081\u000b\u0000\u04ba\u0113"+ - "\u0001\u0000\u0000\u0000\u04bb\u04bc\u0003F\u001b\u0000\u04bc\u04bd\u0001"+ - "\u0000\u0000\u0000\u04bd\u04be\u0006\u0082\u0010\u0000\u04be\u04bf\u0006"+ - "\u0082\f\u0000\u04bf\u0115\u0001\u0000\u0000\u0000\u04c0\u04c1\u0003\u00b2"+ - "Q\u0000\u04c1\u04c2\u0001\u0000\u0000\u0000\u04c2\u04c3\u0006\u0083\u000e"+ - "\u0000\u04c3\u04c4\u0006\u0083\u001b\u0000\u04c4\u0117\u0001\u0000\u0000"+ - "\u0000\u04c5\u04c6\u0007\u0007\u0000\u0000\u04c6\u04c7\u0007\t\u0000\u0000"+ - "\u04c7\u04c8\u0001\u0000\u0000\u0000\u04c8\u04c9\u0006\u0084\u001c\u0000"+ - "\u04c9\u0119\u0001\u0000\u0000\u0000\u04ca\u04cb\u0007\u0013\u0000\u0000"+ - "\u04cb\u04cc\u0007\u0001\u0000\u0000\u04cc\u04cd\u0007\u0005\u0000\u0000"+ - "\u04cd\u04ce\u0007\n\u0000\u0000\u04ce\u04cf\u0001\u0000\u0000\u0000\u04cf"+ - "\u04d0\u0006\u0085\u001c\u0000\u04d0\u011b\u0001\u0000\u0000\u0000\u04d1"+ - "\u04d2\b\"\u0000\u0000\u04d2\u011d\u0001\u0000\u0000\u0000\u04d3\u04d5"+ - "\u0003\u011c\u0086\u0000\u04d4\u04d3\u0001\u0000\u0000\u0000\u04d5\u04d6"+ - "\u0001\u0000\u0000\u0000\u04d6\u04d4\u0001\u0000\u0000\u0000\u04d6\u04d7"+ - "\u0001\u0000\u0000\u0000\u04d7\u04d8\u0001\u0000\u0000\u0000\u04d8\u04d9"+ - "\u0003l.\u0000\u04d9\u04db\u0001\u0000\u0000\u0000\u04da\u04d4\u0001\u0000"+ - "\u0000\u0000\u04da\u04db\u0001\u0000\u0000\u0000\u04db\u04dd\u0001\u0000"+ - "\u0000\u0000\u04dc\u04de\u0003\u011c\u0086\u0000\u04dd\u04dc\u0001\u0000"+ - "\u0000\u0000\u04de\u04df\u0001\u0000\u0000\u0000\u04df\u04dd\u0001\u0000"+ - "\u0000\u0000\u04df\u04e0\u0001\u0000\u0000\u0000\u04e0\u011f\u0001\u0000"+ - "\u0000\u0000\u04e1\u04e2\u0003\u011e\u0087\u0000\u04e2\u04e3\u0001\u0000"+ - "\u0000\u0000\u04e3\u04e4\u0006\u0088\u001d\u0000\u04e4\u0121\u0001\u0000"+ - "\u0000\u0000\u04e5\u04e6\u0003@\u0018\u0000\u04e6\u04e7\u0001\u0000\u0000"+ - "\u0000\u04e7\u04e8\u0006\u0089\u000b\u0000\u04e8\u0123\u0001\u0000\u0000"+ - "\u0000\u04e9\u04ea\u0003B\u0019\u0000\u04ea\u04eb\u0001\u0000\u0000\u0000"+ - "\u04eb\u04ec\u0006\u008a\u000b\u0000\u04ec\u0125\u0001\u0000\u0000\u0000"+ - "\u04ed\u04ee\u0003D\u001a\u0000\u04ee\u04ef\u0001\u0000\u0000\u0000\u04ef"+ - "\u04f0\u0006\u008b\u000b\u0000\u04f0\u0127\u0001\u0000\u0000\u0000\u04f1"+ - "\u04f2\u0003F\u001b\u0000\u04f2\u04f3\u0001\u0000\u0000\u0000\u04f3\u04f4"+ - "\u0006\u008c\u0010\u0000\u04f4\u04f5\u0006\u008c\f\u0000\u04f5\u04f6\u0006"+ - "\u008c\f\u0000\u04f6\u0129\u0001\u0000\u0000\u0000\u04f7\u04f8\u0003h"+ - ",\u0000\u04f8\u04f9\u0001\u0000\u0000\u0000\u04f9\u04fa\u0006\u008d\u0014"+ - "\u0000\u04fa\u012b\u0001\u0000\u0000\u0000\u04fb\u04fc\u0003n/\u0000\u04fc"+ - "\u04fd\u0001\u0000\u0000\u0000\u04fd\u04fe\u0006\u008e\u0013\u0000\u04fe"+ - "\u012d\u0001\u0000\u0000\u0000\u04ff\u0500\u0003r1\u0000\u0500\u0501\u0001"+ - "\u0000\u0000\u0000\u0501\u0502\u0006\u008f\u0017\u0000\u0502\u012f\u0001"+ - "\u0000\u0000\u0000\u0503\u0504\u0003\u011a\u0085\u0000\u0504\u0505\u0001"+ - "\u0000\u0000\u0000\u0505\u0506\u0006\u0090\u001e\u0000\u0506\u0131\u0001"+ - "\u0000\u0000\u0000\u0507\u0508\u0003\u00f6s\u0000\u0508\u0509\u0001\u0000"+ - "\u0000\u0000\u0509\u050a\u0006\u0091\u001a\u0000\u050a\u0133\u0001\u0000"+ - "\u0000\u0000\u050b\u050c\u0003\u00baU\u0000\u050c\u050d\u0001\u0000\u0000"+ - "\u0000\u050d\u050e\u0006\u0092\u001f\u0000\u050e\u0135\u0001\u0000\u0000"+ - "\u0000\u050f\u0510\u0004\u0093\n\u0000\u0510\u0511\u0003\u008a=\u0000"+ - "\u0511\u0512\u0001\u0000\u0000\u0000\u0512\u0513\u0006\u0093\u0018\u0000"+ - "\u0513\u0137\u0001\u0000\u0000\u0000\u0514\u0515\u0004\u0094\u000b\u0000"+ - "\u0515\u0516\u0003\u00b0P\u0000\u0516\u0517\u0001\u0000\u0000\u0000\u0517"+ - "\u0518\u0006\u0094\u0019\u0000\u0518\u0139\u0001\u0000\u0000\u0000\u0519"+ - "\u051a\u0003@\u0018\u0000\u051a\u051b\u0001\u0000\u0000\u0000\u051b\u051c"+ - "\u0006\u0095\u000b\u0000\u051c\u013b\u0001\u0000\u0000\u0000\u051d\u051e"+ - "\u0003B\u0019\u0000\u051e\u051f\u0001\u0000\u0000\u0000\u051f\u0520\u0006"+ - "\u0096\u000b\u0000\u0520\u013d\u0001\u0000\u0000\u0000\u0521\u0522\u0003"+ - "D\u001a\u0000\u0522\u0523\u0001\u0000\u0000\u0000\u0523\u0524\u0006\u0097"+ - "\u000b\u0000\u0524\u013f\u0001\u0000\u0000\u0000\u0525\u0526\u0003F\u001b"+ - "\u0000\u0526\u0527\u0001\u0000\u0000\u0000\u0527\u0528\u0006\u0098\u0010"+ - "\u0000\u0528\u0529\u0006\u0098\f\u0000\u0529\u0141\u0001\u0000\u0000\u0000"+ - "\u052a\u052b\u0003r1\u0000\u052b\u052c\u0001\u0000\u0000\u0000\u052c\u052d"+ - "\u0006\u0099\u0017\u0000\u052d\u0143\u0001\u0000\u0000\u0000\u052e\u052f"+ - "\u0004\u009a\f\u0000\u052f\u0530\u0003\u008a=\u0000\u0530\u0531\u0001"+ - "\u0000\u0000\u0000\u0531\u0532\u0006\u009a\u0018\u0000\u0532\u0145\u0001"+ - "\u0000\u0000\u0000\u0533\u0534\u0004\u009b\r\u0000\u0534\u0535\u0003\u00b0"+ - "P\u0000\u0535\u0536\u0001\u0000\u0000\u0000\u0536\u0537\u0006\u009b\u0019"+ - "\u0000\u0537\u0147\u0001\u0000\u0000\u0000\u0538\u0539\u0003\u00baU\u0000"+ - "\u0539\u053a\u0001\u0000\u0000\u0000\u053a\u053b\u0006\u009c\u001f\u0000"+ - "\u053b\u0149\u0001\u0000\u0000\u0000\u053c\u053d\u0003\u00b6S\u0000\u053d"+ - "\u053e\u0001\u0000\u0000\u0000\u053e\u053f\u0006\u009d \u0000\u053f\u014b"+ - "\u0001\u0000\u0000\u0000\u0540\u0541\u0003@\u0018\u0000\u0541\u0542\u0001"+ - "\u0000\u0000\u0000\u0542\u0543\u0006\u009e\u000b\u0000\u0543\u014d\u0001"+ - "\u0000\u0000\u0000\u0544\u0545\u0003B\u0019\u0000\u0545\u0546\u0001\u0000"+ - "\u0000\u0000\u0546\u0547\u0006\u009f\u000b\u0000\u0547\u014f\u0001\u0000"+ - "\u0000\u0000\u0548\u0549\u0003D\u001a\u0000\u0549\u054a\u0001\u0000\u0000"+ - "\u0000\u054a\u054b\u0006\u00a0\u000b\u0000\u054b\u0151\u0001\u0000\u0000"+ - "\u0000\u054c\u054d\u0003F\u001b\u0000\u054d\u054e\u0001\u0000\u0000\u0000"+ - "\u054e\u054f\u0006\u00a1\u0010\u0000\u054f\u0550\u0006\u00a1\f\u0000\u0550"+ - "\u0153\u0001\u0000\u0000\u0000\u0551\u0552\u0007\u0001\u0000\u0000\u0552"+ - "\u0553\u0007\t\u0000\u0000\u0553\u0554\u0007\u000f\u0000\u0000\u0554\u0555"+ - "\u0007\u0007\u0000\u0000\u0555\u0155\u0001\u0000\u0000\u0000\u0556\u0557"+ - "\u0003@\u0018\u0000\u0557\u0558\u0001\u0000\u0000\u0000\u0558\u0559\u0006"+ - "\u00a3\u000b\u0000\u0559\u0157\u0001\u0000\u0000\u0000\u055a\u055b\u0003"+ - "B\u0019\u0000\u055b\u055c\u0001\u0000\u0000\u0000\u055c\u055d\u0006\u00a4"+ - "\u000b\u0000\u055d\u0159\u0001\u0000\u0000\u0000\u055e\u055f\u0003D\u001a"+ - "\u0000\u055f\u0560\u0001\u0000\u0000\u0000\u0560\u0561\u0006\u00a5\u000b"+ - "\u0000\u0561\u015b\u0001\u0000\u0000\u0000\u0562\u0563\u0003\u00b4R\u0000"+ - "\u0563\u0564\u0001\u0000\u0000\u0000\u0564\u0565\u0006\u00a6\u0011\u0000"+ - "\u0565\u0566\u0006\u00a6\f\u0000\u0566\u015d\u0001\u0000\u0000\u0000\u0567"+ - "\u0568\u0003l.\u0000\u0568\u0569\u0001\u0000\u0000\u0000\u0569\u056a\u0006"+ - "\u00a7\u0012\u0000\u056a\u015f\u0001\u0000\u0000\u0000\u056b\u0571\u0003"+ - "R!\u0000\u056c\u0571\u0003H\u001c\u0000\u056d\u0571\u0003r1\u0000\u056e"+ - "\u0571\u0003J\u001d\u0000\u056f\u0571\u0003X$\u0000\u0570\u056b\u0001"+ - "\u0000\u0000\u0000\u0570\u056c\u0001\u0000\u0000\u0000\u0570\u056d\u0001"+ - "\u0000\u0000\u0000\u0570\u056e\u0001\u0000\u0000\u0000\u0570\u056f\u0001"+ - "\u0000\u0000\u0000\u0571\u0572\u0001\u0000\u0000\u0000\u0572\u0570\u0001"+ - "\u0000\u0000\u0000\u0572\u0573\u0001\u0000\u0000\u0000\u0573\u0161\u0001"+ - "\u0000\u0000\u0000\u0574\u0575\u0003@\u0018\u0000\u0575\u0576\u0001\u0000"+ - "\u0000\u0000\u0576\u0577\u0006\u00a9\u000b\u0000\u0577\u0163\u0001\u0000"+ - "\u0000\u0000\u0578\u0579\u0003B\u0019\u0000\u0579\u057a\u0001\u0000\u0000"+ - "\u0000\u057a\u057b\u0006\u00aa\u000b\u0000\u057b\u0165\u0001\u0000\u0000"+ - "\u0000\u057c\u057d\u0003D\u001a\u0000\u057d\u057e\u0001\u0000\u0000\u0000"+ - "\u057e\u057f\u0006\u00ab\u000b\u0000\u057f\u0167\u0001\u0000\u0000\u0000"+ - "\u0580\u0581\u0003F\u001b\u0000\u0581\u0582\u0001\u0000\u0000\u0000\u0582"+ - "\u0583\u0006\u00ac\u0010\u0000\u0583\u0584\u0006\u00ac\f\u0000\u0584\u0169"+ - "\u0001\u0000\u0000\u0000\u0585\u0586\u0003l.\u0000\u0586\u0587\u0001\u0000"+ - "\u0000\u0000\u0587\u0588\u0006\u00ad\u0012\u0000\u0588\u016b\u0001\u0000"+ - "\u0000\u0000\u0589\u058a\u0003n/\u0000\u058a\u058b\u0001\u0000\u0000\u0000"+ - "\u058b\u058c\u0006\u00ae\u0013\u0000\u058c\u016d\u0001\u0000\u0000\u0000"+ - "\u058d\u058e\u0003r1\u0000\u058e\u058f\u0001\u0000\u0000\u0000\u058f\u0590"+ - "\u0006\u00af\u0017\u0000\u0590\u016f\u0001\u0000\u0000\u0000\u0591\u0592"+ - "\u0003\u0118\u0084\u0000\u0592\u0593\u0001\u0000\u0000\u0000\u0593\u0594"+ - "\u0006\u00b0!\u0000\u0594\u0595\u0006\u00b0\"\u0000\u0595\u0171\u0001"+ - "\u0000\u0000\u0000\u0596\u0597\u0003\u00dcf\u0000\u0597\u0598\u0001\u0000"+ - "\u0000\u0000\u0598\u0599\u0006\u00b1\u0015\u0000\u0599\u0173\u0001\u0000"+ - "\u0000\u0000\u059a\u059b\u0003\\&\u0000\u059b\u059c\u0001\u0000\u0000"+ - "\u0000\u059c\u059d\u0006\u00b2\u0016\u0000\u059d\u0175\u0001\u0000\u0000"+ - "\u0000\u059e\u059f\u0003@\u0018\u0000\u059f\u05a0\u0001\u0000\u0000\u0000"+ - "\u05a0\u05a1\u0006\u00b3\u000b\u0000\u05a1\u0177\u0001\u0000\u0000\u0000"+ - "\u05a2\u05a3\u0003B\u0019\u0000\u05a3\u05a4\u0001\u0000\u0000\u0000\u05a4"+ - "\u05a5\u0006\u00b4\u000b\u0000\u05a5\u0179\u0001\u0000\u0000\u0000\u05a6"+ - "\u05a7\u0003D\u001a\u0000\u05a7\u05a8\u0001\u0000\u0000\u0000\u05a8\u05a9"+ - "\u0006\u00b5\u000b\u0000\u05a9\u017b\u0001\u0000\u0000\u0000\u05aa\u05ab"+ - "\u0003F\u001b\u0000\u05ab\u05ac\u0001\u0000\u0000\u0000\u05ac\u05ad\u0006"+ - "\u00b6\u0010\u0000\u05ad\u05ae\u0006\u00b6\f\u0000\u05ae\u05af\u0006\u00b6"+ - "\f\u0000\u05af\u017d\u0001\u0000\u0000\u0000\u05b0\u05b1\u0003n/\u0000"+ - "\u05b1\u05b2\u0001\u0000\u0000\u0000\u05b2\u05b3\u0006\u00b7\u0013\u0000"+ - "\u05b3\u017f\u0001\u0000\u0000\u0000\u05b4\u05b5\u0003r1\u0000\u05b5\u05b6"+ - "\u0001\u0000\u0000\u0000\u05b6\u05b7\u0006\u00b8\u0017\u0000\u05b7\u0181"+ - "\u0001\u0000\u0000\u0000\u05b8\u05b9\u0003\u00f6s\u0000\u05b9\u05ba\u0001"+ - "\u0000\u0000\u0000\u05ba\u05bb\u0006\u00b9\u001a\u0000\u05bb\u0183\u0001"+ - "\u0000\u0000\u0000\u05bc\u05bd\u0003@\u0018\u0000\u05bd\u05be\u0001\u0000"+ - "\u0000\u0000\u05be\u05bf\u0006\u00ba\u000b\u0000\u05bf\u0185\u0001\u0000"+ - "\u0000\u0000\u05c0\u05c1\u0003B\u0019\u0000\u05c1\u05c2\u0001\u0000\u0000"+ - "\u0000\u05c2\u05c3\u0006\u00bb\u000b\u0000\u05c3\u0187\u0001\u0000\u0000"+ - "\u0000\u05c4\u05c5\u0003D\u001a\u0000\u05c5\u05c6\u0001\u0000\u0000\u0000"+ - "\u05c6\u05c7\u0006\u00bc\u000b\u0000\u05c7\u0189\u0001\u0000\u0000\u0000"+ - "\u05c8\u05c9\u0003F\u001b\u0000\u05c9\u05ca\u0001\u0000\u0000\u0000\u05ca"+ - "\u05cb\u0006\u00bd\u0010\u0000\u05cb\u05cc\u0006\u00bd\f\u0000\u05cc\u018b"+ - "\u0001\u0000\u0000\u0000\u05cd\u05ce\u0007#\u0000\u0000\u05ce\u05cf\u0007"+ - "\u0007\u0000\u0000\u05cf\u05d0\u0007\u0001\u0000\u0000\u05d0\u05d1\u0007"+ - "\t\u0000\u0000\u05d1\u018d\u0001\u0000\u0000\u0000\u05d2\u05d3\u0003\u010a"+ - "}\u0000\u05d3\u05d4\u0001\u0000\u0000\u0000\u05d4\u05d5\u0006\u00bf#\u0000"+ - "\u05d5\u018f\u0001\u0000\u0000\u0000\u05d6\u05d7\u0003\u0118\u0084\u0000"+ - "\u05d7\u05d8\u0001\u0000\u0000\u0000\u05d8\u05d9\u0006\u00c0!\u0000\u05d9"+ - "\u05da\u0006\u00c0\f\u0000\u05da\u05db\u0006\u00c0\u0000\u0000\u05db\u0191"+ - "\u0001\u0000\u0000\u0000\u05dc\u05dd\u0007\u0014\u0000\u0000\u05dd\u05de"+ - "\u0007\u0002\u0000\u0000\u05de\u05df\u0007\u0001\u0000\u0000\u05df\u05e0"+ - "\u0007\t\u0000\u0000\u05e0\u05e1\u0007\u0011\u0000\u0000\u05e1\u05e2\u0001"+ - "\u0000\u0000\u0000\u05e2\u05e3\u0006\u00c1\f\u0000\u05e3\u05e4\u0006\u00c1"+ - "\u0000\u0000\u05e4\u0193\u0001\u0000\u0000\u0000\u05e5\u05e6\u0003\u00dc"+ - "f\u0000\u05e6\u05e7\u0001\u0000\u0000\u0000\u05e7\u05e8\u0006\u00c2\u0015"+ - "\u0000\u05e8\u0195\u0001\u0000\u0000\u0000\u05e9\u05ea\u0003\\&\u0000"+ - "\u05ea\u05eb\u0001\u0000\u0000\u0000\u05eb\u05ec\u0006\u00c3\u0016\u0000"+ - "\u05ec\u0197\u0001\u0000\u0000\u0000\u05ed\u05ee\u0003l.\u0000\u05ee\u05ef"+ - "\u0001\u0000\u0000\u0000\u05ef\u05f0\u0006\u00c4\u0012\u0000\u05f0\u0199"+ - "\u0001\u0000\u0000\u0000\u05f1\u05f2\u0003\u00b6S\u0000\u05f2\u05f3\u0001"+ - "\u0000\u0000\u0000\u05f3\u05f4\u0006\u00c5 \u0000\u05f4\u019b\u0001\u0000"+ - "\u0000\u0000\u05f5\u05f6\u0003\u00baU\u0000\u05f6\u05f7\u0001\u0000\u0000"+ - "\u0000\u05f7\u05f8\u0006\u00c6\u001f\u0000\u05f8\u019d\u0001\u0000\u0000"+ - "\u0000\u05f9\u05fa\u0003@\u0018\u0000\u05fa\u05fb\u0001\u0000\u0000\u0000"+ - "\u05fb\u05fc\u0006\u00c7\u000b\u0000\u05fc\u019f\u0001\u0000\u0000\u0000"+ - "\u05fd\u05fe\u0003B\u0019\u0000\u05fe\u05ff\u0001\u0000\u0000\u0000\u05ff"+ - "\u0600\u0006\u00c8\u000b\u0000\u0600\u01a1\u0001\u0000\u0000\u0000\u0601"+ - "\u0602\u0003D\u001a\u0000\u0602\u0603\u0001\u0000\u0000\u0000\u0603\u0604"+ - "\u0006\u00c9\u000b\u0000\u0604\u01a3\u0001\u0000\u0000\u0000\u0605\u0606"+ - "\u0003F\u001b\u0000\u0606\u0607\u0001\u0000\u0000\u0000\u0607\u0608\u0006"+ - "\u00ca\u0010\u0000\u0608\u0609\u0006\u00ca\f\u0000\u0609\u01a5\u0001\u0000"+ - "\u0000\u0000\u060a\u060b\u0003\u00dcf\u0000\u060b\u060c\u0001\u0000\u0000"+ - "\u0000\u060c\u060d\u0006\u00cb\u0015\u0000\u060d\u060e\u0006\u00cb\f\u0000"+ - "\u060e\u060f\u0006\u00cb$\u0000\u060f\u01a7\u0001\u0000\u0000\u0000\u0610"+ - "\u0611\u0003\\&\u0000\u0611\u0612\u0001\u0000\u0000\u0000\u0612\u0613"+ - "\u0006\u00cc\u0016\u0000\u0613\u0614\u0006\u00cc\f\u0000\u0614\u0615\u0006"+ - "\u00cc$\u0000\u0615\u01a9\u0001\u0000\u0000\u0000\u0616\u0617\u0003@\u0018"+ - "\u0000\u0617\u0618\u0001\u0000\u0000\u0000\u0618\u0619\u0006\u00cd\u000b"+ - "\u0000\u0619\u01ab\u0001\u0000\u0000\u0000\u061a\u061b\u0003B\u0019\u0000"+ - "\u061b\u061c\u0001\u0000\u0000\u0000\u061c\u061d\u0006\u00ce\u000b\u0000"+ - "\u061d\u01ad\u0001\u0000\u0000\u0000\u061e\u061f\u0003D\u001a\u0000\u061f"+ - "\u0620\u0001\u0000\u0000\u0000\u0620\u0621\u0006\u00cf\u000b\u0000\u0621"+ - "\u01af\u0001\u0000\u0000\u0000\u0622\u0623\u0003l.\u0000\u0623\u0624\u0001"+ - "\u0000\u0000\u0000\u0624\u0625\u0006\u00d0\u0012\u0000\u0625\u0626\u0006"+ - "\u00d0\f\u0000\u0626\u0627\u0006\u00d0\n\u0000\u0627\u01b1\u0001\u0000"+ - "\u0000\u0000\u0628\u0629\u0003n/\u0000\u0629\u062a\u0001\u0000\u0000\u0000"+ - "\u062a\u062b\u0006\u00d1\u0013\u0000\u062b\u062c\u0006\u00d1\f\u0000\u062c"+ - "\u062d\u0006\u00d1\n\u0000\u062d\u01b3\u0001\u0000\u0000\u0000\u062e\u062f"+ - "\u0003@\u0018\u0000\u062f\u0630\u0001\u0000\u0000\u0000\u0630\u0631\u0006"+ - "\u00d2\u000b\u0000\u0631\u01b5\u0001\u0000\u0000\u0000\u0632\u0633\u0003"+ - "B\u0019\u0000\u0633\u0634\u0001\u0000\u0000\u0000\u0634\u0635\u0006\u00d3"+ - "\u000b\u0000\u0635\u01b7\u0001\u0000\u0000\u0000\u0636\u0637\u0003D\u001a"+ - "\u0000\u0637\u0638\u0001\u0000\u0000\u0000\u0638\u0639\u0006\u00d4\u000b"+ - "\u0000\u0639\u01b9\u0001\u0000\u0000\u0000\u063a\u063b\u0003\u00baU\u0000"+ - "\u063b\u063c\u0001\u0000\u0000\u0000\u063c\u063d\u0006\u00d5\f\u0000\u063d"+ - "\u063e\u0006\u00d5\u0000\u0000\u063e\u063f\u0006\u00d5\u001f\u0000\u063f"+ - "\u01bb\u0001\u0000\u0000\u0000\u0640\u0641\u0003\u00b6S\u0000\u0641\u0642"+ - "\u0001\u0000\u0000\u0000\u0642\u0643\u0006\u00d6\f\u0000\u0643\u0644\u0006"+ - "\u00d6\u0000\u0000\u0644\u0645\u0006\u00d6 \u0000\u0645\u01bd\u0001\u0000"+ - "\u0000\u0000\u0646\u0647\u0003b)\u0000\u0647\u0648\u0001\u0000\u0000\u0000"+ - "\u0648\u0649\u0006\u00d7\f\u0000\u0649\u064a\u0006\u00d7\u0000\u0000\u064a"+ - "\u064b\u0006\u00d7%\u0000\u064b\u01bf\u0001\u0000\u0000\u0000\u064c\u064d"+ - "\u0003F\u001b\u0000\u064d\u064e\u0001\u0000\u0000\u0000\u064e\u064f\u0006"+ - "\u00d8\u0010\u0000\u064f\u0650\u0006\u00d8\f\u0000\u0650\u01c1\u0001\u0000"+ - "\u0000\u0000B\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b"+ - "\f\r\u000e\u000f\u028e\u0298\u029c\u029f\u02a8\u02aa\u02b5\u02c8\u02cd"+ - "\u02d6\u02dd\u02e2\u02e4\u02ef\u02f7\u02fa\u02fc\u0301\u0306\u030c\u0313"+ - "\u0318\u031e\u0321\u0329\u032d\u03b1\u03b6\u03bd\u03bf\u03cf\u03d4\u03d9"+ - "\u03db\u03e1\u042e\u0433\u0464\u0468\u046d\u0472\u0477\u0479\u047d\u047f"+ - "\u04d6\u04da\u04df\u0570\u0572&\u0005\u0001\u0000\u0005\u0004\u0000\u0005"+ + "\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/\u0002"+ + "0\u00070\u00021\u00071\u00022\u00072\u00023\u00073\u00024\u00074\u0002"+ + "5\u00075\u00026\u00076\u00027\u00077\u00028\u00078\u00029\u00079\u0002"+ + ":\u0007:\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_\u0007_\u0002`\u0007`\u0002a\u0007a\u0002"+ + "b\u0007b\u0002c\u0007c\u0002d\u0007d\u0002e\u0007e\u0002f\u0007f\u0002"+ + "g\u0007g\u0002h\u0007h\u0002i\u0007i\u0002j\u0007j\u0002k\u0007k\u0002"+ + "l\u0007l\u0002m\u0007m\u0002n\u0007n\u0002o\u0007o\u0002p\u0007p\u0002"+ + "q\u0007q\u0002r\u0007r\u0002s\u0007s\u0002t\u0007t\u0002u\u0007u\u0002"+ + "v\u0007v\u0002w\u0007w\u0002x\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\u0002\u00bd\u0007\u00bd\u0002\u00be\u0007\u00be"+ + "\u0002\u00bf\u0007\u00bf\u0002\u00c0\u0007\u00c0\u0002\u00c1\u0007\u00c1"+ + "\u0002\u00c2\u0007\u00c2\u0002\u00c3\u0007\u00c3\u0002\u00c4\u0007\u00c4"+ + "\u0002\u00c5\u0007\u00c5\u0002\u00c6\u0007\u00c6\u0002\u00c7\u0007\u00c7"+ + "\u0002\u00c8\u0007\u00c8\u0002\u00c9\u0007\u00c9\u0002\u00ca\u0007\u00ca"+ + "\u0002\u00cb\u0007\u00cb\u0002\u00cc\u0007\u00cc\u0002\u00cd\u0007\u00cd"+ + "\u0002\u00ce\u0007\u00ce\u0002\u00cf\u0007\u00cf\u0002\u00d0\u0007\u00d0"+ + "\u0002\u00d1\u0007\u00d1\u0002\u00d2\u0007\u00d2\u0002\u00d3\u0007\u00d3"+ + "\u0002\u00d4\u0007\u00d4\u0002\u00d5\u0007\u00d5\u0002\u00d6\u0007\u00d6"+ + "\u0002\u00d7\u0007\u00d7\u0002\u00d8\u0007\u00d8\u0002\u00d9\u0007\u00d9"+ + "\u0002\u00da\u0007\u00da\u0002\u00db\u0007\u00db\u0002\u00dc\u0007\u00dc"+ + "\u0002\u00dd\u0007\u00dd\u0002\u00de\u0007\u00de\u0002\u00df\u0007\u00df"+ + "\u0002\u00e0\u0007\u00e0\u0002\u00e1\u0007\u00e1\u0002\u00e2\u0007\u00e2"+ + "\u0002\u00e3\u0007\u00e3\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\b\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\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\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\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\u000f\u0001\u000f\u0001\u0010\u0001\u0010\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\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\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\u0013\u0001\u0013\u0001\u0013"+ + "\u0001\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014"+ + "\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014"+ + "\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015"+ + "\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016"+ + "\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017"+ + "\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017"+ + "\u0001\u0017\u0001\u0018\u0004\u0018\u02b4\b\u0018\u000b\u0018\f\u0018"+ + "\u02b5\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019\u0001\u0019\u0001"+ + "\u0019\u0005\u0019\u02be\b\u0019\n\u0019\f\u0019\u02c1\t\u0019\u0001\u0019"+ + "\u0003\u0019\u02c4\b\u0019\u0001\u0019\u0003\u0019\u02c7\b\u0019\u0001"+ + "\u0019\u0001\u0019\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001"+ + "\u001a\u0005\u001a\u02d0\b\u001a\n\u001a\f\u001a\u02d3\t\u001a\u0001\u001a"+ + "\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001b\u0004\u001b"+ + "\u02db\b\u001b\u000b\u001b\f\u001b\u02dc\u0001\u001b\u0001\u001b\u0001"+ + "\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001d\u0001\u001d\u0001"+ + "\u001e\u0001\u001e\u0001\u001f\u0001\u001f\u0001\u001f\u0001 \u0001 \u0001"+ + "!\u0001!\u0003!\u02f0\b!\u0001!\u0004!\u02f3\b!\u000b!\f!\u02f4\u0001"+ + "\"\u0001\"\u0001#\u0001#\u0001$\u0001$\u0001$\u0003$\u02fe\b$\u0001%\u0001"+ + "%\u0001&\u0001&\u0001&\u0003&\u0305\b&\u0001\'\u0001\'\u0001\'\u0005\'"+ + "\u030a\b\'\n\'\f\'\u030d\t\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001"+ + "\'\u0005\'\u0315\b\'\n\'\f\'\u0318\t\'\u0001\'\u0001\'\u0001\'\u0001\'"+ + "\u0001\'\u0003\'\u031f\b\'\u0001\'\u0003\'\u0322\b\'\u0003\'\u0324\b\'"+ + "\u0001(\u0004(\u0327\b(\u000b(\f(\u0328\u0001)\u0004)\u032c\b)\u000b)"+ + "\f)\u032d\u0001)\u0001)\u0005)\u0332\b)\n)\f)\u0335\t)\u0001)\u0001)\u0004"+ + ")\u0339\b)\u000b)\f)\u033a\u0001)\u0004)\u033e\b)\u000b)\f)\u033f\u0001"+ + ")\u0001)\u0005)\u0344\b)\n)\f)\u0347\t)\u0003)\u0349\b)\u0001)\u0001)"+ + "\u0001)\u0001)\u0004)\u034f\b)\u000b)\f)\u0350\u0001)\u0001)\u0003)\u0355"+ + "\b)\u0001*\u0001*\u0001*\u0001+\u0001+\u0001+\u0001+\u0001,\u0001,\u0001"+ + ",\u0001,\u0001-\u0001-\u0001.\u0001.\u0001.\u0001/\u0001/\u00010\u0001"+ + "0\u00011\u00011\u00011\u00011\u00011\u00012\u00012\u00013\u00013\u0001"+ + "3\u00013\u00013\u00013\u00014\u00014\u00014\u00014\u00014\u00014\u0001"+ + "5\u00015\u00015\u00016\u00016\u00016\u00017\u00017\u00017\u00017\u0001"+ + "7\u00018\u00018\u00018\u00018\u00018\u00019\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@\u0001A\u0001A\u0001A\u0001A\u0001"+ + "A\u0001B\u0001B\u0001B\u0001C\u0001C\u0001C\u0001D\u0001D\u0001D\u0001"+ + "E\u0001E\u0001F\u0001F\u0001F\u0001G\u0001G\u0001H\u0001H\u0001H\u0001"+ + "I\u0001I\u0001J\u0001J\u0001K\u0001K\u0001L\u0001L\u0001M\u0001M\u0001"+ + "N\u0001N\u0001O\u0001O\u0001P\u0001P\u0001P\u0001P\u0001Q\u0001Q\u0001"+ + "Q\u0003Q\u03d9\bQ\u0001Q\u0005Q\u03dc\bQ\nQ\fQ\u03df\tQ\u0001Q\u0001Q"+ + "\u0004Q\u03e3\bQ\u000bQ\fQ\u03e4\u0003Q\u03e7\bQ\u0001R\u0001R\u0001R"+ + "\u0001R\u0001R\u0001S\u0001S\u0001S\u0001S\u0001S\u0001T\u0001T\u0005"+ + "T\u03f5\bT\nT\fT\u03f8\tT\u0001T\u0001T\u0003T\u03fc\bT\u0001T\u0004T"+ + "\u03ff\bT\u000bT\fT\u0400\u0003T\u0403\bT\u0001U\u0001U\u0004U\u0407\b"+ + "U\u000bU\fU\u0408\u0001U\u0001U\u0001V\u0001V\u0001W\u0001W\u0001W\u0001"+ + "W\u0001X\u0001X\u0001X\u0001X\u0001Y\u0001Y\u0001Y\u0001Y\u0001Z\u0001"+ + "Z\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"+ + "a\u0001a\u0001a\u0001a\u0001b\u0001b\u0001b\u0001b\u0001c\u0001c\u0001"+ + "c\u0001c\u0001d\u0001d\u0001d\u0001d\u0001e\u0001e\u0001e\u0001e\u0001"+ + "e\u0001e\u0001e\u0001e\u0001e\u0001f\u0001f\u0001f\u0003f\u0456\bf\u0001"+ + "g\u0004g\u0459\bg\u000bg\fg\u045a\u0001h\u0001h\u0001h\u0001h\u0001i\u0001"+ + "i\u0001i\u0001i\u0001j\u0001j\u0001j\u0001j\u0001k\u0001k\u0001k\u0001"+ + "k\u0001l\u0001l\u0001l\u0001l\u0001m\u0001m\u0001m\u0001m\u0001m\u0001"+ + "n\u0001n\u0001n\u0001n\u0001o\u0001o\u0001o\u0001o\u0001p\u0001p\u0001"+ + "p\u0001p\u0001q\u0001q\u0001q\u0001q\u0001r\u0001r\u0001r\u0001r\u0003"+ + "r\u048a\br\u0001s\u0001s\u0003s\u048e\bs\u0001s\u0005s\u0491\bs\ns\fs"+ + "\u0494\ts\u0001s\u0001s\u0003s\u0498\bs\u0001s\u0004s\u049b\bs\u000bs"+ + "\fs\u049c\u0003s\u049f\bs\u0001t\u0001t\u0004t\u04a3\bt\u000bt\ft\u04a4"+ + "\u0001u\u0001u\u0001u\u0001u\u0001v\u0001v\u0001v\u0001v\u0001w\u0001"+ + "w\u0001w\u0001w\u0001x\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\u007f\u0001\u007f\u0001\u007f\u0001\u007f\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\u0083\u0001\u0084\u0001\u0084\u0001\u0084"+ + "\u0001\u0084\u0001\u0084\u0001\u0085\u0001\u0085\u0001\u0085\u0001\u0085"+ + "\u0001\u0085\u0001\u0086\u0001\u0086\u0001\u0086\u0001\u0086\u0001\u0086"+ + "\u0001\u0086\u0001\u0086\u0001\u0087\u0001\u0087\u0001\u0088\u0004\u0088"+ + "\u04f8\b\u0088\u000b\u0088\f\u0088\u04f9\u0001\u0088\u0001\u0088\u0003"+ + "\u0088\u04fe\b\u0088\u0001\u0088\u0004\u0088\u0501\b\u0088\u000b\u0088"+ + "\f\u0088\u0502\u0001\u0089\u0001\u0089\u0001\u0089\u0001\u0089\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\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\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\u0097"+ + "\u0001\u0097\u0001\u0097\u0001\u0097\u0001\u0098\u0001\u0098\u0001\u0098"+ + "\u0001\u0098\u0001\u0099\u0001\u0099\u0001\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\u00a1\u0001\u00a1"+ + "\u0001\u00a1\u0001\u00a1\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a2"+ + "\u0001\u00a2\u0001\u00a3\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\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a6"+ + "\u0001\u00a7\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\u0004\u00a9\u0590\b\u00a9\u000b\u00a9\f\u00a9"+ + "\u0591\u0001\u00aa\u0001\u00aa\u0001\u00aa\u0001\u00aa\u0001\u00ab\u0001"+ + "\u00ab\u0001\u00ab\u0001\u00ab\u0001\u00ac\u0001\u00ac\u0001\u00ac\u0001"+ + "\u00ac\u0001\u00ad\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"+ + "\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\u00b6\u0001\u00b6\u0001\u00b6\u0001"+ + "\u00b6\u0001\u00b7\u0001\u00b7\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\u00ba\u0001\u00ba\u0001\u00ba\u0001"+ + "\u00ba\u0001\u00bb\u0001\u00bb\u0001\u00bb\u0001\u00bb\u0001\u00bc\u0001"+ + "\u00bc\u0001\u00bc\u0001\u00bc\u0001\u00bd\u0001\u00bd\u0001\u00bd\u0001"+ + "\u00bd\u0001\u00be\u0001\u00be\u0001\u00be\u0001\u00be\u0001\u00be\u0001"+ + "\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00c0\u0001"+ + "\u00c0\u0001\u00c0\u0001\u00c0\u0001\u00c1\u0001\u00c1\u0001\u00c1\u0001"+ + "\u00c1\u0001\u00c1\u0001\u00c1\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001"+ + "\u00c2\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001"+ + "\u00c3\u0001\u00c3\u0001\u00c3\u0001\u00c3\u0001\u00c4\u0001\u00c4\u0001"+ + "\u00c4\u0001\u00c4\u0001\u00c5\u0001\u00c5\u0001\u00c5\u0001\u00c5\u0001"+ + "\u00c6\u0001\u00c6\u0001\u00c6\u0001\u00c6\u0001\u00c7\u0001\u00c7\u0001"+ + "\u00c7\u0001\u00c7\u0001\u00c8\u0001\u00c8\u0001\u00c8\u0001\u00c8\u0001"+ + "\u00c9\u0001\u00c9\u0001\u00c9\u0001\u00c9\u0001\u00ca\u0001\u00ca\u0001"+ + "\u00ca\u0001\u00ca\u0001\u00cb\u0001\u00cb\u0001\u00cb\u0001\u00cb\u0001"+ + "\u00cb\u0001\u00cc\u0001\u00cc\u0001\u00cc\u0001\u00cc\u0001\u00cc\u0001"+ + "\u00cc\u0001\u00cd\u0001\u00cd\u0001\u00cd\u0001\u00cd\u0001\u00cd\u0001"+ + "\u00cd\u0001\u00ce\u0001\u00ce\u0001\u00ce\u0001\u00ce\u0001\u00cf\u0001"+ + "\u00cf\u0001\u00cf\u0001\u00cf\u0001\u00d0\u0001\u00d0\u0001\u00d0\u0001"+ + "\u00d0\u0001\u00d1\u0001\u00d1\u0001\u00d1\u0001\u00d1\u0001\u00d1\u0001"+ + "\u00d1\u0001\u00d2\u0001\u00d2\u0001\u00d2\u0001\u00d2\u0001\u00d2\u0001"+ + "\u00d2\u0001\u00d3\u0001\u00d3\u0001\u00d3\u0001\u00d3\u0001\u00d4\u0001"+ + "\u00d4\u0001\u00d4\u0001\u00d4\u0001\u00d5\u0001\u00d5\u0001\u00d5\u0001"+ + "\u00d5\u0001\u00d6\u0001\u00d6\u0001\u00d6\u0001\u00d6\u0001\u00d6\u0001"+ + "\u00d6\u0001\u00d7\u0001\u00d7\u0001\u00d7\u0001\u00d7\u0001\u00d7\u0001"+ + "\u00d7\u0001\u00d8\u0001\u00d8\u0001\u00d8\u0001\u00d8\u0001\u00d8\u0001"+ + "\u00d8\u0001\u00d9\u0001\u00d9\u0001\u00d9\u0001\u00d9\u0001\u00d9\u0001"+ + "\u00da\u0001\u00da\u0001\u00da\u0001\u00da\u0001\u00da\u0001\u00db\u0001"+ + "\u00db\u0001\u00db\u0001\u00db\u0001\u00dc\u0001\u00dc\u0001\u00dc\u0001"+ + "\u00dc\u0001\u00dd\u0001\u00dd\u0001\u00dd\u0001\u00dd\u0001\u00de\u0001"+ + "\u00de\u0001\u00de\u0001\u00de\u0001\u00df\u0001\u00df\u0001\u00df\u0001"+ + "\u00df\u0001\u00e0\u0001\u00e0\u0001\u00e0\u0001\u00e0\u0001\u00e1\u0001"+ + "\u00e1\u0001\u00e1\u0001\u00e1\u0001\u00e2\u0001\u00e2\u0001\u00e2\u0001"+ + "\u00e2\u0001\u00e3\u0001\u00e3\u0001\u00e3\u0001\u00e3\u0002\u02d1\u0316"+ + "\u0000\u00e4\u0011\u0001\u0013\u0002\u0015\u0003\u0017\u0004\u0019\u0005"+ + "\u001b\u0006\u001d\u0007\u001f\b!\t#\n%\u000b\'\f)\r+\u000e-\u000f/\u0010"+ + "1\u00113\u00125\u00137\u00149\u0015;\u0016=\u0017?\u0018A\u0019C\u001a"+ + "E\u001bG\u001cI\u001dK\u0000M\u0000O\u0000Q\u0000S\u0000U\u0000W\u0000"+ + "Y\u0000[\u0000]\u0000_\u001ea\u001fc e!g\"i#k$m%o&q\'s(u)w*y+{,}-\u007f"+ + ".\u0081/\u00830\u00851\u00872\u00893\u008b4\u008d5\u008f6\u00917\u0093"+ + "8\u00959\u0097:\u0099;\u009b<\u009d=\u009f>\u00a1?\u00a3@\u00a5A\u00a7"+ + "B\u00a9C\u00abD\u00adE\u00afF\u00b1\u0000\u00b3G\u00b5H\u00b7I\u00b9J"+ + "\u00bb\u0000\u00bdK\u00bfL\u00c1M\u00c3N\u00c5\u0000\u00c7\u0000\u00c9"+ + "O\u00cbP\u00cdQ\u00cf\u0000\u00d1\u0000\u00d3\u0000\u00d5\u0000\u00d7"+ + "\u0000\u00d9\u0000\u00dbR\u00dd\u0000\u00dfS\u00e1\u0000\u00e3\u0000\u00e5"+ + "T\u00e7U\u00e9V\u00eb\u0000\u00ed\u0000\u00ef\u0000\u00f1\u0000\u00f3"+ + "\u0000\u00f5\u0000\u00f7\u0000\u00f9W\u00fbX\u00fdY\u00ffZ\u0101\u0000"+ + "\u0103\u0000\u0105\u0000\u0107\u0000\u0109\u0000\u010b\u0000\u010d[\u010f"+ + "\u0000\u0111\\\u0113]\u0115^\u0117\u0000\u0119\u0000\u011b_\u011d`\u011f"+ + "\u0000\u0121a\u0123\u0000\u0125b\u0127c\u0129d\u012b\u0000\u012d\u0000"+ + "\u012f\u0000\u0131\u0000\u0133\u0000\u0135\u0000\u0137\u0000\u0139\u0000"+ + "\u013b\u0000\u013de\u013ff\u0141g\u0143\u0000\u0145\u0000\u0147\u0000"+ + "\u0149\u0000\u014b\u0000\u014d\u0000\u014fh\u0151i\u0153j\u0155\u0000"+ + "\u0157k\u0159l\u015bm\u015dn\u015f\u0000\u0161\u0000\u0163o\u0165p\u0167"+ + "q\u0169r\u016b\u0000\u016d\u0000\u016f\u0000\u0171\u0000\u0173\u0000\u0175"+ + "\u0000\u0177\u0000\u0179s\u017bt\u017du\u017f\u0000\u0181\u0000\u0183"+ + "\u0000\u0185\u0000\u0187v\u0189w\u018bx\u018d\u0000\u018fy\u0191\u0000"+ + "\u0193\u0000\u0195z\u0197\u0000\u0199\u0000\u019b\u0000\u019d\u0000\u019f"+ + "\u0000\u01a1{\u01a3|\u01a5}\u01a7\u0000\u01a9\u0000\u01ab\u0000\u01ad"+ + "~\u01af\u007f\u01b1\u0080\u01b3\u0000\u01b5\u0000\u01b7\u0081\u01b9\u0082"+ + "\u01bb\u0083\u01bd\u0000\u01bf\u0000\u01c1\u0000\u01c3\u0000\u01c5\u0000"+ + "\u01c7\u0000\u01c9\u0000\u01cb\u0000\u01cd\u0000\u01cf\u0000\u01d1\u0000"+ + "\u01d3\u0084\u01d5\u0085\u01d7\u0086\u0011\u0000\u0001\u0002\u0003\u0004"+ + "\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010$\u0002\u0000DDdd"+ + "\u0002\u0000IIii\u0002\u0000SSss\u0002\u0000EEee\u0002\u0000CCcc\u0002"+ + "\u0000TTtt\u0002\u0000RRrr\u0002\u0000OOoo\u0002\u0000PPpp\u0002\u0000"+ + "NNnn\u0002\u0000HHhh\u0002\u0000VVvv\u0002\u0000AAaa\u0002\u0000LLll\u0002"+ + "\u0000XXxx\u0002\u0000FFff\u0002\u0000MMmm\u0002\u0000GGgg\u0002\u0000"+ + "KKkk\u0002\u0000WWww\u0002\u0000UUuu\u0006\u0000\t\n\r\r //[[]]\u0002"+ + "\u0000\n\n\r\r\u0003\u0000\t\n\r\r \u0001\u000009\u0002\u0000AZaz\b\u0000"+ + "\"\"NNRRTT\\\\nnrrtt\u0004\u0000\n\n\r\r\"\"\\\\\u0002\u0000++--\u0001"+ + "\u0000``\u0002\u0000BBbb\u0002\u0000YYyy\u000b\u0000\t\n\r\r \"\",,/"+ + "/::==[[]]||\u0002\u0000**//\u000b\u0000\t\n\r\r \"#,,//::<<>?\\\\||\u0002"+ + "\u0000JJjj\u06b3\u0000\u0011\u0001\u0000\u0000\u0000\u0000\u0013\u0001"+ + "\u0000\u0000\u0000\u0000\u0015\u0001\u0000\u0000\u0000\u0000\u0017\u0001"+ + "\u0000\u0000\u0000\u0000\u0019\u0001\u0000\u0000\u0000\u0000\u001b\u0001"+ + "\u0000\u0000\u0000\u0000\u001d\u0001\u0000\u0000\u0000\u0000\u001f\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\u00001\u0001\u0000"+ + "\u0000\u0000\u00003\u0001\u0000\u0000\u0000\u00005\u0001\u0000\u0000\u0000"+ + "\u00007\u0001\u0000\u0000\u0000\u00009\u0001\u0000\u0000\u0000\u0000;"+ + "\u0001\u0000\u0000\u0000\u0000=\u0001\u0000\u0000\u0000\u0000?\u0001\u0000"+ + "\u0000\u0000\u0000A\u0001\u0000\u0000\u0000\u0000C\u0001\u0000\u0000\u0000"+ + "\u0000E\u0001\u0000\u0000\u0000\u0000G\u0001\u0000\u0000\u0000\u0001I"+ + "\u0001\u0000\u0000\u0000\u0001_\u0001\u0000\u0000\u0000\u0001a\u0001\u0000"+ + "\u0000\u0000\u0001c\u0001\u0000\u0000\u0000\u0001e\u0001\u0000\u0000\u0000"+ + "\u0001g\u0001\u0000\u0000\u0000\u0001i\u0001\u0000\u0000\u0000\u0001k"+ + "\u0001\u0000\u0000\u0000\u0001m\u0001\u0000\u0000\u0000\u0001o\u0001\u0000"+ + "\u0000\u0000\u0001q\u0001\u0000\u0000\u0000\u0001s\u0001\u0000\u0000\u0000"+ + "\u0001u\u0001\u0000\u0000\u0000\u0001w\u0001\u0000\u0000\u0000\u0001y"+ + "\u0001\u0000\u0000\u0000\u0001{\u0001\u0000\u0000\u0000\u0001}\u0001\u0000"+ + "\u0000\u0000\u0001\u007f\u0001\u0000\u0000\u0000\u0001\u0081\u0001\u0000"+ + "\u0000\u0000\u0001\u0083\u0001\u0000\u0000\u0000\u0001\u0085\u0001\u0000"+ + "\u0000\u0000\u0001\u0087\u0001\u0000\u0000\u0000\u0001\u0089\u0001\u0000"+ + "\u0000\u0000\u0001\u008b\u0001\u0000\u0000\u0000\u0001\u008d\u0001\u0000"+ + "\u0000\u0000\u0001\u008f\u0001\u0000\u0000\u0000\u0001\u0091\u0001\u0000"+ + "\u0000\u0000\u0001\u0093\u0001\u0000\u0000\u0000\u0001\u0095\u0001\u0000"+ + "\u0000\u0000\u0001\u0097\u0001\u0000\u0000\u0000\u0001\u0099\u0001\u0000"+ + "\u0000\u0000\u0001\u009b\u0001\u0000\u0000\u0000\u0001\u009d\u0001\u0000"+ + "\u0000\u0000\u0001\u009f\u0001\u0000\u0000\u0000\u0001\u00a1\u0001\u0000"+ + "\u0000\u0000\u0001\u00a3\u0001\u0000\u0000\u0000\u0001\u00a5\u0001\u0000"+ + "\u0000\u0000\u0001\u00a7\u0001\u0000\u0000\u0000\u0001\u00a9\u0001\u0000"+ + "\u0000\u0000\u0001\u00ab\u0001\u0000\u0000\u0000\u0001\u00ad\u0001\u0000"+ + "\u0000\u0000\u0001\u00af\u0001\u0000\u0000\u0000\u0001\u00b1\u0001\u0000"+ + "\u0000\u0000\u0001\u00b3\u0001\u0000\u0000\u0000\u0001\u00b5\u0001\u0000"+ + "\u0000\u0000\u0001\u00b7\u0001\u0000\u0000\u0000\u0001\u00b9\u0001\u0000"+ + "\u0000\u0000\u0001\u00bd\u0001\u0000\u0000\u0000\u0001\u00bf\u0001\u0000"+ + "\u0000\u0000\u0001\u00c1\u0001\u0000\u0000\u0000\u0001\u00c3\u0001\u0000"+ + "\u0000\u0000\u0002\u00c5\u0001\u0000\u0000\u0000\u0002\u00c7\u0001\u0000"+ + "\u0000\u0000\u0002\u00c9\u0001\u0000\u0000\u0000\u0002\u00cb\u0001\u0000"+ + "\u0000\u0000\u0002\u00cd\u0001\u0000\u0000\u0000\u0003\u00cf\u0001\u0000"+ + "\u0000\u0000\u0003\u00d1\u0001\u0000\u0000\u0000\u0003\u00d3\u0001\u0000"+ + "\u0000\u0000\u0003\u00d5\u0001\u0000\u0000\u0000\u0003\u00d7\u0001\u0000"+ + "\u0000\u0000\u0003\u00d9\u0001\u0000\u0000\u0000\u0003\u00db\u0001\u0000"+ + "\u0000\u0000\u0003\u00df\u0001\u0000\u0000\u0000\u0003\u00e1\u0001\u0000"+ + "\u0000\u0000\u0003\u00e3\u0001\u0000\u0000\u0000\u0003\u00e5\u0001\u0000"+ + "\u0000\u0000\u0003\u00e7\u0001\u0000\u0000\u0000\u0003\u00e9\u0001\u0000"+ + "\u0000\u0000\u0004\u00eb\u0001\u0000\u0000\u0000\u0004\u00ed\u0001\u0000"+ + "\u0000\u0000\u0004\u00ef\u0001\u0000\u0000\u0000\u0004\u00f1\u0001\u0000"+ + "\u0000\u0000\u0004\u00f3\u0001\u0000\u0000\u0000\u0004\u00f9\u0001\u0000"+ + "\u0000\u0000\u0004\u00fb\u0001\u0000\u0000\u0000\u0004\u00fd\u0001\u0000"+ + "\u0000\u0000\u0004\u00ff\u0001\u0000\u0000\u0000\u0005\u0101\u0001\u0000"+ + "\u0000\u0000\u0005\u0103\u0001\u0000\u0000\u0000\u0005\u0105\u0001\u0000"+ + "\u0000\u0000\u0005\u0107\u0001\u0000\u0000\u0000\u0005\u0109\u0001\u0000"+ + "\u0000\u0000\u0005\u010b\u0001\u0000\u0000\u0000\u0005\u010d\u0001\u0000"+ + "\u0000\u0000\u0005\u010f\u0001\u0000\u0000\u0000\u0005\u0111\u0001\u0000"+ + "\u0000\u0000\u0005\u0113\u0001\u0000\u0000\u0000\u0005\u0115\u0001\u0000"+ + "\u0000\u0000\u0006\u0117\u0001\u0000\u0000\u0000\u0006\u0119\u0001\u0000"+ + "\u0000\u0000\u0006\u011b\u0001\u0000\u0000\u0000\u0006\u011d\u0001\u0000"+ + "\u0000\u0000\u0006\u0121\u0001\u0000\u0000\u0000\u0006\u0123\u0001\u0000"+ + "\u0000\u0000\u0006\u0125\u0001\u0000\u0000\u0000\u0006\u0127\u0001\u0000"+ + "\u0000\u0000\u0006\u0129\u0001\u0000\u0000\u0000\u0007\u012b\u0001\u0000"+ + "\u0000\u0000\u0007\u012d\u0001\u0000\u0000\u0000\u0007\u012f\u0001\u0000"+ + "\u0000\u0000\u0007\u0131\u0001\u0000\u0000\u0000\u0007\u0133\u0001\u0000"+ + "\u0000\u0000\u0007\u0135\u0001\u0000\u0000\u0000\u0007\u0137\u0001\u0000"+ + "\u0000\u0000\u0007\u0139\u0001\u0000\u0000\u0000\u0007\u013b\u0001\u0000"+ + "\u0000\u0000\u0007\u013d\u0001\u0000\u0000\u0000\u0007\u013f\u0001\u0000"+ + "\u0000\u0000\u0007\u0141\u0001\u0000\u0000\u0000\b\u0143\u0001\u0000\u0000"+ + "\u0000\b\u0145\u0001\u0000\u0000\u0000\b\u0147\u0001\u0000\u0000\u0000"+ + "\b\u0149\u0001\u0000\u0000\u0000\b\u014b\u0001\u0000\u0000\u0000\b\u014d"+ + "\u0001\u0000\u0000\u0000\b\u014f\u0001\u0000\u0000\u0000\b\u0151\u0001"+ + "\u0000\u0000\u0000\b\u0153\u0001\u0000\u0000\u0000\t\u0155\u0001\u0000"+ + "\u0000\u0000\t\u0157\u0001\u0000\u0000\u0000\t\u0159\u0001\u0000\u0000"+ + "\u0000\t\u015b\u0001\u0000\u0000\u0000\t\u015d\u0001\u0000\u0000\u0000"+ + "\n\u015f\u0001\u0000\u0000\u0000\n\u0161\u0001\u0000\u0000\u0000\n\u0163"+ + "\u0001\u0000\u0000\u0000\n\u0165\u0001\u0000\u0000\u0000\n\u0167\u0001"+ + "\u0000\u0000\u0000\n\u0169\u0001\u0000\u0000\u0000\u000b\u016b\u0001\u0000"+ + "\u0000\u0000\u000b\u016d\u0001\u0000\u0000\u0000\u000b\u016f\u0001\u0000"+ + "\u0000\u0000\u000b\u0171\u0001\u0000\u0000\u0000\u000b\u0173\u0001\u0000"+ + "\u0000\u0000\u000b\u0175\u0001\u0000\u0000\u0000\u000b\u0177\u0001\u0000"+ + "\u0000\u0000\u000b\u0179\u0001\u0000\u0000\u0000\u000b\u017b\u0001\u0000"+ + "\u0000\u0000\u000b\u017d\u0001\u0000\u0000\u0000\f\u017f\u0001\u0000\u0000"+ + "\u0000\f\u0181\u0001\u0000\u0000\u0000\f\u0183\u0001\u0000\u0000\u0000"+ + "\f\u0185\u0001\u0000\u0000\u0000\f\u0187\u0001\u0000\u0000\u0000\f\u0189"+ + "\u0001\u0000\u0000\u0000\f\u018b\u0001\u0000\u0000\u0000\r\u018d\u0001"+ + "\u0000\u0000\u0000\r\u018f\u0001\u0000\u0000\u0000\r\u0191\u0001\u0000"+ + "\u0000\u0000\r\u0193\u0001\u0000\u0000\u0000\r\u0195\u0001\u0000\u0000"+ + "\u0000\r\u0197\u0001\u0000\u0000\u0000\r\u0199\u0001\u0000\u0000\u0000"+ + "\r\u019b\u0001\u0000\u0000\u0000\r\u019d\u0001\u0000\u0000\u0000\r\u019f"+ + "\u0001\u0000\u0000\u0000\r\u01a1\u0001\u0000\u0000\u0000\r\u01a3\u0001"+ + "\u0000\u0000\u0000\r\u01a5\u0001\u0000\u0000\u0000\u000e\u01a7\u0001\u0000"+ + "\u0000\u0000\u000e\u01a9\u0001\u0000\u0000\u0000\u000e\u01ab\u0001\u0000"+ + "\u0000\u0000\u000e\u01ad\u0001\u0000\u0000\u0000\u000e\u01af\u0001\u0000"+ + "\u0000\u0000\u000e\u01b1\u0001\u0000\u0000\u0000\u000f\u01b3\u0001\u0000"+ + "\u0000\u0000\u000f\u01b5\u0001\u0000\u0000\u0000\u000f\u01b7\u0001\u0000"+ + "\u0000\u0000\u000f\u01b9\u0001\u0000\u0000\u0000\u000f\u01bb\u0001\u0000"+ + "\u0000\u0000\u000f\u01bd\u0001\u0000\u0000\u0000\u000f\u01bf\u0001\u0000"+ + "\u0000\u0000\u000f\u01c1\u0001\u0000\u0000\u0000\u000f\u01c3\u0001\u0000"+ + "\u0000\u0000\u0010\u01c5\u0001\u0000\u0000\u0000\u0010\u01c7\u0001\u0000"+ + "\u0000\u0000\u0010\u01c9\u0001\u0000\u0000\u0000\u0010\u01cb\u0001\u0000"+ + "\u0000\u0000\u0010\u01cd\u0001\u0000\u0000\u0000\u0010\u01cf\u0001\u0000"+ + "\u0000\u0000\u0010\u01d1\u0001\u0000\u0000\u0000\u0010\u01d3\u0001\u0000"+ + "\u0000\u0000\u0010\u01d5\u0001\u0000\u0000\u0000\u0010\u01d7\u0001\u0000"+ + "\u0000\u0000\u0011\u01d9\u0001\u0000\u0000\u0000\u0013\u01e3\u0001\u0000"+ + "\u0000\u0000\u0015\u01ea\u0001\u0000\u0000\u0000\u0017\u01f3\u0001\u0000"+ + "\u0000\u0000\u0019\u01fa\u0001\u0000\u0000\u0000\u001b\u0204\u0001\u0000"+ + "\u0000\u0000\u001d\u020b\u0001\u0000\u0000\u0000\u001f\u0212\u0001\u0000"+ + "\u0000\u0000!\u0219\u0001\u0000\u0000\u0000#\u0221\u0001\u0000\u0000\u0000"+ + "%\u022d\u0001\u0000\u0000\u0000\'\u0236\u0001\u0000\u0000\u0000)\u023c"+ + "\u0001\u0000\u0000\u0000+\u0243\u0001\u0000\u0000\u0000-\u024a\u0001\u0000"+ + "\u0000\u0000/\u0252\u0001\u0000\u0000\u00001\u025a\u0001\u0000\u0000\u0000"+ + "3\u0263\u0001\u0000\u0000\u00005\u0273\u0001\u0000\u0000\u00007\u0282"+ + "\u0001\u0000\u0000\u00009\u028e\u0001\u0000\u0000\u0000;\u0299\u0001\u0000"+ + "\u0000\u0000=\u02a1\u0001\u0000\u0000\u0000?\u02a9\u0001\u0000\u0000\u0000"+ + "A\u02b3\u0001\u0000\u0000\u0000C\u02b9\u0001\u0000\u0000\u0000E\u02ca"+ + "\u0001\u0000\u0000\u0000G\u02da\u0001\u0000\u0000\u0000I\u02e0\u0001\u0000"+ + "\u0000\u0000K\u02e4\u0001\u0000\u0000\u0000M\u02e6\u0001\u0000\u0000\u0000"+ + "O\u02e8\u0001\u0000\u0000\u0000Q\u02eb\u0001\u0000\u0000\u0000S\u02ed"+ + "\u0001\u0000\u0000\u0000U\u02f6\u0001\u0000\u0000\u0000W\u02f8\u0001\u0000"+ + "\u0000\u0000Y\u02fd\u0001\u0000\u0000\u0000[\u02ff\u0001\u0000\u0000\u0000"+ + "]\u0304\u0001\u0000\u0000\u0000_\u0323\u0001\u0000\u0000\u0000a\u0326"+ + "\u0001\u0000\u0000\u0000c\u0354\u0001\u0000\u0000\u0000e\u0356\u0001\u0000"+ + "\u0000\u0000g\u0359\u0001\u0000\u0000\u0000i\u035d\u0001\u0000\u0000\u0000"+ + "k\u0361\u0001\u0000\u0000\u0000m\u0363\u0001\u0000\u0000\u0000o\u0366"+ + "\u0001\u0000\u0000\u0000q\u0368\u0001\u0000\u0000\u0000s\u036a\u0001\u0000"+ + "\u0000\u0000u\u036f\u0001\u0000\u0000\u0000w\u0371\u0001\u0000\u0000\u0000"+ + "y\u0377\u0001\u0000\u0000\u0000{\u037d\u0001\u0000\u0000\u0000}\u0380"+ + "\u0001\u0000\u0000\u0000\u007f\u0383\u0001\u0000\u0000\u0000\u0081\u0388"+ + "\u0001\u0000\u0000\u0000\u0083\u038d\u0001\u0000\u0000\u0000\u0085\u038f"+ + "\u0001\u0000\u0000\u0000\u0087\u0393\u0001\u0000\u0000\u0000\u0089\u0398"+ + "\u0001\u0000\u0000\u0000\u008b\u039e\u0001\u0000\u0000\u0000\u008d\u03a1"+ + "\u0001\u0000\u0000\u0000\u008f\u03a3\u0001\u0000\u0000\u0000\u0091\u03a9"+ + "\u0001\u0000\u0000\u0000\u0093\u03ab\u0001\u0000\u0000\u0000\u0095\u03b0"+ + "\u0001\u0000\u0000\u0000\u0097\u03b3\u0001\u0000\u0000\u0000\u0099\u03b6"+ + "\u0001\u0000\u0000\u0000\u009b\u03b9\u0001\u0000\u0000\u0000\u009d\u03bb"+ + "\u0001\u0000\u0000\u0000\u009f\u03be\u0001\u0000\u0000\u0000\u00a1\u03c0"+ + "\u0001\u0000\u0000\u0000\u00a3\u03c3\u0001\u0000\u0000\u0000\u00a5\u03c5"+ + "\u0001\u0000\u0000\u0000\u00a7\u03c7\u0001\u0000\u0000\u0000\u00a9\u03c9"+ + "\u0001\u0000\u0000\u0000\u00ab\u03cb\u0001\u0000\u0000\u0000\u00ad\u03cd"+ + "\u0001\u0000\u0000\u0000\u00af\u03cf\u0001\u0000\u0000\u0000\u00b1\u03d1"+ + "\u0001\u0000\u0000\u0000\u00b3\u03e6\u0001\u0000\u0000\u0000\u00b5\u03e8"+ + "\u0001\u0000\u0000\u0000\u00b7\u03ed\u0001\u0000\u0000\u0000\u00b9\u0402"+ + "\u0001\u0000\u0000\u0000\u00bb\u0404\u0001\u0000\u0000\u0000\u00bd\u040c"+ + "\u0001\u0000\u0000\u0000\u00bf\u040e\u0001\u0000\u0000\u0000\u00c1\u0412"+ + "\u0001\u0000\u0000\u0000\u00c3\u0416\u0001\u0000\u0000\u0000\u00c5\u041a"+ + "\u0001\u0000\u0000\u0000\u00c7\u041f\u0001\u0000\u0000\u0000\u00c9\u0424"+ + "\u0001\u0000\u0000\u0000\u00cb\u0428\u0001\u0000\u0000\u0000\u00cd\u042c"+ + "\u0001\u0000\u0000\u0000\u00cf\u0430\u0001\u0000\u0000\u0000\u00d1\u0435"+ + "\u0001\u0000\u0000\u0000\u00d3\u0439\u0001\u0000\u0000\u0000\u00d5\u043d"+ + "\u0001\u0000\u0000\u0000\u00d7\u0441\u0001\u0000\u0000\u0000\u00d9\u0445"+ + "\u0001\u0000\u0000\u0000\u00db\u0449\u0001\u0000\u0000\u0000\u00dd\u0455"+ + "\u0001\u0000\u0000\u0000\u00df\u0458\u0001\u0000\u0000\u0000\u00e1\u045c"+ + "\u0001\u0000\u0000\u0000\u00e3\u0460\u0001\u0000\u0000\u0000\u00e5\u0464"+ + "\u0001\u0000\u0000\u0000\u00e7\u0468\u0001\u0000\u0000\u0000\u00e9\u046c"+ + "\u0001\u0000\u0000\u0000\u00eb\u0470\u0001\u0000\u0000\u0000\u00ed\u0475"+ + "\u0001\u0000\u0000\u0000\u00ef\u0479\u0001\u0000\u0000\u0000\u00f1\u047d"+ + "\u0001\u0000\u0000\u0000\u00f3\u0481\u0001\u0000\u0000\u0000\u00f5\u0489"+ + "\u0001\u0000\u0000\u0000\u00f7\u049e\u0001\u0000\u0000\u0000\u00f9\u04a2"+ + "\u0001\u0000\u0000\u0000\u00fb\u04a6\u0001\u0000\u0000\u0000\u00fd\u04aa"+ + "\u0001\u0000\u0000\u0000\u00ff\u04ae\u0001\u0000\u0000\u0000\u0101\u04b2"+ + "\u0001\u0000\u0000\u0000\u0103\u04b7\u0001\u0000\u0000\u0000\u0105\u04bb"+ + "\u0001\u0000\u0000\u0000\u0107\u04bf\u0001\u0000\u0000\u0000\u0109\u04c3"+ + "\u0001\u0000\u0000\u0000\u010b\u04c7\u0001\u0000\u0000\u0000\u010d\u04cb"+ + "\u0001\u0000\u0000\u0000\u010f\u04ce\u0001\u0000\u0000\u0000\u0111\u04d2"+ + "\u0001\u0000\u0000\u0000\u0113\u04d6\u0001\u0000\u0000\u0000\u0115\u04da"+ + "\u0001\u0000\u0000\u0000\u0117\u04de\u0001\u0000\u0000\u0000\u0119\u04e3"+ + "\u0001\u0000\u0000\u0000\u011b\u04e8\u0001\u0000\u0000\u0000\u011d\u04ed"+ + "\u0001\u0000\u0000\u0000\u011f\u04f4\u0001\u0000\u0000\u0000\u0121\u04fd"+ + "\u0001\u0000\u0000\u0000\u0123\u0504\u0001\u0000\u0000\u0000\u0125\u0508"+ + "\u0001\u0000\u0000\u0000\u0127\u050c\u0001\u0000\u0000\u0000\u0129\u0510"+ + "\u0001\u0000\u0000\u0000\u012b\u0514\u0001\u0000\u0000\u0000\u012d\u051a"+ + "\u0001\u0000\u0000\u0000\u012f\u051e\u0001\u0000\u0000\u0000\u0131\u0522"+ + "\u0001\u0000\u0000\u0000\u0133\u0526\u0001\u0000\u0000\u0000\u0135\u052a"+ + "\u0001\u0000\u0000\u0000\u0137\u052e\u0001\u0000\u0000\u0000\u0139\u0532"+ + "\u0001\u0000\u0000\u0000\u013b\u0536\u0001\u0000\u0000\u0000\u013d\u053a"+ + "\u0001\u0000\u0000\u0000\u013f\u053e\u0001\u0000\u0000\u0000\u0141\u0542"+ + "\u0001\u0000\u0000\u0000\u0143\u0546\u0001\u0000\u0000\u0000\u0145\u054b"+ + "\u0001\u0000\u0000\u0000\u0147\u054f\u0001\u0000\u0000\u0000\u0149\u0553"+ + "\u0001\u0000\u0000\u0000\u014b\u0557\u0001\u0000\u0000\u0000\u014d\u055b"+ + "\u0001\u0000\u0000\u0000\u014f\u055f\u0001\u0000\u0000\u0000\u0151\u0563"+ + "\u0001\u0000\u0000\u0000\u0153\u0567\u0001\u0000\u0000\u0000\u0155\u056b"+ + "\u0001\u0000\u0000\u0000\u0157\u0570\u0001\u0000\u0000\u0000\u0159\u0575"+ + "\u0001\u0000\u0000\u0000\u015b\u0579\u0001\u0000\u0000\u0000\u015d\u057d"+ + "\u0001\u0000\u0000\u0000\u015f\u0581\u0001\u0000\u0000\u0000\u0161\u0586"+ + "\u0001\u0000\u0000\u0000\u0163\u058f\u0001\u0000\u0000\u0000\u0165\u0593"+ + "\u0001\u0000\u0000\u0000\u0167\u0597\u0001\u0000\u0000\u0000\u0169\u059b"+ + "\u0001\u0000\u0000\u0000\u016b\u059f\u0001\u0000\u0000\u0000\u016d\u05a4"+ + "\u0001\u0000\u0000\u0000\u016f\u05a8\u0001\u0000\u0000\u0000\u0171\u05ac"+ + "\u0001\u0000\u0000\u0000\u0173\u05b0\u0001\u0000\u0000\u0000\u0175\u05b5"+ + "\u0001\u0000\u0000\u0000\u0177\u05b9\u0001\u0000\u0000\u0000\u0179\u05bd"+ + "\u0001\u0000\u0000\u0000\u017b\u05c1\u0001\u0000\u0000\u0000\u017d\u05c5"+ + "\u0001\u0000\u0000\u0000\u017f\u05c9\u0001\u0000\u0000\u0000\u0181\u05cf"+ + "\u0001\u0000\u0000\u0000\u0183\u05d3\u0001\u0000\u0000\u0000\u0185\u05d7"+ + "\u0001\u0000\u0000\u0000\u0187\u05db\u0001\u0000\u0000\u0000\u0189\u05df"+ + "\u0001\u0000\u0000\u0000\u018b\u05e3\u0001\u0000\u0000\u0000\u018d\u05e7"+ + "\u0001\u0000\u0000\u0000\u018f\u05ec\u0001\u0000\u0000\u0000\u0191\u05f1"+ + "\u0001\u0000\u0000\u0000\u0193\u05f5\u0001\u0000\u0000\u0000\u0195\u05fb"+ + "\u0001\u0000\u0000\u0000\u0197\u0604\u0001\u0000\u0000\u0000\u0199\u0608"+ + "\u0001\u0000\u0000\u0000\u019b\u060c\u0001\u0000\u0000\u0000\u019d\u0610"+ + "\u0001\u0000\u0000\u0000\u019f\u0614\u0001\u0000\u0000\u0000\u01a1\u0618"+ + "\u0001\u0000\u0000\u0000\u01a3\u061c\u0001\u0000\u0000\u0000\u01a5\u0620"+ + "\u0001\u0000\u0000\u0000\u01a7\u0624\u0001\u0000\u0000\u0000\u01a9\u0629"+ + "\u0001\u0000\u0000\u0000\u01ab\u062f\u0001\u0000\u0000\u0000\u01ad\u0635"+ + "\u0001\u0000\u0000\u0000\u01af\u0639\u0001\u0000\u0000\u0000\u01b1\u063d"+ + "\u0001\u0000\u0000\u0000\u01b3\u0641\u0001\u0000\u0000\u0000\u01b5\u0647"+ + "\u0001\u0000\u0000\u0000\u01b7\u064d\u0001\u0000\u0000\u0000\u01b9\u0651"+ + "\u0001\u0000\u0000\u0000\u01bb\u0655\u0001\u0000\u0000\u0000\u01bd\u0659"+ + "\u0001\u0000\u0000\u0000\u01bf\u065f\u0001\u0000\u0000\u0000\u01c1\u0665"+ + "\u0001\u0000\u0000\u0000\u01c3\u066b\u0001\u0000\u0000\u0000\u01c5\u0670"+ + "\u0001\u0000\u0000\u0000\u01c7\u0675\u0001\u0000\u0000\u0000\u01c9\u0679"+ + "\u0001\u0000\u0000\u0000\u01cb\u067d\u0001\u0000\u0000\u0000\u01cd\u0681"+ + "\u0001\u0000\u0000\u0000\u01cf\u0685\u0001\u0000\u0000\u0000\u01d1\u0689"+ + "\u0001\u0000\u0000\u0000\u01d3\u068d\u0001\u0000\u0000\u0000\u01d5\u0691"+ + "\u0001\u0000\u0000\u0000\u01d7\u0695\u0001\u0000\u0000\u0000\u01d9\u01da"+ + "\u0007\u0000\u0000\u0000\u01da\u01db\u0007\u0001\u0000\u0000\u01db\u01dc"+ + "\u0007\u0002\u0000\u0000\u01dc\u01dd\u0007\u0002\u0000\u0000\u01dd\u01de"+ + "\u0007\u0003\u0000\u0000\u01de\u01df\u0007\u0004\u0000\u0000\u01df\u01e0"+ + "\u0007\u0005\u0000\u0000\u01e0\u01e1\u0001\u0000\u0000\u0000\u01e1\u01e2"+ + "\u0006\u0000\u0000\u0000\u01e2\u0012\u0001\u0000\u0000\u0000\u01e3\u01e4"+ + "\u0007\u0000\u0000\u0000\u01e4\u01e5\u0007\u0006\u0000\u0000\u01e5\u01e6"+ + "\u0007\u0007\u0000\u0000\u01e6\u01e7\u0007\b\u0000\u0000\u01e7\u01e8\u0001"+ + "\u0000\u0000\u0000\u01e8\u01e9\u0006\u0001\u0001\u0000\u01e9\u0014\u0001"+ + "\u0000\u0000\u0000\u01ea\u01eb\u0007\u0003\u0000\u0000\u01eb\u01ec\u0007"+ + "\t\u0000\u0000\u01ec\u01ed\u0007\u0006\u0000\u0000\u01ed\u01ee\u0007\u0001"+ + "\u0000\u0000\u01ee\u01ef\u0007\u0004\u0000\u0000\u01ef\u01f0\u0007\n\u0000"+ + "\u0000\u01f0\u01f1\u0001\u0000\u0000\u0000\u01f1\u01f2\u0006\u0002\u0002"+ + "\u0000\u01f2\u0016\u0001\u0000\u0000\u0000\u01f3\u01f4\u0007\u0003\u0000"+ + "\u0000\u01f4\u01f5\u0007\u000b\u0000\u0000\u01f5\u01f6\u0007\f\u0000\u0000"+ + "\u01f6\u01f7\u0007\r\u0000\u0000\u01f7\u01f8\u0001\u0000\u0000\u0000\u01f8"+ + "\u01f9\u0006\u0003\u0000\u0000\u01f9\u0018\u0001\u0000\u0000\u0000\u01fa"+ + "\u01fb\u0007\u0003\u0000\u0000\u01fb\u01fc\u0007\u000e\u0000\u0000\u01fc"+ + "\u01fd\u0007\b\u0000\u0000\u01fd\u01fe\u0007\r\u0000\u0000\u01fe\u01ff"+ + "\u0007\f\u0000\u0000\u01ff\u0200\u0007\u0001\u0000\u0000\u0200\u0201\u0007"+ + "\t\u0000\u0000\u0201\u0202\u0001\u0000\u0000\u0000\u0202\u0203\u0006\u0004"+ + "\u0003\u0000\u0203\u001a\u0001\u0000\u0000\u0000\u0204\u0205\u0007\u000f"+ + "\u0000\u0000\u0205\u0206\u0007\u0006\u0000\u0000\u0206\u0207\u0007\u0007"+ + "\u0000\u0000\u0207\u0208\u0007\u0010\u0000\u0000\u0208\u0209\u0001\u0000"+ + "\u0000\u0000\u0209\u020a\u0006\u0005\u0004\u0000\u020a\u001c\u0001\u0000"+ + "\u0000\u0000\u020b\u020c\u0007\u0011\u0000\u0000\u020c\u020d\u0007\u0006"+ + "\u0000\u0000\u020d\u020e\u0007\u0007\u0000\u0000\u020e\u020f\u0007\u0012"+ + "\u0000\u0000\u020f\u0210\u0001\u0000\u0000\u0000\u0210\u0211\u0006\u0006"+ + "\u0000\u0000\u0211\u001e\u0001\u0000\u0000\u0000\u0212\u0213\u0007\u0012"+ + "\u0000\u0000\u0213\u0214\u0007\u0003\u0000\u0000\u0214\u0215\u0007\u0003"+ + "\u0000\u0000\u0215\u0216\u0007\b\u0000\u0000\u0216\u0217\u0001\u0000\u0000"+ + "\u0000\u0217\u0218\u0006\u0007\u0001\u0000\u0218 \u0001\u0000\u0000\u0000"+ + "\u0219\u021a\u0007\r\u0000\u0000\u021a\u021b\u0007\u0001\u0000\u0000\u021b"+ + "\u021c\u0007\u0010\u0000\u0000\u021c\u021d\u0007\u0001\u0000\u0000\u021d"+ + "\u021e\u0007\u0005\u0000\u0000\u021e\u021f\u0001\u0000\u0000\u0000\u021f"+ + "\u0220\u0006\b\u0000\u0000\u0220\"\u0001\u0000\u0000\u0000\u0221\u0222"+ + "\u0007\u0010\u0000\u0000\u0222\u0223\u0007\u000b\u0000\u0000\u0223\u0224"+ + "\u0005_\u0000\u0000\u0224\u0225\u0007\u0003\u0000\u0000\u0225\u0226\u0007"+ + "\u000e\u0000\u0000\u0226\u0227\u0007\b\u0000\u0000\u0227\u0228\u0007\f"+ + "\u0000\u0000\u0228\u0229\u0007\t\u0000\u0000\u0229\u022a\u0007\u0000\u0000"+ + "\u0000\u022a\u022b\u0001\u0000\u0000\u0000\u022b\u022c\u0006\t\u0005\u0000"+ + "\u022c$\u0001\u0000\u0000\u0000\u022d\u022e\u0007\u0006\u0000\u0000\u022e"+ + "\u022f\u0007\u0003\u0000\u0000\u022f\u0230\u0007\t\u0000\u0000\u0230\u0231"+ + "\u0007\f\u0000\u0000\u0231\u0232\u0007\u0010\u0000\u0000\u0232\u0233\u0007"+ + "\u0003\u0000\u0000\u0233\u0234\u0001\u0000\u0000\u0000\u0234\u0235\u0006"+ + "\n\u0006\u0000\u0235&\u0001\u0000\u0000\u0000\u0236\u0237\u0007\u0006"+ + "\u0000\u0000\u0237\u0238\u0007\u0007\u0000\u0000\u0238\u0239\u0007\u0013"+ + "\u0000\u0000\u0239\u023a\u0001\u0000\u0000\u0000\u023a\u023b\u0006\u000b"+ + "\u0000\u0000\u023b(\u0001\u0000\u0000\u0000\u023c\u023d\u0007\u0002\u0000"+ + "\u0000\u023d\u023e\u0007\n\u0000\u0000\u023e\u023f\u0007\u0007\u0000\u0000"+ + "\u023f\u0240\u0007\u0013\u0000\u0000\u0240\u0241\u0001\u0000\u0000\u0000"+ + "\u0241\u0242\u0006\f\u0007\u0000\u0242*\u0001\u0000\u0000\u0000\u0243"+ + "\u0244\u0007\u0002\u0000\u0000\u0244\u0245\u0007\u0007\u0000\u0000\u0245"+ + "\u0246\u0007\u0006\u0000\u0000\u0246\u0247\u0007\u0005\u0000\u0000\u0247"+ + "\u0248\u0001\u0000\u0000\u0000\u0248\u0249\u0006\r\u0000\u0000\u0249,"+ + "\u0001\u0000\u0000\u0000\u024a\u024b\u0007\u0002\u0000\u0000\u024b\u024c"+ + "\u0007\u0005\u0000\u0000\u024c\u024d\u0007\f\u0000\u0000\u024d\u024e\u0007"+ + "\u0005\u0000\u0000\u024e\u024f\u0007\u0002\u0000\u0000\u024f\u0250\u0001"+ + "\u0000\u0000\u0000\u0250\u0251\u0006\u000e\u0000\u0000\u0251.\u0001\u0000"+ + "\u0000\u0000\u0252\u0253\u0007\u0013\u0000\u0000\u0253\u0254\u0007\n\u0000"+ + "\u0000\u0254\u0255\u0007\u0003\u0000\u0000\u0255\u0256\u0007\u0006\u0000"+ + "\u0000\u0256\u0257\u0007\u0003\u0000\u0000\u0257\u0258\u0001\u0000\u0000"+ + "\u0000\u0258\u0259\u0006\u000f\u0000\u0000\u02590\u0001\u0000\u0000\u0000"+ + "\u025a\u025b\u0007\r\u0000\u0000\u025b\u025c\u0007\u0007\u0000\u0000\u025c"+ + "\u025d\u0007\u0007\u0000\u0000\u025d\u025e\u0007\u0012\u0000\u0000\u025e"+ + "\u025f\u0007\u0014\u0000\u0000\u025f\u0260\u0007\b\u0000\u0000\u0260\u0261"+ + "\u0001\u0000\u0000\u0000\u0261\u0262\u0006\u0010\b\u0000\u02622\u0001"+ + "\u0000\u0000\u0000\u0263\u0264\u0004\u0011\u0000\u0000\u0264\u0265\u0007"+ + "\u0004\u0000\u0000\u0265\u0266\u0007\n\u0000\u0000\u0266\u0267\u0007\f"+ + "\u0000\u0000\u0267\u0268\u0007\t\u0000\u0000\u0268\u0269\u0007\u0011\u0000"+ + "\u0000\u0269\u026a\u0007\u0003\u0000\u0000\u026a\u026b\u0005_\u0000\u0000"+ + "\u026b\u026c\u0007\b\u0000\u0000\u026c\u026d\u0007\u0007\u0000\u0000\u026d"+ + "\u026e\u0007\u0001\u0000\u0000\u026e\u026f\u0007\t\u0000\u0000\u026f\u0270"+ + "\u0007\u0005\u0000\u0000\u0270\u0271\u0001\u0000\u0000\u0000\u0271\u0272"+ + "\u0006\u0011\t\u0000\u02724\u0001\u0000\u0000\u0000\u0273\u0274\u0004"+ + "\u0012\u0001\u0000\u0274\u0275\u0007\u0001\u0000\u0000\u0275\u0276\u0007"+ + "\t\u0000\u0000\u0276\u0277\u0007\r\u0000\u0000\u0277\u0278\u0007\u0001"+ + "\u0000\u0000\u0278\u0279\u0007\t\u0000\u0000\u0279\u027a\u0007\u0003\u0000"+ + "\u0000\u027a\u027b\u0007\u0002\u0000\u0000\u027b\u027c\u0007\u0005\u0000"+ + "\u0000\u027c\u027d\u0007\f\u0000\u0000\u027d\u027e\u0007\u0005\u0000\u0000"+ + "\u027e\u027f\u0007\u0002\u0000\u0000\u027f\u0280\u0001\u0000\u0000\u0000"+ + "\u0280\u0281\u0006\u0012\u0000\u0000\u02816\u0001\u0000\u0000\u0000\u0282"+ + "\u0283\u0004\u0013\u0002\u0000\u0283\u0284\u0007\r\u0000\u0000\u0284\u0285"+ + "\u0007\u0007\u0000\u0000\u0285\u0286\u0007\u0007\u0000\u0000\u0286\u0287"+ + "\u0007\u0012\u0000\u0000\u0287\u0288\u0007\u0014\u0000\u0000\u0288\u0289"+ + "\u0007\b\u0000\u0000\u0289\u028a\u0005_\u0000\u0000\u028a\u028b\u0005"+ + "\u8001\uf414\u0000\u0000\u028b\u028c\u0001\u0000\u0000\u0000\u028c\u028d"+ + "\u0006\u0013\n\u0000\u028d8\u0001\u0000\u0000\u0000\u028e\u028f\u0004"+ + "\u0014\u0003\u0000\u028f\u0290\u0007\u0010\u0000\u0000\u0290\u0291\u0007"+ + "\u0003\u0000\u0000\u0291\u0292\u0007\u0005\u0000\u0000\u0292\u0293\u0007"+ + "\u0006\u0000\u0000\u0293\u0294\u0007\u0001\u0000\u0000\u0294\u0295\u0007"+ + "\u0004\u0000\u0000\u0295\u0296\u0007\u0002\u0000\u0000\u0296\u0297\u0001"+ + "\u0000\u0000\u0000\u0297\u0298\u0006\u0014\u000b\u0000\u0298:\u0001\u0000"+ + "\u0000\u0000\u0299\u029a\u0004\u0015\u0004\u0000\u029a\u029b\u0007\u000f"+ + "\u0000\u0000\u029b\u029c\u0007\u0014\u0000\u0000\u029c\u029d\u0007\r\u0000"+ + "\u0000\u029d\u029e\u0007\r\u0000\u0000\u029e\u029f\u0001\u0000\u0000\u0000"+ + "\u029f\u02a0\u0006\u0015\b\u0000\u02a0<\u0001\u0000\u0000\u0000\u02a1"+ + "\u02a2\u0004\u0016\u0005\u0000\u02a2\u02a3\u0007\r\u0000\u0000\u02a3\u02a4"+ + "\u0007\u0003\u0000\u0000\u02a4\u02a5\u0007\u000f\u0000\u0000\u02a5\u02a6"+ + "\u0007\u0005\u0000\u0000\u02a6\u02a7\u0001\u0000\u0000\u0000\u02a7\u02a8"+ + "\u0006\u0016\b\u0000\u02a8>\u0001\u0000\u0000\u0000\u02a9\u02aa\u0004"+ + "\u0017\u0006\u0000\u02aa\u02ab\u0007\u0006\u0000\u0000\u02ab\u02ac\u0007"+ + "\u0001\u0000\u0000\u02ac\u02ad\u0007\u0011\u0000\u0000\u02ad\u02ae\u0007"+ + "\n\u0000\u0000\u02ae\u02af\u0007\u0005\u0000\u0000\u02af\u02b0\u0001\u0000"+ + "\u0000\u0000\u02b0\u02b1\u0006\u0017\b\u0000\u02b1@\u0001\u0000\u0000"+ + "\u0000\u02b2\u02b4\b\u0015\u0000\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\u02b7\u0001\u0000\u0000\u0000"+ + "\u02b7\u02b8\u0006\u0018\u0000\u0000\u02b8B\u0001\u0000\u0000\u0000\u02b9"+ + "\u02ba\u0005/\u0000\u0000\u02ba\u02bb\u0005/\u0000\u0000\u02bb\u02bf\u0001"+ + "\u0000\u0000\u0000\u02bc\u02be\b\u0016\u0000\u0000\u02bd\u02bc\u0001\u0000"+ + "\u0000\u0000\u02be\u02c1\u0001\u0000\u0000\u0000\u02bf\u02bd\u0001\u0000"+ + "\u0000\u0000\u02bf\u02c0\u0001\u0000\u0000\u0000\u02c0\u02c3\u0001\u0000"+ + "\u0000\u0000\u02c1\u02bf\u0001\u0000\u0000\u0000\u02c2\u02c4\u0005\r\u0000"+ + "\u0000\u02c3\u02c2\u0001\u0000\u0000\u0000\u02c3\u02c4\u0001\u0000\u0000"+ + "\u0000\u02c4\u02c6\u0001\u0000\u0000\u0000\u02c5\u02c7\u0005\n\u0000\u0000"+ + "\u02c6\u02c5\u0001\u0000\u0000\u0000\u02c6\u02c7\u0001\u0000\u0000\u0000"+ + "\u02c7\u02c8\u0001\u0000\u0000\u0000\u02c8\u02c9\u0006\u0019\f\u0000\u02c9"+ + "D\u0001\u0000\u0000\u0000\u02ca\u02cb\u0005/\u0000\u0000\u02cb\u02cc\u0005"+ + "*\u0000\u0000\u02cc\u02d1\u0001\u0000\u0000\u0000\u02cd\u02d0\u0003E\u001a"+ + "\u0000\u02ce\u02d0\t\u0000\u0000\u0000\u02cf\u02cd\u0001\u0000\u0000\u0000"+ + "\u02cf\u02ce\u0001\u0000\u0000\u0000\u02d0\u02d3\u0001\u0000\u0000\u0000"+ + "\u02d1\u02d2\u0001\u0000\u0000\u0000\u02d1\u02cf\u0001\u0000\u0000\u0000"+ + "\u02d2\u02d4\u0001\u0000\u0000\u0000\u02d3\u02d1\u0001\u0000\u0000\u0000"+ + "\u02d4\u02d5\u0005*\u0000\u0000\u02d5\u02d6\u0005/\u0000\u0000\u02d6\u02d7"+ + "\u0001\u0000\u0000\u0000\u02d7\u02d8\u0006\u001a\f\u0000\u02d8F\u0001"+ + "\u0000\u0000\u0000\u02d9\u02db\u0007\u0017\u0000\u0000\u02da\u02d9\u0001"+ + "\u0000\u0000\u0000\u02db\u02dc\u0001\u0000\u0000\u0000\u02dc\u02da\u0001"+ + "\u0000\u0000\u0000\u02dc\u02dd\u0001\u0000\u0000\u0000\u02dd\u02de\u0001"+ + "\u0000\u0000\u0000\u02de\u02df\u0006\u001b\f\u0000\u02dfH\u0001\u0000"+ + "\u0000\u0000\u02e0\u02e1\u0005|\u0000\u0000\u02e1\u02e2\u0001\u0000\u0000"+ + "\u0000\u02e2\u02e3\u0006\u001c\r\u0000\u02e3J\u0001\u0000\u0000\u0000"+ + "\u02e4\u02e5\u0007\u0018\u0000\u0000\u02e5L\u0001\u0000\u0000\u0000\u02e6"+ + "\u02e7\u0007\u0019\u0000\u0000\u02e7N\u0001\u0000\u0000\u0000\u02e8\u02e9"+ + "\u0005\\\u0000\u0000\u02e9\u02ea\u0007\u001a\u0000\u0000\u02eaP\u0001"+ + "\u0000\u0000\u0000\u02eb\u02ec\b\u001b\u0000\u0000\u02ecR\u0001\u0000"+ + "\u0000\u0000\u02ed\u02ef\u0007\u0003\u0000\u0000\u02ee\u02f0\u0007\u001c"+ + "\u0000\u0000\u02ef\u02ee\u0001\u0000\u0000\u0000\u02ef\u02f0\u0001\u0000"+ + "\u0000\u0000\u02f0\u02f2\u0001\u0000\u0000\u0000\u02f1\u02f3\u0003K\u001d"+ + "\u0000\u02f2\u02f1\u0001\u0000\u0000\u0000\u02f3\u02f4\u0001\u0000\u0000"+ + "\u0000\u02f4\u02f2\u0001\u0000\u0000\u0000\u02f4\u02f5\u0001\u0000\u0000"+ + "\u0000\u02f5T\u0001\u0000\u0000\u0000\u02f6\u02f7\u0005@\u0000\u0000\u02f7"+ + "V\u0001\u0000\u0000\u0000\u02f8\u02f9\u0005`\u0000\u0000\u02f9X\u0001"+ + "\u0000\u0000\u0000\u02fa\u02fe\b\u001d\u0000\u0000\u02fb\u02fc\u0005`"+ + "\u0000\u0000\u02fc\u02fe\u0005`\u0000\u0000\u02fd\u02fa\u0001\u0000\u0000"+ + "\u0000\u02fd\u02fb\u0001\u0000\u0000\u0000\u02feZ\u0001\u0000\u0000\u0000"+ + "\u02ff\u0300\u0005_\u0000\u0000\u0300\\\u0001\u0000\u0000\u0000\u0301"+ + "\u0305\u0003M\u001e\u0000\u0302\u0305\u0003K\u001d\u0000\u0303\u0305\u0003"+ + "[%\u0000\u0304\u0301\u0001\u0000\u0000\u0000\u0304\u0302\u0001\u0000\u0000"+ + "\u0000\u0304\u0303\u0001\u0000\u0000\u0000\u0305^\u0001\u0000\u0000\u0000"+ + "\u0306\u030b\u0005\"\u0000\u0000\u0307\u030a\u0003O\u001f\u0000\u0308"+ + "\u030a\u0003Q \u0000\u0309\u0307\u0001\u0000\u0000\u0000\u0309\u0308\u0001"+ + "\u0000\u0000\u0000\u030a\u030d\u0001\u0000\u0000\u0000\u030b\u0309\u0001"+ + "\u0000\u0000\u0000\u030b\u030c\u0001\u0000\u0000\u0000\u030c\u030e\u0001"+ + "\u0000\u0000\u0000\u030d\u030b\u0001\u0000\u0000\u0000\u030e\u0324\u0005"+ + "\"\u0000\u0000\u030f\u0310\u0005\"\u0000\u0000\u0310\u0311\u0005\"\u0000"+ + "\u0000\u0311\u0312\u0005\"\u0000\u0000\u0312\u0316\u0001\u0000\u0000\u0000"+ + "\u0313\u0315\b\u0016\u0000\u0000\u0314\u0313\u0001\u0000\u0000\u0000\u0315"+ + "\u0318\u0001\u0000\u0000\u0000\u0316\u0317\u0001\u0000\u0000\u0000\u0316"+ + "\u0314\u0001\u0000\u0000\u0000\u0317\u0319\u0001\u0000\u0000\u0000\u0318"+ + "\u0316\u0001\u0000\u0000\u0000\u0319\u031a\u0005\"\u0000\u0000\u031a\u031b"+ + "\u0005\"\u0000\u0000\u031b\u031c\u0005\"\u0000\u0000\u031c\u031e\u0001"+ + "\u0000\u0000\u0000\u031d\u031f\u0005\"\u0000\u0000\u031e\u031d\u0001\u0000"+ + "\u0000\u0000\u031e\u031f\u0001\u0000\u0000\u0000\u031f\u0321\u0001\u0000"+ + "\u0000\u0000\u0320\u0322\u0005\"\u0000\u0000\u0321\u0320\u0001\u0000\u0000"+ + "\u0000\u0321\u0322\u0001\u0000\u0000\u0000\u0322\u0324\u0001\u0000\u0000"+ + "\u0000\u0323\u0306\u0001\u0000\u0000\u0000\u0323\u030f\u0001\u0000\u0000"+ + "\u0000\u0324`\u0001\u0000\u0000\u0000\u0325\u0327\u0003K\u001d\u0000\u0326"+ + "\u0325\u0001\u0000\u0000\u0000\u0327\u0328\u0001\u0000\u0000\u0000\u0328"+ + "\u0326\u0001\u0000\u0000\u0000\u0328\u0329\u0001\u0000\u0000\u0000\u0329"+ + "b\u0001\u0000\u0000\u0000\u032a\u032c\u0003K\u001d\u0000\u032b\u032a\u0001"+ + "\u0000\u0000\u0000\u032c\u032d\u0001\u0000\u0000\u0000\u032d\u032b\u0001"+ + "\u0000\u0000\u0000\u032d\u032e\u0001\u0000\u0000\u0000\u032e\u032f\u0001"+ + "\u0000\u0000\u0000\u032f\u0333\u0003u2\u0000\u0330\u0332\u0003K\u001d"+ + "\u0000\u0331\u0330\u0001\u0000\u0000\u0000\u0332\u0335\u0001\u0000\u0000"+ + "\u0000\u0333\u0331\u0001\u0000\u0000\u0000\u0333\u0334\u0001\u0000\u0000"+ + "\u0000\u0334\u0355\u0001\u0000\u0000\u0000\u0335\u0333\u0001\u0000\u0000"+ + "\u0000\u0336\u0338\u0003u2\u0000\u0337\u0339\u0003K\u001d\u0000\u0338"+ + "\u0337\u0001\u0000\u0000\u0000\u0339\u033a\u0001\u0000\u0000\u0000\u033a"+ + "\u0338\u0001\u0000\u0000\u0000\u033a\u033b\u0001\u0000\u0000\u0000\u033b"+ + "\u0355\u0001\u0000\u0000\u0000\u033c\u033e\u0003K\u001d\u0000\u033d\u033c"+ + "\u0001\u0000\u0000\u0000\u033e\u033f\u0001\u0000\u0000\u0000\u033f\u033d"+ + "\u0001\u0000\u0000\u0000\u033f\u0340\u0001\u0000\u0000\u0000\u0340\u0348"+ + "\u0001\u0000\u0000\u0000\u0341\u0345\u0003u2\u0000\u0342\u0344\u0003K"+ + "\u001d\u0000\u0343\u0342\u0001\u0000\u0000\u0000\u0344\u0347\u0001\u0000"+ + "\u0000\u0000\u0345\u0343\u0001\u0000\u0000\u0000\u0345\u0346\u0001\u0000"+ + "\u0000\u0000\u0346\u0349\u0001\u0000\u0000\u0000\u0347\u0345\u0001\u0000"+ + "\u0000\u0000\u0348\u0341\u0001\u0000\u0000\u0000\u0348\u0349\u0001\u0000"+ + "\u0000\u0000\u0349\u034a\u0001\u0000\u0000\u0000\u034a\u034b\u0003S!\u0000"+ + "\u034b\u0355\u0001\u0000\u0000\u0000\u034c\u034e\u0003u2\u0000\u034d\u034f"+ + "\u0003K\u001d\u0000\u034e\u034d\u0001\u0000\u0000\u0000\u034f\u0350\u0001"+ + "\u0000\u0000\u0000\u0350\u034e\u0001\u0000\u0000\u0000\u0350\u0351\u0001"+ + "\u0000\u0000\u0000\u0351\u0352\u0001\u0000\u0000\u0000\u0352\u0353\u0003"+ + "S!\u0000\u0353\u0355\u0001\u0000\u0000\u0000\u0354\u032b\u0001\u0000\u0000"+ + "\u0000\u0354\u0336\u0001\u0000\u0000\u0000\u0354\u033d\u0001\u0000\u0000"+ + "\u0000\u0354\u034c\u0001\u0000\u0000\u0000\u0355d\u0001\u0000\u0000\u0000"+ + "\u0356\u0357\u0007\u001e\u0000\u0000\u0357\u0358\u0007\u001f\u0000\u0000"+ + "\u0358f\u0001\u0000\u0000\u0000\u0359\u035a\u0007\f\u0000\u0000\u035a"+ + "\u035b\u0007\t\u0000\u0000\u035b\u035c\u0007\u0000\u0000\u0000\u035ch"+ + "\u0001\u0000\u0000\u0000\u035d\u035e\u0007\f\u0000\u0000\u035e\u035f\u0007"+ + "\u0002\u0000\u0000\u035f\u0360\u0007\u0004\u0000\u0000\u0360j\u0001\u0000"+ + "\u0000\u0000\u0361\u0362\u0005=\u0000\u0000\u0362l\u0001\u0000\u0000\u0000"+ + "\u0363\u0364\u0005:\u0000\u0000\u0364\u0365\u0005:\u0000\u0000\u0365n"+ + "\u0001\u0000\u0000\u0000\u0366\u0367\u0005:\u0000\u0000\u0367p\u0001\u0000"+ + "\u0000\u0000\u0368\u0369\u0005,\u0000\u0000\u0369r\u0001\u0000\u0000\u0000"+ + "\u036a\u036b\u0007\u0000\u0000\u0000\u036b\u036c\u0007\u0003\u0000\u0000"+ + "\u036c\u036d\u0007\u0002\u0000\u0000\u036d\u036e\u0007\u0004\u0000\u0000"+ + "\u036et\u0001\u0000\u0000\u0000\u036f\u0370\u0005.\u0000\u0000\u0370v"+ + "\u0001\u0000\u0000\u0000\u0371\u0372\u0007\u000f\u0000\u0000\u0372\u0373"+ + "\u0007\f\u0000\u0000\u0373\u0374\u0007\r\u0000\u0000\u0374\u0375\u0007"+ + "\u0002\u0000\u0000\u0375\u0376\u0007\u0003\u0000\u0000\u0376x\u0001\u0000"+ + "\u0000\u0000\u0377\u0378\u0007\u000f\u0000\u0000\u0378\u0379\u0007\u0001"+ + "\u0000\u0000\u0379\u037a\u0007\u0006\u0000\u0000\u037a\u037b\u0007\u0002"+ + "\u0000\u0000\u037b\u037c\u0007\u0005\u0000\u0000\u037cz\u0001\u0000\u0000"+ + "\u0000\u037d\u037e\u0007\u0001\u0000\u0000\u037e\u037f\u0007\t\u0000\u0000"+ + "\u037f|\u0001\u0000\u0000\u0000\u0380\u0381\u0007\u0001\u0000\u0000\u0381"+ + "\u0382\u0007\u0002\u0000\u0000\u0382~\u0001\u0000\u0000\u0000\u0383\u0384"+ + "\u0007\r\u0000\u0000\u0384\u0385\u0007\f\u0000\u0000\u0385\u0386\u0007"+ + "\u0002\u0000\u0000\u0386\u0387\u0007\u0005\u0000\u0000\u0387\u0080\u0001"+ + "\u0000\u0000\u0000\u0388\u0389\u0007\r\u0000\u0000\u0389\u038a\u0007\u0001"+ + "\u0000\u0000\u038a\u038b\u0007\u0012\u0000\u0000\u038b\u038c\u0007\u0003"+ + "\u0000\u0000\u038c\u0082\u0001\u0000\u0000\u0000\u038d\u038e\u0005(\u0000"+ + "\u0000\u038e\u0084\u0001\u0000\u0000\u0000\u038f\u0390\u0007\t\u0000\u0000"+ + "\u0390\u0391\u0007\u0007\u0000\u0000\u0391\u0392\u0007\u0005\u0000\u0000"+ + "\u0392\u0086\u0001\u0000\u0000\u0000\u0393\u0394\u0007\t\u0000\u0000\u0394"+ + "\u0395\u0007\u0014\u0000\u0000\u0395\u0396\u0007\r\u0000\u0000\u0396\u0397"+ + "\u0007\r\u0000\u0000\u0397\u0088\u0001\u0000\u0000\u0000\u0398\u0399\u0007"+ + "\t\u0000\u0000\u0399\u039a\u0007\u0014\u0000\u0000\u039a\u039b\u0007\r"+ + "\u0000\u0000\u039b\u039c\u0007\r\u0000\u0000\u039c\u039d\u0007\u0002\u0000"+ + "\u0000\u039d\u008a\u0001\u0000\u0000\u0000\u039e\u039f\u0007\u0007\u0000"+ + "\u0000\u039f\u03a0\u0007\u0006\u0000\u0000\u03a0\u008c\u0001\u0000\u0000"+ + "\u0000\u03a1\u03a2\u0005?\u0000\u0000\u03a2\u008e\u0001\u0000\u0000\u0000"+ + "\u03a3\u03a4\u0007\u0006\u0000\u0000\u03a4\u03a5\u0007\r\u0000\u0000\u03a5"+ + "\u03a6\u0007\u0001\u0000\u0000\u03a6\u03a7\u0007\u0012\u0000\u0000\u03a7"+ + "\u03a8\u0007\u0003\u0000\u0000\u03a8\u0090\u0001\u0000\u0000\u0000\u03a9"+ + "\u03aa\u0005)\u0000\u0000\u03aa\u0092\u0001\u0000\u0000\u0000\u03ab\u03ac"+ + "\u0007\u0005\u0000\u0000\u03ac\u03ad\u0007\u0006\u0000\u0000\u03ad\u03ae"+ + "\u0007\u0014\u0000\u0000\u03ae\u03af\u0007\u0003\u0000\u0000\u03af\u0094"+ + "\u0001\u0000\u0000\u0000\u03b0\u03b1\u0005=\u0000\u0000\u03b1\u03b2\u0005"+ + "=\u0000\u0000\u03b2\u0096\u0001\u0000\u0000\u0000\u03b3\u03b4\u0005=\u0000"+ + "\u0000\u03b4\u03b5\u0005~\u0000\u0000\u03b5\u0098\u0001\u0000\u0000\u0000"+ + "\u03b6\u03b7\u0005!\u0000\u0000\u03b7\u03b8\u0005=\u0000\u0000\u03b8\u009a"+ + "\u0001\u0000\u0000\u0000\u03b9\u03ba\u0005<\u0000\u0000\u03ba\u009c\u0001"+ + "\u0000\u0000\u0000\u03bb\u03bc\u0005<\u0000\u0000\u03bc\u03bd\u0005=\u0000"+ + "\u0000\u03bd\u009e\u0001\u0000\u0000\u0000\u03be\u03bf\u0005>\u0000\u0000"+ + "\u03bf\u00a0\u0001\u0000\u0000\u0000\u03c0\u03c1\u0005>\u0000\u0000\u03c1"+ + "\u03c2\u0005=\u0000\u0000\u03c2\u00a2\u0001\u0000\u0000\u0000\u03c3\u03c4"+ + "\u0005+\u0000\u0000\u03c4\u00a4\u0001\u0000\u0000\u0000\u03c5\u03c6\u0005"+ + "-\u0000\u0000\u03c6\u00a6\u0001\u0000\u0000\u0000\u03c7\u03c8\u0005*\u0000"+ + "\u0000\u03c8\u00a8\u0001\u0000\u0000\u0000\u03c9\u03ca\u0005/\u0000\u0000"+ + "\u03ca\u00aa\u0001\u0000\u0000\u0000\u03cb\u03cc\u0005%\u0000\u0000\u03cc"+ + "\u00ac\u0001\u0000\u0000\u0000\u03cd\u03ce\u0005{\u0000\u0000\u03ce\u00ae"+ + "\u0001\u0000\u0000\u0000\u03cf\u03d0\u0005}\u0000\u0000\u03d0\u00b0\u0001"+ + "\u0000\u0000\u0000\u03d1\u03d2\u0003/\u000f\u0000\u03d2\u03d3\u0001\u0000"+ + "\u0000\u0000\u03d3\u03d4\u0006P\u000e\u0000\u03d4\u00b2\u0001\u0000\u0000"+ + "\u0000\u03d5\u03d8\u0003\u008d>\u0000\u03d6\u03d9\u0003M\u001e\u0000\u03d7"+ + "\u03d9\u0003[%\u0000\u03d8\u03d6\u0001\u0000\u0000\u0000\u03d8\u03d7\u0001"+ + "\u0000\u0000\u0000\u03d9\u03dd\u0001\u0000\u0000\u0000\u03da\u03dc\u0003"+ + "]&\u0000\u03db\u03da\u0001\u0000\u0000\u0000\u03dc\u03df\u0001\u0000\u0000"+ + "\u0000\u03dd\u03db\u0001\u0000\u0000\u0000\u03dd\u03de\u0001\u0000\u0000"+ + "\u0000\u03de\u03e7\u0001\u0000\u0000\u0000\u03df\u03dd\u0001\u0000\u0000"+ + "\u0000\u03e0\u03e2\u0003\u008d>\u0000\u03e1\u03e3\u0003K\u001d\u0000\u03e2"+ + "\u03e1\u0001\u0000\u0000\u0000\u03e3\u03e4\u0001\u0000\u0000\u0000\u03e4"+ + "\u03e2\u0001\u0000\u0000\u0000\u03e4\u03e5\u0001\u0000\u0000\u0000\u03e5"+ + "\u03e7\u0001\u0000\u0000\u0000\u03e6\u03d5\u0001\u0000\u0000\u0000\u03e6"+ + "\u03e0\u0001\u0000\u0000\u0000\u03e7\u00b4\u0001\u0000\u0000\u0000\u03e8"+ + "\u03e9\u0005[\u0000\u0000\u03e9\u03ea\u0001\u0000\u0000\u0000\u03ea\u03eb"+ + "\u0006R\u0000\u0000\u03eb\u03ec\u0006R\u0000\u0000\u03ec\u00b6\u0001\u0000"+ + "\u0000\u0000\u03ed\u03ee\u0005]\u0000\u0000\u03ee\u03ef\u0001\u0000\u0000"+ + "\u0000\u03ef\u03f0\u0006S\r\u0000\u03f0\u03f1\u0006S\r\u0000\u03f1\u00b8"+ + "\u0001\u0000\u0000\u0000\u03f2\u03f6\u0003M\u001e\u0000\u03f3\u03f5\u0003"+ + "]&\u0000\u03f4\u03f3\u0001\u0000\u0000\u0000\u03f5\u03f8\u0001\u0000\u0000"+ + "\u0000\u03f6\u03f4\u0001\u0000\u0000\u0000\u03f6\u03f7\u0001\u0000\u0000"+ + "\u0000\u03f7\u0403\u0001\u0000\u0000\u0000\u03f8\u03f6\u0001\u0000\u0000"+ + "\u0000\u03f9\u03fc\u0003[%\u0000\u03fa\u03fc\u0003U\"\u0000\u03fb\u03f9"+ + "\u0001\u0000\u0000\u0000\u03fb\u03fa\u0001\u0000\u0000\u0000\u03fc\u03fe"+ + "\u0001\u0000\u0000\u0000\u03fd\u03ff\u0003]&\u0000\u03fe\u03fd\u0001\u0000"+ + "\u0000\u0000\u03ff\u0400\u0001\u0000\u0000\u0000\u0400\u03fe\u0001\u0000"+ + "\u0000\u0000\u0400\u0401\u0001\u0000\u0000\u0000\u0401\u0403\u0001\u0000"+ + "\u0000\u0000\u0402\u03f2\u0001\u0000\u0000\u0000\u0402\u03fb\u0001\u0000"+ + "\u0000\u0000\u0403\u00ba\u0001\u0000\u0000\u0000\u0404\u0406\u0003W#\u0000"+ + "\u0405\u0407\u0003Y$\u0000\u0406\u0405\u0001\u0000\u0000\u0000\u0407\u0408"+ + "\u0001\u0000\u0000\u0000\u0408\u0406\u0001\u0000\u0000\u0000\u0408\u0409"+ + "\u0001\u0000\u0000\u0000\u0409\u040a\u0001\u0000\u0000\u0000\u040a\u040b"+ + "\u0003W#\u0000\u040b\u00bc\u0001\u0000\u0000\u0000\u040c\u040d\u0003\u00bb"+ + "U\u0000\u040d\u00be\u0001\u0000\u0000\u0000\u040e\u040f\u0003C\u0019\u0000"+ + "\u040f\u0410\u0001\u0000\u0000\u0000\u0410\u0411\u0006W\f\u0000\u0411"+ + "\u00c0\u0001\u0000\u0000\u0000\u0412\u0413\u0003E\u001a\u0000\u0413\u0414"+ + "\u0001\u0000\u0000\u0000\u0414\u0415\u0006X\f\u0000\u0415\u00c2\u0001"+ + "\u0000\u0000\u0000\u0416\u0417\u0003G\u001b\u0000\u0417\u0418\u0001\u0000"+ + "\u0000\u0000\u0418\u0419\u0006Y\f\u0000\u0419\u00c4\u0001\u0000\u0000"+ + "\u0000\u041a\u041b\u0003\u00b5R\u0000\u041b\u041c\u0001\u0000\u0000\u0000"+ + "\u041c\u041d\u0006Z\u000f\u0000\u041d\u041e\u0006Z\u0010\u0000\u041e\u00c6"+ + "\u0001\u0000\u0000\u0000\u041f\u0420\u0003I\u001c\u0000\u0420\u0421\u0001"+ + "\u0000\u0000\u0000\u0421\u0422\u0006[\u0011\u0000\u0422\u0423\u0006[\r"+ + "\u0000\u0423\u00c8\u0001\u0000\u0000\u0000\u0424\u0425\u0003G\u001b\u0000"+ + "\u0425\u0426\u0001\u0000\u0000\u0000\u0426\u0427\u0006\\\f\u0000\u0427"+ + "\u00ca\u0001\u0000\u0000\u0000\u0428\u0429\u0003C\u0019\u0000\u0429\u042a"+ + "\u0001\u0000\u0000\u0000\u042a\u042b\u0006]\f\u0000\u042b\u00cc\u0001"+ + "\u0000\u0000\u0000\u042c\u042d\u0003E\u001a\u0000\u042d\u042e\u0001\u0000"+ + "\u0000\u0000\u042e\u042f\u0006^\f\u0000\u042f\u00ce\u0001\u0000\u0000"+ + "\u0000\u0430\u0431\u0003I\u001c\u0000\u0431\u0432\u0001\u0000\u0000\u0000"+ + "\u0432\u0433\u0006_\u0011\u0000\u0433\u0434\u0006_\r\u0000\u0434\u00d0"+ + "\u0001\u0000\u0000\u0000\u0435\u0436\u0003\u00b5R\u0000\u0436\u0437\u0001"+ + "\u0000\u0000\u0000\u0437\u0438\u0006`\u000f\u0000\u0438\u00d2\u0001\u0000"+ + "\u0000\u0000\u0439\u043a\u0003\u00b7S\u0000\u043a\u043b\u0001\u0000\u0000"+ + "\u0000\u043b\u043c\u0006a\u0012\u0000\u043c\u00d4\u0001\u0000\u0000\u0000"+ + "\u043d\u043e\u0003o/\u0000\u043e\u043f\u0001\u0000\u0000\u0000\u043f\u0440"+ + "\u0006b\u0013\u0000\u0440\u00d6\u0001\u0000\u0000\u0000\u0441\u0442\u0003"+ + "q0\u0000\u0442\u0443\u0001\u0000\u0000\u0000\u0443\u0444\u0006c\u0014"+ + "\u0000\u0444\u00d8\u0001\u0000\u0000\u0000\u0445\u0446\u0003k-\u0000\u0446"+ + "\u0447\u0001\u0000\u0000\u0000\u0447\u0448\u0006d\u0015\u0000\u0448\u00da"+ + "\u0001\u0000\u0000\u0000\u0449\u044a\u0007\u0010\u0000\u0000\u044a\u044b"+ + "\u0007\u0003\u0000\u0000\u044b\u044c\u0007\u0005\u0000\u0000\u044c\u044d"+ + "\u0007\f\u0000\u0000\u044d\u044e\u0007\u0000\u0000\u0000\u044e\u044f\u0007"+ + "\f\u0000\u0000\u044f\u0450\u0007\u0005\u0000\u0000\u0450\u0451\u0007\f"+ + "\u0000\u0000\u0451\u00dc\u0001\u0000\u0000\u0000\u0452\u0456\b \u0000"+ + "\u0000\u0453\u0454\u0005/\u0000\u0000\u0454\u0456\b!\u0000\u0000\u0455"+ + "\u0452\u0001\u0000\u0000\u0000\u0455\u0453\u0001\u0000\u0000\u0000\u0456"+ + "\u00de\u0001\u0000\u0000\u0000\u0457\u0459\u0003\u00ddf\u0000\u0458\u0457"+ + "\u0001\u0000\u0000\u0000\u0459\u045a\u0001\u0000\u0000\u0000\u045a\u0458"+ + "\u0001\u0000\u0000\u0000\u045a\u045b\u0001\u0000\u0000\u0000\u045b\u00e0"+ + "\u0001\u0000\u0000\u0000\u045c\u045d\u0003\u00dfg\u0000\u045d\u045e\u0001"+ + "\u0000\u0000\u0000\u045e\u045f\u0006h\u0016\u0000\u045f\u00e2\u0001\u0000"+ + "\u0000\u0000\u0460\u0461\u0003_\'\u0000\u0461\u0462\u0001\u0000\u0000"+ + "\u0000\u0462\u0463\u0006i\u0017\u0000\u0463\u00e4\u0001\u0000\u0000\u0000"+ + "\u0464\u0465\u0003C\u0019\u0000\u0465\u0466\u0001\u0000\u0000\u0000\u0466"+ + "\u0467\u0006j\f\u0000\u0467\u00e6\u0001\u0000\u0000\u0000\u0468\u0469"+ + "\u0003E\u001a\u0000\u0469\u046a\u0001\u0000\u0000\u0000\u046a\u046b\u0006"+ + "k\f\u0000\u046b\u00e8\u0001\u0000\u0000\u0000\u046c\u046d\u0003G\u001b"+ + "\u0000\u046d\u046e\u0001\u0000\u0000\u0000\u046e\u046f\u0006l\f\u0000"+ + "\u046f\u00ea\u0001\u0000\u0000\u0000\u0470\u0471\u0003I\u001c\u0000\u0471"+ + "\u0472\u0001\u0000\u0000\u0000\u0472\u0473\u0006m\u0011\u0000\u0473\u0474"+ + "\u0006m\r\u0000\u0474\u00ec\u0001\u0000\u0000\u0000\u0475\u0476\u0003"+ + "u2\u0000\u0476\u0477\u0001\u0000\u0000\u0000\u0477\u0478\u0006n\u0018"+ + "\u0000\u0478\u00ee\u0001\u0000\u0000\u0000\u0479\u047a\u0003q0\u0000\u047a"+ + "\u047b\u0001\u0000\u0000\u0000\u047b\u047c\u0006o\u0014\u0000\u047c\u00f0"+ + "\u0001\u0000\u0000\u0000\u047d\u047e\u0003\u008d>\u0000\u047e\u047f\u0001"+ + "\u0000\u0000\u0000\u047f\u0480\u0006p\u0019\u0000\u0480\u00f2\u0001\u0000"+ + "\u0000\u0000\u0481\u0482\u0003\u00b3Q\u0000\u0482\u0483\u0001\u0000\u0000"+ + "\u0000\u0483\u0484\u0006q\u001a\u0000\u0484\u00f4\u0001\u0000\u0000\u0000"+ + "\u0485\u048a\u0003M\u001e\u0000\u0486\u048a\u0003K\u001d\u0000\u0487\u048a"+ + "\u0003[%\u0000\u0488\u048a\u0003\u00a7K\u0000\u0489\u0485\u0001\u0000"+ + "\u0000\u0000\u0489\u0486\u0001\u0000\u0000\u0000\u0489\u0487\u0001\u0000"+ + "\u0000\u0000\u0489\u0488\u0001\u0000\u0000\u0000\u048a\u00f6\u0001\u0000"+ + "\u0000\u0000\u048b\u048e\u0003M\u001e\u0000\u048c\u048e\u0003\u00a7K\u0000"+ + "\u048d\u048b\u0001\u0000\u0000\u0000\u048d\u048c\u0001\u0000\u0000\u0000"+ + "\u048e\u0492\u0001\u0000\u0000\u0000\u048f\u0491\u0003\u00f5r\u0000\u0490"+ + "\u048f\u0001\u0000\u0000\u0000\u0491\u0494\u0001\u0000\u0000\u0000\u0492"+ + "\u0490\u0001\u0000\u0000\u0000\u0492\u0493\u0001\u0000\u0000\u0000\u0493"+ + "\u049f\u0001\u0000\u0000\u0000\u0494\u0492\u0001\u0000\u0000\u0000\u0495"+ + "\u0498\u0003[%\u0000\u0496\u0498\u0003U\"\u0000\u0497\u0495\u0001\u0000"+ + "\u0000\u0000\u0497\u0496\u0001\u0000\u0000\u0000\u0498\u049a\u0001\u0000"+ + "\u0000\u0000\u0499\u049b\u0003\u00f5r\u0000\u049a\u0499\u0001\u0000\u0000"+ + "\u0000\u049b\u049c\u0001\u0000\u0000\u0000\u049c\u049a\u0001\u0000\u0000"+ + "\u0000\u049c\u049d\u0001\u0000\u0000\u0000\u049d\u049f\u0001\u0000\u0000"+ + "\u0000\u049e\u048d\u0001\u0000\u0000\u0000\u049e\u0497\u0001\u0000\u0000"+ + "\u0000\u049f\u00f8\u0001\u0000\u0000\u0000\u04a0\u04a3\u0003\u00f7s\u0000"+ + "\u04a1\u04a3\u0003\u00bbU\u0000\u04a2\u04a0\u0001\u0000\u0000\u0000\u04a2"+ + "\u04a1\u0001\u0000\u0000\u0000\u04a3\u04a4\u0001\u0000\u0000\u0000\u04a4"+ + "\u04a2\u0001\u0000\u0000\u0000\u04a4\u04a5\u0001\u0000\u0000\u0000\u04a5"+ + "\u00fa\u0001\u0000\u0000\u0000\u04a6\u04a7\u0003C\u0019\u0000\u04a7\u04a8"+ + "\u0001\u0000\u0000\u0000\u04a8\u04a9\u0006u\f\u0000\u04a9\u00fc\u0001"+ + "\u0000\u0000\u0000\u04aa\u04ab\u0003E\u001a\u0000\u04ab\u04ac\u0001\u0000"+ + "\u0000\u0000\u04ac\u04ad\u0006v\f\u0000\u04ad\u00fe\u0001\u0000\u0000"+ + "\u0000\u04ae\u04af\u0003G\u001b\u0000\u04af\u04b0\u0001\u0000\u0000\u0000"+ + "\u04b0\u04b1\u0006w\f\u0000\u04b1\u0100\u0001\u0000\u0000\u0000\u04b2"+ + "\u04b3\u0003I\u001c\u0000\u04b3\u04b4\u0001\u0000\u0000\u0000\u04b4\u04b5"+ + "\u0006x\u0011\u0000\u04b5\u04b6\u0006x\r\u0000\u04b6\u0102\u0001\u0000"+ + "\u0000\u0000\u04b7\u04b8\u0003k-\u0000\u04b8\u04b9\u0001\u0000\u0000\u0000"+ + "\u04b9\u04ba\u0006y\u0015\u0000\u04ba\u0104\u0001\u0000\u0000\u0000\u04bb"+ + "\u04bc\u0003q0\u0000\u04bc\u04bd\u0001\u0000\u0000\u0000\u04bd\u04be\u0006"+ + "z\u0014\u0000\u04be\u0106\u0001\u0000\u0000\u0000\u04bf\u04c0\u0003u2"+ + "\u0000\u04c0\u04c1\u0001\u0000\u0000\u0000\u04c1\u04c2\u0006{\u0018\u0000"+ + "\u04c2\u0108\u0001\u0000\u0000\u0000\u04c3\u04c4\u0003\u008d>\u0000\u04c4"+ + "\u04c5\u0001\u0000\u0000\u0000\u04c5\u04c6\u0006|\u0019\u0000\u04c6\u010a"+ + "\u0001\u0000\u0000\u0000\u04c7\u04c8\u0003\u00b3Q\u0000\u04c8\u04c9\u0001"+ + "\u0000\u0000\u0000\u04c9\u04ca\u0006}\u001a\u0000\u04ca\u010c\u0001\u0000"+ + "\u0000\u0000\u04cb\u04cc\u0007\f\u0000\u0000\u04cc\u04cd\u0007\u0002\u0000"+ + "\u0000\u04cd\u010e\u0001\u0000\u0000\u0000\u04ce\u04cf\u0003\u00f9t\u0000"+ + "\u04cf\u04d0\u0001\u0000\u0000\u0000\u04d0\u04d1\u0006\u007f\u001b\u0000"+ + "\u04d1\u0110\u0001\u0000\u0000\u0000\u04d2\u04d3\u0003C\u0019\u0000\u04d3"+ + "\u04d4\u0001\u0000\u0000\u0000\u04d4\u04d5\u0006\u0080\f\u0000\u04d5\u0112"+ + "\u0001\u0000\u0000\u0000\u04d6\u04d7\u0003E\u001a\u0000\u04d7\u04d8\u0001"+ + "\u0000\u0000\u0000\u04d8\u04d9\u0006\u0081\f\u0000\u04d9\u0114\u0001\u0000"+ + "\u0000\u0000\u04da\u04db\u0003G\u001b\u0000\u04db\u04dc\u0001\u0000\u0000"+ + "\u0000\u04dc\u04dd\u0006\u0082\f\u0000\u04dd\u0116\u0001\u0000\u0000\u0000"+ + "\u04de\u04df\u0003I\u001c\u0000\u04df\u04e0\u0001\u0000\u0000\u0000\u04e0"+ + "\u04e1\u0006\u0083\u0011\u0000\u04e1\u04e2\u0006\u0083\r\u0000\u04e2\u0118"+ + "\u0001\u0000\u0000\u0000\u04e3\u04e4\u0003\u00b5R\u0000\u04e4\u04e5\u0001"+ + "\u0000\u0000\u0000\u04e5\u04e6\u0006\u0084\u000f\u0000\u04e6\u04e7\u0006"+ + "\u0084\u001c\u0000\u04e7\u011a\u0001\u0000\u0000\u0000\u04e8\u04e9\u0007"+ + "\u0007\u0000\u0000\u04e9\u04ea\u0007\t\u0000\u0000\u04ea\u04eb\u0001\u0000"+ + "\u0000\u0000\u04eb\u04ec\u0006\u0085\u001d\u0000\u04ec\u011c\u0001\u0000"+ + "\u0000\u0000\u04ed\u04ee\u0007\u0013\u0000\u0000\u04ee\u04ef\u0007\u0001"+ + "\u0000\u0000\u04ef\u04f0\u0007\u0005\u0000\u0000\u04f0\u04f1\u0007\n\u0000"+ + "\u0000\u04f1\u04f2\u0001\u0000\u0000\u0000\u04f2\u04f3\u0006\u0086\u001d"+ + "\u0000\u04f3\u011e\u0001\u0000\u0000\u0000\u04f4\u04f5\b\"\u0000\u0000"+ + "\u04f5\u0120\u0001\u0000\u0000\u0000\u04f6\u04f8\u0003\u011f\u0087\u0000"+ + "\u04f7\u04f6\u0001\u0000\u0000\u0000\u04f8\u04f9\u0001\u0000\u0000\u0000"+ + "\u04f9\u04f7\u0001\u0000\u0000\u0000\u04f9\u04fa\u0001\u0000\u0000\u0000"+ + "\u04fa\u04fb\u0001\u0000\u0000\u0000\u04fb\u04fc\u0003o/\u0000\u04fc\u04fe"+ + "\u0001\u0000\u0000\u0000\u04fd\u04f7\u0001\u0000\u0000\u0000\u04fd\u04fe"+ + "\u0001\u0000\u0000\u0000\u04fe\u0500\u0001\u0000\u0000\u0000\u04ff\u0501"+ + "\u0003\u011f\u0087\u0000\u0500\u04ff\u0001\u0000\u0000\u0000\u0501\u0502"+ + "\u0001\u0000\u0000\u0000\u0502\u0500\u0001\u0000\u0000\u0000\u0502\u0503"+ + "\u0001\u0000\u0000\u0000\u0503\u0122\u0001\u0000\u0000\u0000\u0504\u0505"+ + "\u0003\u0121\u0088\u0000\u0505\u0506\u0001\u0000\u0000\u0000\u0506\u0507"+ + "\u0006\u0089\u001e\u0000\u0507\u0124\u0001\u0000\u0000\u0000\u0508\u0509"+ + "\u0003C\u0019\u0000\u0509\u050a\u0001\u0000\u0000\u0000\u050a\u050b\u0006"+ + "\u008a\f\u0000\u050b\u0126\u0001\u0000\u0000\u0000\u050c\u050d\u0003E"+ + "\u001a\u0000\u050d\u050e\u0001\u0000\u0000\u0000\u050e\u050f\u0006\u008b"+ + "\f\u0000\u050f\u0128\u0001\u0000\u0000\u0000\u0510\u0511\u0003G\u001b"+ + "\u0000\u0511\u0512\u0001\u0000\u0000\u0000\u0512\u0513\u0006\u008c\f\u0000"+ + "\u0513\u012a\u0001\u0000\u0000\u0000\u0514\u0515\u0003I\u001c\u0000\u0515"+ + "\u0516\u0001\u0000\u0000\u0000\u0516\u0517\u0006\u008d\u0011\u0000\u0517"+ + "\u0518\u0006\u008d\r\u0000\u0518\u0519\u0006\u008d\r\u0000\u0519\u012c"+ + "\u0001\u0000\u0000\u0000\u051a\u051b\u0003k-\u0000\u051b\u051c\u0001\u0000"+ + "\u0000\u0000\u051c\u051d\u0006\u008e\u0015\u0000\u051d\u012e\u0001\u0000"+ + "\u0000\u0000\u051e\u051f\u0003q0\u0000\u051f\u0520\u0001\u0000\u0000\u0000"+ + "\u0520\u0521\u0006\u008f\u0014\u0000\u0521\u0130\u0001\u0000\u0000\u0000"+ + "\u0522\u0523\u0003u2\u0000\u0523\u0524\u0001\u0000\u0000\u0000\u0524\u0525"+ + "\u0006\u0090\u0018\u0000\u0525\u0132\u0001\u0000\u0000\u0000\u0526\u0527"+ + "\u0003\u011d\u0086\u0000\u0527\u0528\u0001\u0000\u0000\u0000\u0528\u0529"+ + "\u0006\u0091\u001f\u0000\u0529\u0134\u0001\u0000\u0000\u0000\u052a\u052b"+ + "\u0003\u00f9t\u0000\u052b\u052c\u0001\u0000\u0000\u0000\u052c\u052d\u0006"+ + "\u0092\u001b\u0000\u052d\u0136\u0001\u0000\u0000\u0000\u052e\u052f\u0003"+ + "\u00bdV\u0000\u052f\u0530\u0001\u0000\u0000\u0000\u0530\u0531\u0006\u0093"+ + " \u0000\u0531\u0138\u0001\u0000\u0000\u0000\u0532\u0533\u0003\u008d>\u0000"+ + "\u0533\u0534\u0001\u0000\u0000\u0000\u0534\u0535\u0006\u0094\u0019\u0000"+ + "\u0535\u013a\u0001\u0000\u0000\u0000\u0536\u0537\u0003\u00b3Q\u0000\u0537"+ + "\u0538\u0001\u0000\u0000\u0000\u0538\u0539\u0006\u0095\u001a\u0000\u0539"+ + "\u013c\u0001\u0000\u0000\u0000\u053a\u053b\u0003C\u0019\u0000\u053b\u053c"+ + "\u0001\u0000\u0000\u0000\u053c\u053d\u0006\u0096\f\u0000\u053d\u013e\u0001"+ + "\u0000\u0000\u0000\u053e\u053f\u0003E\u001a\u0000\u053f\u0540\u0001\u0000"+ + "\u0000\u0000\u0540\u0541\u0006\u0097\f\u0000\u0541\u0140\u0001\u0000\u0000"+ + "\u0000\u0542\u0543\u0003G\u001b\u0000\u0543\u0544\u0001\u0000\u0000\u0000"+ + "\u0544\u0545\u0006\u0098\f\u0000\u0545\u0142\u0001\u0000\u0000\u0000\u0546"+ + "\u0547\u0003I\u001c\u0000\u0547\u0548\u0001\u0000\u0000\u0000\u0548\u0549"+ + "\u0006\u0099\u0011\u0000\u0549\u054a\u0006\u0099\r\u0000\u054a\u0144\u0001"+ + "\u0000\u0000\u0000\u054b\u054c\u0003u2\u0000\u054c\u054d\u0001\u0000\u0000"+ + "\u0000\u054d\u054e\u0006\u009a\u0018\u0000\u054e\u0146\u0001\u0000\u0000"+ + "\u0000\u054f\u0550\u0003\u008d>\u0000\u0550\u0551\u0001\u0000\u0000\u0000"+ + "\u0551\u0552\u0006\u009b\u0019\u0000\u0552\u0148\u0001\u0000\u0000\u0000"+ + "\u0553\u0554\u0003\u00b3Q\u0000\u0554\u0555\u0001\u0000\u0000\u0000\u0555"+ + "\u0556\u0006\u009c\u001a\u0000\u0556\u014a\u0001\u0000\u0000\u0000\u0557"+ + "\u0558\u0003\u00bdV\u0000\u0558\u0559\u0001\u0000\u0000\u0000\u0559\u055a"+ + "\u0006\u009d \u0000\u055a\u014c\u0001\u0000\u0000\u0000\u055b\u055c\u0003"+ + "\u00b9T\u0000\u055c\u055d\u0001\u0000\u0000\u0000\u055d\u055e\u0006\u009e"+ + "!\u0000\u055e\u014e\u0001\u0000\u0000\u0000\u055f\u0560\u0003C\u0019\u0000"+ + "\u0560\u0561\u0001\u0000\u0000\u0000\u0561\u0562\u0006\u009f\f\u0000\u0562"+ + "\u0150\u0001\u0000\u0000\u0000\u0563\u0564\u0003E\u001a\u0000\u0564\u0565"+ + "\u0001\u0000\u0000\u0000\u0565\u0566\u0006\u00a0\f\u0000\u0566\u0152\u0001"+ + "\u0000\u0000\u0000\u0567\u0568\u0003G\u001b\u0000\u0568\u0569\u0001\u0000"+ + "\u0000\u0000\u0569\u056a\u0006\u00a1\f\u0000\u056a\u0154\u0001\u0000\u0000"+ + "\u0000\u056b\u056c\u0003I\u001c\u0000\u056c\u056d\u0001\u0000\u0000\u0000"+ + "\u056d\u056e\u0006\u00a2\u0011\u0000\u056e\u056f\u0006\u00a2\r\u0000\u056f"+ + "\u0156\u0001\u0000\u0000\u0000\u0570\u0571\u0007\u0001\u0000\u0000\u0571"+ + "\u0572\u0007\t\u0000\u0000\u0572\u0573\u0007\u000f\u0000\u0000\u0573\u0574"+ + "\u0007\u0007\u0000\u0000\u0574\u0158\u0001\u0000\u0000\u0000\u0575\u0576"+ + "\u0003C\u0019\u0000\u0576\u0577\u0001\u0000\u0000\u0000\u0577\u0578\u0006"+ + "\u00a4\f\u0000\u0578\u015a\u0001\u0000\u0000\u0000\u0579\u057a\u0003E"+ + "\u001a\u0000\u057a\u057b\u0001\u0000\u0000\u0000\u057b\u057c\u0006\u00a5"+ + "\f\u0000\u057c\u015c\u0001\u0000\u0000\u0000\u057d\u057e\u0003G\u001b"+ + "\u0000\u057e\u057f\u0001\u0000\u0000\u0000\u057f\u0580\u0006\u00a6\f\u0000"+ + "\u0580\u015e\u0001\u0000\u0000\u0000\u0581\u0582\u0003\u00b7S\u0000\u0582"+ + "\u0583\u0001\u0000\u0000\u0000\u0583\u0584\u0006\u00a7\u0012\u0000\u0584"+ + "\u0585\u0006\u00a7\r\u0000\u0585\u0160\u0001\u0000\u0000\u0000\u0586\u0587"+ + "\u0003o/\u0000\u0587\u0588\u0001\u0000\u0000\u0000\u0588\u0589\u0006\u00a8"+ + "\u0013\u0000\u0589\u0162\u0001\u0000\u0000\u0000\u058a\u0590\u0003U\""+ + "\u0000\u058b\u0590\u0003K\u001d\u0000\u058c\u0590\u0003u2\u0000\u058d"+ + "\u0590\u0003M\u001e\u0000\u058e\u0590\u0003[%\u0000\u058f\u058a\u0001"+ + "\u0000\u0000\u0000\u058f\u058b\u0001\u0000\u0000\u0000\u058f\u058c\u0001"+ + "\u0000\u0000\u0000\u058f\u058d\u0001\u0000\u0000\u0000\u058f\u058e\u0001"+ + "\u0000\u0000\u0000\u0590\u0591\u0001\u0000\u0000\u0000\u0591\u058f\u0001"+ + "\u0000\u0000\u0000\u0591\u0592\u0001\u0000\u0000\u0000\u0592\u0164\u0001"+ + "\u0000\u0000\u0000\u0593\u0594\u0003C\u0019\u0000\u0594\u0595\u0001\u0000"+ + "\u0000\u0000\u0595\u0596\u0006\u00aa\f\u0000\u0596\u0166\u0001\u0000\u0000"+ + "\u0000\u0597\u0598\u0003E\u001a\u0000\u0598\u0599\u0001\u0000\u0000\u0000"+ + "\u0599\u059a\u0006\u00ab\f\u0000\u059a\u0168\u0001\u0000\u0000\u0000\u059b"+ + "\u059c\u0003G\u001b\u0000\u059c\u059d\u0001\u0000\u0000\u0000\u059d\u059e"+ + "\u0006\u00ac\f\u0000\u059e\u016a\u0001\u0000\u0000\u0000\u059f\u05a0\u0003"+ + "I\u001c\u0000\u05a0\u05a1\u0001\u0000\u0000\u0000\u05a1\u05a2\u0006\u00ad"+ + "\u0011\u0000\u05a2\u05a3\u0006\u00ad\r\u0000\u05a3\u016c\u0001\u0000\u0000"+ + "\u0000\u05a4\u05a5\u0003o/\u0000\u05a5\u05a6\u0001\u0000\u0000\u0000\u05a6"+ + "\u05a7\u0006\u00ae\u0013\u0000\u05a7\u016e\u0001\u0000\u0000\u0000\u05a8"+ + "\u05a9\u0003q0\u0000\u05a9\u05aa\u0001\u0000\u0000\u0000\u05aa\u05ab\u0006"+ + "\u00af\u0014\u0000\u05ab\u0170\u0001\u0000\u0000\u0000\u05ac\u05ad\u0003"+ + "u2\u0000\u05ad\u05ae\u0001\u0000\u0000\u0000\u05ae\u05af\u0006\u00b0\u0018"+ + "\u0000\u05af\u0172\u0001\u0000\u0000\u0000\u05b0\u05b1\u0003\u011b\u0085"+ + "\u0000\u05b1\u05b2\u0001\u0000\u0000\u0000\u05b2\u05b3\u0006\u00b1\"\u0000"+ + "\u05b3\u05b4\u0006\u00b1#\u0000\u05b4\u0174\u0001\u0000\u0000\u0000\u05b5"+ + "\u05b6\u0003\u00dfg\u0000\u05b6\u05b7\u0001\u0000\u0000\u0000\u05b7\u05b8"+ + "\u0006\u00b2\u0016\u0000\u05b8\u0176\u0001\u0000\u0000\u0000\u05b9\u05ba"+ + "\u0003_\'\u0000\u05ba\u05bb\u0001\u0000\u0000\u0000\u05bb\u05bc\u0006"+ + "\u00b3\u0017\u0000\u05bc\u0178\u0001\u0000\u0000\u0000\u05bd\u05be\u0003"+ + "C\u0019\u0000\u05be\u05bf\u0001\u0000\u0000\u0000\u05bf\u05c0\u0006\u00b4"+ + "\f\u0000\u05c0\u017a\u0001\u0000\u0000\u0000\u05c1\u05c2\u0003E\u001a"+ + "\u0000\u05c2\u05c3\u0001\u0000\u0000\u0000\u05c3\u05c4\u0006\u00b5\f\u0000"+ + "\u05c4\u017c\u0001\u0000\u0000\u0000\u05c5\u05c6\u0003G\u001b\u0000\u05c6"+ + "\u05c7\u0001\u0000\u0000\u0000\u05c7\u05c8\u0006\u00b6\f\u0000\u05c8\u017e"+ + "\u0001\u0000\u0000\u0000\u05c9\u05ca\u0003I\u001c\u0000\u05ca\u05cb\u0001"+ + "\u0000\u0000\u0000\u05cb\u05cc\u0006\u00b7\u0011\u0000\u05cc\u05cd\u0006"+ + "\u00b7\r\u0000\u05cd\u05ce\u0006\u00b7\r\u0000\u05ce\u0180\u0001\u0000"+ + "\u0000\u0000\u05cf\u05d0\u0003q0\u0000\u05d0\u05d1\u0001\u0000\u0000\u0000"+ + "\u05d1\u05d2\u0006\u00b8\u0014\u0000\u05d2\u0182\u0001\u0000\u0000\u0000"+ + "\u05d3\u05d4\u0003u2\u0000\u05d4\u05d5\u0001\u0000\u0000\u0000\u05d5\u05d6"+ + "\u0006\u00b9\u0018\u0000\u05d6\u0184\u0001\u0000\u0000\u0000\u05d7\u05d8"+ + "\u0003\u00f9t\u0000\u05d8\u05d9\u0001\u0000\u0000\u0000\u05d9\u05da\u0006"+ + "\u00ba\u001b\u0000\u05da\u0186\u0001\u0000\u0000\u0000\u05db\u05dc\u0003"+ + "C\u0019\u0000\u05dc\u05dd\u0001\u0000\u0000\u0000\u05dd\u05de\u0006\u00bb"+ + "\f\u0000\u05de\u0188\u0001\u0000\u0000\u0000\u05df\u05e0\u0003E\u001a"+ + "\u0000\u05e0\u05e1\u0001\u0000\u0000\u0000\u05e1\u05e2\u0006\u00bc\f\u0000"+ + "\u05e2\u018a\u0001\u0000\u0000\u0000\u05e3\u05e4\u0003G\u001b\u0000\u05e4"+ + "\u05e5\u0001\u0000\u0000\u0000\u05e5\u05e6\u0006\u00bd\f\u0000\u05e6\u018c"+ + "\u0001\u0000\u0000\u0000\u05e7\u05e8\u0003I\u001c\u0000\u05e8\u05e9\u0001"+ + "\u0000\u0000\u0000\u05e9\u05ea\u0006\u00be\u0011\u0000\u05ea\u05eb\u0006"+ + "\u00be\r\u0000\u05eb\u018e\u0001\u0000\u0000\u0000\u05ec\u05ed\u0007#"+ + "\u0000\u0000\u05ed\u05ee\u0007\u0007\u0000\u0000\u05ee\u05ef\u0007\u0001"+ + "\u0000\u0000\u05ef\u05f0\u0007\t\u0000\u0000\u05f0\u0190\u0001\u0000\u0000"+ + "\u0000\u05f1\u05f2\u0003\u010d~\u0000\u05f2\u05f3\u0001\u0000\u0000\u0000"+ + "\u05f3\u05f4\u0006\u00c0$\u0000\u05f4\u0192\u0001\u0000\u0000\u0000\u05f5"+ + "\u05f6\u0003\u011b\u0085\u0000\u05f6\u05f7\u0001\u0000\u0000\u0000\u05f7"+ + "\u05f8\u0006\u00c1\"\u0000\u05f8\u05f9\u0006\u00c1\r\u0000\u05f9\u05fa"+ + "\u0006\u00c1\u0000\u0000\u05fa\u0194\u0001\u0000\u0000\u0000\u05fb\u05fc"+ + "\u0007\u0014\u0000\u0000\u05fc\u05fd\u0007\u0002\u0000\u0000\u05fd\u05fe"+ + "\u0007\u0001\u0000\u0000\u05fe\u05ff\u0007\t\u0000\u0000\u05ff\u0600\u0007"+ + "\u0011\u0000\u0000\u0600\u0601\u0001\u0000\u0000\u0000\u0601\u0602\u0006"+ + "\u00c2\r\u0000\u0602\u0603\u0006\u00c2\u0000\u0000\u0603\u0196\u0001\u0000"+ + "\u0000\u0000\u0604\u0605\u0003\u00dfg\u0000\u0605\u0606\u0001\u0000\u0000"+ + "\u0000\u0606\u0607\u0006\u00c3\u0016\u0000\u0607\u0198\u0001\u0000\u0000"+ + "\u0000\u0608\u0609\u0003_\'\u0000\u0609\u060a\u0001\u0000\u0000\u0000"+ + "\u060a\u060b\u0006\u00c4\u0017\u0000\u060b\u019a\u0001\u0000\u0000\u0000"+ + "\u060c\u060d\u0003o/\u0000\u060d\u060e\u0001\u0000\u0000\u0000\u060e\u060f"+ + "\u0006\u00c5\u0013\u0000\u060f\u019c\u0001\u0000\u0000\u0000\u0610\u0611"+ + "\u0003\u00b9T\u0000\u0611\u0612\u0001\u0000\u0000\u0000\u0612\u0613\u0006"+ + "\u00c6!\u0000\u0613\u019e\u0001\u0000\u0000\u0000\u0614\u0615\u0003\u00bd"+ + "V\u0000\u0615\u0616\u0001\u0000\u0000\u0000\u0616\u0617\u0006\u00c7 \u0000"+ + "\u0617\u01a0\u0001\u0000\u0000\u0000\u0618\u0619\u0003C\u0019\u0000\u0619"+ + "\u061a\u0001\u0000\u0000\u0000\u061a\u061b\u0006\u00c8\f\u0000\u061b\u01a2"+ + "\u0001\u0000\u0000\u0000\u061c\u061d\u0003E\u001a\u0000\u061d\u061e\u0001"+ + "\u0000\u0000\u0000\u061e\u061f\u0006\u00c9\f\u0000\u061f\u01a4\u0001\u0000"+ + "\u0000\u0000\u0620\u0621\u0003G\u001b\u0000\u0621\u0622\u0001\u0000\u0000"+ + "\u0000\u0622\u0623\u0006\u00ca\f\u0000\u0623\u01a6\u0001\u0000\u0000\u0000"+ + "\u0624\u0625\u0003I\u001c\u0000\u0625\u0626\u0001\u0000\u0000\u0000\u0626"+ + "\u0627\u0006\u00cb\u0011\u0000\u0627\u0628\u0006\u00cb\r\u0000\u0628\u01a8"+ + "\u0001\u0000\u0000\u0000\u0629\u062a\u0003\u00dfg\u0000\u062a\u062b\u0001"+ + "\u0000\u0000\u0000\u062b\u062c\u0006\u00cc\u0016\u0000\u062c\u062d\u0006"+ + "\u00cc\r\u0000\u062d\u062e\u0006\u00cc%\u0000\u062e\u01aa\u0001\u0000"+ + "\u0000\u0000\u062f\u0630\u0003_\'\u0000\u0630\u0631\u0001\u0000\u0000"+ + "\u0000\u0631\u0632\u0006\u00cd\u0017\u0000\u0632\u0633\u0006\u00cd\r\u0000"+ + "\u0633\u0634\u0006\u00cd%\u0000\u0634\u01ac\u0001\u0000\u0000\u0000\u0635"+ + "\u0636\u0003C\u0019\u0000\u0636\u0637\u0001\u0000\u0000\u0000\u0637\u0638"+ + "\u0006\u00ce\f\u0000\u0638\u01ae\u0001\u0000\u0000\u0000\u0639\u063a\u0003"+ + "E\u001a\u0000\u063a\u063b\u0001\u0000\u0000\u0000\u063b\u063c\u0006\u00cf"+ + "\f\u0000\u063c\u01b0\u0001\u0000\u0000\u0000\u063d\u063e\u0003G\u001b"+ + "\u0000\u063e\u063f\u0001\u0000\u0000\u0000\u063f\u0640\u0006\u00d0\f\u0000"+ + "\u0640\u01b2\u0001\u0000\u0000\u0000\u0641\u0642\u0003o/\u0000\u0642\u0643"+ + "\u0001\u0000\u0000\u0000\u0643\u0644\u0006\u00d1\u0013\u0000\u0644\u0645"+ + "\u0006\u00d1\r\u0000\u0645\u0646\u0006\u00d1\u000b\u0000\u0646\u01b4\u0001"+ + "\u0000\u0000\u0000\u0647\u0648\u0003q0\u0000\u0648\u0649\u0001\u0000\u0000"+ + "\u0000\u0649\u064a\u0006\u00d2\u0014\u0000\u064a\u064b\u0006\u00d2\r\u0000"+ + "\u064b\u064c\u0006\u00d2\u000b\u0000\u064c\u01b6\u0001\u0000\u0000\u0000"+ + "\u064d\u064e\u0003C\u0019\u0000\u064e\u064f\u0001\u0000\u0000\u0000\u064f"+ + "\u0650\u0006\u00d3\f\u0000\u0650\u01b8\u0001\u0000\u0000\u0000\u0651\u0652"+ + "\u0003E\u001a\u0000\u0652\u0653\u0001\u0000\u0000\u0000\u0653\u0654\u0006"+ + "\u00d4\f\u0000\u0654\u01ba\u0001\u0000\u0000\u0000\u0655\u0656\u0003G"+ + "\u001b\u0000\u0656\u0657\u0001\u0000\u0000\u0000\u0657\u0658\u0006\u00d5"+ + "\f\u0000\u0658\u01bc\u0001\u0000\u0000\u0000\u0659\u065a\u0003\u00bdV"+ + "\u0000\u065a\u065b\u0001\u0000\u0000\u0000\u065b\u065c\u0006\u00d6\r\u0000"+ + "\u065c\u065d\u0006\u00d6\u0000\u0000\u065d\u065e\u0006\u00d6 \u0000\u065e"+ + "\u01be\u0001\u0000\u0000\u0000\u065f\u0660\u0003\u00b9T\u0000\u0660\u0661"+ + "\u0001\u0000\u0000\u0000\u0661\u0662\u0006\u00d7\r\u0000\u0662\u0663\u0006"+ + "\u00d7\u0000\u0000\u0663\u0664\u0006\u00d7!\u0000\u0664\u01c0\u0001\u0000"+ + "\u0000\u0000\u0665\u0666\u0003e*\u0000\u0666\u0667\u0001\u0000\u0000\u0000"+ + "\u0667\u0668\u0006\u00d8\r\u0000\u0668\u0669\u0006\u00d8\u0000\u0000\u0669"+ + "\u066a\u0006\u00d8&\u0000\u066a\u01c2\u0001\u0000\u0000\u0000\u066b\u066c"+ + "\u0003I\u001c\u0000\u066c\u066d\u0001\u0000\u0000\u0000\u066d\u066e\u0006"+ + "\u00d9\u0011\u0000\u066e\u066f\u0006\u00d9\r\u0000\u066f\u01c4\u0001\u0000"+ + "\u0000\u0000\u0670\u0671\u0003I\u001c\u0000\u0671\u0672\u0001\u0000\u0000"+ + "\u0000\u0672\u0673\u0006\u00da\u0011\u0000\u0673\u0674\u0006\u00da\r\u0000"+ + "\u0674\u01c6\u0001\u0000\u0000\u0000\u0675\u0676\u0003\u011b\u0085\u0000"+ + "\u0676\u0677\u0001\u0000\u0000\u0000\u0677\u0678\u0006\u00db\"\u0000\u0678"+ + "\u01c8\u0001\u0000\u0000\u0000\u0679\u067a\u0003\u010d~\u0000\u067a\u067b"+ + "\u0001\u0000\u0000\u0000\u067b\u067c\u0006\u00dc$\u0000\u067c\u01ca\u0001"+ + "\u0000\u0000\u0000\u067d\u067e\u0003u2\u0000\u067e\u067f\u0001\u0000\u0000"+ + "\u0000\u067f\u0680\u0006\u00dd\u0018\u0000\u0680\u01cc\u0001\u0000\u0000"+ + "\u0000\u0681\u0682\u0003q0\u0000\u0682\u0683\u0001\u0000\u0000\u0000\u0683"+ + "\u0684\u0006\u00de\u0014\u0000\u0684\u01ce\u0001\u0000\u0000\u0000\u0685"+ + "\u0686\u0003\u00bdV\u0000\u0686\u0687\u0001\u0000\u0000\u0000\u0687\u0688"+ + "\u0006\u00df \u0000\u0688\u01d0\u0001\u0000\u0000\u0000\u0689\u068a\u0003"+ + "\u00b9T\u0000\u068a\u068b\u0001\u0000\u0000\u0000\u068b\u068c\u0006\u00e0"+ + "!\u0000\u068c\u01d2\u0001\u0000\u0000\u0000\u068d\u068e\u0003C\u0019\u0000"+ + "\u068e\u068f\u0001\u0000\u0000\u0000\u068f\u0690\u0006\u00e1\f\u0000\u0690"+ + "\u01d4\u0001\u0000\u0000\u0000\u0691\u0692\u0003E\u001a\u0000\u0692\u0693"+ + "\u0001\u0000\u0000\u0000\u0693\u0694\u0006\u00e2\f\u0000\u0694\u01d6\u0001"+ + "\u0000\u0000\u0000\u0695\u0696\u0003G\u001b\u0000\u0696\u0697\u0001\u0000"+ + "\u0000\u0000\u0697\u0698\u0006\u00e3\f\u0000\u0698\u01d8\u0001\u0000\u0000"+ + "\u0000C\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f"+ + "\r\u000e\u000f\u0010\u02b5\u02bf\u02c3\u02c6\u02cf\u02d1\u02dc\u02ef\u02f4"+ + "\u02fd\u0304\u0309\u030b\u0316\u031e\u0321\u0323\u0328\u032d\u0333\u033a"+ + "\u033f\u0345\u0348\u0350\u0354\u03d8\u03dd\u03e4\u03e6\u03f6\u03fb\u0400"+ + "\u0402\u0408\u0455\u045a\u0489\u048d\u0492\u0497\u049c\u049e\u04a2\u04a4"+ + "\u04f9\u04fd\u0502\u058f\u0591\'\u0005\u0001\u0000\u0005\u0004\u0000\u0005"+ "\u0006\u0000\u0005\u0002\u0000\u0005\u0003\u0000\u0005\b\u0000\u0005\u0005"+ - "\u0000\u0005\t\u0000\u0005\r\u0000\u0005\u000b\u0000\u0005\u000e\u0000"+ - "\u0000\u0001\u0000\u0004\u0000\u0000\u0007\u0010\u0000\u0007G\u0000\u0005"+ - "\u0000\u0000\u0007\u001c\u0000\u0007H\u0000\u0007%\u0000\u0007&\u0000"+ - "\u0007#\u0000\u0007R\u0000\u0007\u001d\u0000\u0007(\u0000\u00074\u0000"+ - "\u0007F\u0000\u0007V\u0000\u0005\n\u0000\u0005\u0007\u0000\u0007`\u0000"+ - "\u0007_\u0000\u0007J\u0000\u0007I\u0000\u0007^\u0000\u0005\f\u0000\u0007"+ - "Z\u0000\u0005\u000f\u0000\u0007 \u0000"; + "\u0000\u0005\t\u0000\u0005\r\u0000\u0005\u0010\u0000\u0005\u000b\u0000"+ + "\u0005\u000e\u0000\u0000\u0001\u0000\u0004\u0000\u0000\u0007\u0010\u0000"+ + "\u0007H\u0000\u0005\u0000\u0000\u0007\u001d\u0000\u0007I\u0000\u0007&"+ + "\u0000\u0007\'\u0000\u0007$\u0000\u0007S\u0000\u0007\u001e\u0000\u0007"+ + ")\u0000\u00075\u0000\u0007G\u0000\u0007W\u0000\u0005\n\u0000\u0005\u0007"+ + "\u0000\u0007a\u0000\u0007`\u0000\u0007K\u0000\u0007J\u0000\u0007_\u0000"+ + "\u0005\f\u0000\u0007[\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 25a538f83647..2957751d99f6 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 @@ -27,6 +27,7 @@ null null null null +null '|' null null @@ -130,6 +131,9 @@ null null null null +null +null +null token symbolic names: null @@ -150,6 +154,7 @@ SORT STATS WHERE JOIN_LOOKUP +DEV_CHANGE_POINT DEV_INLINESTATS DEV_LOOKUP DEV_METRICS @@ -263,6 +268,9 @@ METRICS_WS CLOSING_METRICS_LINE_COMMENT CLOSING_METRICS_MULTILINE_COMMENT CLOSING_METRICS_WS +CHANGE_POINT_LINE_COMMENT +CHANGE_POINT_MULTILINE_COMMENT +CHANGE_POINT_WS rule names: singleStatement @@ -331,7 +339,8 @@ joinCommand joinTarget joinCondition joinPredicate +changePointCommand atn: -[4, 1, 130, 644, 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, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 142, 8, 1, 10, 1, 12, 1, 145, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 153, 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, 1, 3, 1, 3, 1, 3, 3, 3, 172, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 184, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 191, 8, 5, 10, 5, 12, 5, 194, 9, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 201, 8, 5, 1, 5, 1, 5, 1, 5, 3, 5, 206, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 214, 8, 5, 10, 5, 12, 5, 217, 9, 5, 1, 6, 1, 6, 3, 6, 221, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 228, 8, 6, 1, 6, 1, 6, 1, 6, 3, 6, 233, 8, 6, 1, 7, 1, 7, 1, 7, 3, 7, 238, 8, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 248, 8, 8, 1, 9, 1, 9, 1, 9, 1, 9, 3, 9, 254, 8, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 5, 9, 262, 8, 9, 10, 9, 12, 9, 265, 9, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 275, 8, 10, 1, 10, 1, 10, 1, 10, 5, 10, 280, 8, 10, 10, 10, 12, 10, 283, 9, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 291, 8, 11, 10, 11, 12, 11, 294, 9, 11, 1, 11, 1, 11, 3, 11, 298, 8, 11, 3, 11, 300, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 310, 8, 13, 10, 13, 12, 13, 313, 9, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 5, 17, 329, 8, 17, 10, 17, 12, 17, 332, 9, 17, 1, 18, 1, 18, 1, 18, 3, 18, 337, 8, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 5, 19, 345, 8, 19, 10, 19, 12, 19, 348, 9, 19, 1, 19, 3, 19, 351, 8, 19, 1, 20, 1, 20, 1, 20, 3, 20, 356, 8, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 5, 23, 368, 8, 23, 10, 23, 12, 23, 371, 9, 23, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 377, 8, 24, 10, 24, 12, 24, 380, 9, 24, 1, 24, 3, 24, 383, 8, 24, 1, 24, 1, 24, 3, 24, 387, 8, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 3, 26, 394, 8, 26, 1, 26, 1, 26, 3, 26, 398, 8, 26, 1, 27, 1, 27, 1, 27, 5, 27, 403, 8, 27, 10, 27, 12, 27, 406, 9, 27, 1, 28, 1, 28, 1, 28, 3, 28, 411, 8, 28, 1, 29, 1, 29, 1, 29, 5, 29, 416, 8, 29, 10, 29, 12, 29, 419, 9, 29, 1, 30, 1, 30, 1, 30, 5, 30, 424, 8, 30, 10, 30, 12, 30, 427, 9, 30, 1, 31, 1, 31, 1, 31, 5, 31, 432, 8, 31, 10, 31, 12, 31, 435, 9, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 3, 33, 442, 8, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 457, 8, 34, 10, 34, 12, 34, 460, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 468, 8, 34, 10, 34, 12, 34, 471, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 479, 8, 34, 10, 34, 12, 34, 482, 9, 34, 1, 34, 1, 34, 3, 34, 486, 8, 34, 1, 35, 1, 35, 3, 35, 490, 8, 35, 1, 36, 1, 36, 1, 36, 3, 36, 495, 8, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 504, 8, 38, 10, 38, 12, 38, 507, 9, 38, 1, 39, 1, 39, 3, 39, 511, 8, 39, 1, 39, 1, 39, 3, 39, 515, 8, 39, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 5, 42, 527, 8, 42, 10, 42, 12, 42, 530, 9, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 3, 44, 540, 8, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 5, 47, 552, 8, 47, 10, 47, 12, 47, 555, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 50, 1, 50, 3, 50, 565, 8, 50, 1, 51, 3, 51, 568, 8, 51, 1, 51, 1, 51, 1, 52, 3, 52, 573, 8, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 595, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 5, 58, 601, 8, 58, 10, 58, 12, 58, 604, 9, 58, 3, 58, 606, 8, 58, 1, 59, 1, 59, 1, 59, 3, 59, 611, 8, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 3, 61, 624, 8, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 5, 64, 637, 8, 64, 10, 64, 12, 64, 640, 9, 64, 1, 65, 1, 65, 1, 65, 0, 4, 2, 10, 18, 20, 66, 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, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 0, 9, 1, 0, 63, 64, 1, 0, 65, 67, 2, 0, 29, 29, 82, 82, 1, 0, 73, 74, 2, 0, 34, 34, 39, 39, 2, 0, 42, 42, 45, 45, 2, 0, 41, 41, 55, 55, 2, 0, 56, 56, 58, 62, 2, 0, 17, 17, 22, 23, 669, 0, 132, 1, 0, 0, 0, 2, 135, 1, 0, 0, 0, 4, 152, 1, 0, 0, 0, 6, 171, 1, 0, 0, 0, 8, 173, 1, 0, 0, 0, 10, 205, 1, 0, 0, 0, 12, 232, 1, 0, 0, 0, 14, 234, 1, 0, 0, 0, 16, 247, 1, 0, 0, 0, 18, 253, 1, 0, 0, 0, 20, 274, 1, 0, 0, 0, 22, 284, 1, 0, 0, 0, 24, 303, 1, 0, 0, 0, 26, 305, 1, 0, 0, 0, 28, 316, 1, 0, 0, 0, 30, 320, 1, 0, 0, 0, 32, 322, 1, 0, 0, 0, 34, 325, 1, 0, 0, 0, 36, 336, 1, 0, 0, 0, 38, 340, 1, 0, 0, 0, 40, 355, 1, 0, 0, 0, 42, 359, 1, 0, 0, 0, 44, 361, 1, 0, 0, 0, 46, 363, 1, 0, 0, 0, 48, 372, 1, 0, 0, 0, 50, 388, 1, 0, 0, 0, 52, 391, 1, 0, 0, 0, 54, 399, 1, 0, 0, 0, 56, 407, 1, 0, 0, 0, 58, 412, 1, 0, 0, 0, 60, 420, 1, 0, 0, 0, 62, 428, 1, 0, 0, 0, 64, 436, 1, 0, 0, 0, 66, 441, 1, 0, 0, 0, 68, 485, 1, 0, 0, 0, 70, 489, 1, 0, 0, 0, 72, 494, 1, 0, 0, 0, 74, 496, 1, 0, 0, 0, 76, 499, 1, 0, 0, 0, 78, 508, 1, 0, 0, 0, 80, 516, 1, 0, 0, 0, 82, 519, 1, 0, 0, 0, 84, 522, 1, 0, 0, 0, 86, 531, 1, 0, 0, 0, 88, 535, 1, 0, 0, 0, 90, 541, 1, 0, 0, 0, 92, 545, 1, 0, 0, 0, 94, 548, 1, 0, 0, 0, 96, 556, 1, 0, 0, 0, 98, 560, 1, 0, 0, 0, 100, 564, 1, 0, 0, 0, 102, 567, 1, 0, 0, 0, 104, 572, 1, 0, 0, 0, 106, 576, 1, 0, 0, 0, 108, 578, 1, 0, 0, 0, 110, 580, 1, 0, 0, 0, 112, 583, 1, 0, 0, 0, 114, 587, 1, 0, 0, 0, 116, 590, 1, 0, 0, 0, 118, 610, 1, 0, 0, 0, 120, 614, 1, 0, 0, 0, 122, 619, 1, 0, 0, 0, 124, 625, 1, 0, 0, 0, 126, 630, 1, 0, 0, 0, 128, 632, 1, 0, 0, 0, 130, 641, 1, 0, 0, 0, 132, 133, 3, 2, 1, 0, 133, 134, 5, 0, 0, 1, 134, 1, 1, 0, 0, 0, 135, 136, 6, 1, -1, 0, 136, 137, 3, 4, 2, 0, 137, 143, 1, 0, 0, 0, 138, 139, 10, 1, 0, 0, 139, 140, 5, 28, 0, 0, 140, 142, 3, 6, 3, 0, 141, 138, 1, 0, 0, 0, 142, 145, 1, 0, 0, 0, 143, 141, 1, 0, 0, 0, 143, 144, 1, 0, 0, 0, 144, 3, 1, 0, 0, 0, 145, 143, 1, 0, 0, 0, 146, 153, 3, 110, 55, 0, 147, 153, 3, 38, 19, 0, 148, 153, 3, 32, 16, 0, 149, 153, 3, 114, 57, 0, 150, 151, 4, 2, 1, 0, 151, 153, 3, 48, 24, 0, 152, 146, 1, 0, 0, 0, 152, 147, 1, 0, 0, 0, 152, 148, 1, 0, 0, 0, 152, 149, 1, 0, 0, 0, 152, 150, 1, 0, 0, 0, 153, 5, 1, 0, 0, 0, 154, 172, 3, 50, 25, 0, 155, 172, 3, 8, 4, 0, 156, 172, 3, 80, 40, 0, 157, 172, 3, 74, 37, 0, 158, 172, 3, 52, 26, 0, 159, 172, 3, 76, 38, 0, 160, 172, 3, 82, 41, 0, 161, 172, 3, 84, 42, 0, 162, 172, 3, 88, 44, 0, 163, 172, 3, 90, 45, 0, 164, 172, 3, 116, 58, 0, 165, 172, 3, 92, 46, 0, 166, 172, 3, 124, 62, 0, 167, 168, 4, 3, 2, 0, 168, 172, 3, 122, 61, 0, 169, 170, 4, 3, 3, 0, 170, 172, 3, 120, 60, 0, 171, 154, 1, 0, 0, 0, 171, 155, 1, 0, 0, 0, 171, 156, 1, 0, 0, 0, 171, 157, 1, 0, 0, 0, 171, 158, 1, 0, 0, 0, 171, 159, 1, 0, 0, 0, 171, 160, 1, 0, 0, 0, 171, 161, 1, 0, 0, 0, 171, 162, 1, 0, 0, 0, 171, 163, 1, 0, 0, 0, 171, 164, 1, 0, 0, 0, 171, 165, 1, 0, 0, 0, 171, 166, 1, 0, 0, 0, 171, 167, 1, 0, 0, 0, 171, 169, 1, 0, 0, 0, 172, 7, 1, 0, 0, 0, 173, 174, 5, 16, 0, 0, 174, 175, 3, 10, 5, 0, 175, 9, 1, 0, 0, 0, 176, 177, 6, 5, -1, 0, 177, 178, 5, 48, 0, 0, 178, 206, 3, 10, 5, 8, 179, 206, 3, 16, 8, 0, 180, 206, 3, 12, 6, 0, 181, 183, 3, 16, 8, 0, 182, 184, 5, 48, 0, 0, 183, 182, 1, 0, 0, 0, 183, 184, 1, 0, 0, 0, 184, 185, 1, 0, 0, 0, 185, 186, 5, 43, 0, 0, 186, 187, 5, 47, 0, 0, 187, 192, 3, 16, 8, 0, 188, 189, 5, 38, 0, 0, 189, 191, 3, 16, 8, 0, 190, 188, 1, 0, 0, 0, 191, 194, 1, 0, 0, 0, 192, 190, 1, 0, 0, 0, 192, 193, 1, 0, 0, 0, 193, 195, 1, 0, 0, 0, 194, 192, 1, 0, 0, 0, 195, 196, 5, 54, 0, 0, 196, 206, 1, 0, 0, 0, 197, 198, 3, 16, 8, 0, 198, 200, 5, 44, 0, 0, 199, 201, 5, 48, 0, 0, 200, 199, 1, 0, 0, 0, 200, 201, 1, 0, 0, 0, 201, 202, 1, 0, 0, 0, 202, 203, 5, 49, 0, 0, 203, 206, 1, 0, 0, 0, 204, 206, 3, 14, 7, 0, 205, 176, 1, 0, 0, 0, 205, 179, 1, 0, 0, 0, 205, 180, 1, 0, 0, 0, 205, 181, 1, 0, 0, 0, 205, 197, 1, 0, 0, 0, 205, 204, 1, 0, 0, 0, 206, 215, 1, 0, 0, 0, 207, 208, 10, 5, 0, 0, 208, 209, 5, 33, 0, 0, 209, 214, 3, 10, 5, 6, 210, 211, 10, 4, 0, 0, 211, 212, 5, 51, 0, 0, 212, 214, 3, 10, 5, 5, 213, 207, 1, 0, 0, 0, 213, 210, 1, 0, 0, 0, 214, 217, 1, 0, 0, 0, 215, 213, 1, 0, 0, 0, 215, 216, 1, 0, 0, 0, 216, 11, 1, 0, 0, 0, 217, 215, 1, 0, 0, 0, 218, 220, 3, 16, 8, 0, 219, 221, 5, 48, 0, 0, 220, 219, 1, 0, 0, 0, 220, 221, 1, 0, 0, 0, 221, 222, 1, 0, 0, 0, 222, 223, 5, 46, 0, 0, 223, 224, 3, 106, 53, 0, 224, 233, 1, 0, 0, 0, 225, 227, 3, 16, 8, 0, 226, 228, 5, 48, 0, 0, 227, 226, 1, 0, 0, 0, 227, 228, 1, 0, 0, 0, 228, 229, 1, 0, 0, 0, 229, 230, 5, 53, 0, 0, 230, 231, 3, 106, 53, 0, 231, 233, 1, 0, 0, 0, 232, 218, 1, 0, 0, 0, 232, 225, 1, 0, 0, 0, 233, 13, 1, 0, 0, 0, 234, 237, 3, 58, 29, 0, 235, 236, 5, 36, 0, 0, 236, 238, 3, 30, 15, 0, 237, 235, 1, 0, 0, 0, 237, 238, 1, 0, 0, 0, 238, 239, 1, 0, 0, 0, 239, 240, 5, 37, 0, 0, 240, 241, 3, 68, 34, 0, 241, 15, 1, 0, 0, 0, 242, 248, 3, 18, 9, 0, 243, 244, 3, 18, 9, 0, 244, 245, 3, 108, 54, 0, 245, 246, 3, 18, 9, 0, 246, 248, 1, 0, 0, 0, 247, 242, 1, 0, 0, 0, 247, 243, 1, 0, 0, 0, 248, 17, 1, 0, 0, 0, 249, 250, 6, 9, -1, 0, 250, 254, 3, 20, 10, 0, 251, 252, 7, 0, 0, 0, 252, 254, 3, 18, 9, 3, 253, 249, 1, 0, 0, 0, 253, 251, 1, 0, 0, 0, 254, 263, 1, 0, 0, 0, 255, 256, 10, 2, 0, 0, 256, 257, 7, 1, 0, 0, 257, 262, 3, 18, 9, 3, 258, 259, 10, 1, 0, 0, 259, 260, 7, 0, 0, 0, 260, 262, 3, 18, 9, 2, 261, 255, 1, 0, 0, 0, 261, 258, 1, 0, 0, 0, 262, 265, 1, 0, 0, 0, 263, 261, 1, 0, 0, 0, 263, 264, 1, 0, 0, 0, 264, 19, 1, 0, 0, 0, 265, 263, 1, 0, 0, 0, 266, 267, 6, 10, -1, 0, 267, 275, 3, 68, 34, 0, 268, 275, 3, 58, 29, 0, 269, 275, 3, 22, 11, 0, 270, 271, 5, 47, 0, 0, 271, 272, 3, 10, 5, 0, 272, 273, 5, 54, 0, 0, 273, 275, 1, 0, 0, 0, 274, 266, 1, 0, 0, 0, 274, 268, 1, 0, 0, 0, 274, 269, 1, 0, 0, 0, 274, 270, 1, 0, 0, 0, 275, 281, 1, 0, 0, 0, 276, 277, 10, 1, 0, 0, 277, 278, 5, 36, 0, 0, 278, 280, 3, 30, 15, 0, 279, 276, 1, 0, 0, 0, 280, 283, 1, 0, 0, 0, 281, 279, 1, 0, 0, 0, 281, 282, 1, 0, 0, 0, 282, 21, 1, 0, 0, 0, 283, 281, 1, 0, 0, 0, 284, 285, 3, 24, 12, 0, 285, 299, 5, 47, 0, 0, 286, 300, 5, 65, 0, 0, 287, 292, 3, 10, 5, 0, 288, 289, 5, 38, 0, 0, 289, 291, 3, 10, 5, 0, 290, 288, 1, 0, 0, 0, 291, 294, 1, 0, 0, 0, 292, 290, 1, 0, 0, 0, 292, 293, 1, 0, 0, 0, 293, 297, 1, 0, 0, 0, 294, 292, 1, 0, 0, 0, 295, 296, 5, 38, 0, 0, 296, 298, 3, 26, 13, 0, 297, 295, 1, 0, 0, 0, 297, 298, 1, 0, 0, 0, 298, 300, 1, 0, 0, 0, 299, 286, 1, 0, 0, 0, 299, 287, 1, 0, 0, 0, 299, 300, 1, 0, 0, 0, 300, 301, 1, 0, 0, 0, 301, 302, 5, 54, 0, 0, 302, 23, 1, 0, 0, 0, 303, 304, 3, 72, 36, 0, 304, 25, 1, 0, 0, 0, 305, 306, 5, 68, 0, 0, 306, 311, 3, 28, 14, 0, 307, 308, 5, 38, 0, 0, 308, 310, 3, 28, 14, 0, 309, 307, 1, 0, 0, 0, 310, 313, 1, 0, 0, 0, 311, 309, 1, 0, 0, 0, 311, 312, 1, 0, 0, 0, 312, 314, 1, 0, 0, 0, 313, 311, 1, 0, 0, 0, 314, 315, 5, 69, 0, 0, 315, 27, 1, 0, 0, 0, 316, 317, 3, 106, 53, 0, 317, 318, 5, 37, 0, 0, 318, 319, 3, 68, 34, 0, 319, 29, 1, 0, 0, 0, 320, 321, 3, 64, 32, 0, 321, 31, 1, 0, 0, 0, 322, 323, 5, 12, 0, 0, 323, 324, 3, 34, 17, 0, 324, 33, 1, 0, 0, 0, 325, 330, 3, 36, 18, 0, 326, 327, 5, 38, 0, 0, 327, 329, 3, 36, 18, 0, 328, 326, 1, 0, 0, 0, 329, 332, 1, 0, 0, 0, 330, 328, 1, 0, 0, 0, 330, 331, 1, 0, 0, 0, 331, 35, 1, 0, 0, 0, 332, 330, 1, 0, 0, 0, 333, 334, 3, 58, 29, 0, 334, 335, 5, 35, 0, 0, 335, 337, 1, 0, 0, 0, 336, 333, 1, 0, 0, 0, 336, 337, 1, 0, 0, 0, 337, 338, 1, 0, 0, 0, 338, 339, 3, 10, 5, 0, 339, 37, 1, 0, 0, 0, 340, 341, 5, 6, 0, 0, 341, 346, 3, 40, 20, 0, 342, 343, 5, 38, 0, 0, 343, 345, 3, 40, 20, 0, 344, 342, 1, 0, 0, 0, 345, 348, 1, 0, 0, 0, 346, 344, 1, 0, 0, 0, 346, 347, 1, 0, 0, 0, 347, 350, 1, 0, 0, 0, 348, 346, 1, 0, 0, 0, 349, 351, 3, 46, 23, 0, 350, 349, 1, 0, 0, 0, 350, 351, 1, 0, 0, 0, 351, 39, 1, 0, 0, 0, 352, 353, 3, 42, 21, 0, 353, 354, 5, 37, 0, 0, 354, 356, 1, 0, 0, 0, 355, 352, 1, 0, 0, 0, 355, 356, 1, 0, 0, 0, 356, 357, 1, 0, 0, 0, 357, 358, 3, 44, 22, 0, 358, 41, 1, 0, 0, 0, 359, 360, 5, 82, 0, 0, 360, 43, 1, 0, 0, 0, 361, 362, 7, 2, 0, 0, 362, 45, 1, 0, 0, 0, 363, 364, 5, 81, 0, 0, 364, 369, 5, 82, 0, 0, 365, 366, 5, 38, 0, 0, 366, 368, 5, 82, 0, 0, 367, 365, 1, 0, 0, 0, 368, 371, 1, 0, 0, 0, 369, 367, 1, 0, 0, 0, 369, 370, 1, 0, 0, 0, 370, 47, 1, 0, 0, 0, 371, 369, 1, 0, 0, 0, 372, 373, 5, 20, 0, 0, 373, 378, 3, 40, 20, 0, 374, 375, 5, 38, 0, 0, 375, 377, 3, 40, 20, 0, 376, 374, 1, 0, 0, 0, 377, 380, 1, 0, 0, 0, 378, 376, 1, 0, 0, 0, 378, 379, 1, 0, 0, 0, 379, 382, 1, 0, 0, 0, 380, 378, 1, 0, 0, 0, 381, 383, 3, 54, 27, 0, 382, 381, 1, 0, 0, 0, 382, 383, 1, 0, 0, 0, 383, 386, 1, 0, 0, 0, 384, 385, 5, 32, 0, 0, 385, 387, 3, 34, 17, 0, 386, 384, 1, 0, 0, 0, 386, 387, 1, 0, 0, 0, 387, 49, 1, 0, 0, 0, 388, 389, 5, 4, 0, 0, 389, 390, 3, 34, 17, 0, 390, 51, 1, 0, 0, 0, 391, 393, 5, 15, 0, 0, 392, 394, 3, 54, 27, 0, 393, 392, 1, 0, 0, 0, 393, 394, 1, 0, 0, 0, 394, 397, 1, 0, 0, 0, 395, 396, 5, 32, 0, 0, 396, 398, 3, 34, 17, 0, 397, 395, 1, 0, 0, 0, 397, 398, 1, 0, 0, 0, 398, 53, 1, 0, 0, 0, 399, 404, 3, 56, 28, 0, 400, 401, 5, 38, 0, 0, 401, 403, 3, 56, 28, 0, 402, 400, 1, 0, 0, 0, 403, 406, 1, 0, 0, 0, 404, 402, 1, 0, 0, 0, 404, 405, 1, 0, 0, 0, 405, 55, 1, 0, 0, 0, 406, 404, 1, 0, 0, 0, 407, 410, 3, 36, 18, 0, 408, 409, 5, 16, 0, 0, 409, 411, 3, 10, 5, 0, 410, 408, 1, 0, 0, 0, 410, 411, 1, 0, 0, 0, 411, 57, 1, 0, 0, 0, 412, 417, 3, 72, 36, 0, 413, 414, 5, 40, 0, 0, 414, 416, 3, 72, 36, 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, 59, 1, 0, 0, 0, 419, 417, 1, 0, 0, 0, 420, 425, 3, 66, 33, 0, 421, 422, 5, 40, 0, 0, 422, 424, 3, 66, 33, 0, 423, 421, 1, 0, 0, 0, 424, 427, 1, 0, 0, 0, 425, 423, 1, 0, 0, 0, 425, 426, 1, 0, 0, 0, 426, 61, 1, 0, 0, 0, 427, 425, 1, 0, 0, 0, 428, 433, 3, 60, 30, 0, 429, 430, 5, 38, 0, 0, 430, 432, 3, 60, 30, 0, 431, 429, 1, 0, 0, 0, 432, 435, 1, 0, 0, 0, 433, 431, 1, 0, 0, 0, 433, 434, 1, 0, 0, 0, 434, 63, 1, 0, 0, 0, 435, 433, 1, 0, 0, 0, 436, 437, 7, 3, 0, 0, 437, 65, 1, 0, 0, 0, 438, 442, 5, 86, 0, 0, 439, 440, 4, 33, 9, 0, 440, 442, 3, 70, 35, 0, 441, 438, 1, 0, 0, 0, 441, 439, 1, 0, 0, 0, 442, 67, 1, 0, 0, 0, 443, 486, 5, 49, 0, 0, 444, 445, 3, 104, 52, 0, 445, 446, 5, 73, 0, 0, 446, 486, 1, 0, 0, 0, 447, 486, 3, 102, 51, 0, 448, 486, 3, 104, 52, 0, 449, 486, 3, 98, 49, 0, 450, 486, 3, 70, 35, 0, 451, 486, 3, 106, 53, 0, 452, 453, 5, 71, 0, 0, 453, 458, 3, 100, 50, 0, 454, 455, 5, 38, 0, 0, 455, 457, 3, 100, 50, 0, 456, 454, 1, 0, 0, 0, 457, 460, 1, 0, 0, 0, 458, 456, 1, 0, 0, 0, 458, 459, 1, 0, 0, 0, 459, 461, 1, 0, 0, 0, 460, 458, 1, 0, 0, 0, 461, 462, 5, 72, 0, 0, 462, 486, 1, 0, 0, 0, 463, 464, 5, 71, 0, 0, 464, 469, 3, 98, 49, 0, 465, 466, 5, 38, 0, 0, 466, 468, 3, 98, 49, 0, 467, 465, 1, 0, 0, 0, 468, 471, 1, 0, 0, 0, 469, 467, 1, 0, 0, 0, 469, 470, 1, 0, 0, 0, 470, 472, 1, 0, 0, 0, 471, 469, 1, 0, 0, 0, 472, 473, 5, 72, 0, 0, 473, 486, 1, 0, 0, 0, 474, 475, 5, 71, 0, 0, 475, 480, 3, 106, 53, 0, 476, 477, 5, 38, 0, 0, 477, 479, 3, 106, 53, 0, 478, 476, 1, 0, 0, 0, 479, 482, 1, 0, 0, 0, 480, 478, 1, 0, 0, 0, 480, 481, 1, 0, 0, 0, 481, 483, 1, 0, 0, 0, 482, 480, 1, 0, 0, 0, 483, 484, 5, 72, 0, 0, 484, 486, 1, 0, 0, 0, 485, 443, 1, 0, 0, 0, 485, 444, 1, 0, 0, 0, 485, 447, 1, 0, 0, 0, 485, 448, 1, 0, 0, 0, 485, 449, 1, 0, 0, 0, 485, 450, 1, 0, 0, 0, 485, 451, 1, 0, 0, 0, 485, 452, 1, 0, 0, 0, 485, 463, 1, 0, 0, 0, 485, 474, 1, 0, 0, 0, 486, 69, 1, 0, 0, 0, 487, 490, 5, 52, 0, 0, 488, 490, 5, 70, 0, 0, 489, 487, 1, 0, 0, 0, 489, 488, 1, 0, 0, 0, 490, 71, 1, 0, 0, 0, 491, 495, 3, 64, 32, 0, 492, 493, 4, 36, 10, 0, 493, 495, 3, 70, 35, 0, 494, 491, 1, 0, 0, 0, 494, 492, 1, 0, 0, 0, 495, 73, 1, 0, 0, 0, 496, 497, 5, 9, 0, 0, 497, 498, 5, 30, 0, 0, 498, 75, 1, 0, 0, 0, 499, 500, 5, 14, 0, 0, 500, 505, 3, 78, 39, 0, 501, 502, 5, 38, 0, 0, 502, 504, 3, 78, 39, 0, 503, 501, 1, 0, 0, 0, 504, 507, 1, 0, 0, 0, 505, 503, 1, 0, 0, 0, 505, 506, 1, 0, 0, 0, 506, 77, 1, 0, 0, 0, 507, 505, 1, 0, 0, 0, 508, 510, 3, 10, 5, 0, 509, 511, 7, 4, 0, 0, 510, 509, 1, 0, 0, 0, 510, 511, 1, 0, 0, 0, 511, 514, 1, 0, 0, 0, 512, 513, 5, 50, 0, 0, 513, 515, 7, 5, 0, 0, 514, 512, 1, 0, 0, 0, 514, 515, 1, 0, 0, 0, 515, 79, 1, 0, 0, 0, 516, 517, 5, 8, 0, 0, 517, 518, 3, 62, 31, 0, 518, 81, 1, 0, 0, 0, 519, 520, 5, 2, 0, 0, 520, 521, 3, 62, 31, 0, 521, 83, 1, 0, 0, 0, 522, 523, 5, 11, 0, 0, 523, 528, 3, 86, 43, 0, 524, 525, 5, 38, 0, 0, 525, 527, 3, 86, 43, 0, 526, 524, 1, 0, 0, 0, 527, 530, 1, 0, 0, 0, 528, 526, 1, 0, 0, 0, 528, 529, 1, 0, 0, 0, 529, 85, 1, 0, 0, 0, 530, 528, 1, 0, 0, 0, 531, 532, 3, 60, 30, 0, 532, 533, 5, 90, 0, 0, 533, 534, 3, 60, 30, 0, 534, 87, 1, 0, 0, 0, 535, 536, 5, 1, 0, 0, 536, 537, 3, 20, 10, 0, 537, 539, 3, 106, 53, 0, 538, 540, 3, 94, 47, 0, 539, 538, 1, 0, 0, 0, 539, 540, 1, 0, 0, 0, 540, 89, 1, 0, 0, 0, 541, 542, 5, 7, 0, 0, 542, 543, 3, 20, 10, 0, 543, 544, 3, 106, 53, 0, 544, 91, 1, 0, 0, 0, 545, 546, 5, 10, 0, 0, 546, 547, 3, 58, 29, 0, 547, 93, 1, 0, 0, 0, 548, 553, 3, 96, 48, 0, 549, 550, 5, 38, 0, 0, 550, 552, 3, 96, 48, 0, 551, 549, 1, 0, 0, 0, 552, 555, 1, 0, 0, 0, 553, 551, 1, 0, 0, 0, 553, 554, 1, 0, 0, 0, 554, 95, 1, 0, 0, 0, 555, 553, 1, 0, 0, 0, 556, 557, 3, 64, 32, 0, 557, 558, 5, 35, 0, 0, 558, 559, 3, 68, 34, 0, 559, 97, 1, 0, 0, 0, 560, 561, 7, 6, 0, 0, 561, 99, 1, 0, 0, 0, 562, 565, 3, 102, 51, 0, 563, 565, 3, 104, 52, 0, 564, 562, 1, 0, 0, 0, 564, 563, 1, 0, 0, 0, 565, 101, 1, 0, 0, 0, 566, 568, 7, 0, 0, 0, 567, 566, 1, 0, 0, 0, 567, 568, 1, 0, 0, 0, 568, 569, 1, 0, 0, 0, 569, 570, 5, 31, 0, 0, 570, 103, 1, 0, 0, 0, 571, 573, 7, 0, 0, 0, 572, 571, 1, 0, 0, 0, 572, 573, 1, 0, 0, 0, 573, 574, 1, 0, 0, 0, 574, 575, 5, 30, 0, 0, 575, 105, 1, 0, 0, 0, 576, 577, 5, 29, 0, 0, 577, 107, 1, 0, 0, 0, 578, 579, 7, 7, 0, 0, 579, 109, 1, 0, 0, 0, 580, 581, 5, 5, 0, 0, 581, 582, 3, 112, 56, 0, 582, 111, 1, 0, 0, 0, 583, 584, 5, 71, 0, 0, 584, 585, 3, 2, 1, 0, 585, 586, 5, 72, 0, 0, 586, 113, 1, 0, 0, 0, 587, 588, 5, 13, 0, 0, 588, 589, 5, 106, 0, 0, 589, 115, 1, 0, 0, 0, 590, 591, 5, 3, 0, 0, 591, 594, 5, 96, 0, 0, 592, 593, 5, 94, 0, 0, 593, 595, 3, 60, 30, 0, 594, 592, 1, 0, 0, 0, 594, 595, 1, 0, 0, 0, 595, 605, 1, 0, 0, 0, 596, 597, 5, 95, 0, 0, 597, 602, 3, 118, 59, 0, 598, 599, 5, 38, 0, 0, 599, 601, 3, 118, 59, 0, 600, 598, 1, 0, 0, 0, 601, 604, 1, 0, 0, 0, 602, 600, 1, 0, 0, 0, 602, 603, 1, 0, 0, 0, 603, 606, 1, 0, 0, 0, 604, 602, 1, 0, 0, 0, 605, 596, 1, 0, 0, 0, 605, 606, 1, 0, 0, 0, 606, 117, 1, 0, 0, 0, 607, 608, 3, 60, 30, 0, 608, 609, 5, 35, 0, 0, 609, 611, 1, 0, 0, 0, 610, 607, 1, 0, 0, 0, 610, 611, 1, 0, 0, 0, 611, 612, 1, 0, 0, 0, 612, 613, 3, 60, 30, 0, 613, 119, 1, 0, 0, 0, 614, 615, 5, 19, 0, 0, 615, 616, 3, 40, 20, 0, 616, 617, 5, 94, 0, 0, 617, 618, 3, 62, 31, 0, 618, 121, 1, 0, 0, 0, 619, 620, 5, 18, 0, 0, 620, 623, 3, 54, 27, 0, 621, 622, 5, 32, 0, 0, 622, 624, 3, 34, 17, 0, 623, 621, 1, 0, 0, 0, 623, 624, 1, 0, 0, 0, 624, 123, 1, 0, 0, 0, 625, 626, 7, 8, 0, 0, 626, 627, 5, 120, 0, 0, 627, 628, 3, 126, 63, 0, 628, 629, 3, 128, 64, 0, 629, 125, 1, 0, 0, 0, 630, 631, 3, 40, 20, 0, 631, 127, 1, 0, 0, 0, 632, 633, 5, 94, 0, 0, 633, 638, 3, 130, 65, 0, 634, 635, 5, 38, 0, 0, 635, 637, 3, 130, 65, 0, 636, 634, 1, 0, 0, 0, 637, 640, 1, 0, 0, 0, 638, 636, 1, 0, 0, 0, 638, 639, 1, 0, 0, 0, 639, 129, 1, 0, 0, 0, 640, 638, 1, 0, 0, 0, 641, 642, 3, 16, 8, 0, 642, 131, 1, 0, 0, 0, 61, 143, 152, 171, 183, 192, 200, 205, 213, 215, 220, 227, 232, 237, 247, 253, 261, 263, 274, 281, 292, 297, 299, 311, 330, 336, 346, 350, 355, 369, 378, 382, 386, 393, 397, 404, 410, 417, 425, 433, 441, 458, 469, 480, 485, 489, 494, 505, 510, 514, 528, 539, 553, 564, 567, 572, 594, 602, 605, 610, 623, 638] \ No newline at end of file +[4, 1, 134, 659, 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, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 144, 8, 1, 10, 1, 12, 1, 147, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 155, 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, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 176, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 188, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 195, 8, 5, 10, 5, 12, 5, 198, 9, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 205, 8, 5, 1, 5, 1, 5, 1, 5, 3, 5, 210, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 218, 8, 5, 10, 5, 12, 5, 221, 9, 5, 1, 6, 1, 6, 3, 6, 225, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 232, 8, 6, 1, 6, 1, 6, 1, 6, 3, 6, 237, 8, 6, 1, 7, 1, 7, 1, 7, 3, 7, 242, 8, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 252, 8, 8, 1, 9, 1, 9, 1, 9, 1, 9, 3, 9, 258, 8, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 5, 9, 266, 8, 9, 10, 9, 12, 9, 269, 9, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 279, 8, 10, 1, 10, 1, 10, 1, 10, 5, 10, 284, 8, 10, 10, 10, 12, 10, 287, 9, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 295, 8, 11, 10, 11, 12, 11, 298, 9, 11, 1, 11, 1, 11, 3, 11, 302, 8, 11, 3, 11, 304, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 314, 8, 13, 10, 13, 12, 13, 317, 9, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 5, 17, 333, 8, 17, 10, 17, 12, 17, 336, 9, 17, 1, 18, 1, 18, 1, 18, 3, 18, 341, 8, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 5, 19, 349, 8, 19, 10, 19, 12, 19, 352, 9, 19, 1, 19, 3, 19, 355, 8, 19, 1, 20, 1, 20, 1, 20, 3, 20, 360, 8, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 5, 23, 372, 8, 23, 10, 23, 12, 23, 375, 9, 23, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 381, 8, 24, 10, 24, 12, 24, 384, 9, 24, 1, 24, 3, 24, 387, 8, 24, 1, 24, 1, 24, 3, 24, 391, 8, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 3, 26, 398, 8, 26, 1, 26, 1, 26, 3, 26, 402, 8, 26, 1, 27, 1, 27, 1, 27, 5, 27, 407, 8, 27, 10, 27, 12, 27, 410, 9, 27, 1, 28, 1, 28, 1, 28, 3, 28, 415, 8, 28, 1, 29, 1, 29, 1, 29, 5, 29, 420, 8, 29, 10, 29, 12, 29, 423, 9, 29, 1, 30, 1, 30, 1, 30, 5, 30, 428, 8, 30, 10, 30, 12, 30, 431, 9, 30, 1, 31, 1, 31, 1, 31, 5, 31, 436, 8, 31, 10, 31, 12, 31, 439, 9, 31, 1, 32, 1, 32, 1, 33, 1, 33, 3, 33, 445, 8, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 460, 8, 34, 10, 34, 12, 34, 463, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 471, 8, 34, 10, 34, 12, 34, 474, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 482, 8, 34, 10, 34, 12, 34, 485, 9, 34, 1, 34, 1, 34, 3, 34, 489, 8, 34, 1, 35, 1, 35, 3, 35, 493, 8, 35, 1, 36, 1, 36, 3, 36, 497, 8, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 506, 8, 38, 10, 38, 12, 38, 509, 9, 38, 1, 39, 1, 39, 3, 39, 513, 8, 39, 1, 39, 1, 39, 3, 39, 517, 8, 39, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 5, 42, 529, 8, 42, 10, 42, 12, 42, 532, 9, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 3, 44, 542, 8, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 5, 47, 554, 8, 47, 10, 47, 12, 47, 557, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 50, 1, 50, 3, 50, 567, 8, 50, 1, 51, 3, 51, 570, 8, 51, 1, 51, 1, 51, 1, 52, 3, 52, 575, 8, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 597, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 5, 58, 603, 8, 58, 10, 58, 12, 58, 606, 9, 58, 3, 58, 608, 8, 58, 1, 59, 1, 59, 1, 59, 3, 59, 613, 8, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 3, 61, 626, 8, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 5, 64, 639, 8, 64, 10, 64, 12, 64, 642, 9, 64, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 650, 8, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 657, 8, 66, 1, 66, 0, 4, 2, 10, 18, 20, 67, 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, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 0, 9, 1, 0, 64, 65, 1, 0, 66, 68, 2, 0, 30, 30, 83, 83, 1, 0, 74, 75, 2, 0, 35, 35, 40, 40, 2, 0, 43, 43, 46, 46, 2, 0, 42, 42, 56, 56, 2, 0, 57, 57, 59, 63, 2, 0, 17, 17, 23, 24, 686, 0, 134, 1, 0, 0, 0, 2, 137, 1, 0, 0, 0, 4, 154, 1, 0, 0, 0, 6, 175, 1, 0, 0, 0, 8, 177, 1, 0, 0, 0, 10, 209, 1, 0, 0, 0, 12, 236, 1, 0, 0, 0, 14, 238, 1, 0, 0, 0, 16, 251, 1, 0, 0, 0, 18, 257, 1, 0, 0, 0, 20, 278, 1, 0, 0, 0, 22, 288, 1, 0, 0, 0, 24, 307, 1, 0, 0, 0, 26, 309, 1, 0, 0, 0, 28, 320, 1, 0, 0, 0, 30, 324, 1, 0, 0, 0, 32, 326, 1, 0, 0, 0, 34, 329, 1, 0, 0, 0, 36, 340, 1, 0, 0, 0, 38, 344, 1, 0, 0, 0, 40, 359, 1, 0, 0, 0, 42, 363, 1, 0, 0, 0, 44, 365, 1, 0, 0, 0, 46, 367, 1, 0, 0, 0, 48, 376, 1, 0, 0, 0, 50, 392, 1, 0, 0, 0, 52, 395, 1, 0, 0, 0, 54, 403, 1, 0, 0, 0, 56, 411, 1, 0, 0, 0, 58, 416, 1, 0, 0, 0, 60, 424, 1, 0, 0, 0, 62, 432, 1, 0, 0, 0, 64, 440, 1, 0, 0, 0, 66, 444, 1, 0, 0, 0, 68, 488, 1, 0, 0, 0, 70, 492, 1, 0, 0, 0, 72, 496, 1, 0, 0, 0, 74, 498, 1, 0, 0, 0, 76, 501, 1, 0, 0, 0, 78, 510, 1, 0, 0, 0, 80, 518, 1, 0, 0, 0, 82, 521, 1, 0, 0, 0, 84, 524, 1, 0, 0, 0, 86, 533, 1, 0, 0, 0, 88, 537, 1, 0, 0, 0, 90, 543, 1, 0, 0, 0, 92, 547, 1, 0, 0, 0, 94, 550, 1, 0, 0, 0, 96, 558, 1, 0, 0, 0, 98, 562, 1, 0, 0, 0, 100, 566, 1, 0, 0, 0, 102, 569, 1, 0, 0, 0, 104, 574, 1, 0, 0, 0, 106, 578, 1, 0, 0, 0, 108, 580, 1, 0, 0, 0, 110, 582, 1, 0, 0, 0, 112, 585, 1, 0, 0, 0, 114, 589, 1, 0, 0, 0, 116, 592, 1, 0, 0, 0, 118, 612, 1, 0, 0, 0, 120, 616, 1, 0, 0, 0, 122, 621, 1, 0, 0, 0, 124, 627, 1, 0, 0, 0, 126, 632, 1, 0, 0, 0, 128, 634, 1, 0, 0, 0, 130, 643, 1, 0, 0, 0, 132, 645, 1, 0, 0, 0, 134, 135, 3, 2, 1, 0, 135, 136, 5, 0, 0, 1, 136, 1, 1, 0, 0, 0, 137, 138, 6, 1, -1, 0, 138, 139, 3, 4, 2, 0, 139, 145, 1, 0, 0, 0, 140, 141, 10, 1, 0, 0, 141, 142, 5, 29, 0, 0, 142, 144, 3, 6, 3, 0, 143, 140, 1, 0, 0, 0, 144, 147, 1, 0, 0, 0, 145, 143, 1, 0, 0, 0, 145, 146, 1, 0, 0, 0, 146, 3, 1, 0, 0, 0, 147, 145, 1, 0, 0, 0, 148, 155, 3, 110, 55, 0, 149, 155, 3, 38, 19, 0, 150, 155, 3, 32, 16, 0, 151, 155, 3, 114, 57, 0, 152, 153, 4, 2, 1, 0, 153, 155, 3, 48, 24, 0, 154, 148, 1, 0, 0, 0, 154, 149, 1, 0, 0, 0, 154, 150, 1, 0, 0, 0, 154, 151, 1, 0, 0, 0, 154, 152, 1, 0, 0, 0, 155, 5, 1, 0, 0, 0, 156, 176, 3, 50, 25, 0, 157, 176, 3, 8, 4, 0, 158, 176, 3, 80, 40, 0, 159, 176, 3, 74, 37, 0, 160, 176, 3, 52, 26, 0, 161, 176, 3, 76, 38, 0, 162, 176, 3, 82, 41, 0, 163, 176, 3, 84, 42, 0, 164, 176, 3, 88, 44, 0, 165, 176, 3, 90, 45, 0, 166, 176, 3, 116, 58, 0, 167, 176, 3, 92, 46, 0, 168, 176, 3, 124, 62, 0, 169, 170, 4, 3, 2, 0, 170, 176, 3, 122, 61, 0, 171, 172, 4, 3, 3, 0, 172, 176, 3, 120, 60, 0, 173, 174, 4, 3, 4, 0, 174, 176, 3, 132, 66, 0, 175, 156, 1, 0, 0, 0, 175, 157, 1, 0, 0, 0, 175, 158, 1, 0, 0, 0, 175, 159, 1, 0, 0, 0, 175, 160, 1, 0, 0, 0, 175, 161, 1, 0, 0, 0, 175, 162, 1, 0, 0, 0, 175, 163, 1, 0, 0, 0, 175, 164, 1, 0, 0, 0, 175, 165, 1, 0, 0, 0, 175, 166, 1, 0, 0, 0, 175, 167, 1, 0, 0, 0, 175, 168, 1, 0, 0, 0, 175, 169, 1, 0, 0, 0, 175, 171, 1, 0, 0, 0, 175, 173, 1, 0, 0, 0, 176, 7, 1, 0, 0, 0, 177, 178, 5, 16, 0, 0, 178, 179, 3, 10, 5, 0, 179, 9, 1, 0, 0, 0, 180, 181, 6, 5, -1, 0, 181, 182, 5, 49, 0, 0, 182, 210, 3, 10, 5, 8, 183, 210, 3, 16, 8, 0, 184, 210, 3, 12, 6, 0, 185, 187, 3, 16, 8, 0, 186, 188, 5, 49, 0, 0, 187, 186, 1, 0, 0, 0, 187, 188, 1, 0, 0, 0, 188, 189, 1, 0, 0, 0, 189, 190, 5, 44, 0, 0, 190, 191, 5, 48, 0, 0, 191, 196, 3, 16, 8, 0, 192, 193, 5, 39, 0, 0, 193, 195, 3, 16, 8, 0, 194, 192, 1, 0, 0, 0, 195, 198, 1, 0, 0, 0, 196, 194, 1, 0, 0, 0, 196, 197, 1, 0, 0, 0, 197, 199, 1, 0, 0, 0, 198, 196, 1, 0, 0, 0, 199, 200, 5, 55, 0, 0, 200, 210, 1, 0, 0, 0, 201, 202, 3, 16, 8, 0, 202, 204, 5, 45, 0, 0, 203, 205, 5, 49, 0, 0, 204, 203, 1, 0, 0, 0, 204, 205, 1, 0, 0, 0, 205, 206, 1, 0, 0, 0, 206, 207, 5, 50, 0, 0, 207, 210, 1, 0, 0, 0, 208, 210, 3, 14, 7, 0, 209, 180, 1, 0, 0, 0, 209, 183, 1, 0, 0, 0, 209, 184, 1, 0, 0, 0, 209, 185, 1, 0, 0, 0, 209, 201, 1, 0, 0, 0, 209, 208, 1, 0, 0, 0, 210, 219, 1, 0, 0, 0, 211, 212, 10, 5, 0, 0, 212, 213, 5, 34, 0, 0, 213, 218, 3, 10, 5, 6, 214, 215, 10, 4, 0, 0, 215, 216, 5, 52, 0, 0, 216, 218, 3, 10, 5, 5, 217, 211, 1, 0, 0, 0, 217, 214, 1, 0, 0, 0, 218, 221, 1, 0, 0, 0, 219, 217, 1, 0, 0, 0, 219, 220, 1, 0, 0, 0, 220, 11, 1, 0, 0, 0, 221, 219, 1, 0, 0, 0, 222, 224, 3, 16, 8, 0, 223, 225, 5, 49, 0, 0, 224, 223, 1, 0, 0, 0, 224, 225, 1, 0, 0, 0, 225, 226, 1, 0, 0, 0, 226, 227, 5, 47, 0, 0, 227, 228, 3, 106, 53, 0, 228, 237, 1, 0, 0, 0, 229, 231, 3, 16, 8, 0, 230, 232, 5, 49, 0, 0, 231, 230, 1, 0, 0, 0, 231, 232, 1, 0, 0, 0, 232, 233, 1, 0, 0, 0, 233, 234, 5, 54, 0, 0, 234, 235, 3, 106, 53, 0, 235, 237, 1, 0, 0, 0, 236, 222, 1, 0, 0, 0, 236, 229, 1, 0, 0, 0, 237, 13, 1, 0, 0, 0, 238, 241, 3, 58, 29, 0, 239, 240, 5, 37, 0, 0, 240, 242, 3, 30, 15, 0, 241, 239, 1, 0, 0, 0, 241, 242, 1, 0, 0, 0, 242, 243, 1, 0, 0, 0, 243, 244, 5, 38, 0, 0, 244, 245, 3, 68, 34, 0, 245, 15, 1, 0, 0, 0, 246, 252, 3, 18, 9, 0, 247, 248, 3, 18, 9, 0, 248, 249, 3, 108, 54, 0, 249, 250, 3, 18, 9, 0, 250, 252, 1, 0, 0, 0, 251, 246, 1, 0, 0, 0, 251, 247, 1, 0, 0, 0, 252, 17, 1, 0, 0, 0, 253, 254, 6, 9, -1, 0, 254, 258, 3, 20, 10, 0, 255, 256, 7, 0, 0, 0, 256, 258, 3, 18, 9, 3, 257, 253, 1, 0, 0, 0, 257, 255, 1, 0, 0, 0, 258, 267, 1, 0, 0, 0, 259, 260, 10, 2, 0, 0, 260, 261, 7, 1, 0, 0, 261, 266, 3, 18, 9, 3, 262, 263, 10, 1, 0, 0, 263, 264, 7, 0, 0, 0, 264, 266, 3, 18, 9, 2, 265, 259, 1, 0, 0, 0, 265, 262, 1, 0, 0, 0, 266, 269, 1, 0, 0, 0, 267, 265, 1, 0, 0, 0, 267, 268, 1, 0, 0, 0, 268, 19, 1, 0, 0, 0, 269, 267, 1, 0, 0, 0, 270, 271, 6, 10, -1, 0, 271, 279, 3, 68, 34, 0, 272, 279, 3, 58, 29, 0, 273, 279, 3, 22, 11, 0, 274, 275, 5, 48, 0, 0, 275, 276, 3, 10, 5, 0, 276, 277, 5, 55, 0, 0, 277, 279, 1, 0, 0, 0, 278, 270, 1, 0, 0, 0, 278, 272, 1, 0, 0, 0, 278, 273, 1, 0, 0, 0, 278, 274, 1, 0, 0, 0, 279, 285, 1, 0, 0, 0, 280, 281, 10, 1, 0, 0, 281, 282, 5, 37, 0, 0, 282, 284, 3, 30, 15, 0, 283, 280, 1, 0, 0, 0, 284, 287, 1, 0, 0, 0, 285, 283, 1, 0, 0, 0, 285, 286, 1, 0, 0, 0, 286, 21, 1, 0, 0, 0, 287, 285, 1, 0, 0, 0, 288, 289, 3, 24, 12, 0, 289, 303, 5, 48, 0, 0, 290, 304, 5, 66, 0, 0, 291, 296, 3, 10, 5, 0, 292, 293, 5, 39, 0, 0, 293, 295, 3, 10, 5, 0, 294, 292, 1, 0, 0, 0, 295, 298, 1, 0, 0, 0, 296, 294, 1, 0, 0, 0, 296, 297, 1, 0, 0, 0, 297, 301, 1, 0, 0, 0, 298, 296, 1, 0, 0, 0, 299, 300, 5, 39, 0, 0, 300, 302, 3, 26, 13, 0, 301, 299, 1, 0, 0, 0, 301, 302, 1, 0, 0, 0, 302, 304, 1, 0, 0, 0, 303, 290, 1, 0, 0, 0, 303, 291, 1, 0, 0, 0, 303, 304, 1, 0, 0, 0, 304, 305, 1, 0, 0, 0, 305, 306, 5, 55, 0, 0, 306, 23, 1, 0, 0, 0, 307, 308, 3, 72, 36, 0, 308, 25, 1, 0, 0, 0, 309, 310, 5, 69, 0, 0, 310, 315, 3, 28, 14, 0, 311, 312, 5, 39, 0, 0, 312, 314, 3, 28, 14, 0, 313, 311, 1, 0, 0, 0, 314, 317, 1, 0, 0, 0, 315, 313, 1, 0, 0, 0, 315, 316, 1, 0, 0, 0, 316, 318, 1, 0, 0, 0, 317, 315, 1, 0, 0, 0, 318, 319, 5, 70, 0, 0, 319, 27, 1, 0, 0, 0, 320, 321, 3, 106, 53, 0, 321, 322, 5, 38, 0, 0, 322, 323, 3, 68, 34, 0, 323, 29, 1, 0, 0, 0, 324, 325, 3, 64, 32, 0, 325, 31, 1, 0, 0, 0, 326, 327, 5, 12, 0, 0, 327, 328, 3, 34, 17, 0, 328, 33, 1, 0, 0, 0, 329, 334, 3, 36, 18, 0, 330, 331, 5, 39, 0, 0, 331, 333, 3, 36, 18, 0, 332, 330, 1, 0, 0, 0, 333, 336, 1, 0, 0, 0, 334, 332, 1, 0, 0, 0, 334, 335, 1, 0, 0, 0, 335, 35, 1, 0, 0, 0, 336, 334, 1, 0, 0, 0, 337, 338, 3, 58, 29, 0, 338, 339, 5, 36, 0, 0, 339, 341, 1, 0, 0, 0, 340, 337, 1, 0, 0, 0, 340, 341, 1, 0, 0, 0, 341, 342, 1, 0, 0, 0, 342, 343, 3, 10, 5, 0, 343, 37, 1, 0, 0, 0, 344, 345, 5, 6, 0, 0, 345, 350, 3, 40, 20, 0, 346, 347, 5, 39, 0, 0, 347, 349, 3, 40, 20, 0, 348, 346, 1, 0, 0, 0, 349, 352, 1, 0, 0, 0, 350, 348, 1, 0, 0, 0, 350, 351, 1, 0, 0, 0, 351, 354, 1, 0, 0, 0, 352, 350, 1, 0, 0, 0, 353, 355, 3, 46, 23, 0, 354, 353, 1, 0, 0, 0, 354, 355, 1, 0, 0, 0, 355, 39, 1, 0, 0, 0, 356, 357, 3, 42, 21, 0, 357, 358, 5, 38, 0, 0, 358, 360, 1, 0, 0, 0, 359, 356, 1, 0, 0, 0, 359, 360, 1, 0, 0, 0, 360, 361, 1, 0, 0, 0, 361, 362, 3, 44, 22, 0, 362, 41, 1, 0, 0, 0, 363, 364, 7, 2, 0, 0, 364, 43, 1, 0, 0, 0, 365, 366, 7, 2, 0, 0, 366, 45, 1, 0, 0, 0, 367, 368, 5, 82, 0, 0, 368, 373, 5, 83, 0, 0, 369, 370, 5, 39, 0, 0, 370, 372, 5, 83, 0, 0, 371, 369, 1, 0, 0, 0, 372, 375, 1, 0, 0, 0, 373, 371, 1, 0, 0, 0, 373, 374, 1, 0, 0, 0, 374, 47, 1, 0, 0, 0, 375, 373, 1, 0, 0, 0, 376, 377, 5, 21, 0, 0, 377, 382, 3, 40, 20, 0, 378, 379, 5, 39, 0, 0, 379, 381, 3, 40, 20, 0, 380, 378, 1, 0, 0, 0, 381, 384, 1, 0, 0, 0, 382, 380, 1, 0, 0, 0, 382, 383, 1, 0, 0, 0, 383, 386, 1, 0, 0, 0, 384, 382, 1, 0, 0, 0, 385, 387, 3, 54, 27, 0, 386, 385, 1, 0, 0, 0, 386, 387, 1, 0, 0, 0, 387, 390, 1, 0, 0, 0, 388, 389, 5, 33, 0, 0, 389, 391, 3, 34, 17, 0, 390, 388, 1, 0, 0, 0, 390, 391, 1, 0, 0, 0, 391, 49, 1, 0, 0, 0, 392, 393, 5, 4, 0, 0, 393, 394, 3, 34, 17, 0, 394, 51, 1, 0, 0, 0, 395, 397, 5, 15, 0, 0, 396, 398, 3, 54, 27, 0, 397, 396, 1, 0, 0, 0, 397, 398, 1, 0, 0, 0, 398, 401, 1, 0, 0, 0, 399, 400, 5, 33, 0, 0, 400, 402, 3, 34, 17, 0, 401, 399, 1, 0, 0, 0, 401, 402, 1, 0, 0, 0, 402, 53, 1, 0, 0, 0, 403, 408, 3, 56, 28, 0, 404, 405, 5, 39, 0, 0, 405, 407, 3, 56, 28, 0, 406, 404, 1, 0, 0, 0, 407, 410, 1, 0, 0, 0, 408, 406, 1, 0, 0, 0, 408, 409, 1, 0, 0, 0, 409, 55, 1, 0, 0, 0, 410, 408, 1, 0, 0, 0, 411, 414, 3, 36, 18, 0, 412, 413, 5, 16, 0, 0, 413, 415, 3, 10, 5, 0, 414, 412, 1, 0, 0, 0, 414, 415, 1, 0, 0, 0, 415, 57, 1, 0, 0, 0, 416, 421, 3, 72, 36, 0, 417, 418, 5, 41, 0, 0, 418, 420, 3, 72, 36, 0, 419, 417, 1, 0, 0, 0, 420, 423, 1, 0, 0, 0, 421, 419, 1, 0, 0, 0, 421, 422, 1, 0, 0, 0, 422, 59, 1, 0, 0, 0, 423, 421, 1, 0, 0, 0, 424, 429, 3, 66, 33, 0, 425, 426, 5, 41, 0, 0, 426, 428, 3, 66, 33, 0, 427, 425, 1, 0, 0, 0, 428, 431, 1, 0, 0, 0, 429, 427, 1, 0, 0, 0, 429, 430, 1, 0, 0, 0, 430, 61, 1, 0, 0, 0, 431, 429, 1, 0, 0, 0, 432, 437, 3, 60, 30, 0, 433, 434, 5, 39, 0, 0, 434, 436, 3, 60, 30, 0, 435, 433, 1, 0, 0, 0, 436, 439, 1, 0, 0, 0, 437, 435, 1, 0, 0, 0, 437, 438, 1, 0, 0, 0, 438, 63, 1, 0, 0, 0, 439, 437, 1, 0, 0, 0, 440, 441, 7, 3, 0, 0, 441, 65, 1, 0, 0, 0, 442, 445, 5, 87, 0, 0, 443, 445, 3, 70, 35, 0, 444, 442, 1, 0, 0, 0, 444, 443, 1, 0, 0, 0, 445, 67, 1, 0, 0, 0, 446, 489, 5, 50, 0, 0, 447, 448, 3, 104, 52, 0, 448, 449, 5, 74, 0, 0, 449, 489, 1, 0, 0, 0, 450, 489, 3, 102, 51, 0, 451, 489, 3, 104, 52, 0, 452, 489, 3, 98, 49, 0, 453, 489, 3, 70, 35, 0, 454, 489, 3, 106, 53, 0, 455, 456, 5, 72, 0, 0, 456, 461, 3, 100, 50, 0, 457, 458, 5, 39, 0, 0, 458, 460, 3, 100, 50, 0, 459, 457, 1, 0, 0, 0, 460, 463, 1, 0, 0, 0, 461, 459, 1, 0, 0, 0, 461, 462, 1, 0, 0, 0, 462, 464, 1, 0, 0, 0, 463, 461, 1, 0, 0, 0, 464, 465, 5, 73, 0, 0, 465, 489, 1, 0, 0, 0, 466, 467, 5, 72, 0, 0, 467, 472, 3, 98, 49, 0, 468, 469, 5, 39, 0, 0, 469, 471, 3, 98, 49, 0, 470, 468, 1, 0, 0, 0, 471, 474, 1, 0, 0, 0, 472, 470, 1, 0, 0, 0, 472, 473, 1, 0, 0, 0, 473, 475, 1, 0, 0, 0, 474, 472, 1, 0, 0, 0, 475, 476, 5, 73, 0, 0, 476, 489, 1, 0, 0, 0, 477, 478, 5, 72, 0, 0, 478, 483, 3, 106, 53, 0, 479, 480, 5, 39, 0, 0, 480, 482, 3, 106, 53, 0, 481, 479, 1, 0, 0, 0, 482, 485, 1, 0, 0, 0, 483, 481, 1, 0, 0, 0, 483, 484, 1, 0, 0, 0, 484, 486, 1, 0, 0, 0, 485, 483, 1, 0, 0, 0, 486, 487, 5, 73, 0, 0, 487, 489, 1, 0, 0, 0, 488, 446, 1, 0, 0, 0, 488, 447, 1, 0, 0, 0, 488, 450, 1, 0, 0, 0, 488, 451, 1, 0, 0, 0, 488, 452, 1, 0, 0, 0, 488, 453, 1, 0, 0, 0, 488, 454, 1, 0, 0, 0, 488, 455, 1, 0, 0, 0, 488, 466, 1, 0, 0, 0, 488, 477, 1, 0, 0, 0, 489, 69, 1, 0, 0, 0, 490, 493, 5, 53, 0, 0, 491, 493, 5, 71, 0, 0, 492, 490, 1, 0, 0, 0, 492, 491, 1, 0, 0, 0, 493, 71, 1, 0, 0, 0, 494, 497, 3, 64, 32, 0, 495, 497, 3, 70, 35, 0, 496, 494, 1, 0, 0, 0, 496, 495, 1, 0, 0, 0, 497, 73, 1, 0, 0, 0, 498, 499, 5, 9, 0, 0, 499, 500, 5, 31, 0, 0, 500, 75, 1, 0, 0, 0, 501, 502, 5, 14, 0, 0, 502, 507, 3, 78, 39, 0, 503, 504, 5, 39, 0, 0, 504, 506, 3, 78, 39, 0, 505, 503, 1, 0, 0, 0, 506, 509, 1, 0, 0, 0, 507, 505, 1, 0, 0, 0, 507, 508, 1, 0, 0, 0, 508, 77, 1, 0, 0, 0, 509, 507, 1, 0, 0, 0, 510, 512, 3, 10, 5, 0, 511, 513, 7, 4, 0, 0, 512, 511, 1, 0, 0, 0, 512, 513, 1, 0, 0, 0, 513, 516, 1, 0, 0, 0, 514, 515, 5, 51, 0, 0, 515, 517, 7, 5, 0, 0, 516, 514, 1, 0, 0, 0, 516, 517, 1, 0, 0, 0, 517, 79, 1, 0, 0, 0, 518, 519, 5, 8, 0, 0, 519, 520, 3, 62, 31, 0, 520, 81, 1, 0, 0, 0, 521, 522, 5, 2, 0, 0, 522, 523, 3, 62, 31, 0, 523, 83, 1, 0, 0, 0, 524, 525, 5, 11, 0, 0, 525, 530, 3, 86, 43, 0, 526, 527, 5, 39, 0, 0, 527, 529, 3, 86, 43, 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, 85, 1, 0, 0, 0, 532, 530, 1, 0, 0, 0, 533, 534, 3, 60, 30, 0, 534, 535, 5, 91, 0, 0, 535, 536, 3, 60, 30, 0, 536, 87, 1, 0, 0, 0, 537, 538, 5, 1, 0, 0, 538, 539, 3, 20, 10, 0, 539, 541, 3, 106, 53, 0, 540, 542, 3, 94, 47, 0, 541, 540, 1, 0, 0, 0, 541, 542, 1, 0, 0, 0, 542, 89, 1, 0, 0, 0, 543, 544, 5, 7, 0, 0, 544, 545, 3, 20, 10, 0, 545, 546, 3, 106, 53, 0, 546, 91, 1, 0, 0, 0, 547, 548, 5, 10, 0, 0, 548, 549, 3, 58, 29, 0, 549, 93, 1, 0, 0, 0, 550, 555, 3, 96, 48, 0, 551, 552, 5, 39, 0, 0, 552, 554, 3, 96, 48, 0, 553, 551, 1, 0, 0, 0, 554, 557, 1, 0, 0, 0, 555, 553, 1, 0, 0, 0, 555, 556, 1, 0, 0, 0, 556, 95, 1, 0, 0, 0, 557, 555, 1, 0, 0, 0, 558, 559, 3, 64, 32, 0, 559, 560, 5, 36, 0, 0, 560, 561, 3, 68, 34, 0, 561, 97, 1, 0, 0, 0, 562, 563, 7, 6, 0, 0, 563, 99, 1, 0, 0, 0, 564, 567, 3, 102, 51, 0, 565, 567, 3, 104, 52, 0, 566, 564, 1, 0, 0, 0, 566, 565, 1, 0, 0, 0, 567, 101, 1, 0, 0, 0, 568, 570, 7, 0, 0, 0, 569, 568, 1, 0, 0, 0, 569, 570, 1, 0, 0, 0, 570, 571, 1, 0, 0, 0, 571, 572, 5, 32, 0, 0, 572, 103, 1, 0, 0, 0, 573, 575, 7, 0, 0, 0, 574, 573, 1, 0, 0, 0, 574, 575, 1, 0, 0, 0, 575, 576, 1, 0, 0, 0, 576, 577, 5, 31, 0, 0, 577, 105, 1, 0, 0, 0, 578, 579, 5, 30, 0, 0, 579, 107, 1, 0, 0, 0, 580, 581, 7, 7, 0, 0, 581, 109, 1, 0, 0, 0, 582, 583, 5, 5, 0, 0, 583, 584, 3, 112, 56, 0, 584, 111, 1, 0, 0, 0, 585, 586, 5, 72, 0, 0, 586, 587, 3, 2, 1, 0, 587, 588, 5, 73, 0, 0, 588, 113, 1, 0, 0, 0, 589, 590, 5, 13, 0, 0, 590, 591, 5, 107, 0, 0, 591, 115, 1, 0, 0, 0, 592, 593, 5, 3, 0, 0, 593, 596, 5, 97, 0, 0, 594, 595, 5, 95, 0, 0, 595, 597, 3, 60, 30, 0, 596, 594, 1, 0, 0, 0, 596, 597, 1, 0, 0, 0, 597, 607, 1, 0, 0, 0, 598, 599, 5, 96, 0, 0, 599, 604, 3, 118, 59, 0, 600, 601, 5, 39, 0, 0, 601, 603, 3, 118, 59, 0, 602, 600, 1, 0, 0, 0, 603, 606, 1, 0, 0, 0, 604, 602, 1, 0, 0, 0, 604, 605, 1, 0, 0, 0, 605, 608, 1, 0, 0, 0, 606, 604, 1, 0, 0, 0, 607, 598, 1, 0, 0, 0, 607, 608, 1, 0, 0, 0, 608, 117, 1, 0, 0, 0, 609, 610, 3, 60, 30, 0, 610, 611, 5, 36, 0, 0, 611, 613, 1, 0, 0, 0, 612, 609, 1, 0, 0, 0, 612, 613, 1, 0, 0, 0, 613, 614, 1, 0, 0, 0, 614, 615, 3, 60, 30, 0, 615, 119, 1, 0, 0, 0, 616, 617, 5, 20, 0, 0, 617, 618, 3, 40, 20, 0, 618, 619, 5, 95, 0, 0, 619, 620, 3, 62, 31, 0, 620, 121, 1, 0, 0, 0, 621, 622, 5, 19, 0, 0, 622, 625, 3, 54, 27, 0, 623, 624, 5, 33, 0, 0, 624, 626, 3, 34, 17, 0, 625, 623, 1, 0, 0, 0, 625, 626, 1, 0, 0, 0, 626, 123, 1, 0, 0, 0, 627, 628, 7, 8, 0, 0, 628, 629, 5, 121, 0, 0, 629, 630, 3, 126, 63, 0, 630, 631, 3, 128, 64, 0, 631, 125, 1, 0, 0, 0, 632, 633, 3, 40, 20, 0, 633, 127, 1, 0, 0, 0, 634, 635, 5, 95, 0, 0, 635, 640, 3, 130, 65, 0, 636, 637, 5, 39, 0, 0, 637, 639, 3, 130, 65, 0, 638, 636, 1, 0, 0, 0, 639, 642, 1, 0, 0, 0, 640, 638, 1, 0, 0, 0, 640, 641, 1, 0, 0, 0, 641, 129, 1, 0, 0, 0, 642, 640, 1, 0, 0, 0, 643, 644, 3, 16, 8, 0, 644, 131, 1, 0, 0, 0, 645, 646, 5, 18, 0, 0, 646, 649, 3, 58, 29, 0, 647, 648, 5, 95, 0, 0, 648, 650, 3, 58, 29, 0, 649, 647, 1, 0, 0, 0, 649, 650, 1, 0, 0, 0, 650, 656, 1, 0, 0, 0, 651, 652, 5, 91, 0, 0, 652, 653, 3, 58, 29, 0, 653, 654, 5, 39, 0, 0, 654, 655, 3, 58, 29, 0, 655, 657, 1, 0, 0, 0, 656, 651, 1, 0, 0, 0, 656, 657, 1, 0, 0, 0, 657, 133, 1, 0, 0, 0, 63, 145, 154, 175, 187, 196, 204, 209, 217, 219, 224, 231, 236, 241, 251, 257, 265, 267, 278, 285, 296, 301, 303, 315, 334, 340, 350, 354, 359, 373, 382, 386, 390, 397, 401, 408, 414, 421, 429, 437, 444, 461, 472, 483, 488, 492, 496, 507, 512, 516, 530, 541, 555, 566, 569, 574, 596, 604, 607, 612, 625, 640, 649, 656] \ 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 b28f8ed4e1fa..3691f2374408 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 @@ -27,31 +27,32 @@ public class EsqlBaseParser extends ParserConfig { public static final int DISSECT=1, DROP=2, ENRICH=3, EVAL=4, EXPLAIN=5, FROM=6, GROK=7, KEEP=8, LIMIT=9, MV_EXPAND=10, RENAME=11, ROW=12, SHOW=13, SORT=14, STATS=15, - WHERE=16, JOIN_LOOKUP=17, DEV_INLINESTATS=18, DEV_LOOKUP=19, DEV_METRICS=20, - DEV_JOIN_FULL=21, DEV_JOIN_LEFT=22, DEV_JOIN_RIGHT=23, UNKNOWN_CMD=24, - LINE_COMMENT=25, MULTILINE_COMMENT=26, WS=27, PIPE=28, QUOTED_STRING=29, - INTEGER_LITERAL=30, DECIMAL_LITERAL=31, BY=32, AND=33, ASC=34, ASSIGN=35, - CAST_OP=36, COLON=37, COMMA=38, DESC=39, DOT=40, FALSE=41, FIRST=42, IN=43, - IS=44, LAST=45, LIKE=46, LP=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, LEFT_BRACES=68, - RIGHT_BRACES=69, NAMED_OR_POSITIONAL_PARAM=70, OPENING_BRACKET=71, CLOSING_BRACKET=72, - UNQUOTED_IDENTIFIER=73, QUOTED_IDENTIFIER=74, EXPR_LINE_COMMENT=75, EXPR_MULTILINE_COMMENT=76, - EXPR_WS=77, EXPLAIN_WS=78, EXPLAIN_LINE_COMMENT=79, EXPLAIN_MULTILINE_COMMENT=80, - METADATA=81, UNQUOTED_SOURCE=82, FROM_LINE_COMMENT=83, FROM_MULTILINE_COMMENT=84, - FROM_WS=85, ID_PATTERN=86, PROJECT_LINE_COMMENT=87, PROJECT_MULTILINE_COMMENT=88, - PROJECT_WS=89, AS=90, RENAME_LINE_COMMENT=91, RENAME_MULTILINE_COMMENT=92, - RENAME_WS=93, ON=94, WITH=95, ENRICH_POLICY_NAME=96, ENRICH_LINE_COMMENT=97, - ENRICH_MULTILINE_COMMENT=98, ENRICH_WS=99, ENRICH_FIELD_LINE_COMMENT=100, - ENRICH_FIELD_MULTILINE_COMMENT=101, ENRICH_FIELD_WS=102, MVEXPAND_LINE_COMMENT=103, - MVEXPAND_MULTILINE_COMMENT=104, MVEXPAND_WS=105, INFO=106, SHOW_LINE_COMMENT=107, - SHOW_MULTILINE_COMMENT=108, SHOW_WS=109, SETTING=110, SETTING_LINE_COMMENT=111, - SETTTING_MULTILINE_COMMENT=112, SETTING_WS=113, LOOKUP_LINE_COMMENT=114, - LOOKUP_MULTILINE_COMMENT=115, LOOKUP_WS=116, LOOKUP_FIELD_LINE_COMMENT=117, - LOOKUP_FIELD_MULTILINE_COMMENT=118, LOOKUP_FIELD_WS=119, JOIN=120, USING=121, - JOIN_LINE_COMMENT=122, JOIN_MULTILINE_COMMENT=123, JOIN_WS=124, METRICS_LINE_COMMENT=125, - METRICS_MULTILINE_COMMENT=126, METRICS_WS=127, CLOSING_METRICS_LINE_COMMENT=128, - CLOSING_METRICS_MULTILINE_COMMENT=129, CLOSING_METRICS_WS=130; + WHERE=16, JOIN_LOOKUP=17, DEV_CHANGE_POINT=18, DEV_INLINESTATS=19, DEV_LOOKUP=20, + DEV_METRICS=21, DEV_JOIN_FULL=22, DEV_JOIN_LEFT=23, DEV_JOIN_RIGHT=24, + UNKNOWN_CMD=25, LINE_COMMENT=26, MULTILINE_COMMENT=27, WS=28, PIPE=29, + QUOTED_STRING=30, INTEGER_LITERAL=31, DECIMAL_LITERAL=32, BY=33, AND=34, + ASC=35, ASSIGN=36, CAST_OP=37, COLON=38, COMMA=39, DESC=40, DOT=41, FALSE=42, + FIRST=43, IN=44, IS=45, LAST=46, LIKE=47, LP=48, NOT=49, NULL=50, NULLS=51, + OR=52, PARAM=53, RLIKE=54, RP=55, TRUE=56, EQ=57, CIEQ=58, NEQ=59, LT=60, + LTE=61, GT=62, GTE=63, PLUS=64, MINUS=65, ASTERISK=66, SLASH=67, PERCENT=68, + LEFT_BRACES=69, RIGHT_BRACES=70, NAMED_OR_POSITIONAL_PARAM=71, OPENING_BRACKET=72, + CLOSING_BRACKET=73, UNQUOTED_IDENTIFIER=74, QUOTED_IDENTIFIER=75, EXPR_LINE_COMMENT=76, + EXPR_MULTILINE_COMMENT=77, EXPR_WS=78, EXPLAIN_WS=79, EXPLAIN_LINE_COMMENT=80, + EXPLAIN_MULTILINE_COMMENT=81, METADATA=82, UNQUOTED_SOURCE=83, FROM_LINE_COMMENT=84, + FROM_MULTILINE_COMMENT=85, FROM_WS=86, ID_PATTERN=87, PROJECT_LINE_COMMENT=88, + PROJECT_MULTILINE_COMMENT=89, PROJECT_WS=90, AS=91, RENAME_LINE_COMMENT=92, + RENAME_MULTILINE_COMMENT=93, RENAME_WS=94, ON=95, WITH=96, ENRICH_POLICY_NAME=97, + ENRICH_LINE_COMMENT=98, ENRICH_MULTILINE_COMMENT=99, ENRICH_WS=100, ENRICH_FIELD_LINE_COMMENT=101, + ENRICH_FIELD_MULTILINE_COMMENT=102, ENRICH_FIELD_WS=103, MVEXPAND_LINE_COMMENT=104, + MVEXPAND_MULTILINE_COMMENT=105, MVEXPAND_WS=106, INFO=107, SHOW_LINE_COMMENT=108, + SHOW_MULTILINE_COMMENT=109, SHOW_WS=110, SETTING=111, SETTING_LINE_COMMENT=112, + SETTTING_MULTILINE_COMMENT=113, SETTING_WS=114, LOOKUP_LINE_COMMENT=115, + LOOKUP_MULTILINE_COMMENT=116, LOOKUP_WS=117, LOOKUP_FIELD_LINE_COMMENT=118, + LOOKUP_FIELD_MULTILINE_COMMENT=119, LOOKUP_FIELD_WS=120, JOIN=121, USING=122, + JOIN_LINE_COMMENT=123, JOIN_MULTILINE_COMMENT=124, JOIN_WS=125, METRICS_LINE_COMMENT=126, + METRICS_MULTILINE_COMMENT=127, METRICS_WS=128, CLOSING_METRICS_LINE_COMMENT=129, + CLOSING_METRICS_MULTILINE_COMMENT=130, CLOSING_METRICS_WS=131, CHANGE_POINT_LINE_COMMENT=132, + CHANGE_POINT_MULTILINE_COMMENT=133, CHANGE_POINT_WS=134; 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, @@ -73,7 +74,7 @@ public class EsqlBaseParser extends ParserConfig { RULE_explainCommand = 55, RULE_subqueryExpression = 56, RULE_showCommand = 57, RULE_enrichCommand = 58, RULE_enrichWithClause = 59, RULE_lookupCommand = 60, RULE_inlinestatsCommand = 61, RULE_joinCommand = 62, RULE_joinTarget = 63, - RULE_joinCondition = 64, RULE_joinPredicate = 65; + RULE_joinCondition = 64, RULE_joinPredicate = 65, RULE_changePointCommand = 66; private static String[] makeRuleNames() { return new String[] { "singleStatement", "query", "sourceCommand", "processingCommand", "whereCommand", @@ -89,7 +90,8 @@ public class EsqlBaseParser extends ParserConfig { "commandOptions", "commandOption", "booleanValue", "numericValue", "decimalValue", "integerValue", "string", "comparisonOperator", "explainCommand", "subqueryExpression", "showCommand", "enrichCommand", "enrichWithClause", "lookupCommand", - "inlinestatsCommand", "joinCommand", "joinTarget", "joinCondition", "joinPredicate" + "inlinestatsCommand", "joinCommand", "joinTarget", "joinCondition", "joinPredicate", + "changePointCommand" }; } public static final String[] ruleNames = makeRuleNames(); @@ -99,16 +101,16 @@ public class EsqlBaseParser extends ParserConfig { null, "'dissect'", "'drop'", "'enrich'", "'eval'", "'explain'", "'from'", "'grok'", "'keep'", "'limit'", "'mv_expand'", "'rename'", "'row'", "'show'", "'sort'", "'stats'", "'where'", "'lookup'", null, null, null, null, null, - null, null, null, null, null, "'|'", null, null, null, "'by'", "'and'", - "'asc'", "'='", "'::'", "':'", "','", "'desc'", "'.'", "'false'", "'first'", - "'in'", "'is'", "'last'", "'like'", "'('", "'not'", "'null'", "'nulls'", - "'or'", "'?'", "'rlike'", "')'", "'true'", "'=='", "'=~'", "'!='", "'<'", - "'<='", "'>'", "'>='", "'+'", "'-'", "'*'", "'/'", "'%'", "'{'", "'}'", - null, null, "']'", null, null, null, null, null, null, null, null, "'metadata'", - null, 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, null, null, null, null, null, null, - null, null, null, null, "'join'", "'USING'" + null, null, null, null, null, null, "'|'", null, null, null, "'by'", + "'and'", "'asc'", "'='", "'::'", "':'", "','", "'desc'", "'.'", "'false'", + "'first'", "'in'", "'is'", "'last'", "'like'", "'('", "'not'", "'null'", + "'nulls'", "'or'", "'?'", "'rlike'", "')'", "'true'", "'=='", "'=~'", + "'!='", "'<'", "'<='", "'>'", "'>='", "'+'", "'-'", "'*'", "'/'", "'%'", + "'{'", "'}'", null, null, "']'", null, null, null, null, null, null, + null, null, "'metadata'", null, 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, null, null, + null, null, null, null, null, null, null, null, "'join'", "'USING'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); @@ -116,9 +118,9 @@ public class EsqlBaseParser extends ParserConfig { return new String[] { null, "DISSECT", "DROP", "ENRICH", "EVAL", "EXPLAIN", "FROM", "GROK", "KEEP", "LIMIT", "MV_EXPAND", "RENAME", "ROW", "SHOW", "SORT", "STATS", - "WHERE", "JOIN_LOOKUP", "DEV_INLINESTATS", "DEV_LOOKUP", "DEV_METRICS", - "DEV_JOIN_FULL", "DEV_JOIN_LEFT", "DEV_JOIN_RIGHT", "UNKNOWN_CMD", "LINE_COMMENT", - "MULTILINE_COMMENT", "WS", "PIPE", "QUOTED_STRING", "INTEGER_LITERAL", + "WHERE", "JOIN_LOOKUP", "DEV_CHANGE_POINT", "DEV_INLINESTATS", "DEV_LOOKUP", + "DEV_METRICS", "DEV_JOIN_FULL", "DEV_JOIN_LEFT", "DEV_JOIN_RIGHT", "UNKNOWN_CMD", + "LINE_COMMENT", "MULTILINE_COMMENT", "WS", "PIPE", "QUOTED_STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "AND", "ASC", "ASSIGN", "CAST_OP", "COLON", "COMMA", "DESC", "DOT", "FALSE", "FIRST", "IN", "IS", "LAST", "LIKE", "LP", "NOT", "NULL", "NULLS", "OR", "PARAM", "RLIKE", "RP", "TRUE", "EQ", @@ -139,7 +141,8 @@ public class EsqlBaseParser extends ParserConfig { "LOOKUP_FIELD_LINE_COMMENT", "LOOKUP_FIELD_MULTILINE_COMMENT", "LOOKUP_FIELD_WS", "JOIN", "USING", "JOIN_LINE_COMMENT", "JOIN_MULTILINE_COMMENT", "JOIN_WS", "METRICS_LINE_COMMENT", "METRICS_MULTILINE_COMMENT", "METRICS_WS", "CLOSING_METRICS_LINE_COMMENT", - "CLOSING_METRICS_MULTILINE_COMMENT", "CLOSING_METRICS_WS" + "CLOSING_METRICS_MULTILINE_COMMENT", "CLOSING_METRICS_WS", "CHANGE_POINT_LINE_COMMENT", + "CHANGE_POINT_MULTILINE_COMMENT", "CHANGE_POINT_WS" }; } private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); @@ -226,9 +229,9 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(132); + setState(134); query(0); - setState(133); + setState(135); match(EOF); } } @@ -324,11 +327,11 @@ public class EsqlBaseParser extends ParserConfig { _ctx = _localctx; _prevctx = _localctx; - setState(136); + setState(138); sourceCommand(); } _ctx.stop = _input.LT(-1); - setState(143); + setState(145); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,0,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { @@ -339,16 +342,16 @@ public class EsqlBaseParser extends ParserConfig { { _localctx = new CompositeQueryContext(new QueryContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_query); - setState(138); - if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)"); - setState(139); - match(PIPE); setState(140); + if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)"); + setState(141); + match(PIPE); + setState(142); processingCommand(); } } } - setState(145); + setState(147); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,0,_ctx); } @@ -406,43 +409,43 @@ public class EsqlBaseParser extends ParserConfig { SourceCommandContext _localctx = new SourceCommandContext(_ctx, getState()); enterRule(_localctx, 4, RULE_sourceCommand); try { - setState(152); + setState(154); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,1,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(146); + setState(148); explainCommand(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(147); + setState(149); fromCommand(); } break; case 3: enterOuterAlt(_localctx, 3); { - setState(148); + setState(150); rowCommand(); } break; case 4: enterOuterAlt(_localctx, 4); { - setState(149); + setState(151); showCommand(); } break; case 5: enterOuterAlt(_localctx, 5); { - setState(150); + setState(152); if (!(this.isDevVersion())) throw new FailedPredicateException(this, "this.isDevVersion()"); - setState(151); + setState(153); metricsCommand(); } break; @@ -506,6 +509,9 @@ public class EsqlBaseParser extends ParserConfig { public LookupCommandContext lookupCommand() { return getRuleContext(LookupCommandContext.class,0); } + public ChangePointCommandContext changePointCommand() { + return getRuleContext(ChangePointCommandContext.class,0); + } @SuppressWarnings("this-escape") public ProcessingCommandContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); @@ -530,118 +536,127 @@ public class EsqlBaseParser extends ParserConfig { ProcessingCommandContext _localctx = new ProcessingCommandContext(_ctx, getState()); enterRule(_localctx, 6, RULE_processingCommand); try { - setState(171); + setState(175); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,2,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(154); + setState(156); evalCommand(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(155); + setState(157); whereCommand(); } break; case 3: enterOuterAlt(_localctx, 3); { - setState(156); + setState(158); keepCommand(); } break; case 4: enterOuterAlt(_localctx, 4); { - setState(157); + setState(159); limitCommand(); } break; case 5: enterOuterAlt(_localctx, 5); { - setState(158); + setState(160); statsCommand(); } break; case 6: enterOuterAlt(_localctx, 6); { - setState(159); + setState(161); sortCommand(); } break; case 7: enterOuterAlt(_localctx, 7); { - setState(160); + setState(162); dropCommand(); } break; case 8: enterOuterAlt(_localctx, 8); { - setState(161); + setState(163); renameCommand(); } break; case 9: enterOuterAlt(_localctx, 9); { - setState(162); + setState(164); dissectCommand(); } break; case 10: enterOuterAlt(_localctx, 10); { - setState(163); + setState(165); grokCommand(); } break; case 11: enterOuterAlt(_localctx, 11); { - setState(164); + setState(166); enrichCommand(); } break; case 12: enterOuterAlt(_localctx, 12); { - setState(165); + setState(167); mvExpandCommand(); } break; case 13: enterOuterAlt(_localctx, 13); { - setState(166); + setState(168); joinCommand(); } break; case 14: enterOuterAlt(_localctx, 14); { - setState(167); + setState(169); if (!(this.isDevVersion())) throw new FailedPredicateException(this, "this.isDevVersion()"); - setState(168); + setState(170); inlinestatsCommand(); } break; case 15: enterOuterAlt(_localctx, 15); { - setState(169); + setState(171); if (!(this.isDevVersion())) throw new FailedPredicateException(this, "this.isDevVersion()"); - setState(170); + setState(172); lookupCommand(); } break; + case 16: + enterOuterAlt(_localctx, 16); + { + setState(173); + if (!(this.isDevVersion())) throw new FailedPredicateException(this, "this.isDevVersion()"); + setState(174); + changePointCommand(); + } + break; } } catch (RecognitionException re) { @@ -687,9 +702,9 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(173); + setState(177); match(WHERE); - setState(174); + setState(178); booleanExpression(0); } } @@ -905,7 +920,7 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(205); + setState(209); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,6,_ctx) ) { case 1: @@ -914,9 +929,9 @@ public class EsqlBaseParser extends ParserConfig { _ctx = _localctx; _prevctx = _localctx; - setState(177); + setState(181); match(NOT); - setState(178); + setState(182); booleanExpression(8); } break; @@ -925,7 +940,7 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new BooleanDefaultContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(179); + setState(183); valueExpression(); } break; @@ -934,7 +949,7 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new RegexExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(180); + setState(184); regexBooleanExpression(); } break; @@ -943,41 +958,41 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new LogicalInContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(181); + setState(185); valueExpression(); - setState(183); + setState(187); _errHandler.sync(this); _la = _input.LA(1); if (_la==NOT) { { - setState(182); + setState(186); match(NOT); } } - setState(185); + setState(189); match(IN); - setState(186); + setState(190); match(LP); - setState(187); + setState(191); valueExpression(); - setState(192); + setState(196); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(188); + setState(192); match(COMMA); - setState(189); + setState(193); valueExpression(); } } - setState(194); + setState(198); _errHandler.sync(this); _la = _input.LA(1); } - setState(195); + setState(199); match(RP); } break; @@ -986,21 +1001,21 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new IsNullContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(197); + setState(201); valueExpression(); - setState(198); + setState(202); match(IS); - setState(200); + setState(204); _errHandler.sync(this); _la = _input.LA(1); if (_la==NOT) { { - setState(199); + setState(203); match(NOT); } } - setState(202); + setState(206); match(NULL); } break; @@ -1009,13 +1024,13 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new MatchExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(204); + setState(208); matchBooleanExpression(); } break; } _ctx.stop = _input.LT(-1); - setState(215); + setState(219); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,8,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { @@ -1023,7 +1038,7 @@ public class EsqlBaseParser extends ParserConfig { if ( _parseListeners!=null ) triggerExitRuleEvent(); _prevctx = _localctx; { - setState(213); + setState(217); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,7,_ctx) ) { case 1: @@ -1031,11 +1046,11 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new LogicalBinaryContext(new BooleanExpressionContext(_parentctx, _parentState)); ((LogicalBinaryContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_booleanExpression); - setState(207); + setState(211); if (!(precpred(_ctx, 5))) throw new FailedPredicateException(this, "precpred(_ctx, 5)"); - setState(208); + setState(212); ((LogicalBinaryContext)_localctx).operator = match(AND); - setState(209); + setState(213); ((LogicalBinaryContext)_localctx).right = booleanExpression(6); } break; @@ -1044,18 +1059,18 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new LogicalBinaryContext(new BooleanExpressionContext(_parentctx, _parentState)); ((LogicalBinaryContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_booleanExpression); - setState(210); + setState(214); if (!(precpred(_ctx, 4))) throw new FailedPredicateException(this, "precpred(_ctx, 4)"); - setState(211); + setState(215); ((LogicalBinaryContext)_localctx).operator = match(OR); - setState(212); + setState(216); ((LogicalBinaryContext)_localctx).right = booleanExpression(5); } break; } } } - setState(217); + setState(221); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,8,_ctx); } @@ -1110,48 +1125,48 @@ public class EsqlBaseParser extends ParserConfig { enterRule(_localctx, 12, RULE_regexBooleanExpression); int _la; try { - setState(232); + setState(236); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,11,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(218); + setState(222); valueExpression(); - setState(220); + setState(224); _errHandler.sync(this); _la = _input.LA(1); if (_la==NOT) { { - setState(219); + setState(223); match(NOT); } } - setState(222); + setState(226); ((RegexBooleanExpressionContext)_localctx).kind = match(LIKE); - setState(223); + setState(227); ((RegexBooleanExpressionContext)_localctx).pattern = string(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(225); + setState(229); valueExpression(); - setState(227); + setState(231); _errHandler.sync(this); _la = _input.LA(1); if (_la==NOT) { { - setState(226); + setState(230); match(NOT); } } - setState(229); + setState(233); ((RegexBooleanExpressionContext)_localctx).kind = match(RLIKE); - setState(230); + setState(234); ((RegexBooleanExpressionContext)_localctx).pattern = string(); } break; @@ -1211,23 +1226,23 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(234); + setState(238); ((MatchBooleanExpressionContext)_localctx).fieldExp = qualifiedName(); - setState(237); + setState(241); _errHandler.sync(this); _la = _input.LA(1); if (_la==CAST_OP) { { - setState(235); + setState(239); match(CAST_OP); - setState(236); + setState(240); ((MatchBooleanExpressionContext)_localctx).fieldType = dataType(); } } - setState(239); + setState(243); match(COLON); - setState(240); + setState(244); ((MatchBooleanExpressionContext)_localctx).matchQuery = constant(); } } @@ -1311,14 +1326,14 @@ public class EsqlBaseParser extends ParserConfig { ValueExpressionContext _localctx = new ValueExpressionContext(_ctx, getState()); enterRule(_localctx, 16, RULE_valueExpression); try { - setState(247); + setState(251); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,13,_ctx) ) { case 1: _localctx = new ValueExpressionDefaultContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(242); + setState(246); operatorExpression(0); } break; @@ -1326,11 +1341,11 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new ComparisonContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(243); + setState(247); ((ComparisonContext)_localctx).left = operatorExpression(0); - setState(244); + setState(248); comparisonOperator(); - setState(245); + setState(249); ((ComparisonContext)_localctx).right = operatorExpression(0); } break; @@ -1455,7 +1470,7 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(253); + setState(257); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,14,_ctx) ) { case 1: @@ -1464,7 +1479,7 @@ public class EsqlBaseParser extends ParserConfig { _ctx = _localctx; _prevctx = _localctx; - setState(250); + setState(254); primaryExpression(0); } break; @@ -1473,7 +1488,7 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new ArithmeticUnaryContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(251); + setState(255); ((ArithmeticUnaryContext)_localctx).operator = _input.LT(1); _la = _input.LA(1); if ( !(_la==PLUS || _la==MINUS) ) { @@ -1484,13 +1499,13 @@ public class EsqlBaseParser extends ParserConfig { _errHandler.reportMatch(this); consume(); } - setState(252); + setState(256); operatorExpression(3); } break; } _ctx.stop = _input.LT(-1); - setState(263); + setState(267); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,16,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { @@ -1498,7 +1513,7 @@ public class EsqlBaseParser extends ParserConfig { if ( _parseListeners!=null ) triggerExitRuleEvent(); _prevctx = _localctx; { - setState(261); + setState(265); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,15,_ctx) ) { case 1: @@ -1506,12 +1521,12 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new ArithmeticBinaryContext(new OperatorExpressionContext(_parentctx, _parentState)); ((ArithmeticBinaryContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_operatorExpression); - setState(255); + setState(259); if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)"); - setState(256); + setState(260); ((ArithmeticBinaryContext)_localctx).operator = _input.LT(1); _la = _input.LA(1); - if ( !(((((_la - 65)) & ~0x3f) == 0 && ((1L << (_la - 65)) & 7L) != 0)) ) { + if ( !(((((_la - 66)) & ~0x3f) == 0 && ((1L << (_la - 66)) & 7L) != 0)) ) { ((ArithmeticBinaryContext)_localctx).operator = (Token)_errHandler.recoverInline(this); } else { @@ -1519,7 +1534,7 @@ public class EsqlBaseParser extends ParserConfig { _errHandler.reportMatch(this); consume(); } - setState(257); + setState(261); ((ArithmeticBinaryContext)_localctx).right = operatorExpression(3); } break; @@ -1528,9 +1543,9 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new ArithmeticBinaryContext(new OperatorExpressionContext(_parentctx, _parentState)); ((ArithmeticBinaryContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_operatorExpression); - setState(258); + setState(262); if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)"); - setState(259); + setState(263); ((ArithmeticBinaryContext)_localctx).operator = _input.LT(1); _la = _input.LA(1); if ( !(_la==PLUS || _la==MINUS) ) { @@ -1541,14 +1556,14 @@ public class EsqlBaseParser extends ParserConfig { _errHandler.reportMatch(this); consume(); } - setState(260); + setState(264); ((ArithmeticBinaryContext)_localctx).right = operatorExpression(2); } break; } } } - setState(265); + setState(269); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,16,_ctx); } @@ -1706,7 +1721,7 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(274); + setState(278); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,17,_ctx) ) { case 1: @@ -1715,7 +1730,7 @@ public class EsqlBaseParser extends ParserConfig { _ctx = _localctx; _prevctx = _localctx; - setState(267); + setState(271); constant(); } break; @@ -1724,7 +1739,7 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new DereferenceContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(268); + setState(272); qualifiedName(); } break; @@ -1733,7 +1748,7 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new FunctionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(269); + setState(273); functionExpression(); } break; @@ -1742,17 +1757,17 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new ParenthesizedExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(270); + setState(274); match(LP); - setState(271); + setState(275); booleanExpression(0); - setState(272); + setState(276); match(RP); } break; } _ctx.stop = _input.LT(-1); - setState(281); + setState(285); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,18,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { @@ -1763,16 +1778,16 @@ public class EsqlBaseParser extends ParserConfig { { _localctx = new InlineCastContext(new PrimaryExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_primaryExpression); - setState(276); + setState(280); if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)"); - setState(277); + setState(281); match(CAST_OP); - setState(278); + setState(282); dataType(); } } } - setState(283); + setState(287); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,18,_ctx); } @@ -1838,50 +1853,64 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(284); + setState(288); functionName(); - setState(285); + setState(289); match(LP); - setState(299); + setState(303); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,21,_ctx) ) { - case 1: + switch (_input.LA(1)) { + case ASTERISK: { - setState(286); + setState(290); match(ASTERISK); } break; - case 2: + case QUOTED_STRING: + case INTEGER_LITERAL: + case DECIMAL_LITERAL: + case FALSE: + case LP: + case NOT: + case NULL: + case PARAM: + case TRUE: + case PLUS: + case MINUS: + case NAMED_OR_POSITIONAL_PARAM: + case OPENING_BRACKET: + case UNQUOTED_IDENTIFIER: + case QUOTED_IDENTIFIER: { { - setState(287); + setState(291); booleanExpression(0); - setState(292); + setState(296); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,19,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(288); + setState(292); match(COMMA); - setState(289); + setState(293); booleanExpression(0); } } } - setState(294); + setState(298); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,19,_ctx); } - setState(297); + setState(301); _errHandler.sync(this); _la = _input.LA(1); if (_la==COMMA) { { - setState(295); + setState(299); match(COMMA); - setState(296); + setState(300); mapExpression(); } } @@ -1889,8 +1918,12 @@ public class EsqlBaseParser extends ParserConfig { } } break; + case RP: + break; + default: + break; } - setState(301); + setState(305); match(RP); } } @@ -1936,7 +1969,7 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(303); + setState(307); identifierOrParameter(); } } @@ -1992,27 +2025,27 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(305); + setState(309); match(LEFT_BRACES); - setState(306); + setState(310); entryExpression(); - setState(311); + setState(315); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(307); + setState(311); match(COMMA); - setState(308); + setState(312); entryExpression(); } } - setState(313); + setState(317); _errHandler.sync(this); _la = _input.LA(1); } - setState(314); + setState(318); match(RIGHT_BRACES); } } @@ -2064,11 +2097,11 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(316); + setState(320); ((EntryExpressionContext)_localctx).key = string(); - setState(317); + setState(321); match(COLON); - setState(318); + setState(322); ((EntryExpressionContext)_localctx).value = constant(); } } @@ -2126,7 +2159,7 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new ToDataTypeContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(320); + setState(324); identifier(); } } @@ -2173,9 +2206,9 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(322); + setState(326); match(ROW); - setState(323); + setState(327); fields(); } } @@ -2229,23 +2262,23 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(325); + setState(329); field(); - setState(330); + setState(334); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,23,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(326); + setState(330); match(COMMA); - setState(327); + setState(331); field(); } } } - setState(332); + setState(336); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,23,_ctx); } @@ -2297,19 +2330,19 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(336); + setState(340); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,24,_ctx) ) { case 1: { - setState(333); + setState(337); qualifiedName(); - setState(334); + setState(338); match(ASSIGN); } break; } - setState(338); + setState(342); booleanExpression(0); } } @@ -2367,34 +2400,34 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(340); + setState(344); match(FROM); - setState(341); + setState(345); indexPattern(); - setState(346); + setState(350); _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(342); + setState(346); match(COMMA); - setState(343); + setState(347); indexPattern(); } } } - setState(348); + setState(352); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,25,_ctx); } - setState(350); + setState(354); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,26,_ctx) ) { case 1: { - setState(349); + setState(353); metadata(); } break; @@ -2447,19 +2480,19 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(355); + setState(359); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,27,_ctx) ) { case 1: { - setState(352); + setState(356); clusterString(); - setState(353); + setState(357); match(COLON); } break; } - setState(357); + setState(361); indexString(); } } @@ -2477,6 +2510,7 @@ public class EsqlBaseParser extends ParserConfig { @SuppressWarnings("CheckReturnValue") public static class ClusterStringContext extends ParserRuleContext { public TerminalNode UNQUOTED_SOURCE() { return getToken(EsqlBaseParser.UNQUOTED_SOURCE, 0); } + public TerminalNode QUOTED_STRING() { return getToken(EsqlBaseParser.QUOTED_STRING, 0); } @SuppressWarnings("this-escape") public ClusterStringContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); @@ -2500,11 +2534,20 @@ public class EsqlBaseParser extends ParserConfig { public final ClusterStringContext clusterString() throws RecognitionException { ClusterStringContext _localctx = new ClusterStringContext(_ctx, getState()); enterRule(_localctx, 42, RULE_clusterString); + int _la; try { enterOuterAlt(_localctx, 1); { - setState(359); - match(UNQUOTED_SOURCE); + setState(363); + _la = _input.LA(1); + if ( !(_la==QUOTED_STRING || _la==UNQUOTED_SOURCE) ) { + _errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } } } catch (RecognitionException re) { @@ -2549,7 +2592,7 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(361); + setState(365); _la = _input.LA(1); if ( !(_la==QUOTED_STRING || _la==UNQUOTED_SOURCE) ) { _errHandler.recoverInline(this); @@ -2610,25 +2653,25 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(363); + setState(367); match(METADATA); - setState(364); + setState(368); match(UNQUOTED_SOURCE); - setState(369); + setState(373); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,28,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(365); + setState(369); match(COMMA); - setState(366); + setState(370); match(UNQUOTED_SOURCE); } } } - setState(371); + setState(375); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,28,_ctx); } @@ -2694,46 +2737,46 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(372); + setState(376); match(DEV_METRICS); - setState(373); + setState(377); indexPattern(); - setState(378); + setState(382); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,29,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(374); + setState(378); match(COMMA); - setState(375); + setState(379); indexPattern(); } } } - setState(380); + setState(384); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,29,_ctx); } - setState(382); + setState(386); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,30,_ctx) ) { case 1: { - setState(381); + setState(385); ((MetricsCommandContext)_localctx).aggregates = aggFields(); } break; } - setState(386); + setState(390); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,31,_ctx) ) { case 1: { - setState(384); + setState(388); match(BY); - setState(385); + setState(389); ((MetricsCommandContext)_localctx).grouping = fields(); } break; @@ -2783,9 +2826,9 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(388); + setState(392); match(EVAL); - setState(389); + setState(393); fields(); } } @@ -2838,26 +2881,26 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(391); + setState(395); match(STATS); - setState(393); + setState(397); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,32,_ctx) ) { case 1: { - setState(392); + setState(396); ((StatsCommandContext)_localctx).stats = aggFields(); } break; } - setState(397); + setState(401); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,33,_ctx) ) { case 1: { - setState(395); + setState(399); match(BY); - setState(396); + setState(400); ((StatsCommandContext)_localctx).grouping = fields(); } break; @@ -2914,23 +2957,23 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(399); + setState(403); aggField(); - setState(404); + setState(408); _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(400); + setState(404); match(COMMA); - setState(401); + setState(405); aggField(); } } } - setState(406); + setState(410); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,34,_ctx); } @@ -2982,16 +3025,16 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(407); + setState(411); field(); - setState(410); + setState(414); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,35,_ctx) ) { case 1: { - setState(408); + setState(412); match(WHERE); - setState(409); + setState(413); booleanExpression(0); } break; @@ -3048,23 +3091,23 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(412); + setState(416); identifierOrParameter(); - setState(417); + setState(421); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,36,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(413); + setState(417); match(DOT); - setState(414); + setState(418); identifierOrParameter(); } } } - setState(419); + setState(423); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,36,_ctx); } @@ -3120,23 +3163,23 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(420); + setState(424); identifierPattern(); - setState(425); + setState(429); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,37,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(421); + setState(425); match(DOT); - setState(422); + setState(426); identifierPattern(); } } } - setState(427); + setState(431); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,37,_ctx); } @@ -3192,23 +3235,23 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(428); + setState(432); qualifiedNamePattern(); - setState(433); + setState(437); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,38,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(429); + setState(433); match(COMMA); - setState(430); + setState(434); qualifiedNamePattern(); } } } - setState(435); + setState(439); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,38,_ctx); } @@ -3256,7 +3299,7 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(436); + setState(440); _la = _input.LA(1); if ( !(_la==UNQUOTED_IDENTIFIER || _la==QUOTED_IDENTIFIER) ) { _errHandler.recoverInline(this); @@ -3309,25 +3352,26 @@ public class EsqlBaseParser extends ParserConfig { IdentifierPatternContext _localctx = new IdentifierPatternContext(_ctx, getState()); enterRule(_localctx, 66, RULE_identifierPattern); try { - setState(441); + setState(444); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,39,_ctx) ) { - case 1: + switch (_input.LA(1)) { + case ID_PATTERN: enterOuterAlt(_localctx, 1); { - setState(438); + setState(442); match(ID_PATTERN); } break; - case 2: + case PARAM: + case NAMED_OR_POSITIONAL_PARAM: enterOuterAlt(_localctx, 2); { - setState(439); - if (!(this.isDevVersion())) throw new FailedPredicateException(this, "this.isDevVersion()"); - setState(440); + setState(443); parameter(); } break; + default: + throw new NoViableAltException(this); } } catch (RecognitionException re) { @@ -3597,14 +3641,14 @@ public class EsqlBaseParser extends ParserConfig { enterRule(_localctx, 68, RULE_constant); int _la; try { - setState(485); + setState(488); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,43,_ctx) ) { case 1: _localctx = new NullLiteralContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(443); + setState(446); match(NULL); } break; @@ -3612,9 +3656,9 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new QualifiedIntegerLiteralContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(444); + setState(447); integerValue(); - setState(445); + setState(448); match(UNQUOTED_IDENTIFIER); } break; @@ -3622,7 +3666,7 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new DecimalLiteralContext(_localctx); enterOuterAlt(_localctx, 3); { - setState(447); + setState(450); decimalValue(); } break; @@ -3630,7 +3674,7 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new IntegerLiteralContext(_localctx); enterOuterAlt(_localctx, 4); { - setState(448); + setState(451); integerValue(); } break; @@ -3638,7 +3682,7 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new BooleanLiteralContext(_localctx); enterOuterAlt(_localctx, 5); { - setState(449); + setState(452); booleanValue(); } break; @@ -3646,7 +3690,7 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new InputParameterContext(_localctx); enterOuterAlt(_localctx, 6); { - setState(450); + setState(453); parameter(); } break; @@ -3654,7 +3698,7 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new StringLiteralContext(_localctx); enterOuterAlt(_localctx, 7); { - setState(451); + setState(454); string(); } break; @@ -3662,27 +3706,27 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new NumericArrayLiteralContext(_localctx); enterOuterAlt(_localctx, 8); { - setState(452); + setState(455); match(OPENING_BRACKET); - setState(453); + setState(456); numericValue(); - setState(458); + setState(461); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(454); + setState(457); match(COMMA); - setState(455); + setState(458); numericValue(); } } - setState(460); + setState(463); _errHandler.sync(this); _la = _input.LA(1); } - setState(461); + setState(464); match(CLOSING_BRACKET); } break; @@ -3690,27 +3734,27 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new BooleanArrayLiteralContext(_localctx); enterOuterAlt(_localctx, 9); { - setState(463); + setState(466); match(OPENING_BRACKET); - setState(464); + setState(467); booleanValue(); - setState(469); + setState(472); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(465); + setState(468); match(COMMA); - setState(466); + setState(469); booleanValue(); } } - setState(471); + setState(474); _errHandler.sync(this); _la = _input.LA(1); } - setState(472); + setState(475); match(CLOSING_BRACKET); } break; @@ -3718,27 +3762,27 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new StringArrayLiteralContext(_localctx); enterOuterAlt(_localctx, 10); { - setState(474); + setState(477); match(OPENING_BRACKET); - setState(475); + setState(478); string(); - setState(480); + setState(483); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(476); + setState(479); match(COMMA); - setState(477); + setState(480); string(); } } - setState(482); + setState(485); _errHandler.sync(this); _la = _input.LA(1); } - setState(483); + setState(486); match(CLOSING_BRACKET); } break; @@ -3812,14 +3856,14 @@ public class EsqlBaseParser extends ParserConfig { ParameterContext _localctx = new ParameterContext(_ctx, getState()); enterRule(_localctx, 70, RULE_parameter); try { - setState(489); + setState(492); _errHandler.sync(this); switch (_input.LA(1)) { case PARAM: _localctx = new InputParamContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(487); + setState(490); match(PARAM); } break; @@ -3827,7 +3871,7 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new InputNamedOrPositionalParamContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(488); + setState(491); match(NAMED_OR_POSITIONAL_PARAM); } break; @@ -3878,25 +3922,27 @@ public class EsqlBaseParser extends ParserConfig { IdentifierOrParameterContext _localctx = new IdentifierOrParameterContext(_ctx, getState()); enterRule(_localctx, 72, RULE_identifierOrParameter); try { - setState(494); + setState(496); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,45,_ctx) ) { - case 1: + switch (_input.LA(1)) { + case UNQUOTED_IDENTIFIER: + case QUOTED_IDENTIFIER: enterOuterAlt(_localctx, 1); { - setState(491); + setState(494); identifier(); } break; - case 2: + case PARAM: + case NAMED_OR_POSITIONAL_PARAM: enterOuterAlt(_localctx, 2); { - setState(492); - if (!(this.isDevVersion())) throw new FailedPredicateException(this, "this.isDevVersion()"); - setState(493); + setState(495); parameter(); } break; + default: + throw new NoViableAltException(this); } } catch (RecognitionException re) { @@ -3940,9 +3986,9 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(496); + setState(498); match(LIMIT); - setState(497); + setState(499); match(INTEGER_LITERAL); } } @@ -3997,25 +4043,25 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(499); + setState(501); match(SORT); - setState(500); + setState(502); orderExpression(); - setState(505); + setState(507); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,46,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(501); + setState(503); match(COMMA); - setState(502); + setState(504); orderExpression(); } } } - setState(507); + setState(509); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,46,_ctx); } @@ -4071,14 +4117,14 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(508); - booleanExpression(0); setState(510); + booleanExpression(0); + setState(512); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,47,_ctx) ) { case 1: { - setState(509); + setState(511); ((OrderExpressionContext)_localctx).ordering = _input.LT(1); _la = _input.LA(1); if ( !(_la==ASC || _la==DESC) ) { @@ -4092,14 +4138,14 @@ public class EsqlBaseParser extends ParserConfig { } break; } - setState(514); + setState(516); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,48,_ctx) ) { case 1: { - setState(512); + setState(514); match(NULLS); - setState(513); + setState(515); ((OrderExpressionContext)_localctx).nullOrdering = _input.LT(1); _la = _input.LA(1); if ( !(_la==FIRST || _la==LAST) ) { @@ -4158,9 +4204,9 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(516); + setState(518); match(KEEP); - setState(517); + setState(519); qualifiedNamePatterns(); } } @@ -4207,9 +4253,9 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(519); + setState(521); match(DROP); - setState(520); + setState(522); qualifiedNamePatterns(); } } @@ -4264,25 +4310,25 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(522); + setState(524); match(RENAME); - setState(523); + setState(525); renameClause(); - setState(528); + setState(530); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,49,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(524); + setState(526); match(COMMA); - setState(525); + setState(527); renameClause(); } } } - setState(530); + setState(532); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,49,_ctx); } @@ -4336,11 +4382,11 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(531); - ((RenameClauseContext)_localctx).oldName = qualifiedNamePattern(); - setState(532); - match(AS); setState(533); + ((RenameClauseContext)_localctx).oldName = qualifiedNamePattern(); + setState(534); + match(AS); + setState(535); ((RenameClauseContext)_localctx).newName = qualifiedNamePattern(); } } @@ -4393,18 +4439,18 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(535); - match(DISSECT); - setState(536); - primaryExpression(0); setState(537); - string(); + match(DISSECT); + setState(538); + primaryExpression(0); setState(539); + string(); + setState(541); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,50,_ctx) ) { case 1: { - setState(538); + setState(540); commandOptions(); } break; @@ -4457,11 +4503,11 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(541); - match(GROK); - setState(542); - primaryExpression(0); setState(543); + match(GROK); + setState(544); + primaryExpression(0); + setState(545); string(); } } @@ -4508,9 +4554,9 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(545); + setState(547); match(MV_EXPAND); - setState(546); + setState(548); qualifiedName(); } } @@ -4564,23 +4610,23 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(548); + setState(550); commandOption(); - setState(553); + setState(555); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,51,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(549); + setState(551); match(COMMA); - setState(550); + setState(552); commandOption(); } } } - setState(555); + setState(557); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,51,_ctx); } @@ -4632,11 +4678,11 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(556); - identifier(); - setState(557); - match(ASSIGN); setState(558); + identifier(); + setState(559); + match(ASSIGN); + setState(560); constant(); } } @@ -4682,7 +4728,7 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(560); + setState(562); _la = _input.LA(1); if ( !(_la==FALSE || _la==TRUE) ) { _errHandler.recoverInline(this); @@ -4737,20 +4783,20 @@ public class EsqlBaseParser extends ParserConfig { NumericValueContext _localctx = new NumericValueContext(_ctx, getState()); enterRule(_localctx, 100, RULE_numericValue); try { - setState(564); + setState(566); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,52,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(562); + setState(564); decimalValue(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(563); + setState(565); integerValue(); } break; @@ -4799,12 +4845,12 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(567); + setState(569); _errHandler.sync(this); _la = _input.LA(1); if (_la==PLUS || _la==MINUS) { { - setState(566); + setState(568); _la = _input.LA(1); if ( !(_la==PLUS || _la==MINUS) ) { _errHandler.recoverInline(this); @@ -4817,7 +4863,7 @@ public class EsqlBaseParser extends ParserConfig { } } - setState(569); + setState(571); match(DECIMAL_LITERAL); } } @@ -4864,12 +4910,12 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(572); + setState(574); _errHandler.sync(this); _la = _input.LA(1); if (_la==PLUS || _la==MINUS) { { - setState(571); + setState(573); _la = _input.LA(1); if ( !(_la==PLUS || _la==MINUS) ) { _errHandler.recoverInline(this); @@ -4882,7 +4928,7 @@ public class EsqlBaseParser extends ParserConfig { } } - setState(574); + setState(576); match(INTEGER_LITERAL); } } @@ -4926,7 +4972,7 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(576); + setState(578); match(QUOTED_STRING); } } @@ -4976,9 +5022,9 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(578); + setState(580); _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 9007199254740992000L) != 0)) ) { + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & -432345564227567616L) != 0)) ) { _errHandler.recoverInline(this); } else { @@ -5031,9 +5077,9 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(580); + setState(582); match(EXPLAIN); - setState(581); + setState(583); subqueryExpression(); } } @@ -5081,11 +5127,11 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(583); - match(OPENING_BRACKET); - setState(584); - query(0); setState(585); + match(OPENING_BRACKET); + setState(586); + query(0); + setState(587); match(CLOSING_BRACKET); } } @@ -5142,9 +5188,9 @@ public class EsqlBaseParser extends ParserConfig { _localctx = new ShowInfoContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(587); + setState(589); match(SHOW); - setState(588); + setState(590); match(INFO); } } @@ -5207,46 +5253,46 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(590); + setState(592); match(ENRICH); - setState(591); + setState(593); ((EnrichCommandContext)_localctx).policyName = match(ENRICH_POLICY_NAME); - setState(594); + setState(596); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,55,_ctx) ) { case 1: { - setState(592); + setState(594); match(ON); - setState(593); + setState(595); ((EnrichCommandContext)_localctx).matchField = qualifiedNamePattern(); } break; } - setState(605); + setState(607); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,57,_ctx) ) { case 1: { - setState(596); + setState(598); match(WITH); - setState(597); + setState(599); enrichWithClause(); - setState(602); + setState(604); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,56,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(598); + setState(600); match(COMMA); - setState(599); + setState(601); enrichWithClause(); } } } - setState(604); + setState(606); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,56,_ctx); } @@ -5303,19 +5349,19 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(610); + setState(612); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,58,_ctx) ) { case 1: { - setState(607); + setState(609); ((EnrichWithClauseContext)_localctx).newName = qualifiedNamePattern(); - setState(608); + setState(610); match(ASSIGN); } break; } - setState(612); + setState(614); ((EnrichWithClauseContext)_localctx).enrichField = qualifiedNamePattern(); } } @@ -5368,13 +5414,13 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(614); - match(DEV_LOOKUP); - setState(615); - ((LookupCommandContext)_localctx).tableName = indexPattern(); setState(616); - match(ON); + match(DEV_LOOKUP); setState(617); + ((LookupCommandContext)_localctx).tableName = indexPattern(); + setState(618); + match(ON); + setState(619); ((LookupCommandContext)_localctx).matchFields = qualifiedNamePatterns(); } } @@ -5427,18 +5473,18 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(619); + setState(621); match(DEV_INLINESTATS); - setState(620); + setState(622); ((InlinestatsCommandContext)_localctx).stats = aggFields(); - setState(623); + setState(625); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,59,_ctx) ) { case 1: { - setState(621); + setState(623); match(BY); - setState(622); + setState(624); ((InlinestatsCommandContext)_localctx).grouping = fields(); } break; @@ -5496,10 +5542,10 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(625); + setState(627); ((JoinCommandContext)_localctx).type = _input.LT(1); _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 12713984L) != 0)) ) { + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 25296896L) != 0)) ) { ((JoinCommandContext)_localctx).type = (Token)_errHandler.recoverInline(this); } else { @@ -5507,11 +5553,11 @@ public class EsqlBaseParser extends ParserConfig { _errHandler.reportMatch(this); consume(); } - setState(626); - match(JOIN); - setState(627); - joinTarget(); setState(628); + match(JOIN); + setState(629); + joinTarget(); + setState(630); joinCondition(); } } @@ -5558,7 +5604,7 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(630); + setState(632); ((JoinTargetContext)_localctx).index = indexPattern(); } } @@ -5613,25 +5659,25 @@ public class EsqlBaseParser extends ParserConfig { int _alt; enterOuterAlt(_localctx, 1); { - setState(632); + setState(634); match(ON); - setState(633); + setState(635); joinPredicate(); - setState(638); + setState(640); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,60,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(634); + setState(636); match(COMMA); - setState(635); + setState(637); joinPredicate(); } } } - setState(640); + setState(642); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,60,_ctx); } @@ -5679,7 +5725,7 @@ public class EsqlBaseParser extends ParserConfig { try { enterOuterAlt(_localctx, 1); { - setState(641); + setState(643); valueExpression(); } } @@ -5694,6 +5740,93 @@ public class EsqlBaseParser extends ParserConfig { return _localctx; } + @SuppressWarnings("CheckReturnValue") + public static class ChangePointCommandContext extends ParserRuleContext { + public QualifiedNameContext value; + public QualifiedNameContext key; + public QualifiedNameContext targetType; + public QualifiedNameContext targetPvalue; + public TerminalNode DEV_CHANGE_POINT() { return getToken(EsqlBaseParser.DEV_CHANGE_POINT, 0); } + public List qualifiedName() { + return getRuleContexts(QualifiedNameContext.class); + } + public QualifiedNameContext qualifiedName(int i) { + return getRuleContext(QualifiedNameContext.class,i); + } + public TerminalNode ON() { return getToken(EsqlBaseParser.ON, 0); } + public TerminalNode AS() { return getToken(EsqlBaseParser.AS, 0); } + public TerminalNode COMMA() { return getToken(EsqlBaseParser.COMMA, 0); } + @SuppressWarnings("this-escape") + public ChangePointCommandContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_changePointCommand; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof EsqlBaseParserListener ) ((EsqlBaseParserListener)listener).enterChangePointCommand(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof EsqlBaseParserListener ) ((EsqlBaseParserListener)listener).exitChangePointCommand(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof EsqlBaseParserVisitor ) return ((EsqlBaseParserVisitor)visitor).visitChangePointCommand(this); + else return visitor.visitChildren(this); + } + } + + public final ChangePointCommandContext changePointCommand() throws RecognitionException { + ChangePointCommandContext _localctx = new ChangePointCommandContext(_ctx, getState()); + enterRule(_localctx, 132, RULE_changePointCommand); + try { + enterOuterAlt(_localctx, 1); + { + setState(645); + match(DEV_CHANGE_POINT); + setState(646); + ((ChangePointCommandContext)_localctx).value = qualifiedName(); + setState(649); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,61,_ctx) ) { + case 1: + { + setState(647); + match(ON); + setState(648); + ((ChangePointCommandContext)_localctx).key = qualifiedName(); + } + break; + } + setState(656); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,62,_ctx) ) { + case 1: + { + setState(651); + match(AS); + setState(652); + ((ChangePointCommandContext)_localctx).targetType = qualifiedName(); + setState(653); + match(COMMA); + setState(654); + ((ChangePointCommandContext)_localctx).targetPvalue = qualifiedName(); + } + break; + } + } + } + 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: @@ -5708,10 +5841,6 @@ public class EsqlBaseParser extends ParserConfig { return operatorExpression_sempred((OperatorExpressionContext)_localctx, predIndex); case 10: return primaryExpression_sempred((PrimaryExpressionContext)_localctx, predIndex); - case 33: - return identifierPattern_sempred((IdentifierPatternContext)_localctx, predIndex); - case 36: - return identifierOrParameter_sempred((IdentifierOrParameterContext)_localctx, predIndex); } return true; } @@ -5735,51 +5864,39 @@ public class EsqlBaseParser extends ParserConfig { return this.isDevVersion(); case 3: return this.isDevVersion(); + case 4: + return this.isDevVersion(); } return true; } private boolean booleanExpression_sempred(BooleanExpressionContext _localctx, int predIndex) { switch (predIndex) { - case 4: - return precpred(_ctx, 5); case 5: + return precpred(_ctx, 5); + case 6: return precpred(_ctx, 4); } return true; } private boolean operatorExpression_sempred(OperatorExpressionContext _localctx, int predIndex) { switch (predIndex) { - case 6: - return precpred(_ctx, 2); case 7: + return precpred(_ctx, 2); + case 8: return precpred(_ctx, 1); } return true; } private boolean primaryExpression_sempred(PrimaryExpressionContext _localctx, int predIndex) { - switch (predIndex) { - case 8: - return precpred(_ctx, 1); - } - return true; - } - private boolean identifierPattern_sempred(IdentifierPatternContext _localctx, int predIndex) { switch (predIndex) { case 9: - return this.isDevVersion(); - } - return true; - } - private boolean identifierOrParameter_sempred(IdentifierOrParameterContext _localctx, int predIndex) { - switch (predIndex) { - case 10: - return this.isDevVersion(); + return precpred(_ctx, 1); } return true; } public static final String _serializedATN = - "\u0004\u0001\u0082\u0284\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001"+ + "\u0004\u0001\u0086\u0293\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"+ @@ -5796,394 +5913,404 @@ public class EsqlBaseParser extends ParserConfig { "1\u00022\u00072\u00023\u00073\u00024\u00074\u00025\u00075\u00026\u0007"+ "6\u00027\u00077\u00028\u00078\u00029\u00079\u0002:\u0007:\u0002;\u0007"+ ";\u0002<\u0007<\u0002=\u0007=\u0002>\u0007>\u0002?\u0007?\u0002@\u0007"+ - "@\u0002A\u0007A\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001"+ - "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0005\u0001\u008e"+ - "\b\u0001\n\u0001\f\u0001\u0091\t\u0001\u0001\u0002\u0001\u0002\u0001\u0002"+ - "\u0001\u0002\u0001\u0002\u0001\u0002\u0003\u0002\u0099\b\u0002\u0001\u0003"+ + "@\u0002A\u0007A\u0002B\u0007B\u0001\u0000\u0001\u0000\u0001\u0000\u0001"+ + "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0005"+ + "\u0001\u0090\b\u0001\n\u0001\f\u0001\u0093\t\u0001\u0001\u0002\u0001\u0002"+ + "\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0003\u0002\u009b\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\u0001\u0003\u0001\u0003\u0003\u0003\u00ac\b\u0003"+ - "\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0005"+ - "\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0003\u0005\u00b8\b\u0005"+ - "\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0005\u0005"+ - "\u00bf\b\u0005\n\u0005\f\u0005\u00c2\t\u0005\u0001\u0005\u0001\u0005\u0001"+ - "\u0005\u0001\u0005\u0001\u0005\u0003\u0005\u00c9\b\u0005\u0001\u0005\u0001"+ - "\u0005\u0001\u0005\u0003\u0005\u00ce\b\u0005\u0001\u0005\u0001\u0005\u0001"+ - "\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0005\u0005\u00d6\b\u0005\n"+ - "\u0005\f\u0005\u00d9\t\u0005\u0001\u0006\u0001\u0006\u0003\u0006\u00dd"+ - "\b\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0003"+ - "\u0006\u00e4\b\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0003\u0006\u00e9"+ - "\b\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0003\u0007\u00ee\b\u0007"+ - "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\b\u0001\b\u0001\b\u0001\b\u0001"+ - "\b\u0003\b\u00f8\b\b\u0001\t\u0001\t\u0001\t\u0001\t\u0003\t\u00fe\b\t"+ - "\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0005\t\u0106\b\t\n\t"+ - "\f\t\u0109\t\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n"+ - "\u0001\n\u0003\n\u0113\b\n\u0001\n\u0001\n\u0001\n\u0005\n\u0118\b\n\n"+ - "\n\f\n\u011b\t\n\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001"+ - "\u000b\u0001\u000b\u0005\u000b\u0123\b\u000b\n\u000b\f\u000b\u0126\t\u000b"+ - "\u0001\u000b\u0001\u000b\u0003\u000b\u012a\b\u000b\u0003\u000b\u012c\b"+ - "\u000b\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001\r\u0001\r\u0001\r"+ - "\u0001\r\u0005\r\u0136\b\r\n\r\f\r\u0139\t\r\u0001\r\u0001\r\u0001\u000e"+ - "\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f\u0001\u0010"+ - "\u0001\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0011\u0005\u0011"+ - "\u0149\b\u0011\n\u0011\f\u0011\u014c\t\u0011\u0001\u0012\u0001\u0012\u0001"+ - "\u0012\u0003\u0012\u0151\b\u0012\u0001\u0012\u0001\u0012\u0001\u0013\u0001"+ - "\u0013\u0001\u0013\u0001\u0013\u0005\u0013\u0159\b\u0013\n\u0013\f\u0013"+ - "\u015c\t\u0013\u0001\u0013\u0003\u0013\u015f\b\u0013\u0001\u0014\u0001"+ - "\u0014\u0001\u0014\u0003\u0014\u0164\b\u0014\u0001\u0014\u0001\u0014\u0001"+ - "\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017\u0001"+ - "\u0017\u0001\u0017\u0005\u0017\u0170\b\u0017\n\u0017\f\u0017\u0173\t\u0017"+ - "\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0005\u0018\u0179\b\u0018"+ - "\n\u0018\f\u0018\u017c\t\u0018\u0001\u0018\u0003\u0018\u017f\b\u0018\u0001"+ - "\u0018\u0001\u0018\u0003\u0018\u0183\b\u0018\u0001\u0019\u0001\u0019\u0001"+ - "\u0019\u0001\u001a\u0001\u001a\u0003\u001a\u018a\b\u001a\u0001\u001a\u0001"+ - "\u001a\u0003\u001a\u018e\b\u001a\u0001\u001b\u0001\u001b\u0001\u001b\u0005"+ - "\u001b\u0193\b\u001b\n\u001b\f\u001b\u0196\t\u001b\u0001\u001c\u0001\u001c"+ - "\u0001\u001c\u0003\u001c\u019b\b\u001c\u0001\u001d\u0001\u001d\u0001\u001d"+ - "\u0005\u001d\u01a0\b\u001d\n\u001d\f\u001d\u01a3\t\u001d\u0001\u001e\u0001"+ - "\u001e\u0001\u001e\u0005\u001e\u01a8\b\u001e\n\u001e\f\u001e\u01ab\t\u001e"+ - "\u0001\u001f\u0001\u001f\u0001\u001f\u0005\u001f\u01b0\b\u001f\n\u001f"+ - "\f\u001f\u01b3\t\u001f\u0001 \u0001 \u0001!\u0001!\u0001!\u0003!\u01ba"+ - "\b!\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001"+ - "\"\u0001\"\u0001\"\u0001\"\u0001\"\u0005\"\u01c9\b\"\n\"\f\"\u01cc\t\""+ - "\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0005\"\u01d4\b\"\n\""+ - "\f\"\u01d7\t\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0005\""+ - "\u01df\b\"\n\"\f\"\u01e2\t\"\u0001\"\u0001\"\u0003\"\u01e6\b\"\u0001#"+ - "\u0001#\u0003#\u01ea\b#\u0001$\u0001$\u0001$\u0003$\u01ef\b$\u0001%\u0001"+ - "%\u0001%\u0001&\u0001&\u0001&\u0001&\u0005&\u01f8\b&\n&\f&\u01fb\t&\u0001"+ - "\'\u0001\'\u0003\'\u01ff\b\'\u0001\'\u0001\'\u0003\'\u0203\b\'\u0001("+ - "\u0001(\u0001(\u0001)\u0001)\u0001)\u0001*\u0001*\u0001*\u0001*\u0005"+ - "*\u020f\b*\n*\f*\u0212\t*\u0001+\u0001+\u0001+\u0001+\u0001,\u0001,\u0001"+ - ",\u0001,\u0003,\u021c\b,\u0001-\u0001-\u0001-\u0001-\u0001.\u0001.\u0001"+ - ".\u0001/\u0001/\u0001/\u0005/\u0228\b/\n/\f/\u022b\t/\u00010\u00010\u0001"+ - "0\u00010\u00011\u00011\u00012\u00012\u00032\u0235\b2\u00013\u00033\u0238"+ - "\b3\u00013\u00013\u00014\u00034\u023d\b4\u00014\u00014\u00015\u00015\u0001"+ - "6\u00016\u00017\u00017\u00017\u00018\u00018\u00018\u00018\u00019\u0001"+ - "9\u00019\u0001:\u0001:\u0001:\u0001:\u0003:\u0253\b:\u0001:\u0001:\u0001"+ - ":\u0001:\u0005:\u0259\b:\n:\f:\u025c\t:\u0003:\u025e\b:\u0001;\u0001;"+ - "\u0001;\u0003;\u0263\b;\u0001;\u0001;\u0001<\u0001<\u0001<\u0001<\u0001"+ - "<\u0001=\u0001=\u0001=\u0001=\u0003=\u0270\b=\u0001>\u0001>\u0001>\u0001"+ - ">\u0001>\u0001?\u0001?\u0001@\u0001@\u0001@\u0001@\u0005@\u027d\b@\n@"+ - "\f@\u0280\t@\u0001A\u0001A\u0001A\u0000\u0004\u0002\n\u0012\u0014B\u0000"+ - "\u0002\u0004\u0006\b\n\f\u000e\u0010\u0012\u0014\u0016\u0018\u001a\u001c"+ - "\u001e \"$&(*,.02468:<>@BDFHJLNPRTVXZ\\^`bdfhjlnprtvxz|~\u0080\u0082\u0000"+ - "\t\u0001\u0000?@\u0001\u0000AC\u0002\u0000\u001d\u001dRR\u0001\u0000I"+ - "J\u0002\u0000\"\"\'\'\u0002\u0000**--\u0002\u0000))77\u0002\u000088:>"+ - "\u0002\u0000\u0011\u0011\u0016\u0017\u029d\u0000\u0084\u0001\u0000\u0000"+ - "\u0000\u0002\u0087\u0001\u0000\u0000\u0000\u0004\u0098\u0001\u0000\u0000"+ - "\u0000\u0006\u00ab\u0001\u0000\u0000\u0000\b\u00ad\u0001\u0000\u0000\u0000"+ - "\n\u00cd\u0001\u0000\u0000\u0000\f\u00e8\u0001\u0000\u0000\u0000\u000e"+ - "\u00ea\u0001\u0000\u0000\u0000\u0010\u00f7\u0001\u0000\u0000\u0000\u0012"+ - "\u00fd\u0001\u0000\u0000\u0000\u0014\u0112\u0001\u0000\u0000\u0000\u0016"+ - "\u011c\u0001\u0000\u0000\u0000\u0018\u012f\u0001\u0000\u0000\u0000\u001a"+ - "\u0131\u0001\u0000\u0000\u0000\u001c\u013c\u0001\u0000\u0000\u0000\u001e"+ - "\u0140\u0001\u0000\u0000\u0000 \u0142\u0001\u0000\u0000\u0000\"\u0145"+ - "\u0001\u0000\u0000\u0000$\u0150\u0001\u0000\u0000\u0000&\u0154\u0001\u0000"+ - "\u0000\u0000(\u0163\u0001\u0000\u0000\u0000*\u0167\u0001\u0000\u0000\u0000"+ - ",\u0169\u0001\u0000\u0000\u0000.\u016b\u0001\u0000\u0000\u00000\u0174"+ - "\u0001\u0000\u0000\u00002\u0184\u0001\u0000\u0000\u00004\u0187\u0001\u0000"+ - "\u0000\u00006\u018f\u0001\u0000\u0000\u00008\u0197\u0001\u0000\u0000\u0000"+ - ":\u019c\u0001\u0000\u0000\u0000<\u01a4\u0001\u0000\u0000\u0000>\u01ac"+ - "\u0001\u0000\u0000\u0000@\u01b4\u0001\u0000\u0000\u0000B\u01b9\u0001\u0000"+ - "\u0000\u0000D\u01e5\u0001\u0000\u0000\u0000F\u01e9\u0001\u0000\u0000\u0000"+ - "H\u01ee\u0001\u0000\u0000\u0000J\u01f0\u0001\u0000\u0000\u0000L\u01f3"+ - "\u0001\u0000\u0000\u0000N\u01fc\u0001\u0000\u0000\u0000P\u0204\u0001\u0000"+ - "\u0000\u0000R\u0207\u0001\u0000\u0000\u0000T\u020a\u0001\u0000\u0000\u0000"+ - "V\u0213\u0001\u0000\u0000\u0000X\u0217\u0001\u0000\u0000\u0000Z\u021d"+ - "\u0001\u0000\u0000\u0000\\\u0221\u0001\u0000\u0000\u0000^\u0224\u0001"+ - "\u0000\u0000\u0000`\u022c\u0001\u0000\u0000\u0000b\u0230\u0001\u0000\u0000"+ - "\u0000d\u0234\u0001\u0000\u0000\u0000f\u0237\u0001\u0000\u0000\u0000h"+ - "\u023c\u0001\u0000\u0000\u0000j\u0240\u0001\u0000\u0000\u0000l\u0242\u0001"+ - "\u0000\u0000\u0000n\u0244\u0001\u0000\u0000\u0000p\u0247\u0001\u0000\u0000"+ - "\u0000r\u024b\u0001\u0000\u0000\u0000t\u024e\u0001\u0000\u0000\u0000v"+ - "\u0262\u0001\u0000\u0000\u0000x\u0266\u0001\u0000\u0000\u0000z\u026b\u0001"+ - "\u0000\u0000\u0000|\u0271\u0001\u0000\u0000\u0000~\u0276\u0001\u0000\u0000"+ - "\u0000\u0080\u0278\u0001\u0000\u0000\u0000\u0082\u0281\u0001\u0000\u0000"+ - "\u0000\u0084\u0085\u0003\u0002\u0001\u0000\u0085\u0086\u0005\u0000\u0000"+ - "\u0001\u0086\u0001\u0001\u0000\u0000\u0000\u0087\u0088\u0006\u0001\uffff"+ - "\uffff\u0000\u0088\u0089\u0003\u0004\u0002\u0000\u0089\u008f\u0001\u0000"+ - "\u0000\u0000\u008a\u008b\n\u0001\u0000\u0000\u008b\u008c\u0005\u001c\u0000"+ - "\u0000\u008c\u008e\u0003\u0006\u0003\u0000\u008d\u008a\u0001\u0000\u0000"+ - "\u0000\u008e\u0091\u0001\u0000\u0000\u0000\u008f\u008d\u0001\u0000\u0000"+ - "\u0000\u008f\u0090\u0001\u0000\u0000\u0000\u0090\u0003\u0001\u0000\u0000"+ - "\u0000\u0091\u008f\u0001\u0000\u0000\u0000\u0092\u0099\u0003n7\u0000\u0093"+ - "\u0099\u0003&\u0013\u0000\u0094\u0099\u0003 \u0010\u0000\u0095\u0099\u0003"+ - "r9\u0000\u0096\u0097\u0004\u0002\u0001\u0000\u0097\u0099\u00030\u0018"+ - "\u0000\u0098\u0092\u0001\u0000\u0000\u0000\u0098\u0093\u0001\u0000\u0000"+ - "\u0000\u0098\u0094\u0001\u0000\u0000\u0000\u0098\u0095\u0001\u0000\u0000"+ - "\u0000\u0098\u0096\u0001\u0000\u0000\u0000\u0099\u0005\u0001\u0000\u0000"+ - "\u0000\u009a\u00ac\u00032\u0019\u0000\u009b\u00ac\u0003\b\u0004\u0000"+ - "\u009c\u00ac\u0003P(\u0000\u009d\u00ac\u0003J%\u0000\u009e\u00ac\u0003"+ - "4\u001a\u0000\u009f\u00ac\u0003L&\u0000\u00a0\u00ac\u0003R)\u0000\u00a1"+ - "\u00ac\u0003T*\u0000\u00a2\u00ac\u0003X,\u0000\u00a3\u00ac\u0003Z-\u0000"+ - "\u00a4\u00ac\u0003t:\u0000\u00a5\u00ac\u0003\\.\u0000\u00a6\u00ac\u0003"+ - "|>\u0000\u00a7\u00a8\u0004\u0003\u0002\u0000\u00a8\u00ac\u0003z=\u0000"+ - "\u00a9\u00aa\u0004\u0003\u0003\u0000\u00aa\u00ac\u0003x<\u0000\u00ab\u009a"+ - "\u0001\u0000\u0000\u0000\u00ab\u009b\u0001\u0000\u0000\u0000\u00ab\u009c"+ - "\u0001\u0000\u0000\u0000\u00ab\u009d\u0001\u0000\u0000\u0000\u00ab\u009e"+ - "\u0001\u0000\u0000\u0000\u00ab\u009f\u0001\u0000\u0000\u0000\u00ab\u00a0"+ - "\u0001\u0000\u0000\u0000\u00ab\u00a1\u0001\u0000\u0000\u0000\u00ab\u00a2"+ - "\u0001\u0000\u0000\u0000\u00ab\u00a3\u0001\u0000\u0000\u0000\u00ab\u00a4"+ - "\u0001\u0000\u0000\u0000\u00ab\u00a5\u0001\u0000\u0000\u0000\u00ab\u00a6"+ - "\u0001\u0000\u0000\u0000\u00ab\u00a7\u0001\u0000\u0000\u0000\u00ab\u00a9"+ - "\u0001\u0000\u0000\u0000\u00ac\u0007\u0001\u0000\u0000\u0000\u00ad\u00ae"+ - "\u0005\u0010\u0000\u0000\u00ae\u00af\u0003\n\u0005\u0000\u00af\t\u0001"+ - "\u0000\u0000\u0000\u00b0\u00b1\u0006\u0005\uffff\uffff\u0000\u00b1\u00b2"+ - "\u00050\u0000\u0000\u00b2\u00ce\u0003\n\u0005\b\u00b3\u00ce\u0003\u0010"+ - "\b\u0000\u00b4\u00ce\u0003\f\u0006\u0000\u00b5\u00b7\u0003\u0010\b\u0000"+ - "\u00b6\u00b8\u00050\u0000\u0000\u00b7\u00b6\u0001\u0000\u0000\u0000\u00b7"+ - "\u00b8\u0001\u0000\u0000\u0000\u00b8\u00b9\u0001\u0000\u0000\u0000\u00b9"+ - "\u00ba\u0005+\u0000\u0000\u00ba\u00bb\u0005/\u0000\u0000\u00bb\u00c0\u0003"+ - "\u0010\b\u0000\u00bc\u00bd\u0005&\u0000\u0000\u00bd\u00bf\u0003\u0010"+ - "\b\u0000\u00be\u00bc\u0001\u0000\u0000\u0000\u00bf\u00c2\u0001\u0000\u0000"+ - "\u0000\u00c0\u00be\u0001\u0000\u0000\u0000\u00c0\u00c1\u0001\u0000\u0000"+ - "\u0000\u00c1\u00c3\u0001\u0000\u0000\u0000\u00c2\u00c0\u0001\u0000\u0000"+ - "\u0000\u00c3\u00c4\u00056\u0000\u0000\u00c4\u00ce\u0001\u0000\u0000\u0000"+ - "\u00c5\u00c6\u0003\u0010\b\u0000\u00c6\u00c8\u0005,\u0000\u0000\u00c7"+ - "\u00c9\u00050\u0000\u0000\u00c8\u00c7\u0001\u0000\u0000\u0000\u00c8\u00c9"+ - "\u0001\u0000\u0000\u0000\u00c9\u00ca\u0001\u0000\u0000\u0000\u00ca\u00cb"+ - "\u00051\u0000\u0000\u00cb\u00ce\u0001\u0000\u0000\u0000\u00cc\u00ce\u0003"+ - "\u000e\u0007\u0000\u00cd\u00b0\u0001\u0000\u0000\u0000\u00cd\u00b3\u0001"+ - "\u0000\u0000\u0000\u00cd\u00b4\u0001\u0000\u0000\u0000\u00cd\u00b5\u0001"+ - "\u0000\u0000\u0000\u00cd\u00c5\u0001\u0000\u0000\u0000\u00cd\u00cc\u0001"+ - "\u0000\u0000\u0000\u00ce\u00d7\u0001\u0000\u0000\u0000\u00cf\u00d0\n\u0005"+ - "\u0000\u0000\u00d0\u00d1\u0005!\u0000\u0000\u00d1\u00d6\u0003\n\u0005"+ - "\u0006\u00d2\u00d3\n\u0004\u0000\u0000\u00d3\u00d4\u00053\u0000\u0000"+ - "\u00d4\u00d6\u0003\n\u0005\u0005\u00d5\u00cf\u0001\u0000\u0000\u0000\u00d5"+ - "\u00d2\u0001\u0000\u0000\u0000\u00d6\u00d9\u0001\u0000\u0000\u0000\u00d7"+ - "\u00d5\u0001\u0000\u0000\u0000\u00d7\u00d8\u0001\u0000\u0000\u0000\u00d8"+ - "\u000b\u0001\u0000\u0000\u0000\u00d9\u00d7\u0001\u0000\u0000\u0000\u00da"+ - "\u00dc\u0003\u0010\b\u0000\u00db\u00dd\u00050\u0000\u0000\u00dc\u00db"+ - "\u0001\u0000\u0000\u0000\u00dc\u00dd\u0001\u0000\u0000\u0000\u00dd\u00de"+ - "\u0001\u0000\u0000\u0000\u00de\u00df\u0005.\u0000\u0000\u00df\u00e0\u0003"+ - "j5\u0000\u00e0\u00e9\u0001\u0000\u0000\u0000\u00e1\u00e3\u0003\u0010\b"+ - "\u0000\u00e2\u00e4\u00050\u0000\u0000\u00e3\u00e2\u0001\u0000\u0000\u0000"+ - "\u00e3\u00e4\u0001\u0000\u0000\u0000\u00e4\u00e5\u0001\u0000\u0000\u0000"+ - "\u00e5\u00e6\u00055\u0000\u0000\u00e6\u00e7\u0003j5\u0000\u00e7\u00e9"+ - "\u0001\u0000\u0000\u0000\u00e8\u00da\u0001\u0000\u0000\u0000\u00e8\u00e1"+ - "\u0001\u0000\u0000\u0000\u00e9\r\u0001\u0000\u0000\u0000\u00ea\u00ed\u0003"+ - ":\u001d\u0000\u00eb\u00ec\u0005$\u0000\u0000\u00ec\u00ee\u0003\u001e\u000f"+ - "\u0000\u00ed\u00eb\u0001\u0000\u0000\u0000\u00ed\u00ee\u0001\u0000\u0000"+ - "\u0000\u00ee\u00ef\u0001\u0000\u0000\u0000\u00ef\u00f0\u0005%\u0000\u0000"+ - "\u00f0\u00f1\u0003D\"\u0000\u00f1\u000f\u0001\u0000\u0000\u0000\u00f2"+ - "\u00f8\u0003\u0012\t\u0000\u00f3\u00f4\u0003\u0012\t\u0000\u00f4\u00f5"+ - "\u0003l6\u0000\u00f5\u00f6\u0003\u0012\t\u0000\u00f6\u00f8\u0001\u0000"+ - "\u0000\u0000\u00f7\u00f2\u0001\u0000\u0000\u0000\u00f7\u00f3\u0001\u0000"+ - "\u0000\u0000\u00f8\u0011\u0001\u0000\u0000\u0000\u00f9\u00fa\u0006\t\uffff"+ - "\uffff\u0000\u00fa\u00fe\u0003\u0014\n\u0000\u00fb\u00fc\u0007\u0000\u0000"+ - "\u0000\u00fc\u00fe\u0003\u0012\t\u0003\u00fd\u00f9\u0001\u0000\u0000\u0000"+ - "\u00fd\u00fb\u0001\u0000\u0000\u0000\u00fe\u0107\u0001\u0000\u0000\u0000"+ - "\u00ff\u0100\n\u0002\u0000\u0000\u0100\u0101\u0007\u0001\u0000\u0000\u0101"+ - "\u0106\u0003\u0012\t\u0003\u0102\u0103\n\u0001\u0000\u0000\u0103\u0104"+ - "\u0007\u0000\u0000\u0000\u0104\u0106\u0003\u0012\t\u0002\u0105\u00ff\u0001"+ - "\u0000\u0000\u0000\u0105\u0102\u0001\u0000\u0000\u0000\u0106\u0109\u0001"+ - "\u0000\u0000\u0000\u0107\u0105\u0001\u0000\u0000\u0000\u0107\u0108\u0001"+ - "\u0000\u0000\u0000\u0108\u0013\u0001\u0000\u0000\u0000\u0109\u0107\u0001"+ - "\u0000\u0000\u0000\u010a\u010b\u0006\n\uffff\uffff\u0000\u010b\u0113\u0003"+ - "D\"\u0000\u010c\u0113\u0003:\u001d\u0000\u010d\u0113\u0003\u0016\u000b"+ - "\u0000\u010e\u010f\u0005/\u0000\u0000\u010f\u0110\u0003\n\u0005\u0000"+ - "\u0110\u0111\u00056\u0000\u0000\u0111\u0113\u0001\u0000\u0000\u0000\u0112"+ - "\u010a\u0001\u0000\u0000\u0000\u0112\u010c\u0001\u0000\u0000\u0000\u0112"+ - "\u010d\u0001\u0000\u0000\u0000\u0112\u010e\u0001\u0000\u0000\u0000\u0113"+ - "\u0119\u0001\u0000\u0000\u0000\u0114\u0115\n\u0001\u0000\u0000\u0115\u0116"+ - "\u0005$\u0000\u0000\u0116\u0118\u0003\u001e\u000f\u0000\u0117\u0114\u0001"+ - "\u0000\u0000\u0000\u0118\u011b\u0001\u0000\u0000\u0000\u0119\u0117\u0001"+ - "\u0000\u0000\u0000\u0119\u011a\u0001\u0000\u0000\u0000\u011a\u0015\u0001"+ - "\u0000\u0000\u0000\u011b\u0119\u0001\u0000\u0000\u0000\u011c\u011d\u0003"+ - "\u0018\f\u0000\u011d\u012b\u0005/\u0000\u0000\u011e\u012c\u0005A\u0000"+ - "\u0000\u011f\u0124\u0003\n\u0005\u0000\u0120\u0121\u0005&\u0000\u0000"+ - "\u0121\u0123\u0003\n\u0005\u0000\u0122\u0120\u0001\u0000\u0000\u0000\u0123"+ - "\u0126\u0001\u0000\u0000\u0000\u0124\u0122\u0001\u0000\u0000\u0000\u0124"+ - "\u0125\u0001\u0000\u0000\u0000\u0125\u0129\u0001\u0000\u0000\u0000\u0126"+ - "\u0124\u0001\u0000\u0000\u0000\u0127\u0128\u0005&\u0000\u0000\u0128\u012a"+ - "\u0003\u001a\r\u0000\u0129\u0127\u0001\u0000\u0000\u0000\u0129\u012a\u0001"+ - "\u0000\u0000\u0000\u012a\u012c\u0001\u0000\u0000\u0000\u012b\u011e\u0001"+ - "\u0000\u0000\u0000\u012b\u011f\u0001\u0000\u0000\u0000\u012b\u012c\u0001"+ - "\u0000\u0000\u0000\u012c\u012d\u0001\u0000\u0000\u0000\u012d\u012e\u0005"+ - "6\u0000\u0000\u012e\u0017\u0001\u0000\u0000\u0000\u012f\u0130\u0003H$"+ - "\u0000\u0130\u0019\u0001\u0000\u0000\u0000\u0131\u0132\u0005D\u0000\u0000"+ - "\u0132\u0137\u0003\u001c\u000e\u0000\u0133\u0134\u0005&\u0000\u0000\u0134"+ - "\u0136\u0003\u001c\u000e\u0000\u0135\u0133\u0001\u0000\u0000\u0000\u0136"+ - "\u0139\u0001\u0000\u0000\u0000\u0137\u0135\u0001\u0000\u0000\u0000\u0137"+ - "\u0138\u0001\u0000\u0000\u0000\u0138\u013a\u0001\u0000\u0000\u0000\u0139"+ - "\u0137\u0001\u0000\u0000\u0000\u013a\u013b\u0005E\u0000\u0000\u013b\u001b"+ - "\u0001\u0000\u0000\u0000\u013c\u013d\u0003j5\u0000\u013d\u013e\u0005%"+ - "\u0000\u0000\u013e\u013f\u0003D\"\u0000\u013f\u001d\u0001\u0000\u0000"+ - "\u0000\u0140\u0141\u0003@ \u0000\u0141\u001f\u0001\u0000\u0000\u0000\u0142"+ - "\u0143\u0005\f\u0000\u0000\u0143\u0144\u0003\"\u0011\u0000\u0144!\u0001"+ - "\u0000\u0000\u0000\u0145\u014a\u0003$\u0012\u0000\u0146\u0147\u0005&\u0000"+ - "\u0000\u0147\u0149\u0003$\u0012\u0000\u0148\u0146\u0001\u0000\u0000\u0000"+ - "\u0149\u014c\u0001\u0000\u0000\u0000\u014a\u0148\u0001\u0000\u0000\u0000"+ - "\u014a\u014b\u0001\u0000\u0000\u0000\u014b#\u0001\u0000\u0000\u0000\u014c"+ - "\u014a\u0001\u0000\u0000\u0000\u014d\u014e\u0003:\u001d\u0000\u014e\u014f"+ - "\u0005#\u0000\u0000\u014f\u0151\u0001\u0000\u0000\u0000\u0150\u014d\u0001"+ - "\u0000\u0000\u0000\u0150\u0151\u0001\u0000\u0000\u0000\u0151\u0152\u0001"+ - "\u0000\u0000\u0000\u0152\u0153\u0003\n\u0005\u0000\u0153%\u0001\u0000"+ - "\u0000\u0000\u0154\u0155\u0005\u0006\u0000\u0000\u0155\u015a\u0003(\u0014"+ - "\u0000\u0156\u0157\u0005&\u0000\u0000\u0157\u0159\u0003(\u0014\u0000\u0158"+ - "\u0156\u0001\u0000\u0000\u0000\u0159\u015c\u0001\u0000\u0000\u0000\u015a"+ - "\u0158\u0001\u0000\u0000\u0000\u015a\u015b\u0001\u0000\u0000\u0000\u015b"+ - "\u015e\u0001\u0000\u0000\u0000\u015c\u015a\u0001\u0000\u0000\u0000\u015d"+ - "\u015f\u0003.\u0017\u0000\u015e\u015d\u0001\u0000\u0000\u0000\u015e\u015f"+ - "\u0001\u0000\u0000\u0000\u015f\'\u0001\u0000\u0000\u0000\u0160\u0161\u0003"+ - "*\u0015\u0000\u0161\u0162\u0005%\u0000\u0000\u0162\u0164\u0001\u0000\u0000"+ - "\u0000\u0163\u0160\u0001\u0000\u0000\u0000\u0163\u0164\u0001\u0000\u0000"+ - "\u0000\u0164\u0165\u0001\u0000\u0000\u0000\u0165\u0166\u0003,\u0016\u0000"+ - "\u0166)\u0001\u0000\u0000\u0000\u0167\u0168\u0005R\u0000\u0000\u0168+"+ - "\u0001\u0000\u0000\u0000\u0169\u016a\u0007\u0002\u0000\u0000\u016a-\u0001"+ - "\u0000\u0000\u0000\u016b\u016c\u0005Q\u0000\u0000\u016c\u0171\u0005R\u0000"+ - "\u0000\u016d\u016e\u0005&\u0000\u0000\u016e\u0170\u0005R\u0000\u0000\u016f"+ - "\u016d\u0001\u0000\u0000\u0000\u0170\u0173\u0001\u0000\u0000\u0000\u0171"+ - "\u016f\u0001\u0000\u0000\u0000\u0171\u0172\u0001\u0000\u0000\u0000\u0172"+ - "/\u0001\u0000\u0000\u0000\u0173\u0171\u0001\u0000\u0000\u0000\u0174\u0175"+ - "\u0005\u0014\u0000\u0000\u0175\u017a\u0003(\u0014\u0000\u0176\u0177\u0005"+ - "&\u0000\u0000\u0177\u0179\u0003(\u0014\u0000\u0178\u0176\u0001\u0000\u0000"+ - "\u0000\u0179\u017c\u0001\u0000\u0000\u0000\u017a\u0178\u0001\u0000\u0000"+ - "\u0000\u017a\u017b\u0001\u0000\u0000\u0000\u017b\u017e\u0001\u0000\u0000"+ - "\u0000\u017c\u017a\u0001\u0000\u0000\u0000\u017d\u017f\u00036\u001b\u0000"+ - "\u017e\u017d\u0001\u0000\u0000\u0000\u017e\u017f\u0001\u0000\u0000\u0000"+ - "\u017f\u0182\u0001\u0000\u0000\u0000\u0180\u0181\u0005 \u0000\u0000\u0181"+ - "\u0183\u0003\"\u0011\u0000\u0182\u0180\u0001\u0000\u0000\u0000\u0182\u0183"+ - "\u0001\u0000\u0000\u0000\u01831\u0001\u0000\u0000\u0000\u0184\u0185\u0005"+ - "\u0004\u0000\u0000\u0185\u0186\u0003\"\u0011\u0000\u01863\u0001\u0000"+ - "\u0000\u0000\u0187\u0189\u0005\u000f\u0000\u0000\u0188\u018a\u00036\u001b"+ - "\u0000\u0189\u0188\u0001\u0000\u0000\u0000\u0189\u018a\u0001\u0000\u0000"+ - "\u0000\u018a\u018d\u0001\u0000\u0000\u0000\u018b\u018c\u0005 \u0000\u0000"+ - "\u018c\u018e\u0003\"\u0011\u0000\u018d\u018b\u0001\u0000\u0000\u0000\u018d"+ - "\u018e\u0001\u0000\u0000\u0000\u018e5\u0001\u0000\u0000\u0000\u018f\u0194"+ - "\u00038\u001c\u0000\u0190\u0191\u0005&\u0000\u0000\u0191\u0193\u00038"+ - "\u001c\u0000\u0192\u0190\u0001\u0000\u0000\u0000\u0193\u0196\u0001\u0000"+ - "\u0000\u0000\u0194\u0192\u0001\u0000\u0000\u0000\u0194\u0195\u0001\u0000"+ - "\u0000\u0000\u01957\u0001\u0000\u0000\u0000\u0196\u0194\u0001\u0000\u0000"+ - "\u0000\u0197\u019a\u0003$\u0012\u0000\u0198\u0199\u0005\u0010\u0000\u0000"+ - "\u0199\u019b\u0003\n\u0005\u0000\u019a\u0198\u0001\u0000\u0000\u0000\u019a"+ - "\u019b\u0001\u0000\u0000\u0000\u019b9\u0001\u0000\u0000\u0000\u019c\u01a1"+ - "\u0003H$\u0000\u019d\u019e\u0005(\u0000\u0000\u019e\u01a0\u0003H$\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"+ - "\u01a9\u0003B!\u0000\u01a5\u01a6\u0005(\u0000\u0000\u01a6\u01a8\u0003"+ - "B!\u0000\u01a7\u01a5\u0001\u0000\u0000\u0000\u01a8\u01ab\u0001\u0000\u0000"+ - "\u0000\u01a9\u01a7\u0001\u0000\u0000\u0000\u01a9\u01aa\u0001\u0000\u0000"+ - "\u0000\u01aa=\u0001\u0000\u0000\u0000\u01ab\u01a9\u0001\u0000\u0000\u0000"+ - "\u01ac\u01b1\u0003<\u001e\u0000\u01ad\u01ae\u0005&\u0000\u0000\u01ae\u01b0"+ - "\u0003<\u001e\u0000\u01af\u01ad\u0001\u0000\u0000\u0000\u01b0\u01b3\u0001"+ - "\u0000\u0000\u0000\u01b1\u01af\u0001\u0000\u0000\u0000\u01b1\u01b2\u0001"+ - "\u0000\u0000\u0000\u01b2?\u0001\u0000\u0000\u0000\u01b3\u01b1\u0001\u0000"+ - "\u0000\u0000\u01b4\u01b5\u0007\u0003\u0000\u0000\u01b5A\u0001\u0000\u0000"+ - "\u0000\u01b6\u01ba\u0005V\u0000\u0000\u01b7\u01b8\u0004!\t\u0000\u01b8"+ - "\u01ba\u0003F#\u0000\u01b9\u01b6\u0001\u0000\u0000\u0000\u01b9\u01b7\u0001"+ - "\u0000\u0000\u0000\u01baC\u0001\u0000\u0000\u0000\u01bb\u01e6\u00051\u0000"+ - "\u0000\u01bc\u01bd\u0003h4\u0000\u01bd\u01be\u0005I\u0000\u0000\u01be"+ - "\u01e6\u0001\u0000\u0000\u0000\u01bf\u01e6\u0003f3\u0000\u01c0\u01e6\u0003"+ - "h4\u0000\u01c1\u01e6\u0003b1\u0000\u01c2\u01e6\u0003F#\u0000\u01c3\u01e6"+ - "\u0003j5\u0000\u01c4\u01c5\u0005G\u0000\u0000\u01c5\u01ca\u0003d2\u0000"+ - "\u01c6\u01c7\u0005&\u0000\u0000\u01c7\u01c9\u0003d2\u0000\u01c8\u01c6"+ - "\u0001\u0000\u0000\u0000\u01c9\u01cc\u0001\u0000\u0000\u0000\u01ca\u01c8"+ - "\u0001\u0000\u0000\u0000\u01ca\u01cb\u0001\u0000\u0000\u0000\u01cb\u01cd"+ - "\u0001\u0000\u0000\u0000\u01cc\u01ca\u0001\u0000\u0000\u0000\u01cd\u01ce"+ - "\u0005H\u0000\u0000\u01ce\u01e6\u0001\u0000\u0000\u0000\u01cf\u01d0\u0005"+ - "G\u0000\u0000\u01d0\u01d5\u0003b1\u0000\u01d1\u01d2\u0005&\u0000\u0000"+ - "\u01d2\u01d4\u0003b1\u0000\u01d3\u01d1\u0001\u0000\u0000\u0000\u01d4\u01d7"+ - "\u0001\u0000\u0000\u0000\u01d5\u01d3\u0001\u0000\u0000\u0000\u01d5\u01d6"+ - "\u0001\u0000\u0000\u0000\u01d6\u01d8\u0001\u0000\u0000\u0000\u01d7\u01d5"+ - "\u0001\u0000\u0000\u0000\u01d8\u01d9\u0005H\u0000\u0000\u01d9\u01e6\u0001"+ - "\u0000\u0000\u0000\u01da\u01db\u0005G\u0000\u0000\u01db\u01e0\u0003j5"+ - "\u0000\u01dc\u01dd\u0005&\u0000\u0000\u01dd\u01df\u0003j5\u0000\u01de"+ - "\u01dc\u0001\u0000\u0000\u0000\u01df\u01e2\u0001\u0000\u0000\u0000\u01e0"+ - "\u01de\u0001\u0000\u0000\u0000\u01e0\u01e1\u0001\u0000\u0000\u0000\u01e1"+ - "\u01e3\u0001\u0000\u0000\u0000\u01e2\u01e0\u0001\u0000\u0000\u0000\u01e3"+ - "\u01e4\u0005H\u0000\u0000\u01e4\u01e6\u0001\u0000\u0000\u0000\u01e5\u01bb"+ - "\u0001\u0000\u0000\u0000\u01e5\u01bc\u0001\u0000\u0000\u0000\u01e5\u01bf"+ - "\u0001\u0000\u0000\u0000\u01e5\u01c0\u0001\u0000\u0000\u0000\u01e5\u01c1"+ - "\u0001\u0000\u0000\u0000\u01e5\u01c2\u0001\u0000\u0000\u0000\u01e5\u01c3"+ - "\u0001\u0000\u0000\u0000\u01e5\u01c4\u0001\u0000\u0000\u0000\u01e5\u01cf"+ - "\u0001\u0000\u0000\u0000\u01e5\u01da\u0001\u0000\u0000\u0000\u01e6E\u0001"+ - "\u0000\u0000\u0000\u01e7\u01ea\u00054\u0000\u0000\u01e8\u01ea\u0005F\u0000"+ - "\u0000\u01e9\u01e7\u0001\u0000\u0000\u0000\u01e9\u01e8\u0001\u0000\u0000"+ - "\u0000\u01eaG\u0001\u0000\u0000\u0000\u01eb\u01ef\u0003@ \u0000\u01ec"+ - "\u01ed\u0004$\n\u0000\u01ed\u01ef\u0003F#\u0000\u01ee\u01eb\u0001\u0000"+ - "\u0000\u0000\u01ee\u01ec\u0001\u0000\u0000\u0000\u01efI\u0001\u0000\u0000"+ - "\u0000\u01f0\u01f1\u0005\t\u0000\u0000\u01f1\u01f2\u0005\u001e\u0000\u0000"+ - "\u01f2K\u0001\u0000\u0000\u0000\u01f3\u01f4\u0005\u000e\u0000\u0000\u01f4"+ - "\u01f9\u0003N\'\u0000\u01f5\u01f6\u0005&\u0000\u0000\u01f6\u01f8\u0003"+ - "N\'\u0000\u01f7\u01f5\u0001\u0000\u0000\u0000\u01f8\u01fb\u0001\u0000"+ - "\u0000\u0000\u01f9\u01f7\u0001\u0000\u0000\u0000\u01f9\u01fa\u0001\u0000"+ - "\u0000\u0000\u01faM\u0001\u0000\u0000\u0000\u01fb\u01f9\u0001\u0000\u0000"+ - "\u0000\u01fc\u01fe\u0003\n\u0005\u0000\u01fd\u01ff\u0007\u0004\u0000\u0000"+ - "\u01fe\u01fd\u0001\u0000\u0000\u0000\u01fe\u01ff\u0001\u0000\u0000\u0000"+ - "\u01ff\u0202\u0001\u0000\u0000\u0000\u0200\u0201\u00052\u0000\u0000\u0201"+ - "\u0203\u0007\u0005\u0000\u0000\u0202\u0200\u0001\u0000\u0000\u0000\u0202"+ - "\u0203\u0001\u0000\u0000\u0000\u0203O\u0001\u0000\u0000\u0000\u0204\u0205"+ - "\u0005\b\u0000\u0000\u0205\u0206\u0003>\u001f\u0000\u0206Q\u0001\u0000"+ - "\u0000\u0000\u0207\u0208\u0005\u0002\u0000\u0000\u0208\u0209\u0003>\u001f"+ - "\u0000\u0209S\u0001\u0000\u0000\u0000\u020a\u020b\u0005\u000b\u0000\u0000"+ - "\u020b\u0210\u0003V+\u0000\u020c\u020d\u0005&\u0000\u0000\u020d\u020f"+ - "\u0003V+\u0000\u020e\u020c\u0001\u0000\u0000\u0000\u020f\u0212\u0001\u0000"+ - "\u0000\u0000\u0210\u020e\u0001\u0000\u0000\u0000\u0210\u0211\u0001\u0000"+ - "\u0000\u0000\u0211U\u0001\u0000\u0000\u0000\u0212\u0210\u0001\u0000\u0000"+ - "\u0000\u0213\u0214\u0003<\u001e\u0000\u0214\u0215\u0005Z\u0000\u0000\u0215"+ - "\u0216\u0003<\u001e\u0000\u0216W\u0001\u0000\u0000\u0000\u0217\u0218\u0005"+ - "\u0001\u0000\u0000\u0218\u0219\u0003\u0014\n\u0000\u0219\u021b\u0003j"+ - "5\u0000\u021a\u021c\u0003^/\u0000\u021b\u021a\u0001\u0000\u0000\u0000"+ - "\u021b\u021c\u0001\u0000\u0000\u0000\u021cY\u0001\u0000\u0000\u0000\u021d"+ - "\u021e\u0005\u0007\u0000\u0000\u021e\u021f\u0003\u0014\n\u0000\u021f\u0220"+ - "\u0003j5\u0000\u0220[\u0001\u0000\u0000\u0000\u0221\u0222\u0005\n\u0000"+ - "\u0000\u0222\u0223\u0003:\u001d\u0000\u0223]\u0001\u0000\u0000\u0000\u0224"+ - "\u0229\u0003`0\u0000\u0225\u0226\u0005&\u0000\u0000\u0226\u0228\u0003"+ - "`0\u0000\u0227\u0225\u0001\u0000\u0000\u0000\u0228\u022b\u0001\u0000\u0000"+ - "\u0000\u0229\u0227\u0001\u0000\u0000\u0000\u0229\u022a\u0001\u0000\u0000"+ - "\u0000\u022a_\u0001\u0000\u0000\u0000\u022b\u0229\u0001\u0000\u0000\u0000"+ - "\u022c\u022d\u0003@ \u0000\u022d\u022e\u0005#\u0000\u0000\u022e\u022f"+ - "\u0003D\"\u0000\u022fa\u0001\u0000\u0000\u0000\u0230\u0231\u0007\u0006"+ - "\u0000\u0000\u0231c\u0001\u0000\u0000\u0000\u0232\u0235\u0003f3\u0000"+ - "\u0233\u0235\u0003h4\u0000\u0234\u0232\u0001\u0000\u0000\u0000\u0234\u0233"+ - "\u0001\u0000\u0000\u0000\u0235e\u0001\u0000\u0000\u0000\u0236\u0238\u0007"+ - "\u0000\u0000\u0000\u0237\u0236\u0001\u0000\u0000\u0000\u0237\u0238\u0001"+ - "\u0000\u0000\u0000\u0238\u0239\u0001\u0000\u0000\u0000\u0239\u023a\u0005"+ - "\u001f\u0000\u0000\u023ag\u0001\u0000\u0000\u0000\u023b\u023d\u0007\u0000"+ - "\u0000\u0000\u023c\u023b\u0001\u0000\u0000\u0000\u023c\u023d\u0001\u0000"+ - "\u0000\u0000\u023d\u023e\u0001\u0000\u0000\u0000\u023e\u023f\u0005\u001e"+ - "\u0000\u0000\u023fi\u0001\u0000\u0000\u0000\u0240\u0241\u0005\u001d\u0000"+ - "\u0000\u0241k\u0001\u0000\u0000\u0000\u0242\u0243\u0007\u0007\u0000\u0000"+ - "\u0243m\u0001\u0000\u0000\u0000\u0244\u0245\u0005\u0005\u0000\u0000\u0245"+ - "\u0246\u0003p8\u0000\u0246o\u0001\u0000\u0000\u0000\u0247\u0248\u0005"+ - "G\u0000\u0000\u0248\u0249\u0003\u0002\u0001\u0000\u0249\u024a\u0005H\u0000"+ - "\u0000\u024aq\u0001\u0000\u0000\u0000\u024b\u024c\u0005\r\u0000\u0000"+ - "\u024c\u024d\u0005j\u0000\u0000\u024ds\u0001\u0000\u0000\u0000\u024e\u024f"+ - "\u0005\u0003\u0000\u0000\u024f\u0252\u0005`\u0000\u0000\u0250\u0251\u0005"+ - "^\u0000\u0000\u0251\u0253\u0003<\u001e\u0000\u0252\u0250\u0001\u0000\u0000"+ - "\u0000\u0252\u0253\u0001\u0000\u0000\u0000\u0253\u025d\u0001\u0000\u0000"+ - "\u0000\u0254\u0255\u0005_\u0000\u0000\u0255\u025a\u0003v;\u0000\u0256"+ - "\u0257\u0005&\u0000\u0000\u0257\u0259\u0003v;\u0000\u0258\u0256\u0001"+ - "\u0000\u0000\u0000\u0259\u025c\u0001\u0000\u0000\u0000\u025a\u0258\u0001"+ - "\u0000\u0000\u0000\u025a\u025b\u0001\u0000\u0000\u0000\u025b\u025e\u0001"+ - "\u0000\u0000\u0000\u025c\u025a\u0001\u0000\u0000\u0000\u025d\u0254\u0001"+ - "\u0000\u0000\u0000\u025d\u025e\u0001\u0000\u0000\u0000\u025eu\u0001\u0000"+ - "\u0000\u0000\u025f\u0260\u0003<\u001e\u0000\u0260\u0261\u0005#\u0000\u0000"+ - "\u0261\u0263\u0001\u0000\u0000\u0000\u0262\u025f\u0001\u0000\u0000\u0000"+ - "\u0262\u0263\u0001\u0000\u0000\u0000\u0263\u0264\u0001\u0000\u0000\u0000"+ - "\u0264\u0265\u0003<\u001e\u0000\u0265w\u0001\u0000\u0000\u0000\u0266\u0267"+ - "\u0005\u0013\u0000\u0000\u0267\u0268\u0003(\u0014\u0000\u0268\u0269\u0005"+ - "^\u0000\u0000\u0269\u026a\u0003>\u001f\u0000\u026ay\u0001\u0000\u0000"+ - "\u0000\u026b\u026c\u0005\u0012\u0000\u0000\u026c\u026f\u00036\u001b\u0000"+ - "\u026d\u026e\u0005 \u0000\u0000\u026e\u0270\u0003\"\u0011\u0000\u026f"+ - "\u026d\u0001\u0000\u0000\u0000\u026f\u0270\u0001\u0000\u0000\u0000\u0270"+ - "{\u0001\u0000\u0000\u0000\u0271\u0272\u0007\b\u0000\u0000\u0272\u0273"+ - "\u0005x\u0000\u0000\u0273\u0274\u0003~?\u0000\u0274\u0275\u0003\u0080"+ - "@\u0000\u0275}\u0001\u0000\u0000\u0000\u0276\u0277\u0003(\u0014\u0000"+ - "\u0277\u007f\u0001\u0000\u0000\u0000\u0278\u0279\u0005^\u0000\u0000\u0279"+ - "\u027e\u0003\u0082A\u0000\u027a\u027b\u0005&\u0000\u0000\u027b\u027d\u0003"+ - "\u0082A\u0000\u027c\u027a\u0001\u0000\u0000\u0000\u027d\u0280\u0001\u0000"+ - "\u0000\u0000\u027e\u027c\u0001\u0000\u0000\u0000\u027e\u027f\u0001\u0000"+ - "\u0000\u0000\u027f\u0081\u0001\u0000\u0000\u0000\u0280\u027e\u0001\u0000"+ - "\u0000\u0000\u0281\u0282\u0003\u0010\b\u0000\u0282\u0083\u0001\u0000\u0000"+ - "\u0000=\u008f\u0098\u00ab\u00b7\u00c0\u00c8\u00cd\u00d5\u00d7\u00dc\u00e3"+ - "\u00e8\u00ed\u00f7\u00fd\u0105\u0107\u0112\u0119\u0124\u0129\u012b\u0137"+ - "\u014a\u0150\u015a\u015e\u0163\u0171\u017a\u017e\u0182\u0189\u018d\u0194"+ - "\u019a\u01a1\u01a9\u01b1\u01b9\u01ca\u01d5\u01e0\u01e5\u01e9\u01ee\u01f9"+ - "\u01fe\u0202\u0210\u021b\u0229\u0234\u0237\u023c\u0252\u025a\u025d\u0262"+ - "\u026f\u027e"; + "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+ + "\u0001\u0003\u0003\u0003\u00b0\b\u0003\u0001\u0004\u0001\u0004\u0001\u0004"+ + "\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+ + "\u0001\u0005\u0003\u0005\u00bc\b\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+ + "\u0001\u0005\u0001\u0005\u0005\u0005\u00c3\b\u0005\n\u0005\f\u0005\u00c6"+ + "\t\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0003"+ + "\u0005\u00cd\b\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0003\u0005\u00d2"+ + "\b\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001"+ + "\u0005\u0005\u0005\u00da\b\u0005\n\u0005\f\u0005\u00dd\t\u0005\u0001\u0006"+ + "\u0001\u0006\u0003\u0006\u00e1\b\u0006\u0001\u0006\u0001\u0006\u0001\u0006"+ + "\u0001\u0006\u0001\u0006\u0003\u0006\u00e8\b\u0006\u0001\u0006\u0001\u0006"+ + "\u0001\u0006\u0003\u0006\u00ed\b\u0006\u0001\u0007\u0001\u0007\u0001\u0007"+ + "\u0003\u0007\u00f2\b\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\b"+ + "\u0001\b\u0001\b\u0001\b\u0001\b\u0003\b\u00fc\b\b\u0001\t\u0001\t\u0001"+ + "\t\u0001\t\u0003\t\u0102\b\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001"+ + "\t\u0005\t\u010a\b\t\n\t\f\t\u010d\t\t\u0001\n\u0001\n\u0001\n\u0001\n"+ + "\u0001\n\u0001\n\u0001\n\u0001\n\u0003\n\u0117\b\n\u0001\n\u0001\n\u0001"+ + "\n\u0005\n\u011c\b\n\n\n\f\n\u011f\t\n\u0001\u000b\u0001\u000b\u0001\u000b"+ + "\u0001\u000b\u0001\u000b\u0001\u000b\u0005\u000b\u0127\b\u000b\n\u000b"+ + "\f\u000b\u012a\t\u000b\u0001\u000b\u0001\u000b\u0003\u000b\u012e\b\u000b"+ + "\u0003\u000b\u0130\b\u000b\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001"+ + "\r\u0001\r\u0001\r\u0001\r\u0005\r\u013a\b\r\n\r\f\r\u013d\t\r\u0001\r"+ + "\u0001\r\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001"+ + "\u000f\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001"+ + "\u0011\u0005\u0011\u014d\b\u0011\n\u0011\f\u0011\u0150\t\u0011\u0001\u0012"+ + "\u0001\u0012\u0001\u0012\u0003\u0012\u0155\b\u0012\u0001\u0012\u0001\u0012"+ + "\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0005\u0013\u015d\b\u0013"+ + "\n\u0013\f\u0013\u0160\t\u0013\u0001\u0013\u0003\u0013\u0163\b\u0013\u0001"+ + "\u0014\u0001\u0014\u0001\u0014\u0003\u0014\u0168\b\u0014\u0001\u0014\u0001"+ + "\u0014\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001\u0017\u0001"+ + "\u0017\u0001\u0017\u0001\u0017\u0005\u0017\u0174\b\u0017\n\u0017\f\u0017"+ + "\u0177\t\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0005\u0018"+ + "\u017d\b\u0018\n\u0018\f\u0018\u0180\t\u0018\u0001\u0018\u0003\u0018\u0183"+ + "\b\u0018\u0001\u0018\u0001\u0018\u0003\u0018\u0187\b\u0018\u0001\u0019"+ + "\u0001\u0019\u0001\u0019\u0001\u001a\u0001\u001a\u0003\u001a\u018e\b\u001a"+ + "\u0001\u001a\u0001\u001a\u0003\u001a\u0192\b\u001a\u0001\u001b\u0001\u001b"+ + "\u0001\u001b\u0005\u001b\u0197\b\u001b\n\u001b\f\u001b\u019a\t\u001b\u0001"+ + "\u001c\u0001\u001c\u0001\u001c\u0003\u001c\u019f\b\u001c\u0001\u001d\u0001"+ + "\u001d\u0001\u001d\u0005\u001d\u01a4\b\u001d\n\u001d\f\u001d\u01a7\t\u001d"+ + "\u0001\u001e\u0001\u001e\u0001\u001e\u0005\u001e\u01ac\b\u001e\n\u001e"+ + "\f\u001e\u01af\t\u001e\u0001\u001f\u0001\u001f\u0001\u001f\u0005\u001f"+ + "\u01b4\b\u001f\n\u001f\f\u001f\u01b7\t\u001f\u0001 \u0001 \u0001!\u0001"+ + "!\u0003!\u01bd\b!\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001"+ + "\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0005\"\u01cc\b\"\n"+ + "\"\f\"\u01cf\t\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0005"+ + "\"\u01d7\b\"\n\"\f\"\u01da\t\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\""+ + "\u0001\"\u0005\"\u01e2\b\"\n\"\f\"\u01e5\t\"\u0001\"\u0001\"\u0003\"\u01e9"+ + "\b\"\u0001#\u0001#\u0003#\u01ed\b#\u0001$\u0001$\u0003$\u01f1\b$\u0001"+ + "%\u0001%\u0001%\u0001&\u0001&\u0001&\u0001&\u0005&\u01fa\b&\n&\f&\u01fd"+ + "\t&\u0001\'\u0001\'\u0003\'\u0201\b\'\u0001\'\u0001\'\u0003\'\u0205\b"+ + "\'\u0001(\u0001(\u0001(\u0001)\u0001)\u0001)\u0001*\u0001*\u0001*\u0001"+ + "*\u0005*\u0211\b*\n*\f*\u0214\t*\u0001+\u0001+\u0001+\u0001+\u0001,\u0001"+ + ",\u0001,\u0001,\u0003,\u021e\b,\u0001-\u0001-\u0001-\u0001-\u0001.\u0001"+ + ".\u0001.\u0001/\u0001/\u0001/\u0005/\u022a\b/\n/\f/\u022d\t/\u00010\u0001"+ + "0\u00010\u00010\u00011\u00011\u00012\u00012\u00032\u0237\b2\u00013\u0003"+ + "3\u023a\b3\u00013\u00013\u00014\u00034\u023f\b4\u00014\u00014\u00015\u0001"+ + "5\u00016\u00016\u00017\u00017\u00017\u00018\u00018\u00018\u00018\u0001"+ + "9\u00019\u00019\u0001:\u0001:\u0001:\u0001:\u0003:\u0255\b:\u0001:\u0001"+ + ":\u0001:\u0001:\u0005:\u025b\b:\n:\f:\u025e\t:\u0003:\u0260\b:\u0001;"+ + "\u0001;\u0001;\u0003;\u0265\b;\u0001;\u0001;\u0001<\u0001<\u0001<\u0001"+ + "<\u0001<\u0001=\u0001=\u0001=\u0001=\u0003=\u0272\b=\u0001>\u0001>\u0001"+ + ">\u0001>\u0001>\u0001?\u0001?\u0001@\u0001@\u0001@\u0001@\u0005@\u027f"+ + "\b@\n@\f@\u0282\t@\u0001A\u0001A\u0001B\u0001B\u0001B\u0001B\u0003B\u028a"+ + "\bB\u0001B\u0001B\u0001B\u0001B\u0001B\u0003B\u0291\bB\u0001B\u0000\u0004"+ + "\u0002\n\u0012\u0014C\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010\u0012"+ + "\u0014\u0016\u0018\u001a\u001c\u001e \"$&(*,.02468:<>@BDFHJLNPRTVXZ\\"+ + "^`bdfhjlnprtvxz|~\u0080\u0082\u0084\u0000\t\u0001\u0000@A\u0001\u0000"+ + "BD\u0002\u0000\u001e\u001eSS\u0001\u0000JK\u0002\u0000##((\u0002\u0000"+ + "++..\u0002\u0000**88\u0002\u000099;?\u0002\u0000\u0011\u0011\u0017\u0018"+ + "\u02ae\u0000\u0086\u0001\u0000\u0000\u0000\u0002\u0089\u0001\u0000\u0000"+ + "\u0000\u0004\u009a\u0001\u0000\u0000\u0000\u0006\u00af\u0001\u0000\u0000"+ + "\u0000\b\u00b1\u0001\u0000\u0000\u0000\n\u00d1\u0001\u0000\u0000\u0000"+ + "\f\u00ec\u0001\u0000\u0000\u0000\u000e\u00ee\u0001\u0000\u0000\u0000\u0010"+ + "\u00fb\u0001\u0000\u0000\u0000\u0012\u0101\u0001\u0000\u0000\u0000\u0014"+ + "\u0116\u0001\u0000\u0000\u0000\u0016\u0120\u0001\u0000\u0000\u0000\u0018"+ + "\u0133\u0001\u0000\u0000\u0000\u001a\u0135\u0001\u0000\u0000\u0000\u001c"+ + "\u0140\u0001\u0000\u0000\u0000\u001e\u0144\u0001\u0000\u0000\u0000 \u0146"+ + "\u0001\u0000\u0000\u0000\"\u0149\u0001\u0000\u0000\u0000$\u0154\u0001"+ + "\u0000\u0000\u0000&\u0158\u0001\u0000\u0000\u0000(\u0167\u0001\u0000\u0000"+ + "\u0000*\u016b\u0001\u0000\u0000\u0000,\u016d\u0001\u0000\u0000\u0000."+ + "\u016f\u0001\u0000\u0000\u00000\u0178\u0001\u0000\u0000\u00002\u0188\u0001"+ + "\u0000\u0000\u00004\u018b\u0001\u0000\u0000\u00006\u0193\u0001\u0000\u0000"+ + "\u00008\u019b\u0001\u0000\u0000\u0000:\u01a0\u0001\u0000\u0000\u0000<"+ + "\u01a8\u0001\u0000\u0000\u0000>\u01b0\u0001\u0000\u0000\u0000@\u01b8\u0001"+ + "\u0000\u0000\u0000B\u01bc\u0001\u0000\u0000\u0000D\u01e8\u0001\u0000\u0000"+ + "\u0000F\u01ec\u0001\u0000\u0000\u0000H\u01f0\u0001\u0000\u0000\u0000J"+ + "\u01f2\u0001\u0000\u0000\u0000L\u01f5\u0001\u0000\u0000\u0000N\u01fe\u0001"+ + "\u0000\u0000\u0000P\u0206\u0001\u0000\u0000\u0000R\u0209\u0001\u0000\u0000"+ + "\u0000T\u020c\u0001\u0000\u0000\u0000V\u0215\u0001\u0000\u0000\u0000X"+ + "\u0219\u0001\u0000\u0000\u0000Z\u021f\u0001\u0000\u0000\u0000\\\u0223"+ + "\u0001\u0000\u0000\u0000^\u0226\u0001\u0000\u0000\u0000`\u022e\u0001\u0000"+ + "\u0000\u0000b\u0232\u0001\u0000\u0000\u0000d\u0236\u0001\u0000\u0000\u0000"+ + "f\u0239\u0001\u0000\u0000\u0000h\u023e\u0001\u0000\u0000\u0000j\u0242"+ + "\u0001\u0000\u0000\u0000l\u0244\u0001\u0000\u0000\u0000n\u0246\u0001\u0000"+ + "\u0000\u0000p\u0249\u0001\u0000\u0000\u0000r\u024d\u0001\u0000\u0000\u0000"+ + "t\u0250\u0001\u0000\u0000\u0000v\u0264\u0001\u0000\u0000\u0000x\u0268"+ + "\u0001\u0000\u0000\u0000z\u026d\u0001\u0000\u0000\u0000|\u0273\u0001\u0000"+ + "\u0000\u0000~\u0278\u0001\u0000\u0000\u0000\u0080\u027a\u0001\u0000\u0000"+ + "\u0000\u0082\u0283\u0001\u0000\u0000\u0000\u0084\u0285\u0001\u0000\u0000"+ + "\u0000\u0086\u0087\u0003\u0002\u0001\u0000\u0087\u0088\u0005\u0000\u0000"+ + "\u0001\u0088\u0001\u0001\u0000\u0000\u0000\u0089\u008a\u0006\u0001\uffff"+ + "\uffff\u0000\u008a\u008b\u0003\u0004\u0002\u0000\u008b\u0091\u0001\u0000"+ + "\u0000\u0000\u008c\u008d\n\u0001\u0000\u0000\u008d\u008e\u0005\u001d\u0000"+ + "\u0000\u008e\u0090\u0003\u0006\u0003\u0000\u008f\u008c\u0001\u0000\u0000"+ + "\u0000\u0090\u0093\u0001\u0000\u0000\u0000\u0091\u008f\u0001\u0000\u0000"+ + "\u0000\u0091\u0092\u0001\u0000\u0000\u0000\u0092\u0003\u0001\u0000\u0000"+ + "\u0000\u0093\u0091\u0001\u0000\u0000\u0000\u0094\u009b\u0003n7\u0000\u0095"+ + "\u009b\u0003&\u0013\u0000\u0096\u009b\u0003 \u0010\u0000\u0097\u009b\u0003"+ + "r9\u0000\u0098\u0099\u0004\u0002\u0001\u0000\u0099\u009b\u00030\u0018"+ + "\u0000\u009a\u0094\u0001\u0000\u0000\u0000\u009a\u0095\u0001\u0000\u0000"+ + "\u0000\u009a\u0096\u0001\u0000\u0000\u0000\u009a\u0097\u0001\u0000\u0000"+ + "\u0000\u009a\u0098\u0001\u0000\u0000\u0000\u009b\u0005\u0001\u0000\u0000"+ + "\u0000\u009c\u00b0\u00032\u0019\u0000\u009d\u00b0\u0003\b\u0004\u0000"+ + "\u009e\u00b0\u0003P(\u0000\u009f\u00b0\u0003J%\u0000\u00a0\u00b0\u0003"+ + "4\u001a\u0000\u00a1\u00b0\u0003L&\u0000\u00a2\u00b0\u0003R)\u0000\u00a3"+ + "\u00b0\u0003T*\u0000\u00a4\u00b0\u0003X,\u0000\u00a5\u00b0\u0003Z-\u0000"+ + "\u00a6\u00b0\u0003t:\u0000\u00a7\u00b0\u0003\\.\u0000\u00a8\u00b0\u0003"+ + "|>\u0000\u00a9\u00aa\u0004\u0003\u0002\u0000\u00aa\u00b0\u0003z=\u0000"+ + "\u00ab\u00ac\u0004\u0003\u0003\u0000\u00ac\u00b0\u0003x<\u0000\u00ad\u00ae"+ + "\u0004\u0003\u0004\u0000\u00ae\u00b0\u0003\u0084B\u0000\u00af\u009c\u0001"+ + "\u0000\u0000\u0000\u00af\u009d\u0001\u0000\u0000\u0000\u00af\u009e\u0001"+ + "\u0000\u0000\u0000\u00af\u009f\u0001\u0000\u0000\u0000\u00af\u00a0\u0001"+ + "\u0000\u0000\u0000\u00af\u00a1\u0001\u0000\u0000\u0000\u00af\u00a2\u0001"+ + "\u0000\u0000\u0000\u00af\u00a3\u0001\u0000\u0000\u0000\u00af\u00a4\u0001"+ + "\u0000\u0000\u0000\u00af\u00a5\u0001\u0000\u0000\u0000\u00af\u00a6\u0001"+ + "\u0000\u0000\u0000\u00af\u00a7\u0001\u0000\u0000\u0000\u00af\u00a8\u0001"+ + "\u0000\u0000\u0000\u00af\u00a9\u0001\u0000\u0000\u0000\u00af\u00ab\u0001"+ + "\u0000\u0000\u0000\u00af\u00ad\u0001\u0000\u0000\u0000\u00b0\u0007\u0001"+ + "\u0000\u0000\u0000\u00b1\u00b2\u0005\u0010\u0000\u0000\u00b2\u00b3\u0003"+ + "\n\u0005\u0000\u00b3\t\u0001\u0000\u0000\u0000\u00b4\u00b5\u0006\u0005"+ + "\uffff\uffff\u0000\u00b5\u00b6\u00051\u0000\u0000\u00b6\u00d2\u0003\n"+ + "\u0005\b\u00b7\u00d2\u0003\u0010\b\u0000\u00b8\u00d2\u0003\f\u0006\u0000"+ + "\u00b9\u00bb\u0003\u0010\b\u0000\u00ba\u00bc\u00051\u0000\u0000\u00bb"+ + "\u00ba\u0001\u0000\u0000\u0000\u00bb\u00bc\u0001\u0000\u0000\u0000\u00bc"+ + "\u00bd\u0001\u0000\u0000\u0000\u00bd\u00be\u0005,\u0000\u0000\u00be\u00bf"+ + "\u00050\u0000\u0000\u00bf\u00c4\u0003\u0010\b\u0000\u00c0\u00c1\u0005"+ + "\'\u0000\u0000\u00c1\u00c3\u0003\u0010\b\u0000\u00c2\u00c0\u0001\u0000"+ + "\u0000\u0000\u00c3\u00c6\u0001\u0000\u0000\u0000\u00c4\u00c2\u0001\u0000"+ + "\u0000\u0000\u00c4\u00c5\u0001\u0000\u0000\u0000\u00c5\u00c7\u0001\u0000"+ + "\u0000\u0000\u00c6\u00c4\u0001\u0000\u0000\u0000\u00c7\u00c8\u00057\u0000"+ + "\u0000\u00c8\u00d2\u0001\u0000\u0000\u0000\u00c9\u00ca\u0003\u0010\b\u0000"+ + "\u00ca\u00cc\u0005-\u0000\u0000\u00cb\u00cd\u00051\u0000\u0000\u00cc\u00cb"+ + "\u0001\u0000\u0000\u0000\u00cc\u00cd\u0001\u0000\u0000\u0000\u00cd\u00ce"+ + "\u0001\u0000\u0000\u0000\u00ce\u00cf\u00052\u0000\u0000\u00cf\u00d2\u0001"+ + "\u0000\u0000\u0000\u00d0\u00d2\u0003\u000e\u0007\u0000\u00d1\u00b4\u0001"+ + "\u0000\u0000\u0000\u00d1\u00b7\u0001\u0000\u0000\u0000\u00d1\u00b8\u0001"+ + "\u0000\u0000\u0000\u00d1\u00b9\u0001\u0000\u0000\u0000\u00d1\u00c9\u0001"+ + "\u0000\u0000\u0000\u00d1\u00d0\u0001\u0000\u0000\u0000\u00d2\u00db\u0001"+ + "\u0000\u0000\u0000\u00d3\u00d4\n\u0005\u0000\u0000\u00d4\u00d5\u0005\""+ + "\u0000\u0000\u00d5\u00da\u0003\n\u0005\u0006\u00d6\u00d7\n\u0004\u0000"+ + "\u0000\u00d7\u00d8\u00054\u0000\u0000\u00d8\u00da\u0003\n\u0005\u0005"+ + "\u00d9\u00d3\u0001\u0000\u0000\u0000\u00d9\u00d6\u0001\u0000\u0000\u0000"+ + "\u00da\u00dd\u0001\u0000\u0000\u0000\u00db\u00d9\u0001\u0000\u0000\u0000"+ + "\u00db\u00dc\u0001\u0000\u0000\u0000\u00dc\u000b\u0001\u0000\u0000\u0000"+ + "\u00dd\u00db\u0001\u0000\u0000\u0000\u00de\u00e0\u0003\u0010\b\u0000\u00df"+ + "\u00e1\u00051\u0000\u0000\u00e0\u00df\u0001\u0000\u0000\u0000\u00e0\u00e1"+ + "\u0001\u0000\u0000\u0000\u00e1\u00e2\u0001\u0000\u0000\u0000\u00e2\u00e3"+ + "\u0005/\u0000\u0000\u00e3\u00e4\u0003j5\u0000\u00e4\u00ed\u0001\u0000"+ + "\u0000\u0000\u00e5\u00e7\u0003\u0010\b\u0000\u00e6\u00e8\u00051\u0000"+ + "\u0000\u00e7\u00e6\u0001\u0000\u0000\u0000\u00e7\u00e8\u0001\u0000\u0000"+ + "\u0000\u00e8\u00e9\u0001\u0000\u0000\u0000\u00e9\u00ea\u00056\u0000\u0000"+ + "\u00ea\u00eb\u0003j5\u0000\u00eb\u00ed\u0001\u0000\u0000\u0000\u00ec\u00de"+ + "\u0001\u0000\u0000\u0000\u00ec\u00e5\u0001\u0000\u0000\u0000\u00ed\r\u0001"+ + "\u0000\u0000\u0000\u00ee\u00f1\u0003:\u001d\u0000\u00ef\u00f0\u0005%\u0000"+ + "\u0000\u00f0\u00f2\u0003\u001e\u000f\u0000\u00f1\u00ef\u0001\u0000\u0000"+ + "\u0000\u00f1\u00f2\u0001\u0000\u0000\u0000\u00f2\u00f3\u0001\u0000\u0000"+ + "\u0000\u00f3\u00f4\u0005&\u0000\u0000\u00f4\u00f5\u0003D\"\u0000\u00f5"+ + "\u000f\u0001\u0000\u0000\u0000\u00f6\u00fc\u0003\u0012\t\u0000\u00f7\u00f8"+ + "\u0003\u0012\t\u0000\u00f8\u00f9\u0003l6\u0000\u00f9\u00fa\u0003\u0012"+ + "\t\u0000\u00fa\u00fc\u0001\u0000\u0000\u0000\u00fb\u00f6\u0001\u0000\u0000"+ + "\u0000\u00fb\u00f7\u0001\u0000\u0000\u0000\u00fc\u0011\u0001\u0000\u0000"+ + "\u0000\u00fd\u00fe\u0006\t\uffff\uffff\u0000\u00fe\u0102\u0003\u0014\n"+ + "\u0000\u00ff\u0100\u0007\u0000\u0000\u0000\u0100\u0102\u0003\u0012\t\u0003"+ + "\u0101\u00fd\u0001\u0000\u0000\u0000\u0101\u00ff\u0001\u0000\u0000\u0000"+ + "\u0102\u010b\u0001\u0000\u0000\u0000\u0103\u0104\n\u0002\u0000\u0000\u0104"+ + "\u0105\u0007\u0001\u0000\u0000\u0105\u010a\u0003\u0012\t\u0003\u0106\u0107"+ + "\n\u0001\u0000\u0000\u0107\u0108\u0007\u0000\u0000\u0000\u0108\u010a\u0003"+ + "\u0012\t\u0002\u0109\u0103\u0001\u0000\u0000\u0000\u0109\u0106\u0001\u0000"+ + "\u0000\u0000\u010a\u010d\u0001\u0000\u0000\u0000\u010b\u0109\u0001\u0000"+ + "\u0000\u0000\u010b\u010c\u0001\u0000\u0000\u0000\u010c\u0013\u0001\u0000"+ + "\u0000\u0000\u010d\u010b\u0001\u0000\u0000\u0000\u010e\u010f\u0006\n\uffff"+ + "\uffff\u0000\u010f\u0117\u0003D\"\u0000\u0110\u0117\u0003:\u001d\u0000"+ + "\u0111\u0117\u0003\u0016\u000b\u0000\u0112\u0113\u00050\u0000\u0000\u0113"+ + "\u0114\u0003\n\u0005\u0000\u0114\u0115\u00057\u0000\u0000\u0115\u0117"+ + "\u0001\u0000\u0000\u0000\u0116\u010e\u0001\u0000\u0000\u0000\u0116\u0110"+ + "\u0001\u0000\u0000\u0000\u0116\u0111\u0001\u0000\u0000\u0000\u0116\u0112"+ + "\u0001\u0000\u0000\u0000\u0117\u011d\u0001\u0000\u0000\u0000\u0118\u0119"+ + "\n\u0001\u0000\u0000\u0119\u011a\u0005%\u0000\u0000\u011a\u011c\u0003"+ + "\u001e\u000f\u0000\u011b\u0118\u0001\u0000\u0000\u0000\u011c\u011f\u0001"+ + "\u0000\u0000\u0000\u011d\u011b\u0001\u0000\u0000\u0000\u011d\u011e\u0001"+ + "\u0000\u0000\u0000\u011e\u0015\u0001\u0000\u0000\u0000\u011f\u011d\u0001"+ + "\u0000\u0000\u0000\u0120\u0121\u0003\u0018\f\u0000\u0121\u012f\u00050"+ + "\u0000\u0000\u0122\u0130\u0005B\u0000\u0000\u0123\u0128\u0003\n\u0005"+ + "\u0000\u0124\u0125\u0005\'\u0000\u0000\u0125\u0127\u0003\n\u0005\u0000"+ + "\u0126\u0124\u0001\u0000\u0000\u0000\u0127\u012a\u0001\u0000\u0000\u0000"+ + "\u0128\u0126\u0001\u0000\u0000\u0000\u0128\u0129\u0001\u0000\u0000\u0000"+ + "\u0129\u012d\u0001\u0000\u0000\u0000\u012a\u0128\u0001\u0000\u0000\u0000"+ + "\u012b\u012c\u0005\'\u0000\u0000\u012c\u012e\u0003\u001a\r\u0000\u012d"+ + "\u012b\u0001\u0000\u0000\u0000\u012d\u012e\u0001\u0000\u0000\u0000\u012e"+ + "\u0130\u0001\u0000\u0000\u0000\u012f\u0122\u0001\u0000\u0000\u0000\u012f"+ + "\u0123\u0001\u0000\u0000\u0000\u012f\u0130\u0001\u0000\u0000\u0000\u0130"+ + "\u0131\u0001\u0000\u0000\u0000\u0131\u0132\u00057\u0000\u0000\u0132\u0017"+ + "\u0001\u0000\u0000\u0000\u0133\u0134\u0003H$\u0000\u0134\u0019\u0001\u0000"+ + "\u0000\u0000\u0135\u0136\u0005E\u0000\u0000\u0136\u013b\u0003\u001c\u000e"+ + "\u0000\u0137\u0138\u0005\'\u0000\u0000\u0138\u013a\u0003\u001c\u000e\u0000"+ + "\u0139\u0137\u0001\u0000\u0000\u0000\u013a\u013d\u0001\u0000\u0000\u0000"+ + "\u013b\u0139\u0001\u0000\u0000\u0000\u013b\u013c\u0001\u0000\u0000\u0000"+ + "\u013c\u013e\u0001\u0000\u0000\u0000\u013d\u013b\u0001\u0000\u0000\u0000"+ + "\u013e\u013f\u0005F\u0000\u0000\u013f\u001b\u0001\u0000\u0000\u0000\u0140"+ + "\u0141\u0003j5\u0000\u0141\u0142\u0005&\u0000\u0000\u0142\u0143\u0003"+ + "D\"\u0000\u0143\u001d\u0001\u0000\u0000\u0000\u0144\u0145\u0003@ \u0000"+ + "\u0145\u001f\u0001\u0000\u0000\u0000\u0146\u0147\u0005\f\u0000\u0000\u0147"+ + "\u0148\u0003\"\u0011\u0000\u0148!\u0001\u0000\u0000\u0000\u0149\u014e"+ + "\u0003$\u0012\u0000\u014a\u014b\u0005\'\u0000\u0000\u014b\u014d\u0003"+ + "$\u0012\u0000\u014c\u014a\u0001\u0000\u0000\u0000\u014d\u0150\u0001\u0000"+ + "\u0000\u0000\u014e\u014c\u0001\u0000\u0000\u0000\u014e\u014f\u0001\u0000"+ + "\u0000\u0000\u014f#\u0001\u0000\u0000\u0000\u0150\u014e\u0001\u0000\u0000"+ + "\u0000\u0151\u0152\u0003:\u001d\u0000\u0152\u0153\u0005$\u0000\u0000\u0153"+ + "\u0155\u0001\u0000\u0000\u0000\u0154\u0151\u0001\u0000\u0000\u0000\u0154"+ + "\u0155\u0001\u0000\u0000\u0000\u0155\u0156\u0001\u0000\u0000\u0000\u0156"+ + "\u0157\u0003\n\u0005\u0000\u0157%\u0001\u0000\u0000\u0000\u0158\u0159"+ + "\u0005\u0006\u0000\u0000\u0159\u015e\u0003(\u0014\u0000\u015a\u015b\u0005"+ + "\'\u0000\u0000\u015b\u015d\u0003(\u0014\u0000\u015c\u015a\u0001\u0000"+ + "\u0000\u0000\u015d\u0160\u0001\u0000\u0000\u0000\u015e\u015c\u0001\u0000"+ + "\u0000\u0000\u015e\u015f\u0001\u0000\u0000\u0000\u015f\u0162\u0001\u0000"+ + "\u0000\u0000\u0160\u015e\u0001\u0000\u0000\u0000\u0161\u0163\u0003.\u0017"+ + "\u0000\u0162\u0161\u0001\u0000\u0000\u0000\u0162\u0163\u0001\u0000\u0000"+ + "\u0000\u0163\'\u0001\u0000\u0000\u0000\u0164\u0165\u0003*\u0015\u0000"+ + "\u0165\u0166\u0005&\u0000\u0000\u0166\u0168\u0001\u0000\u0000\u0000\u0167"+ + "\u0164\u0001\u0000\u0000\u0000\u0167\u0168\u0001\u0000\u0000\u0000\u0168"+ + "\u0169\u0001\u0000\u0000\u0000\u0169\u016a\u0003,\u0016\u0000\u016a)\u0001"+ + "\u0000\u0000\u0000\u016b\u016c\u0007\u0002\u0000\u0000\u016c+\u0001\u0000"+ + "\u0000\u0000\u016d\u016e\u0007\u0002\u0000\u0000\u016e-\u0001\u0000\u0000"+ + "\u0000\u016f\u0170\u0005R\u0000\u0000\u0170\u0175\u0005S\u0000\u0000\u0171"+ + "\u0172\u0005\'\u0000\u0000\u0172\u0174\u0005S\u0000\u0000\u0173\u0171"+ + "\u0001\u0000\u0000\u0000\u0174\u0177\u0001\u0000\u0000\u0000\u0175\u0173"+ + "\u0001\u0000\u0000\u0000\u0175\u0176\u0001\u0000\u0000\u0000\u0176/\u0001"+ + "\u0000\u0000\u0000\u0177\u0175\u0001\u0000\u0000\u0000\u0178\u0179\u0005"+ + "\u0015\u0000\u0000\u0179\u017e\u0003(\u0014\u0000\u017a\u017b\u0005\'"+ + "\u0000\u0000\u017b\u017d\u0003(\u0014\u0000\u017c\u017a\u0001\u0000\u0000"+ + "\u0000\u017d\u0180\u0001\u0000\u0000\u0000\u017e\u017c\u0001\u0000\u0000"+ + "\u0000\u017e\u017f\u0001\u0000\u0000\u0000\u017f\u0182\u0001\u0000\u0000"+ + "\u0000\u0180\u017e\u0001\u0000\u0000\u0000\u0181\u0183\u00036\u001b\u0000"+ + "\u0182\u0181\u0001\u0000\u0000\u0000\u0182\u0183\u0001\u0000\u0000\u0000"+ + "\u0183\u0186\u0001\u0000\u0000\u0000\u0184\u0185\u0005!\u0000\u0000\u0185"+ + "\u0187\u0003\"\u0011\u0000\u0186\u0184\u0001\u0000\u0000\u0000\u0186\u0187"+ + "\u0001\u0000\u0000\u0000\u01871\u0001\u0000\u0000\u0000\u0188\u0189\u0005"+ + "\u0004\u0000\u0000\u0189\u018a\u0003\"\u0011\u0000\u018a3\u0001\u0000"+ + "\u0000\u0000\u018b\u018d\u0005\u000f\u0000\u0000\u018c\u018e\u00036\u001b"+ + "\u0000\u018d\u018c\u0001\u0000\u0000\u0000\u018d\u018e\u0001\u0000\u0000"+ + "\u0000\u018e\u0191\u0001\u0000\u0000\u0000\u018f\u0190\u0005!\u0000\u0000"+ + "\u0190\u0192\u0003\"\u0011\u0000\u0191\u018f\u0001\u0000\u0000\u0000\u0191"+ + "\u0192\u0001\u0000\u0000\u0000\u01925\u0001\u0000\u0000\u0000\u0193\u0198"+ + "\u00038\u001c\u0000\u0194\u0195\u0005\'\u0000\u0000\u0195\u0197\u0003"+ + "8\u001c\u0000\u0196\u0194\u0001\u0000\u0000\u0000\u0197\u019a\u0001\u0000"+ + "\u0000\u0000\u0198\u0196\u0001\u0000\u0000\u0000\u0198\u0199\u0001\u0000"+ + "\u0000\u0000\u01997\u0001\u0000\u0000\u0000\u019a\u0198\u0001\u0000\u0000"+ + "\u0000\u019b\u019e\u0003$\u0012\u0000\u019c\u019d\u0005\u0010\u0000\u0000"+ + "\u019d\u019f\u0003\n\u0005\u0000\u019e\u019c\u0001\u0000\u0000\u0000\u019e"+ + "\u019f\u0001\u0000\u0000\u0000\u019f9\u0001\u0000\u0000\u0000\u01a0\u01a5"+ + "\u0003H$\u0000\u01a1\u01a2\u0005)\u0000\u0000\u01a2\u01a4\u0003H$\u0000"+ + "\u01a3\u01a1\u0001\u0000\u0000\u0000\u01a4\u01a7\u0001\u0000\u0000\u0000"+ + "\u01a5\u01a3\u0001\u0000\u0000\u0000\u01a5\u01a6\u0001\u0000\u0000\u0000"+ + "\u01a6;\u0001\u0000\u0000\u0000\u01a7\u01a5\u0001\u0000\u0000\u0000\u01a8"+ + "\u01ad\u0003B!\u0000\u01a9\u01aa\u0005)\u0000\u0000\u01aa\u01ac\u0003"+ + "B!\u0000\u01ab\u01a9\u0001\u0000\u0000\u0000\u01ac\u01af\u0001\u0000\u0000"+ + "\u0000\u01ad\u01ab\u0001\u0000\u0000\u0000\u01ad\u01ae\u0001\u0000\u0000"+ + "\u0000\u01ae=\u0001\u0000\u0000\u0000\u01af\u01ad\u0001\u0000\u0000\u0000"+ + "\u01b0\u01b5\u0003<\u001e\u0000\u01b1\u01b2\u0005\'\u0000\u0000\u01b2"+ + "\u01b4\u0003<\u001e\u0000\u01b3\u01b1\u0001\u0000\u0000\u0000\u01b4\u01b7"+ + "\u0001\u0000\u0000\u0000\u01b5\u01b3\u0001\u0000\u0000\u0000\u01b5\u01b6"+ + "\u0001\u0000\u0000\u0000\u01b6?\u0001\u0000\u0000\u0000\u01b7\u01b5\u0001"+ + "\u0000\u0000\u0000\u01b8\u01b9\u0007\u0003\u0000\u0000\u01b9A\u0001\u0000"+ + "\u0000\u0000\u01ba\u01bd\u0005W\u0000\u0000\u01bb\u01bd\u0003F#\u0000"+ + "\u01bc\u01ba\u0001\u0000\u0000\u0000\u01bc\u01bb\u0001\u0000\u0000\u0000"+ + "\u01bdC\u0001\u0000\u0000\u0000\u01be\u01e9\u00052\u0000\u0000\u01bf\u01c0"+ + "\u0003h4\u0000\u01c0\u01c1\u0005J\u0000\u0000\u01c1\u01e9\u0001\u0000"+ + "\u0000\u0000\u01c2\u01e9\u0003f3\u0000\u01c3\u01e9\u0003h4\u0000\u01c4"+ + "\u01e9\u0003b1\u0000\u01c5\u01e9\u0003F#\u0000\u01c6\u01e9\u0003j5\u0000"+ + "\u01c7\u01c8\u0005H\u0000\u0000\u01c8\u01cd\u0003d2\u0000\u01c9\u01ca"+ + "\u0005\'\u0000\u0000\u01ca\u01cc\u0003d2\u0000\u01cb\u01c9\u0001\u0000"+ + "\u0000\u0000\u01cc\u01cf\u0001\u0000\u0000\u0000\u01cd\u01cb\u0001\u0000"+ + "\u0000\u0000\u01cd\u01ce\u0001\u0000\u0000\u0000\u01ce\u01d0\u0001\u0000"+ + "\u0000\u0000\u01cf\u01cd\u0001\u0000\u0000\u0000\u01d0\u01d1\u0005I\u0000"+ + "\u0000\u01d1\u01e9\u0001\u0000\u0000\u0000\u01d2\u01d3\u0005H\u0000\u0000"+ + "\u01d3\u01d8\u0003b1\u0000\u01d4\u01d5\u0005\'\u0000\u0000\u01d5\u01d7"+ + "\u0003b1\u0000\u01d6\u01d4\u0001\u0000\u0000\u0000\u01d7\u01da\u0001\u0000"+ + "\u0000\u0000\u01d8\u01d6\u0001\u0000\u0000\u0000\u01d8\u01d9\u0001\u0000"+ + "\u0000\u0000\u01d9\u01db\u0001\u0000\u0000\u0000\u01da\u01d8\u0001\u0000"+ + "\u0000\u0000\u01db\u01dc\u0005I\u0000\u0000\u01dc\u01e9\u0001\u0000\u0000"+ + "\u0000\u01dd\u01de\u0005H\u0000\u0000\u01de\u01e3\u0003j5\u0000\u01df"+ + "\u01e0\u0005\'\u0000\u0000\u01e0\u01e2\u0003j5\u0000\u01e1\u01df\u0001"+ + "\u0000\u0000\u0000\u01e2\u01e5\u0001\u0000\u0000\u0000\u01e3\u01e1\u0001"+ + "\u0000\u0000\u0000\u01e3\u01e4\u0001\u0000\u0000\u0000\u01e4\u01e6\u0001"+ + "\u0000\u0000\u0000\u01e5\u01e3\u0001\u0000\u0000\u0000\u01e6\u01e7\u0005"+ + "I\u0000\u0000\u01e7\u01e9\u0001\u0000\u0000\u0000\u01e8\u01be\u0001\u0000"+ + "\u0000\u0000\u01e8\u01bf\u0001\u0000\u0000\u0000\u01e8\u01c2\u0001\u0000"+ + "\u0000\u0000\u01e8\u01c3\u0001\u0000\u0000\u0000\u01e8\u01c4\u0001\u0000"+ + "\u0000\u0000\u01e8\u01c5\u0001\u0000\u0000\u0000\u01e8\u01c6\u0001\u0000"+ + "\u0000\u0000\u01e8\u01c7\u0001\u0000\u0000\u0000\u01e8\u01d2\u0001\u0000"+ + "\u0000\u0000\u01e8\u01dd\u0001\u0000\u0000\u0000\u01e9E\u0001\u0000\u0000"+ + "\u0000\u01ea\u01ed\u00055\u0000\u0000\u01eb\u01ed\u0005G\u0000\u0000\u01ec"+ + "\u01ea\u0001\u0000\u0000\u0000\u01ec\u01eb\u0001\u0000\u0000\u0000\u01ed"+ + "G\u0001\u0000\u0000\u0000\u01ee\u01f1\u0003@ \u0000\u01ef\u01f1\u0003"+ + "F#\u0000\u01f0\u01ee\u0001\u0000\u0000\u0000\u01f0\u01ef\u0001\u0000\u0000"+ + "\u0000\u01f1I\u0001\u0000\u0000\u0000\u01f2\u01f3\u0005\t\u0000\u0000"+ + "\u01f3\u01f4\u0005\u001f\u0000\u0000\u01f4K\u0001\u0000\u0000\u0000\u01f5"+ + "\u01f6\u0005\u000e\u0000\u0000\u01f6\u01fb\u0003N\'\u0000\u01f7\u01f8"+ + "\u0005\'\u0000\u0000\u01f8\u01fa\u0003N\'\u0000\u01f9\u01f7\u0001\u0000"+ + "\u0000\u0000\u01fa\u01fd\u0001\u0000\u0000\u0000\u01fb\u01f9\u0001\u0000"+ + "\u0000\u0000\u01fb\u01fc\u0001\u0000\u0000\u0000\u01fcM\u0001\u0000\u0000"+ + "\u0000\u01fd\u01fb\u0001\u0000\u0000\u0000\u01fe\u0200\u0003\n\u0005\u0000"+ + "\u01ff\u0201\u0007\u0004\u0000\u0000\u0200\u01ff\u0001\u0000\u0000\u0000"+ + "\u0200\u0201\u0001\u0000\u0000\u0000\u0201\u0204\u0001\u0000\u0000\u0000"+ + "\u0202\u0203\u00053\u0000\u0000\u0203\u0205\u0007\u0005\u0000\u0000\u0204"+ + "\u0202\u0001\u0000\u0000\u0000\u0204\u0205\u0001\u0000\u0000\u0000\u0205"+ + "O\u0001\u0000\u0000\u0000\u0206\u0207\u0005\b\u0000\u0000\u0207\u0208"+ + "\u0003>\u001f\u0000\u0208Q\u0001\u0000\u0000\u0000\u0209\u020a\u0005\u0002"+ + "\u0000\u0000\u020a\u020b\u0003>\u001f\u0000\u020bS\u0001\u0000\u0000\u0000"+ + "\u020c\u020d\u0005\u000b\u0000\u0000\u020d\u0212\u0003V+\u0000\u020e\u020f"+ + "\u0005\'\u0000\u0000\u020f\u0211\u0003V+\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\u0213U\u0001\u0000\u0000"+ + "\u0000\u0214\u0212\u0001\u0000\u0000\u0000\u0215\u0216\u0003<\u001e\u0000"+ + "\u0216\u0217\u0005[\u0000\u0000\u0217\u0218\u0003<\u001e\u0000\u0218W"+ + "\u0001\u0000\u0000\u0000\u0219\u021a\u0005\u0001\u0000\u0000\u021a\u021b"+ + "\u0003\u0014\n\u0000\u021b\u021d\u0003j5\u0000\u021c\u021e\u0003^/\u0000"+ + "\u021d\u021c\u0001\u0000\u0000\u0000\u021d\u021e\u0001\u0000\u0000\u0000"+ + "\u021eY\u0001\u0000\u0000\u0000\u021f\u0220\u0005\u0007\u0000\u0000\u0220"+ + "\u0221\u0003\u0014\n\u0000\u0221\u0222\u0003j5\u0000\u0222[\u0001\u0000"+ + "\u0000\u0000\u0223\u0224\u0005\n\u0000\u0000\u0224\u0225\u0003:\u001d"+ + "\u0000\u0225]\u0001\u0000\u0000\u0000\u0226\u022b\u0003`0\u0000\u0227"+ + "\u0228\u0005\'\u0000\u0000\u0228\u022a\u0003`0\u0000\u0229\u0227\u0001"+ + "\u0000\u0000\u0000\u022a\u022d\u0001\u0000\u0000\u0000\u022b\u0229\u0001"+ + "\u0000\u0000\u0000\u022b\u022c\u0001\u0000\u0000\u0000\u022c_\u0001\u0000"+ + "\u0000\u0000\u022d\u022b\u0001\u0000\u0000\u0000\u022e\u022f\u0003@ \u0000"+ + "\u022f\u0230\u0005$\u0000\u0000\u0230\u0231\u0003D\"\u0000\u0231a\u0001"+ + "\u0000\u0000\u0000\u0232\u0233\u0007\u0006\u0000\u0000\u0233c\u0001\u0000"+ + "\u0000\u0000\u0234\u0237\u0003f3\u0000\u0235\u0237\u0003h4\u0000\u0236"+ + "\u0234\u0001\u0000\u0000\u0000\u0236\u0235\u0001\u0000\u0000\u0000\u0237"+ + "e\u0001\u0000\u0000\u0000\u0238\u023a\u0007\u0000\u0000\u0000\u0239\u0238"+ + "\u0001\u0000\u0000\u0000\u0239\u023a\u0001\u0000\u0000\u0000\u023a\u023b"+ + "\u0001\u0000\u0000\u0000\u023b\u023c\u0005 \u0000\u0000\u023cg\u0001\u0000"+ + "\u0000\u0000\u023d\u023f\u0007\u0000\u0000\u0000\u023e\u023d\u0001\u0000"+ + "\u0000\u0000\u023e\u023f\u0001\u0000\u0000\u0000\u023f\u0240\u0001\u0000"+ + "\u0000\u0000\u0240\u0241\u0005\u001f\u0000\u0000\u0241i\u0001\u0000\u0000"+ + "\u0000\u0242\u0243\u0005\u001e\u0000\u0000\u0243k\u0001\u0000\u0000\u0000"+ + "\u0244\u0245\u0007\u0007\u0000\u0000\u0245m\u0001\u0000\u0000\u0000\u0246"+ + "\u0247\u0005\u0005\u0000\u0000\u0247\u0248\u0003p8\u0000\u0248o\u0001"+ + "\u0000\u0000\u0000\u0249\u024a\u0005H\u0000\u0000\u024a\u024b\u0003\u0002"+ + "\u0001\u0000\u024b\u024c\u0005I\u0000\u0000\u024cq\u0001\u0000\u0000\u0000"+ + "\u024d\u024e\u0005\r\u0000\u0000\u024e\u024f\u0005k\u0000\u0000\u024f"+ + "s\u0001\u0000\u0000\u0000\u0250\u0251\u0005\u0003\u0000\u0000\u0251\u0254"+ + "\u0005a\u0000\u0000\u0252\u0253\u0005_\u0000\u0000\u0253\u0255\u0003<"+ + "\u001e\u0000\u0254\u0252\u0001\u0000\u0000\u0000\u0254\u0255\u0001\u0000"+ + "\u0000\u0000\u0255\u025f\u0001\u0000\u0000\u0000\u0256\u0257\u0005`\u0000"+ + "\u0000\u0257\u025c\u0003v;\u0000\u0258\u0259\u0005\'\u0000\u0000\u0259"+ + "\u025b\u0003v;\u0000\u025a\u0258\u0001\u0000\u0000\u0000\u025b\u025e\u0001"+ + "\u0000\u0000\u0000\u025c\u025a\u0001\u0000\u0000\u0000\u025c\u025d\u0001"+ + "\u0000\u0000\u0000\u025d\u0260\u0001\u0000\u0000\u0000\u025e\u025c\u0001"+ + "\u0000\u0000\u0000\u025f\u0256\u0001\u0000\u0000\u0000\u025f\u0260\u0001"+ + "\u0000\u0000\u0000\u0260u\u0001\u0000\u0000\u0000\u0261\u0262\u0003<\u001e"+ + "\u0000\u0262\u0263\u0005$\u0000\u0000\u0263\u0265\u0001\u0000\u0000\u0000"+ + "\u0264\u0261\u0001\u0000\u0000\u0000\u0264\u0265\u0001\u0000\u0000\u0000"+ + "\u0265\u0266\u0001\u0000\u0000\u0000\u0266\u0267\u0003<\u001e\u0000\u0267"+ + "w\u0001\u0000\u0000\u0000\u0268\u0269\u0005\u0014\u0000\u0000\u0269\u026a"+ + "\u0003(\u0014\u0000\u026a\u026b\u0005_\u0000\u0000\u026b\u026c\u0003>"+ + "\u001f\u0000\u026cy\u0001\u0000\u0000\u0000\u026d\u026e\u0005\u0013\u0000"+ + "\u0000\u026e\u0271\u00036\u001b\u0000\u026f\u0270\u0005!\u0000\u0000\u0270"+ + "\u0272\u0003\"\u0011\u0000\u0271\u026f\u0001\u0000\u0000\u0000\u0271\u0272"+ + "\u0001\u0000\u0000\u0000\u0272{\u0001\u0000\u0000\u0000\u0273\u0274\u0007"+ + "\b\u0000\u0000\u0274\u0275\u0005y\u0000\u0000\u0275\u0276\u0003~?\u0000"+ + "\u0276\u0277\u0003\u0080@\u0000\u0277}\u0001\u0000\u0000\u0000\u0278\u0279"+ + "\u0003(\u0014\u0000\u0279\u007f\u0001\u0000\u0000\u0000\u027a\u027b\u0005"+ + "_\u0000\u0000\u027b\u0280\u0003\u0082A\u0000\u027c\u027d\u0005\'\u0000"+ + "\u0000\u027d\u027f\u0003\u0082A\u0000\u027e\u027c\u0001\u0000\u0000\u0000"+ + "\u027f\u0282\u0001\u0000\u0000\u0000\u0280\u027e\u0001\u0000\u0000\u0000"+ + "\u0280\u0281\u0001\u0000\u0000\u0000\u0281\u0081\u0001\u0000\u0000\u0000"+ + "\u0282\u0280\u0001\u0000\u0000\u0000\u0283\u0284\u0003\u0010\b\u0000\u0284"+ + "\u0083\u0001\u0000\u0000\u0000\u0285\u0286\u0005\u0012\u0000\u0000\u0286"+ + "\u0289\u0003:\u001d\u0000\u0287\u0288\u0005_\u0000\u0000\u0288\u028a\u0003"+ + ":\u001d\u0000\u0289\u0287\u0001\u0000\u0000\u0000\u0289\u028a\u0001\u0000"+ + "\u0000\u0000\u028a\u0290\u0001\u0000\u0000\u0000\u028b\u028c\u0005[\u0000"+ + "\u0000\u028c\u028d\u0003:\u001d\u0000\u028d\u028e\u0005\'\u0000\u0000"+ + "\u028e\u028f\u0003:\u001d\u0000\u028f\u0291\u0001\u0000\u0000\u0000\u0290"+ + "\u028b\u0001\u0000\u0000\u0000\u0290\u0291\u0001\u0000\u0000\u0000\u0291"+ + "\u0085\u0001\u0000\u0000\u0000?\u0091\u009a\u00af\u00bb\u00c4\u00cc\u00d1"+ + "\u00d9\u00db\u00e0\u00e7\u00ec\u00f1\u00fb\u0101\u0109\u010b\u0116\u011d"+ + "\u0128\u012d\u012f\u013b\u014e\u0154\u015e\u0162\u0167\u0175\u017e\u0182"+ + "\u0186\u018d\u0191\u0198\u019e\u01a5\u01ad\u01b5\u01bc\u01cd\u01d8\u01e3"+ + "\u01e8\u01ec\u01f0\u01fb\u0200\u0204\u0212\u021d\u022b\u0236\u0239\u023e"+ + "\u0254\u025c\u025f\u0264\u0271\u0280\u0289\u0290"; 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 df6d8f1e3501..ee2c97e1e381 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 @@ -1100,6 +1100,18 @@ public class EsqlBaseParserBaseListener implements EsqlBaseParserListener { *

    The default implementation does nothing.

    */ @Override public void exitJoinPredicate(EsqlBaseParser.JoinPredicateContext ctx) { } + /** + * {@inheritDoc} + * + *

    The default implementation does nothing.

    + */ + @Override public void enterChangePointCommand(EsqlBaseParser.ChangePointCommandContext ctx) { } + /** + * {@inheritDoc} + * + *

    The default implementation does nothing.

    + */ + @Override public void exitChangePointCommand(EsqlBaseParser.ChangePointCommandContext 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 885ba91e20dc..c1e3a4b32795 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 @@ -650,4 +650,11 @@ public class EsqlBaseParserBaseVisitor extends AbstractParseTreeVisitor im * {@link #visitChildren} on {@code ctx}.

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

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

    + */ + @Override public T visitChangePointCommand(EsqlBaseParser.ChangePointCommandContext 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 2c1faa374695..c4f72ae1444d 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 @@ -981,4 +981,14 @@ public interface EsqlBaseParserListener extends ParseTreeListener { * @param ctx the parse tree */ void exitJoinPredicate(EsqlBaseParser.JoinPredicateContext ctx); + /** + * Enter a parse tree produced by {@link EsqlBaseParser#changePointCommand}. + * @param ctx the parse tree + */ + void enterChangePointCommand(EsqlBaseParser.ChangePointCommandContext ctx); + /** + * Exit a parse tree produced by {@link EsqlBaseParser#changePointCommand}. + * @param ctx the parse tree + */ + void exitChangePointCommand(EsqlBaseParser.ChangePointCommandContext 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 73afd23393cd..4dc2670662f5 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 @@ -591,4 +591,10 @@ public interface EsqlBaseParserVisitor extends ParseTreeVisitor { * @return the visitor result */ T visitJoinPredicate(EsqlBaseParser.JoinPredicateContext ctx); + /** + * Visit a parse tree produced by {@link EsqlBaseParser#changePointCommand}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitChangePointCommand(EsqlBaseParser.ChangePointCommandContext 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 78c3044257f9..9d7c3dd90847 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 @@ -795,9 +795,9 @@ public abstract class ExpressionBuilder extends IdentifierBuilder { private NamedExpression enrichFieldName(EsqlBaseParser.QualifiedNamePatternContext ctx) { return visitQualifiedNamePattern(ctx, ne -> { - if (ne instanceof UnresolvedNamePattern up) { + if (ne instanceof UnresolvedNamePattern || ne instanceof UnresolvedStar) { var src = ne.source(); - throw new ParsingException(src, "Using wildcards [*] in ENRICH WITH projections is not allowed [{}]", up.pattern()); + throw new ParsingException(src, "Using wildcards [*] in ENRICH WITH projections is not allowed, found [{}]", src.text()); } }); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/IdentifierBuilder.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/IdentifierBuilder.java index ae2379318474..fdcd7fc961b9 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/IdentifierBuilder.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/IdentifierBuilder.java @@ -13,6 +13,7 @@ import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.MetadataCreateIndexService; import org.elasticsearch.common.Strings; import org.elasticsearch.indices.InvalidIndexNameException; +import org.elasticsearch.transport.RemoteClusterService; import org.elasticsearch.xpack.esql.core.util.Holder; import org.elasticsearch.xpack.esql.parser.EsqlBaseParser.IdentifierContext; import org.elasticsearch.xpack.esql.parser.EsqlBaseParser.IndexStringContext; @@ -51,10 +52,24 @@ abstract class IdentifierBuilder extends AbstractBuilder { return "`" + unquotedString.replace("`", "``") + "`"; } + @Override + public String visitClusterString(EsqlBaseParser.ClusterStringContext ctx) { + if (ctx == null) { + return null; + } else if (ctx.UNQUOTED_SOURCE() != null) { + return ctx.UNQUOTED_SOURCE().getText(); + } else { + return unquote(ctx.QUOTED_STRING().getText()); + } + } + @Override public String visitIndexString(IndexStringContext ctx) { - TerminalNode n = ctx.UNQUOTED_SOURCE(); - return n != null ? n.getText() : unquote(ctx.QUOTED_STRING().getText()); + if (ctx.UNQUOTED_SOURCE() != null) { + return ctx.UNQUOTED_SOURCE().getText(); + } else { + return unquote(ctx.QUOTED_STRING().getText()); + } } public String visitIndexPattern(List ctx) { @@ -62,18 +77,26 @@ abstract class IdentifierBuilder extends AbstractBuilder { Holder hasSeenStar = new Holder<>(false); ctx.forEach(c -> { String indexPattern = visitIndexString(c.indexString()); - String clusterString = c.clusterString() != null ? c.clusterString().getText() : null; + String clusterString = visitClusterString(c.clusterString()); // skip validating index on remote cluster, because the behavior of remote cluster is not consistent with local cluster // For example, invalid#index is an invalid index name, however FROM *:invalid#index does not return an error if (clusterString == null) { hasSeenStar.set(indexPattern.contains(WILDCARD) || hasSeenStar.get()); validateIndexPattern(indexPattern, c, hasSeenStar.get()); + } else { + validateClusterString(clusterString, c); } patterns.add(clusterString != null ? clusterString + REMOTE_CLUSTER_INDEX_SEPARATOR + indexPattern : indexPattern); }); return Strings.collectionToDelimitedString(patterns, ","); } + protected static void validateClusterString(String clusterString, EsqlBaseParser.IndexPatternContext ctx) { + if (clusterString.indexOf(RemoteClusterService.REMOTE_CLUSTER_INDEX_SEPARATOR) != -1) { + throw new ParsingException(source(ctx), "cluster string [{}] must not contain ':'", clusterString); + } + } + private static void validateIndexPattern(String indexPattern, EsqlBaseParser.IndexPatternContext ctx, boolean hasSeenStar) { // multiple index names can be in the same double quote, e.g. indexPattern = "idx1, *, -idx2" String[] indices = indexPattern.split(","); 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 5ccdda5b1839..4645a15bc196 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 @@ -30,6 +30,7 @@ import org.elasticsearch.xpack.esql.core.expression.FoldContext; import org.elasticsearch.xpack.esql.core.expression.Literal; import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute; import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; import org.elasticsearch.xpack.esql.core.expression.UnresolvedAttribute; import org.elasticsearch.xpack.esql.core.expression.UnresolvedStar; import org.elasticsearch.xpack.esql.core.tree.Source; @@ -40,6 +41,7 @@ import org.elasticsearch.xpack.esql.expression.UnresolvedNamePattern; import org.elasticsearch.xpack.esql.expression.function.UnresolvedFunction; import org.elasticsearch.xpack.esql.plan.IndexPattern; import org.elasticsearch.xpack.esql.plan.logical.Aggregate; +import org.elasticsearch.xpack.esql.plan.logical.ChangePoint; import org.elasticsearch.xpack.esql.plan.logical.Dissect; import org.elasticsearch.xpack.esql.plan.logical.Drop; import org.elasticsearch.xpack.esql.plan.logical.Enrich; @@ -422,7 +424,11 @@ public class LogicalPlanBuilder extends ExpressionBuilder { : matchField instanceof UnresolvedStar ? WILDCARD : null; if (patternString != null) { - throw new ParsingException(source, "Using wildcards [*] in ENRICH WITH projections is not allowed [{}]", patternString); + throw new ParsingException( + source, + "Using wildcards [*] in ENRICH WITH projections is not allowed, found [{}]", + patternString + ); } List keepClauses = visitList(this, ctx.enrichWithClause(), NamedExpression.class); @@ -439,6 +445,24 @@ public class LogicalPlanBuilder extends ExpressionBuilder { }; } + @Override + public PlanFactory visitChangePointCommand(EsqlBaseParser.ChangePointCommandContext ctx) { + Source src = source(ctx); + Attribute value = visitQualifiedName(ctx.value); + Attribute key = ctx.key == null ? new UnresolvedAttribute(src, "@timestamp") : visitQualifiedName(ctx.key); + Attribute targetType = new ReferenceAttribute( + src, + ctx.targetType == null ? "type" : visitQualifiedName(ctx.targetType).name(), + DataType.KEYWORD + ); + Attribute targetPvalue = new ReferenceAttribute( + src, + ctx.targetPvalue == null ? "pvalue" : visitQualifiedName(ctx.targetPvalue).name(), + DataType.DOUBLE + ); + return child -> new ChangePoint(src, child, value, key, targetType, targetPvalue); + } + private static Tuple parsePolicyName(Token policyToken) { String stringValue = policyToken.getText(); int index = stringValue.indexOf(":"); diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/PlanWritables.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/PlanWritables.java index b3c273cbfa1b..ab2b6b6e0585 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/PlanWritables.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/PlanWritables.java @@ -43,7 +43,6 @@ import org.elasticsearch.xpack.esql.plan.physical.HashJoinExec; import org.elasticsearch.xpack.esql.plan.physical.LimitExec; import org.elasticsearch.xpack.esql.plan.physical.LocalSourceExec; import org.elasticsearch.xpack.esql.plan.physical.MvExpandExec; -import org.elasticsearch.xpack.esql.plan.physical.OrderExec; import org.elasticsearch.xpack.esql.plan.physical.ProjectExec; import org.elasticsearch.xpack.esql.plan.physical.ShowExec; import org.elasticsearch.xpack.esql.plan.physical.SubqueryExec; @@ -57,7 +56,7 @@ public class PlanWritables { public static List getNamedWriteables() { List entries = new ArrayList<>(); entries.addAll(logical()); - entries.addAll(phsyical()); + entries.addAll(physical()); return entries; } @@ -84,7 +83,7 @@ public class PlanWritables { ); } - public static List phsyical() { + public static List physical() { return List.of( AggregateExec.ENTRY, DissectExec.ENTRY, @@ -103,7 +102,6 @@ public class PlanWritables { LimitExec.ENTRY, LocalSourceExec.ENTRY, MvExpandExec.ENTRY, - OrderExec.ENTRY, ProjectExec.ENTRY, ShowExec.ENTRY, SubqueryExec.ENTRY, diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Aggregate.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Aggregate.java index 5c40bfce3206..8cff1d4c88e9 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Aggregate.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Aggregate.java @@ -40,7 +40,7 @@ import static org.elasticsearch.xpack.esql.common.Failure.fail; import static org.elasticsearch.xpack.esql.expression.NamedExpressions.mergeOutputAttributes; import static org.elasticsearch.xpack.esql.plan.logical.Filter.checkFilterConditionDataType; -public class Aggregate extends UnaryPlan implements PostAnalysisVerificationAware, TelemetryAware { +public class Aggregate extends UnaryPlan implements PostAnalysisVerificationAware, TelemetryAware, SortAgnostic { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry( LogicalPlan.class, "Aggregate", diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/ChangePoint.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/ChangePoint.java new file mode 100644 index 000000000000..5814256838b1 --- /dev/null +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/ChangePoint.java @@ -0,0 +1,156 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.plan.logical; + +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.compute.operator.ChangePointOperator; +import org.elasticsearch.xpack.esql.capabilities.PostAnalysisVerificationAware; +import org.elasticsearch.xpack.esql.common.Failures; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.AttributeSet; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.Literal; +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.expression.NamedExpressions; +import org.elasticsearch.xpack.esql.expression.Order; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; + +import static org.elasticsearch.xpack.esql.common.Failure.fail; + +/** + * Plan that detects change points in a list of values. See also: + *
      + *
    • {@link org.elasticsearch.compute.operator.ChangePointOperator} + *
    • {@link org.elasticsearch.xpack.ml.aggs.changepoint.ChangePointDetector} + *
    + * + * ChangePoint should always run on the coordinating node after the data is collected + * in sorted order by key. This is enforced by adding OrderBy in the surrogate plan. + * Furthermore, ChangePoint should be called with at most 1000 data points. That's + * enforced by the Limit in the surrogate plan. + */ +public class ChangePoint extends UnaryPlan implements SurrogateLogicalPlan, PostAnalysisVerificationAware { + + private final Attribute value; + private final Attribute key; + private final Attribute targetType; + private final Attribute targetPvalue; + + private List output; + + public ChangePoint(Source source, LogicalPlan child, Attribute value, Attribute key, Attribute targetType, Attribute targetPvalue) { + super(source, child); + this.value = value; + this.key = key; + this.targetType = targetType; + this.targetPvalue = targetPvalue; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + throw new UnsupportedOperationException("not serialized"); + } + + @Override + public String getWriteableName() { + throw new UnsupportedOperationException("not serialized"); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, ChangePoint::new, child(), value, key, targetType, targetPvalue); + } + + @Override + public UnaryPlan replaceChild(LogicalPlan newChild) { + return new ChangePoint(source(), newChild, value, key, targetType, targetPvalue); + } + + @Override + public List output() { + if (output == null) { + output = NamedExpressions.mergeOutputAttributes(List.of(targetType, targetPvalue), child().output()); + } + return output; + } + + public Attribute value() { + return value; + } + + public Attribute key() { + return key; + } + + public Attribute targetType() { + return targetType; + } + + public Attribute targetPvalue() { + return targetPvalue; + } + + @Override + protected AttributeSet computeReferences() { + return Expressions.references(List.of(key, value)); + } + + @Override + public boolean expressionsResolved() { + return value.resolved() && key.resolved(); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), value, key, targetType, targetPvalue); + } + + @Override + public boolean equals(Object other) { + return super.equals(other) + && Objects.equals(value, ((ChangePoint) other).value) + && Objects.equals(key, ((ChangePoint) other).key) + && Objects.equals(targetType, ((ChangePoint) other).targetType) + && Objects.equals(targetPvalue, ((ChangePoint) other).targetPvalue); + } + + private Order order() { + return new Order(source(), key, Order.OrderDirection.ASC, Order.NullsPosition.ANY); + } + + @Override + public LogicalPlan surrogate() { + OrderBy orderBy = new OrderBy(source(), child(), List.of(order())); + // The first Limit of N+1 data points is necessary to generate a possible warning, + Limit limit = new Limit( + source(), + new Literal(Source.EMPTY, ChangePointOperator.INPUT_VALUE_COUNT_LIMIT + 1, DataType.INTEGER), + orderBy + ); + ChangePoint changePoint = new ChangePoint(source(), limit, value, key, targetType, targetPvalue); + // The second Limit of N data points is to truncate the output. + return new Limit(source(), new Literal(Source.EMPTY, ChangePointOperator.INPUT_VALUE_COUNT_LIMIT, DataType.INTEGER), changePoint); + } + + @Override + public void postAnalysisVerification(Failures failures) { + // Key must be sortable + Order order = order(); + if (DataType.isSortable(order.dataType()) == false) { + failures.add(fail(this, "change point key [" + key.name() + "] must be sortable")); + } + // Value must be a number + if (value.dataType().isNumeric() == false) { + failures.add(fail(this, "change point value [" + value.name() + "] must be numeric")); + } + } +} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Drop.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Drop.java index 483c3508013a..c8668f58ab5c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Drop.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Drop.java @@ -17,7 +17,7 @@ import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; -public class Drop extends UnaryPlan implements TelemetryAware { +public class Drop extends UnaryPlan implements TelemetryAware, SortAgnostic { private final List removals; public Drop(Source source, LogicalPlan child, List removals) { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java index 4e9fc8731802..11e9a57064e5 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java @@ -49,7 +49,7 @@ import static org.elasticsearch.xpack.esql.common.Failure.fail; import static org.elasticsearch.xpack.esql.core.expression.Expressions.asAttributes; import static org.elasticsearch.xpack.esql.expression.NamedExpressions.mergeOutputAttributes; -public class Enrich extends UnaryPlan implements GeneratingPlan, PostAnalysisPlanVerificationAware, TelemetryAware { +public class Enrich extends UnaryPlan implements GeneratingPlan, PostAnalysisPlanVerificationAware, TelemetryAware, SortAgnostic { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry( LogicalPlan.class, "Enrich", diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Eval.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Eval.java index 7c437dac0340..af81e26d57c6 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Eval.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Eval.java @@ -38,7 +38,7 @@ import static org.elasticsearch.xpack.esql.common.Failure.fail; import static org.elasticsearch.xpack.esql.core.expression.Expressions.asAttributes; import static org.elasticsearch.xpack.esql.expression.NamedExpressions.mergeOutputAttributes; -public class Eval extends UnaryPlan implements GeneratingPlan, PostAnalysisVerificationAware, TelemetryAware { +public class Eval extends UnaryPlan implements GeneratingPlan, PostAnalysisVerificationAware, TelemetryAware, SortAgnostic { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(LogicalPlan.class, "Eval", Eval::new); private final List fields; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Filter.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Filter.java index 6931c320007f..7a1726ea59e9 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Filter.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Filter.java @@ -29,7 +29,7 @@ import static org.elasticsearch.xpack.esql.core.type.DataType.NULL; * {@code SELECT x FROM y WHERE z ..} the "WHERE" clause is a Filter. A * {@code Filter} has a "condition" Expression that does the filtering. */ -public class Filter extends UnaryPlan implements PostAnalysisVerificationAware, TelemetryAware { +public class Filter extends UnaryPlan implements PostAnalysisVerificationAware, TelemetryAware, SortAgnostic { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(LogicalPlan.class, "Filter", Filter::new); private final Expression condition; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/InlineStats.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/InlineStats.java index 527ba28d377f..724aa2da2598 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/InlineStats.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/InlineStats.java @@ -37,7 +37,7 @@ import static org.elasticsearch.xpack.esql.expression.NamedExpressions.mergeOutp * underlying aggregate. *

    */ -public class InlineStats extends UnaryPlan implements NamedWriteable, SurrogateLogicalPlan, TelemetryAware { +public class InlineStats extends UnaryPlan implements NamedWriteable, SurrogateLogicalPlan, TelemetryAware, SortAgnostic { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry( LogicalPlan.class, "InlineStats", diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Keep.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Keep.java index 67108afb9466..268c6bbe1724 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Keep.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Keep.java @@ -15,7 +15,7 @@ import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; -public class Keep extends Project implements TelemetryAware { +public class Keep extends Project implements TelemetryAware, SortAgnostic { public Keep(Source source, LogicalPlan child, List projections) { super(source, child, projections); diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Lookup.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Lookup.java index 1c05ceb12452..56dae7b1f16c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Lookup.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Lookup.java @@ -32,7 +32,7 @@ import java.util.Objects; * Looks up values from the associated {@code tables}. * The class is supposed to be substituted by a {@link Join}. */ -public class Lookup extends UnaryPlan implements SurrogateLogicalPlan, TelemetryAware { +public class Lookup extends UnaryPlan implements SurrogateLogicalPlan, TelemetryAware, SortAgnostic { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(LogicalPlan.class, "Lookup", Lookup::new); private final Expression tableName; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/MvExpand.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/MvExpand.java index e700ad90afda..f65811fc2652 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/MvExpand.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/MvExpand.java @@ -23,7 +23,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; -public class MvExpand extends UnaryPlan implements TelemetryAware { +public class MvExpand extends UnaryPlan implements TelemetryAware, SortAgnostic { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(LogicalPlan.class, "MvExpand", MvExpand::new); private final NamedExpression target; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/OrderBy.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/OrderBy.java index 051e2c7769bd..ddb07e0490db 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/OrderBy.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/OrderBy.java @@ -10,6 +10,7 @@ import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.xpack.esql.capabilities.PostAnalysisVerificationAware; +import org.elasticsearch.xpack.esql.capabilities.PostOptimizationVerificationAware; import org.elasticsearch.xpack.esql.capabilities.TelemetryAware; import org.elasticsearch.xpack.esql.common.Failures; import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; @@ -25,7 +26,12 @@ import java.util.Objects; import static org.elasticsearch.xpack.esql.common.Failure.fail; -public class OrderBy extends UnaryPlan implements PostAnalysisVerificationAware, TelemetryAware { +public class OrderBy extends UnaryPlan + implements + PostAnalysisVerificationAware, + PostOptimizationVerificationAware, + TelemetryAware, + SortAgnostic { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(LogicalPlan.class, "OrderBy", OrderBy::new); private final List order; @@ -109,4 +115,9 @@ public class OrderBy extends UnaryPlan implements PostAnalysisVerificationAware, } }); } + + @Override + public void postOptimizationVerification(Failures failures) { + failures.add(fail(this, "Unbounded sort not supported yet [{}] please add a limit", this.sourceText())); + } } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Project.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Project.java index e12a8cb557fd..a36341f60525 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Project.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Project.java @@ -25,7 +25,7 @@ import java.util.Objects; /** * A {@code Project} is a {@code Plan} with one child. In {@code SELECT x FROM y}, the "SELECT" statement is a Project. */ -public class Project extends UnaryPlan { +public class Project extends UnaryPlan implements SortAgnostic { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(LogicalPlan.class, "Project", Project::new); private final List projections; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/RegexExtract.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/RegexExtract.java index d691507b62cb..f111b5d03edb 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/RegexExtract.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/RegexExtract.java @@ -24,7 +24,7 @@ import java.util.Objects; import static org.elasticsearch.xpack.esql.common.Failure.fail; import static org.elasticsearch.xpack.esql.expression.NamedExpressions.mergeOutputAttributes; -public abstract class RegexExtract extends UnaryPlan implements GeneratingPlan, PostAnalysisVerificationAware { +public abstract class RegexExtract extends UnaryPlan implements GeneratingPlan, PostAnalysisVerificationAware, SortAgnostic { protected final Expression input; protected final List extractedFields; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Rename.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Rename.java index 7887d8ed66b9..c609bfdae87e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Rename.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Rename.java @@ -21,7 +21,7 @@ import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute; import java.util.List; import java.util.Objects; -public class Rename extends UnaryPlan implements TelemetryAware { +public class Rename extends UnaryPlan implements TelemetryAware, SortAgnostic { private final List renamings; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/SortAgnostic.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/SortAgnostic.java new file mode 100644 index 000000000000..3955b542ca49 --- /dev/null +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/SortAgnostic.java @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.plan.logical; + +/** + * This interface is intended to check redundancy of a previous SORT. + *

    + * + * An example is with commands that compute values record by record, regardless of the input order + * and that don't rely on the context (intended as previous/next records). + * + *


    + *

    + * + * Example 1: if a MY_COMMAND that implements this interface is used between two sorts, + * then we can assume that + *

    + * + * | SORT x, y, z | MY_COMMAND | SORT a, b, c + * + *

    + * is equivalent to + *

    + * + * | MY_COMMAND | SORT a, b, c + * + * + *


    + *

    + * + * Example 2: commands that make previous order irrelevant, eg. because they collapse the results; + * STATS is one of them, eg. + * + *

    + * + * | SORT x, y, z | STATS count(*) + * + *

    + * is equivalent to + *

    + * + * | STATS count(*) + * + *

    + * + * and if MY_COMMAND implements this interface, then + * + *

    + * + * | SORT x, y, z | MY_COMMAND | STATS count(*) + * + *

    + * is equivalent to + *

    + * + * | MY_COMMAND | STATS count(*) + * + * + *


    + *

    + * + * In all the other cases, eg. if the command does not implement this interface + * then we assume that the previous SORT is still relevant and cannot be pruned. + * + *


    + *

    + * + * Eg. LIMIT does not implement this interface, because + * + *

    + * + * | SORT x, y, z | LIMIT 10 | SORT a, b, c + * + *

    + * is NOT equivalent to + *

    + * + * | LIMIT 10 | SORT a, b, c + * + * + *


    + *

    + * + * For n-ary plans that implement this interface, + * we assume that the above applies to all the children + * + */ +public interface SortAgnostic {} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/join/Join.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/join/Join.java index 997bff70663b..14877abb6227 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/join/Join.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/join/Join.java @@ -21,6 +21,7 @@ import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput; import org.elasticsearch.xpack.esql.plan.logical.BinaryPlan; import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.plan.logical.SortAgnostic; import java.io.IOException; import java.util.ArrayList; @@ -32,7 +33,7 @@ import static org.elasticsearch.xpack.esql.core.type.DataType.TEXT; import static org.elasticsearch.xpack.esql.expression.NamedExpressions.mergeOutputAttributes; import static org.elasticsearch.xpack.esql.plan.logical.join.JoinTypes.LEFT; -public class Join extends BinaryPlan implements PostAnalysisVerificationAware { +public class Join extends BinaryPlan implements PostAnalysisVerificationAware, SortAgnostic { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(LogicalPlan.class, "Join", Join::new); private final JoinConfig config; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ChangePointExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ChangePointExec.java new file mode 100644 index 000000000000..b0ce1be86990 --- /dev/null +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ChangePointExec.java @@ -0,0 +1,107 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.plan.physical; + +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.AttributeSet; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.expression.NamedExpressions; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; + +public class ChangePointExec extends UnaryExec { + + private final Attribute value; + private final Attribute key; + private final Attribute targetType; + private final Attribute targetPvalue; + + private List output; + + public ChangePointExec( + Source source, + PhysicalPlan child, + Attribute value, + Attribute key, + Attribute targetType, + Attribute targetPvalue + ) { + super(source, child); + this.value = value; + this.key = key; + this.targetType = targetType; + this.targetPvalue = targetPvalue; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + throw new UnsupportedOperationException("not serialized"); + } + + @Override + public String getWriteableName() { + throw new UnsupportedOperationException("not serialized"); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, ChangePointExec::new, child(), value, key, targetType, targetPvalue); + } + + @Override + public ChangePointExec replaceChild(PhysicalPlan newChild) { + return new ChangePointExec(source(), newChild, value, key, targetType, targetPvalue); + } + + @Override + protected AttributeSet computeReferences() { + return key.references().combine(value.references()); + } + + @Override + public List output() { + if (output == null) { + output = NamedExpressions.mergeOutputAttributes(List.of(targetType, targetPvalue), child().output()); + } + return output; + } + + public Attribute value() { + return value; + } + + public Attribute key() { + return key; + } + + public Attribute targetType() { + return targetType; + } + + public Attribute targetPvalue() { + return targetPvalue; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), value, key, targetType, targetPvalue); + } + + @Override + public boolean equals(Object other) { + return super.equals(other) + && Objects.equals(value, ((ChangePointExec) other).value) + && Objects.equals(key, ((ChangePointExec) other).key) + && Objects.equals(targetType, ((ChangePointExec) other).targetType) + && Objects.equals(targetPvalue, ((ChangePointExec) other).targetPvalue); + } +} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/OrderExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/OrderExec.java deleted file mode 100644 index 9d53e828f4f8..000000000000 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/OrderExec.java +++ /dev/null @@ -1,88 +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.plan.physical; - -import org.elasticsearch.common.io.stream.NamedWriteableRegistry; -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.xpack.esql.core.tree.NodeInfo; -import org.elasticsearch.xpack.esql.core.tree.Source; -import org.elasticsearch.xpack.esql.expression.Order; -import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput; - -import java.io.IOException; -import java.util.List; -import java.util.Objects; - -public class OrderExec extends UnaryExec { - public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry( - PhysicalPlan.class, - "OrderExec", - OrderExec::new - ); - - private final List order; - - public OrderExec(Source source, PhysicalPlan child, List order) { - super(source, child); - this.order = order; - } - - private OrderExec(StreamInput in) throws IOException { - this( - Source.readFrom((PlanStreamInput) in), - in.readNamedWriteable(PhysicalPlan.class), - in.readCollectionAsList(org.elasticsearch.xpack.esql.expression.Order::new) - ); - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - Source.EMPTY.writeTo(out); - out.writeNamedWriteable(child()); - out.writeCollection(order()); - } - - @Override - public String getWriteableName() { - return ENTRY.name; - } - - @Override - protected NodeInfo info() { - return NodeInfo.create(this, OrderExec::new, child(), order); - } - - @Override - public OrderExec replaceChild(PhysicalPlan newChild) { - return new OrderExec(source(), newChild, order); - } - - public List order() { - return order; - } - - @Override - public int hashCode() { - return Objects.hash(order, child()); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - - OrderExec other = (OrderExec) obj; - - return Objects.equals(order, other.order) && Objects.equals(child(), other.child()); - } -} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AbstractPhysicalOperationProviders.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AbstractPhysicalOperationProviders.java index 072bae21da2a..8fb51457b6a8 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AbstractPhysicalOperationProviders.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AbstractPhysicalOperationProviders.java @@ -95,7 +95,7 @@ public abstract class AbstractPhysicalOperationProviders implements PhysicalOper aggregatorMode, sourceLayout, false, // non-grouping - s -> aggregatorFactories.add(s.supplier.aggregatorFactory(s.mode)) + s -> aggregatorFactories.add(s.supplier.aggregatorFactory(s.mode, s.channels)) ); if (aggregatorFactories.isEmpty() == false) { @@ -169,7 +169,7 @@ public abstract class AbstractPhysicalOperationProviders implements PhysicalOper aggregatorMode, sourceLayout, true, // grouping - s -> aggregatorFactories.add(s.supplier.groupingAggregatorFactory(s.mode)) + s -> aggregatorFactories.add(s.supplier.groupingAggregatorFactory(s.mode, s.channels)) ); if (groupSpecs.size() == 1 && groupSpecs.get(0).channel == null) { @@ -251,7 +251,7 @@ public abstract class AbstractPhysicalOperationProviders implements PhysicalOper return attrs; } - private record AggFunctionSupplierContext(AggregatorFunctionSupplier supplier, AggregatorMode mode) {} + private record AggFunctionSupplierContext(AggregatorFunctionSupplier supplier, List channels, AggregatorMode mode) {} private void aggregatesToFactory( @@ -308,11 +308,12 @@ public abstract class AbstractPhysicalOperationProviders implements PhysicalOper } else { throw new EsqlIllegalArgumentException("illegal aggregation mode"); } + + AggregatorFunctionSupplier aggSupplier = supplier(aggregateFunction); + List inputChannels = sourceAttr.stream().map(attr -> layout.get(attr.id()).channel()).toList(); assert inputChannels.stream().allMatch(i -> i >= 0) : inputChannels; - AggregatorFunctionSupplier aggSupplier = supplier(aggregateFunction, inputChannels); - // apply the filter only in the initial phase - as the rest of the data is already filtered if (aggregateFunction.hasFilter() && mode.isInputPartial() == false) { EvalOperator.ExpressionEvaluator.Factory evalFactory = EvalMapper.toEvaluator( @@ -322,15 +323,15 @@ public abstract class AbstractPhysicalOperationProviders implements PhysicalOper ); aggSupplier = new FilteredAggregatorFunctionSupplier(aggSupplier, evalFactory); } - consumer.accept(new AggFunctionSupplierContext(aggSupplier, mode)); + consumer.accept(new AggFunctionSupplierContext(aggSupplier, inputChannels, mode)); } } } } - private static AggregatorFunctionSupplier supplier(AggregateFunction aggregateFunction, List inputChannels) { + private static AggregatorFunctionSupplier supplier(AggregateFunction aggregateFunction) { if (aggregateFunction instanceof ToAggregator delegate) { - return delegate.supplier(inputChannels); + return delegate.supplier(); } throw new EsqlIllegalArgumentException("aggregate functions must extend ToAggregator"); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AggregateMapper.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AggregateMapper.java index 56ab4652bd48..505d87d10196 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AggregateMapper.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AggregateMapper.java @@ -10,7 +10,6 @@ package org.elasticsearch.xpack.esql.planner; import org.elasticsearch.common.Strings; import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.data.ElementType; -import org.elasticsearch.core.Tuple; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; import org.elasticsearch.xpack.esql.core.expression.Alias; import org.elasticsearch.xpack.esql.core.expression.Attribute; @@ -20,89 +19,20 @@ import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute; import org.elasticsearch.xpack.esql.core.expression.NamedExpression; import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; -import org.elasticsearch.xpack.esql.core.expression.function.Function; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.aggregate.AggregateFunction; -import org.elasticsearch.xpack.esql.expression.function.aggregate.Count; -import org.elasticsearch.xpack.esql.expression.function.aggregate.CountDistinct; -import org.elasticsearch.xpack.esql.expression.function.aggregate.FromPartial; -import org.elasticsearch.xpack.esql.expression.function.aggregate.Max; -import org.elasticsearch.xpack.esql.expression.function.aggregate.MedianAbsoluteDeviation; -import org.elasticsearch.xpack.esql.expression.function.aggregate.Min; -import org.elasticsearch.xpack.esql.expression.function.aggregate.NumericAggregate; -import org.elasticsearch.xpack.esql.expression.function.aggregate.Percentile; -import org.elasticsearch.xpack.esql.expression.function.aggregate.Rate; -import org.elasticsearch.xpack.esql.expression.function.aggregate.SpatialAggregateFunction; -import org.elasticsearch.xpack.esql.expression.function.aggregate.SpatialCentroid; -import org.elasticsearch.xpack.esql.expression.function.aggregate.SpatialExtent; -import org.elasticsearch.xpack.esql.expression.function.aggregate.StdDev; -import org.elasticsearch.xpack.esql.expression.function.aggregate.Sum; -import org.elasticsearch.xpack.esql.expression.function.aggregate.ToPartial; -import org.elasticsearch.xpack.esql.expression.function.aggregate.Top; -import org.elasticsearch.xpack.esql.expression.function.aggregate.Values; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; import java.util.stream.Stream; /** * Static class used to convert aggregate expressions to the named expressions that represent their intermediate state. - *

    - * At class load time, the mapper is populated with all supported aggregate functions and their intermediate state. - *

    - *

    - * Reflection is used to call the {@code intermediateStateDesc()}` static method of the aggregate functions, - * but the function classes are found based on the exising information within this class. - *

    - *

    - * This class must be updated when aggregations are created or updated, by adding the new aggs or types to the corresponding methods. - *

    */ final class AggregateMapper { - private static final List NUMERIC = List.of("Int", "Long", "Double"); - private static final List SPATIAL_EXTRA_CONFIGS = List.of("SourceValues", "DocValues"); - - /** List of all mappable ESQL agg functions (excludes surrogates like AVG = SUM/COUNT). */ - private static final List> AGG_FUNCTIONS = List.of( - Count.class, - CountDistinct.class, - Max.class, - MedianAbsoluteDeviation.class, - Min.class, - Percentile.class, - SpatialCentroid.class, - SpatialExtent.class, - StdDev.class, - Sum.class, - Values.class, - Top.class, - Rate.class, - - // internal function - FromPartial.class, - ToPartial.class - ); - - /** Record of agg Class, type, and grouping (or non-grouping). */ - private record AggDef(Class aggClazz, String type, String extra, boolean grouping) { - public AggDef withoutExtra() { - return new AggDef(aggClazz, type, "", grouping); - } - } - - /** Map of AggDef types to intermediate named expressions. */ - private static final Map> MAPPER = AGG_FUNCTIONS.stream() - .flatMap(AggregateMapper::aggDefs) - .collect(Collectors.toUnmodifiableMap(aggDef -> aggDef, AggregateMapper::lookupIntermediateState)); - + // TODO: Do we need this cache? /** Cache of aggregates to intermediate expressions. */ private final HashMap> cache = new HashMap<>(); @@ -144,127 +74,21 @@ final class AggregateMapper { } private static List entryForAgg(String aggAlias, AggregateFunction aggregateFunction, boolean grouping) { - var aggDef = new AggDef( - aggregateFunction.getClass(), - dataTypeToString(aggregateFunction.field().dataType(), aggregateFunction.getClass()), - aggregateFunction instanceof SpatialAggregateFunction ? "SourceValues" : "", - grouping - ); - var is = getNonNull(aggDef); - return isToNE(is, aggAlias).toList(); - } - - /** Gets the agg from the mapper - wrapper around map::get for more informative failure.*/ - private static List getNonNull(AggDef aggDef) { - var l = MAPPER.getOrDefault(aggDef, MAPPER.get(aggDef.withoutExtra())); - if (l == null) { - throw new EsqlIllegalArgumentException("Cannot find intermediate state for: " + aggDef); - } - return l; - } - - private static Stream aggDefs(Class clazz) { - List types; - List extraConfigs = List.of(""); - if (NumericAggregate.class.isAssignableFrom(clazz)) { - types = NUMERIC; - } else if (Max.class.isAssignableFrom(clazz) || Min.class.isAssignableFrom(clazz)) { - types = List.of("Boolean", "Int", "Long", "Double", "Ip", "BytesRef"); - } else if (clazz == Count.class) { - types = List.of(""); // no extra type distinction - } else if (clazz == SpatialCentroid.class) { - types = List.of("GeoPoint", "CartesianPoint"); - extraConfigs = SPATIAL_EXTRA_CONFIGS; - } else if (clazz == SpatialExtent.class) { - types = List.of("GeoPoint", "CartesianPoint", "GeoShape", "CartesianShape"); - extraConfigs = SPATIAL_EXTRA_CONFIGS; - } else if (Values.class.isAssignableFrom(clazz)) { - // TODO can't we figure this out from the function itself? - types = List.of("Int", "Long", "Double", "Boolean", "BytesRef"); - } else if (Top.class.isAssignableFrom(clazz)) { - types = List.of("Boolean", "Int", "Long", "Double", "Ip", "BytesRef"); - } else if (Rate.class.isAssignableFrom(clazz) || StdDev.class.isAssignableFrom(clazz)) { - types = List.of("Int", "Long", "Double"); - } else if (FromPartial.class.isAssignableFrom(clazz) || ToPartial.class.isAssignableFrom(clazz)) { - types = List.of(""); // no type - } else if (CountDistinct.class.isAssignableFrom(clazz)) { - types = Stream.concat(NUMERIC.stream(), Stream.of("Boolean", "BytesRef")).toList(); + List intermediateState; + if (aggregateFunction instanceof ToAggregator toAggregator) { + var supplier = toAggregator.supplier(); + intermediateState = grouping ? supplier.groupingIntermediateStateDesc() : supplier.nonGroupingIntermediateStateDesc(); } else { - assert false : "unknown aggregate type " + clazz; - throw new IllegalArgumentException("unknown aggregate type " + clazz); + throw new EsqlIllegalArgumentException("Aggregate has no defined intermediate state: " + aggregateFunction); } - return combinations(types, extraConfigs).flatMap(typeAndExtraConfig -> { - var type = typeAndExtraConfig.v1(); - var extra = typeAndExtraConfig.v2(); - - if (clazz.isAssignableFrom(Rate.class)) { - // rate doesn't support non-grouping aggregations - return Stream.of(new AggDef(clazz, type, extra, true)); - } else if (Objects.equals(type, "AggregateMetricDouble")) { - // TODO: support grouping aggregations for aggregate metric double - return Stream.of(new AggDef(clazz, type, extra, false)); - } else { - return Stream.of(new AggDef(clazz, type, extra, true), new AggDef(clazz, type, extra, false)); - } - }); - } - - private static Stream> combinations(List types, List extraConfigs) { - return types.stream().flatMap(type -> extraConfigs.stream().map(config -> new Tuple<>(type, config))); - } - - /** Retrieves the intermediate state description for a given class, type, and grouping. */ - private static List lookupIntermediateState(AggDef aggDef) { - try { - return (List) lookup(aggDef.aggClazz(), aggDef.type(), aggDef.extra(), aggDef.grouping()).invokeExact(); - } catch (Throwable t) { - // invokeExact forces us to handle any Throwable thrown by lookup. - throw new EsqlIllegalArgumentException(t); - } - } - - /** Looks up the intermediate state method for a given class, type, and grouping. */ - private static MethodHandle lookup(Class clazz, String type, String extra, boolean grouping) { - try { - return lookupRetry(clazz, type, extra, grouping); - } catch (IllegalAccessException | NoSuchMethodException | ClassNotFoundException e) { - throw new EsqlIllegalArgumentException(e); - } - } - - private static MethodHandle lookupRetry(Class clazz, String type, String extra, boolean grouping) throws IllegalAccessException, - NoSuchMethodException, ClassNotFoundException { - try { - return MethodHandles.lookup() - .findStatic( - Class.forName(determineAggName(clazz, type, extra, grouping)), - "intermediateStateDesc", - MethodType.methodType(List.class) - ); - } catch (NoSuchMethodException ignore) { - // Retry without the extra information. - return MethodHandles.lookup() - .findStatic( - Class.forName(determineAggName(clazz, type, "", grouping)), - "intermediateStateDesc", - MethodType.methodType(List.class) - ); - } - } - - /** Determines the engines agg class name, for the given class, type, and grouping. */ - private static String determineAggName(Class clazz, String type, String extra, boolean grouping) { - return "org.elasticsearch.compute.aggregation." - + (clazz.getSimpleName().startsWith("Spatial") ? "spatial." : "") - + clazz.getSimpleName() - + type - + extra - + (grouping ? "Grouping" : "") - + "AggregatorFunction"; + return intermediateStateToNamedExpressions(intermediateState, aggAlias).toList(); } /** Maps intermediate state description to named expressions. */ - private static Stream isToNE(List intermediateStateDescs, String aggAlias) { + private static Stream intermediateStateToNamedExpressions( + List intermediateStateDescs, + String aggAlias + ) { return intermediateStateDescs.stream().map(is -> { final DataType dataType; if (Strings.isEmpty(is.dataType())) { @@ -288,34 +112,4 @@ final class AggregateMapper { case FLOAT, NULL, DOC, COMPOSITE, UNKNOWN -> throw new EsqlIllegalArgumentException("unsupported agg type: " + elementType); }; } - - /** Returns the string representation for the data type. This reflects the engine's aggs naming structure. */ - private static String dataTypeToString(DataType type, Class aggClass) { - if (aggClass == Count.class) { - return ""; // no type distinction - } - if (aggClass == ToPartial.class || aggClass == FromPartial.class) { - return ""; - } - if ((aggClass == Max.class || aggClass == Min.class || aggClass == Top.class) && type.equals(DataType.IP)) { - return "Ip"; - } - - return switch (type) { - case BOOLEAN -> "Boolean"; - case INTEGER, COUNTER_INTEGER -> "Int"; - case LONG, DATETIME, COUNTER_LONG, DATE_NANOS -> "Long"; - case DOUBLE, COUNTER_DOUBLE -> "Double"; - case KEYWORD, IP, VERSION, TEXT, SEMANTIC_TEXT -> "BytesRef"; - case GEO_POINT -> "GeoPoint"; - case CARTESIAN_POINT -> "CartesianPoint"; - case GEO_SHAPE -> "GeoShape"; - case CARTESIAN_SHAPE -> "CartesianShape"; - case AGGREGATE_METRIC_DOUBLE -> "AggregateMetricDouble"; - case UNSUPPORTED, NULL, UNSIGNED_LONG, SHORT, BYTE, FLOAT, HALF_FLOAT, SCALED_FLOAT, OBJECT, SOURCE, DATE_PERIOD, TIME_DURATION, - DOC_DATA_TYPE, TSID_DATA_TYPE, PARTIAL_AGG -> throw new EsqlIllegalArgumentException( - "illegal agg type: " + type.typeName() - ); - }; - } } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlanner.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlanner.java index c4985b029cfc..2d9246cb98e0 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlanner.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlanner.java @@ -17,12 +17,14 @@ import org.elasticsearch.compute.data.ElementType; import org.elasticsearch.compute.data.LocalCircuitBreaker; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.lucene.LuceneOperator; +import org.elasticsearch.compute.operator.ChangePointOperator; import org.elasticsearch.compute.operator.ColumnExtractOperator; import org.elasticsearch.compute.operator.ColumnLoadOperator; import org.elasticsearch.compute.operator.Driver; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator.EvalOperatorFactory; import org.elasticsearch.compute.operator.FilterOperator.FilterOperatorFactory; +import org.elasticsearch.compute.operator.LimitOperator; import org.elasticsearch.compute.operator.LocalSourceOperator; import org.elasticsearch.compute.operator.LocalSourceOperator.LocalSourceFactory; import org.elasticsearch.compute.operator.MvExpandOperator; @@ -71,6 +73,7 @@ import org.elasticsearch.xpack.esql.evaluator.EvalMapper; import org.elasticsearch.xpack.esql.evaluator.command.GrokEvaluatorExtracter; import org.elasticsearch.xpack.esql.expression.Order; import org.elasticsearch.xpack.esql.plan.physical.AggregateExec; +import org.elasticsearch.xpack.esql.plan.physical.ChangePointExec; import org.elasticsearch.xpack.esql.plan.physical.DissectExec; import org.elasticsearch.xpack.esql.plan.physical.EnrichExec; import org.elasticsearch.xpack.esql.plan.physical.EsQueryExec; @@ -110,7 +113,6 @@ import java.util.stream.Stream; import static java.util.Arrays.asList; import static java.util.stream.Collectors.joining; -import static org.elasticsearch.compute.operator.LimitOperator.Factory; import static org.elasticsearch.compute.operator.ProjectOperator.ProjectOperatorFactory; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToInt; @@ -221,6 +223,8 @@ public class LocalExecutionPlanner { return planLimit(limit, context); } else if (node instanceof MvExpandExec mvExpand) { return planMvExpand(mvExpand, context); + } else if (node instanceof ChangePointExec changePoint) { + return planChangePoint(changePoint, context); } // source nodes else if (node instanceof EsQueryExec esQuery) { @@ -684,7 +688,7 @@ public class LocalExecutionPlanner { private PhysicalOperation planLimit(LimitExec limit, LocalExecutionPlannerContext context) { PhysicalOperation source = plan(limit.child(), context); - return source.with(new Factory((Integer) limit.limit().fold(context.foldCtx)), source.layout); + return source.with(new LimitOperator.Factory((Integer) limit.limit().fold(context.foldCtx)), source.layout); } private PhysicalOperation planMvExpand(MvExpandExec mvExpandExec, LocalExecutionPlannerContext context) { @@ -698,6 +702,20 @@ public class LocalExecutionPlanner { ); } + private PhysicalOperation planChangePoint(ChangePointExec changePoint, LocalExecutionPlannerContext context) { + PhysicalOperation source = plan(changePoint.child(), context); + Layout layout = source.layout.builder().append(changePoint.targetType()).append(changePoint.targetPvalue()).build(); + return source.with( + new ChangePointOperator.Factory( + layout.get(changePoint.value().id()).channel(), + changePoint.sourceText(), + changePoint.sourceLocation().getLineNumber(), + changePoint.sourceLocation().getColumnNumber() + ), + layout + ); + } + /** * Immutable physical operation. */ diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/ToAggregator.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/ToAggregator.java index 62bc0a96ab87..053d4bc839f1 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/ToAggregator.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/ToAggregator.java @@ -9,11 +9,9 @@ package org.elasticsearch.xpack.esql.planner; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; -import java.util.List; - /** * Expressions that have a mapping to an {@link AggregatorFunctionSupplier}. */ public interface ToAggregator { - AggregatorFunctionSupplier supplier(List inputChannels); + AggregatorFunctionSupplier supplier(); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/LocalMapper.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/LocalMapper.java index f95ae0e0783e..217737de5309 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/LocalMapper.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/LocalMapper.java @@ -17,7 +17,6 @@ import org.elasticsearch.xpack.esql.plan.logical.EsRelation; import org.elasticsearch.xpack.esql.plan.logical.LeafPlan; import org.elasticsearch.xpack.esql.plan.logical.Limit; import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.esql.plan.logical.OrderBy; import org.elasticsearch.xpack.esql.plan.logical.TopN; import org.elasticsearch.xpack.esql.plan.logical.UnaryPlan; import org.elasticsearch.xpack.esql.plan.logical.join.Join; @@ -28,7 +27,6 @@ import org.elasticsearch.xpack.esql.plan.physical.HashJoinExec; import org.elasticsearch.xpack.esql.plan.physical.LimitExec; import org.elasticsearch.xpack.esql.plan.physical.LocalSourceExec; import org.elasticsearch.xpack.esql.plan.physical.LookupJoinExec; -import org.elasticsearch.xpack.esql.plan.physical.OrderExec; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.esql.plan.physical.TopNExec; @@ -81,10 +79,6 @@ public class LocalMapper { return new LimitExec(limit.source(), mappedChild, limit.limit()); } - if (unary instanceof OrderBy o) { - return new OrderExec(o.source(), mappedChild, o.order()); - } - if (unary instanceof TopN topN) { return new TopNExec(topN.source(), mappedChild, topN.order(), topN.limit(), null); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/Mapper.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/Mapper.java index 8a4325ed84b2..8ea19f545e67 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/Mapper.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/Mapper.java @@ -32,7 +32,6 @@ import org.elasticsearch.xpack.esql.plan.physical.HashJoinExec; import org.elasticsearch.xpack.esql.plan.physical.LimitExec; import org.elasticsearch.xpack.esql.plan.physical.LocalSourceExec; import org.elasticsearch.xpack.esql.plan.physical.LookupJoinExec; -import org.elasticsearch.xpack.esql.plan.physical.OrderExec; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.esql.plan.physical.TopNExec; import org.elasticsearch.xpack.esql.plan.physical.UnaryExec; @@ -105,7 +104,7 @@ public class Mapper { return enrichExec.child(); } if (f instanceof UnaryExec unaryExec) { - if (f instanceof LimitExec || f instanceof ExchangeExec || f instanceof OrderExec || f instanceof TopNExec) { + if (f instanceof LimitExec || f instanceof ExchangeExec || f instanceof TopNExec) { return f; } else { return unaryExec.child(); @@ -161,11 +160,6 @@ public class Mapper { return new LimitExec(limit.source(), mappedChild, limit.limit()); } - if (unary instanceof OrderBy o) { - mappedChild = addExchangeForFragment(o, mappedChild); - return new OrderExec(o.source(), mappedChild, o.order()); - } - if (unary instanceof TopN topN) { mappedChild = addExchangeForFragment(topN, mappedChild); return new TopNExec(topN.source(), mappedChild, topN.order(), topN.limit(), null); diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/MapperUtils.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/MapperUtils.java index f358a77a08ae..a71c491a0347 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/MapperUtils.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/MapperUtils.java @@ -13,6 +13,7 @@ import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; import org.elasticsearch.xpack.esql.core.expression.Attribute; import org.elasticsearch.xpack.esql.core.expression.FoldContext; import org.elasticsearch.xpack.esql.plan.logical.Aggregate; +import org.elasticsearch.xpack.esql.plan.logical.ChangePoint; import org.elasticsearch.xpack.esql.plan.logical.Dissect; import org.elasticsearch.xpack.esql.plan.logical.Enrich; import org.elasticsearch.xpack.esql.plan.logical.Eval; @@ -26,6 +27,7 @@ import org.elasticsearch.xpack.esql.plan.logical.UnaryPlan; import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation; import org.elasticsearch.xpack.esql.plan.logical.show.ShowInfo; import org.elasticsearch.xpack.esql.plan.physical.AggregateExec; +import org.elasticsearch.xpack.esql.plan.physical.ChangePointExec; import org.elasticsearch.xpack.esql.plan.physical.DissectExec; import org.elasticsearch.xpack.esql.plan.physical.EnrichExec; import org.elasticsearch.xpack.esql.plan.physical.EvalExec; @@ -98,6 +100,17 @@ class MapperUtils { return new MvExpandExec(mvExpand.source(), child, mvExpand.target(), mvExpand.expanded()); } + if (p instanceof ChangePoint changePoint) { + return new ChangePointExec( + changePoint.source(), + child, + changePoint.value(), + changePoint.key(), + changePoint.targetType(), + changePoint.targetPvalue() + ); + } + return unsupported(p); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestSender.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestSender.java index 6af2c12ace08..8c2a6bb06da9 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestSender.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestSender.java @@ -34,7 +34,9 @@ import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.esql.action.EsqlSearchShardsAction; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -58,6 +60,7 @@ abstract class DataNodeRequestSender { private final Map nodePermits = new HashMap<>(); private final Map shardFailures = ConcurrentCollections.newConcurrentMap(); private final AtomicBoolean changed = new AtomicBoolean(); + private boolean reportedFailure = false; // guarded by sendingLock DataNodeRequestSender(TransportService transportService, Executor esqlExecutor, CancellableTask rootTask) { this.transportService = transportService; @@ -117,11 +120,14 @@ abstract class DataNodeRequestSender { ); } } - if (shardFailures.values().stream().anyMatch(shardFailure -> shardFailure.fatal)) { - for (var e : shardFailures.values()) { - computeListener.acquireAvoid().onFailure(e.failure); - } + if (reportedFailure || shardFailures.values().stream().anyMatch(shardFailure -> shardFailure.fatal)) { + reportedFailure = true; + reportFailures(computeListener); } else { + pendingShardIds.removeIf(shr -> { + var failure = shardFailures.get(shr); + return failure != null && failure.fatal; + }); var nodeRequests = selectNodeRequests(targetShards); for (NodeRequest request : nodeRequests) { sendOneNodeRequest(targetShards, computeListener, request); @@ -136,6 +142,20 @@ abstract class DataNodeRequestSender { } } + private void reportFailures(ComputeListener computeListener) { + assert sendingLock.isHeldByCurrentThread(); + assert reportedFailure; + Iterator it = shardFailures.values().iterator(); + Set seen = Collections.newSetFromMap(new IdentityHashMap<>()); + while (it.hasNext()) { + ShardFailure failure = it.next(); + if (seen.add(failure.failure)) { + computeListener.acquireAvoid().onFailure(failure.failure); + } + it.remove(); + } + } + private void sendOneNodeRequest(TargetShards targetShards, ComputeListener computeListener, NodeRequest request) { final ActionListener> listener = computeListener.acquireCompute(); sendRequest(request.node, request.shardIds, request.aliasFilters, new NodeListener() { @@ -148,7 +168,7 @@ abstract class DataNodeRequestSender { @Override public void onResponse(DataNodeComputeResponse response) { // remove failures of successful shards - for (ShardId shardId : targetShards.shardIds()) { + for (ShardId shardId : request.shardIds()) { if (response.shardLevelFailures().containsKey(shardId) == false) { shardFailures.remove(shardId); } @@ -250,6 +270,7 @@ abstract class DataNodeRequestSender { final Iterator shardsIt = pendingShardIds.iterator(); while (shardsIt.hasNext()) { ShardId shardId = shardsIt.next(); + assert shardFailures.get(shardId) == null || shardFailures.get(shardId).fatal == false; TargetShard shard = targetShards.getShard(shardId); Iterator nodesIt = shard.remainingNodes.iterator(); DiscoveryNode selectedNode = null; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlAsyncStopAction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlAsyncStopAction.java index a4007a520ed3..f5f51029ae8a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlAsyncStopAction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlAsyncStopAction.java @@ -7,7 +7,8 @@ package org.elasticsearch.xpack.esql.plugin; -import org.elasticsearch.ResourceNotFoundException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListenerResponseHandler; import org.elasticsearch.action.support.ActionFilters; @@ -16,10 +17,8 @@ import org.elasticsearch.client.internal.Client; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.util.concurrent.EsExecutors; -import org.elasticsearch.compute.EsqlRefCountingListener; import org.elasticsearch.compute.data.BlockFactory; import org.elasticsearch.compute.operator.exchange.ExchangeService; -import org.elasticsearch.core.TimeValue; import org.elasticsearch.injection.guice.Inject; import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.TaskId; @@ -32,12 +31,11 @@ import org.elasticsearch.xpack.core.async.AsyncTaskIndexService; import org.elasticsearch.xpack.core.async.GetAsyncResultRequest; import org.elasticsearch.xpack.core.security.SecurityContext; import org.elasticsearch.xpack.esql.action.EsqlAsyncStopAction; +import org.elasticsearch.xpack.esql.action.EsqlExecutionInfo; import org.elasticsearch.xpack.esql.action.EsqlQueryResponse; import org.elasticsearch.xpack.esql.action.EsqlQueryTask; import java.io.IOException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; import static org.elasticsearch.xpack.core.ClientHelper.ASYNC_SEARCH_ORIGIN; @@ -55,6 +53,8 @@ public class TransportEsqlAsyncStopAction extends HandledTransportAction listener) { String asyncIdStr = asyncId.getEncoded(); - TransportEsqlQueryAction.EsqlQueryListener asyncListener = queryAction.getAsyncListener(asyncIdStr); - if (asyncListener == null) { + EsqlQueryTask asyncTask = getEsqlQueryTask(asyncId); + GetAsyncResultRequest getAsyncResultRequest = new GetAsyncResultRequest(asyncIdStr); + if (asyncTask == null) { // This should mean one of the two things: either bad request ID, or the query has already finished // In both cases, let regular async get deal with it. - var getAsyncResultRequest = new GetAsyncResultRequest(asyncIdStr); - // TODO: this should not be happening, but if the listener is not registered and the query is not finished, - // we give it some time to finish - getAsyncResultRequest.setWaitForCompletionTimeout(new TimeValue(1, TimeUnit.SECONDS)); + logger.debug("Async stop for task {}, no task present - passing to GetAsyncResultRequest", asyncIdStr); getResultsAction.execute(task, getAsyncResultRequest, listener); return; } - try { - EsqlQueryTask asyncTask = AsyncTaskIndexService.getTask(taskManager, asyncId, EsqlQueryTask.class); - if (false == security.currentUserHasAccessToTask(asyncTask)) { - throw new ResourceNotFoundException(asyncId + " not found"); - } - } catch (IOException e) { - throw new ResourceNotFoundException(asyncId + " not found", e); + logger.debug("Async stop for task {} - stopping", asyncIdStr); + final EsqlExecutionInfo esqlExecutionInfo = asyncTask.executionInfo(); + if (esqlExecutionInfo != null) { + esqlExecutionInfo.markAsPartial(); } - // Here we will wait for both the response to become available and for the finish operation to complete - var responseHolder = new AtomicReference(); - try (var refs = new EsqlRefCountingListener(listener.map(unused -> responseHolder.get()))) { - asyncListener.addListener(refs.acquire().map(r -> { - responseHolder.set(r); - return null; - })); - asyncListener.markAsPartial(); - exchangeService.finishSessionEarly(sessionID(asyncId), refs.acquire()); + Runnable getResults = () -> getResultsAction.execute(task, getAsyncResultRequest, listener); + exchangeService.finishSessionEarly(sessionID(asyncId), ActionListener.running(() -> { + if (asyncTask.addCompletionListener(() -> ActionListener.running(getResults)) == false) { + getResults.run(); + } + })); + } + + private EsqlQueryTask getEsqlQueryTask(AsyncExecutionId asyncId) { + try { + return AsyncTaskIndexService.getTaskAndCheckAuthentication(taskManager, security, asyncId, EsqlQueryTask.class); + } catch (IOException e) { + return null; } } } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java index caf70063e08f..5b0dfa14014a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java @@ -13,14 +13,12 @@ import org.elasticsearch.action.admin.cluster.stats.CCSUsage; import org.elasticsearch.action.admin.cluster.stats.CCSUsageTelemetry; import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.HandledTransportAction; -import org.elasticsearch.action.support.SubscribableListener; import org.elasticsearch.client.internal.Client; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.util.BigArrays; -import org.elasticsearch.common.util.concurrent.ConcurrentCollections; import org.elasticsearch.common.util.concurrent.EsExecutors; import org.elasticsearch.compute.data.BlockFactory; import org.elasticsearch.compute.operator.exchange.ExchangeService; @@ -82,8 +80,6 @@ public class TransportEsqlQueryAction extends HandledTransportAction asyncListeners = ConcurrentCollections.newConcurrentMap(); @Inject @SuppressWarnings("this-escape") @@ -190,41 +186,11 @@ public class TransportEsqlQueryAction extends HandledTransportAction { - private EsqlExecutionInfo executionInfo; - - public EsqlQueryListener(EsqlExecutionInfo executionInfo) { - this.executionInfo = executionInfo; - } - - public EsqlExecutionInfo getExecutionInfo() { - return executionInfo; - } - - public void markAsPartial() { - if (executionInfo != null) { - executionInfo.markAsPartial(); - } - } - } - @Override public void execute(EsqlQueryRequest request, EsqlQueryTask task, ActionListener listener) { // set EsqlExecutionInfo on async-search task so that it is accessible to GET _query/async while the query is still running task.setExecutionInfo(createEsqlExecutionInfo(request)); - // Since the request is async here, we need to wrap the listener in a SubscribableListener so that we can collect the results from - // other endpoints, such as _query/async/stop - EsqlQueryListener subListener = new EsqlQueryListener(task.executionInfo()); - String asyncExecutionId = task.getExecutionId().getEncoded(); - subListener.addListener(ActionListener.runAfter(listener, () -> asyncListeners.remove(asyncExecutionId))); - asyncListeners.put(asyncExecutionId, subListener); - ActionListener.run(subListener, l -> innerExecute(task, request, l)); - } - - public EsqlQueryListener getAsyncListener(String executionId) { - return asyncListeners.get(executionId); + ActionListener.run(listener, l -> innerExecute(task, request, l)); } private void innerExecute(Task task, EsqlQueryRequest request, ActionListener listener) { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlStatsAction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlStatsAction.java index 4067fc5a4e06..4e67bb4f7de5 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlStatsAction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlStatsAction.java @@ -13,7 +13,6 @@ import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.features.FeatureService; import org.elasticsearch.injection.guice.Inject; import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; @@ -34,14 +33,12 @@ public class TransportEsqlStatsAction extends TransportNodesAction< Void> { // the plan executor holds the metrics - private final FeatureService featureService; private final PlanExecutor planExecutor; @Inject public TransportEsqlStatsAction( TransportService transportService, ClusterService clusterService, - FeatureService featureService, ThreadPool threadPool, ActionFilters actionFilters, PlanExecutor planExecutor @@ -54,7 +51,6 @@ public class TransportEsqlStatsAction extends TransportNodesAction< EsqlStatsRequest.NodeStatsRequest::new, threadPool.executor(ThreadPool.Names.MANAGEMENT) ); - this.featureService = featureService; this.planExecutor = planExecutor; } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java index f6988743f738..263c076c2331 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java @@ -74,6 +74,7 @@ import org.elasticsearch.xpack.esql.optimizer.TestLocalPhysicalPlanOptimizer; import org.elasticsearch.xpack.esql.parser.EsqlParser; import org.elasticsearch.xpack.esql.plan.logical.Enrich; import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.plan.physical.ChangePointExec; import org.elasticsearch.xpack.esql.plan.physical.HashJoinExec; import org.elasticsearch.xpack.esql.plan.physical.LocalSourceExec; import org.elasticsearch.xpack.esql.plan.physical.OutputExec; @@ -564,12 +565,9 @@ public class CsvTests extends ESTestCase { // Asserts that the serialization and deserialization of the plan creates an equivalent plan. private void opportunisticallyAssertPlanSerialization(PhysicalPlan plan) { - - // skip plans with localSourceExec - if (plan.anyMatch(p -> p instanceof LocalSourceExec || p instanceof HashJoinExec)) { + if (plan.anyMatch(p -> p instanceof LocalSourceExec || p instanceof HashJoinExec || p instanceof ChangePointExec)) { return; } - SerializationTestUtils.assertSerialization(plan, configuration); } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/IdentifierGenerator.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/IdentifierGenerator.java index 3392ae9b6e3b..df8cacff67f4 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/IdentifierGenerator.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/IdentifierGenerator.java @@ -78,15 +78,16 @@ public class IdentifierGenerator { index.insert(0, "-"); } - var pattern = maybeQuote(index.toString()); - if (canAdd(Features.CROSS_CLUSTER, features)) { - var cluster = randomIdentifier(); - pattern = maybeQuote(cluster + ":" + pattern); - } - - if (pattern.contains("|") && pattern.contains("\"") == false) { + var pattern = index.toString(); + if (pattern.contains("|")) { pattern = quote(pattern); } + pattern = maybeQuote(pattern); + + if (canAdd(Features.CROSS_CLUSTER, features)) { + var cluster = maybeQuote(randomIdentifier()); + pattern = maybeQuote(cluster + ":" + pattern); + } return pattern; } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlQueryRequestTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlQueryRequestTests.java index dcb83dadfcf9..698291a54fa6 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlQueryRequestTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlQueryRequestTests.java @@ -144,10 +144,6 @@ public class EsqlQueryRequestTests extends ESTestCase { } public void testNamedParamsForIdentifiersPatterns() throws IOException { - assumeTrue( - "named parameters for identifiers and patterns require snapshot build", - EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - ); String query = randomAlphaOfLengthBetween(1, 100); boolean columnar = randomBoolean(); Locale locale = randomLocale(random()); @@ -260,10 +256,6 @@ public class EsqlQueryRequestTests extends ESTestCase { } public void testInvalidParamsForIdentifiersPatterns() throws IOException { - assumeTrue( - "named parameters for identifiers and patterns require snapshot build", - EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - ); String query = randomAlphaOfLengthBetween(1, 100); boolean columnar = randomBoolean(); Locale locale = randomLocale(random()); 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 1c288a9bc33f..187c83cd5f24 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 @@ -2344,10 +2344,6 @@ public class AnalyzerTests extends ESTestCase { } public void testNamedParamsForIdentifiers() { - assumeTrue( - "named parameters for identifiers and patterns require snapshot build", - EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - ); assertProjectionWithMapping( """ from test @@ -2438,10 +2434,6 @@ public class AnalyzerTests extends ESTestCase { } public void testInvalidNamedParamsForIdentifiers() { - assumeTrue( - "named parameters for identifiers and patterns require snapshot build", - EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - ); // missing field assertError( """ @@ -2511,10 +2503,6 @@ public class AnalyzerTests extends ESTestCase { } public void testNamedParamsForIdentifierPatterns() { - assumeTrue( - "named parameters for identifiers and patterns require snapshot build", - EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - ); assertProjectionWithMapping( """ from test @@ -2545,10 +2533,6 @@ public class AnalyzerTests extends ESTestCase { } public void testInvalidNamedParamsForIdentifierPatterns() { - assumeTrue( - "named parameters for identifiers and patterns require snapshot build", - EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - ); // missing pattern assertError( """ diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java index e7f2fa1b97fb..8be008be7a81 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java @@ -8,6 +8,7 @@ package org.elasticsearch.xpack.esql.analysis; import org.elasticsearch.Build; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.logging.LoggerMessageFormat; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.esql.VerificationException; @@ -36,11 +37,24 @@ import java.util.Set; import static org.elasticsearch.xpack.esql.EsqlTestUtils.paramAsConstant; import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning; import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.loadMapping; +import static org.elasticsearch.xpack.esql.core.type.DataType.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataType.CARTESIAN_POINT; +import static org.elasticsearch.xpack.esql.core.type.DataType.CARTESIAN_SHAPE; import static org.elasticsearch.xpack.esql.core.type.DataType.COUNTER_DOUBLE; import static org.elasticsearch.xpack.esql.core.type.DataType.COUNTER_INTEGER; import static org.elasticsearch.xpack.esql.core.type.DataType.COUNTER_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataType.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataType.DATE_NANOS; +import static org.elasticsearch.xpack.esql.core.type.DataType.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataType.FLOAT; +import static org.elasticsearch.xpack.esql.core.type.DataType.GEO_POINT; +import static org.elasticsearch.xpack.esql.core.type.DataType.GEO_SHAPE; +import static org.elasticsearch.xpack.esql.core.type.DataType.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataType.IP; import static org.elasticsearch.xpack.esql.core.type.DataType.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataType.LONG; import static org.elasticsearch.xpack.esql.core.type.DataType.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataType.VERSION; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; @@ -2003,6 +2017,57 @@ public class VerifierTests extends ESTestCase { ); } + public void testChangePoint() { + assumeTrue("change_point must be enabled", EsqlCapabilities.Cap.CHANGE_POINT.isEnabled()); + var airports = AnalyzerTestUtils.analyzer(loadMapping("mapping-airports.json", "airports")); + assertEquals("1:30: Unknown column [blahblah]", error("FROM airports | CHANGE_POINT blahblah ON scalerank", airports)); + assertEquals("1:43: Unknown column [blahblah]", error("FROM airports | CHANGE_POINT scalerank ON blahblah", airports)); + // TODO: nicer error message for missing default column "@timestamp" + assertEquals("1:17: Unknown column [@timestamp]", error("FROM airports | CHANGE_POINT scalerank", airports)); + } + + public void testChangePoint_keySortable() { + assumeTrue("change_point must be enabled", EsqlCapabilities.Cap.CHANGE_POINT.isEnabled()); + List sortableTypes = List.of(BOOLEAN, DOUBLE, DATE_NANOS, DATETIME, INTEGER, IP, KEYWORD, LONG, UNSIGNED_LONG, VERSION); + List unsortableTypes = List.of(CARTESIAN_POINT, CARTESIAN_SHAPE, GEO_POINT, GEO_SHAPE); + for (DataType type : sortableTypes) { + query(Strings.format("ROW key=NULL::%s, value=0\n | CHANGE_POINT value ON key", type)); + } + for (DataType type : unsortableTypes) { + assertEquals( + "2:4: change point key [key] must be sortable", + error(Strings.format("ROW key=NULL::%s, value=0\n | CHANGE_POINT value ON key", type)) + ); + } + } + + public void testChangePoint_valueNumeric() { + assumeTrue("change_point must be enabled", EsqlCapabilities.Cap.CHANGE_POINT.isEnabled()); + List numericTypes = List.of(DOUBLE, INTEGER, LONG, UNSIGNED_LONG); + List nonNumericTypes = List.of( + BOOLEAN, + CARTESIAN_POINT, + CARTESIAN_SHAPE, + DATE_NANOS, + DATETIME, + GEO_POINT, + GEO_SHAPE, + IP, + KEYWORD, + VERSION + ); + for (DataType type : numericTypes) { + query(Strings.format("ROW key=0, value=NULL::%s\n | CHANGE_POINT value ON key", type)); + } + for (DataType type : nonNumericTypes) { + assertEquals( + "2:4: change point value [value] must be numeric", + error(Strings.format("ROW key=0, value=NULL::%s\n | CHANGE_POINT value ON key", type)) + ); + } + assertEquals("2:4: change point value [value] must be numeric", error("ROW key=0, value=NULL\n | CHANGE_POINT value ON key")); + } + public void testSortByAggregate() { assertEquals("1:18: Aggregate functions are not allowed in SORT [COUNT]", error("ROW a = 1 | SORT count(*)")); assertEquals("1:28: Aggregate functions are not allowed in SORT [COUNT]", error("ROW a = 1 | SORT to_string(count(*))")); @@ -2036,13 +2101,7 @@ public class VerifierTests extends ESTestCase { query("FROM test | WHERE match(first_name, \"Jean\", {\"auto_generate_synonyms_phrase_query\": true})"); // Check all data types for available options - DataType[] optionTypes = new DataType[] { - DataType.INTEGER, - DataType.LONG, - DataType.FLOAT, - DataType.DOUBLE, - DataType.KEYWORD, - DataType.BOOLEAN }; + DataType[] optionTypes = new DataType[] { INTEGER, LONG, FLOAT, DOUBLE, KEYWORD, BOOLEAN }; for (Map.Entry allowedOptions : Match.ALLOWED_OPTIONS.entrySet()) { String optionName = allowedOptions.getKey(); DataType optionType = allowedOptions.getValue(); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/enrich/EnrichOperatorStatusTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/enrich/EnrichOperatorStatusTests.java index 4fc67f85cc06..5f30cc860cae 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/enrich/EnrichOperatorStatusTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/enrich/EnrichOperatorStatusTests.java @@ -41,25 +41,25 @@ public class EnrichOperatorStatusTests extends AbstractWireSerializingTestCase new EnrichLookupOperator.Status( in.receivedPages(), randomValueOtherThan(in.completedPages(), ESTestCase::randomNonNegativeLong), in.totalTerms, - in.totalTimeInMillis() + in.procesNanos() ); case 2 -> new EnrichLookupOperator.Status( in.receivedPages(), in.completedPages(), randomValueOtherThan(in.totalTerms, ESTestCase::randomNonNegativeLong), - in.totalTimeInMillis() + in.procesNanos() ); case 3 -> new EnrichLookupOperator.Status( in.receivedPages(), in.completedPages(), in.totalTerms, - randomValueOtherThan(in.totalTimeInMillis(), ESTestCase::randomNonNegativeLong) + randomValueOtherThan(in.procesNanos(), ESTestCase::randomNonNegativeLong) ); default -> throw new AssertionError("unknown "); }; @@ -70,10 +70,10 @@ public class EnrichOperatorStatusTests extends AbstractWireSerializingTestCase receivedPages = randomValueOtherThan(receivedPages, ESTestCase::randomNonNegativeLong); case 1 -> completedPages = randomValueOtherThan(completedPages, ESTestCase::randomNonNegativeLong); - case 2 -> totalTimeInMillis = randomValueOtherThan(totalTimeInMillis, ESTestCase::randomNonNegativeLong); + case 2 -> procesNanos = randomValueOtherThan(procesNanos, ESTestCase::randomNonNegativeLong); case 3 -> totalTerms = randomValueOtherThan(totalTerms, ESTestCase::randomNonNegativeLong); case 4 -> emittedPages = randomValueOtherThan(emittedPages, ESTestCase::randomNonNegativeLong); default -> throw new UnsupportedOperationException(); } - return new LookupFromIndexOperator.Status(receivedPages, completedPages, totalTimeInMillis, totalTerms, emittedPages); + return new LookupFromIndexOperator.Status(receivedPages, completedPages, procesNanos, totalTerms, emittedPages); } public void testToXContent() { @@ -57,10 +57,10 @@ public class LookupFromIndexOperatorStatusTests extends AbstractWireSerializingT String json = Strings.toString(status, true, true); assertThat(json, equalTo(""" { + "process_nanos" : 10000, + "process_time" : "10micros", "received_pages" : 100, "completed_pages" : 50, - "total_time_in_millis" : 10000, - "total_time" : "10s", "emitted_pages" : 88, "total_terms" : 120 }""")); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractAggregationTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractAggregationTestCase.java index 9f0fc34b7d53..f8ba9c125108 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractAggregationTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractAggregationTestCase.java @@ -410,15 +410,15 @@ public abstract class AbstractAggregationTestCase extends AbstractFunctionTestCa } private Aggregator aggregator(Expression expression, List inputChannels, AggregatorMode mode) { - AggregatorFunctionSupplier aggregatorFunctionSupplier = ((ToAggregator) expression).supplier(inputChannels); + AggregatorFunctionSupplier aggregatorFunctionSupplier = ((ToAggregator) expression).supplier(); - return new Aggregator(aggregatorFunctionSupplier.aggregator(driverContext()), mode); + return new Aggregator(aggregatorFunctionSupplier.aggregator(driverContext(), inputChannels), mode); } private GroupingAggregator groupingAggregator(Expression expression, List inputChannels, AggregatorMode mode) { - AggregatorFunctionSupplier aggregatorFunctionSupplier = ((ToAggregator) expression).supplier(inputChannels); + AggregatorFunctionSupplier aggregatorFunctionSupplier = ((ToAggregator) expression).supplier(); - return new GroupingAggregator(aggregatorFunctionSupplier.groupingAggregator(driverContext()), mode); + return new GroupingAggregator(aggregatorFunctionSupplier.groupingAggregator(driverContext(), inputChannels), mode); } /** diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java index c03ff0cfbeee..65e0a2f1b20a 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java @@ -924,7 +924,7 @@ public abstract class AbstractFunctionTestCase extends ESTestCase { description.returnType(), description.description(), description.variadic(), - description.isAggregation() + description.type() ); } renderTypes(name, description.args()); @@ -1216,7 +1216,11 @@ public abstract class AbstractFunctionTestCase extends ESTestCase { builder.field("operator", info.operator()); assertThat(isAggregation(), equalTo(false)); } else { - builder.field("type", isAggregation() ? "agg" : "eval"); + builder.field("type", switch (info.type()) { + case SCALAR -> "scalar"; + case AGGREGATE -> "agg"; + case GROUPING -> "grouping"; + }); } builder.field("name", name); builder.field("description", removeAsciidocLinks(info.description())); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java index 7f04f076ed15..53e666738e18 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java @@ -22,6 +22,7 @@ import org.elasticsearch.xpack.esql.expression.function.AbstractScalarFunctionTe import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.FunctionName; +import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.junit.AfterClass; @@ -147,8 +148,8 @@ public class WildcardLikeTests extends AbstractScalarFunctionTestCase { } @Override - public boolean isAggregation() { - return orig.isAggregation(); + public FunctionType type() { + return orig.type(); } @Override diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java index ea88f4fd5ba0..6fb1cb9ca14e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java @@ -96,6 +96,7 @@ import org.elasticsearch.xpack.esql.index.EsIndex; import org.elasticsearch.xpack.esql.index.IndexResolution; import org.elasticsearch.xpack.esql.optimizer.rules.logical.LiteralsOnTheRight; import org.elasticsearch.xpack.esql.optimizer.rules.logical.OptimizerRules; +import org.elasticsearch.xpack.esql.optimizer.rules.logical.PruneRedundantOrderBy; import org.elasticsearch.xpack.esql.optimizer.rules.logical.PushDownAndCombineLimits; import org.elasticsearch.xpack.esql.optimizer.rules.logical.PushDownEnrich; import org.elasticsearch.xpack.esql.optimizer.rules.logical.PushDownEval; @@ -1839,10 +1840,9 @@ public class LogicalPlanOptimizerTests extends ESTestCase { /** * Expected - * TopN[[Order[first_name{f}#170,ASC,LAST]],1000[INTEGER]] - * \_MvExpand[first_name{f}#170] - * \_TopN[[Order[emp_no{f}#169,ASC,LAST]],1000[INTEGER]] - * \_EsRelation[test][avg_worked_seconds{f}#167, birth_date{f}#168, emp_n..] + * TopN[[Order[first_name{r}#5575,ASC,LAST]],1000[INTEGER]] + * \_MvExpand[first_name{f}#5565,first_name{r}#5575,null] + * \_EsRelation[test][_meta_field{f}#5570, emp_no{f}#5564, first_name{f}#..] */ public void testDontCombineOrderByThroughMvExpand() { LogicalPlan plan = optimizedPlan(""" @@ -1854,9 +1854,7 @@ public class LogicalPlanOptimizerTests extends ESTestCase { var topN = as(plan, TopN.class); assertThat(orderNames(topN), contains("first_name")); var mvExpand = as(topN.child(), MvExpand.class); - topN = as(mvExpand.child(), TopN.class); - assertThat(orderNames(topN), contains("emp_no")); - as(topN.child(), EsRelation.class); + as(mvExpand.child(), EsRelation.class); } /** @@ -2065,12 +2063,10 @@ public class LogicalPlanOptimizerTests extends ESTestCase { } /** - * Expected - * EsqlProject[[emp_no{f}#350, first_name{f}#351, salary{f}#352]] - * \_TopN[[Order[salary{f}#352,ASC,LAST], Order[first_name{f}#351,ASC,LAST]],5[INTEGER]] - * \_MvExpand[first_name{f}#351] - * \_TopN[[Order[emp_no{f}#350,ASC,LAST]],10000[INTEGER]] - * \_EsRelation[employees][emp_no{f}#350, first_name{f}#351, salary{f}#352] + * EsqlProject[[emp_no{f}#10, first_name{r}#21, salary{f}#15]] + * \_TopN[[Order[salary{f}#15,ASC,LAST], Order[first_name{r}#21,ASC,LAST]],5[INTEGER]] + * \_MvExpand[first_name{f}#11,first_name{r}#21,null] + * \_EsRelation[test][_meta_field{f}#16, emp_no{f}#10, first_name{f}#11, ..] */ public void testPushDownLimitThroughMultipleSort_AfterMvExpand() { LogicalPlan plan = optimizedPlan(""" @@ -2086,20 +2082,16 @@ public class LogicalPlanOptimizerTests extends ESTestCase { assertThat(topN.limit().fold(FoldContext.small()), equalTo(5)); assertThat(orderNames(topN), contains("salary", "first_name")); var mvExp = as(topN.child(), MvExpand.class); - topN = as(mvExp.child(), TopN.class); - assertThat(topN.limit().fold(FoldContext.small()), equalTo(10000)); - assertThat(orderNames(topN), contains("emp_no")); - as(topN.child(), EsRelation.class); + as(mvExp.child(), EsRelation.class); } /** * Expected - * EsqlProject[[emp_no{f}#361, first_name{f}#362, salary{f}#363]] - * \_TopN[[Order[first_name{f}#362,ASC,LAST]],5[INTEGER]] - * \_TopN[[Order[salary{f}#363,ASC,LAST]],5[INTEGER]] - * \_MvExpand[first_name{f}#362] - * \_TopN[[Order[emp_no{f}#361,ASC,LAST]],10000[INTEGER]] - * \_EsRelation[employees][emp_no{f}#361, first_name{f}#362, salary{f}#363] + * EsqlProject[[emp_no{f}#2560, first_name{r}#2571, salary{f}#2565]] + * \_TopN[[Order[first_name{r}#2571,ASC,LAST]],5[INTEGER]] + * \_TopN[[Order[salary{f}#2565,ASC,LAST]],5[INTEGER]] + * \_MvExpand[first_name{f}#2561,first_name{r}#2571,null] + * \_EsRelation[test][_meta_field{f}#2566, emp_no{f}#2560, first_name{f}#..] */ public void testPushDownLimitThroughMultipleSort_AfterMvExpand2() { LogicalPlan plan = optimizedPlan(""" @@ -2119,10 +2111,7 @@ public class LogicalPlanOptimizerTests extends ESTestCase { assertThat(topN.limit().fold(FoldContext.small()), equalTo(5)); assertThat(orderNames(topN), contains("salary")); var mvExp = as(topN.child(), MvExpand.class); - topN = as(mvExp.child(), TopN.class); - assertThat(topN.limit().fold(FoldContext.small()), equalTo(10000)); - assertThat(orderNames(topN), contains("emp_no")); - as(topN.child(), EsRelation.class); + as(mvExp.child(), EsRelation.class); } /** @@ -2231,8 +2220,7 @@ public class LogicalPlanOptimizerTests extends ESTestCase { * \_TopN[[Order[salary{f}#12,ASC,LAST]],5[INTEGER]] * \_Eval[[100[INTEGER] AS b]] * \_MvExpand[first_name{f}#11] - * \_TopN[[Order[first_name{f}#11,ASC,LAST]],10000[INTEGER]] - * \_EsRelation[employees][emp_no{f}#10, first_name{f}#11, salary{f}#12] + * \_EsRelation[employees][emp_no{f}#10, first_name{f}#11, salary{f}#12] */ public void testPushDownLimit_PastEvalAndMvExpand() { LogicalPlan plan = optimizedPlan(""" @@ -2250,22 +2238,18 @@ public class LogicalPlanOptimizerTests extends ESTestCase { assertThat(orderNames(topN), contains("salary")); var eval = as(topN.child(), Eval.class); var mvExp = as(eval.child(), MvExpand.class); - topN = as(mvExp.child(), TopN.class); - assertThat(topN.limit().fold(FoldContext.small()), equalTo(10000)); - assertThat(orderNames(topN), contains("first_name")); - as(topN.child(), EsRelation.class); + as(mvExp.child(), EsRelation.class); } /** * Expected - * EsqlProject[[emp_no{f}#12, first_name{r}#22, salary{f}#17]] - * \_TopN[[Order[salary{f}#17,ASC,LAST], Order[first_name{r}#22,ASC,LAST]],1000[INTEGER]] - * \_Filter[gender{f}#14 == [46][KEYWORD] AND WILDCARDLIKE(first_name{r}#22)] - * \_MvExpand[first_name{f}#13,first_name{r}#22,null] - * \_TopN[[Order[emp_no{f}#12,ASC,LAST]],10000[INTEGER]] - * \_EsRelation[test][_meta_field{f}#18, emp_no{f}#12, first_name{f}#13, ..] + * EsqlProject[[emp_no{f}#5885, first_name{r}#5896, salary{f}#5890]] + * \_TopN[[Order[salary{f}#5890,ASC,LAST], Order[first_name{r}#5896,ASC,LAST]],1000[INTEGER]] + * \_Filter[gender{f}#5887 == [46][KEYWORD] AND WILDCARDLIKE(first_name{r}#5896)] + * \_MvExpand[first_name{f}#5886,first_name{r}#5896,null] + * \_EsRelation[test][_meta_field{f}#5891, emp_no{f}#5885, first_name{f}#..] */ - public void testAddDefaultLimit_BeforeMvExpand_WithFilterOnExpandedField_ResultTruncationDefaultSize() { + public void testRedundantSort_BeforeMvExpand_WithFilterOnExpandedField_ResultTruncationDefaultSize() { LogicalPlan plan = optimizedPlan(""" from test | sort emp_no @@ -2282,9 +2266,7 @@ public class LogicalPlanOptimizerTests extends ESTestCase { var filter = as(topN.child(), Filter.class); assertThat(filter.condition(), instanceOf(And.class)); var mvExp = as(filter.child(), MvExpand.class); - topN = as(mvExp.child(), TopN.class); // TODO is it correct? Double-check AddDefaultTopN rule - assertThat(orderNames(topN), contains("emp_no")); - as(topN.child(), EsRelation.class); + as(mvExp.child(), EsRelation.class); } /** @@ -2367,8 +2349,7 @@ public class LogicalPlanOptimizerTests extends ESTestCase { var mvExpand = as(topN.child(), MvExpand.class); var filter = as(mvExpand.child(), Filter.class); mvExpand = as(filter.child(), MvExpand.class); - var topN2 = as(mvExpand.child(), TopN.class); // TODO is it correct? Double-check AddDefaultTopN rule - as(topN2.child(), EsRelation.class); + as(mvExpand.child(), EsRelation.class); } /** @@ -2463,20 +2444,18 @@ public class LogicalPlanOptimizerTests extends ESTestCase { assertThat(orderNames(topN), contains("first_name")); assertThat(topN.limit().fold(FoldContext.small()), equalTo(10000)); var mvExpand = as(topN.child(), MvExpand.class); - var topN2 = as(mvExpand.child(), TopN.class); // TODO is it correct? Double-check AddDefaultTopN rule - as(topN2.child(), EsRelation.class); + as(mvExpand.child(), EsRelation.class); } /** * Expected - * EsqlProject[[emp_no{f}#104, first_name{f}#105, salary{f}#106]] - * \_TopN[[Order[salary{f}#106,ASC,LAST], Order[first_name{f}#105,ASC,LAST]],15[INTEGER]] - * \_Filter[gender{f}#215 == [46][KEYWORD] AND WILDCARDLIKE(first_name{f}#105)] - * \_MvExpand[first_name{f}#105] - * \_TopN[[Order[emp_no{f}#104,ASC,LAST]],10000[INTEGER]] - * \_EsRelation[employees][emp_no{f}#104, first_name{f}#105, salary{f}#106] + * EsqlProject[[emp_no{f}#3517, first_name{r}#3528, salary{f}#3522]] + * \_TopN[[Order[salary{f}#3522,ASC,LAST], Order[first_name{r}#3528,ASC,LAST]],15[INTEGER]] + * \_Filter[gender{f}#3519 == [46][KEYWORD] AND WILDCARDLIKE(first_name{r}#3528)] + * \_MvExpand[first_name{f}#3518,first_name{r}#3528,null] + * \_EsRelation[test][_meta_field{f}#3523, emp_no{f}#3517, first_name{f}#..] */ - public void testAddDefaultLimit_BeforeMvExpand_WithFilterOnExpandedField() { + public void testRedundantSort_BeforeMvExpand_WithFilterOnExpandedField() { LogicalPlan plan = optimizedPlan(""" from test | sort emp_no @@ -2494,24 +2473,18 @@ public class LogicalPlanOptimizerTests extends ESTestCase { var filter = as(topN.child(), Filter.class); assertThat(filter.condition(), instanceOf(And.class)); var mvExp = as(filter.child(), MvExpand.class); - topN = as(mvExp.child(), TopN.class); - // the filter acts on first_name (the one used in mv_expand), so the limit 15 is not pushed down past mv_expand - // instead the default limit is added - assertThat(topN.limit().fold(FoldContext.small()), equalTo(10000)); - assertThat(orderNames(topN), contains("emp_no")); - as(topN.child(), EsRelation.class); + as(mvExp.child(), EsRelation.class); } /** * Expected - * EsqlProject[[emp_no{f}#104, first_name{f}#105, salary{f}#106]] - * \_TopN[[Order[salary{f}#106,ASC,LAST], Order[first_name{f}#105,ASC,LAST]],15[INTEGER]] - * \_Filter[gender{f}#215 == [46][KEYWORD] AND salary{f}#106 > 60000[INTEGER]] - * \_MvExpand[first_name{f}#105] - * \_TopN[[Order[emp_no{f}#104,ASC,LAST]],10000[INTEGER]] - * \_EsRelation[employees][emp_no{f}#104, first_name{f}#105, salary{f}#106] + * EsqlProject[[emp_no{f}#3421, first_name{r}#3432, salary{f}#3426]] + * \_TopN[[Order[salary{f}#3426,ASC,LAST], Order[first_name{r}#3432,ASC,LAST]],15[INTEGER]] + * \_Filter[gender{f}#3423 == [46][KEYWORD] AND salary{f}#3426 > 60000[INTEGER]] + * \_MvExpand[first_name{f}#3422,first_name{r}#3432,null] + * \_EsRelation[test][_meta_field{f}#3427, emp_no{f}#3421, first_name{f}#..] */ - public void testAddDefaultLimit_BeforeMvExpand_WithFilter_NOT_OnExpandedField() { + public void testRedundantSort_BeforeMvExpand_WithFilter_NOT_OnExpandedField() { LogicalPlan plan = optimizedPlan(""" from test | sort emp_no @@ -2529,24 +2502,18 @@ public class LogicalPlanOptimizerTests extends ESTestCase { var filter = as(topN.child(), Filter.class); assertThat(filter.condition(), instanceOf(And.class)); var mvExp = as(filter.child(), MvExpand.class); - topN = as(mvExp.child(), TopN.class); - // the filters after mv_expand do not act on the expanded field values, as such the limit 15 is the one being pushed down - // otherwise that limit wouldn't have pushed down and the default limit was instead being added by default before mv_expanded - assertThat(topN.limit().fold(FoldContext.small()), equalTo(10000)); - assertThat(orderNames(topN), contains("emp_no")); - as(topN.child(), EsRelation.class); + as(mvExp.child(), EsRelation.class); } /** * Expected - * EsqlProject[[emp_no{f}#116, first_name{f}#117 AS x, salary{f}#119]] - * \_TopN[[Order[salary{f}#119,ASC,LAST], Order[first_name{f}#117,ASC,LAST]],15[INTEGER]] - * \_Filter[gender{f}#118 == [46][KEYWORD] AND WILDCARDLIKE(first_name{f}#117)] - * \_MvExpand[first_name{f}#117] - * \_TopN[[Order[gender{f}#118,ASC,LAST]],10000[INTEGER]] - * \_EsRelation[employees][emp_no{f}#116, first_name{f}#117, gender{f}#118, sa..] + * EsqlProject[[emp_no{f}#2085, first_name{r}#2096 AS x, salary{f}#2090]] + * \_TopN[[Order[salary{f}#2090,ASC,LAST], Order[first_name{r}#2096,ASC,LAST]],15[INTEGER]] + * \_Filter[gender{f}#2087 == [46][KEYWORD] AND WILDCARDLIKE(first_name{r}#2096)] + * \_MvExpand[first_name{f}#2086,first_name{r}#2096,null] + * \_EsRelation[test][_meta_field{f}#2091, emp_no{f}#2085, first_name{f}#..] */ - public void testAddDefaultLimit_BeforeMvExpand_WithFilterOnExpandedFieldAlias() { + public void testRedundantSort_BeforeMvExpand_WithFilterOnExpandedFieldAlias() { LogicalPlan plan = optimizedPlan(""" from test | sort gender @@ -2565,11 +2532,7 @@ public class LogicalPlanOptimizerTests extends ESTestCase { var filter = as(topN.child(), Filter.class); assertThat(filter.condition(), instanceOf(And.class)); var mvExp = as(filter.child(), MvExpand.class); - topN = as(mvExp.child(), TopN.class); - // the filter uses an alias ("x") to the expanded field ("first_name"), so the default limit is used and not the one provided - assertThat(topN.limit().fold(FoldContext.small()), equalTo(10000)); - assertThat(orderNames(topN), contains("gender")); - as(topN.child(), EsRelation.class); + as(mvExp.child(), EsRelation.class); } /** @@ -7270,4 +7233,349 @@ public class LogicalPlanOptimizerTests extends ESTestCase { assertEquals(new Literal(EMPTY, 2.0, DataType.DOUBLE), ee.value()); assertEquals(DataType.DOUBLE, ee.dataType()); } + + /** + * TopN[[Order[emp_no{f}#11,ASC,LAST]],1000[INTEGER]] + * \_Join[LEFT,[language_code{r}#5],[language_code{r}#5],[language_code{f}#22]] + * |_EsqlProject[[_meta_field{f}#17, emp_no{f}#11, first_name{f}#12, gender{f}#13, hire_date{f}#18, job{f}#19, job.raw{f}#20, l + * anguages{f}#14 AS language_code, last_name{f}#15, long_noidx{f}#21, salary{f}#16, foo{r}#7]] + * | \_Eval[[[62 61 72][KEYWORD] AS foo]] + * | \_Filter[languages{f}#14 > 1[INTEGER]] + * | \_EsRelation[test][_meta_field{f}#17, emp_no{f}#11, first_name{f}#12, ..] + * \_EsRelation[languages_lookup][LOOKUP][language_code{f}#22, language_name{f}#23] + */ + public void testRedundantSortOnJoin() { + assumeTrue("Requires LOOKUP JOIN", EsqlCapabilities.Cap.JOIN_LOOKUP_V12.isEnabled()); + + var plan = optimizedPlan(""" + FROM test + | SORT languages + | RENAME languages AS language_code + | EVAL foo = "bar" + | LOOKUP JOIN languages_lookup ON language_code + | WHERE language_code > 1 + | SORT emp_no + """); + + var topN = as(plan, TopN.class); + var join = as(topN.child(), Join.class); + var project = as(join.left(), EsqlProject.class); + var eval = as(project.child(), Eval.class); + var filter = as(eval.child(), Filter.class); + as(filter.child(), EsRelation.class); + } + + /** + * TopN[[Order[emp_no{f}#9,ASC,LAST]],1000[INTEGER]] + * \_Filter[emp_no{f}#9 > 1[INTEGER]] + * \_MvExpand[languages{f}#12,languages{r}#20,null] + * \_Eval[[[62 61 72][KEYWORD] AS foo]] + * \_EsRelation[test][_meta_field{f}#15, emp_no{f}#9, first_name{f}#10, g..] + */ + public void testRedundantSortOnMvExpand() { + var plan = optimizedPlan(""" + FROM test + | SORT languages + | EVAL foo = "bar" + | MV_EXPAND languages + | WHERE emp_no > 1 + | SORT emp_no + """); + + var topN = as(plan, TopN.class); + var filter = as(topN.child(), Filter.class); + var mvExpand = as(filter.child(), MvExpand.class); + var eval = as(mvExpand.child(), Eval.class); + as(eval.child(), EsRelation.class); + } + + /** + * TopN[[Order[emp_no{f}#11,ASC,LAST]],1000[INTEGER]] + * \_Join[LEFT,[language_code{r}#5],[language_code{r}#5],[language_code{f}#22]] + * |_Filter[emp_no{f}#11 > 1[INTEGER]] + * | \_MvExpand[languages{f}#14,languages{r}#24,null] + * | \_Eval[[languages{f}#14 AS language_code]] + * | \_EsRelation[test][_meta_field{f}#17, emp_no{f}#11, first_name{f}#12, ..] + * \_EsRelation[languages_lookup][LOOKUP][language_code{f}#22, language_name{f}#23] + */ + public void testRedundantSortOnMvExpandAndJoin() { + var plan = optimizedPlan(""" + FROM test + | SORT languages + | EVAL language_code = languages + | MV_EXPAND languages + | WHERE emp_no > 1 + | LOOKUP JOIN languages_lookup ON language_code + | SORT emp_no + """); + + var topN = as(plan, TopN.class); + var join = as(topN.child(), Join.class); + var filter = as(join.left(), Filter.class); + var mvExpand = as(filter.child(), MvExpand.class); + var eval = as(mvExpand.child(), Eval.class); + as(eval.child(), EsRelation.class); + } + + /** + * TopN[[Order[emp_no{f}#12,ASC,LAST]],1000[INTEGER]] + * \_Join[LEFT,[language_code{r}#5],[language_code{r}#5],[language_code{f}#23]] + * |_Filter[emp_no{f}#12 > 1[INTEGER]] + * | \_MvExpand[languages{f}#15,languages{r}#25,null] + * | \_Eval[[languages{f}#15 AS language_code]] + * | \_EsRelation[test][_meta_field{f}#18, emp_no{f}#12, first_name{f}#13, ..] + * \_EsRelation[languages_lookup][LOOKUP][language_code{f}#23, language_name{f}#24] + */ + public void testMultlipleRedundantSortOnMvExpandAndJoin() { + var plan = optimizedPlan(""" + FROM test + | SORT first_name + | EVAL language_code = languages + | MV_EXPAND languages + | sort last_name + | WHERE emp_no > 1 + | LOOKUP JOIN languages_lookup ON language_code + | SORT emp_no + """); + + var topN = as(plan, TopN.class); + var join = as(topN.child(), Join.class); + var filter = as(join.left(), Filter.class); + var mvExpand = as(filter.child(), MvExpand.class); + var eval = as(mvExpand.child(), Eval.class); + as(eval.child(), EsRelation.class); + } + + /** + * TopN[[Order[emp_no{f}#16,ASC,LAST]],1000[INTEGER]] + * \_Filter[emp_no{f}#16 > 1[INTEGER]] + * \_MvExpand[languages{f}#19,languages{r}#31] + * \_Dissect[foo{r}#5,Parser[pattern=%{z}, appendSeparator=, parser=org.elasticsearch.dissect.DissectParser@26f2cab],[z{r}#10 + * ]] + * \_Grok[foo{r}#5,Parser[pattern=%{WORD:y}, grok=org.elasticsearch.grok.Grok@6ea44ccd],[y{r}#9]] + * \_Enrich[ANY,[6c 61 6e 67 75 61 67 65 73 5f 69 64 78][KEYWORD],foo{r}#5,{"match":{"indices":[],"match_field":"id","enrich_ + * fields":["language_code","language_name"]}},{=languages_idx},[language_code{r}#29, language_name{r}#30]] + * \_Eval[[TOSTRING(languages{f}#19) AS foo]] + * \_EsRelation[test][_meta_field{f}#22, emp_no{f}#16, first_name{f}#17, ..] + */ + public void testRedundantSortOnMvExpandEnrichGrokDissect() { + var plan = optimizedPlan(""" + FROM test + | SORT languages + | EVAL foo = to_string(languages) + | ENRICH languages_idx on foo + | GROK foo "%{WORD:y}" + | DISSECT foo "%{z}" + | MV_EXPAND languages + | WHERE emp_no > 1 + | SORT emp_no + """); + + var topN = as(plan, TopN.class); + var filter = as(topN.child(), Filter.class); + var mvExpand = as(filter.child(), MvExpand.class); + var dissect = as(mvExpand.child(), Dissect.class); + var grok = as(dissect.child(), Grok.class); + var enrich = as(grok.child(), Enrich.class); + var eval = as(enrich.child(), Eval.class); + as(eval.child(), EsRelation.class); + } + + /** + * TopN[[Order[emp_no{f}#20,ASC,LAST]],1000[INTEGER]] + * \_Filter[emp_no{f}#20 > 1[INTEGER]] + * \_MvExpand[languages{f}#23,languages{r}#37] + * \_Dissect[foo{r}#5,Parser[pattern=%{z}, appendSeparator=, parser=org.elasticsearch.dissect.DissectParser@3e922db0],[z{r}#1 + * 4]] + * \_Grok[foo{r}#5,Parser[pattern=%{WORD:y}, grok=org.elasticsearch.grok.Grok@4d6ad024],[y{r}#13]] + * \_Enrich[ANY,[6c 61 6e 67 75 61 67 65 73 5f 69 64 78][KEYWORD],foo{r}#5,{"match":{"indices":[],"match_field":"id","enrich_ + * fields":["language_code","language_name"]}},{=languages_idx},[language_code{r}#35, language_name{r}#36]] + * \_Join[LEFT,[language_code{r}#8],[language_code{r}#8],[language_code{f}#31]] + * |_Eval[[TOSTRING(languages{f}#23) AS foo, languages{f}#23 AS language_code]] + * | \_EsRelation[test][_meta_field{f}#26, emp_no{f}#20, first_name{f}#21, ..] + * \_EsRelation[languages_lookup][LOOKUP][language_code{f}#31] + */ + public void testRedundantSortOnMvExpandJoinEnrichGrokDissect() { + var plan = optimizedPlan(""" + FROM test + | SORT languages + | EVAL foo = to_string(languages), language_code = languages + | LOOKUP JOIN languages_lookup ON language_code + | ENRICH languages_idx on foo + | GROK foo "%{WORD:y}" + | DISSECT foo "%{z}" + | MV_EXPAND languages + | WHERE emp_no > 1 + | SORT emp_no + """); + + var topN = as(plan, TopN.class); + var filter = as(topN.child(), Filter.class); + var mvExpand = as(filter.child(), MvExpand.class); + var dissect = as(mvExpand.child(), Dissect.class); + var grok = as(dissect.child(), Grok.class); + var enrich = as(grok.child(), Enrich.class); + var join = as(enrich.child(), Join.class); + var eval = as(join.left(), Eval.class); + as(eval.child(), EsRelation.class); + } + + /** + * TopN[[Order[emp_no{f}#23,ASC,LAST]],1000[INTEGER]] + * \_Filter[emp_no{f}#23 > 1[INTEGER]] + * \_MvExpand[languages{f}#26,languages{r}#36] + * \_EsqlProject[[language_name{f}#35, foo{r}#5 AS bar, languages{f}#26, emp_no{f}#23]] + * \_Join[LEFT,[language_code{r}#8],[language_code{r}#8],[language_code{f}#34]] + * |_Project[[_meta_field{f}#29, emp_no{f}#23, first_name{f}#24, gender{f}#25, hire_date{f}#30, job{f}#31, job.raw{f}#32, l + * anguages{f}#26, last_name{f}#27, long_noidx{f}#33, salary{f}#28, foo{r}#5, languages{f}#26 AS language_code]] + * | \_Eval[[TOSTRING(languages{f}#26) AS foo]] + * | \_EsRelation[test][_meta_field{f}#29, emp_no{f}#23, first_name{f}#24, ..] + * \_EsRelation[languages_lookup][LOOKUP][language_code{f}#34, language_name{f}#35] + */ + public void testRedundantSortOnMvExpandJoinKeepDropRename() { + var plan = optimizedPlan(""" + FROM test + | SORT languages + | EVAL foo = to_string(languages), language_code = languages + | LOOKUP JOIN languages_lookup ON language_code + | KEEP language_name, language_code, foo, languages, emp_no + | DROP language_code + | RENAME foo AS bar + | MV_EXPAND languages + | WHERE emp_no > 1 + | SORT emp_no + """); + + var topN = as(plan, TopN.class); + var filter = as(topN.child(), Filter.class); + var mvExpand = as(filter.child(), MvExpand.class); + var project = as(mvExpand.child(), Project.class); + var join = as(project.child(), Join.class); + var project2 = as(join.left(), Project.class); + var eval = as(project2.child(), Eval.class); + as(eval.child(), EsRelation.class); + } + + /** + * TopN[[Order[emp_no{f}#15,ASC,LAST]],1000[INTEGER]] + * \_Filter[emp_no{f}#15 > 1[INTEGER]] + * \_MvExpand[foo{r}#10,foo{r}#29] + * \_Eval[[CONCAT(language_name{r}#28,[66 6f 6f][KEYWORD]) AS foo]] + * \_MvExpand[language_name{f}#27,language_name{r}#28] + * \_Join[LEFT,[language_code{r}#3],[language_code{r}#3],[language_code{f}#26]] + * |_Eval[[1[INTEGER] AS language_code]] + * | \_EsRelation[test][_meta_field{f}#21, emp_no{f}#15, first_name{f}#16, ..] + * \_EsRelation[languages_lookup][LOOKUP][language_code{f}#26, language_name{f}#27] + */ + public void testEvalLookupMultipleSorts() { + var plan = optimizedPlan(""" + FROM test + | EVAL language_code = 1 + | LOOKUP JOIN languages_lookup ON language_code + | SORT language_name + | MV_EXPAND language_name + | EVAL foo = concat(language_name, "foo") + | MV_EXPAND foo + | WHERE emp_no > 1 + | SORT emp_no + """); + + var topN = as(plan, TopN.class); + var filter = as(topN.child(), Filter.class); + var mvExpand = as(filter.child(), MvExpand.class); + var eval = as(mvExpand.child(), Eval.class); + mvExpand = as(eval.child(), MvExpand.class); + var join = as(mvExpand.child(), Join.class); + eval = as(join.left(), Eval.class); + as(eval.child(), EsRelation.class); + + } + + public void testUnboundedSortSimple() { + var query = """ + ROW x = [1,2,3], y = 1 + | SORT y + | MV_EXPAND x + | WHERE x > 2 + """; + + VerificationException e = expectThrows(VerificationException.class, () -> plan(query)); + assertThat(e.getMessage(), containsString("line 2:5: Unbounded sort not supported yet [SORT y] please add a limit")); + } + + public void testUnboundedSortJoin() { + var query = """ + ROW x = [1,2,3], y = 2, language_code = 1 + | SORT y + | LOOKUP JOIN languages_lookup ON language_code + | WHERE language_name == "foo" + """; + + VerificationException e = expectThrows(VerificationException.class, () -> plan(query)); + assertThat(e.getMessage(), containsString("line 2:5: Unbounded sort not supported yet [SORT y] please add a limit")); + } + + public void testUnboundedSortWithMvExpandAndFilter() { + var query = """ + FROM test + | EVAL language_code = 1 + | LOOKUP JOIN languages_lookup ON language_code + | SORT language_name + | EVAL foo = concat(language_name, "foo") + | MV_EXPAND foo + | WHERE foo == "foo" + """; + + VerificationException e = expectThrows(VerificationException.class, () -> plan(query)); + assertThat(e.getMessage(), containsString("line 4:3: Unbounded sort not supported yet [SORT language_name] please add a limit")); + } + + public void testUnboundedSortWithLookupJoinAndFilter() { + var query = """ + FROM test + | EVAL language_code = 1 + | EVAL foo = concat(language_code::string, "foo") + | MV_EXPAND foo + | SORT foo + | LOOKUP JOIN languages_lookup ON language_code + | WHERE language_name == "foo" + """; + + VerificationException e = expectThrows(VerificationException.class, () -> plan(query)); + assertThat(e.getMessage(), containsString("line 5:3: Unbounded sort not supported yet [SORT foo] please add a limit")); + } + + public void testUnboundedSortExpandFilter() { + var query = """ + ROW x = [1,2,3], y = 1 + | SORT x + | MV_EXPAND x + | WHERE x > 2 + """; + + VerificationException e = expectThrows(VerificationException.class, () -> plan(query)); + assertThat(e.getMessage(), containsString("line 2:5: Unbounded sort not supported yet [SORT x] please add a limit")); + } + + public void testPruneRedundantOrderBy() { + var rule = new PruneRedundantOrderBy(); + + var query = """ + row x = [1,2,3], y = 1 + | sort x + | mv_expand x + | sort x + | mv_expand x + | sort y + """; + LogicalPlan analyzed = analyzer.analyze(parser.createStatement(query)); + LogicalPlan optimized = rule.apply(analyzed); + + // check that all the redundant SORTs are removed in a single run + var limit = as(optimized, Limit.class); + var orderBy = as(limit.child(), OrderBy.class); + var mvExpand = as(orderBy.child(), MvExpand.class); + var mvExpand2 = as(mvExpand.child(), MvExpand.class); + as(mvExpand2.child(), Row.class); + } } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java index f7bdf52315fe..b877937d6397 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java @@ -7631,7 +7631,6 @@ public class PhysicalPlanOptimizerTests extends ESTestCase { } public void testScore() { - assumeTrue("'METADATA _score' is disabled", EsqlCapabilities.Cap.METADATA_SCORE.isEnabled()); var plan = physicalPlan(""" from test metadata _score | where match(first_name, "john") @@ -7658,7 +7657,6 @@ public class PhysicalPlanOptimizerTests extends ESTestCase { } public void testScoreTopN() { - assumeTrue("'METADATA _score' is disabled", EsqlCapabilities.Cap.METADATA_SCORE.isEnabled()); var plan = physicalPlan(""" from test metadata _score | where match(first_name, "john") 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 efa3226ee330..47e1616060bd 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 @@ -1081,15 +1081,28 @@ public class StatementParserTests extends AbstractStatementParserTests { 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, found [foo*]"); + expectError("from a | enrich countries on * ", "Using wildcards [*] in ENRICH WITH projections is not allowed, found [*]"); + expectError( + "from a | enrich countries on foo with bar*", + "Using wildcards [*] in ENRICH WITH projections is not allowed, found [bar*]" + ); + expectError("from a | enrich countries on foo with *", "Using wildcards [*] in ENRICH WITH projections is not allowed, found [*]"); 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, found [bar*]" + ); + expectError( + "from a | enrich countries on foo with x = * ", + "Using wildcards [*] in ENRICH WITH projections is not allowed, found [*]" ); 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, found [x*]" + ); + expectError( + "from a | enrich countries on foo with * = bar ", + "Using wildcards [*] in ENRICH WITH projections is not allowed, found [*]" ); expectError( "from a | enrich typo:countries on foo", @@ -1587,10 +1600,6 @@ public class StatementParserTests extends AbstractStatementParserTests { } public void testParamForIdentifier() { - assumeTrue( - "named parameters for identifiers and patterns require snapshot build", - EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - ); // field names can appear in eval/where/stats/sort/keep/drop/rename/dissect/grok/enrich/mvexpand // eval, where assertEquals( @@ -1848,10 +1857,6 @@ public class StatementParserTests extends AbstractStatementParserTests { } public void testParamForIdentifierPattern() { - assumeTrue( - "named parameters for identifiers and patterns require snapshot build", - EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - ); // name patterns can appear in keep and drop // all patterns LogicalPlan plan = statement( @@ -1941,10 +1946,6 @@ public class StatementParserTests extends AbstractStatementParserTests { } public void testParamInInvalidPosition() { - assumeTrue( - "named parameters for identifiers and patterns require snapshot build", - EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - ); // param for pattern is not supported in eval/where/stats/sort/rename/dissect/grok/enrich/mvexpand // where/stats/sort/dissect/grok are covered in RestEsqlTestCase List invalidParamPositions = List.of("eval ?f1 = 1", "stats x = ?f1(*)", "mv_expand ?f1", "rename ?f1 as ?f2"); @@ -1985,7 +1986,7 @@ public class StatementParserTests extends AbstractStatementParserTests { expectError( "from idx1 | " + enrich, List.of(paramAsPattern("f1", pattern), paramAsIdentifier("f2", "f.2"), paramAsIdentifier("f3", "f.3*")), - "Using wildcards [*] in ENRICH WITH projections is not allowed [" + pattern + "]" + "Using wildcards [*] in ENRICH WITH projections is not allowed, found [" + pattern + "]" ); expectError( "from idx1 | " + enrich, @@ -1996,10 +1997,6 @@ public class StatementParserTests extends AbstractStatementParserTests { } public void testMissingParam() { - assumeTrue( - "named parameters for identifiers and patterns require snapshot build", - EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - ); // cover all processing commands eval/where/stats/sort/rename/dissect/grok/enrich/mvexpand/keep/drop String error = "Unknown query parameter [f1], did you mean [f4]?"; String errorMvExpandFunctionNameCommandOption = "Query parameter [?f1] is null or undefined, cannot be used as an identifier"; @@ -2294,6 +2291,10 @@ public class StatementParserTests extends AbstractStatementParserTests { expectError("from test | eval A = coalesce(\"Å\", Å)", "line 1:36: token recognition error at: 'Å'"); } + public void testInvalidRemoteClusterPattern() { + expectError("from \"rem:ote\":index", "cluster string [rem:ote] must not contain ':'"); + } + private LogicalPlan unresolvedRelation(String index) { return new UnresolvedRelation(EMPTY, new IndexPattern(EMPTY, index), false, List.of(), IndexMode.STANDARD, null, "FROM"); } @@ -2481,10 +2482,6 @@ public class StatementParserTests extends AbstractStatementParserTests { public void testNamedFunctionArgumentInMapWithNamedParameters() { // map entry values provided in named parameter, arrays are not supported by named parameters yet - assumeTrue( - "named parameters for identifiers and patterns require snapshot build", - EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - ); LinkedHashMap expectedMap1 = new LinkedHashMap<>(4); expectedMap1.put("option1", "string"); expectedMap1.put("option2", 1); @@ -2892,10 +2889,6 @@ public class StatementParserTests extends AbstractStatementParserTests { } public void testNamedFunctionArgumentWithUnsupportedNamedParameterTypes() { - assumeTrue( - "named parameters for identifiers and patterns require snapshot build", - EsqlCapabilities.Cap.NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES_SIMPLIFIED_SYNTAX.isEnabled() - ); Map commands = Map.ofEntries( Map.entry("eval x = {}", "29"), Map.entry("where {}", "26"), diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/physical/OrderExecSerializationTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/physical/OrderExecSerializationTests.java deleted file mode 100644 index 755f1cd4f52d..000000000000 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/physical/OrderExecSerializationTests.java +++ /dev/null @@ -1,46 +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.plan.physical; - -import org.elasticsearch.xpack.esql.core.tree.Source; -import org.elasticsearch.xpack.esql.expression.Order; -import org.elasticsearch.xpack.esql.expression.OrderSerializationTests; - -import java.io.IOException; -import java.util.List; - -public class OrderExecSerializationTests extends AbstractPhysicalPlanSerializationTests { - public static OrderExec randomOrderExec(int depth) { - Source source = randomSource(); - PhysicalPlan child = randomChild(depth); - List order = randomList(1, 10, OrderSerializationTests::randomOrder); - return new OrderExec(source, child, order); - } - - @Override - protected OrderExec createTestInstance() { - return randomOrderExec(0); - } - - @Override - protected OrderExec mutateInstance(OrderExec instance) throws IOException { - PhysicalPlan child = instance.child(); - List order = instance.order(); - if (randomBoolean()) { - child = randomValueOtherThan(child, () -> randomChild(0)); - } else { - order = randomValueOtherThan(order, () -> randomList(1, 10, OrderSerializationTests::randomOrder)); - } - return new OrderExec(instance.source(), child, order); - } - - @Override - protected boolean alwaysEmptySource() { - return true; - } -} diff --git a/x-pack/plugin/inference/qa/inference-service-tests/src/javaRestTest/java/org/elasticsearch/xpack/inference/InferenceBaseRestTest.java b/x-pack/plugin/inference/qa/inference-service-tests/src/javaRestTest/java/org/elasticsearch/xpack/inference/InferenceBaseRestTest.java index 950ff196e513..36a4b95a7ca2 100644 --- a/x-pack/plugin/inference/qa/inference-service-tests/src/javaRestTest/java/org/elasticsearch/xpack/inference/InferenceBaseRestTest.java +++ b/x-pack/plugin/inference/qa/inference-service-tests/src/javaRestTest/java/org/elasticsearch/xpack/inference/InferenceBaseRestTest.java @@ -360,8 +360,7 @@ public class InferenceBaseRestTest extends ESRestTestCase { List input, @Nullable Consumer responseConsumerCallback ) throws Exception { - var route = randomBoolean() ? "_stream" : "_unified"; // TODO remove unified route - var endpoint = Strings.format("_inference/%s/%s/%s", taskType, modelId, route); + var endpoint = Strings.format("_inference/%s/%s/_stream", taskType, modelId); return callAsyncUnified(endpoint, input, "user", responseConsumerCallback); } diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/InferenceRevokeDefaultEndpointsIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/InferenceRevokeDefaultEndpointsIT.java new file mode 100644 index 000000000000..0fa8d39d4c89 --- /dev/null +++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/InferenceRevokeDefaultEndpointsIT.java @@ -0,0 +1,271 @@ +/* + * 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.integration; + +import org.elasticsearch.ResourceNotFoundException; +import org.elasticsearch.action.support.PlainActionFuture; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.core.TimeValue; +import org.elasticsearch.inference.InferenceService; +import org.elasticsearch.inference.MinimalServiceSettings; +import org.elasticsearch.inference.Model; +import org.elasticsearch.inference.TaskType; +import org.elasticsearch.inference.UnparsedModel; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.reindex.ReindexPlugin; +import org.elasticsearch.test.ESSingleNodeTestCase; +import org.elasticsearch.test.http.MockResponse; +import org.elasticsearch.test.http.MockWebServer; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.xpack.inference.external.http.HttpClientManager; +import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSenderTests; +import org.elasticsearch.xpack.inference.logging.ThrottlerManager; +import org.elasticsearch.xpack.inference.registry.ModelRegistry; +import org.elasticsearch.xpack.inference.services.elastic.ElasticInferenceService; +import org.elasticsearch.xpack.inference.services.elastic.ElasticInferenceServiceComponents; +import org.elasticsearch.xpack.inference.services.elastic.authorization.ElasticInferenceServiceAuthorizationHandler; +import org.junit.After; +import org.junit.Before; + +import java.util.Collection; +import java.util.EnumSet; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static org.elasticsearch.xpack.inference.Utils.inferenceUtilityPool; +import static org.elasticsearch.xpack.inference.Utils.mockClusterServiceEmpty; +import static org.elasticsearch.xpack.inference.external.http.Utils.getUrl; +import static org.elasticsearch.xpack.inference.services.ServiceComponentsTests.createWithEmptySettings; +import static org.hamcrest.CoreMatchers.is; +import static org.mockito.Mockito.mock; + +public class InferenceRevokeDefaultEndpointsIT extends ESSingleNodeTestCase { + private static final TimeValue TIMEOUT = new TimeValue(30, TimeUnit.SECONDS); + + private ModelRegistry modelRegistry; + private final MockWebServer webServer = new MockWebServer(); + private ThreadPool threadPool; + private String gatewayUrl; + + @Before + public void createComponents() throws Exception { + threadPool = createThreadPool(inferenceUtilityPool()); + webServer.start(); + gatewayUrl = getUrl(webServer); + modelRegistry = new ModelRegistry(client()); + } + + @After + public void shutdown() { + terminate(threadPool); + webServer.close(); + } + + @Override + protected boolean resetNodeAfterTest() { + return true; + } + + @Override + protected Collection> getPlugins() { + return pluginList(ReindexPlugin.class); + } + + public void testDefaultConfigs_Returns_DefaultChatCompletion_V1_WhenTaskTypeIsCorrect() throws Exception { + String responseJson = """ + { + "models": [ + { + "model_name": "rainbow-sprinkles", + "task_types": ["chat"] + } + ] + } + """; + + webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseJson)); + + try (var service = createElasticInferenceService()) { + service.waitForAuthorizationToComplete(TIMEOUT); + assertThat(service.supportedStreamingTasks(), is(EnumSet.of(TaskType.CHAT_COMPLETION))); + assertThat( + service.defaultConfigIds(), + is( + List.of( + new InferenceService.DefaultConfigId(".rainbow-sprinkles-elastic", MinimalServiceSettings.chatCompletion(), service) + ) + ) + ); + assertThat(service.supportedTaskTypes(), is(EnumSet.of(TaskType.CHAT_COMPLETION))); + + PlainActionFuture> listener = new PlainActionFuture<>(); + service.defaultConfigs(listener); + assertThat(listener.actionGet(TIMEOUT).get(0).getConfigurations().getInferenceEntityId(), is(".rainbow-sprinkles-elastic")); + } + } + + public void testRemoves_DefaultChatCompletion_V1_WhenAuthorizationReturnsEmpty() throws Exception { + { + String responseJson = """ + { + "models": [ + { + "model_name": "rainbow-sprinkles", + "task_types": ["chat"] + } + ] + } + """; + + webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseJson)); + + try (var service = createElasticInferenceService()) { + service.waitForAuthorizationToComplete(TIMEOUT); + assertThat(service.supportedStreamingTasks(), is(EnumSet.of(TaskType.CHAT_COMPLETION))); + assertThat( + service.defaultConfigIds(), + is( + List.of( + new InferenceService.DefaultConfigId( + ".rainbow-sprinkles-elastic", + MinimalServiceSettings.chatCompletion(), + service + ) + ) + ) + ); + assertThat(service.supportedTaskTypes(), is(EnumSet.of(TaskType.CHAT_COMPLETION))); + + PlainActionFuture> listener = new PlainActionFuture<>(); + service.defaultConfigs(listener); + assertThat(listener.actionGet(TIMEOUT).get(0).getConfigurations().getInferenceEntityId(), is(".rainbow-sprinkles-elastic")); + + var getModelListener = new PlainActionFuture(); + // persists the default endpoints + modelRegistry.getModel(".rainbow-sprinkles-elastic", getModelListener); + + var inferenceEntity = getModelListener.actionGet(TIMEOUT); + assertThat(inferenceEntity.inferenceEntityId(), is(".rainbow-sprinkles-elastic")); + assertThat(inferenceEntity.taskType(), is(TaskType.CHAT_COMPLETION)); + } + } + { + String noAuthorizationResponseJson = """ + { + "models": [] + } + """; + + webServer.enqueue(new MockResponse().setResponseCode(200).setBody(noAuthorizationResponseJson)); + + try (var service = createElasticInferenceService()) { + service.waitForAuthorizationToComplete(TIMEOUT); + assertThat(service.supportedStreamingTasks(), is(EnumSet.noneOf(TaskType.class))); + assertTrue(service.defaultConfigIds().isEmpty()); + assertThat(service.supportedTaskTypes(), is(EnumSet.noneOf(TaskType.class))); + + var getModelListener = new PlainActionFuture(); + modelRegistry.getModel(".rainbow-sprinkles-elastic", getModelListener); + + var exception = expectThrows(ResourceNotFoundException.class, () -> getModelListener.actionGet(TIMEOUT)); + assertThat(exception.getMessage(), is("Inference endpoint not found [.rainbow-sprinkles-elastic]")); + } + } + } + + public void testRemoves_DefaultChatCompletion_V1_WhenAuthorizationDoesNotReturnAuthForIt() throws Exception { + { + String responseJson = """ + { + "models": [ + { + "model_name": "rainbow-sprinkles", + "task_types": ["chat"] + }, + { + "model_name": "elser-v2", + "task_types": ["embed/text/sparse"] + } + ] + } + """; + + webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseJson)); + + try (var service = createElasticInferenceService()) { + service.waitForAuthorizationToComplete(TIMEOUT); + assertThat(service.supportedStreamingTasks(), is(EnumSet.of(TaskType.CHAT_COMPLETION))); + assertThat( + service.defaultConfigIds(), + is( + List.of( + new InferenceService.DefaultConfigId( + ".rainbow-sprinkles-elastic", + MinimalServiceSettings.chatCompletion(), + service + ) + ) + ) + ); + assertThat(service.supportedTaskTypes(), is(EnumSet.of(TaskType.CHAT_COMPLETION, TaskType.SPARSE_EMBEDDING))); + + PlainActionFuture> listener = new PlainActionFuture<>(); + service.defaultConfigs(listener); + assertThat(listener.actionGet(TIMEOUT).get(0).getConfigurations().getInferenceEntityId(), is(".rainbow-sprinkles-elastic")); + + var getModelListener = new PlainActionFuture(); + // persists the default endpoints + modelRegistry.getModel(".rainbow-sprinkles-elastic", getModelListener); + + var inferenceEntity = getModelListener.actionGet(TIMEOUT); + assertThat(inferenceEntity.inferenceEntityId(), is(".rainbow-sprinkles-elastic")); + assertThat(inferenceEntity.taskType(), is(TaskType.CHAT_COMPLETION)); + } + } + { + String noAuthorizationResponseJson = """ + { + "models": [ + { + "model_name": "elser-v2", + "task_types": ["embed/text/sparse"] + } + ] + } + """; + + webServer.enqueue(new MockResponse().setResponseCode(200).setBody(noAuthorizationResponseJson)); + + try (var service = createElasticInferenceService()) { + service.waitForAuthorizationToComplete(TIMEOUT); + assertThat(service.supportedStreamingTasks(), is(EnumSet.noneOf(TaskType.class))); + assertTrue(service.defaultConfigIds().isEmpty()); + assertThat(service.supportedTaskTypes(), is(EnumSet.of(TaskType.SPARSE_EMBEDDING))); + + var getModelListener = new PlainActionFuture(); + modelRegistry.getModel(".rainbow-sprinkles-elastic", getModelListener); + + var exception = expectThrows(ResourceNotFoundException.class, () -> getModelListener.actionGet(TIMEOUT)); + assertThat(exception.getMessage(), is("Inference endpoint not found [.rainbow-sprinkles-elastic]")); + } + } + } + + private ElasticInferenceService createElasticInferenceService() { + var httpManager = HttpClientManager.create(Settings.EMPTY, threadPool, mockClusterServiceEmpty(), mock(ThrottlerManager.class)); + var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, httpManager); + + return new ElasticInferenceService( + senderFactory, + createWithEmptySettings(threadPool), + new ElasticInferenceServiceComponents(gatewayUrl), + modelRegistry, + new ElasticInferenceServiceAuthorizationHandler(gatewayUrl, threadPool) + ); + } +} diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/ModelRegistryIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/ModelRegistryIT.java index 51ee42cf2f7f..4fad6977ab85 100644 --- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/ModelRegistryIT.java +++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/ModelRegistryIT.java @@ -10,10 +10,12 @@ package org.elasticsearch.xpack.inference.integration; import org.elasticsearch.ElasticsearchStatusException; import org.elasticsearch.TransportVersion; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.client.internal.Client; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper; import org.elasticsearch.inference.InferenceService; @@ -51,7 +53,9 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; @@ -70,6 +74,7 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; public class ModelRegistryIT extends ESSingleNodeTestCase { + private static final TimeValue TIMEOUT = new TimeValue(30, TimeUnit.SECONDS); private ModelRegistry modelRegistry; @@ -195,6 +200,56 @@ public class ModelRegistryIT extends ESSingleNodeTestCase { assertThat(exceptionHolder.get().getMessage(), containsString("Inference endpoint not found [model1]")); } + public void testNonExistentDeleteModel_DoesNotThrowAnException() { + var listener = new PlainActionFuture(); + + modelRegistry.deleteModel("non-existent-model", listener); + assertTrue(listener.actionGet(TIMEOUT)); + } + + public void testRemoveDefaultConfigs_DoesNotThrowAnException_WhenSearchingForNonExistentInferenceEndpointIds() { + var listener = new PlainActionFuture(); + + modelRegistry.deleteModels(Set.of("non-existent-model", "abc"), listener); + assertTrue(listener.actionGet(TIMEOUT)); + } + + public void testRemoveDefaultConfigs_RemovesModelsFromPersistentStorage_AndInMemoryCache() { + var service = mock(InferenceService.class); + + var defaultConfigs = new ArrayList(); + var defaultIds = new ArrayList(); + for (var id : new String[] { "model1", "model2", "model3" }) { + var modelSettings = ModelRegistryTests.randomMinimalServiceSettings(); + defaultConfigs.add(createModel(id, modelSettings.taskType(), "name")); + defaultIds.add(new InferenceService.DefaultConfigId(id, modelSettings, service)); + } + + doAnswer(invocation -> { + ActionListener> listener = invocation.getArgument(0); + listener.onResponse(defaultConfigs); + return Void.TYPE; + }).when(service).defaultConfigs(any()); + + defaultIds.forEach(modelRegistry::addDefaultIds); + + var getModelsListener = new PlainActionFuture>(); + modelRegistry.getAllModels(true, getModelsListener); + var unparsedModels = getModelsListener.actionGet(TIMEOUT); + assertThat(unparsedModels.size(), is(3)); + + var removeModelsListener = new PlainActionFuture(); + + modelRegistry.removeDefaultConfigs(Set.of("model1", "model2", "model3"), removeModelsListener); + assertTrue(removeModelsListener.actionGet(TIMEOUT)); + + var getModelsAfterDeleteListener = new PlainActionFuture>(); + // the models should have been removed from the in memory cache, if not they they will be persisted again by this call + modelRegistry.getAllModels(true, getModelsAfterDeleteListener); + var unparsedModelsAfterDelete = getModelsAfterDeleteListener.actionGet(TIMEOUT); + assertThat(unparsedModelsAfterDelete.size(), is(0)); + } + public void testGetModelsByTaskType() throws InterruptedException { var service = "foo"; var sparseAndTextEmbeddingModels = new ArrayList(); @@ -315,8 +370,7 @@ public class ModelRegistryIT extends ESSingleNodeTestCase { } doAnswer(invocation -> { - @SuppressWarnings("unchecked") - var listener = (ActionListener>) invocation.getArguments()[0]; + ActionListener> listener = invocation.getArgument(0); listener.onResponse(defaultConfigs); return Void.TYPE; }).when(service).defaultConfigs(any()); @@ -381,8 +435,7 @@ public class ModelRegistryIT extends ESSingleNodeTestCase { } doAnswer(invocation -> { - @SuppressWarnings("unchecked") - var listener = (ActionListener>) invocation.getArguments()[0]; + ActionListener> listener = invocation.getArgument(0); listener.onResponse(defaultConfigs); return Void.TYPE; }).when(service).defaultConfigs(any()); @@ -424,8 +477,7 @@ public class ModelRegistryIT extends ESSingleNodeTestCase { } doAnswer(invocation -> { - @SuppressWarnings("unchecked") - var listener = (ActionListener>) invocation.getArguments()[0]; + ActionListener> listener = invocation.getArgument(0); listener.onResponse(defaultConfigs); return Void.TYPE; }).when(service).defaultConfigs(any()); @@ -469,8 +521,7 @@ public class ModelRegistryIT extends ESSingleNodeTestCase { ); doAnswer(invocation -> { - @SuppressWarnings("unchecked") - var listener = (ActionListener>) invocation.getArguments()[0]; + ActionListener> listener = invocation.getArgument(0); listener.onResponse(defaultConfigs); return Void.TYPE; }).when(service).defaultConfigs(any()); @@ -523,8 +574,7 @@ public class ModelRegistryIT extends ESSingleNodeTestCase { defaultIds.add(new InferenceService.DefaultConfigId("default-chat", MinimalServiceSettings.completion(), service)); doAnswer(invocation -> { - @SuppressWarnings("unchecked") - var listener = (ActionListener>) invocation.getArguments()[0]; + ActionListener> listener = invocation.getArgument(0); listener.onResponse(List.of(defaultSparse, defaultChat, defaultText)); return Void.TYPE; }).when(service).defaultConfigs(any()); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java index d63e3f773b14..e8fcb8dfe117 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java @@ -36,6 +36,7 @@ public class InferenceFeatures implements FeatureSpecification { SemanticTextFieldMapper.SEMANTIC_TEXT_DELETE_FIX, SemanticTextFieldMapper.SEMANTIC_TEXT_ZERO_SIZE_FIX, SemanticTextFieldMapper.SEMANTIC_TEXT_ALWAYS_EMIT_INFERENCE_ID_FIX, + SemanticTextFieldMapper.SEMANTIC_TEXT_SKIP_INFERENCE_FIELDS, SEMANTIC_TEXT_HIGHLIGHTER, SEMANTIC_MATCH_QUERY_REWRITE_INTERCEPTION_SUPPORTED, SEMANTIC_SPARSE_VECTOR_QUERY_REWRITE_INTERCEPTION_SUPPORTED, 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 23df62caab43..e3604351c193 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 @@ -58,6 +58,7 @@ import org.elasticsearch.xpack.core.inference.action.GetInferenceDiagnosticsActi import org.elasticsearch.xpack.core.inference.action.GetInferenceModelAction; import org.elasticsearch.xpack.core.inference.action.GetInferenceServicesAction; import org.elasticsearch.xpack.core.inference.action.InferenceAction; +import org.elasticsearch.xpack.core.inference.action.InferenceActionProxy; import org.elasticsearch.xpack.core.inference.action.PutInferenceModelAction; import org.elasticsearch.xpack.core.inference.action.UnifiedCompletionAction; import org.elasticsearch.xpack.core.inference.action.UpdateInferenceModelAction; @@ -67,6 +68,7 @@ import org.elasticsearch.xpack.inference.action.TransportGetInferenceDiagnostics import org.elasticsearch.xpack.inference.action.TransportGetInferenceModelAction; import org.elasticsearch.xpack.inference.action.TransportGetInferenceServicesAction; import org.elasticsearch.xpack.inference.action.TransportInferenceAction; +import org.elasticsearch.xpack.inference.action.TransportInferenceActionProxy; import org.elasticsearch.xpack.inference.action.TransportInferenceUsageAction; import org.elasticsearch.xpack.inference.action.TransportPutInferenceModelAction; import org.elasticsearch.xpack.inference.action.TransportUnifiedCompletionInferenceAction; @@ -104,7 +106,6 @@ import org.elasticsearch.xpack.inference.rest.RestGetInferenceServicesAction; import org.elasticsearch.xpack.inference.rest.RestInferenceAction; import org.elasticsearch.xpack.inference.rest.RestPutInferenceModelAction; import org.elasticsearch.xpack.inference.rest.RestStreamInferenceAction; -import org.elasticsearch.xpack.inference.rest.RestUnifiedCompletionInferenceAction; import org.elasticsearch.xpack.inference.rest.RestUpdateInferenceModelAction; import org.elasticsearch.xpack.inference.services.ServiceComponents; import org.elasticsearch.xpack.inference.services.alibabacloudsearch.AlibabaCloudSearchService; @@ -195,6 +196,7 @@ public class InferencePlugin extends Plugin public List> getActions() { return List.of( new ActionHandler<>(InferenceAction.INSTANCE, TransportInferenceAction.class), + new ActionHandler<>(InferenceActionProxy.INSTANCE, TransportInferenceActionProxy.class), new ActionHandler<>(GetInferenceModelAction.INSTANCE, TransportGetInferenceModelAction.class), new ActionHandler<>(PutInferenceModelAction.INSTANCE, TransportPutInferenceModelAction.class), new ActionHandler<>(UpdateInferenceModelAction.INSTANCE, TransportUpdateInferenceModelAction.class), @@ -226,8 +228,7 @@ public class InferencePlugin extends Plugin new RestUpdateInferenceModelAction(), new RestDeleteInferenceEndpointAction(), new RestGetInferenceDiagnosticsAction(), - new RestGetInferenceServicesAction(), - new RestUnifiedCompletionInferenceAction(threadPoolSetOnce) + new RestGetInferenceServicesAction() ); } diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportDeleteInferenceEndpointAction.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportDeleteInferenceEndpointAction.java index 242c2f79733e..3b6901ae0c31 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportDeleteInferenceEndpointAction.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportDeleteInferenceEndpointAction.java @@ -88,6 +88,17 @@ public class TransportDeleteInferenceEndpointAction extends TransportMasterNodeA ClusterState state, ActionListener masterListener ) { + if (modelRegistry.containsDefaultConfigId(request.getInferenceEndpointId())) { + masterListener.onFailure( + new ElasticsearchStatusException( + "[{}] is a reserved inference endpoint. Cannot delete a reserved inference endpoint.", + RestStatus.BAD_REQUEST, + request.getInferenceEndpointId() + ) + ); + return; + } + SubscribableListener.newForked(modelConfigListener -> { // Get the model from the registry diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportInferenceActionProxy.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportInferenceActionProxy.java new file mode 100644 index 000000000000..6d46f834d487 --- /dev/null +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/TransportInferenceActionProxy.java @@ -0,0 +1,125 @@ +/* + * 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.ElasticsearchStatusException; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.HandledTransportAction; +import org.elasticsearch.client.internal.Client; +import org.elasticsearch.common.util.concurrent.EsExecutors; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.inference.TaskType; +import org.elasticsearch.inference.UnparsedModel; +import org.elasticsearch.injection.guice.Inject; +import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.tasks.Task; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xcontent.XContentParserConfiguration; +import org.elasticsearch.xpack.core.inference.action.InferenceAction; +import org.elasticsearch.xpack.core.inference.action.InferenceActionProxy; +import org.elasticsearch.xpack.core.inference.action.UnifiedCompletionAction; +import org.elasticsearch.xpack.core.inference.results.UnifiedChatCompletionException; +import org.elasticsearch.xpack.inference.registry.ModelRegistry; + +import java.io.IOException; + +import static org.elasticsearch.xpack.core.ClientHelper.INFERENCE_ORIGIN; +import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin; + +public class TransportInferenceActionProxy extends HandledTransportAction { + private final ModelRegistry modelRegistry; + private final Client client; + + @Inject + public TransportInferenceActionProxy( + TransportService transportService, + ActionFilters actionFilters, + ModelRegistry modelRegistry, + Client client + ) { + super( + InferenceActionProxy.NAME, + transportService, + actionFilters, + InferenceActionProxy.Request::new, + EsExecutors.DIRECT_EXECUTOR_SERVICE + ); + + this.modelRegistry = modelRegistry; + this.client = client; + } + + @Override + protected void doExecute(Task task, InferenceActionProxy.Request request, ActionListener listener) { + try { + ActionListener getModelListener = listener.delegateFailureAndWrap((l, unparsedModel) -> { + if (unparsedModel.taskType() == TaskType.CHAT_COMPLETION) { + sendUnifiedCompletionRequest(request, l); + } else { + sendInferenceActionRequest(request, l); + } + }); + + if (request.getTaskType() == TaskType.ANY) { + modelRegistry.getModelWithSecrets(request.getInferenceEntityId(), getModelListener); + } else if (request.getTaskType() == TaskType.CHAT_COMPLETION) { + sendUnifiedCompletionRequest(request, listener); + } else { + sendInferenceActionRequest(request, listener); + } + } catch (Exception e) { + listener.onFailure(e); + } + } + + private void sendUnifiedCompletionRequest(InferenceActionProxy.Request request, ActionListener listener) { + // format any validation exceptions from the rest -> transport path as UnifiedChatCompletionException + var unifiedErrorFormatListener = listener.delegateResponse((l, e) -> l.onFailure(UnifiedChatCompletionException.fromThrowable(e))); + + try { + if (request.isStreaming() == false) { + throw new ElasticsearchStatusException( + "The [chat_completion] task type only supports streaming, please try again with the _stream API", + RestStatus.BAD_REQUEST + ); + } + + UnifiedCompletionAction.Request unifiedRequest; + try ( + var parser = XContentHelper.createParser(XContentParserConfiguration.EMPTY, request.getContent(), request.getContentType()) + ) { + unifiedRequest = UnifiedCompletionAction.Request.parseRequest( + request.getInferenceEntityId(), + request.getTaskType(), + request.getTimeout(), + parser + ); + } + + executeAsyncWithOrigin(client, INFERENCE_ORIGIN, UnifiedCompletionAction.INSTANCE, unifiedRequest, unifiedErrorFormatListener); + } catch (Exception e) { + unifiedErrorFormatListener.onFailure(e); + } + } + + private void sendInferenceActionRequest(InferenceActionProxy.Request request, ActionListener listener) + throws IOException { + InferenceAction.Request.Builder inferenceActionRequestBuilder; + try (var parser = XContentHelper.createParser(XContentParserConfiguration.EMPTY, request.getContent(), request.getContentType())) { + inferenceActionRequestBuilder = InferenceAction.Request.parseRequest( + request.getInferenceEntityId(), + request.getTaskType(), + parser + ); + inferenceActionRequestBuilder.setInferenceTimeout(request.getTimeout()).setStream(request.isStreaming()); + } + + executeAsyncWithOrigin(client, INFERENCE_ORIGIN, InferenceAction.INSTANCE, inferenceActionRequestBuilder.build(), listener); + } +} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/elastic/ElasticInferenceServiceUnifiedChatCompletionResponseHandler.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/elastic/ElasticInferenceServiceUnifiedChatCompletionResponseHandler.java index db09317b7b79..a240035468b8 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/elastic/ElasticInferenceServiceUnifiedChatCompletionResponseHandler.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/elastic/ElasticInferenceServiceUnifiedChatCompletionResponseHandler.java @@ -8,6 +8,7 @@ package org.elasticsearch.xpack.inference.external.elastic; import org.elasticsearch.inference.InferenceServiceResults; +import org.elasticsearch.rest.RestStatus; import org.elasticsearch.xpack.core.inference.results.StreamingUnifiedChatCompletionResults; import org.elasticsearch.xpack.core.inference.results.UnifiedChatCompletionException; import org.elasticsearch.xpack.inference.external.http.HttpResult; @@ -15,12 +16,15 @@ import org.elasticsearch.xpack.inference.external.http.retry.ErrorResponse; import org.elasticsearch.xpack.inference.external.http.retry.ResponseParser; import org.elasticsearch.xpack.inference.external.openai.OpenAiUnifiedStreamingProcessor; import org.elasticsearch.xpack.inference.external.request.Request; +import org.elasticsearch.xpack.inference.external.response.elastic.ElasticInferenceServiceErrorResponseEntity; import org.elasticsearch.xpack.inference.external.response.streaming.ServerSentEventParser; import org.elasticsearch.xpack.inference.external.response.streaming.ServerSentEventProcessor; import java.util.Locale; import java.util.concurrent.Flow; +import static org.elasticsearch.core.Strings.format; + public class ElasticInferenceServiceUnifiedChatCompletionResponseHandler extends ElasticInferenceServiceResponseHandler { public ElasticInferenceServiceUnifiedChatCompletionResponseHandler(String requestType, ResponseParser parseFunction) { super(requestType, parseFunction, true); @@ -29,7 +33,8 @@ public class ElasticInferenceServiceUnifiedChatCompletionResponseHandler extends @Override public InferenceServiceResults parseResult(Request request, Flow.Publisher flow) { var serverSentEventProcessor = new ServerSentEventProcessor(new ServerSentEventParser()); - var openAiProcessor = new OpenAiUnifiedStreamingProcessor(); // EIS uses the unified API spec + // EIS uses the unified API spec + var openAiProcessor = new OpenAiUnifiedStreamingProcessor((m, e) -> buildMidStreamError(request, m, e)); flow.subscribe(serverSentEventProcessor); serverSentEventProcessor.subscribe(openAiProcessor); @@ -52,4 +57,30 @@ public class ElasticInferenceServiceUnifiedChatCompletionResponseHandler extends return super.buildError(message, request, result, errorResponse); } } + + private static Exception buildMidStreamError(Request request, String message, Exception e) { + var errorResponse = ElasticInferenceServiceErrorResponseEntity.fromString(message); + if (errorResponse.errorStructureFound()) { + return new UnifiedChatCompletionException( + RestStatus.INTERNAL_SERVER_ERROR, + format( + "%s for request from inference entity id [%s]. Error message: [%s]", + SERVER_ERROR_OBJECT, + request.getInferenceEntityId(), + errorResponse.getErrorMessage() + ), + "error", + "stream_error" + ); + } else if (e != null) { + return UnifiedChatCompletionException.fromThrowable(e); + } else { + return new UnifiedChatCompletionException( + RestStatus.INTERNAL_SERVER_ERROR, + format("%s for request from inference entity id [%s]", SERVER_ERROR_OBJECT, request.getInferenceEntityId()), + "error", + "stream_error" + ); + } + } } diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/openai/OpenAiUnifiedChatCompletionResponseHandler.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/openai/OpenAiUnifiedChatCompletionResponseHandler.java index 2901b449f8a6..b2096253bdeb 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/openai/OpenAiUnifiedChatCompletionResponseHandler.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/openai/OpenAiUnifiedChatCompletionResponseHandler.java @@ -9,6 +9,7 @@ package org.elasticsearch.xpack.inference.external.openai; import org.elasticsearch.core.Nullable; import org.elasticsearch.inference.InferenceServiceResults; +import org.elasticsearch.rest.RestStatus; import org.elasticsearch.xcontent.ConstructingObjectParser; import org.elasticsearch.xcontent.ParseField; import org.elasticsearch.xcontent.XContentFactory; @@ -29,6 +30,8 @@ import java.util.Objects; import java.util.Optional; import java.util.concurrent.Flow; +import static org.elasticsearch.core.Strings.format; + public class OpenAiUnifiedChatCompletionResponseHandler extends OpenAiChatCompletionResponseHandler { public OpenAiUnifiedChatCompletionResponseHandler(String requestType, ResponseParser parseFunction) { super(requestType, parseFunction, OpenAiErrorResponse::fromResponse); @@ -37,7 +40,7 @@ public class OpenAiUnifiedChatCompletionResponseHandler extends OpenAiChatComple @Override public InferenceServiceResults parseResult(Request request, Flow.Publisher flow) { var serverSentEventProcessor = new ServerSentEventProcessor(new ServerSentEventParser()); - var openAiProcessor = new OpenAiUnifiedStreamingProcessor(); + var openAiProcessor = new OpenAiUnifiedStreamingProcessor((m, e) -> buildMidStreamError(request, m, e)); flow.subscribe(serverSentEventProcessor); serverSentEventProcessor.subscribe(openAiProcessor); @@ -64,6 +67,33 @@ public class OpenAiUnifiedChatCompletionResponseHandler extends OpenAiChatComple } } + private static Exception buildMidStreamError(Request request, String message, Exception e) { + var errorResponse = OpenAiErrorResponse.fromString(message); + if (errorResponse instanceof OpenAiErrorResponse oer) { + return new UnifiedChatCompletionException( + RestStatus.INTERNAL_SERVER_ERROR, + format( + "%s for request from inference entity id [%s]. Error message: [%s]", + SERVER_ERROR_OBJECT, + request.getInferenceEntityId(), + errorResponse.getErrorMessage() + ), + oer.type(), + oer.code(), + oer.param() + ); + } else if (e != null) { + return UnifiedChatCompletionException.fromThrowable(e); + } else { + return new UnifiedChatCompletionException( + RestStatus.INTERNAL_SERVER_ERROR, + format("%s for request from inference entity id [%s]", SERVER_ERROR_OBJECT, request.getInferenceEntityId()), + errorResponse != null ? errorResponse.getClass().getSimpleName() : "unknown", + "stream_error" + ); + } + } + private static class OpenAiErrorResponse extends ErrorResponse { private static final ConstructingObjectParser, Void> ERROR_PARSER = new ConstructingObjectParser<>( "open_ai_error", @@ -103,6 +133,19 @@ public class OpenAiUnifiedChatCompletionResponseHandler extends OpenAiChatComple return ErrorResponse.UNDEFINED_ERROR; } + private static ErrorResponse fromString(String response) { + try ( + XContentParser parser = XContentFactory.xContent(XContentType.JSON) + .createParser(XContentParserConfiguration.EMPTY, response) + ) { + return ERROR_PARSER.apply(parser, null).orElse(ErrorResponse.UNDEFINED_ERROR); + } catch (Exception e) { + // swallow the error + } + + return ErrorResponse.UNDEFINED_ERROR; + } + @Nullable private final String code; @Nullable diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/openai/OpenAiUnifiedStreamingProcessor.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/openai/OpenAiUnifiedStreamingProcessor.java index 599d71df3dcf..bfd4456279a8 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/openai/OpenAiUnifiedStreamingProcessor.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/openai/OpenAiUnifiedStreamingProcessor.java @@ -20,6 +20,7 @@ import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.results.StreamingUnifiedChatCompletionResults; import org.elasticsearch.xpack.inference.common.DelegatingProcessor; import org.elasticsearch.xpack.inference.external.response.streaming.ServerSentEvent; +import org.elasticsearch.xpack.inference.external.response.streaming.ServerSentEventField; import java.io.IOException; import java.util.ArrayDeque; @@ -28,6 +29,7 @@ import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.concurrent.LinkedBlockingDeque; +import java.util.function.BiFunction; import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken; import static org.elasticsearch.xpack.inference.external.response.XContentUtils.moveToFirstToken; @@ -57,7 +59,13 @@ public class OpenAiUnifiedStreamingProcessor extends DelegatingProcessor errorParser; private final Deque buffer = new LinkedBlockingDeque<>(); + private volatile boolean previousEventWasError = false; + + public OpenAiUnifiedStreamingProcessor(BiFunction errorParser) { + this.errorParser = errorParser; + } @Override protected void upstreamRequest(long n) { @@ -71,7 +79,25 @@ public class OpenAiUnifiedStreamingProcessor extends DelegatingProcessor item) throws Exception { var parserConfig = XContentParserConfiguration.EMPTY.withDeprecationHandler(LoggingDeprecationHandler.INSTANCE); - var results = parseEvent(item, OpenAiUnifiedStreamingProcessor::parse, parserConfig, logger); + + var results = new ArrayDeque(item.size()); + for (var event : item) { + if (ServerSentEventField.EVENT == event.name() && "error".equals(event.value())) { + previousEventWasError = true; + } else if (ServerSentEventField.DATA == event.name() && event.hasValue()) { + if (previousEventWasError) { + throw errorParser.apply(event.value(), null); + } + + try { + var delta = parse(parserConfig, event); + delta.forEachRemaining(results::offer); + } catch (Exception e) { + logger.warn("Failed to parse event from inference provider: {}", event); + throw errorParser.apply(event.value(), e); + } + } + } if (results.isEmpty()) { upstream().request(1); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/elastic/ElasticInferenceServiceErrorResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/elastic/ElasticInferenceServiceErrorResponseEntity.java index 696be7b2acdd..29b090390169 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/elastic/ElasticInferenceServiceErrorResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/elastic/ElasticInferenceServiceErrorResponseEntity.java @@ -9,6 +9,7 @@ package org.elasticsearch.xpack.inference.external.response.elastic; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.elasticsearch.common.CheckedSupplier; import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; @@ -16,6 +17,18 @@ import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.http.retry.ErrorResponse; +import java.io.IOException; + +/** + * An example error response would look like + * + * + * { + * "error": "some error" + * } + * + * + */ public class ElasticInferenceServiceErrorResponseEntity extends ErrorResponse { private static final Logger logger = LogManager.getLogger(ElasticInferenceServiceErrorResponseEntity.class); @@ -24,24 +37,18 @@ public class ElasticInferenceServiceErrorResponseEntity extends ErrorResponse { super(errorMessage); } - /** - * An example error response would look like - * - * - * { - * "error": "some error" - * } - * - * - * @param response The error response - * @return An error entity if the response is JSON with the above structure - * or {@link ErrorResponse#UNDEFINED_ERROR} if the error field wasn't found - */ public static ErrorResponse fromResponse(HttpResult response) { - try ( - XContentParser jsonParser = XContentFactory.xContent(XContentType.JSON) - .createParser(XContentParserConfiguration.EMPTY, response.body()) - ) { + return fromParser( + () -> XContentFactory.xContent(XContentType.JSON).createParser(XContentParserConfiguration.EMPTY, response.body()) + ); + } + + public static ErrorResponse fromString(String response) { + return fromParser(() -> XContentFactory.xContent(XContentType.JSON).createParser(XContentParserConfiguration.EMPTY, response)); + } + + private static ErrorResponse fromParser(CheckedSupplier jsonParserFactory) { + try (XContentParser jsonParser = jsonParserFactory.get()) { var responseMap = jsonParser.map(); var error = (String) responseMap.get("error"); if (error != null) { @@ -50,7 +57,6 @@ public class ElasticInferenceServiceErrorResponseEntity extends ErrorResponse { } catch (Exception e) { logger.debug("Failed to parse error response", e); } - return ErrorResponse.UNDEFINED_ERROR; } } 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 f24f407fd051..3bebd8086d79 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 @@ -117,6 +117,7 @@ public class SemanticTextFieldMapper extends FieldMapper implements InferenceFie public static final NodeFeature SEMANTIC_TEXT_ALWAYS_EMIT_INFERENCE_ID_FIX = new NodeFeature( "semantic_text.always_emit_inference_id_fix" ); + public static final NodeFeature SEMANTIC_TEXT_SKIP_INFERENCE_FIELDS = new NodeFeature("semantic_text.skip_inference_fields"); public static final String CONTENT_TYPE = "semantic_text"; public static final String DEFAULT_ELSER_2_INFERENCE_ID = DEFAULT_ELSER_ID; diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/registry/ModelRegistry.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/registry/ModelRegistry.java index a9642a685aec..2bcb130ddccb 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/registry/ModelRegistry.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/registry/ModelRegistry.java @@ -28,6 +28,7 @@ import org.elasticsearch.action.support.SubscribableListener; import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.client.internal.Client; import org.elasticsearch.client.internal.OriginSettingClient; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.index.engine.VersionConflictEngineException; @@ -61,6 +62,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -111,7 +113,7 @@ public class ModelRegistry { public ModelRegistry(Client client) { this.client = new OriginSettingClient(client, ClientHelper.INFERENCE_ORIGIN); - defaultConfigIds = new HashMap<>(); + defaultConfigIds = new ConcurrentHashMap<>(); } /** @@ -644,11 +646,32 @@ public class ModelRegistry { return null; } + public synchronized void removeDefaultConfigs(Set inferenceEntityIds, ActionListener listener) { + if (inferenceEntityIds.isEmpty()) { + listener.onResponse(true); + return; + } + + defaultConfigIds.keySet().removeAll(inferenceEntityIds); + deleteModels(inferenceEntityIds, listener); + } + public void deleteModel(String inferenceEntityId, ActionListener listener) { - if (preventDeletionLock.contains(inferenceEntityId)) { + deleteModels(Set.of(inferenceEntityId), listener); + } + + public void deleteModels(Set inferenceEntityIds, ActionListener listener) { + var lockedInferenceIds = new HashSet<>(inferenceEntityIds); + lockedInferenceIds.retainAll(preventDeletionLock); + + if (lockedInferenceIds.isEmpty() == false) { listener.onFailure( new ElasticsearchStatusException( - "Model is currently being updated, you may delete the model once the update completes", + Strings.format( + "The inference endpoint(s) %s are currently being updated, please wait until after they are " + + "finished updating to delete.", + lockedInferenceIds + ), RestStatus.CONFLICT ) ); @@ -657,7 +680,7 @@ public class ModelRegistry { DeleteByQueryRequest request = new DeleteByQueryRequest().setAbortOnVersionConflict(false); request.indices(InferenceIndex.INDEX_PATTERN, InferenceSecretsIndex.INDEX_PATTERN); - request.setQuery(documentIdQuery(inferenceEntityId)); + request.setQuery(documentIdsQuery(inferenceEntityIds)); request.setRefresh(true); client.execute(DeleteByQueryAction.INSTANCE, request, listener.delegateFailureAndWrap((l, r) -> l.onResponse(Boolean.TRUE))); @@ -695,6 +718,11 @@ public class ModelRegistry { return QueryBuilders.constantScoreQuery(QueryBuilders.idsQuery().addIds(Model.documentId(inferenceEntityId))); } + private QueryBuilder documentIdsQuery(Set inferenceEntityIds) { + var documentIdsArray = inferenceEntityIds.stream().map(Model::documentId).toArray(String[]::new); + return QueryBuilders.constantScoreQuery(QueryBuilders.idsQuery().addIds(documentIdsArray)); + } + static Optional idMatchedDefault( String inferenceId, List defaultConfigIds diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/BaseInferenceAction.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/BaseInferenceAction.java index d911158e8229..06a0849b91d4 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/BaseInferenceAction.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/BaseInferenceAction.java @@ -15,6 +15,7 @@ import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.xpack.core.inference.action.InferenceAction; +import org.elasticsearch.xpack.core.inference.action.InferenceActionProxy; import java.io.IOException; @@ -41,21 +42,22 @@ abstract class BaseInferenceAction extends BaseRestHandler { @Override protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException { var params = parseParams(restRequest); - - InferenceAction.Request.Builder requestBuilder; - try (var parser = restRequest.contentParser()) { - requestBuilder = InferenceAction.Request.parseRequest(params.inferenceEntityId(), params.taskType(), parser); - } - + var content = restRequest.requiredContent(); var inferTimeout = parseTimeout(restRequest); - requestBuilder.setInferenceTimeout(inferTimeout); - var request = prepareInferenceRequest(requestBuilder); - return channel -> client.execute(InferenceAction.INSTANCE, request, listener(channel)); + + var request = new InferenceActionProxy.Request( + params.taskType(), + params.inferenceEntityId(), + content, + restRequest.getXContentType(), + inferTimeout, + shouldStream() + ); + + return channel -> client.execute(InferenceActionProxy.INSTANCE, request, ActionListener.withRef(listener(channel), content)); } - protected InferenceAction.Request prepareInferenceRequest(InferenceAction.Request.Builder builder) { - return builder.build(); - } + protected abstract boolean shouldStream(); protected abstract ActionListener listener(RestChannel channel); } 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 7f43676dfb5f..b1edec79dfb7 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 @@ -24,22 +24,14 @@ public final class Paths { static final String INFERENCE_SERVICES_PATH = "_inference/_services"; static final String TASK_TYPE_INFERENCE_SERVICES_PATH = "_inference/_services/{" + TASK_TYPE + "}"; - static final String STREAM_INFERENCE_ID_PATH = "_inference/{" + TASK_TYPE_OR_INFERENCE_ID + "}/_stream"; + public static final String STREAM_SUFFIX = "_stream"; + static final String STREAM_INFERENCE_ID_PATH = "_inference/{" + TASK_TYPE_OR_INFERENCE_ID + "}/" + STREAM_SUFFIX; static final String STREAM_TASK_TYPE_INFERENCE_ID_PATH = "_inference/{" - + TASK_TYPE_OR_INFERENCE_ID - + "}/{" - + INFERENCE_ID - + "}/_stream"; - - // TODO remove the _unified path - public static final String UNIFIED_SUFFIX = "_unified"; - static final String UNIFIED_INFERENCE_ID_PATH = "_inference/{" + TASK_TYPE_OR_INFERENCE_ID + "}/" + UNIFIED_SUFFIX; - static final String UNIFIED_TASK_TYPE_INFERENCE_ID_PATH = "_inference/{" + TASK_TYPE_OR_INFERENCE_ID + "}/{" + INFERENCE_ID + "}/" - + UNIFIED_SUFFIX; + + STREAM_SUFFIX; private Paths() { diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestInferenceAction.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestInferenceAction.java index 0fbc2f8214cb..55083dcd4c88 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestInferenceAction.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestInferenceAction.java @@ -32,6 +32,11 @@ public class RestInferenceAction extends BaseInferenceAction { return List.of(new Route(POST, INFERENCE_ID_PATH), new Route(POST, TASK_TYPE_INFERENCE_ID_PATH)); } + @Override + protected boolean shouldStream() { + return false; + } + @Override protected ActionListener listener(RestChannel channel) { return new RestChunkedToXContentListener<>(channel); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestStreamInferenceAction.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestStreamInferenceAction.java index 518056365d88..f37f4e9fb1f9 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestStreamInferenceAction.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestStreamInferenceAction.java @@ -9,17 +9,12 @@ package org.elasticsearch.xpack.inference.rest; import org.apache.lucene.util.SetOnce; import org.elasticsearch.action.ActionListener; -import org.elasticsearch.client.internal.node.NodeClient; -import org.elasticsearch.inference.TaskType; import org.elasticsearch.rest.RestChannel; -import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.Scope; import org.elasticsearch.rest.ServerlessScope; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.action.UnifiedCompletionAction; -import java.io.IOException; import java.util.List; import java.util.Objects; @@ -46,41 +41,13 @@ public class RestStreamInferenceAction extends BaseInferenceAction { return List.of(new Route(POST, STREAM_INFERENCE_ID_PATH), new Route(POST, STREAM_TASK_TYPE_INFERENCE_ID_PATH)); } - @Override - protected InferenceAction.Request prepareInferenceRequest(InferenceAction.Request.Builder builder) { - return builder.setStream(true).build(); - } - @Override protected ActionListener listener(RestChannel channel) { return new ServerSentEventsRestActionListener(channel, threadPool); } @Override - protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException { - var params = parseParams(restRequest); - var inferTimeout = parseTimeout(restRequest); - - if (params.taskType() == TaskType.CHAT_COMPLETION) { - UnifiedCompletionAction.Request request; - try (var parser = restRequest.contentParser()) { - request = UnifiedCompletionAction.Request.parseRequest(params.inferenceEntityId(), params.taskType(), inferTimeout, parser); - } - - return channel -> client.execute( - UnifiedCompletionAction.INSTANCE, - request, - new ServerSentEventsRestActionListener(channel, threadPool) - ); - } else { - InferenceAction.Request.Builder requestBuilder; - try (var parser = restRequest.contentParser()) { - requestBuilder = InferenceAction.Request.parseRequest(params.inferenceEntityId(), params.taskType(), parser); - } - - requestBuilder.setInferenceTimeout(inferTimeout); - var request = prepareInferenceRequest(requestBuilder); - return channel -> client.execute(InferenceAction.INSTANCE, request, listener(channel)); - } + protected boolean shouldStream() { + return true; } } diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestUnifiedCompletionInferenceAction.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestUnifiedCompletionInferenceAction.java deleted file mode 100644 index 0efd31a6832c..000000000000 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/rest/RestUnifiedCompletionInferenceAction.java +++ /dev/null @@ -1,67 +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.inference.rest; - -import org.apache.lucene.util.SetOnce; -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.threadpool.ThreadPool; -import org.elasticsearch.xpack.core.inference.action.UnifiedCompletionAction; -import org.elasticsearch.xpack.core.inference.results.UnifiedChatCompletionException; - -import java.io.IOException; -import java.util.List; -import java.util.Objects; - -import static org.elasticsearch.rest.RestRequest.Method.POST; -import static org.elasticsearch.xpack.inference.rest.Paths.UNIFIED_INFERENCE_ID_PATH; -import static org.elasticsearch.xpack.inference.rest.Paths.UNIFIED_TASK_TYPE_INFERENCE_ID_PATH; - -@ServerlessScope(Scope.PUBLIC) -public class RestUnifiedCompletionInferenceAction extends BaseRestHandler { - private final SetOnce threadPool; - - public RestUnifiedCompletionInferenceAction(SetOnce threadPool) { - super(); - this.threadPool = Objects.requireNonNull(threadPool); - } - - @Override - public String getName() { - return "unified_inference_action"; - } - - @Override - public List routes() { - return List.of(new Route(POST, UNIFIED_INFERENCE_ID_PATH), new Route(POST, UNIFIED_TASK_TYPE_INFERENCE_ID_PATH)); - } - - @Override - protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException { - var params = BaseInferenceAction.parseParams(restRequest); - - var inferTimeout = BaseInferenceAction.parseTimeout(restRequest); - - UnifiedCompletionAction.Request request; - try (var parser = restRequest.contentParser()) { - request = UnifiedCompletionAction.Request.parseRequest(params.inferenceEntityId(), params.taskType(), inferTimeout, parser); - } - - return channel -> client.execute( - UnifiedCompletionAction.INSTANCE, - request, - new ServerSentEventsRestActionListener(channel, threadPool).delegateResponse((l, e) -> { - // format any validation exceptions from the rest -> transport path as UnifiedChatCompletionException - l.onFailure(UnifiedChatCompletionException.fromThrowable(e)); - }) - ); - } -} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/ServiceUtils.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/ServiceUtils.java index 1ddae3cc8df9..13d641101a1c 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/ServiceUtils.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/ServiceUtils.java @@ -42,7 +42,7 @@ import static org.elasticsearch.core.Strings.format; import static org.elasticsearch.xpack.core.ml.inference.assignment.AdaptiveAllocationsSettings.ENABLED; import static org.elasticsearch.xpack.core.ml.inference.assignment.AdaptiveAllocationsSettings.MAX_NUMBER_OF_ALLOCATIONS; import static org.elasticsearch.xpack.core.ml.inference.assignment.AdaptiveAllocationsSettings.MIN_NUMBER_OF_ALLOCATIONS; -import static org.elasticsearch.xpack.inference.rest.Paths.UNIFIED_SUFFIX; +import static org.elasticsearch.xpack.inference.rest.Paths.STREAM_SUFFIX; import static org.elasticsearch.xpack.inference.services.ServiceFields.SIMILARITY; public final class ServiceUtils { @@ -796,7 +796,7 @@ public final class ServiceUtils { model.getTaskType(), model.getTaskType(), model.getInferenceEntityId(), - UNIFIED_SUFFIX + STREAM_SUFFIX ); } diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceService.java index ea95f121ca6a..c4e961d9e9f6 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceService.java @@ -68,8 +68,10 @@ import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; import static org.elasticsearch.xpack.core.inference.results.ResultUtils.createInvalidChunkedResultException; +import static org.elasticsearch.xpack.inference.InferencePlugin.UTILITY_THREAD_POOL_NAME; import static org.elasticsearch.xpack.inference.external.action.ActionUtils.constructFailedToSendRequestMessage; import static org.elasticsearch.xpack.inference.services.ServiceFields.MAX_INPUT_TOKENS; import static org.elasticsearch.xpack.inference.services.ServiceFields.MODEL_ID; @@ -158,10 +160,7 @@ public class ElasticInferenceService extends SenderService { private void getAuthorization() { try { - ActionListener listener = ActionListener.wrap(result -> { - setAuthorizedContent(result); - authorizationCompletedLatch.countDown(); - }, e -> { + ActionListener listener = ActionListener.wrap(this::setAuthorizedContent, e -> { // we don't need to do anything if there was a failure, everything is disabled by default authorizationCompletedLatch.countDown(); }); @@ -177,18 +176,30 @@ public class ElasticInferenceService extends SenderService { var authorizedTaskTypesAndModels = auth.newLimitedToTaskTypes(EnumSet.copyOf(IMPLEMENTED_TASK_TYPES)); // recalculate which default config ids and models are authorized now - var authorizedDefaultConfigIds = getAuthorizedDefaultConfigIds(auth); - var authorizedDefaultModelObjects = getAuthorizedDefaultModelsObjects(auth); + var authorizedDefaultModelIds = getAuthorizedDefaultModelIds(auth); + + var authorizedDefaultConfigIds = getAuthorizedDefaultConfigIds(authorizedDefaultModelIds, auth); + var authorizedDefaultModelObjects = getAuthorizedDefaultModelsObjects(authorizedDefaultModelIds); authRef.set(new AuthorizedContent(authorizedTaskTypesAndModels, authorizedDefaultConfigIds, authorizedDefaultModelObjects)); configuration = new Configuration(authRef.get().taskTypesAndModels.getAuthorizedTaskTypes()); defaultConfigIds().forEach(modelRegistry::addDefaultIds); + handleRevokedDefaultConfigs(authorizedDefaultModelIds); } - private List getAuthorizedDefaultConfigIds(ElasticInferenceServiceAuthorization auth) { - var authorizedDefaultModelIds = getAuthorizedDefaultModelIds(auth); + private Set getAuthorizedDefaultModelIds(ElasticInferenceServiceAuthorization auth) { + var authorizedModels = auth.getAuthorizedModelIds(); + var authorizedDefaultModelIds = new HashSet<>(defaultModelsConfigs.keySet()); + authorizedDefaultModelIds.retainAll(authorizedModels); + return authorizedDefaultModelIds; + } + + private List getAuthorizedDefaultConfigIds( + Set authorizedDefaultModelIds, + ElasticInferenceServiceAuthorization auth + ) { var authorizedConfigIds = new ArrayList(); for (var id : authorizedDefaultModelIds) { var modelConfig = defaultModelsConfigs.get(id); @@ -210,17 +221,7 @@ public class ElasticInferenceService extends SenderService { return authorizedConfigIds; } - private Set getAuthorizedDefaultModelIds(ElasticInferenceServiceAuthorization auth) { - var authorizedModels = auth.getAuthorizedModelIds(); - var authorizedDefaultModelIds = new HashSet<>(defaultModelsConfigs.keySet()); - authorizedDefaultModelIds.retainAll(authorizedModels); - - return authorizedDefaultModelIds; - } - - private List getAuthorizedDefaultModelsObjects(ElasticInferenceServiceAuthorization auth) { - var authorizedDefaultModelIds = getAuthorizedDefaultModelIds(auth); - + private List getAuthorizedDefaultModelsObjects(Set authorizedDefaultModelIds) { var authorizedModels = new ArrayList(); for (var id : authorizedDefaultModelIds) { var modelConfig = defaultModelsConfigs.get(id); @@ -232,8 +233,39 @@ public class ElasticInferenceService extends SenderService { return authorizedModels; } - // Default for testing - void waitForAuthorizationToComplete(TimeValue waitTime) { + private void handleRevokedDefaultConfigs(Set authorizedDefaultModelIds) { + // if a model was initially returned in the authorization response but is absent, then we'll assume authorization was revoked + var unauthorizedDefaultModelIds = new HashSet<>(defaultModelsConfigs.keySet()); + unauthorizedDefaultModelIds.removeAll(authorizedDefaultModelIds); + + // get all the default inference endpoint ids for the unauthorized model ids + var unauthorizedDefaultInferenceEndpointIds = unauthorizedDefaultModelIds.stream() + .map(defaultModelsConfigs::get) // get all the model configs + .filter(Objects::nonNull) // limit to only non-null + .map(modelConfig -> modelConfig.model.getInferenceEntityId()) // get the inference ids + .collect(Collectors.toSet()); + + var deleteInferenceEndpointsListener = ActionListener.wrap(result -> { + logger.trace(Strings.format("Successfully revoked access to default inference endpoint IDs: %s", unauthorizedDefaultModelIds)); + authorizationCompletedLatch.countDown(); + }, e -> { + logger.warn( + Strings.format("Failed to revoke access to default inference endpoint IDs: %s, error: %s", unauthorizedDefaultModelIds, e) + ); + authorizationCompletedLatch.countDown(); + }); + + getServiceComponents().threadPool() + .executor(UTILITY_THREAD_POOL_NAME) + .execute(() -> modelRegistry.removeDefaultConfigs(unauthorizedDefaultInferenceEndpointIds, deleteInferenceEndpointsListener)); + } + + /** + * Waits the specified amount of time for the authorization call to complete. This is mainly to make testing easier. + * @param waitTime the max time to wait + * @throws IllegalStateException if the wait time is exceeded or the call receives an {@link InterruptedException} + */ + public void waitForAuthorizationToComplete(TimeValue waitTime) { try { if (authorizationCompletedLatch.await(waitTime.getSeconds(), TimeUnit.SECONDS) == false) { throw new IllegalStateException("The wait time has expired for authorization to complete."); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalService.java index c7f19adb269a..ddc5e3e1aa36 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalService.java @@ -854,12 +854,15 @@ public class ElasticsearchInternalService extends BaseElasticsearchInternalServi return; } - var modelsByDeploymentIds = new HashMap(); + var modelsByDeploymentIds = new HashMap>(); for (var model : models) { assert model instanceof ElasticsearchInternalModel; if (model instanceof ElasticsearchInternalModel esModel) { - modelsByDeploymentIds.put(esModel.mlNodeDeploymentId(), esModel); + modelsByDeploymentIds.merge(esModel.mlNodeDeploymentId(), new ArrayList<>(List.of(esModel)), (a, b) -> { + a.addAll(b); + return a; + }); } else { listener.onFailure( new ElasticsearchStatusException( @@ -878,10 +881,13 @@ public class ElasticsearchInternalService extends BaseElasticsearchInternalServi new GetDeploymentStatsAction.Request(deploymentIds), ActionListener.wrap(stats -> { for (var deploymentStats : stats.getStats().results()) { - var model = modelsByDeploymentIds.get(deploymentStats.getDeploymentId()); - model.updateNumAllocations(deploymentStats.getNumberOfAllocations()); + var modelsForDeploymentId = modelsByDeploymentIds.get(deploymentStats.getDeploymentId()); + modelsForDeploymentId.forEach(model -> model.updateNumAllocations(deploymentStats.getNumberOfAllocations())); } - listener.onResponse(new ArrayList<>(modelsByDeploymentIds.values())); + var updatedModels = new ArrayList(); + modelsByDeploymentIds.values().forEach(updatedModels::addAll); + + listener.onResponse(updatedModels); }, e -> { logger.warn("Get deployment stats failed, cannot update the endpoint's number of allocations", e); // continue with the original response diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/validation/ModelValidatorBuilder.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/validation/ModelValidatorBuilder.java index e4de3d6beb80..1c4306c4edd4 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/validation/ModelValidatorBuilder.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/validation/ModelValidatorBuilder.java @@ -29,7 +29,7 @@ public class ModelValidatorBuilder { case SPARSE_EMBEDDING, RERANK, ANY -> { return new SimpleModelValidator(new SimpleServiceIntegrationValidator()); } - default -> throw new IllegalArgumentException(Strings.format("Can't validate inference model of for task type %s ", taskType)); + default -> throw new IllegalArgumentException(Strings.format("Can't validate inference model for task type %s", taskType)); } } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/TransportDeleteInferenceEndpointActionTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/TransportDeleteInferenceEndpointActionTests.java new file mode 100644 index 000000000000..a640e64c2022 --- /dev/null +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/TransportDeleteInferenceEndpointActionTests.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.inference.action; + +import org.elasticsearch.ElasticsearchStatusException; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.PlainActionFuture; +import org.elasticsearch.client.internal.Client; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.core.TimeValue; +import org.elasticsearch.inference.InferenceService; +import org.elasticsearch.inference.InferenceServiceRegistry; +import org.elasticsearch.inference.MinimalServiceSettings; +import org.elasticsearch.inference.TaskType; +import org.elasticsearch.tasks.Task; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.inference.action.DeleteInferenceEndpointAction; +import org.elasticsearch.xpack.inference.registry.ModelRegistry; +import org.junit.After; +import org.junit.Before; + +import static org.elasticsearch.xpack.inference.Utils.inferenceUtilityPool; +import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.mock; + +public class TransportDeleteInferenceEndpointActionTests extends ESTestCase { + + private static final TimeValue TIMEOUT = TimeValue.timeValueSeconds(30); + + private TransportDeleteInferenceEndpointAction action; + private ThreadPool threadPool; + private ModelRegistry modelRegistry; + + @Before + public void setUp() throws Exception { + super.setUp(); + modelRegistry = new ModelRegistry(mock(Client.class)); + threadPool = createThreadPool(inferenceUtilityPool()); + action = new TransportDeleteInferenceEndpointAction( + mock(TransportService.class), + mock(ClusterService.class), + threadPool, + mock(ActionFilters.class), + mock(IndexNameExpressionResolver.class), + modelRegistry, + mock(InferenceServiceRegistry.class) + ); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + terminate(threadPool); + } + + public void testFailsToDelete_ADefaultEndpoint() { + modelRegistry.addDefaultIds( + new InferenceService.DefaultConfigId("model-id", MinimalServiceSettings.chatCompletion(), mock(InferenceService.class)) + ); + + var listener = new PlainActionFuture(); + + action.masterOperation( + mock(Task.class), + new DeleteInferenceEndpointAction.Request("model-id", TaskType.CHAT_COMPLETION, true, false), + mock(ClusterState.class), + listener + ); + + var exception = expectThrows(ElasticsearchStatusException.class, () -> listener.actionGet(TIMEOUT)); + assertThat( + exception.getMessage(), + is("[model-id] is a reserved inference endpoint. " + "Cannot delete a reserved inference endpoint.") + ); + } +} diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/TransportInferenceActionProxyTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/TransportInferenceActionProxyTests.java new file mode 100644 index 000000000000..a9e6ec55a622 --- /dev/null +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/TransportInferenceActionProxyTests.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.inference.action; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.PlainActionFuture; +import org.elasticsearch.client.internal.Client; +import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.core.TimeValue; +import org.elasticsearch.inference.TaskType; +import org.elasticsearch.inference.UnparsedModel; +import org.elasticsearch.tasks.Task; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.threadpool.TestThreadPool; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xcontent.XContentType; +import org.elasticsearch.xpack.core.inference.action.InferenceAction; +import org.elasticsearch.xpack.core.inference.action.InferenceActionProxy; +import org.elasticsearch.xpack.core.inference.action.UnifiedCompletionAction; +import org.elasticsearch.xpack.inference.registry.ModelRegistry; +import org.junit.After; +import org.junit.Before; + +import java.util.Collections; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class TransportInferenceActionProxyTests extends ESTestCase { + private Client client; + private ThreadPool threadPool; + private TransportInferenceActionProxy action; + private ModelRegistry modelRegistry; + + @Before + public void setUp() throws Exception { + super.setUp(); + client = mock(Client.class); + threadPool = new TestThreadPool("test"); + when(client.threadPool()).thenReturn(threadPool); + modelRegistry = mock(ModelRegistry.class); + + action = new TransportInferenceActionProxy(mock(TransportService.class), mock(ActionFilters.class), modelRegistry, client); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + terminate(threadPool); + } + + public void testExecutesAUnifiedCompletionRequest_WhenTaskTypeIsChatCompletion_InRequest() { + String requestJson = """ + { + "model": "gpt-4o", + "messages": [ + { + "role": "user", + "content": [ + { + "text": "some text", + "type": "string" + } + ] + } + ] + } + """; + + @SuppressWarnings("unchecked") + ActionListener listener = (ActionListener) mock(ActionListener.class); + var request = new InferenceActionProxy.Request( + TaskType.CHAT_COMPLETION, + "id", + new BytesArray(requestJson), + XContentType.JSON, + TimeValue.ONE_MINUTE, + true + ); + + action.doExecute(mock(Task.class), request, listener); + + verify(client, times(1)).execute(eq(UnifiedCompletionAction.INSTANCE), any(), any()); + } + + public void testExecutesAUnifiedCompletionRequest_WhenTaskTypeIsChatCompletion_FromStorage() { + String requestJson = """ + { + "model": "gpt-4o", + "messages": [ + { + "role": "user", + "content": [ + { + "text": "some text", + "type": "string" + } + ] + } + ] + } + """; + + doAnswer(invocation -> { + ActionListener listener = invocation.getArgument(1); + listener.onResponse( + new UnparsedModel("id", TaskType.CHAT_COMPLETION, "service", Collections.emptyMap(), Collections.emptyMap()) + ); + + return Void.TYPE; + }).when(modelRegistry).getModelWithSecrets(any(), any()); + + var listener = new PlainActionFuture(); + var request = new InferenceActionProxy.Request( + TaskType.ANY, + "id", + new BytesArray(requestJson), + XContentType.JSON, + TimeValue.ONE_MINUTE, + true + ); + + action.doExecute(mock(Task.class), request, listener); + + verify(client, times(1)).execute(eq(UnifiedCompletionAction.INSTANCE), any(), any()); + } + + public void testExecutesAnInferenceAction_WhenTaskTypeIsCompletion_InRequest() { + String requestJson = """ + { + "input": ["some text"] + } + """; + + @SuppressWarnings("unchecked") + ActionListener listener = (ActionListener) mock(ActionListener.class); + var request = new InferenceActionProxy.Request( + TaskType.COMPLETION, + "id", + new BytesArray(requestJson), + XContentType.JSON, + TimeValue.ONE_MINUTE, + true + ); + + action.doExecute(mock(Task.class), request, listener); + + verify(client, times(1)).execute(eq(InferenceAction.INSTANCE), any(), any()); + } + + public void testExecutesAnInferenceAction_WhenTaskTypeIsCompletion_FromStorage() { + String requestJson = """ + { + "input": ["some text"] + } + """; + + doAnswer(invocation -> { + ActionListener listener = invocation.getArgument(1); + listener.onResponse(new UnparsedModel("id", TaskType.COMPLETION, "service", Collections.emptyMap(), Collections.emptyMap())); + + return Void.TYPE; + }).when(modelRegistry).getModelWithSecrets(any(), any()); + + var listener = new PlainActionFuture(); + var request = new InferenceActionProxy.Request( + TaskType.ANY, + "id", + new BytesArray(requestJson), + XContentType.JSON, + TimeValue.ONE_MINUTE, + true + ); + + action.doExecute(mock(Task.class), request, listener); + + verify(client, times(1)).execute(eq(InferenceAction.INSTANCE), any(), any()); + } +} diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/UpdateInferenceModelActionRequestTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/UpdateInferenceModelActionRequestTests.java new file mode 100644 index 000000000000..ab1e1d9c4cb2 --- /dev/null +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/UpdateInferenceModelActionRequestTests.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.inference.action; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.inference.TaskType; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xcontent.XContentType; +import org.elasticsearch.xpack.core.inference.action.UpdateInferenceModelAction; +import org.elasticsearch.xpack.inference.InferenceNamedWriteablesProvider; + +import java.io.IOException; + +public class UpdateInferenceModelActionRequestTests extends AbstractWireSerializingTestCase { + + @Override + protected Writeable.Reader instanceReader() { + return UpdateInferenceModelAction.Request::new; + } + + @Override + protected UpdateInferenceModelAction.Request createTestInstance() { + return new UpdateInferenceModelAction.Request( + randomAlphaOfLength(5), + randomBytesReference(50), + randomFrom(XContentType.values()), + randomFrom(TaskType.values()), + randomTimeValue() + ); + } + + @Override + protected UpdateInferenceModelAction.Request mutateInstance(UpdateInferenceModelAction.Request instance) throws IOException { + return randomValueOtherThan(instance, this::createTestInstance); + } + + @Override + protected NamedWriteableRegistry getNamedWriteableRegistry() { + return new NamedWriteableRegistry(InferenceNamedWriteablesProvider.getNamedWriteables()); + } +} diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/UpdateInferenceModelActionResponseTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/UpdateInferenceModelActionResponseTests.java new file mode 100644 index 000000000000..02208511d148 --- /dev/null +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/UpdateInferenceModelActionResponseTests.java @@ -0,0 +1,39 @@ +/* + * 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.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xpack.core.inference.action.UpdateInferenceModelAction; +import org.elasticsearch.xpack.inference.InferenceNamedWriteablesProvider; +import org.elasticsearch.xpack.inference.ModelConfigurationsTests; + +import java.io.IOException; + +public class UpdateInferenceModelActionResponseTests extends AbstractWireSerializingTestCase { + @Override + protected Writeable.Reader instanceReader() { + return UpdateInferenceModelAction.Response::new; + } + + @Override + protected UpdateInferenceModelAction.Response createTestInstance() { + return new UpdateInferenceModelAction.Response(ModelConfigurationsTests.createRandomInstance()); + } + + @Override + protected UpdateInferenceModelAction.Response mutateInstance(UpdateInferenceModelAction.Response instance) throws IOException { + return randomValueOtherThan(instance, this::createTestInstance); + } + + @Override + protected NamedWriteableRegistry getNamedWriteableRegistry() { + return new NamedWriteableRegistry(InferenceNamedWriteablesProvider.getNamedWriteables()); + } +} diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/registry/ModelRegistryTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/registry/ModelRegistryTests.java index 162bcc8f0971..65e4d049ef58 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/registry/ModelRegistryTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/registry/ModelRegistryTests.java @@ -28,6 +28,7 @@ import org.elasticsearch.inference.MinimalServiceSettings; import org.elasticsearch.inference.SimilarityMeasure; import org.elasticsearch.inference.TaskType; import org.elasticsearch.inference.UnparsedModel; +import org.elasticsearch.rest.RestStatus; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.SearchResponseUtils; @@ -41,6 +42,7 @@ import org.junit.Before; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; import static org.elasticsearch.core.Strings.format; @@ -52,6 +54,8 @@ import static org.hamcrest.Matchers.is; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class ModelRegistryTests extends ESTestCase { @@ -295,6 +299,37 @@ public class ModelRegistryTests extends ESTestCase { ); } + public void testRemoveDefaultConfigs_DoesNotCallClient_WhenPassedAnEmptySet() { + var client = mock(Client.class); + + var registry = new ModelRegistry(client); + var listener = new PlainActionFuture(); + + registry.removeDefaultConfigs(Set.of(), listener); + + assertTrue(listener.actionGet(TIMEOUT)); + verify(client, times(0)).execute(any(), any(), any()); + } + + public void testDeleteModels_Returns_ConflictException_WhenModelIsBeingAdded() { + var client = mockClient(); + + var registry = new ModelRegistry(client); + var model = TestModel.createRandomInstance(); + var newModel = TestModel.createRandomInstance(); + registry.updateModelTransaction(newModel, model, new PlainActionFuture<>()); + + var listener = new PlainActionFuture(); + + registry.deleteModels(Set.of(newModel.getInferenceEntityId()), listener); + var exception = expectThrows(ElasticsearchStatusException.class, () -> listener.actionGet(TIMEOUT)); + assertThat( + exception.getMessage(), + containsString("are currently being updated, please wait until after they are finished updating to delete.") + ); + assertThat(exception.status(), is(RestStatus.CONFLICT)); + } + public void testIdMatchedDefault() { var defaultConfigIds = new ArrayList(); defaultConfigIds.add( diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/BaseInferenceActionTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/BaseInferenceActionTests.java index 9e6718172a2f..61d28fae402b 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/BaseInferenceActionTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/BaseInferenceActionTests.java @@ -21,6 +21,7 @@ import org.elasticsearch.test.rest.FakeRestRequest; 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.action.InferenceActionProxy; import org.elasticsearch.xpack.core.inference.results.InferenceByteEmbedding; import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingByteResults; import org.junit.Before; @@ -43,6 +44,11 @@ public class BaseInferenceActionTests extends RestActionTestCase { @Before public void setUpAction() { controller().registerHandler(new BaseInferenceAction() { + @Override + protected boolean shouldStream() { + return false; + } + @Override protected ActionListener listener(RestChannel channel) { return new RestChunkedToXContentListener<>(channel); @@ -103,10 +109,10 @@ public class BaseInferenceActionTests extends RestActionTestCase { public void testUsesDefaultTimeout() { SetOnce executeCalled = new SetOnce<>(); verifyingClient.setExecuteVerifier(((actionType, actionRequest) -> { - assertThat(actionRequest, instanceOf(InferenceAction.Request.class)); + assertThat(actionRequest, instanceOf(InferenceActionProxy.Request.class)); - var request = (InferenceAction.Request) actionRequest; - assertThat(request.getInferenceTimeout(), is(InferenceAction.Request.DEFAULT_TIMEOUT)); + var request = (InferenceActionProxy.Request) actionRequest; + assertThat(request.getTimeout(), is(InferenceAction.Request.DEFAULT_TIMEOUT)); executeCalled.set(true); return createResponse(); @@ -123,10 +129,10 @@ public class BaseInferenceActionTests extends RestActionTestCase { public void testUses3SecondTimeoutFromParams() { SetOnce executeCalled = new SetOnce<>(); verifyingClient.setExecuteVerifier(((actionType, actionRequest) -> { - assertThat(actionRequest, instanceOf(InferenceAction.Request.class)); + assertThat(actionRequest, instanceOf(InferenceActionProxy.Request.class)); - var request = (InferenceAction.Request) actionRequest; - assertThat(request.getInferenceTimeout(), is(TimeValue.timeValueSeconds(3))); + var request = (InferenceActionProxy.Request) actionRequest; + assertThat(request.getTimeout(), is(TimeValue.timeValueSeconds(3))); executeCalled.set(true); return createResponse(); 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/RestInferenceActionProxyTests.java similarity index 90% rename from x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/RestInferenceActionTests.java rename to x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/RestInferenceActionProxyTests.java index 1b0df1b4a20d..433e33fe1521 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/RestInferenceActionProxyTests.java @@ -13,7 +13,7 @@ import org.elasticsearch.rest.RestRequest; import org.elasticsearch.test.rest.FakeRestRequest; 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.action.InferenceActionProxy; import org.junit.Before; import static org.elasticsearch.xpack.inference.rest.BaseInferenceActionTests.createResponse; @@ -21,7 +21,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; -public class RestInferenceActionTests extends RestActionTestCase { +public class RestInferenceActionProxyTests extends RestActionTestCase { @Before public void setUpAction() { @@ -31,9 +31,9 @@ public class RestInferenceActionTests extends RestActionTestCase { public void testStreamIsFalse() { SetOnce executeCalled = new SetOnce<>(); verifyingClient.setExecuteVerifier(((actionType, actionRequest) -> { - assertThat(actionRequest, instanceOf(InferenceAction.Request.class)); + assertThat(actionRequest, instanceOf(InferenceActionProxy.Request.class)); - var request = (InferenceAction.Request) actionRequest; + var request = (InferenceActionProxy.Request) actionRequest; assertThat(request.isStreaming(), is(false)); executeCalled.set(true); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/RestStreamInferenceActionTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/RestStreamInferenceActionTests.java index f67680ef6b62..e69dd3fda624 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/RestStreamInferenceActionTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/RestStreamInferenceActionTests.java @@ -9,13 +9,18 @@ package org.elasticsearch.xpack.inference.rest; import org.apache.lucene.util.SetOnce; import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.rest.AbstractRestChannel; +import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestResponse; import org.elasticsearch.test.rest.FakeRestRequest; import org.elasticsearch.test.rest.RestActionTestCase; import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.action.InferenceAction; +import org.elasticsearch.xpack.core.inference.action.InferenceActionProxy; import org.junit.After; import org.junit.Before; @@ -42,9 +47,9 @@ public class RestStreamInferenceActionTests extends RestActionTestCase { public void testStreamIsTrue() { SetOnce executeCalled = new SetOnce<>(); verifyingClient.setExecuteVerifier(((actionType, actionRequest) -> { - assertThat(actionRequest, instanceOf(InferenceAction.Request.class)); + assertThat(actionRequest, instanceOf(InferenceActionProxy.Request.class)); - var request = (InferenceAction.Request) actionRequest; + var request = (InferenceActionProxy.Request) actionRequest; assertThat(request.isStreaming(), is(true)); executeCalled.set(true); @@ -58,4 +63,50 @@ public class RestStreamInferenceActionTests extends RestActionTestCase { dispatchRequest(inferenceRequest); assertThat(executeCalled.get(), equalTo(true)); } + + public void testStreamIsTrue_ChatCompletion() { + SetOnce executeCalled = new SetOnce<>(); + verifyingClient.setExecuteVerifier(((actionType, actionRequest) -> { + assertThat(actionRequest, instanceOf(InferenceActionProxy.Request.class)); + + var request = (InferenceActionProxy.Request) actionRequest; + assertThat(request.isStreaming(), is(true)); + + executeCalled.set(true); + return createResponse(); + })); + + var requestBody = """ + { + "messages": [ + { + "content": "abc", + "role": "user" + } + ] + } + """; + + RestRequest inferenceRequest = new FakeRestRequest.Builder(xContentRegistry()).withMethod(RestRequest.Method.POST) + .withPath("_inference/chat_completion/test/_stream") + .withContent(new BytesArray(requestBody), XContentType.JSON) + .build(); + + final SetOnce responseSetOnce = new SetOnce<>(); + dispatchRequest(inferenceRequest, new AbstractRestChannel(inferenceRequest, true) { + @Override + public void sendResponse(RestResponse response) { + responseSetOnce.set(response); + } + }); + + // the response content will be null when there is no error + assertNull(responseSetOnce.get().content()); + assertThat(executeCalled.get(), equalTo(true)); + } + + private void dispatchRequest(final RestRequest request, final RestChannel channel) { + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + controller().dispatchRequest(request, channel, threadContext); + } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/RestUnifiedCompletionInferenceActionTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/RestUnifiedCompletionInferenceActionTests.java deleted file mode 100644 index 9dc23c890c14..000000000000 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/rest/RestUnifiedCompletionInferenceActionTests.java +++ /dev/null @@ -1,91 +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.inference.rest; - -import org.apache.lucene.util.SetOnce; -import org.elasticsearch.common.bytes.BytesArray; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.util.concurrent.ThreadContext; -import org.elasticsearch.rest.AbstractRestChannel; -import org.elasticsearch.rest.RestChannel; -import org.elasticsearch.rest.RestRequest; -import org.elasticsearch.rest.RestResponse; -import org.elasticsearch.test.rest.FakeRestRequest; -import org.elasticsearch.test.rest.RestActionTestCase; -import org.elasticsearch.threadpool.TestThreadPool; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.action.UnifiedCompletionAction; -import org.junit.After; -import org.junit.Before; - -import static org.elasticsearch.xpack.inference.rest.BaseInferenceActionTests.createResponse; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; - -public class RestUnifiedCompletionInferenceActionTests extends RestActionTestCase { - private final SetOnce threadPool = new SetOnce<>(); - - @Before - public void setUpAction() { - threadPool.set(new TestThreadPool(getTestName())); - controller().registerHandler(new RestUnifiedCompletionInferenceAction(threadPool)); - } - - @After - public void tearDownAction() { - terminate(threadPool.get()); - } - - public void testStreamIsTrue() { - SetOnce executeCalled = new SetOnce<>(); - verifyingClient.setExecuteVerifier(((actionType, actionRequest) -> { - assertThat(actionRequest, instanceOf(UnifiedCompletionAction.Request.class)); - - var request = (UnifiedCompletionAction.Request) actionRequest; - assertThat(request.isStreaming(), is(true)); - - executeCalled.set(true); - return createResponse(); - })); - - var requestBody = """ - { - "messages": [ - { - "content": "abc", - "role": "user" - } - ] - } - """; - - RestRequest inferenceRequest = new FakeRestRequest.Builder(xContentRegistry()).withMethod(RestRequest.Method.POST) - .withPath("_inference/completion/test/_unified") - .withContent(new BytesArray(requestBody), XContentType.JSON) - .build(); - - final SetOnce responseSetOnce = new SetOnce<>(); - dispatchRequest(inferenceRequest, new AbstractRestChannel(inferenceRequest, true) { - @Override - public void sendResponse(RestResponse response) { - responseSetOnce.set(response); - } - }); - - // the response content will be null when there is no error - assertNull(responseSetOnce.get().content()); - assertThat(executeCalled.get(), equalTo(true)); - } - - private void dispatchRequest(final RestRequest request, final RestChannel channel) { - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - controller().dispatchRequest(request, channel, threadContext); - } -} diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceServiceTests.java index 5d66486731f5..46c2435ed1fe 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceServiceTests.java @@ -366,6 +366,14 @@ public class ElasticInferenceServiceTests extends ESTestCase { private ModelRegistry mockModelRegistry() { var client = mock(Client.class); when(client.threadPool()).thenReturn(threadPool); + + doAnswer(invocationOnMock -> { + @SuppressWarnings("unchecked") + var listener = (ActionListener) invocationOnMock.getArgument(2); + listener.onResponse(true); + + return Void.TYPE; + }).when(client).execute(any(), any(), any()); return new ModelRegistry(client); } @@ -436,7 +444,7 @@ public class ElasticInferenceServiceTests extends ESTestCase { "Inference entity [model_id] does not support task type [chat_completion] " + "for inference, the task type must be one of [sparse_embedding]. " + "The task type for the inference entity is chat_completion, " - + "please use the _inference/chat_completion/model_id/_unified URL." + + "please use the _inference/chat_completion/model_id/_stream URL." ) ); @@ -962,14 +970,51 @@ public class ElasticInferenceServiceTests extends ESTestCase { } public void testUnifiedCompletionError() throws Exception { + testUnifiedStreamError(404, """ + { + "error": "The model `rainbow-sprinkles` does not exist or you do not have access to it." + }""", """ + {\ + "error":{\ + "code":"not_found",\ + "message":"Received an unsuccessful status code for request from inference entity id [id] status \ + [404]. Error message: [The model `rainbow-sprinkles` does not exist or you do not have access to it.]",\ + "type":"error"\ + }}"""); + } + + public void testUnifiedCompletionErrorMidStream() throws Exception { + testUnifiedStreamError(200, """ + data: { "error": "some error" } + + """, """ + {\ + "error":{\ + "code":"stream_error",\ + "message":"Received an error response for request from inference entity id [id]. Error message: [some error]",\ + "type":"error"\ + }}"""); + } + + public void testUnifiedCompletionMalformedError() throws Exception { + testUnifiedStreamError(200, """ + data: { i am not json } + + """, """ + {\ + "error":{\ + "code":"bad_request",\ + "message":"[1:3] Unexpected character ('i' (code 105)): was expecting double-quote to start field name\\n\ + at [Source: (String)\\"{ i am not json }\\"; line: 1, column: 3]",\ + "type":"x_content_parse_exception"\ + }}"""); + } + + private void testUnifiedStreamError(int responseCode, String responseJson, String expectedJson) throws Exception { var eisGatewayUrl = getUrl(webServer); var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); try (var service = createService(senderFactory, eisGatewayUrl)) { - var responseJson = """ - { - "error": "The model `rainbow-sprinkles` does not exist or you do not have access to it." - }"""; - webServer.enqueue(new MockResponse().setResponseCode(404).setBody(responseJson)); + webServer.enqueue(new MockResponse().setResponseCode(responseCode).setBody(responseJson)); var model = new ElasticInferenceServiceCompletionModel( "id", TaskType.COMPLETION, @@ -1004,14 +1049,7 @@ public class ElasticInferenceServiceTests extends ESTestCase { }); var json = XContentHelper.convertToJson(BytesReference.bytes(builder), false, builder.contentType()); - assertThat(json, is(""" - {\ - "error":{\ - "code":"not_found",\ - "message":"Received an unsuccessful status code for request from inference entity id [id] status \ - [404]. Error message: [The model `rainbow-sprinkles` does not exist or you do not have access to it.]",\ - "type":"error"\ - }}""")); + assertThat(json, is(expectedJson)); } }); } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalServiceTests.java index 580871bb2c9a..d1ce79b863c6 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalServiceTests.java @@ -79,6 +79,7 @@ import org.mockito.Mockito; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.List; @@ -109,6 +110,7 @@ import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; public class ElasticsearchInternalServiceTests extends ESTestCase { @@ -1640,6 +1642,148 @@ public class ElasticsearchInternalServiceTests extends ESTestCase { } } + public void testUpdateModelsWithDynamicFields_NoModelsToUpdate() throws Exception { + ActionListener> resultsListener = ActionListener.>wrap( + updatedModels -> assertEquals(Collections.emptyList(), updatedModels), + e -> fail("Unexpected exception: " + e) + ); + + try (var service = createService(mock(Client.class))) { + service.updateModelsWithDynamicFields(List.of(), resultsListener); + } + } + + public void testUpdateModelsWithDynamicFields_InvalidModelProvided() throws IOException { + ActionListener> resultsListener = ActionListener.wrap( + updatedModels -> fail("Expected invalid model assertion error to be thrown"), + e -> fail("Expected invalid model assertion error to be thrown") + ); + + try (var service = createService(mock(Client.class))) { + assertThrows( + AssertionError.class, + () -> { service.updateModelsWithDynamicFields(List.of(mock(Model.class)), resultsListener); } + ); + } + } + + @SuppressWarnings("unchecked") + public void testUpdateModelsWithDynamicFields_FailsToRetrieveDeployments() throws IOException { + var deploymentId = randomAlphaOfLength(10); + var model = mock(ElasticsearchInternalModel.class); + when(model.mlNodeDeploymentId()).thenReturn(deploymentId); + when(model.getTaskType()).thenReturn(TaskType.TEXT_EMBEDDING); + + ActionListener> resultsListener = ActionListener.wrap(updatedModels -> { + assertEquals(updatedModels.size(), 1); + verify(model).mlNodeDeploymentId(); + verifyNoMoreInteractions(model); + }, e -> fail("Expected original models to be returned")); + + var client = mock(Client.class); + when(client.threadPool()).thenReturn(threadPool); + doAnswer(invocation -> { + var listener = (ActionListener) invocation.getArguments()[2]; + listener.onFailure(new RuntimeException(randomAlphaOfLength(10))); + return null; + }).when(client).execute(eq(GetDeploymentStatsAction.INSTANCE), any(), any()); + + try (var service = createService(client)) { + service.updateModelsWithDynamicFields(List.of(model), resultsListener); + } + } + + public void testUpdateModelsWithDynamicFields_SingleModelToUpdate() throws IOException { + var deploymentId = randomAlphaOfLength(10); + var model = mock(ElasticsearchInternalModel.class); + when(model.mlNodeDeploymentId()).thenReturn(deploymentId); + when(model.getTaskType()).thenReturn(TaskType.TEXT_EMBEDDING); + + var modelsByDeploymentId = new HashMap>(); + modelsByDeploymentId.put(deploymentId, List.of(model)); + + testUpdateModelsWithDynamicFields(modelsByDeploymentId); + } + + public void testUpdateModelsWithDynamicFields_MultipleModelsWithDifferentDeploymentsToUpdate() throws IOException { + var deploymentId1 = randomAlphaOfLength(10); + var model1 = mock(ElasticsearchInternalModel.class); + when(model1.mlNodeDeploymentId()).thenReturn(deploymentId1); + when(model1.getTaskType()).thenReturn(TaskType.TEXT_EMBEDDING); + var deploymentId2 = randomAlphaOfLength(10); + var model2 = mock(ElasticsearchInternalModel.class); + when(model2.mlNodeDeploymentId()).thenReturn(deploymentId2); + when(model2.getTaskType()).thenReturn(TaskType.TEXT_EMBEDDING); + + var modelsByDeploymentId = new HashMap>(); + modelsByDeploymentId.put(deploymentId1, List.of(model1)); + modelsByDeploymentId.put(deploymentId2, List.of(model2)); + + testUpdateModelsWithDynamicFields(modelsByDeploymentId); + } + + public void testUpdateModelsWithDynamicFields_MultipleModelsWithSameDeploymentsToUpdate() throws IOException { + var deploymentId = randomAlphaOfLength(10); + var model1 = mock(ElasticsearchInternalModel.class); + when(model1.mlNodeDeploymentId()).thenReturn(deploymentId); + when(model1.getTaskType()).thenReturn(TaskType.TEXT_EMBEDDING); + var model2 = mock(ElasticsearchInternalModel.class); + when(model2.mlNodeDeploymentId()).thenReturn(deploymentId); + when(model2.getTaskType()).thenReturn(TaskType.TEXT_EMBEDDING); + + var modelsByDeploymentId = new HashMap>(); + modelsByDeploymentId.put(deploymentId, List.of(model1, model2)); + + testUpdateModelsWithDynamicFields(modelsByDeploymentId); + } + + @SuppressWarnings("unchecked") + private void testUpdateModelsWithDynamicFields(Map> modelsByDeploymentId) throws IOException { + var modelsToUpdate = new ArrayList(); + modelsByDeploymentId.values().forEach(modelsToUpdate::addAll); + + var updatedNumberOfAllocations = new HashMap(); + modelsByDeploymentId.keySet().forEach(deploymentId -> updatedNumberOfAllocations.put(deploymentId, randomIntBetween(1, 10))); + + ActionListener> resultsListener = ActionListener.wrap(updatedModels -> { + assertEquals(updatedModels.size(), modelsToUpdate.size()); + modelsByDeploymentId.forEach((deploymentId, models) -> { + var expectedNumberOfAllocations = updatedNumberOfAllocations.get(deploymentId); + models.forEach(model -> { + verify((ElasticsearchInternalModel) model).updateNumAllocations(expectedNumberOfAllocations); + verify((ElasticsearchInternalModel) model).mlNodeDeploymentId(); + verifyNoMoreInteractions(model); + }); + }); + }, e -> fail("Unexpected exception: " + e)); + + var client = mock(Client.class); + when(client.threadPool()).thenReturn(threadPool); + doAnswer(invocation -> { + var listener = (ActionListener) invocation.getArguments()[2]; + var mockAssignmentStats = new ArrayList(); + modelsByDeploymentId.keySet().forEach(deploymentId -> { + var mockAssignmentStatsForDeploymentId = mock(AssignmentStats.class); + when(mockAssignmentStatsForDeploymentId.getDeploymentId()).thenReturn(deploymentId); + when(mockAssignmentStatsForDeploymentId.getNumberOfAllocations()).thenReturn(updatedNumberOfAllocations.get(deploymentId)); + mockAssignmentStats.add(mockAssignmentStatsForDeploymentId); + }); + listener.onResponse( + new GetDeploymentStatsAction.Response( + Collections.emptyList(), + Collections.emptyList(), + mockAssignmentStats, + mockAssignmentStats.size() + ) + ); + return null; + }).when(client).execute(eq(GetDeploymentStatsAction.INSTANCE), any(), any()); + + try (var service = createService(client)) { + service.updateModelsWithDynamicFields(modelsToUpdate, resultsListener); + } + } + public void testUpdateWithoutMlEnabled() throws IOException, InterruptedException { var cs = mock(ClusterService.class); var cSettings = new ClusterSettings(Settings.EMPTY, Set.of(MachineLearningField.MAX_LAZY_ML_NODES)); 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 34539042c1f0..b31cdf4f9d59 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 @@ -937,7 +937,7 @@ public class OpenAiServiceTests extends ESTestCase { "Inference entity [model_id] does not support task type [chat_completion] " + "for inference, the task type must be one of [text_embedding, completion]. " + "The task type for the inference entity is chat_completion, " - + "please use the _inference/chat_completion/model_id/_unified URL." + + "please use the _inference/chat_completion/model_id/_stream URL." ) ); @@ -1078,7 +1078,17 @@ public class OpenAiServiceTests extends ESTestCase { } }"""; webServer.enqueue(new MockResponse().setResponseCode(404).setBody(responseJson)); + testStreamError(""" + {\ + "error":{\ + "code":"model_not_found",\ + "message":"Received an unsuccessful status code for request from inference entity id [id] status \ + [404]. Error message: [The model `gpt-4awero` does not exist or you do not have access to it.]",\ + "type":"invalid_request_error"\ + }}"""); + } + private void testStreamError(String expectedResponse) throws Exception { var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); try (var service = new OpenAiService(senderFactory, createWithEmptySettings(threadPool))) { var model = OpenAiChatCompletionModelTests.createChatCompletionModel(getUrl(webServer), "org", "secret", "model", "user"); @@ -1107,19 +1117,44 @@ public class OpenAiServiceTests extends ESTestCase { }); var json = XContentHelper.convertToJson(BytesReference.bytes(builder), false, builder.contentType()); - assertThat(json, is(""" - {\ - "error":{\ - "code":"model_not_found",\ - "message":"Received an unsuccessful status code for request from inference entity id [id] status \ - [404]. Error message: [The model `gpt-4awero` does not exist or you do not have access to it.]",\ - "type":"invalid_request_error"\ - }}""")); + assertThat(json, is(expectedResponse)); } }); } } + public void testMidStreamUnifiedCompletionError() throws Exception { + String responseJson = """ + event: error + data: { "error": { "message": "Timed out waiting for more data", "type": "timeout" } } + + """; + webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseJson)); + testStreamError(""" + {\ + "error":{\ + "message":"Received an error response for request from inference entity id [id]. Error message: \ + [Timed out waiting for more data]",\ + "type":"timeout"\ + }}"""); + } + + public void testUnifiedCompletionMalformedError() throws Exception { + String responseJson = """ + data: { invalid json } + + """; + webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseJson)); + testStreamError(""" + {\ + "error":{\ + "code":"bad_request",\ + "message":"[1:3] Unexpected character ('i' (code 105)): was expecting double-quote to start field name\\n\ + at [Source: (String)\\"{ invalid json }\\"; line: 1, column: 3]",\ + "type":"x_content_parse_exception"\ + }}"""); + } + public void testInfer_StreamRequest() throws Exception { String responseJson = """ data: {\ diff --git a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/30_semantic_text_inference_bwc.yml b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/30_semantic_text_inference_bwc.yml index 07341273151b..5f87942b2c71 100644 --- a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/30_semantic_text_inference_bwc.yml +++ b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/30_semantic_text_inference_bwc.yml @@ -650,3 +650,28 @@ setup: - match: { hits.total.value: 1 } - match: { hits.total.relation: eq } - match: { hits.hits.0._source.dense_field.text: "updated text" } + +--- +"Skip fetching _inference_fields": + - requires: + cluster_features: semantic_text.skip_inference_fields + reason: Skip _inference_fields when search is performed on legacy semantic_text format. + + - do: + index: + index: test-index + id: doc_1 + body: + sparse_field: "test value" + refresh: true + + - do: + search: + index: test-index + body: + fields: [ _inference_fields ] + query: + match_all: { } + + - match: { hits.total.value: 1 } + - not_exists: hits.hits.0._source._inference_fields diff --git a/x-pack/plugin/logsdb/build.gradle b/x-pack/plugin/logsdb/build.gradle index 917f8207d2d2..bef07258a8e3 100644 --- a/x-pack/plugin/logsdb/build.gradle +++ b/x-pack/plugin/logsdb/build.gradle @@ -42,13 +42,3 @@ tasks.named("javaRestTest").configure { tasks.named('yamlRestTest') { usesDefaultDistribution() } - -tasks.named("yamlRestTest") { - if (buildParams.isSnapshotBuild() == false) { - systemProperty 'tests.rest.blacklist', [ - "60_synthetic_source_recovery/*" - ].join(',') - } -} - - diff --git a/x-pack/plugin/logsdb/src/javaRestTest/java/org/elasticsearch/xpack/logsdb/qa/DataGenerationHelper.java b/x-pack/plugin/logsdb/src/javaRestTest/java/org/elasticsearch/xpack/logsdb/qa/DataGenerationHelper.java index 8a5bb8d12cd3..fb890f3ac7ae 100644 --- a/x-pack/plugin/logsdb/src/javaRestTest/java/org/elasticsearch/xpack/logsdb/qa/DataGenerationHelper.java +++ b/x-pack/plugin/logsdb/src/javaRestTest/java/org/elasticsearch/xpack/logsdb/qa/DataGenerationHelper.java @@ -49,14 +49,14 @@ public class DataGenerationHelper { "host.name", FieldType.KEYWORD, Map.of("type", "keyword"), - () -> ESTestCase.randomAlphaOfLength(5) + (ignored) -> ESTestCase.randomAlphaOfLength(5) ), // Needed for terms query new PredefinedField.WithGenerator( "method", FieldType.KEYWORD, Map.of("type", "keyword"), - () -> ESTestCase.randomFrom("put", "post", "get") + (ignored) -> ESTestCase.randomFrom("put", "post", "get") ), // Needed for histogram aggregation @@ -64,7 +64,7 @@ public class DataGenerationHelper { "memory_usage_bytes", FieldType.LONG, Map.of("type", "long"), - () -> ESTestCase.randomLongBetween(1000, 2000) + (ignored) -> ESTestCase.randomLongBetween(1000, 2000) ) ) ); diff --git a/x-pack/plugin/logsdb/src/yamlRestTest/java/org/elasticsearch/xpack/logsdb/LogsdbTestSuiteIT.java b/x-pack/plugin/logsdb/src/yamlRestTest/java/org/elasticsearch/xpack/logsdb/LogsdbTestSuiteIT.java index fcac791cb205..a683305c9fde 100644 --- a/x-pack/plugin/logsdb/src/yamlRestTest/java/org/elasticsearch/xpack/logsdb/LogsdbTestSuiteIT.java +++ b/x-pack/plugin/logsdb/src/yamlRestTest/java/org/elasticsearch/xpack/logsdb/LogsdbTestSuiteIT.java @@ -11,6 +11,7 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.test.cluster.ElasticsearchCluster; +import org.elasticsearch.test.cluster.FeatureFlag; import org.elasticsearch.test.cluster.local.distribution.DistributionType; import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate; import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase; @@ -23,6 +24,7 @@ public class LogsdbTestSuiteIT extends ESClientYamlSuiteTestCase { .distribution(DistributionType.DEFAULT) .setting("xpack.security.enabled", "false") .setting("xpack.license.self_generated.type", "trial") + .feature(FeatureFlag.INDEX_RECOVERY_USE_SYNTHETIC_SOURCE) .build(); public LogsdbTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) { diff --git a/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateMetricDoubleFieldMapper.java b/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateMetricDoubleFieldMapper.java index 3ab49126ecb0..70adabf414f6 100644 --- a/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateMetricDoubleFieldMapper.java +++ b/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateMetricDoubleFieldMapper.java @@ -540,9 +540,6 @@ public class AggregateMetricDoubleFieldMapper extends FieldMapper { NumericDocValues sumValues = getNumericDocValues(sumFieldType, context.reader()); NumericDocValues valueCountValues = getNumericDocValues(countFieldType, context.reader()); - if (minValues == null || maxValues == null || sumValues == null || valueCountValues == null) { - throw new UnsupportedOperationException("Must have all subfields to use aggregate double metric in ESQL"); - } return new BlockDocValuesReader() { private int docID = -1; @@ -576,13 +573,13 @@ public class AggregateMetricDoubleFieldMapper extends FieldMapper { if (doc < lastDoc) { throw new IllegalStateException("docs within same block must be in order"); } - if (values.advanceExact(doc)) { + if (values == null || values.advanceExact(doc) == false) { + builder.appendNull(); + } else { double value = NumericUtils.sortableLongToDouble(values.longValue()); lastDoc = doc; this.docID = doc; builder.appendDouble(value); - } else { - builder.appendNull(); } } } @@ -595,13 +592,13 @@ public class AggregateMetricDoubleFieldMapper extends FieldMapper { if (doc < lastDoc) { throw new IllegalStateException("docs within same block must be in order"); } - if (values.advanceExact(doc)) { + if (values == null || values.advanceExact(doc) == false) { + builder.appendNull(); + } else { int value = Math.toIntExact(values.longValue()); lastDoc = doc; this.docID = doc; builder.appendInt(value); - } else { - builder.appendNull(); } } } @@ -610,10 +607,10 @@ public class AggregateMetricDoubleFieldMapper extends FieldMapper { public void read(int docId, StoredFields storedFields, Builder builder) throws IOException { var blockBuilder = (AggregateMetricDoubleBuilder) builder; this.docID = docId; - read(docId, blockBuilder); + readSingleRow(docId, blockBuilder); } - private void read(int docId, AggregateMetricDoubleBuilder builder) throws IOException { + private void readSingleRow(int docId, AggregateMetricDoubleBuilder builder) throws IOException { if (minValues.advanceExact(docId)) { builder.min().appendDouble(NumericUtils.sortableLongToDouble(minValues.longValue())); } else { diff --git a/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/CreateIndexFromSourceActionIT.java b/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/CreateIndexFromSourceActionIT.java index 5220e17618a3..fb491132147a 100644 --- a/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/CreateIndexFromSourceActionIT.java +++ b/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/CreateIndexFromSourceActionIT.java @@ -32,6 +32,8 @@ import java.util.Locale; import java.util.Map; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.not; public class CreateIndexFromSourceActionIT extends ESIntegTestCase { @@ -206,7 +208,7 @@ public class CreateIndexFromSourceActionIT extends ESIntegTestCase { assertTrue(destSettings.getAsBoolean(IndexMetadata.SETTING_BLOCKS_READ, false)); // override null removed - assertNull(destSettings.get(IndexMetadata.SETTING_BLOCKS_WRITE)); + assertThat(destSettings.keySet(), not(hasItem(IndexMetadata.SETTING_BLOCKS_WRITE))); } public void testRemoveIndexBlocksByDefault() throws Exception { @@ -236,9 +238,9 @@ public class CreateIndexFromSourceActionIT extends ESIntegTestCase { var destSettings = settingsResponse.getIndexToSettings().get(destIndex); // remove block settings override both source settings and override settings - assertNull(destSettings.get(IndexMetadata.SETTING_BLOCKS_WRITE)); - assertNull(destSettings.get(IndexMetadata.SETTING_READ_ONLY_ALLOW_DELETE)); - assertNull(destSettings.get(IndexMetadata.SETTING_BLOCKS_READ)); + assertThat(destSettings.keySet(), not(hasItem(IndexMetadata.SETTING_BLOCKS_WRITE))); + assertThat(destSettings.keySet(), not(hasItem(IndexMetadata.SETTING_READ_ONLY_ALLOW_DELETE))); + assertThat(destSettings.keySet(), not(hasItem(IndexMetadata.SETTING_BLOCKS_READ))); } public void testMappingsOverridden() { diff --git a/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/ReindexDatastreamIndexTransportActionIT.java b/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/ReindexDatastreamIndexTransportActionIT.java index 37311ca57141..a3642ddb664d 100644 --- a/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/ReindexDatastreamIndexTransportActionIT.java +++ b/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/ReindexDatastreamIndexTransportActionIT.java @@ -24,8 +24,6 @@ import org.elasticsearch.action.admin.indices.template.put.TransportPutComposabl import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; -import org.elasticsearch.action.ingest.DeletePipelineRequest; -import org.elasticsearch.action.ingest.DeletePipelineTransportAction; import org.elasticsearch.action.ingest.PutPipelineRequest; import org.elasticsearch.action.ingest.PutPipelineTransportAction; import org.elasticsearch.cluster.block.ClusterBlockException; @@ -70,18 +68,8 @@ import static org.hamcrest.Matchers.equalTo; public class ReindexDatastreamIndexTransportActionIT extends ESIntegTestCase { @After - private void cleanupCluster() throws Exception { - safeGet( - clusterAdmin().execute( - DeletePipelineTransportAction.TYPE, - new DeletePipelineRequest( - TEST_REQUEST_TIMEOUT, - TEST_REQUEST_TIMEOUT, - MigrateTemplateRegistry.REINDEX_DATA_STREAM_PIPELINE_NAME - ) - ) - ); - super.cleanUpCluster(); + private void cleanup() { + deletePipeline(MigrateTemplateRegistry.REINDEX_DATA_STREAM_PIPELINE_NAME); } private static final String MAPPING = """ diff --git a/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/action/CreateIndexFromSourceTransportAction.java b/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/action/CreateIndexFromSourceTransportAction.java index dcedb9084653..5840478d5551 100644 --- a/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/action/CreateIndexFromSourceTransportAction.java +++ b/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/action/CreateIndexFromSourceTransportAction.java @@ -46,13 +46,13 @@ public class CreateIndexFromSourceTransportAction extends HandledTransportAction private final ClusterService clusterService; private final Client client; private final IndexScopedSettings indexScopedSettings; - private static final Settings REMOVE_INDEX_BLOCKS_SETTING_OVERRIDE = Settings.builder() - .putNull(IndexMetadata.SETTING_READ_ONLY) - .putNull(IndexMetadata.SETTING_READ_ONLY_ALLOW_DELETE) - .putNull(IndexMetadata.SETTING_BLOCKS_WRITE) - .putNull(IndexMetadata.SETTING_BLOCKS_METADATA) - .putNull(IndexMetadata.SETTING_BLOCKS_READ) - .build(); + private static final Set INDEX_BLOCK_SETTINGS = Set.of( + IndexMetadata.SETTING_READ_ONLY, + IndexMetadata.SETTING_READ_ONLY_ALLOW_DELETE, + IndexMetadata.SETTING_BLOCKS_WRITE, + IndexMetadata.SETTING_BLOCKS_METADATA, + IndexMetadata.SETTING_BLOCKS_READ + ); @Inject public CreateIndexFromSourceTransportAction( @@ -89,12 +89,15 @@ public class CreateIndexFromSourceTransportAction extends HandledTransportAction Settings.Builder settings = Settings.builder() // first settings from source index - .put(filterSettings(sourceIndex)) - // then override with request settings - .put(request.settingsOverride()); + .put(filterSettings(sourceIndex)); + + if (request.settingsOverride().isEmpty() == false) { + applyOverrides(settings, request.settingsOverride()); + } + if (request.removeIndexBlocks()) { // lastly, override with settings to remove index blocks if requested - settings.put(REMOVE_INDEX_BLOCKS_SETTING_OVERRIDE); + INDEX_BLOCK_SETTINGS.forEach(settings::remove); } Map mergeMappings; @@ -114,6 +117,16 @@ public class CreateIndexFromSourceTransportAction extends HandledTransportAction client.admin().indices().create(createIndexRequest, listener.map(response -> response)); } + private void applyOverrides(Settings.Builder settings, Settings overrides) { + overrides.keySet().forEach(key -> { + if (overrides.get(key) != null) { + settings.put(key, overrides.get(key)); + } else { + settings.remove(key); + } + }); + } + private static Map toMap(@Nullable MappingMetadata sourceMapping) { return Optional.ofNullable(sourceMapping) .map(MappingMetadata::source) @@ -122,10 +135,14 @@ public class CreateIndexFromSourceTransportAction extends HandledTransportAction .orElse(Map.of()); } + @SuppressWarnings("unchecked") private static Map mergeMappings(@Nullable MappingMetadata sourceMapping, Map mappingAddition) throws IOException { Map combinedMappingMap = new HashMap<>(toMap(sourceMapping)); XContentHelper.update(combinedMappingMap, mappingAddition, true); + if (sourceMapping != null && combinedMappingMap.size() == 1 && combinedMappingMap.containsKey(sourceMapping.type())) { + combinedMappingMap = (Map) combinedMappingMap.get(sourceMapping.type()); + } return combinedMappingMap; } diff --git a/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/task/ReindexDataStreamPersistentTaskExecutor.java b/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/task/ReindexDataStreamPersistentTaskExecutor.java index 9b3112485bf0..e9585eae4b19 100644 --- a/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/task/ReindexDataStreamPersistentTaskExecutor.java +++ b/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/task/ReindexDataStreamPersistentTaskExecutor.java @@ -226,6 +226,7 @@ public class ReindexDataStreamPersistentTaskExecutor extends PersistentTasksExec }, e -> { reindexDataStreamTask.reindexFailed(index.getName(), e); listener.onResponse(null); + maybeProcessNextIndex(indicesRemaining, reindexDataStreamTask, sourceDataStream, listener, parentTaskId); })); } diff --git a/x-pack/plugin/ml/qa/basic-multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlBasicMultiNodeIT.java b/x-pack/plugin/ml/qa/basic-multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlBasicMultiNodeIT.java index 76b6dd991a41..04dcb76a3188 100644 --- a/x-pack/plugin/ml/qa/basic-multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlBasicMultiNodeIT.java +++ b/x-pack/plugin/ml/qa/basic-multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlBasicMultiNodeIT.java @@ -41,6 +41,15 @@ public class MlBasicMultiNodeIT extends ESRestTestCase { ) .build(); + private static final RequestOptions FLUSH_OPTIONS = RequestOptions.DEFAULT.toBuilder() + .setWarningsHandler( + warnings -> Collections.singletonList( + "Forcing any buffered data to be processed is deprecated, " + + "in a future major version it will be compulsory to use a datafeed" + ).equals(warnings) == false + ) + .build(); + public void testMachineLearningInstalled() throws Exception { Response response = client().performRequest(new Request("GET", "/_xpack")); Map features = (Map) entityAsMap(response).get("features"); @@ -93,7 +102,9 @@ public class MlBasicMultiNodeIT extends ESRestTestCase { assertEquals(1403481600000L, responseBody.get("earliest_record_timestamp")); assertEquals(1403481700000L, responseBody.get("latest_record_timestamp")); - Response flushResponse = client().performRequest(new Request("POST", BASE_PATH + "anomaly_detectors/" + jobId + "/_flush")); + Request flustRequest = new Request("POST", BASE_PATH + "anomaly_detectors/" + jobId + "/_flush"); + flustRequest.setOptions(FLUSH_OPTIONS); + Response flushResponse = client().performRequest(flustRequest); assertFlushResponse(flushResponse, true, 1403481600000L); Request closeRequest = new Request("POST", BASE_PATH + "anomaly_detectors/" + jobId + "/_close"); @@ -191,7 +202,9 @@ public class MlBasicMultiNodeIT extends ESRestTestCase { assertEquals(1403481600000L, responseBody.get("earliest_record_timestamp")); assertEquals(1403482000000L, responseBody.get("latest_record_timestamp")); - Response flushResponse = client().performRequest(new Request("POST", BASE_PATH + "anomaly_detectors/" + jobId + "/_flush")); + Request flushRequest = new Request("POST", BASE_PATH + "anomaly_detectors/" + jobId + "/_flush"); + flushRequest.setOptions(FLUSH_OPTIONS); + Response flushResponse = client().performRequest(flushRequest); assertFlushResponse(flushResponse, true, 1403481600000L); Request closeRequest = new Request("POST", BASE_PATH + "anomaly_detectors/" + jobId + "/_close"); diff --git a/x-pack/plugin/ml/qa/native-multi-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlJobIT.java b/x-pack/plugin/ml/qa/native-multi-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlJobIT.java index d981a60adbdb..cebcb6631c9b 100644 --- a/x-pack/plugin/ml/qa/native-multi-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlJobIT.java +++ b/x-pack/plugin/ml/qa/native-multi-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlJobIT.java @@ -58,6 +58,14 @@ public class MlJobIT extends ESRestTestCase { ).equals(warnings) == false ) .build(); + private static final RequestOptions FLUSH_OPTIONS = RequestOptions.DEFAULT.toBuilder() + .setWarningsHandler( + warnings -> Collections.singletonList( + "Forcing any buffered data to be processed is deprecated, " + + "in a future major version it will be compulsory to use a datafeed" + ).equals(warnings) == false + ) + .build(); @Override protected Settings restClientSettings() { @@ -534,9 +542,9 @@ public class MlJobIT extends ESRestTestCase { postDataRequest.setJsonEntity("{ \"airline\":\"LOT\", \"responsetime\":100, \"time\":\"2019-07-01 00:10:00Z\" }"); client().performRequest(postDataRequest); - Response flushResponse = client().performRequest( - new Request("POST", MachineLearning.BASE_PATH + "anomaly_detectors/" + jobId + "/_flush") - ); + Request flushRequest = new Request("POST", MachineLearning.BASE_PATH + "anomaly_detectors/" + jobId + "/_flush"); + flushRequest.setOptions(FLUSH_OPTIONS); + Response flushResponse = client().performRequest(flushRequest); assertThat(entityAsMap(flushResponse), hasEntry("flushed", true)); closeJob(jobId); @@ -574,9 +582,9 @@ public class MlJobIT extends ESRestTestCase { { "airline":"LOT", "response_time":100, "time":"2019-07-01 02:00:00Z" }"""); client().performRequest(postDataRequest); - Response flushResponse = client().performRequest( - new Request("POST", MachineLearning.BASE_PATH + "anomaly_detectors/" + jobId + "/_flush") - ); + Request flushRequest = new Request("POST", MachineLearning.BASE_PATH + "anomaly_detectors/" + jobId + "/_flush"); + flushRequest.setOptions(FLUSH_OPTIONS); + Response flushResponse = client().performRequest(flushRequest); assertThat(entityAsMap(flushResponse), hasEntry("flushed", true)); closeJob(jobId); diff --git a/x-pack/plugin/ml/qa/native-multi-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlNativeDataFrameAnalyticsIntegTestCase.java b/x-pack/plugin/ml/qa/native-multi-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlNativeDataFrameAnalyticsIntegTestCase.java index 4747adf4acb8..77c805654c3f 100644 --- a/x-pack/plugin/ml/qa/native-multi-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlNativeDataFrameAnalyticsIntegTestCase.java +++ b/x-pack/plugin/ml/qa/native-multi-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlNativeDataFrameAnalyticsIntegTestCase.java @@ -124,7 +124,7 @@ abstract class MlNativeDataFrameAnalyticsIntegTestCase extends MlNativeIntegTest } protected void waitUntilAnalyticsIsStopped(String id) throws Exception { - waitUntilAnalyticsIsStopped(id, TimeValue.timeValueSeconds(60)); + waitUntilAnalyticsIsStopped(id, TimeValue.timeValueSeconds(90)); } protected void waitUntilAnalyticsIsStopped(String id, TimeValue waitTime) throws Exception { diff --git a/x-pack/plugin/ml/src/main/java/module-info.java b/x-pack/plugin/ml/src/main/java/module-info.java index 4984fa8912e2..1013b8e052e4 100644 --- a/x-pack/plugin/ml/src/main/java/module-info.java +++ b/x-pack/plugin/ml/src/main/java/module-info.java @@ -37,8 +37,11 @@ module org.elasticsearch.ml { exports org.elasticsearch.xpack.ml; exports org.elasticsearch.xpack.ml.action; + exports org.elasticsearch.xpack.ml.aggs; exports org.elasticsearch.xpack.ml.aggs.categorization; + exports org.elasticsearch.xpack.ml.aggs.changepoint; exports org.elasticsearch.xpack.ml.autoscaling; exports org.elasticsearch.xpack.ml.job.categorization; exports org.elasticsearch.xpack.ml.notifications; + } diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/aggs/changepoint/ChangeType.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/aggs/changepoint/ChangeType.java index 7df542b59107..580209b2d821 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/aggs/changepoint/ChangeType.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/aggs/changepoint/ChangeType.java @@ -121,6 +121,10 @@ public interface ChangeType extends NamedWriteable, NamedXContentObject { return NAME; } + public String getReason() { + return reason; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/notifications/AbstractMlAuditor.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/notifications/AbstractMlAuditor.java index 213d3851b3b9..99b03c272541 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/notifications/AbstractMlAuditor.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/notifications/AbstractMlAuditor.java @@ -47,7 +47,8 @@ abstract class AbstractMlAuditor extends Abstrac clusterService.getNodeName(), messageFactory, clusterService, - indexNameExpressionResolver + indexNameExpressionResolver, + clusterService.threadPool().generic() ); clusterService.addListener(event -> { if (event.metadataChanged()) { diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestFlushJobAction.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestFlushJobAction.java index 650c5d92e758..e2bed63e18b3 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestFlushJobAction.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestFlushJobAction.java @@ -34,7 +34,9 @@ public class RestFlushJobAction extends BaseRestHandler { @Override public List routes() { - return List.of(new Route(POST, BASE_PATH + "anomaly_detectors/{" + ID + "}/_flush")); + final String msg = "Forcing any buffered data to be processed is deprecated, " + + "in a future major version it will be compulsory to use a datafeed"; + return List.of(Route.builder(POST, BASE_PATH + "anomaly_detectors/{" + ID + "}/_flush").deprecateAndKeep(msg).build()); } @Override diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestPostDataAction.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestPostDataAction.java index 0fcad773100f..443e15a6018e 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestPostDataAction.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestPostDataAction.java @@ -8,7 +8,6 @@ package org.elasticsearch.xpack.ml.rest.job; import org.elasticsearch.action.ActionListener; import org.elasticsearch.client.internal.node.NodeClient; -import org.elasticsearch.core.UpdateForV9; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestStatus; @@ -27,19 +26,11 @@ public class RestPostDataAction extends BaseRestHandler { private static final String DEFAULT_RESET_START = ""; private static final String DEFAULT_RESET_END = ""; - @UpdateForV9(owner = UpdateForV9.Owner.MACHINE_LEARNING) - // these routes were ".deprecated" in RestApiVersion.V_8 which will require use of REST API compatibility headers to access - // this API in v9. It is unclear if this was intentional for v9, and the code has been updated to ".deprecateAndKeep" which will - // continue to emit deprecations warnings but will not require any special headers to access the API in v9. - // Please review and update the code and tests as needed. The original code remains commented out below for reference. @Override public List routes() { final String msg = "Posting data directly to anomaly detection jobs is deprecated, " + "in a future major version it will be compulsory to use a datafeed"; - return List.of( - // Route.builder(POST, BASE_PATH + "anomaly_detectors/{" + Job.ID + "}/_data").deprecated(msg, RestApiVersion.V_8).build(), - Route.builder(POST, BASE_PATH + "anomaly_detectors/{" + Job.ID + "}/_data").deprecateAndKeep(msg).build() - ); + return List.of(Route.builder(POST, BASE_PATH + "anomaly_detectors/{" + Job.ID + "}/_data").deprecateAndKeep(msg).build()); } @Override diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/full/CacheService.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/full/CacheService.java index 2d8d78473501..a02c32cd56d9 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/full/CacheService.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/cache/full/CacheService.java @@ -245,7 +245,11 @@ public class CacheService extends AbstractLifecycleComponent { final Lifecycle.State state = lifecycleState(); assert state != Lifecycle.State.INITIALIZED : state; if (state != Lifecycle.State.STARTED) { - throw new IllegalStateException("Failed to read data from cache: cache service is not started [" + state + "]"); + if (state == Lifecycle.State.STOPPED) { + throw new AlreadyClosedException("Failed to read data from cache: cache service is stopped"); + } else { + throw new IllegalStateException("Failed to read data from cache: cache service is not started [" + state + "]"); + } } } 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 5d3b13b9d451..7e571b6db2f9 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 @@ -327,6 +327,8 @@ public class Constants { "cluster:admin/xpack/watcher/settings/update", "cluster:admin/xpack/watcher/watch/put", "cluster:internal/remote_cluster/nodes", + "cluster:internal/xpack/inference", + "cluster:internal/xpack/inference/unified", "cluster:internal/xpack/ml/coordinatedinference", "cluster:internal/xpack/ml/datafeed/isolate", "cluster:internal/xpack/ml/datafeed/running_state", @@ -386,9 +388,8 @@ public class Constants { "cluster:monitor/xpack/enrich/stats", "cluster:monitor/xpack/eql/stats/dist", "cluster:monitor/xpack/esql/stats/dist", - "cluster:monitor/xpack/inference", + "cluster:monitor/xpack/inference/post", "cluster:monitor/xpack/inference/get", - "cluster:monitor/xpack/inference/unified", "cluster:monitor/xpack/inference/diagnostics/get", "cluster:monitor/xpack/inference/services/get", "cluster:monitor/xpack/info", diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java index d0c159aab81e..f3db0a3d2f63 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -69,7 +69,6 @@ import org.elasticsearch.core.Nullable; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.TimeValue; import org.elasticsearch.env.Environment; -import org.elasticsearch.env.NodeMetadata; import org.elasticsearch.features.FeatureService; import org.elasticsearch.features.NodeFeature; import org.elasticsearch.http.HttpPreRequest; @@ -758,7 +757,6 @@ public class Security extends Plugin services.scriptService(), services.xContentRegistry(), services.environment(), - services.nodeEnvironment().nodeMetadata(), services.indexNameExpressionResolver(), services.telemetryProvider(), new PersistentTasksService(services.clusterService(), services.threadPool(), services.client()), @@ -779,7 +777,6 @@ public class Security extends Plugin ScriptService scriptService, NamedXContentRegistry xContentRegistry, Environment environment, - NodeMetadata nodeMetadata, IndexNameExpressionResolver expressionResolver, TelemetryProvider telemetryProvider, PersistentTasksService persistentTasksService, @@ -992,7 +989,6 @@ public class Security extends Plugin getLicenseState(), systemIndices.getMainIndexManager(), clusterService, - featureService, reservedRoleNameChecker, xContentRegistry ); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java index f4202502cef8..137b09f06694 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java @@ -37,7 +37,6 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.Maps; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.core.Nullable; -import org.elasticsearch.features.FeatureService; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.license.LicenseUtils; @@ -142,8 +141,6 @@ public class NativeRolesStore implements BiConsumer, ActionListener< private final ClusterService clusterService; - private final FeatureService featureService; - private final ReservedRoleNameChecker reservedRoleNameChecker; private final NamedXContentRegistry xContentRegistry; @@ -154,7 +151,6 @@ public class NativeRolesStore implements BiConsumer, ActionListener< XPackLicenseState licenseState, SecurityIndexManager securityIndex, ClusterService clusterService, - FeatureService featureService, ReservedRoleNameChecker reservedRoleNameChecker, NamedXContentRegistry xContentRegistry ) { @@ -163,7 +159,6 @@ public class NativeRolesStore implements BiConsumer, ActionListener< this.licenseState = licenseState; this.securityIndex = securityIndex; this.clusterService = clusterService; - this.featureService = featureService; this.reservedRoleNameChecker = reservedRoleNameChecker; this.xContentRegistry = xContentRegistry; this.enabled = settings.getAsBoolean(NATIVE_ROLES_ENABLED, true); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java index c2658b29040a..402674b35b3f 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java @@ -33,14 +33,11 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsModule; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.core.TimeValue; -import org.elasticsearch.env.BuildVersion; import org.elasticsearch.env.Environment; -import org.elasticsearch.env.NodeMetadata; import org.elasticsearch.env.TestEnvironment; import org.elasticsearch.features.FeatureService; import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.IndexVersion; import org.elasticsearch.index.IndexVersions; import org.elasticsearch.index.SlowLogFieldProvider; import org.elasticsearch.index.analysis.AnalysisRegistry; @@ -204,7 +201,6 @@ public class SecurityTests extends ESTestCase { private Collection createComponentsUtil(Settings settings) throws Exception { Environment env = TestEnvironment.newEnvironment(settings); - NodeMetadata nodeMetadata = new NodeMetadata(randomAlphaOfLength(8), BuildVersion.current(), IndexVersion.current()); ThreadPool threadPool = mock(ThreadPool.class); ClusterService clusterService = mock(ClusterService.class); settings = Security.additionalSettings(settings, true); @@ -228,7 +224,6 @@ public class SecurityTests extends ESTestCase { mock(ScriptService.class), xContentRegistry(), env, - nodeMetadata, TestIndexNameExpressionResolver.newInstance(threadContext), TelemetryProvider.NOOP, mock(PersistentTasksService.class), diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStoreTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStoreTests.java index f638773328d8..28bb1a8f65ec 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStoreTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStoreTests.java @@ -149,7 +149,6 @@ public class NativeRolesStoreTests extends ESTestCase { TestUtils.newTestLicenseState(), securityIndex, clusterService, - mock(FeatureService.class), new ReservedRoleNameChecker.Default(), mock(NamedXContentRegistry.class) ); @@ -405,7 +404,6 @@ public class NativeRolesStoreTests extends ESTestCase { licenseState, securityIndex, clusterService, - mock(FeatureService.class), mock(ReservedRoleNameChecker.class), mock(NamedXContentRegistry.class) ); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransportTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransportTests.java index 0663172fa2e9..8a79e2232cfe 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransportTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransportTests.java @@ -370,7 +370,21 @@ public class SecurityNetty4HttpServerTransportTests extends AbstractHttpServerTr new NetworkService(List.of()), testThreadPool, xContentRegistry(), - new NullDispatcher(), + new HttpServerTransport.Dispatcher() { + @Override + public void dispatchRequest(RestRequest request, RestChannel channel, ThreadContext threadContext) { + fail("Request should not be dispatched"); + } + + @Override + public void dispatchBadRequest(RestChannel channel, ThreadContext threadContext, Throwable cause) { + try { + channel.sendResponse(new RestResponse(channel, (Exception) cause)); + } catch (IOException e) { + fail(e, "Unexpected exception dispatching bad request"); + } + } + }, randomClusterSettings(), new SharedGroupFactory(settings), Tracer.NOOP, diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/SnapshotLifecycle.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/SnapshotLifecycle.java index 820170b03662..073a00e2f5f1 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/SnapshotLifecycle.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/SnapshotLifecycle.java @@ -24,7 +24,6 @@ import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsFilter; import org.elasticsearch.core.IOUtils; -import org.elasticsearch.features.FeatureService; import org.elasticsearch.features.NodeFeature; import org.elasticsearch.health.HealthIndicatorService; import org.elasticsearch.license.XPackLicenseState; @@ -94,7 +93,6 @@ public class SnapshotLifecycle extends Plugin implements ActionPlugin, HealthPlu private final SetOnce snapshotRetentionService = new SetOnce<>(); private final SetOnce snapshotHistoryStore = new SetOnce<>(); private final SetOnce slmHealthIndicatorService = new SetOnce<>(); - private final SetOnce featureService = new SetOnce<>(); private final Settings settings; public SnapshotLifecycle(Settings settings) { @@ -127,7 +125,6 @@ public class SnapshotLifecycle extends Plugin implements ActionPlugin, HealthPlu ClusterService clusterService = services.clusterService(); ThreadPool threadPool = services.threadPool(); final List components = new ArrayList<>(); - featureService.set(services.featureService()); SnapshotLifecycleTemplateRegistry templateRegistry = new SnapshotLifecycleTemplateRegistry( settings, clusterService, diff --git a/x-pack/plugin/sql/jdbc/build.gradle b/x-pack/plugin/sql/jdbc/build.gradle index d1b179f09e40..fd0e43fb23c3 100644 --- a/x-pack/plugin/sql/jdbc/build.gradle +++ b/x-pack/plugin/sql/jdbc/build.gradle @@ -20,11 +20,20 @@ dependencies { testImplementation project(':modules:rest-root') } -tasks.named("compileJava").configure { +java { targetCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8 } +tasks.named("compileTestJava").configure { + targetCompatibility = buildParams.getMinimumRuntimeVersion() + sourceCompatibility = buildParams.getMinimumRuntimeVersion() +} + +tasks.named("test").configure { + // reset the unit test classpath as using the shadow jar won't work due to relocated packages + classpath = sourceSets.test.runtimeClasspath +} tasks.named("shadowJar").configure { relocate 'com.fasterxml', 'shadow.fasterxml' @@ -34,7 +43,3 @@ tasks.named("shadowJar").configure { } } -tasks.named("test").configure { - // reset the unit test classpath as using the shadow jar won't work due to relocated packages - classpath = sourceSets.test.runtimeClasspath -} diff --git a/x-pack/plugin/sql/sql-client/build.gradle b/x-pack/plugin/sql/sql-client/build.gradle index 4a20e00666ea..f52e4b9ed96d 100644 --- a/x-pack/plugin/sql/sql-client/build.gradle +++ b/x-pack/plugin/sql/sql-client/build.gradle @@ -12,11 +12,16 @@ dependencies { testImplementation(testArtifact(project(xpackModule('core')))) } -tasks.named("compileJava").configure { +java { targetCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8 } +tasks.named("compileTestJava").configure { + targetCompatibility = buildParams.getMinimumRuntimeVersion() + sourceCompatibility = buildParams.getMinimumRuntimeVersion() +} + tasks.named('forbiddenApisMain').configure { // does not depend on core, so only jdk and http signatures should be checked replaceSignatureFiles 'jdk-signatures' diff --git a/x-pack/plugin/sql/sql-proto/build.gradle b/x-pack/plugin/sql/sql-proto/build.gradle index 2cb1cfa89f03..0a34afdbc250 100644 --- a/x-pack/plugin/sql/sql-proto/build.gradle +++ b/x-pack/plugin/sql/sql-proto/build.gradle @@ -16,11 +16,16 @@ dependencies { } } -tasks.named("compileJava").configure { +java { targetCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8 } +tasks.named("compileTestJava").configure { + targetCompatibility = buildParams.getMinimumRuntimeVersion() + sourceCompatibility = buildParams.getMinimumRuntimeVersion() +} + tasks.named('forbiddenApisMain').configure { //sql does not depend on server, so only jdk signatures should be checked replaceSignatureFiles 'jdk-signatures' diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/40_tsdb.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/40_tsdb.yml index 5bdd2baf6050..512ea155144b 100644 --- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/40_tsdb.yml +++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/40_tsdb.yml @@ -80,7 +80,6 @@ setup: time_series_dimension: true agg_metric: type: aggregate_metric_double - # TODO: tests with a subset of metrics metrics: [ min, max, sum, value_count ] default_metric: max k8s: @@ -102,6 +101,80 @@ setup: - '{"@timestamp": "2021-04-28T18:50:04.467Z", "dim": "A", "agg_metric": {"max": 10, "min": -1, "sum": 20, "value_count": 5}}' - '{"index": {}}' - '{"@timestamp": "2021-04-28T18:50:24.467Z", "dim": "B", "agg_metric": {"max": 20, "min": 3, "sum": 50, "value_count": 7}}' + - '{"index": {}}' + - '{"@timestamp": "2021-04-28T18:50:44.467Z", "dim": "B", "agg_metric": {"max": 17, "min": -5, "sum": 33, "value_count": 9}}' + + - do: + indices.create: + index: test3 + body: + settings: + index: + mode: time_series + routing_path: [ k8s.pod.uid ] + time_series: + start_time: 2021-04-28T00:00:00Z + end_time: 2021-04-29T00:00:00Z + mappings: + properties: + "@timestamp": + type: date + agg_metric: + type: aggregate_metric_double + metrics: [ min, max ] + default_metric: min + k8s: + properties: + pod: + properties: + uid: + type: keyword + time_series_dimension: true + - do: + bulk: + refresh: true + index: test3 + body: + - '{"index": {}}' + - '{"@timestamp": "2021-04-28T19:50:04.467Z", "agg_metric": {"max": 1, "min": -3}, "k8s": {"pod": {"uid":"947e4ced-1786-4e53-9e0c-5c447e959507"}}}' + - '{"index": {}}' + - '{"@timestamp": "2021-04-28T19:50:24.467Z", "agg_metric": {"max": 10, "min": 3}, "k8s": {"pod": {"uid":"947e4ced-1786-4e53-9e0c-5c447e959507"}}}' + - '{"index": {}}' + - '{"@timestamp": "2021-04-28T19:50:44.467Z", "agg_metric": {"max": 17, "min": 2}, "k8s": {"pod": {"uid":"df3145b3-0563-4d3b-a0f7-897eb2876ea9"}}}' + + - do: + indices.create: + index: test4 + body: + settings: + index: + mode: time_series + routing_path: [ k8s.pod.uid ] + time_series: + start_time: 2021-04-28T00:00:00Z + end_time: 2021-04-29T00:00:00Z + mappings: + properties: + "@timestamp": + type: date + agg_metric: + type: aggregate_metric_double + metrics: [ sum, value_count ] + default_metric: sum + k8s: + properties: + pod: + properties: + uid: + type: keyword + time_series_dimension: true + - do: + bulk: + refresh: true + index: test4 + body: + - '{"index": {}}' + - '{"@timestamp": "2021-04-28T23:50:04.467Z", "agg_metric": {"sum": 1, "value_count": 10}, "k8s": {"pod": {"uid":"947e4ced-1786-4e53-9e0c-5c447e959507"}}}' --- load everything: @@ -226,7 +299,7 @@ from doc with aggregate_metric_double: - match: {columns.3.type: "ip"} - match: {columns.4.name: "k8s.pod.network.tx"} - match: {columns.4.type: "long"} - - length: {values: 2} + - length: {values: 3} --- stats on aggregate_metric_double: @@ -255,9 +328,122 @@ stats on aggregate_metric_double: - match: {columns.3.name: "count(agg_metric)"} - match: {columns.3.type: "long"} - match: {values.0.0: 20.0} + - match: {values.0.1: -5.0} + - match: {values.0.2: 103.0} + - match: {values.0.3: 21.0} + +--- +grouping stats on aggregate_metric_double: + - requires: + test_runner_features: [capabilities] + capabilities: + - method: POST + path: /_query + parameters: [] + capabilities: [aggregate_metric_double] + reason: "Support for aggregate_metric_double" + - do: + allowed_warnings_regex: + - "No limit defined, adding default limit of \\[.*\\]" + esql.query: + body: + query: "FROM test2 + | STATS max(agg_metric), min(agg_metric), sum(agg_metric), count(agg_metric) BY dim + | SORT dim" + - length: {values: 2} + - length: {values.0: 5} + - match: {columns.0.name: "max(agg_metric)"} + - match: {columns.0.type: "double"} + - match: {columns.1.name: "min(agg_metric)"} + - match: {columns.1.type: "double"} + - match: {columns.2.name: "sum(agg_metric)"} + - match: {columns.2.type: "double"} + - match: {columns.3.name: "count(agg_metric)"} + - match: {columns.3.type: "long"} + - match: {columns.4.name: "dim"} + - match: {columns.4.type: "keyword"} + - match: {values.0.0: 10.0} - match: {values.0.1: -1.0} - - match: {values.0.2: 70.0} - - match: {values.0.3: 12.0} + - match: {values.0.2: 20.0} + - match: {values.0.3: 5.0} + - match: {values.0.4: "A"} + - match: {values.1.0: 20.0} + - match: {values.1.1: -5.0} + - match: {values.1.2: 83.0} + - match: {values.1.3: 16.0} + - match: {values.1.4: "B"} + +--- +stats on aggregate_metric_double with partial submetrics: + - requires: + test_runner_features: [capabilities] + capabilities: + - method: POST + path: /_query + parameters: [] + capabilities: [aggregate_metric_double_partial_submetrics] + reason: "Support for partial submetrics in aggregate_metric_double" + - do: + allowed_warnings_regex: + - "No limit defined, adding default limit of \\[.*\\]" + esql.query: + body: + query: 'FROM test3 | STATS max(agg_metric), min(agg_metric), sum(agg_metric), count(agg_metric) BY k8s.pod.uid | SORT k8s.pod.uid' + + - length: {values: 2} + - length: {values.0: 5} + - match: {columns.0.name: "max(agg_metric)"} + - match: {columns.0.type: "double"} + - match: {columns.1.name: "min(agg_metric)"} + - match: {columns.1.type: "double"} + - match: {columns.2.name: "sum(agg_metric)"} + - match: {columns.2.type: "double"} + - match: {columns.3.name: "count(agg_metric)"} + - match: {columns.3.type: "long"} + - match: {columns.4.name: "k8s.pod.uid"} + - match: {columns.4.type: "keyword"} + - match: {values.0.0: 10.0} + - match: {values.0.1: -3.0} + - match: {values.0.2: null} + - match: {values.0.3: null} + - match: {values.0.4: "947e4ced-1786-4e53-9e0c-5c447e959507"} + - match: {values.1.0: 17.0} + - match: {values.1.1: 2.0} + - match: {values.1.2: null} + - match: {values.1.3: null} + - match: {values.1.4: "df3145b3-0563-4d3b-a0f7-897eb2876ea9"} + +--- +stats on aggregate_metric_double missing min and max: + - requires: + test_runner_features: [ capabilities ] + capabilities: + - method: POST + path: /_query + parameters: [ ] + capabilities: [ aggregate_metric_double_partial_submetrics ] + reason: "Support for partial submetrics in aggregate_metric_double" + - do: + allowed_warnings_regex: + - "No limit defined, adding default limit of \\[.*\\]" + esql.query: + body: + query: 'FROM test4 | STATS max(agg_metric), min(agg_metric), sum(agg_metric), count(agg_metric)' + + - length: {values: 1} + - length: {values.0: 4} + - match: {columns.0.name: "max(agg_metric)"} + - match: {columns.0.type: "double"} + - match: {columns.1.name: "min(agg_metric)"} + - match: {columns.1.type: "double"} + - match: {columns.2.name: "sum(agg_metric)"} + - match: {columns.2.type: "double"} + - match: {columns.3.name: "count(agg_metric)"} + - match: {columns.3.type: "long"} + - match: {values.0.0: null} + - match: {values.0.1: null} + - match: {values.0.2: 1.0} + - match: {values.0.3: 10} --- from index pattern unsupported counter: @@ -267,8 +453,8 @@ from index pattern unsupported counter: - method: POST path: /_query parameters: [] - capabilities: [aggregate_metric_double] - reason: "Support for aggregate_metric_double" + capabilities: [aggregate_metric_double_partial_submetrics] + reason: "Support for partial submetrics in aggregate_metric_double" - do: allowed_warnings_regex: - "No limit defined, adding default limit of \\[.*\\]" @@ -294,7 +480,7 @@ from index pattern unsupported counter: - match: {columns.7.type: "keyword"} - match: {columns.8.name: "metricset"} - match: {columns.8.type: "keyword"} - - length: {values: 10} + - length: {values: 15} --- from index pattern explicit counter use: @@ -315,7 +501,7 @@ from index pattern explicit counter use: query: 'FROM test* | keep *.tx' - match: {columns.0.name: "k8s.pod.network.tx"} - match: {columns.0.type: "unsupported"} - - length: {values: 10} + - length: {values: 15} --- _source: diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/ml/job_cat_apis.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/ml/job_cat_apis.yml index 25a127f077c2..a95f59e81e58 100644 --- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/ml/job_cat_apis.yml +++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/ml/job_cat_apis.yml @@ -87,6 +87,8 @@ setup: {"airline":"JZA","responsetime":"244.1276","time":"1403485200"} - do: + warnings: + - 'Forcing any buffered data to be processed is deprecated, in a future major version it will be compulsory to use a datafeed' ml.flush_job: job_id: job-stats-test - match: { flushed: true } diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/ml/jobs_get_stats.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/ml/jobs_get_stats.yml index 6aab1fb9e894..ab4c7311d830 100644 --- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/ml/jobs_get_stats.yml +++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/ml/jobs_get_stats.yml @@ -87,6 +87,8 @@ setup: {"airline":"JZA","responsetime":"244.1276","time":"1403485200"} - do: + warnings: + - 'Forcing any buffered data to be processed is deprecated, in a future major version it will be compulsory to use a datafeed' ml.flush_job: job_id: job-stats-test - match: { flushed: true } @@ -131,6 +133,8 @@ setup: {"airline":"JZA","responsetime":"244.1276","time":"1403485200"} - do: + warnings: + - 'Forcing any buffered data to be processed is deprecated, in a future major version it will be compulsory to use a datafeed' ml.flush_job: job_id: job-stats-test - match: { flushed: true } diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/ml/post_data.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/ml/post_data.yml index 9577f80f4592..7cf56d757c09 100644 --- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/ml/post_data.yml +++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/ml/post_data.yml @@ -77,6 +77,8 @@ setup: - match: { latest_record_timestamp: 1403481700000} - do: + warnings: + - 'Forcing any buffered data to be processed is deprecated, in a future major version it will be compulsory to use a datafeed' ml.flush_job: job_id: post-data-job - match: { flushed: true } @@ -110,7 +112,12 @@ setup: --- "Test flush and close job WITHOUT sending any data": + - skip: + features: + - "warnings" - do: + warnings: + - 'Forcing any buffered data to be processed is deprecated, in a future major version it will be compulsory to use a datafeed' ml.flush_job: job_id: post-data-job - match: { flushed: true } @@ -150,6 +157,8 @@ setup: # Skip a bucket - do: + warnings: + - 'Forcing any buffered data to be processed is deprecated, in a future major version it will be compulsory to use a datafeed' ml.flush_job: job_id: post-data-job skip_time: 1403488700 @@ -266,26 +275,36 @@ setup: - skip: reason: "https://github.com/elastic/elasticsearch/issues/34747" cluster_features: ["gte_v6.5.0"] + features: + - "warnings" - do: catch: missing + warnings: + - 'Forcing any buffered data to be processed is deprecated, in a future major version it will be compulsory to use a datafeed' ml.flush_job: job_id: not_a_job - do: catch: /parse_exception/ + warnings: + - 'Forcing any buffered data to be processed is deprecated, in a future major version it will be compulsory to use a datafeed' ml.flush_job: job_id: post-data-job start: not_a_date - do: catch: /parse_exception/ + warnings: + - 'Forcing any buffered data to be processed is deprecated, in a future major version it will be compulsory to use a datafeed' ml.flush_job: job_id: post-data-job end: end_not_a_date - do: catch: /parse_exception/ + warnings: + - 'Forcing any buffered data to be processed is deprecated, in a future major version it will be compulsory to use a datafeed' ml.flush_job: job_id: post-data-job advance_time: advance_time_not_a_date @@ -311,6 +330,8 @@ setup: - do: catch: /status_exception/ + warnings: + - 'Forcing any buffered data to be processed is deprecated, in a future major version it will be compulsory to use a datafeed' ml.flush_job: job_id: post-data-closed-job diff --git a/x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/notifications/TransformAuditor.java b/x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/notifications/TransformAuditor.java index 51e679ff9fe6..402a8cbe12bd 100644 --- a/x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/notifications/TransformAuditor.java +++ b/x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/notifications/TransformAuditor.java @@ -52,7 +52,8 @@ public class TransformAuditor extends AbstractAuditor { nodeName, TransformAuditMessage::new, clusterService, - indexNameExpressionResolver + indexNameExpressionResolver, + clusterService.threadPool().generic() ); clusterService.addListener(event -> { if (event.metadataChanged()) { diff --git a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/action/TransformUpdaterTests.java b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/action/TransformUpdaterTests.java index b9d91287ce45..3231d705f389 100644 --- a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/action/TransformUpdaterTests.java +++ b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/action/TransformUpdaterTests.java @@ -18,7 +18,6 @@ import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.client.internal.Client; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; -import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.core.Tuple; @@ -66,7 +65,6 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; -import static org.mockito.Mockito.mock; public class TransformUpdaterTests extends ESTestCase { @@ -77,8 +75,7 @@ public class TransformUpdaterTests extends ESTestCase { private final IndexNameExpressionResolver indexNameExpressionResolver = TestIndexNameExpressionResolver.newInstance(); private TestThreadPool threadPool; private Client client; - private ClusterService clusterService = mock(ClusterService.class); - private TransformAuditor auditor = new MockTransformAuditor(clusterService, mock(IndexNameExpressionResolver.class)); + private TransformAuditor auditor; private final Settings settings = Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build(); private final Settings destIndexSettings = new DefaultTransformExtension().getTransformDestinationIndexSettings(); @@ -124,8 +121,7 @@ public class TransformUpdaterTests extends ESTestCase { } threadPool = createThreadPool(); client = new MyMockClient(threadPool); - clusterService = mock(ClusterService.class); - auditor = new MockTransformAuditor(clusterService, mock(IndexNameExpressionResolver.class)); + auditor = MockTransformAuditor.createMockAuditor(); } @After diff --git a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/notifications/MockTransformAuditor.java b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/notifications/MockTransformAuditor.java index 758d29381c97..e4f1251bbede 100644 --- a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/notifications/MockTransformAuditor.java +++ b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/notifications/MockTransformAuditor.java @@ -17,6 +17,8 @@ import org.elasticsearch.cluster.metadata.Metadata; import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.regex.Regex; +import org.elasticsearch.common.util.concurrent.EsExecutors; +import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.core.common.notifications.Level; import org.elasticsearch.xpack.core.transform.notifications.TransformAuditMessage; @@ -54,13 +56,16 @@ public class MockTransformAuditor extends TransformAuditor { when(state.getMetadata()).thenReturn(metadata); ClusterService clusterService = mock(ClusterService.class); when(clusterService.state()).thenReturn(state); + ThreadPool threadPool = mock(); + when(threadPool.generic()).thenReturn(EsExecutors.DIRECT_EXECUTOR_SERVICE); + when(clusterService.threadPool()).thenReturn(threadPool); return new MockTransformAuditor(clusterService, mock(IndexNameExpressionResolver.class)); } private final List expectations; - public MockTransformAuditor(ClusterService clusterService, IndexNameExpressionResolver indexNameResolver) { + private MockTransformAuditor(ClusterService clusterService, IndexNameExpressionResolver indexNameResolver) { super(mock(Client.class), MOCK_NODE_NAME, clusterService, indexNameResolver, true); expectations = new CopyOnWriteArrayList<>(); } diff --git a/x-pack/qa/core-rest-tests-with-security/build.gradle b/x-pack/qa/core-rest-tests-with-security/build.gradle index a3f50089d542..f85d6ba961e0 100644 --- a/x-pack/qa/core-rest-tests-with-security/build.gradle +++ b/x-pack/qa/core-rest-tests-with-security/build.gradle @@ -32,8 +32,6 @@ tasks.named("yamlRestTest").configure { ArrayList blacklist = [ 'index/10_with_id/Index with ID', 'indices.get_alias/10_basic/Get alias against closed indices', - 'update/100_synthetic_source/keyword', - 'update/100_synthetic_source/stored text' ]; if (buildParams.isSnapshotBuild() == false) { blacklist += [ diff --git a/x-pack/qa/core-rest-tests-with-security/src/yamlRestTest/java/org/elasticsearch/xpack/security/CoreWithSecurityClientYamlTestSuiteIT.java b/x-pack/qa/core-rest-tests-with-security/src/yamlRestTest/java/org/elasticsearch/xpack/security/CoreWithSecurityClientYamlTestSuiteIT.java index 94eeee5ed929..16baa729d970 100644 --- a/x-pack/qa/core-rest-tests-with-security/src/yamlRestTest/java/org/elasticsearch/xpack/security/CoreWithSecurityClientYamlTestSuiteIT.java +++ b/x-pack/qa/core-rest-tests-with-security/src/yamlRestTest/java/org/elasticsearch/xpack/security/CoreWithSecurityClientYamlTestSuiteIT.java @@ -50,6 +50,7 @@ public class CoreWithSecurityClientYamlTestSuiteIT extends ESClientYamlSuiteTest .user(USER, PASS) .feature(FeatureFlag.TIME_SERIES_MODE) .feature(FeatureFlag.SUB_OBJECTS_AUTO_ENABLED) + .feature(FeatureFlag.INDEX_RECOVERY_USE_SYNTHETIC_SOURCE) .build(); public CoreWithSecurityClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) { diff --git a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java index 6f72382078a2..ca5fdf94e28f 100644 --- a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java +++ b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java @@ -8,12 +8,15 @@ package org.elasticsearch.upgrades; import org.apache.http.util.EntityUtils; import org.elasticsearch.Build; +import org.elasticsearch.TransportVersions; import org.elasticsearch.Version; import org.elasticsearch.client.Node; import org.elasticsearch.client.Request; +import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.Response; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; +import org.elasticsearch.client.WarningsHandler; import org.elasticsearch.cluster.metadata.DataStream; import org.elasticsearch.cluster.metadata.DataStreamTestHelper; import org.elasticsearch.common.settings.SecureString; @@ -194,20 +197,79 @@ public class DataStreamsUpgradeIT extends AbstractUpgradeTestCase { createAndRolloverDataStream(dataStreamName, numRollovers); createDataStreamFromNonDataStreamIndices(dataStreamFromNonDataStreamIndices); } else if (CLUSTER_TYPE == ClusterType.UPGRADED) { + Map> oldIndicesMetadata = getIndicesMetadata(dataStreamName); upgradeDataStream(dataStreamName, numRollovers, numRollovers + 1, 0); upgradeDataStream(dataStreamFromNonDataStreamIndices, 0, 1, 0); + Map> upgradedIndicesMetadata = getIndicesMetadata(dataStreamName); + compareIndexMetadata(oldIndicesMetadata, upgradedIndicesMetadata); } } - private static void createAndRolloverDataStream(String dataStreamName, int numRollovers) throws IOException { + private void compareIndexMetadata( + Map> oldIndicesMetadata, + Map> upgradedIndicesMetadata + ) { + for (Map.Entry> upgradedIndexEntry : upgradedIndicesMetadata.entrySet()) { + String upgradedIndexName = upgradedIndexEntry.getKey(); + if (upgradedIndexName.startsWith(".migrated-")) { + String oldIndexName = "." + upgradedIndexName.substring(".migrated-".length()); + Map oldIndexMetadata = oldIndicesMetadata.get(oldIndexName); + Map upgradedIndexMetadata = upgradedIndexEntry.getValue(); + compareSettings(oldIndexMetadata, upgradedIndexMetadata); + assertThat("Mappings did not match", upgradedIndexMetadata.get("mappings"), equalTo(oldIndexMetadata.get("mappings"))); + // TODO: Uncomment the following two checks once we are correctly copying this state over: + // assertThat("ILM states did not match", upgradedIndexMetadata.get("ilm"), equalTo(oldIndexMetadata.get("ilm"))); + // assertThat( + // "Rollover info did not match", + // upgradedIndexMetadata.get("rollover_info"), + // equalTo(oldIndexMetadata.get("rollover_info")) + // ); + assertThat(upgradedIndexMetadata.get("system"), equalTo(oldIndexMetadata.get("system"))); + } + } + } + + private void compareSettings(Map oldIndexMetadata, Map upgradedIndexMetadata) { + Map oldIndexSettings = getIndexSettingsFromIndexMetadata(oldIndexMetadata); + Map upgradedIndexSettings = getIndexSettingsFromIndexMetadata(upgradedIndexMetadata); + final Set SETTINGS_TO_CHECK = Set.of( + "lifecycle", + "mode", + "routing", + "hidden", + "number_of_shards", + // "creation_date", TODO: Uncomment this once we are correctly copying over this setting + "number_of_replicas" + ); + for (String setting : SETTINGS_TO_CHECK) { + assertThat( + "Unexpected value for setting " + setting, + upgradedIndexSettings.get(setting), + equalTo(oldIndexSettings.get(setting)) + ); + } + } + + @SuppressWarnings("unchecked") + private Map getIndexSettingsFromIndexMetadata(Map indexMetadata) { + return (Map) ((Map) indexMetadata.get("settings")).get("index"); + } + + private void createAndRolloverDataStream(String dataStreamName, int numRollovers) throws IOException { + boolean useIlm = randomBoolean(); + if (useIlm) { + createIlmPolicy(); + } // We want to create a data stream and roll it over several times so that we have several indices to upgrade - final String template = """ + String template = """ { "settings":{ "index": { + $ILM_SETTING "mode": "time_series" } }, + $DSL_TEMPLATE "mappings":{ "dynamic_templates": [ { @@ -253,6 +315,19 @@ public class DataStreamsUpgradeIT extends AbstractUpgradeTestCase { } } """; + if (useIlm) { + template = template.replace("$ILM_SETTING", """ + "lifecycle.name": "test-lifecycle-policy", + """); + template = template.replace("$DSL_TEMPLATE", ""); + } else { + template = template.replace("$ILM_SETTING", ""); + template = template.replace("$DSL_TEMPLATE", """ + "lifecycle": { + "data_retention": "7d" + }, + """); + } final String indexTemplate = """ { "index_patterns": ["$PATTERN"], @@ -273,6 +348,52 @@ public class DataStreamsUpgradeIT extends AbstractUpgradeTestCase { } } + private static void createIlmPolicy() throws IOException { + String ilmPolicy = """ + { + "policy": { + "phases": { + "hot": { + "actions": { + "rollover": { + "max_primary_shard_size": "50kb" + } + } + }, + "warm": { + "min_age": "30d", + "actions": { + "shrink": { + "number_of_shards": 1 + }, + "forcemerge": { + "max_num_segments": 1 + } + } + } + } + } + }"""; + Request putIlmPolicyRequest = new Request("PUT", "_ilm/policy/test-lifecycle-policy"); + putIlmPolicyRequest.setJsonEntity(ilmPolicy); + assertOK(client().performRequest(putIlmPolicyRequest)); + } + + /* + * This returns a Map of index metadata for each index in the data stream, as retrieved from the cluster state. + */ + @SuppressWarnings("unchecked") + private Map> getIndicesMetadata(String dataStreamName) throws IOException { + Request getClusterStateRequest = new Request("GET", "/_cluster/state/metadata/" + dataStreamName); + Response clusterStateResponse = client().performRequest(getClusterStateRequest); + Map clusterState = XContentHelper.convertToMap( + JsonXContent.jsonXContent, + clusterStateResponse.getEntity().getContent(), + false + ); + return ((Map>>) clusterState.get("metadata")).get("indices"); + } + private void createDataStreamFromNonDataStreamIndices(String dataStreamFromNonDataStreamIndices) throws IOException { /* * This method creates an index, creates an alias to that index, and then converts the aliased index into a data stream. This is @@ -300,8 +421,27 @@ public class DataStreamsUpgradeIT extends AbstractUpgradeTestCase { putIndexTemplateRequest.setJsonEntity( indexTemplate.replace("$TEMPLATE", templateWithNoTimestamp).replace("$PATTERN", dataStreamFromNonDataStreamIndices + "-*") ); - assertOK(client().performRequest(putIndexTemplateRequest)); String indexName = dataStreamFromNonDataStreamIndices + "-01"; + if (minimumTransportVersion().before(TransportVersions.V_8_0_0)) { + /* + * It is not possible to create a 7.x index template with a type. And you can't create an empty index with a type. But you can + * create the index with a type by posting a document to an index with a type. We do that here so that we test that the type is + * removed when we reindex into 8.x. + */ + String typeName = "test-type"; + Request createIndexRequest = new Request("POST", indexName + "/" + typeName); + createIndexRequest.setJsonEntity(""" + { + "@timestamp": "2099-11-15T13:12:00", + "message": "GET /search HTTP/1.1 200 1070000", + "user": { + "id": "kimchy" + } + }"""); + createIndexRequest.setOptions(RequestOptions.DEFAULT.toBuilder().setWarningsHandler(WarningsHandler.PERMISSIVE).build()); + assertOK(client().performRequest(createIndexRequest)); + } + assertOK(client().performRequest(putIndexTemplateRequest)); bulkLoadDataMissingTimestamp(indexName); /* * Next, we will change the index's mapping to include a @timestamp field since we are going to convert it to a data stream. But diff --git a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/MlJobSnapshotUpgradeIT.java b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/MlJobSnapshotUpgradeIT.java index f9d28670dab6..75613c7e3ebc 100644 --- a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/MlJobSnapshotUpgradeIT.java +++ b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/MlJobSnapshotUpgradeIT.java @@ -338,7 +338,23 @@ public class MlJobSnapshotUpgradeIT extends AbstractUpgradeTestCase { } protected void flushJob(String jobId) throws IOException { - client().performRequest(new Request("POST", "/_ml/anomaly_detectors/" + jobId + "/_flush")); + // Flush job is deprecated, so a deprecation warning is possible (depending on the old version) + RequestOptions flushOptions = RequestOptions.DEFAULT.toBuilder().setWarningsHandler(warnings -> { + if (warnings.isEmpty()) { + // No warning is OK - it means we hit an old node where flush is not deprecated + return false; + } else if (warnings.size() > 1) { + return true; + } + return warnings.get(0) + .equals( + "Forcing any buffered data to be processed is deprecated, " + + "in a future major version it will be compulsory to use a datafeed" + ) == false; + }).build(); + Request flushRequest = new Request("POST", "/_ml/anomaly_detectors/" + jobId + "/_flush"); + flushRequest.setOptions(flushOptions); + client().performRequest(flushRequest); } private void closeJob(String jobId) throws IOException {