datatrails: fix: improve performance of related metrics sort (#82285)

fix: improve performance of related metrics sort
This commit is contained in:
Darren Janeczek 2024-02-12 09:52:44 -05:00 committed by GitHub
parent 1fe32479d7
commit cd09c36448
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 43 additions and 17 deletions

View File

@ -1,5 +1,4 @@
import { css } from '@emotion/css';
import leven from 'leven';
import { debounce } from 'lodash';
import React, { useCallback } from 'react';
@ -29,6 +28,7 @@ import { MetricCategoryCascader } from './MetricCategory/MetricCategoryCascader'
import { MetricScene } from './MetricScene';
import { SelectMetricAction } from './SelectMetricAction';
import { hideEmptyPreviews } from './hideEmptyPreviews';
import { sortRelatedMetrics } from './relatedMetrics';
import { getVariablesWithMetricConstant, trailDS, VAR_DATASOURCE, VAR_FILTERS_EXPR, VAR_METRIC_NAMES } from './shared';
import { getColorByIndex, getTrailFor } from './utils';
@ -431,22 +431,6 @@ function getCardPanelFor(metric: string) {
.build();
}
// Computes the Levenshtein distance between two strings, twice, once for the first half and once for the whole string.
function sortRelatedMetrics(metricList: string[], metric: string) {
return metricList.sort((aValue, bValue) => {
const aSplit = aValue.split('_');
const aHalf = aSplit.slice(0, aSplit.length / 2).join('_');
const bSplit = bValue.split('_');
const bHalf = bSplit.slice(0, bSplit.length / 2).join('_');
return (
(leven(aHalf, metric!) || 0 + (leven(aValue, metric!) || 0)) -
(leven(bHalf, metric!) || 0 + (leven(bValue, metric!) || 0))
);
});
}
function getStyles(theme: GrafanaTheme2) {
return {
container: css({

View File

@ -0,0 +1,42 @@
import leven from 'leven';
export function sortRelatedMetrics(metricList: string[], metric: string) {
return metricList.sort((aValue, bValue) => {
const a = getLevenDistances(aValue, metric);
const b = getLevenDistances(bValue, metric);
return a.halfLeven + a.wholeLeven - (b.halfLeven + b.wholeLeven);
});
}
type LevenDistances = { halfLeven: number; wholeLeven: number };
type TargetToLevenDistances = Map<string, LevenDistances>;
const metricToTargetLevenDistances = new Map<string, TargetToLevenDistances>();
// Provides the Levenshtein distance between a metric to be sorted
// and a targetMetric compared to which all other metrics are being sorted
// There are two distances: once for the first half and once for the whole string.
// This operation is not expected to be symmetric; order of parameters matters
// since only `metric` is split.
function getLevenDistances(metric: string, targetMetric: string) {
let targetToDistances: TargetToLevenDistances | undefined = metricToTargetLevenDistances.get(metric);
if (!targetToDistances) {
targetToDistances = new Map<string, LevenDistances>();
metricToTargetLevenDistances.set(metric, targetToDistances);
}
let distances: LevenDistances | undefined = targetToDistances.get(targetMetric);
if (!distances) {
const metricSplit = metric.split('_');
const metricHalf = metricSplit.slice(0, metricSplit.length / 2).join('_');
const halfLeven = leven(metricHalf, targetMetric!) || 0;
const wholeLeven = leven(metric, targetMetric!) || 0;
distances = { halfLeven, wholeLeven };
targetToDistances.set(targetMetric, distances);
}
return distances;
}