1
0
Эх сурвалжийг харах

ESQL: New telemetry for commands (#102937)

* Add enrich,mv_expand,show,row,from,drop,keep,rename commands to telemetry
Andrei Stefan 1 жил өмнө
parent
commit
6bba0efa78

+ 5 - 0
docs/changelog/102937.yaml

@@ -0,0 +1,5 @@
+pr: 102937
+summary: "ESQL: New telemetry commands"
+area: ES|QL
+type: enhancement
+issues: []

+ 9 - 1
docs/reference/rest-api/usage.asciidoc

@@ -220,7 +220,15 @@ GET /_xpack/usage
       "grok" : 0,
       "limit" : 0,
       "where" : 0,
-      "sort" : 0
+      "sort" : 0,
+      "drop" : 0,
+      "show" : 0,
+      "rename" : 0,
+      "mv_expand" : 0,
+      "keep" : 0,
+      "enrich" : 0,
+      "from" : 0,
+      "row" : 0
     },
     "queries" : {
       "rest" : {

+ 16 - 3
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java

@@ -22,6 +22,7 @@ import org.elasticsearch.xpack.esql.plan.logical.Keep;
 import org.elasticsearch.xpack.esql.plan.logical.MvExpand;
 import org.elasticsearch.xpack.esql.plan.logical.Rename;
 import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject;
+import org.elasticsearch.xpack.esql.stats.FeatureMetric;
 import org.elasticsearch.xpack.esql.type.EsqlDataTypes;
 import org.elasticsearch.xpack.ql.analyzer.AnalyzerRules;
 import org.elasticsearch.xpack.ql.analyzer.AnalyzerRules.BaseAnalyzerRule;
@@ -62,6 +63,7 @@ import org.elasticsearch.xpack.ql.util.CollectionUtils;
 import org.elasticsearch.xpack.ql.util.StringUtils;
 
 import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -75,6 +77,7 @@ import java.util.stream.Collectors;
 
 import static java.util.Collections.singletonList;
 import static org.elasticsearch.common.logging.LoggerMessageFormat.format;
+import static org.elasticsearch.xpack.esql.stats.FeatureMetric.LIMIT;
 import static org.elasticsearch.xpack.ql.analyzer.AnalyzerRules.resolveFunction;
 import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME;
 import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD;
@@ -107,11 +110,12 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
     }
 
     public LogicalPlan analyze(LogicalPlan plan) {
-        return verify(execute(plan));
+        BitSet partialMetrics = new BitSet(FeatureMetric.values().length);
+        return verify(execute(plan), gatherPreAnalysisMetrics(plan, partialMetrics));
     }
 
-    public LogicalPlan verify(LogicalPlan plan) {
-        Collection<Failure> failures = verifier.verify(plan);
+    public LogicalPlan verify(LogicalPlan plan, BitSet partialMetrics) {
+        Collection<Failure> failures = verifier.verify(plan, partialMetrics);
         if (failures.isEmpty() == false) {
             throw new VerificationException(failures);
         }
@@ -702,4 +706,13 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
             return result;
         }
     }
+
+    private BitSet gatherPreAnalysisMetrics(LogicalPlan plan, BitSet b) {
+        // count only the explicit "limit" the user added, otherwise all queries will have a "limit" and telemetry won't reflect reality
+        if (plan.collectFirstChildren(Limit.class::isInstance).isEmpty() == false) {
+            b.set(LIMIT.ordinal());
+        }
+        plan.forEachDown(p -> FeatureMetric.set(p, b));
+        return b;
+    }
 }

+ 6 - 33
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Verifier.java

@@ -11,9 +11,7 @@ import org.elasticsearch.xpack.esql.evaluator.predicate.operator.comparison.Equa
 import org.elasticsearch.xpack.esql.evaluator.predicate.operator.comparison.NotEquals;
 import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute;
 import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Neg;
-import org.elasticsearch.xpack.esql.plan.logical.Dissect;
 import org.elasticsearch.xpack.esql.plan.logical.Eval;
-import org.elasticsearch.xpack.esql.plan.logical.Grok;
 import org.elasticsearch.xpack.esql.plan.logical.RegexExtract;
 import org.elasticsearch.xpack.esql.plan.logical.Row;
 import org.elasticsearch.xpack.esql.stats.FeatureMetric;
@@ -34,10 +32,7 @@ import org.elasticsearch.xpack.ql.expression.function.aggregate.AggregateFunctio
 import org.elasticsearch.xpack.ql.expression.predicate.BinaryOperator;
 import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison;
 import org.elasticsearch.xpack.ql.plan.logical.Aggregate;
-import org.elasticsearch.xpack.ql.plan.logical.Filter;
-import org.elasticsearch.xpack.ql.plan.logical.Limit;
 import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan;
-import org.elasticsearch.xpack.ql.plan.logical.OrderBy;
 import org.elasticsearch.xpack.ql.plan.logical.Project;
 import org.elasticsearch.xpack.ql.type.DataType;
 import org.elasticsearch.xpack.ql.type.DataTypes;
@@ -50,13 +45,6 @@ import java.util.List;
 import java.util.Set;
 import java.util.stream.Stream;
 
-import static org.elasticsearch.xpack.esql.stats.FeatureMetric.DISSECT;
-import static org.elasticsearch.xpack.esql.stats.FeatureMetric.EVAL;
-import static org.elasticsearch.xpack.esql.stats.FeatureMetric.GROK;
-import static org.elasticsearch.xpack.esql.stats.FeatureMetric.LIMIT;
-import static org.elasticsearch.xpack.esql.stats.FeatureMetric.SORT;
-import static org.elasticsearch.xpack.esql.stats.FeatureMetric.STATS;
-import static org.elasticsearch.xpack.esql.stats.FeatureMetric.WHERE;
 import static org.elasticsearch.xpack.ql.analyzer.VerifierChecks.checkFilterConditionType;
 import static org.elasticsearch.xpack.ql.common.Failure.fail;
 import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST;
@@ -73,9 +61,11 @@ public class Verifier {
      * Verify that a {@link LogicalPlan} can be executed.
      *
      * @param plan The logical plan to be verified
+     * @param partialMetrics a bitset indicating a certain command (or "telemetry feature") is present in the query
      * @return a collection of verification failures; empty if and only if the plan is valid
      */
-    Collection<Failure> verify(LogicalPlan plan) {
+    Collection<Failure> verify(LogicalPlan plan, BitSet partialMetrics) {
+        assert partialMetrics != null;
         Set<Failure> failures = new LinkedHashSet<>();
 
         // quick verification for unresolved attributes
@@ -152,7 +142,7 @@ public class Verifier {
 
         // gather metrics
         if (failures.isEmpty()) {
-            gatherMetrics(plan);
+            gatherMetrics(plan, partialMetrics);
         }
 
         return failures;
@@ -259,25 +249,8 @@ public class Verifier {
         });
     }
 
-    private void gatherMetrics(LogicalPlan plan) {
-        BitSet b = new BitSet(FeatureMetric.values().length);
-        plan.forEachDown(p -> {
-            if (p instanceof Dissect) {
-                b.set(DISSECT.ordinal());
-            } else if (p instanceof Eval) {
-                b.set(EVAL.ordinal());
-            } else if (p instanceof Grok) {
-                b.set(GROK.ordinal());
-            } else if (p instanceof Limit) {
-                b.set(LIMIT.ordinal());
-            } else if (p instanceof OrderBy) {
-                b.set(SORT.ordinal());
-            } else if (p instanceof Aggregate) {
-                b.set(STATS.ordinal());
-            } else if (p instanceof Filter) {
-                b.set(WHERE.ordinal());
-            }
-        });
+    private void gatherMetrics(LogicalPlan plan, BitSet b) {
+        plan.forEachDown(p -> FeatureMetric.set(p, b));
         for (int i = b.nextSetBit(0); i >= 0; i = b.nextSetBit(i + 1)) {
             metrics.inc(FeatureMetric.values()[i]);
         }

+ 56 - 8
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/stats/FeatureMetric.java

@@ -7,25 +7,73 @@
 
 package org.elasticsearch.xpack.esql.stats;
 
+import org.elasticsearch.xpack.esql.plan.logical.Dissect;
+import org.elasticsearch.xpack.esql.plan.logical.Drop;
+import org.elasticsearch.xpack.esql.plan.logical.Enrich;
+import org.elasticsearch.xpack.esql.plan.logical.Eval;
+import org.elasticsearch.xpack.esql.plan.logical.Grok;
+import org.elasticsearch.xpack.esql.plan.logical.Keep;
+import org.elasticsearch.xpack.esql.plan.logical.MvExpand;
+import org.elasticsearch.xpack.esql.plan.logical.Rename;
+import org.elasticsearch.xpack.esql.plan.logical.Row;
+import org.elasticsearch.xpack.esql.plan.logical.show.ShowFunctions;
+import org.elasticsearch.xpack.esql.plan.logical.show.ShowInfo;
+import org.elasticsearch.xpack.ql.plan.logical.Aggregate;
+import org.elasticsearch.xpack.ql.plan.logical.EsRelation;
+import org.elasticsearch.xpack.ql.plan.logical.Filter;
+import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan;
+import org.elasticsearch.xpack.ql.plan.logical.OrderBy;
+
+import java.util.BitSet;
 import java.util.Locale;
+import java.util.function.Predicate;
 
 public enum FeatureMetric {
-
     /**
      * The order of these enum values is important, do not change it.
      * For any new values added to it, they should go at the end of the list.
      * see {@link org.elasticsearch.xpack.esql.analysis.Verifier#gatherMetrics}
      */
-    DISSECT,
-    EVAL,
-    GROK,
-    LIMIT,
-    SORT,
-    STATS,
-    WHERE;
+    DISSECT(Dissect.class::isInstance),
+    EVAL(Eval.class::isInstance),
+    GROK(Grok.class::isInstance),
+    LIMIT(plan -> false), // the limit is checked in Analyzer.gatherPreAnalysisMetrics, because it has a more complex and general check
+    SORT(OrderBy.class::isInstance),
+    STATS(Aggregate.class::isInstance),
+    WHERE(Filter.class::isInstance),
+    ENRICH(Enrich.class::isInstance),
+    MV_EXPAND(MvExpand.class::isInstance),
+    SHOW(plan -> plan instanceof ShowInfo || plan instanceof ShowFunctions),
+    ROW(Row.class::isInstance),
+    FROM(EsRelation.class::isInstance),
+    DROP(Drop.class::isInstance),
+    KEEP(Keep.class::isInstance),
+    RENAME(Rename.class::isInstance);
+
+    private Predicate<LogicalPlan> planCheck;
+
+    FeatureMetric(Predicate<LogicalPlan> planCheck) {
+        this.planCheck = planCheck;
+    }
 
     @Override
     public String toString() {
         return this.name().toLowerCase(Locale.ROOT);
     }
+
+    public static void set(LogicalPlan plan, BitSet bitset) {
+        for (FeatureMetric metric : FeatureMetric.values()) {
+            if (set(plan, bitset, metric)) {
+                return;
+            }
+        }
+    }
+
+    public static boolean set(LogicalPlan plan, BitSet bitset, FeatureMetric metric) {
+        var isMatch = metric.planCheck.test(plan);
+        if (isMatch) {
+            bitset.set(metric.ordinal());
+        }
+        return isMatch;
+    }
 }

+ 257 - 14
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/VerifierMetricsTests.java

@@ -9,19 +9,25 @@ package org.elasticsearch.xpack.esql.stats;
 
 import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.xpack.core.watcher.common.stats.Counters;
-import org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils;
 import org.elasticsearch.xpack.esql.analysis.Verifier;
 import org.elasticsearch.xpack.esql.parser.EsqlParser;
-import org.elasticsearch.xpack.ql.index.IndexResolution;
 
 import java.util.List;
 
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
 import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.analyzer;
 import static org.elasticsearch.xpack.esql.stats.FeatureMetric.DISSECT;
+import static org.elasticsearch.xpack.esql.stats.FeatureMetric.DROP;
+import static org.elasticsearch.xpack.esql.stats.FeatureMetric.ENRICH;
 import static org.elasticsearch.xpack.esql.stats.FeatureMetric.EVAL;
+import static org.elasticsearch.xpack.esql.stats.FeatureMetric.FROM;
 import static org.elasticsearch.xpack.esql.stats.FeatureMetric.GROK;
+import static org.elasticsearch.xpack.esql.stats.FeatureMetric.KEEP;
 import static org.elasticsearch.xpack.esql.stats.FeatureMetric.LIMIT;
+import static org.elasticsearch.xpack.esql.stats.FeatureMetric.MV_EXPAND;
+import static org.elasticsearch.xpack.esql.stats.FeatureMetric.RENAME;
+import static org.elasticsearch.xpack.esql.stats.FeatureMetric.ROW;
+import static org.elasticsearch.xpack.esql.stats.FeatureMetric.SHOW;
 import static org.elasticsearch.xpack.esql.stats.FeatureMetric.SORT;
 import static org.elasticsearch.xpack.esql.stats.FeatureMetric.STATS;
 import static org.elasticsearch.xpack.esql.stats.FeatureMetric.WHERE;
@@ -36,10 +42,18 @@ public class VerifierMetricsTests extends ESTestCase {
         assertEquals(1L, dissect(c));
         assertEquals(0, eval(c));
         assertEquals(0, grok(c));
-        assertEquals(1L, limit(c));
+        assertEquals(0, limit(c));
         assertEquals(0, sort(c));
         assertEquals(0, stats(c));
         assertEquals(0, where(c));
+        assertEquals(0, enrich(c));
+        assertEquals(0, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(0, row(c));
+        assertEquals(1L, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(0, keep(c));
+        assertEquals(0, rename(c));
     }
 
     public void testEvalQuery() {
@@ -47,10 +61,18 @@ public class VerifierMetricsTests extends ESTestCase {
         assertEquals(0, dissect(c));
         assertEquals(1L, eval(c));
         assertEquals(0, grok(c));
-        assertEquals(1L, limit(c));
+        assertEquals(0, limit(c));
         assertEquals(0, sort(c));
         assertEquals(0, stats(c));
         assertEquals(0, where(c));
+        assertEquals(0, enrich(c));
+        assertEquals(0, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(0, row(c));
+        assertEquals(1L, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(0, keep(c));
+        assertEquals(0, rename(c));
     }
 
     public void testGrokQuery() {
@@ -58,10 +80,18 @@ public class VerifierMetricsTests extends ESTestCase {
         assertEquals(0, dissect(c));
         assertEquals(0, eval(c));
         assertEquals(1L, grok(c));
-        assertEquals(1L, limit(c));
+        assertEquals(0, limit(c));
         assertEquals(0, sort(c));
         assertEquals(0, stats(c));
         assertEquals(0, where(c));
+        assertEquals(0, enrich(c));
+        assertEquals(0, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(0, row(c));
+        assertEquals(1L, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(0, keep(c));
+        assertEquals(0, rename(c));
     }
 
     public void testLimitQuery() {
@@ -73,6 +103,14 @@ public class VerifierMetricsTests extends ESTestCase {
         assertEquals(0, sort(c));
         assertEquals(0, stats(c));
         assertEquals(0, where(c));
+        assertEquals(0, enrich(c));
+        assertEquals(0, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(0, row(c));
+        assertEquals(1L, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(0, keep(c));
+        assertEquals(0, rename(c));
     }
 
     public void testSortQuery() {
@@ -80,10 +118,18 @@ public class VerifierMetricsTests extends ESTestCase {
         assertEquals(0, dissect(c));
         assertEquals(0, eval(c));
         assertEquals(0, grok(c));
-        assertEquals(1L, limit(c));
+        assertEquals(0, limit(c));
         assertEquals(1L, sort(c));
         assertEquals(0, stats(c));
         assertEquals(0, where(c));
+        assertEquals(0, enrich(c));
+        assertEquals(0, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(0, row(c));
+        assertEquals(1L, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(0, keep(c));
+        assertEquals(0, rename(c));
     }
 
     public void testStatsQuery() {
@@ -91,10 +137,18 @@ public class VerifierMetricsTests extends ESTestCase {
         assertEquals(0, dissect(c));
         assertEquals(0, eval(c));
         assertEquals(0, grok(c));
-        assertEquals(1L, limit(c));
+        assertEquals(0, limit(c));
         assertEquals(0, sort(c));
         assertEquals(1L, stats(c));
         assertEquals(0, where(c));
+        assertEquals(0, enrich(c));
+        assertEquals(0, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(0, row(c));
+        assertEquals(1L, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(0, keep(c));
+        assertEquals(0, rename(c));
     }
 
     public void testWhereQuery() {
@@ -102,10 +156,18 @@ public class VerifierMetricsTests extends ESTestCase {
         assertEquals(0, dissect(c));
         assertEquals(0, eval(c));
         assertEquals(0, grok(c));
-        assertEquals(1L, limit(c));
+        assertEquals(0, limit(c));
         assertEquals(0, sort(c));
         assertEquals(0, stats(c));
         assertEquals(1L, where(c));
+        assertEquals(0, enrich(c));
+        assertEquals(0, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(0, row(c));
+        assertEquals(1L, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(0, keep(c));
+        assertEquals(0, rename(c));
     }
 
     public void testTwoWhereQuery() {
@@ -117,6 +179,14 @@ public class VerifierMetricsTests extends ESTestCase {
         assertEquals(1L, sort(c));
         assertEquals(0, stats(c));
         assertEquals(1L, where(c));
+        assertEquals(0, enrich(c));
+        assertEquals(0, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(0, row(c));
+        assertEquals(1L, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(0, keep(c));
+        assertEquals(0, rename(c));
     }
 
     public void testTwoQueriesExecuted() {
@@ -144,10 +214,153 @@ public class VerifierMetricsTests extends ESTestCase {
         assertEquals(1L, dissect(c));
         assertEquals(1L, eval(c));
         assertEquals(1L, grok(c));
-        assertEquals(2L, limit(c));
+        assertEquals(1L, limit(c));
         assertEquals(2L, sort(c));
         assertEquals(1L, stats(c));
         assertEquals(2L, where(c));
+        assertEquals(0, enrich(c));
+        assertEquals(0, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(0, row(c));
+        assertEquals(2L, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(0, keep(c));
+        assertEquals(0, rename(c));
+    }
+
+    public void testEnrich() {
+        Counters c = esql("""
+            from employees
+            | sort emp_no
+            | limit 1
+            | eval x = to_string(languages)
+            | enrich languages on x
+            | keep emp_no, language_name""");
+        assertEquals(0, dissect(c));
+        assertEquals(1L, eval(c));
+        assertEquals(0, grok(c));
+        assertEquals(1L, limit(c));
+        assertEquals(1L, sort(c));
+        assertEquals(0, stats(c));
+        assertEquals(0, where(c));
+        assertEquals(1L, enrich(c));
+        assertEquals(0, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(0, row(c));
+        assertEquals(1L, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(1L, keep(c));
+        assertEquals(0, rename(c));
+    }
+
+    public void testMvExpand() {
+        Counters c = esql("""
+            from employees
+            | where emp_no == 10004
+            | limit 1
+            | keep emp_no, job
+            | mv_expand job
+            | where job LIKE \"*a*\"
+            | limit 2
+            | where job LIKE \"*a*\"
+            | limit 3""");
+        assertEquals(0, dissect(c));
+        assertEquals(0, eval(c));
+        assertEquals(0, grok(c));
+        assertEquals(1L, limit(c));
+        assertEquals(0, sort(c));
+        assertEquals(0, stats(c));
+        assertEquals(1L, where(c));
+        assertEquals(0, enrich(c));
+        assertEquals(1L, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(0, row(c));
+        assertEquals(1L, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(1L, keep(c));
+        assertEquals(0, rename(c));
+    }
+
+    public void testShowFunctionsOrInfo() {
+        String showCommand = randomFrom("show functions", "show info");
+        Counters c = esql(showCommand + " |  stats  a = count(*), b = count(*), c = count(*) |  mv_expand c");
+        assertEquals(0, dissect(c));
+        assertEquals(0, eval(c));
+        assertEquals(0, grok(c));
+        assertEquals(0, limit(c));
+        assertEquals(0, sort(c));
+        assertEquals(1L, stats(c));
+        assertEquals(0, where(c));
+        assertEquals(0, enrich(c));
+        assertEquals(1L, mvExpand(c));
+        assertEquals(1L, show(c));
+        assertEquals(0, row(c));
+        assertEquals(0, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(0, keep(c));
+        assertEquals(0, rename(c));
+    }
+
+    public void testRow() {
+        Counters c = esql("row a = [\"1\", \"2\"] | enrich languages on a with a_lang = language_name");
+        assertEquals(0, dissect(c));
+        assertEquals(0, eval(c));
+        assertEquals(0, grok(c));
+        assertEquals(0, limit(c));
+        assertEquals(0, sort(c));
+        assertEquals(0, stats(c));
+        assertEquals(0, where(c));
+        assertEquals(1L, enrich(c));
+        assertEquals(0, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(1L, row(c));
+        assertEquals(0, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(0, keep(c));
+        assertEquals(0, rename(c));
+    }
+
+    public void testDropAndRename() {
+        Counters c = esql("from employees | rename gender AS foo | stats bar = count(*) by foo | drop foo | sort bar | drop bar");
+        assertEquals(0, dissect(c));
+        assertEquals(0, eval(c));
+        assertEquals(0, grok(c));
+        assertEquals(0, limit(c));
+        assertEquals(1L, sort(c));
+        assertEquals(1L, stats(c));
+        assertEquals(0, where(c));
+        assertEquals(0, enrich(c));
+        assertEquals(0, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(0, row(c));
+        assertEquals(1L, from(c));
+        assertEquals(1L, drop(c));
+        assertEquals(0, keep(c));
+        assertEquals(1L, rename(c));
+    }
+
+    public void testKeep() {
+        Counters c = esql("""
+            from employees
+            | keep emp_no, languages
+            | where languages is null or emp_no <= 10030
+            | where languages in (2, 3, emp_no)
+            | keep languages""");
+        assertEquals(0, dissect(c));
+        assertEquals(0, eval(c));
+        assertEquals(0, grok(c));
+        assertEquals(0, limit(c));
+        assertEquals(0, sort(c));
+        assertEquals(0, stats(c));
+        assertEquals(1L, where(c));
+        assertEquals(0, enrich(c));
+        assertEquals(0, mvExpand(c));
+        assertEquals(0, show(c));
+        assertEquals(0, row(c));
+        assertEquals(1L, from(c));
+        assertEquals(0, drop(c));
+        assertEquals(1L, keep(c));
+        assertEquals(0, rename(c));
     }
 
     private long dissect(Counters c) {
@@ -178,8 +391,40 @@ public class VerifierMetricsTests extends ESTestCase {
         return c.get(FPREFIX + WHERE);
     }
 
-    private Counters esql(String sql) {
-        return esql(sql, null);
+    private long enrich(Counters c) {
+        return c.get(FPREFIX + ENRICH);
+    }
+
+    private long mvExpand(Counters c) {
+        return c.get(FPREFIX + MV_EXPAND);
+    }
+
+    private long show(Counters c) {
+        return c.get(FPREFIX + SHOW);
+    }
+
+    private long row(Counters c) {
+        return c.get(FPREFIX + ROW);
+    }
+
+    private long from(Counters c) {
+        return c.get(FPREFIX + FROM);
+    }
+
+    private long drop(Counters c) {
+        return c.get(FPREFIX + DROP);
+    }
+
+    private long keep(Counters c) {
+        return c.get(FPREFIX + KEEP);
+    }
+
+    private long rename(Counters c) {
+        return c.get(FPREFIX + RENAME);
+    }
+
+    private Counters esql(String esql) {
+        return esql(esql, null);
     }
 
     private void esqlWithVerifier(String esql, Verifier verifier) {
@@ -187,15 +432,13 @@ public class VerifierMetricsTests extends ESTestCase {
     }
 
     private Counters esql(String esql, Verifier v) {
-        IndexResolution mapping = AnalyzerTestUtils.analyzerDefaultMapping();
-
         Verifier verifier = v;
         Metrics metrics = null;
         if (v == null) {
             metrics = new Metrics();
             verifier = new Verifier(metrics);
         }
-        analyzer(mapping, verifier).analyze(parser.createStatement(esql));
+        analyzer(verifier).analyze(parser.createStatement(esql));
 
         return metrics == null ? null : metrics.stats();
     }

+ 11 - 3
x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_usage.yml

@@ -1,8 +1,8 @@
 ---
 setup:
   - skip:
-      version: " - 8.10.99"
-      reason: "ESQL is available in 8.11+"
+      version: " - 8.11.99"
+      reason: "Latest, more complete, telemetry available in 8.12+"
 
   - do:
       indices.create:
@@ -23,11 +23,19 @@ setup:
   - do: {xpack.usage: {}}
   - match: { esql.available: true }
   - match: { esql.enabled: true }
-  - length: { esql.features: 7 }
+  - length: { esql.features: 15 }
   - set: {esql.features.dissect: dissect_counter}
+  - set: {esql.features.drop: drop_counter}
   - set: {esql.features.eval: eval_counter}
+  - set: {esql.features.enrich: enrich_counter}
+  - set: {esql.features.from: from_counter}
   - set: {esql.features.grok: grok_counter}
+  - set: {esql.features.keep: keep_counter}
   - set: {esql.features.limit: limit_counter}
+  - set: {esql.features.mv_expand: mv_expand_counter}
+  - set: {esql.features.rename: rename_counter}
+  - set: {esql.features.row: row_counter}
+  - set: {esql.features.show: show_counter}
   - set: {esql.features.sort: sort_counter}
   - set: {esql.features.stats: stats_counter}
   - set: {esql.features.where: where_counter}