Skip to content

ES|QL: Add (stack) telemetry for views#143745

Merged
luigidellaquila merged 18 commits intoelastic:mainfrom
luigidellaquila:esql/views_telemetry_stack
Mar 25, 2026
Merged

ES|QL: Add (stack) telemetry for views#143745
luigidellaquila merged 18 commits intoelastic:mainfrom
luigidellaquila:esql/views_telemetry_stack

Conversation

@luigidellaquila
Copy link
Copy Markdown
Member

@luigidellaquila luigidellaquila commented Mar 6, 2026

Adding Telemetry (stack) for views usage.

We just increment the counter every time a query uses views, ie. we don't track how many views a single query is using.
Developed using AI-assisted tooling

@luigidellaquila luigidellaquila added >enhancement test-release Trigger CI checks against release build :Analytics/ES|QL AKA ESQL labels Mar 6, 2026
@elasticsearchmachine
Copy link
Copy Markdown
Collaborator

Hi @luigidellaquila, I've created a changelog YAML for you.

@luigidellaquila luigidellaquila removed the test-release Trigger CI checks against release build label Mar 9, 2026
@luigidellaquila luigidellaquila marked this pull request as ready for review March 9, 2026 09:42
@elasticsearchmachine elasticsearchmachine added the Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) label Mar 9, 2026
@elasticsearchmachine
Copy link
Copy Markdown
Collaborator

Pinging @elastic/es-analytical-engine (Team:Analytics)

@astefan astefan self-requested a review March 13, 2026 10:41
return child();
}

public String name() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the original code kept name private and, also, to have an easier check for this - why not create a boolean method in Subquery that checks the name existence? isView or something similar.

Wondering also why Subquery was not extended with a new class - View - that added the name. It feels very fragile to check name inside Subquery to discover if a plan is or is not a View. My 2c.
Maybe @craigtaverner can weigh in on this aspect (unrelated to this PR).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @astefan, I'm adding an isView() method, it will make the code much more readable, and maybe it will simplify a future refactoring.
I agree that having a subclass specific for views could make things more clear

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It reminds me of this PR, it adds ViewUnionAll that extends UnionAll. I wonder if it affects view and subquery's telemetry?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm updating the PR at #143564 to remove the name field from Subquery. Instead the name is being saved inside the ViewUnionAll class, as @fang-xing-esql mentioned. I do actually also have a NamedSubquery class extending Subquery, but this is only ephemeral, and should not exist in the final plan.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That PR merged, and so Subquery no longer has names.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should remove these changes to Subquery.

if (metrics == null || viewResolution.viewQueries().isEmpty()) {
return;
}
// If any views were used, increment the views metric
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this comment helps the readability of the code. I think it is obvious what the next line does :-).

public void testSubqueryTelemetry() {
Row innerPlan = new Row(Source.EMPTY, List.of());

// A named Subquery represents a view - it should be excluded from plan traversal telemetry
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imho, this method also has too many comments.

Copy link
Copy Markdown
Contributor

@craigtaverner craigtaverner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the changes to Subquery will make this easier. Let's get that in and simplify this one.

issues: []
pr: 143745
summary: Add (stack) telemetry for views
type: enhancement
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering, do we add changelog entries for unreleased (snapshot-ony) features? Perhaps the label should be >non-issue?

COMPLETION(Completion.class::isInstance),
SAMPLE(Sample.class::isInstance),
SUBQUERY(Subquery.class::isInstance),
SUBQUERY(plan -> plan instanceof Subquery s && s.isView() == false),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm removing the use of Subquery in views, so we won't need to use the isView method.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subquery is now entirely removed from views.

SAMPLE(Sample.class::isInstance),
SUBQUERY(Subquery.class::isInstance),
SUBQUERY(plan -> plan instanceof Subquery s && s.isView() == false),
VIEWS(plan -> false), // Views are counted in EsqlSession.gatherViewMetrics, not via plan traversal
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, actually we could use plan traversal once the ViewUnionAll is implemented.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed my mind. The EsqlSession.gatherViewMetrics is the way to go.

}

private static boolean explicitlyExcluded(LogicalPlan plan) {
if (plan instanceof Subquery s && s.isView()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can probably drop this too.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, drop this.

Copy link
Copy Markdown
Contributor

@craigtaverner craigtaverner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I approve of the EsqlSession.gatherViewMetrics approach. But we need to revert the changes to Subquery, since that is no longer used in Views at all.

}

private void gatherViewMetrics(ViewResolver.ViewResolutionResult viewResolution) {
if (metrics == null || viewResolution.viewQueries().isEmpty()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does look like the best approach for now, since we cannot rely on Subquery.name() nor on the existence of ViewUnionAll, both of which can be empty/missing due to query simplification/compaction.

return child();
}

public String name() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should remove these changes to Subquery.

COMPLETION(Completion.class::isInstance),
SAMPLE(Sample.class::isInstance),
SUBQUERY(Subquery.class::isInstance),
SUBQUERY(plan -> plan instanceof Subquery s && s.isView() == false),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subquery is now entirely removed from views.

SAMPLE(Sample.class::isInstance),
SUBQUERY(Subquery.class::isInstance),
SUBQUERY(plan -> plan instanceof Subquery s && s.isView() == false),
VIEWS(plan -> false), // Views are counted in EsqlSession.gatherViewMetrics, not via plan traversal
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed my mind. The EsqlSession.gatherViewMetrics is the way to go.

}

private static boolean explicitlyExcluded(LogicalPlan plan) {
if (plan instanceof Subquery s && s.isView()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, drop this.

public void testSubqueryTelemetry() {
Row innerPlan = new Row(Source.EMPTY, List.of());

Subquery view = new Subquery(Source.EMPTY, innerPlan, "my_view");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subquery is no longer used for views, so this should be changed.

Copy link
Copy Markdown
Contributor

@craigtaverner craigtaverner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, although I am wondering about the use of a plural name while all other counters use singular?

COMPLETION(Completion.class::isInstance),
SAMPLE(Sample.class::isInstance),
SUBQUERY(Subquery.class::isInstance),
VIEWS(plan -> false), // Views are counted in EsqlSession.gatherViewMetrics, not via plan traversal
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering about the use of plural here, while others mostly use singular.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks!

- set: { esql.features.completion: completion_counter }
- set: { esql.features.sample: sample_counter }
- set: { esql.features.subquery: subquery_counter }
- set: { esql.features.views: views_counter }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed almost all other counters use the singular, like subquery_counter, and we are almost the only one using plural. Should we switch to singular?

@luigidellaquila luigidellaquila enabled auto-merge (squash) March 25, 2026 09:37
@luigidellaquila luigidellaquila merged commit e805d5d into elastic:main Mar 25, 2026
36 checks passed
seanzatzdev pushed a commit to seanzatzdev/elasticsearch that referenced this pull request Mar 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

:Analytics/ES|QL AKA ESQL >non-issue Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) v9.4.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants