diff --git a/docs/changelog/125570.yaml b/docs/changelog/125570.yaml
deleted file mode 100644
index ede177c666470..0000000000000
--- a/docs/changelog/125570.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125570
-summary: ES|QL random sampling
-area: Machine Learning
-type: feature
-issues: []
diff --git a/docs/changelog/129797.yaml b/docs/changelog/129797.yaml
new file mode 100644
index 0000000000000..dd2d4d397214d
--- /dev/null
+++ b/docs/changelog/129797.yaml
@@ -0,0 +1,5 @@
+pr: 129797
+summary: "Revert \"[8.19] Backport ES|QL sample processing command\""
+area: ES|QL
+type: bug
+issues: []
diff --git a/docs/reference/esql/esql-commands.asciidoc b/docs/reference/esql/esql-commands.asciidoc
index 1a3ad359da436..f66b420ba503e 100644
--- a/docs/reference/esql/esql-commands.asciidoc
+++ b/docs/reference/esql/esql-commands.asciidoc
@@ -46,7 +46,6 @@ endif::[]
* experimental:[] <>
* experimental:[] <>
* <>
-* experimental:[] <>
* <>
* <>
* <>
@@ -71,7 +70,6 @@ include::processing-commands/limit.asciidoc[]
include::processing-commands/lookup.asciidoc[]
include::processing-commands/mv_expand.asciidoc[]
include::processing-commands/rename.asciidoc[]
-include::processing-commands/sample.asciidoc[]
include::processing-commands/sort.asciidoc[]
include::processing-commands/stats.asciidoc[]
include::processing-commands/where.asciidoc[]
diff --git a/docs/reference/esql/functions/description/date_trunc.asciidoc b/docs/reference/esql/functions/description/date_trunc.asciidoc
index 1fb874e3bd9cd..14824ff534402 100644
--- a/docs/reference/esql/functions/description/date_trunc.asciidoc
+++ b/docs/reference/esql/functions/description/date_trunc.asciidoc
@@ -2,4 +2,4 @@
*Description*
-Rounds down a date to the closest interval.
+Rounds down a date to the closest interval since epoch, which starts at `0001-01-01T00:00:00Z`.
diff --git a/docs/reference/esql/functions/kibana/docs/date_trunc.md b/docs/reference/esql/functions/kibana/docs/date_trunc.md
index baa36d79d2f93..158bb02d86d0d 100644
--- a/docs/reference/esql/functions/kibana/docs/date_trunc.md
+++ b/docs/reference/esql/functions/kibana/docs/date_trunc.md
@@ -3,9 +3,7 @@ This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../READ
-->
### DATE_TRUNC
-
-Rounds down a date to the closest interval since epoch, which starts
-at `0001-01-01T00:00:00Z`.
+Rounds down a date to the closest interval since epoch, which starts at `0001-01-01T00:00:00Z`.
```
FROM employees
diff --git a/docs/reference/esql/functions/kibana/docs/sample.md b/docs/reference/esql/functions/kibana/docs/sample.md
index 9d09e04688c1f..e69de29bb2d1d 100644
--- a/docs/reference/esql/functions/kibana/docs/sample.md
+++ b/docs/reference/esql/functions/kibana/docs/sample.md
@@ -1,11 +0,0 @@
-
-
-### SAMPLE
-Collects sample values for a field.
-
-```
-FROM employees
-| STATS sample = SAMPLE(gender, 5)
-```
diff --git a/docs/reference/esql/functions/types/to_ip.asciidoc b/docs/reference/esql/functions/types/to_ip.asciidoc
index d2f94889b81ef..6de0e250a0cb9 100644
--- a/docs/reference/esql/functions/types/to_ip.asciidoc
+++ b/docs/reference/esql/functions/types/to_ip.asciidoc
@@ -4,8 +4,8 @@
[%header.monospaced.styled,format=dsv,separator=|]
|===
-field | result
-ip | ip
-keyword | ip
-text | ip
+field | options | result
+ip | | ip
+keyword | | ip
+text | | ip
|===
diff --git a/docs/reference/esql/processing-commands/sample.asciidoc b/docs/reference/esql/processing-commands/sample.asciidoc
deleted file mode 100644
index a5c2a2f7e0b30..0000000000000
--- a/docs/reference/esql/processing-commands/sample.asciidoc
+++ /dev/null
@@ -1,30 +0,0 @@
-[discrete]
-[[esql-sample]]
-=== `SAMPLE`
-
-preview::[]
-
-The `SAMPLE` command samples a fraction of the table rows.
-
-**Syntax**
-
-[source,esql]
-----
-SAMPLE probability
-----
-
-*Parameters*
-
-`probability`::
-The probability that a row is included in the sample. The value must be between 0 and 1, exclusive.
-
-*Example*
-
-[source.merge.styled,esql]
-----
-include::{esql-specs}/sample.csv-spec[tag=sampleForDocs]
-----
-[%header.monospaced.styled,format=dsv,separator=|]
-|===
-include::{esql-specs}/sample.csv-spec[tag=sampleForDocs-result]
-|===
diff --git a/docs/reference/rest-api/usage.asciidoc b/docs/reference/rest-api/usage.asciidoc
index a04be2cb142ff..0a9d4a4367dfc 100644
--- a/docs/reference/rest-api/usage.asciidoc
+++ b/docs/reference/rest-api/usage.asciidoc
@@ -249,8 +249,7 @@ GET /_xpack/usage
"lookup_join" : 0,
"change_point" : 0,
"completion": 0,
- "rerank": 0,
- "sample": 0
+ "rerank": 0
},
"queries" : {
"rest" : {
diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java
index 96ec8c7d1762e..baf52f3f67d4e 100644
--- a/server/src/main/java/org/elasticsearch/TransportVersions.java
+++ b/server/src/main/java/org/elasticsearch/TransportVersions.java
@@ -244,7 +244,6 @@ static TransportVersion def(int id) {
public static final TransportVersion SETTINGS_IN_DATA_STREAMS_8_19 = def(8_841_0_51);
public static final TransportVersion ML_INFERENCE_CUSTOM_SERVICE_REMOVE_ERROR_PARSING_8_19 = def(8_841_0_52);
public static final TransportVersion ML_INFERENCE_CUSTOM_SERVICE_EMBEDDING_BATCH_SIZE_8_19 = def(8_841_0_53);
- public static final TransportVersion RANDOM_SAMPLER_QUERY_BUILDER_8_19 = def(8_841_0_54);
/*
* STOP! READ THIS FIRST! No, really,
diff --git a/server/src/main/java/org/elasticsearch/search/SearchModule.java b/server/src/main/java/org/elasticsearch/search/SearchModule.java
index d72c7e1be1e7a..fd8630154bd6d 100644
--- a/server/src/main/java/org/elasticsearch/search/SearchModule.java
+++ b/server/src/main/java/org/elasticsearch/search/SearchModule.java
@@ -137,7 +137,6 @@
import org.elasticsearch.search.aggregations.bucket.sampler.UnmappedSampler;
import org.elasticsearch.search.aggregations.bucket.sampler.random.InternalRandomSampler;
import org.elasticsearch.search.aggregations.bucket.sampler.random.RandomSamplerAggregationBuilder;
-import org.elasticsearch.search.aggregations.bucket.sampler.random.RandomSamplingQueryBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.DoubleTerms;
import org.elasticsearch.search.aggregations.bucket.terms.LongRareTerms;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
@@ -1210,9 +1209,6 @@ private void registerQueryParsers(List plugins) {
registerQuery(new QuerySpec<>(ExactKnnQueryBuilder.NAME, ExactKnnQueryBuilder::new, parser -> {
throw new IllegalArgumentException("[exact_knn] queries cannot be provided directly");
}));
- registerQuery(
- new QuerySpec<>(RandomSamplingQueryBuilder.NAME, RandomSamplingQueryBuilder::new, RandomSamplingQueryBuilder::fromXContent)
- );
registerFromPlugin(plugins, SearchPlugin::getQueries, this::registerQuery);
diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/sampler/random/RandomSamplingQuery.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/sampler/random/RandomSamplingQuery.java
index fb8e992e806ce..ed39f41d9daed 100644
--- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/sampler/random/RandomSamplingQuery.java
+++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/sampler/random/RandomSamplingQuery.java
@@ -43,34 +43,14 @@ public final class RandomSamplingQuery extends Query {
* can be generated
*/
public RandomSamplingQuery(double p, int seed, int hash) {
- checkProbabilityRange(p);
+ if (p <= 0.0 || p >= 1.0) {
+ throw new IllegalArgumentException("RandomSampling probability must be between 0.0 and 1.0, was [" + p + "]");
+ }
this.p = p;
this.seed = seed;
this.hash = hash;
}
- /**
- * Verifies that the probability is within the (0.0, 1.0) range.
- * @throws IllegalArgumentException in case of an invalid probability.
- */
- public static void checkProbabilityRange(double p) throws IllegalArgumentException {
- if (p <= 0.0 || p >= 1.0) {
- throw new IllegalArgumentException("RandomSampling probability must be strictly between 0.0 and 1.0, was [" + p + "]");
- }
- }
-
- public double probability() {
- return p;
- }
-
- public int seed() {
- return seed;
- }
-
- public int hash() {
- return hash;
- }
-
@Override
public String toString(String field) {
return "RandomSamplingQuery{" + "p=" + p + ", seed=" + seed + ", hash=" + hash + '}';
@@ -117,13 +97,13 @@ public void visit(QueryVisitor visitor) {
/**
* A DocIDSetIter that skips a geometrically random number of documents
*/
- public static class RandomSamplingIterator extends DocIdSetIterator {
+ static class RandomSamplingIterator extends DocIdSetIterator {
private final int maxDoc;
private final double p;
private final FastGeometric distribution;
private int doc = -1;
- public RandomSamplingIterator(int maxDoc, double p, IntSupplier rng) {
+ RandomSamplingIterator(int maxDoc, double p, IntSupplier rng) {
this.maxDoc = maxDoc;
this.p = p;
this.distribution = new FastGeometric(rng, p);
diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/sampler/random/RandomSamplingQueryBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/sampler/random/RandomSamplingQueryBuilder.java
deleted file mode 100644
index b19a4de19160c..0000000000000
--- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/sampler/random/RandomSamplingQueryBuilder.java
+++ /dev/null
@@ -1,149 +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.search.aggregations.bucket.sampler.random;
-
-import org.apache.lucene.search.Query;
-import org.elasticsearch.TransportVersion;
-import org.elasticsearch.TransportVersions;
-import org.elasticsearch.common.Randomness;
-import org.elasticsearch.common.io.stream.StreamInput;
-import org.elasticsearch.common.io.stream.StreamOutput;
-import org.elasticsearch.index.query.AbstractQueryBuilder;
-import org.elasticsearch.index.query.SearchExecutionContext;
-import org.elasticsearch.xcontent.ConstructingObjectParser;
-import org.elasticsearch.xcontent.ParseField;
-import org.elasticsearch.xcontent.XContentBuilder;
-import org.elasticsearch.xcontent.XContentParser;
-
-import java.io.IOException;
-import java.util.Objects;
-
-import static org.elasticsearch.search.aggregations.bucket.sampler.random.RandomSamplingQuery.checkProbabilityRange;
-import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
-import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstructorArg;
-
-public class RandomSamplingQueryBuilder extends AbstractQueryBuilder {
-
- public static final String NAME = "random_sampling";
- static final ParseField PROBABILITY = new ParseField("query");
- static final ParseField SEED = new ParseField("seed");
- static final ParseField HASH = new ParseField("hash");
-
- private final double probability;
- private int seed = Randomness.get().nextInt();
- private int hash = 0;
-
- public RandomSamplingQueryBuilder(double probability) {
- checkProbabilityRange(probability);
- this.probability = probability;
- }
-
- public RandomSamplingQueryBuilder seed(int seed) {
- checkProbabilityRange(probability);
- this.seed = seed;
- return this;
- }
-
- public RandomSamplingQueryBuilder(StreamInput in) throws IOException {
- super(in);
- this.probability = in.readDouble();
- this.seed = in.readInt();
- this.hash = in.readInt();
- }
-
- public RandomSamplingQueryBuilder hash(Integer hash) {
- this.hash = hash;
- return this;
- }
-
- public double probability() {
- return probability;
- }
-
- public int seed() {
- return seed;
- }
-
- public int hash() {
- return hash;
- }
-
- @Override
- protected void doWriteTo(StreamOutput out) throws IOException {
- out.writeDouble(probability);
- out.writeInt(seed);
- out.writeInt(hash);
- }
-
- @Override
- protected void doXContent(XContentBuilder builder, Params params) throws IOException {
- builder.startObject(NAME);
- builder.field(PROBABILITY.getPreferredName(), probability);
- builder.field(SEED.getPreferredName(), seed);
- builder.field(HASH.getPreferredName(), hash);
- builder.endObject();
- }
-
- private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
- NAME,
- false,
- args -> {
- var randomSamplingQueryBuilder = new RandomSamplingQueryBuilder((double) args[0]);
- if (args[1] != null) {
- randomSamplingQueryBuilder.seed((int) args[1]);
- }
- if (args[2] != null) {
- randomSamplingQueryBuilder.hash((int) args[2]);
- }
- return randomSamplingQueryBuilder;
- }
- );
-
- static {
- PARSER.declareDouble(constructorArg(), PROBABILITY);
- PARSER.declareInt(optionalConstructorArg(), SEED);
- PARSER.declareInt(optionalConstructorArg(), HASH);
- }
-
- public static RandomSamplingQueryBuilder fromXContent(XContentParser parser) throws IOException {
- return PARSER.apply(parser, null);
- }
-
- @Override
- protected Query doToQuery(SearchExecutionContext context) throws IOException {
- return new RandomSamplingQuery(probability, seed, hash);
- }
-
- @Override
- protected boolean doEquals(RandomSamplingQueryBuilder other) {
- return probability == other.probability && seed == other.seed && hash == other.hash;
- }
-
- @Override
- protected int doHashCode() {
- return Objects.hash(probability, seed, hash);
- }
-
- /**
- * Returns the name of the writeable object
- */
- @Override
- public String getWriteableName() {
- return NAME;
- }
-
- /**
- * The minimal version of the recipient this object can be sent to
- */
- @Override
- public TransportVersion getMinimalSupportedVersion() {
- return TransportVersions.RANDOM_SAMPLER_QUERY_BUILDER_8_19;
- }
-}
diff --git a/server/src/test/java/org/elasticsearch/search/SearchModuleTests.java b/server/src/test/java/org/elasticsearch/search/SearchModuleTests.java
index d0fbd84379c61..0a3c2c939b456 100644
--- a/server/src/test/java/org/elasticsearch/search/SearchModuleTests.java
+++ b/server/src/test/java/org/elasticsearch/search/SearchModuleTests.java
@@ -449,7 +449,6 @@ public CheckedBiConsumer getReque
"range",
"regexp",
"knn_score_doc",
- "random_sampling",
"script",
"script_score",
"simple_query_string",
diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/sampler/random/RandomSamplingQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/sampler/random/RandomSamplingQueryBuilderTests.java
deleted file mode 100644
index d64068042a57c..0000000000000
--- a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/sampler/random/RandomSamplingQueryBuilderTests.java
+++ /dev/null
@@ -1,75 +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.search.aggregations.bucket.sampler.random;
-
-import org.apache.lucene.search.Query;
-import org.elasticsearch.index.query.SearchExecutionContext;
-import org.elasticsearch.test.AbstractQueryTestCase;
-import org.elasticsearch.xcontent.XContentParseException;
-
-import java.io.IOException;
-
-import static org.hamcrest.Matchers.equalTo;
-
-public class RandomSamplingQueryBuilderTests extends AbstractQueryTestCase {
-
- @Override
- protected RandomSamplingQueryBuilder doCreateTestQueryBuilder() {
- double probability = randomDoubleBetween(0.0, 1.0, false);
- var builder = new RandomSamplingQueryBuilder(probability);
- if (randomBoolean()) {
- builder.seed(randomInt());
- }
- if (randomBoolean()) {
- builder.hash(randomInt());
- }
- return builder;
- }
-
- @Override
- protected void doAssertLuceneQuery(RandomSamplingQueryBuilder queryBuilder, Query query, SearchExecutionContext context)
- throws IOException {
- var rsQuery = asInstanceOf(RandomSamplingQuery.class, query);
- assertThat(rsQuery.probability(), equalTo(queryBuilder.probability()));
- assertThat(rsQuery.seed(), equalTo(queryBuilder.seed()));
- assertThat(rsQuery.hash(), equalTo(queryBuilder.hash()));
- }
-
- @Override
- protected boolean supportsBoost() {
- return false;
- }
-
- @Override
- protected boolean supportsQueryName() {
- return false;
- }
-
- @Override
- public void testUnknownField() {
- var json = "{ \""
- + RandomSamplingQueryBuilder.NAME
- + "\" : {\"bogusField\" : \"someValue\", \""
- + RandomSamplingQueryBuilder.PROBABILITY.getPreferredName()
- + "\" : \""
- + randomBoolean()
- + "\", \""
- + RandomSamplingQueryBuilder.SEED.getPreferredName()
- + "\" : \""
- + randomInt()
- + "\", \""
- + RandomSamplingQueryBuilder.HASH.getPreferredName()
- + "\" : \""
- + randomInt()
- + "\" } }";
- var e = expectThrows(XContentParseException.class, () -> parseQuery(json));
- assertTrue(e.getMessage().contains("bogusField"));
- }
-}
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/MetadataAttribute.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/MetadataAttribute.java
index 3260489983abd..c922d0f928640 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/MetadataAttribute.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/MetadataAttribute.java
@@ -172,10 +172,6 @@ public static boolean isSupported(String name) {
return ATTRIBUTES_MAP.containsKey(name);
}
- public static boolean isScoreAttribute(Expression a) {
- return a instanceof MetadataAttribute ma && ma.name().equals(SCORE);
- }
-
@Override
@SuppressWarnings("checkstyle:EqualsHashCode")// equals is implemented in parent. See innerEquals instead
public int hashCode() {
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/Page.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/Page.java
index 240e701e5062b..5958bb6a966ee 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/Page.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/Page.java
@@ -294,21 +294,4 @@ public Page projectBlocks(int[] blockMapping) {
}
}
}
-
- public Page filter(int... positions) {
- Block[] filteredBlocks = new Block[blocks.length];
- boolean success = false;
- try {
- for (int i = 0; i < blocks.length; i++) {
- filteredBlocks[i] = getBlock(i).filter(positions);
- }
- success = true;
- } finally {
- releaseBlocks();
- if (success == false) {
- Releasables.closeExpectNoException(filteredBlocks);
- }
- }
- return new Page(filteredBlocks);
- }
}
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
index 21efa314f1eed..2693c13a5383a 100644
--- 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
@@ -19,9 +19,9 @@
import org.elasticsearch.xpack.ml.aggs.changepoint.ChangePointDetector;
import org.elasticsearch.xpack.ml.aggs.changepoint.ChangeType;
-import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
+import java.util.LinkedList;
import java.util.List;
/**
@@ -68,8 +68,8 @@ public ChangePointOperator(DriverContext driverContext, int channel, String sour
this.sourceColumn = sourceColumn;
finished = false;
- inputPages = new ArrayDeque<>();
- outputPages = new ArrayDeque<>();
+ inputPages = new LinkedList<>();
+ outputPages = new LinkedList<>();
warnings = null;
}
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/FilterOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/FilterOperator.java
index d95f60f2191c8..5b8d485c4da3a 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/FilterOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/FilterOperator.java
@@ -7,6 +7,7 @@
package org.elasticsearch.compute.operator;
+import org.elasticsearch.compute.data.Block;
import org.elasticsearch.compute.data.BooleanBlock;
import org.elasticsearch.compute.data.Page;
import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator;
@@ -68,7 +69,20 @@ protected Page process(Page page) {
}
positions = Arrays.copyOf(positions, rowCount);
- return page.filter(positions);
+ Block[] filteredBlocks = new Block[page.getBlockCount()];
+ boolean success = false;
+ try {
+ for (int i = 0; i < page.getBlockCount(); i++) {
+ filteredBlocks[i] = page.getBlock(i).filter(positions);
+ }
+ success = true;
+ } finally {
+ page.releaseBlocks();
+ if (success == false) {
+ Releasables.closeExpectNoException(filteredBlocks);
+ }
+ }
+ return new Page(filteredBlocks);
}
}
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/SampleOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/SampleOperator.java
deleted file mode 100644
index 56ba95f66f5fa..0000000000000
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/SampleOperator.java
+++ /dev/null
@@ -1,242 +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.compute.operator;
-
-import org.elasticsearch.TransportVersion;
-import org.elasticsearch.TransportVersions;
-import org.elasticsearch.common.Randomness;
-import org.elasticsearch.common.Strings;
-import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
-import org.elasticsearch.common.io.stream.StreamInput;
-import org.elasticsearch.common.io.stream.StreamOutput;
-import org.elasticsearch.compute.data.Page;
-import org.elasticsearch.core.TimeValue;
-import org.elasticsearch.search.aggregations.bucket.sampler.random.RandomSamplingQuery;
-import org.elasticsearch.xcontent.XContentBuilder;
-
-import java.io.IOException;
-import java.util.ArrayDeque;
-import java.util.Arrays;
-import java.util.Deque;
-import java.util.Objects;
-import java.util.SplittableRandom;
-
-public class SampleOperator implements Operator {
-
- public static class Factory implements OperatorFactory {
-
- private final double probability;
- private final Integer seed;
-
- public Factory(double probability) {
- this(probability, null);
- }
-
- // visible for testing
- Factory(double probability, Integer seed) {
- this.probability = probability;
- this.seed = seed;
- }
-
- @Override
- public SampleOperator get(DriverContext driverContext) {
- return new SampleOperator(probability, seed == null ? Randomness.get().nextInt() : seed);
- }
-
- @Override
- public String describe() {
- return "SampleOperator[probability = " + probability + "]";
- }
- }
-
- private final Deque outputPages;
-
- /**
- * At any time this iterator will point to be next document that still
- * needs to be sampled. If this document is on the current page, it's
- * added to the output and the iterator is advanced. It the document is
- * not on the current page, the current page is finished and the index
- * is used for the next page.
- */
- private final RandomSamplingQuery.RandomSamplingIterator randomSamplingIterator;
- private boolean finished;
-
- private int pagesProcessed = 0;
- private int rowsReceived = 0;
- private int rowsEmitted = 0;
- private long collectNanos;
- private long emitNanos;
-
- private SampleOperator(double probability, int seed) {
- finished = false;
- outputPages = new ArrayDeque<>();
- SplittableRandom random = new SplittableRandom(seed);
- randomSamplingIterator = new RandomSamplingQuery.RandomSamplingIterator(Integer.MAX_VALUE, probability, random::nextInt);
- // Initialize the iterator to the next document that needs to be sampled.
- randomSamplingIterator.nextDoc();
- }
-
- /**
- * whether the given operator can accept more input pages
- */
- @Override
- public boolean needsInput() {
- return finished == false;
- }
-
- /**
- * adds an input page to the operator. only called when needsInput() == true and isFinished() == false
- *
- * @param page
- * @throws UnsupportedOperationException if the operator is a {@link SourceOperator}
- */
- @Override
- public void addInput(Page page) {
- long startTime = System.nanoTime();
- createOutputPage(page);
- rowsReceived += page.getPositionCount();
- page.releaseBlocks();
- pagesProcessed++;
- collectNanos += System.nanoTime() - startTime;
- }
-
- private void createOutputPage(Page page) {
- final int[] sampledPositions = new int[page.getPositionCount()];
- int sampledIdx = 0;
- for (int i = randomSamplingIterator.docID(); i - rowsReceived < page.getPositionCount(); i = randomSamplingIterator.nextDoc()) {
- sampledPositions[sampledIdx++] = i - rowsReceived;
- }
- if (sampledIdx > 0) {
- outputPages.add(page.filter(Arrays.copyOf(sampledPositions, sampledIdx)));
- }
- }
-
- /**
- * notifies the operator that it won't receive any more input pages
- */
- @Override
- public void finish() {
- finished = true;
- }
-
- /**
- * whether the operator has finished processing all input pages and made the corresponding output pages available
- */
- @Override
- public boolean isFinished() {
- return finished && outputPages.isEmpty();
- }
-
- @Override
- public Page getOutput() {
- final var emitStart = System.nanoTime();
- Page page;
- if (outputPages.isEmpty()) {
- page = null;
- } else {
- page = outputPages.removeFirst();
- rowsEmitted += page.getPositionCount();
- }
- emitNanos += System.nanoTime() - emitStart;
- return page;
- }
-
- /**
- * notifies the operator that it won't be used anymore (i.e. none of the other methods called),
- * and its resources can be cleaned up
- */
- @Override
- public void close() {
- for (Page page : outputPages) {
- page.releaseBlocks();
- }
- }
-
- @Override
- public String toString() {
- return "SampleOperator[sampled = " + rowsEmitted + "/" + rowsReceived + "]";
- }
-
- @Override
- public Operator.Status status() {
- return new Status(collectNanos, emitNanos, pagesProcessed, rowsReceived, rowsEmitted);
- }
-
- private record Status(long collectNanos, long emitNanos, int pagesProcessed, int rowsReceived, int rowsEmitted)
- implements
- Operator.Status {
-
- public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
- Operator.Status.class,
- "sample",
- Status::new
- );
-
- Status(StreamInput streamInput) throws IOException {
- this(streamInput.readVLong(), streamInput.readVLong(), streamInput.readVInt(), streamInput.readVInt(), streamInput.readVInt());
- }
-
- @Override
- public void writeTo(StreamOutput out) throws IOException {
- out.writeVLong(collectNanos);
- out.writeVLong(emitNanos);
- out.writeVInt(pagesProcessed);
- out.writeVInt(rowsReceived);
- out.writeVInt(rowsEmitted);
- }
-
- @Override
- public String getWriteableName() {
- return ENTRY.name;
- }
-
- @Override
- public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
- builder.startObject();
- builder.field("collect_nanos", collectNanos);
- if (builder.humanReadable()) {
- builder.field("collect_time", TimeValue.timeValueNanos(collectNanos));
- }
- builder.field("emit_nanos", emitNanos);
- if (builder.humanReadable()) {
- builder.field("emit_time", TimeValue.timeValueNanos(emitNanos));
- }
- builder.field("pages_processed", pagesProcessed);
- builder.field("rows_received", rowsReceived);
- builder.field("rows_emitted", rowsEmitted);
- return builder.endObject();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Status other = (Status) o;
- return collectNanos == other.collectNanos
- && emitNanos == other.emitNanos
- && pagesProcessed == other.pagesProcessed
- && rowsReceived == other.rowsReceived
- && rowsEmitted == other.rowsEmitted;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(collectNanos, emitNanos, pagesProcessed, rowsReceived, rowsEmitted);
- }
-
- @Override
- public String toString() {
- return Strings.toString(this);
- }
-
- @Override
- public TransportVersion getMinimalSupportedVersion() {
- return TransportVersions.ZERO;
- }
- }
-}
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/SampleOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/SampleOperatorTests.java
deleted file mode 100644
index 11d22b7630031..0000000000000
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/SampleOperatorTests.java
+++ /dev/null
@@ -1,74 +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.compute.operator;
-
-import org.elasticsearch.compute.data.BlockFactory;
-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.List;
-import java.util.stream.LongStream;
-
-import static org.hamcrest.Matchers.both;
-import static org.hamcrest.Matchers.closeTo;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.lessThan;
-
-public class SampleOperatorTests extends OperatorTestCase {
-
- @Override
- protected SourceOperator simpleInput(BlockFactory blockFactory, int size) {
- return new SequenceLongBlockSourceOperator(blockFactory, LongStream.range(0, size));
- }
-
- @Override
- protected void assertSimpleOutput(List input, List results) {
- int inputCount = input.stream().mapToInt(Page::getPositionCount).sum();
- int outputCount = results.stream().mapToInt(Page::getPositionCount).sum();
- double meanExpectedOutputCount = 0.5 * inputCount;
- double stdDevExpectedOutputCount = Math.sqrt(meanExpectedOutputCount);
- assertThat((double) outputCount, closeTo(meanExpectedOutputCount, 10 * stdDevExpectedOutputCount));
- }
-
- @Override
- protected SampleOperator.Factory simple() {
- return new SampleOperator.Factory(0.5, randomInt());
- }
-
- @Override
- protected Matcher expectedDescriptionOfSimple() {
- return equalTo("SampleOperator[probability = 0.5]");
- }
-
- @Override
- protected Matcher expectedToStringOfSimple() {
- return equalTo("SampleOperator[sampled = 0/0]");
- }
-
- public void testAccuracy() {
- BlockFactory blockFactory = driverContext().blockFactory();
- int totalPositionCount = 0;
-
- for (int iter = 0; iter < 10000; iter++) {
- SampleOperator operator = simple().get(driverContext());
- operator.addInput(new Page(blockFactory.newConstantNullBlock(20000)));
- Page output = operator.getOutput();
- // 10000 expected rows, stddev=sqrt(10000)=100, so this is 10 stddevs.
- assertThat(output.getPositionCount(), both(greaterThan(9000)).and(lessThan(11000)));
- totalPositionCount += output.getPositionCount();
- output.releaseBlocks();
- }
-
- int averagePositionCount = totalPositionCount / 10000;
- // Running 10000 times, so the stddev is divided by sqrt(10000)=100, so this 10 stddevs again.
- assertThat(averagePositionCount, both(greaterThan(9990)).and(lessThan(10010)));
- }
-}
diff --git a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/RestSampleIT.java b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/RestSampleIT.java
deleted file mode 100644
index 523d9c15ab128..0000000000000
--- a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/RestSampleIT.java
+++ /dev/null
@@ -1,26 +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.qa.single_node;
-
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
-
-import org.elasticsearch.test.TestClustersThreadFilter;
-import org.elasticsearch.test.cluster.ElasticsearchCluster;
-import org.elasticsearch.xpack.esql.qa.rest.RestSampleTestCase;
-import org.junit.ClassRule;
-
-@ThreadLeakFilters(filters = TestClustersThreadFilter.class)
-public class RestSampleIT extends RestSampleTestCase {
- @ClassRule
- public static ElasticsearchCluster cluster = Clusters.testCluster();
-
- @Override
- protected String getTestRestCluster() {
- return cluster.getHttpAddresses();
- }
-}
diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestSampleTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestSampleTestCase.java
deleted file mode 100644
index 913dff4655a2b..0000000000000
--- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestSampleTestCase.java
+++ /dev/null
@@ -1,148 +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.qa.rest;
-
-import org.elasticsearch.client.Request;
-import org.elasticsearch.client.ResponseException;
-import org.elasticsearch.test.rest.ESRestTestCase;
-import org.elasticsearch.xpack.esql.action.EsqlCapabilities;
-import org.hamcrest.Description;
-import org.hamcrest.TypeSafeMatcher;
-import org.junit.After;
-import org.junit.Before;
-
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.IntStream;
-
-import static org.hamcrest.Matchers.both;
-import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.lessThan;
-
-public class RestSampleTestCase extends ESRestTestCase {
-
- @Before
- public void skipWhenSampleDisabled() throws IOException {
- assumeTrue(
- "Requires SAMPLE capability",
- EsqlSpecTestCase.hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.SAMPLE_V3.capabilityName()))
- );
- }
-
- @Before
- @After
- public void assertRequestBreakerEmpty() throws Exception {
- EsqlSpecTestCase.assertRequestBreakerEmpty();
- }
-
- /**
- * Matcher for the results of sampling 50% of the elements 0,1,2,...,998,999.
- * The results should consist of unique numbers in [0,999]. Furthermore, the
- * size should on average be 500. Allowing for 10 stddev deviations, the size
- * should be in [250,750].
- */
- private static final TypeSafeMatcher>> RESULT_MATCHER = new TypeSafeMatcher<>() {
- @Override
- public void describeTo(Description description) {
- description.appendText("a list with between 250 and 750 unique elements in [0,999]");
- }
-
- @Override
- protected boolean matchesSafely(List> lists) {
- if (lists.size() < 250 || lists.size() > 750) {
- return false;
- }
- Set values = new HashSet<>();
- for (List list : lists) {
- if (list.size() != 1) {
- return false;
- }
- Integer value = list.get(0);
- if (value == null || value < 0 || value >= 1000) {
- return false;
- }
- values.add(value);
- }
- return values.size() == lists.size();
- }
- };
-
- /**
- * This tests sampling in the Lucene query.
- */
- public void testSample_withFrom() throws IOException {
- createTestIndex();
- test("FROM sample-test-index | SAMPLE 0.5 | LIMIT 1000");
- deleteTestIndex();
- }
-
- /**
- * This tests sampling in the ES|QL operator.
- */
- public void testSample_withRow() throws IOException {
- List numbers = IntStream.range(0, 999).boxed().toList();
- test("ROW value = " + numbers + " | MV_EXPAND value | SAMPLE 0.5 | LIMIT 1000");
- }
-
- private void test(String query) throws IOException {
- int iterationCount = 1000;
- int totalResultSize = 0;
- for (int iteration = 0; iteration < iterationCount; iteration++) {
- Map result = runEsqlQuery(query);
- assertResultMap(result, defaultOutputColumns(), RESULT_MATCHER);
- totalResultSize += ((List>) result.get("values")).size();
- }
- // On average there's 500 elements in the results set.
- // Allowing for 10 stddev deviations, it should be in [490,510].
- assertThat(totalResultSize / iterationCount, both(greaterThan(490)).and(lessThan(510)));
- }
-
- private static List
*/
@Override public T visitChangePointCommand(EsqlBaseParser.ChangePointCommandContext ctx) { return visitChildren(ctx); }
- /**
- * {@inheritDoc}
- *
- * The default implementation returns the result of calling
- * {@link #visitChildren} on {@code ctx}.
- */
- @Override public T visitSampleCommand(EsqlBaseParser.SampleCommandContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
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 232290e4a2b2e..3aa40694d7a64 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
@@ -1041,16 +1041,6 @@ public interface EsqlBaseParserListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitChangePointCommand(EsqlBaseParser.ChangePointCommandContext ctx);
- /**
- * Enter a parse tree produced by {@link EsqlBaseParser#sampleCommand}.
- * @param ctx the parse tree
- */
- void enterSampleCommand(EsqlBaseParser.SampleCommandContext ctx);
- /**
- * Exit a parse tree produced by {@link EsqlBaseParser#sampleCommand}.
- * @param ctx the parse tree
- */
- void exitSampleCommand(EsqlBaseParser.SampleCommandContext ctx);
/**
* Enter a parse tree produced by {@link EsqlBaseParser#lookupCommand}.
* @param ctx the parse tree
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 d25901c2fdc3d..4013268b82a0e 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
@@ -626,12 +626,6 @@ public interface EsqlBaseParserVisitor extends ParseTreeVisitor {
* @return the visitor result
*/
T visitChangePointCommand(EsqlBaseParser.ChangePointCommandContext ctx);
- /**
- * Visit a parse tree produced by {@link EsqlBaseParser#sampleCommand}.
- * @param ctx the parse tree
- * @return the visitor result
- */
- T visitSampleCommand(EsqlBaseParser.SampleCommandContext ctx);
/**
* Visit a parse tree produced by {@link EsqlBaseParser#lookupCommand}.
* @param ctx the parse tree
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 34a9de0e3bae8..501040f412b05 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
@@ -62,7 +62,6 @@
import org.elasticsearch.xpack.esql.plan.logical.OrderBy;
import org.elasticsearch.xpack.esql.plan.logical.Rename;
import org.elasticsearch.xpack.esql.plan.logical.Row;
-import org.elasticsearch.xpack.esql.plan.logical.Sample;
import org.elasticsearch.xpack.esql.plan.logical.UnresolvedRelation;
import org.elasticsearch.xpack.esql.plan.logical.inference.Completion;
import org.elasticsearch.xpack.esql.plan.logical.inference.Rerank;
@@ -798,17 +797,4 @@ private Literal visitInferenceId(Expression expression) {
expression.getClass()
);
}
-
- public PlanFactory visitSampleCommand(EsqlBaseParser.SampleCommandContext ctx) {
- Source source = source(ctx);
- Object val = expression(ctx.probability).fold(FoldContext.small() /* TODO remove me */);
- if (val instanceof Double probability && probability > 0.0 && probability < 1.0) {
- return input -> new Sample(source, new Literal(source, probability, DataType.DOUBLE), input);
- } else {
- throw new ParsingException(
- source(ctx),
- "invalid value for SAMPLE probability [" + BytesRefs.toString(val) + "], expecting a number between 0 and 1, exclusive"
- );
- }
- }
}
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 880fda66d38a7..0662e0870eebc 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
@@ -21,7 +21,6 @@
import org.elasticsearch.xpack.esql.plan.logical.MvExpand;
import org.elasticsearch.xpack.esql.plan.logical.OrderBy;
import org.elasticsearch.xpack.esql.plan.logical.Project;
-import org.elasticsearch.xpack.esql.plan.logical.Sample;
import org.elasticsearch.xpack.esql.plan.logical.TopN;
import org.elasticsearch.xpack.esql.plan.logical.inference.Completion;
import org.elasticsearch.xpack.esql.plan.logical.inference.Rerank;
@@ -47,7 +46,6 @@
import org.elasticsearch.xpack.esql.plan.physical.LocalSourceExec;
import org.elasticsearch.xpack.esql.plan.physical.MvExpandExec;
import org.elasticsearch.xpack.esql.plan.physical.ProjectExec;
-import org.elasticsearch.xpack.esql.plan.physical.SampleExec;
import org.elasticsearch.xpack.esql.plan.physical.ShowExec;
import org.elasticsearch.xpack.esql.plan.physical.SubqueryExec;
import org.elasticsearch.xpack.esql.plan.physical.TopNExec;
@@ -87,7 +85,6 @@ public static List logical() {
OrderBy.ENTRY,
Project.ENTRY,
Rerank.ENTRY,
- Sample.ENTRY,
TopN.ENTRY
);
}
@@ -114,7 +111,6 @@ public static List physical() {
MvExpandExec.ENTRY,
ProjectExec.ENTRY,
RerankExec.ENTRY,
- SampleExec.ENTRY,
ShowExec.ENTRY,
SubqueryExec.ENTRY,
TopNExec.ENTRY
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Sample.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Sample.java
deleted file mode 100644
index c9c139bf77148..0000000000000
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Sample.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.logical;
-
-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.TelemetryAware;
-import org.elasticsearch.xpack.esql.core.expression.Expression;
-import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
-import org.elasticsearch.xpack.esql.core.tree.Source;
-import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput;
-
-import java.io.IOException;
-import java.util.Objects;
-
-public class Sample extends UnaryPlan implements TelemetryAware {
- public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(LogicalPlan.class, "Sample", Sample::new);
-
- private final Expression probability;
-
- public Sample(Source source, Expression probability, LogicalPlan child) {
- super(source, child);
- this.probability = probability;
- }
-
- private Sample(StreamInput in) throws IOException {
- this(
- Source.readFrom((PlanStreamInput) in),
- in.readNamedWriteable(Expression.class), // probability
- in.readNamedWriteable(LogicalPlan.class) // child
- );
- }
-
- @Override
- public void writeTo(StreamOutput out) throws IOException {
- source().writeTo(out);
- out.writeNamedWriteable(probability);
- out.writeNamedWriteable(child());
- }
-
- @Override
- public String getWriteableName() {
- return ENTRY.name;
- }
-
- @Override
- protected NodeInfo info() {
- return NodeInfo.create(this, Sample::new, probability, child());
- }
-
- @Override
- public Sample replaceChild(LogicalPlan newChild) {
- return new Sample(source(), probability, newChild);
- }
-
- public Expression probability() {
- return probability;
- }
-
- @Override
- public boolean expressionsResolved() {
- return probability.resolved();
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(probability, child());
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
-
- var other = (Sample) obj;
-
- return Objects.equals(probability, other.probability) && Objects.equals(child(), other.child());
- }
-}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsQueryExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsQueryExec.java
index 2e74c7153f77e..60e7eb535f444 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsQueryExec.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsQueryExec.java
@@ -308,12 +308,6 @@ public EsQueryExec withSorts(List sorts) {
: new EsQueryExec(source(), indexPattern, indexMode, indexNameWithModes, attrs, query, limit, sorts, estimatedRowSize);
}
- public EsQueryExec withQuery(QueryBuilder query) {
- return Objects.equals(this.query, query)
- ? this
- : new EsQueryExec(source(), indexPattern, indexMode, indexNameWithModes, attrs, query, limit, sorts, estimatedRowSize);
- }
-
@Override
public int hashCode() {
return Objects.hash(indexPattern, indexMode, indexNameWithModes, attrs, query, limit, sorts);
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/SampleExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/SampleExec.java
deleted file mode 100644
index 25dbf633713da..0000000000000
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/SampleExec.java
+++ /dev/null
@@ -1,90 +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.expression.Expression;
-import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
-import org.elasticsearch.xpack.esql.core.tree.Source;
-import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput;
-
-import java.io.IOException;
-import java.util.Objects;
-
-public class SampleExec extends UnaryExec {
- public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
- PhysicalPlan.class,
- "SampleExec",
- SampleExec::new
- );
-
- private final Expression probability;
-
- public SampleExec(Source source, PhysicalPlan child, Expression probability) {
- super(source, child);
- this.probability = probability;
- }
-
- public SampleExec(StreamInput in) throws IOException {
- this(
- Source.readFrom((PlanStreamInput) in),
- in.readNamedWriteable(PhysicalPlan.class), // child
- in.readNamedWriteable(Expression.class) // probability
- );
- }
-
- @Override
- public void writeTo(StreamOutput out) throws IOException {
- source().writeTo(out);
- out.writeNamedWriteable(child());
- out.writeNamedWriteable(probability);
- }
-
- @Override
- public UnaryExec replaceChild(PhysicalPlan newChild) {
- return new SampleExec(source(), newChild, probability);
- }
-
- @Override
- protected NodeInfo extends PhysicalPlan> info() {
- return NodeInfo.create(this, SampleExec::new, child(), probability);
- }
-
- /**
- * Returns the name of the writeable object
- */
- @Override
- public String getWriteableName() {
- return ENTRY.name;
- }
-
- public Expression probability() {
- return probability;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(child(), probability);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
-
- var other = (SampleExec) obj;
-
- return Objects.equals(child(), other.child()) && Objects.equals(probability, other.probability);
- }
-}
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 281dd8f480831..32ac32e0ac849 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
@@ -35,7 +35,6 @@
import org.elasticsearch.compute.operator.Operator.OperatorFactory;
import org.elasticsearch.compute.operator.OutputOperator.OutputOperatorFactory;
import org.elasticsearch.compute.operator.RowInTableLookupOperator;
-import org.elasticsearch.compute.operator.SampleOperator;
import org.elasticsearch.compute.operator.ScoreOperator;
import org.elasticsearch.compute.operator.ShowOperator;
import org.elasticsearch.compute.operator.SinkOperator;
@@ -64,7 +63,6 @@
import org.elasticsearch.xpack.esql.core.expression.Expressions;
import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
import org.elasticsearch.xpack.esql.core.expression.FoldContext;
-import org.elasticsearch.xpack.esql.core.expression.Foldables;
import org.elasticsearch.xpack.esql.core.expression.Literal;
import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute;
import org.elasticsearch.xpack.esql.core.expression.NameId;
@@ -105,7 +103,6 @@
import org.elasticsearch.xpack.esql.plan.physical.OutputExec;
import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan;
import org.elasticsearch.xpack.esql.plan.physical.ProjectExec;
-import org.elasticsearch.xpack.esql.plan.physical.SampleExec;
import org.elasticsearch.xpack.esql.plan.physical.ShowExec;
import org.elasticsearch.xpack.esql.plan.physical.TopNExec;
import org.elasticsearch.xpack.esql.plan.physical.inference.CompletionExec;
@@ -250,8 +247,6 @@ private PhysicalOperation plan(PhysicalPlan node, LocalExecutionPlannerContext c
return planChangePoint(changePoint, context);
} else if (node instanceof CompletionExec completion) {
return planCompletion(completion, context);
- } else if (node instanceof SampleExec Sample) {
- return planSample(Sample, context);
}
// source nodes
else if (node instanceof EsQueryExec esQuery) {
@@ -819,12 +814,6 @@ private PhysicalOperation planChangePoint(ChangePointExec changePoint, LocalExec
);
}
- private PhysicalOperation planSample(SampleExec rsx, LocalExecutionPlannerContext context) {
- PhysicalOperation source = plan(rsx.child(), context);
- var probability = (double) Foldables.valueOf(context.foldCtx(), rsx.probability());
- return source.with(new SampleOperator.Factory(probability), source.layout);
- }
-
/**
* Immutable physical operation.
*/
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 a7d9adb1014af..217737de5309b 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.LeafPlan;
import org.elasticsearch.xpack.esql.plan.logical.Limit;
import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
-import org.elasticsearch.xpack.esql.plan.logical.Sample;
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;
@@ -29,7 +28,6 @@
import org.elasticsearch.xpack.esql.plan.physical.LocalSourceExec;
import org.elasticsearch.xpack.esql.plan.physical.LookupJoinExec;
import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan;
-import org.elasticsearch.xpack.esql.plan.physical.SampleExec;
import org.elasticsearch.xpack.esql.plan.physical.TopNExec;
import java.util.List;
@@ -85,10 +83,6 @@ private PhysicalPlan mapUnary(UnaryPlan unary) {
return new TopNExec(topN.source(), mappedChild, topN.order(), topN.limit(), null);
}
- if (unary instanceof Sample sample) {
- return new SampleExec(sample.source(), mappedChild, sample.probability());
- }
-
//
// Pipeline operators
//
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 cca65657bbe5b..f301503246cc6 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
@@ -20,7 +20,6 @@
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.Sample;
import org.elasticsearch.xpack.esql.plan.logical.TopN;
import org.elasticsearch.xpack.esql.plan.logical.UnaryPlan;
import org.elasticsearch.xpack.esql.plan.logical.inference.Rerank;
@@ -35,7 +34,6 @@
import org.elasticsearch.xpack.esql.plan.physical.LocalSourceExec;
import org.elasticsearch.xpack.esql.plan.physical.LookupJoinExec;
import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan;
-import org.elasticsearch.xpack.esql.plan.physical.SampleExec;
import org.elasticsearch.xpack.esql.plan.physical.TopNExec;
import org.elasticsearch.xpack.esql.plan.physical.UnaryExec;
import org.elasticsearch.xpack.esql.plan.physical.inference.RerankExec;
@@ -181,12 +179,6 @@ private PhysicalPlan mapUnary(UnaryPlan unary) {
);
}
- // TODO: share code with local LocalMapper?
- if (unary instanceof Sample sample) {
- mappedChild = addExchangeForFragment(sample, mappedChild);
- return new SampleExec(sample.source(), mappedChild, sample.probability());
- }
-
//
// Pipeline operators
//
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 66ec93b700620..5c7c66e9f1236 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
@@ -12,7 +12,6 @@
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.core.expression.MetadataAttribute;
import org.elasticsearch.xpack.esql.plan.logical.Aggregate;
import org.elasticsearch.xpack.esql.plan.logical.ChangePoint;
import org.elasticsearch.xpack.esql.plan.logical.Dissect;
@@ -50,7 +49,7 @@
/**
* Class for sharing code across Mappers.
*/
-public class MapperUtils {
+class MapperUtils {
private MapperUtils() {}
static PhysicalPlan mapLeaf(LeafPlan p) {
@@ -157,13 +156,4 @@ static AggregateExec aggExec(Aggregate aggregate, PhysicalPlan child, Aggregator
static PhysicalPlan unsupported(LogicalPlan p) {
throw new EsqlIllegalArgumentException("unsupported logical plan node [" + p.nodeName() + "]");
}
-
- public static boolean hasScoreAttribute(List extends Attribute> attributes) {
- for (Attribute attr : attributes) {
- if (MetadataAttribute.isScoreAttribute(attr)) {
- return true;
- }
- }
- return false;
- }
}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/telemetry/FeatureMetric.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/telemetry/FeatureMetric.java
index 273ad46c149fb..7eaea682a0440 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/telemetry/FeatureMetric.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/telemetry/FeatureMetric.java
@@ -27,7 +27,6 @@
import org.elasticsearch.xpack.esql.plan.logical.Project;
import org.elasticsearch.xpack.esql.plan.logical.Rename;
import org.elasticsearch.xpack.esql.plan.logical.Row;
-import org.elasticsearch.xpack.esql.plan.logical.Sample;
import org.elasticsearch.xpack.esql.plan.logical.UnresolvedRelation;
import org.elasticsearch.xpack.esql.plan.logical.inference.Completion;
import org.elasticsearch.xpack.esql.plan.logical.inference.Rerank;
@@ -61,8 +60,7 @@ public enum FeatureMetric {
CHANGE_POINT(ChangePoint.class::isInstance),
INLINESTATS(InlineStats.class::isInstance),
COMPLETION(Completion.class::isInstance),
- RERANK(Rerank.class::isInstance),
- SAMPLE(Sample.class::isInstance);
+ RERANK(Rerank.class::isInstance);
/**
* List here plans we want to exclude from telemetry
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java
index f8c26c880d3d8..eeebc0d9726c0 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java
@@ -30,8 +30,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
import static org.elasticsearch.xpack.core.enrich.EnrichPolicy.GEO_MATCH_TYPE;
import static org.elasticsearch.xpack.core.enrich.EnrichPolicy.MATCH_TYPE;
@@ -236,13 +234,4 @@ public static IndexResolution indexWithDateDateNanosUnionType() {
);
return IndexResolution.valid(index);
}
-
- public static E randomValueOtherThanTest(Predicate exclude, Supplier supplier) {
- while (true) {
- E value = supplier.get();
- if (exclude.test(value) == false) {
- return value;
- }
- }
- }
}
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java
index 5cfa311ec4f55..0333e6ccad407 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java
@@ -158,25 +158,6 @@ public void testInvalidLimit() {
assertEquals("1:13: Invalid value for LIMIT [-1], expecting a non negative integer", error("row a = 1 | limit -1"));
}
- public void testInvalidSample() {
- assertEquals(
- "1:13: invalid value for SAMPLE probability [foo], expecting a number between 0 and 1, exclusive",
- error("row a = 1 | sample \"foo\"")
- );
- assertEquals(
- "1:13: invalid value for SAMPLE probability [-1.0], expecting a number between 0 and 1, exclusive",
- error("row a = 1 | sample -1.0")
- );
- assertEquals(
- "1:13: invalid value for SAMPLE probability [0], expecting a number between 0 and 1, exclusive",
- error("row a = 1 | sample 0")
- );
- assertEquals(
- "1:13: invalid value for SAMPLE probability [1], expecting a number between 0 and 1, exclusive",
- error("row a = 1 | sample 1")
- );
- }
-
private String error(String query) {
ParsingException e = expectThrows(ParsingException.class, () -> defaultAnalyzer.analyze(parser.createStatement(query)));
String message = e.getMessage();
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 2dd97d6811aab..a73e1a6455b9b 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
@@ -107,7 +107,6 @@
import org.elasticsearch.xpack.esql.parser.ParsingException;
import org.elasticsearch.xpack.esql.plan.GeneratingPlan;
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.EsRelation;
@@ -120,7 +119,6 @@
import org.elasticsearch.xpack.esql.plan.logical.OrderBy;
import org.elasticsearch.xpack.esql.plan.logical.Project;
import org.elasticsearch.xpack.esql.plan.logical.Row;
-import org.elasticsearch.xpack.esql.plan.logical.Sample;
import org.elasticsearch.xpack.esql.plan.logical.TopN;
import org.elasticsearch.xpack.esql.plan.logical.UnaryPlan;
import org.elasticsearch.xpack.esql.plan.logical.inference.Completion;
@@ -7724,149 +7722,4 @@ public void testPruneRedundantOrderBy() {
var mvExpand2 = as(mvExpand.child(), MvExpand.class);
as(mvExpand2.child(), Row.class);
}
-
- /**
- * Eval[[1[INTEGER] AS irrelevant1, 2[INTEGER] AS irrelevant2]]
- * \_Limit[1000[INTEGER],false]
- * \_Sample[0.015[DOUBLE],15[INTEGER]]
- * \_EsRelation[test][_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, ge..]
- */
- public void testSampleMerged() {
- assumeTrue("sample must be enabled", EsqlCapabilities.Cap.SAMPLE_V3.isEnabled());
-
- var query = """
- FROM TEST
- | SAMPLE .3
- | EVAL irrelevant1 = 1
- | SAMPLE .5
- | EVAL irrelevant2 = 2
- | SAMPLE .1
- """;
- var optimized = optimizedPlan(query);
-
- var eval = as(optimized, Eval.class);
- var limit = as(eval.child(), Limit.class);
- var sample = as(limit.child(), Sample.class);
- var source = as(sample.child(), EsRelation.class);
-
- assertThat(sample.probability().fold(FoldContext.small()), equalTo(0.015));
- }
-
- public void testSamplePushDown() {
- assumeTrue("sample must be enabled", EsqlCapabilities.Cap.SAMPLE_V3.isEnabled());
-
- for (var command : List.of(
- "ENRICH languages_idx on first_name",
- "EVAL x = 1",
- // "INSIST emp_no", // TODO
- "KEEP emp_no",
- "DROP emp_no",
- "RENAME emp_no AS x",
- "GROK first_name \"%{WORD:bar}\"",
- "DISSECT first_name \"%{z}\""
- )) {
- var query = "FROM TEST | " + command + " | SAMPLE .5";
- var optimized = optimizedPlan(query);
-
- var unary = as(optimized, UnaryPlan.class);
- var limit = as(unary.child(), Limit.class);
- var sample = as(limit.child(), Sample.class);
- var source = as(sample.child(), EsRelation.class);
-
- assertThat(sample.probability().fold(FoldContext.small()), equalTo(0.5));
- }
- }
-
- public void testSamplePushDown_sort() {
- assumeTrue("sample must be enabled", EsqlCapabilities.Cap.SAMPLE_V3.isEnabled());
-
- var query = "FROM TEST | WHERE emp_no > 0 | SAMPLE 0.5 | LIMIT 100";
- var optimized = optimizedPlan(query);
-
- var limit = as(optimized, Limit.class);
- var filter = as(limit.child(), Filter.class);
- var sample = as(filter.child(), Sample.class);
- var source = as(sample.child(), EsRelation.class);
-
- assertThat(sample.probability().fold(FoldContext.small()), equalTo(0.5));
- }
-
- public void testSamplePushDown_where() {
- assumeTrue("sample must be enabled", EsqlCapabilities.Cap.SAMPLE_V3.isEnabled());
-
- var query = "FROM TEST | SORT emp_no | SAMPLE 0.5 | LIMIT 100";
- var optimized = optimizedPlan(query);
-
- var topN = as(optimized, TopN.class);
- var sample = as(topN.child(), Sample.class);
- var source = as(sample.child(), EsRelation.class);
-
- assertThat(sample.probability().fold(FoldContext.small()), equalTo(0.5));
- }
-
- public void testSampleNoPushDown() {
- assumeTrue("sample must be enabled", EsqlCapabilities.Cap.SAMPLE_V3.isEnabled());
-
- for (var command : List.of("LIMIT 100", "MV_EXPAND languages", "STATS COUNT()")) {
- var query = "FROM TEST | " + command + " | SAMPLE .5";
- var optimized = optimizedPlan(query);
-
- var limit = as(optimized, Limit.class);
- var sample = as(limit.child(), Sample.class);
- var unary = as(sample.child(), UnaryPlan.class);
- var source = as(unary.child(), EsRelation.class);
- }
- }
-
- /**
- * Limit[1000[INTEGER],false]
- * \_Sample[0.5[DOUBLE],null]
- * \_Join[LEFT,[language_code{r}#4],[language_code{r}#4],[language_code{f}#17]]
- * |_Eval[[emp_no{f}#6 AS language_code]]
- * | \_EsRelation[test][_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, ge..]
- * \_EsRelation[languages_lookup][LOOKUP][language_code{f}#17, language_name{f}#18]
- */
- public void testSampleNoPushDownLookupJoin() {
- assumeTrue("sample must be enabled", EsqlCapabilities.Cap.SAMPLE_V3.isEnabled());
-
- var query = """
- FROM TEST
- | EVAL language_code = emp_no
- | LOOKUP JOIN languages_lookup ON language_code
- | SAMPLE .5
- """;
- var optimized = optimizedPlan(query);
-
- var limit = as(optimized, Limit.class);
- var sample = as(limit.child(), Sample.class);
- var join = as(sample.child(), Join.class);
- var eval = as(join.left(), Eval.class);
- var source = as(eval.child(), EsRelation.class);
- }
-
- /**
- * Limit[1000[INTEGER],false]
- * \_Sample[0.5[DOUBLE],null]
- * \_Limit[1000[INTEGER],false]
- * \_ChangePoint[emp_no{f}#6,hire_date{f}#13,type{r}#4,pvalue{r}#5]
- * \_TopN[[Order[hire_date{f}#13,ASC,ANY]],1001[INTEGER]]
- * \_EsRelation[test][_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, ge..]
- */
- public void testSampleNoPushDownChangePoint() {
- assumeTrue("sample must be enabled", EsqlCapabilities.Cap.SAMPLE_V3.isEnabled());
-
- var query = """
- FROM TEST
- | CHANGE_POINT emp_no ON hire_date
- | SAMPLE .5
- """;
- var optimized = optimizedPlan(query);
-
- var limit = as(optimized, Limit.class);
- var sample = as(limit.child(), Sample.class);
- limit = as(sample.child(), Limit.class);
- var changePoint = as(limit.child(), ChangePoint.class);
- var topN = as(changePoint.child(), TopN.class);
- var source = as(topN.child(), EsRelation.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 5ae5b8becb0f2..cc25c9bd02090 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
@@ -35,7 +35,6 @@
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.TermsQueryBuilder;
import org.elasticsearch.index.query.WildcardQueryBuilder;
-import org.elasticsearch.search.aggregations.bucket.sampler.random.RandomSamplingQueryBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.test.ESTestCase;
@@ -188,7 +187,6 @@
import static org.elasticsearch.xpack.esql.core.util.TestUtils.stripThrough;
import static org.elasticsearch.xpack.esql.parser.ExpressionBuilder.MAX_EXPRESSION_DEPTH;
import static org.elasticsearch.xpack.esql.parser.LogicalPlanBuilder.MAX_QUERY_DEPTH;
-import static org.elasticsearch.xpack.esql.planner.mapper.MapperUtils.hasScoreAttribute;
import static org.hamcrest.Matchers.closeTo;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
@@ -7906,7 +7904,7 @@ public void testScore() {
EsRelation esRelation = as(filter.child(), EsRelation.class);
assertTrue(esRelation.optimized());
assertTrue(esRelation.resolved());
- assertTrue(hasScoreAttribute(esRelation.output()));
+ assertTrue(esRelation.output().stream().anyMatch(a -> a.name().equals(MetadataAttribute.SCORE) && a instanceof MetadataAttribute));
}
public void testScoreTopN() {
@@ -7929,7 +7927,7 @@ public void testScoreTopN() {
Order scoreOrer = order.get(0);
assertEquals(Order.OrderDirection.DESC, scoreOrer.direction());
Expression child = scoreOrer.child();
- assertTrue(MetadataAttribute.isScoreAttribute(child));
+ assertTrue(child instanceof MetadataAttribute ma && ma.name().equals(MetadataAttribute.SCORE));
Filter filter = as(topN.child(), Filter.class);
Match match = as(filter.condition(), Match.class);
@@ -7939,7 +7937,7 @@ public void testScoreTopN() {
EsRelation esRelation = as(filter.child(), EsRelation.class);
assertTrue(esRelation.optimized());
assertTrue(esRelation.resolved());
- assertTrue(hasScoreAttribute(esRelation.output()));
+ assertTrue(esRelation.output().stream().anyMatch(a -> a.name().equals(MetadataAttribute.SCORE) && a instanceof MetadataAttribute));
}
public void testReductionPlanForTopN() {
@@ -8023,39 +8021,6 @@ public void testNotEqualsPushdownToDelegate() {
);
}
- /*
- * LimitExec[1000[INTEGER]]
- * \_ExchangeExec[[_meta_field{f}#8, emp_no{f}#2, first_name{f}#3, gender{f}#4, hire_date{f}#9, job{f}#10, job.raw{f}#11, langua
- * ges{f}#5, last_name{f}#6, long_noidx{f}#12, salary{f}#7],false]
- * \_ProjectExec[[_meta_field{f}#8, emp_no{f}#2, first_name{f}#3, gender{f}#4, hire_date{f}#9, job{f}#10, job.raw{f}#11, langua
- * ges{f}#5, last_name{f}#6, long_noidx{f}#12, salary{f}#7]]
- * \_FieldExtractExec[_meta_field{f}#8, emp_no{f}#2, first_name{f}#3, gen..]<[],[]>
- * \_EsQueryExec[test], indexMode[standard],
- * query[{"bool":{"filter":[{"sampling":{"probability":0.1,"seed":234,"hash":0}}],"boost":1.0}}]
- * [_doc{f}#24], limit[1000], sort[] estimatedRowSize[332]
- */
- public void testSamplePushDown() {
- assumeTrue("sample must be enabled", EsqlCapabilities.Cap.SAMPLE_V3.isEnabled());
-
- var plan = physicalPlan("""
- FROM test
- | SAMPLE +0.1
- """);
- var optimized = optimizedPlan(plan);
-
- var limit = as(optimized, LimitExec.class);
- var exchange = as(limit.child(), ExchangeExec.class);
- var project = as(exchange.child(), ProjectExec.class);
- var fieldExtract = as(project.child(), FieldExtractExec.class);
- var esQuery = as(fieldExtract.child(), EsQueryExec.class);
-
- var boolQuery = as(esQuery.query(), BoolQueryBuilder.class);
- var filter = boolQuery.filter();
- var randomSampling = as(filter.get(0), RandomSamplingQueryBuilder.class);
- assertThat(randomSampling.probability(), equalTo(0.1));
- assertThat(randomSampling.hash(), equalTo(0));
- }
-
@SuppressWarnings("SameParameterValue")
private static void assertFilterCondition(
Filter filter,
@@ -8239,7 +8204,7 @@ private PhysicalPlan physicalPlan(String query, TestDataSource dataSource, boole
var logical = logicalOptimizer.optimize(dataSource.analyzer.analyze(parser.createStatement(query)));
// System.out.println("Logical\n" + logical);
var physical = mapper.map(logical);
- // System.out.println("Physical\n" + physical);
+ // System.out.println(physical);
if (assertSerialization) {
assertSerialization(physical, config);
}
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 23c4256a6b743..d90f59f04074d 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
@@ -106,7 +106,6 @@
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.startsWith;
//@TestLogging(value = "org.elasticsearch.xpack.esql:TRACE", reason = "debug")
public class StatementParserTests extends AbstractStatementParserTests {
@@ -3543,21 +3542,6 @@ public void testInvalidCompletion() {
expectError("FROM foo* | COMPLETION completion=prompt", "line 1:41: mismatched input '' expecting {");
}
- public void testSample() {
- assumeTrue("SAMPLE requires corresponding capability", EsqlCapabilities.Cap.SAMPLE_V3.isEnabled());
- expectError("FROM test | SAMPLE .1 2", "line 1:23: extraneous input '2' expecting ");
- expectError("FROM test | SAMPLE .1 \"2\"", "line 1:23: extraneous input '\"2\"' expecting ");
- expectError(
- "FROM test | SAMPLE 1",
- "line 1:13: invalid value for SAMPLE probability [1], expecting a number between 0 and 1, exclusive"
- );
- expectThrows(
- ParsingException.class,
- startsWith("line 1:19: mismatched input '' expecting {"),
- () -> statement("FROM test | SAMPLE")
- );
- }
-
static Alias alias(String name, Expression value) {
return new Alias(EMPTY, name, value);
}
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/logical/SampleSerializationTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/logical/SampleSerializationTests.java
deleted file mode 100644
index f5303a12dde72..0000000000000
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/logical/SampleSerializationTests.java
+++ /dev/null
@@ -1,52 +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.logical;
-
-import org.elasticsearch.xpack.esql.core.expression.Literal;
-import org.elasticsearch.xpack.esql.core.type.DataType;
-
-import java.io.IOException;
-
-public class SampleSerializationTests extends AbstractLogicalPlanSerializationTests {
- /**
- * Creates a random test instance to use in the tests. This method will be
- * called multiple times during test execution and should return a different
- * random instance each time it is called.
- */
- @Override
- protected Sample createTestInstance() {
- return new Sample(randomSource(), randomProbability(), randomChild(0));
- }
-
- public static Literal randomProbability() {
- return new Literal(randomSource(), randomDoubleBetween(0, 1, false), DataType.DOUBLE);
- }
-
- public static Literal randomSeed() {
- return randomBoolean() ? new Literal(randomSource(), randomInt(), DataType.INTEGER) : null;
- }
-
- /**
- * Returns an instance which is mutated slightly so it should not be equal
- * to the given instance.
- *
- * @param instance
- */
- @Override
- protected Sample mutateInstance(Sample instance) throws IOException {
- var probability = instance.probability();
- var child = instance.child();
- int updateSelector = randomIntBetween(0, 1);
- switch (updateSelector) {
- case 0 -> probability = randomValueOtherThan(probability, SampleSerializationTests::randomProbability);
- case 1 -> child = randomValueOtherThan(child, () -> randomChild(0));
- default -> throw new IllegalArgumentException("Invalid selector: " + updateSelector);
- }
- return new Sample(instance.source(), probability, child);
- }
-}
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/physical/SampleExecSerializationTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/physical/SampleExecSerializationTests.java
deleted file mode 100644
index 385e2e37aa140..0000000000000
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/physical/SampleExecSerializationTests.java
+++ /dev/null
@@ -1,45 +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.plan.logical.SampleSerializationTests;
-
-import java.io.IOException;
-
-import static org.elasticsearch.xpack.esql.plan.logical.SampleSerializationTests.randomProbability;
-
-public class SampleExecSerializationTests extends AbstractPhysicalPlanSerializationTests {
- /**
- * Creates a random test instance to use in the tests. This method will be
- * called multiple times during test execution and should return a different
- * random instance each time it is called.
- */
- @Override
- protected SampleExec createTestInstance() {
- return new SampleExec(randomSource(), randomChild(0), randomProbability());
- }
-
- /**
- * Returns an instance which is mutated slightly so it should not be equal
- * to the given instance.
- *
- * @param instance
- */
- @Override
- protected SampleExec mutateInstance(SampleExec instance) throws IOException {
- var probability = instance.probability();
- var child = instance.child();
- int updateSelector = randomIntBetween(0, 1);
- switch (updateSelector) {
- case 0 -> probability = randomValueOtherThan(probability, SampleSerializationTests::randomProbability);
- case 1 -> child = randomValueOtherThan(child, () -> randomChild(0));
- default -> throw new IllegalArgumentException("Invalid selector: " + updateSelector);
- }
- return new SampleExec(instance.source(), child, probability);
- }
-}
diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/10_basic.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/10_basic.yml
index 56befed48ce31..489917b7b575b 100644
--- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/10_basic.yml
+++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/10_basic.yml
@@ -359,22 +359,20 @@ setup:
- match: {values.2: ["1",2.0,null,true,123,1674835275193]}
---
-"Test Unnamed Input Params Also For Limit And Sample":
+"Test Unnamed Input Params Also For Limit":
- requires:
test_runner_features: [ capabilities ]
capabilities:
- method: POST
path: /_query
parameters: [ ]
- capabilities: [ parameter_for_limit, parameter_for_sample ]
+ capabilities: [ parameter_for_limit ]
reason: "named or positional parameters"
- do:
esql.query:
body:
- # The "| sort time" is to work around https://github.com/elastic/elasticsearch/issues/120272
- # TODO: remove it when the issue is fixed
- query: 'from test | sort time | sample ? | eval x = ?, y = ?, z = ?, t = ?, u = ?, v = ? | keep x, y, z, t, u, v | limit ?'
- params: [0.999999999999, "1", 2.0, null, true, 123, 1674835275193, 3]
+ query: 'from test | eval x = ?, y = ?, z = ?, t = ?, u = ?, v = ? | keep x, y, z, t, u, v | limit ?'
+ params: ["1", 2.0, null, true, 123, 1674835275193, 3]
- length: {columns: 6}
- match: {columns.0.name: "x"}
@@ -403,16 +401,14 @@ setup:
- method: POST
path: /_query
parameters: [ ]
- capabilities: [ parameter_for_limit, parameter_for_sample ]
+ capabilities: [ parameter_for_limit ]
reason: "named or positional parameters"
- do:
esql.query:
body:
- # The "| sort time" is to work around https://github.com/elastic/elasticsearch/issues/120272
- # TODO: remove it when the issue is fixed
- query: 'from test | sort time | sample ? | eval x = ?, y = ?, z = ?, t = ?, u = ?, v = ? | keep x, y, z, t, u, v | limit ?'
- params: [{"s": 0.99999999999}, {"n1" : "1"}, {"n2" : 2.0}, {"n3" : null}, {"n4" : true}, {"n5" : 123}, {"n6": 1674835275193}, {"l": 3}]
+ query: 'from test | eval x = ?, y = ?, z = ?, t = ?, u = ?, v = ? | keep x, y, z, t, u, v | limit ?'
+ params: [{"n1" : "1"}, {"n2" : 2.0}, {"n3" : null}, {"n4" : true}, {"n5" : 123}, {"n6": 1674835275193}, {"l": 3}]
- length: {columns: 6}
- match: {columns.0.name: "x"}
@@ -469,16 +465,14 @@ setup:
- method: POST
path: /_query
parameters: [ ]
- capabilities: [ parameter_for_limit, parameter_for_sample ]
+ capabilities: [ parameter_for_limit ]
reason: "named or positional parameters for field names"
- do:
esql.query:
body:
- # The "| sort time" is to work around https://github.com/elastic/elasticsearch/issues/120272
- # TODO: remove it when the issue is fixed
- query: 'from test | sort time | sample ?s | stats x = count(?f1), y = sum(?f2) by ?f3 | sort ?f3 | keep ?f3, x, y | limit ?l'
- params: [{"s": 0.99999999999}, {"f1" : {"identifier" : "time"}}, {"f2" : { "identifier" : "count" }}, {"f3" : { "identifier" : "color"}}, {"l": 3}]
+ query: 'from test | stats x = count(?f1), y = sum(?f2) by ?f3 | sort ?f3 | keep ?f3, x, y | limit ?l'
+ params: [{"f1" : {"identifier" : "time"}}, {"f2" : { "identifier" : "count" }}, {"f3" : { "identifier" : "color"}}, {"l": 3}]
- length: {columns: 3}
- match: {columns.0.name: "color"}
diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_usage.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_usage.yml
index d74aea2f47802..44b657a9c2300 100644
--- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_usage.yml
+++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_usage.yml
@@ -37,7 +37,7 @@ setup:
- do: {xpack.usage: {}}
- match: { esql.available: true }
- match: { esql.enabled: true }
- - length: { esql.features: 22 }
+ - length: { esql.features: 21 }
- set: {esql.features.dissect: dissect_counter}
- set: {esql.features.drop: drop_counter}
- set: {esql.features.eval: eval_counter}
@@ -59,7 +59,6 @@ setup:
- set: {esql.features.inlinestats: inlinestats_counter}
- set: {esql.features.rerank: rerank_counter}
- set: {esql.features.completion: completion_counter}
- - set: {esql.features.sample: sample_counter}
- length: { esql.queries: 3 }
- set: {esql.queries.rest.total: rest_total_counter}
- set: {esql.queries.rest.failed: rest_failed_counter}
@@ -94,7 +93,6 @@ setup:
- match: {esql.features.inlinestats: $inlinestats_counter}
- match: {esql.features.rerank: $rerank_counter}
- match: {esql.features.completion: $completion_counter}
- - match: {esql.features.sample: $sample_counter}
- gt: {esql.queries.rest.total: $rest_total_counter}
- match: {esql.queries.rest.failed: $rest_failed_counter}
- match: {esql.queries.kibana.total: $kibana_total_counter}
@@ -123,7 +121,7 @@ setup:
- do: {xpack.usage: {}}
- match: { esql.available: true }
- match: { esql.enabled: true }
- - length: { esql.features: 22 }
+ - length: { esql.features: 21 }
- set: {esql.features.dissect: dissect_counter}
- set: {esql.features.drop: drop_counter}
- set: {esql.features.eval: eval_counter}
@@ -143,7 +141,6 @@ setup:
- set: {esql.features.lookup: lookup_counter}
- set: {esql.features.change_point: change_point_counter}
- set: {esql.features.inlinestats: inlinestats_counter}
- - set: {esql.features.sample: sample_counter}
- length: { esql.queries: 3 }
- set: {esql.queries.rest.total: rest_total_counter}
- set: {esql.queries.rest.failed: rest_failed_counter}