Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,19 @@
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.KeepGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.LimitGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.LookupJoinGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.MetricsStatsGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.MvExpandGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.RenameGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.SortGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.StatsGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.TimeSeriesStatsGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.WhereGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.source.FromGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.source.MetricGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.source.TimeSeriesGenerator;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.elasticsearch.test.ESTestCase.randomAlphaOfLength;
import static org.elasticsearch.test.ESTestCase.randomBoolean;
Expand All @@ -56,7 +57,7 @@ public record QueryExecuted(String query, int depth, List<Column> outputSchema,
/**
* Commands at the beginning of queries that begin queries on time series indices, eg. TS
*/
static List<CommandGenerator> TIME_SERIES_SOURCE_COMMANDS = List.of(MetricGenerator.INSTANCE);
static List<CommandGenerator> TIME_SERIES_SOURCE_COMMANDS = List.of(TimeSeriesGenerator.INSTANCE);

/**
* These are downstream commands, ie. that cannot appear as the first command in a query
Expand All @@ -79,24 +80,10 @@ public record QueryExecuted(String query, int depth, List<Column> outputSchema,
WhereGenerator.INSTANCE
);

static List<CommandGenerator> TIME_SERIES_PIPE_COMMANDS = List.of(
ChangePointGenerator.INSTANCE,
DissectGenerator.INSTANCE,
DropGenerator.INSTANCE,
EnrichGenerator.INSTANCE,
EvalGenerator.INSTANCE,
ForkGenerator.INSTANCE,
GrokGenerator.INSTANCE,
KeepGenerator.INSTANCE,
LimitGenerator.INSTANCE,
LookupJoinGenerator.INSTANCE,
MetricsStatsGenerator.INSTANCE,
MvExpandGenerator.INSTANCE,
RenameGenerator.INSTANCE,
SortGenerator.INSTANCE,
StatsGenerator.INSTANCE,
WhereGenerator.INSTANCE
);
static List<CommandGenerator> TIME_SERIES_PIPE_COMMANDS = Stream.concat(
PIPE_COMMANDS.stream(),
Stream.of(TimeSeriesStatsGenerator.INSTANCE)
).toList();

public static CommandGenerator sourceCommand() {
return randomFrom(SOURCE_COMMANDS);
Expand All @@ -111,7 +98,6 @@ public static CommandGenerator randomPipeCommandGenerator() {
}

public static CommandGenerator randomMetricsPipeCommandGenerator() {
// todo better way
return randomFrom(TIME_SERIES_PIPE_COMMANDS);
}

Expand Down Expand Up @@ -143,7 +129,7 @@ public static void generatePipeline(
if (executor.currentSchema().isEmpty()) {
break;
}
commandGenerator = isTimeSeries ? randomMetricsPipeCommandGenerator() : EsqlQueryGenerator.randomPipeCommandGenerator();
commandGenerator = isTimeSeries ? randomMetricsPipeCommandGenerator() : randomPipeCommandGenerator();
desc = commandGenerator.generate(executor.previousCommands(), executor.currentSchema(), schema);
if (desc == CommandGenerator.EMPTY_DESCRIPTION) {
continue;
Expand Down Expand Up @@ -262,10 +248,17 @@ public static String metricsAgg(List<Column> previousOutput) {
if (numericPlusAggMetricFieldName == null) {
yield null;
}
yield switch ((randomIntBetween(0, 3))) {
yield switch ((randomIntBetween(0, 5))) {
case 0 -> "max_over_time(" + numericPlusAggMetricFieldName + ")";
case 1 -> "min_over_time(" + numericPlusAggMetricFieldName + ")";
case 2 -> "sum_over_time(" + numericPlusAggMetricFieldName + ")";
case 3 -> {
if (outerCommand.equals("sum") || outerCommand.equals("avg")) {
yield null;
}
yield "present_over_time(" + numericPlusAggMetricFieldName + ")";
}
case 4 -> "count_over_time(" + numericPlusAggMetricFieldName + ")";
default -> "avg_over_time(" + numericPlusAggMetricFieldName + ")";
};
}
Expand All @@ -279,11 +272,19 @@ yield switch ((randomIntBetween(0, 3))) {
}
case 2 -> {
// numerics except aggregate_metric_double
// TODO: move to case 0 when support for aggregate_metric_double is added to these functions
// TODO: add to case 0 when support for aggregate_metric_double is added to these functions
// TODO: add to case 1 when support for counters is added
String numericFieldName = randomNumericField(previousOutput);
if (numericFieldName == null) {
yield null;
}
if (previousOutput.stream()
.noneMatch(
column -> column.name.equals("@timestamp") && (column.type.equals("date_nanos") || column.type.equals("datetime"))
)) {
// first_over_time and last_over_time require @timestamp to be available and be either datetime or date_nanos
yield null;
}
yield (randomBoolean() ? "first_over_time(" : "last_over_time(") + numericFieldName + ")";
}
default -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,12 @@ public abstract class GenerativeRestTest extends ESRestTestCase {
"optimized incorrectly due to missing references", // https://github.com/elastic/elasticsearch/issues/131509

// Awaiting fixes for correctness
"Expecting at most \\[.*\\] columns, got \\[.*\\]" // https://github.com/elastic/elasticsearch/issues/129561
"Expecting at most \\[.*\\] columns, got \\[.*\\]", // https://github.com/elastic/elasticsearch/issues/129561

// TS-command tests
"Invalid call to dataType on an unresolved object \\?LASTOVERTIME", // https://github.com/elastic/elasticsearch/issues/134791
"class org.elasticsearch.compute.data..*Block cannot be cast to class org.elasticsearch.compute.data..*Block", // https://github.com/elastic/elasticsearch/issues/134793
"Output has changed from \\[.*\\] to \\[.*\\]" // https://github.com/elastic/elasticsearch/issues/134794
);

public static final Set<Pattern> ALLOWED_ERROR_PATTERNS = ALLOWED_ERRORS.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
import static org.elasticsearch.test.ESTestCase.randomIntBetween;
import static org.elasticsearch.xpack.esql.qa.rest.generative.EsqlQueryGenerator.randomDateField;

public class MetricsStatsGenerator implements CommandGenerator {
public class TimeSeriesStatsGenerator implements CommandGenerator {

public static final String STATS = "stats";
public static final CommandGenerator INSTANCE = new MetricsStatsGenerator();
public static final CommandGenerator INSTANCE = new TimeSeriesStatsGenerator();

@Override
public CommandDescription generate(
Expand All @@ -31,8 +31,9 @@ public CommandDescription generate(
) {
// generates stats in the form of:
// `STATS some_aggregation(some_field) by optional_grouping_field, non_optional = bucket(time_field, 5minute)`
// where `some_aggregation` can be a time series aggregation, or a regular aggregation
// There is a variable number of aggregations per command
// where `some_aggregation` can be a time series aggregation in the form of agg1(agg2_over_time(some_field)),
// or a regular aggregation.
// There is a variable number of aggregations per pipe

List<EsqlQueryGenerator.Column> nonNull = previousOutput.stream()
.filter(EsqlQueryGenerator::fieldCanBeUsed)
Expand Down Expand Up @@ -80,12 +81,9 @@ public CommandDescription generate(
}
}
// TODO: add alternative time buckets
cmd.append(
(randomBoolean() ? EsqlQueryGenerator.randomIdentifier() : EsqlQueryGenerator.randomName(previousOutput))
+ " = bucket("
+ timestamp
+ ",1hour)"
);
// TODO: replace name of bucket with half chance of being EsqlQueryGenerator.randomName(previousOutput) if
// is fixed https://github.com/elastic/elasticsearch/issues/134796
cmd.append(EsqlQueryGenerator.randomIdentifier() + " = bucket(" + timestamp + ",1hour)");
return new CommandDescription(STATS, this, cmd.toString(), Map.of());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
import static org.elasticsearch.test.ESTestCase.randomIntBetween;
import static org.elasticsearch.xpack.esql.qa.rest.generative.EsqlQueryGenerator.indexPattern;

public class MetricGenerator implements CommandGenerator {
public class TimeSeriesGenerator implements CommandGenerator {

public static final MetricGenerator INSTANCE = new MetricGenerator();
public static final TimeSeriesGenerator INSTANCE = new TimeSeriesGenerator();

@Override
public CommandDescription generate(
Expand Down