Skip to content

[Research] Possible performance improvements in Lens expressions #182151

@markov00

Description

@markov00

I will add here some of the findings related to performance bottlenecks I've found in the current Lens/SearchStrategy architecture and possible improvements to these solutions.

Unnecessary multiple requests with the same esagg query

When a search is sent to ES and a response is received, the search service is looking if the request needs a post-flight request.

if (!this.hasPostFlightRequests()) {
obs.next(this.postFlightTransform(response));
obs.complete();
} else {
// Treat the complete response as partial, then run the postFlightRequests.
obs.next({
...this.postFlightTransform(response),
isPartial: true,
isRunning: true,
});

If needed, it transforms the response to a partial response and update the body with the postflight request.
This works correctly if the postflight is actually necessary, but due to the current implementation the postflight request is always "applied" even if not needed, causing a subsequent request to be sent to ES.
This results to an increase of:

  • more time spent unnecessary before returning the results to the client
  • 1 more unnecessary search strategy that cache check
  • 1 more unnecessary run of tabify

Analysis
The current method that checks if a request needs a subsequent post-flight request relies on a loose check from the function hasPostFlightRequests. This function checks if the agg property type.postFlightRequest is a function.

private hasPostFlightRequests() {
const aggs = this.getField('aggs');
if (aggs instanceof AggConfigs) {
return aggs.aggs.some(
(agg) => agg.enabled && typeof agg.type.postFlightRequest === 'function'
);
} else {
return false;
}
}

This function is there even if is not required. For example in a terms aggregation without the other bucket the function is still there but just return its identity

postFlightRequest: createOtherBucketPostFlightRequest(constructSingleTermOtherFilter),

All the other cases this is defaulted to an identity function, so the hasPostFlightRequests function will always return true.
this.postFlightRequest = config.postFlightRequest || identity;

wait_for_completion_timeout value is too low and can't process, without delays, a full response

This parameter, used in async search, describes the timeout before returning asynch search with a partial result..
This parameter is currently set to 200ms.

waitForCompletion: schema.duration({ defaultValue: '200ms' }),

After this 200ms interval the polling mechanism kicks in and the results then are just delayed everytime by at least ~300ms

const getPollInterval = (elapsedTime: number): number => {
if (typeof pollInterval === 'number') return pollInterval;
else {
// if static pollInterval is not provided, then use default back-off logic
switch (true) {
case elapsedTime < 1500:
return 300;
case elapsedTime < 5000:
return 1000;
case elapsedTime < 20000:
return 2500;
default:
return 5000;
}
}
};

Probably I don't have enough knowledge in that, but I don't see any major drawback to increase this value to at least 1s as proposed here #157837 (comment) or even more.
The main drawback with that is an open connection between ES and Kibana that last for ~1 second, instead of opening and closing a new one 5 times in the same time interval.

getXDomain can be speeded up

When using cartesian charts, we compute the x domain. If that domain is big, the time to compute is pretty relevant. For example for a 50k data point dataset it tooks ~40ms. This can probably reduced by half if we adopt a better strategy on data processing, avoiding multiple array scans to sort, filter, map values and we just loop once with a reduce.

Screenshot 2024-04-30 at 17 24 52

Metadata

Metadata

Assignees

No one assigned

    Labels

    Team:VisualizationsTeam label for Lens, elastic-charts, Graph, legacy editors (TSVB, Visualize, Timelion) t//researchtechnical debtImprovement of the software architecture and operational architecture

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions