[ML] translate anomaly utils (#28675)

[ML] translate anomalies table utils
This commit is contained in:
pavel06081991 2019-01-16 14:50:07 +03:00 committed by GitHub
parent 890a094901
commit 9d72276f13
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 92 additions and 50 deletions

View file

@ -182,30 +182,30 @@ describe('ML - anomaly utils', () => {
describe('getSeverity', () => {
it('returns warning for 0 <= score < 25', () => {
expect(getSeverity(0)).to.be('warning');
expect(getSeverity(0.001)).to.be('warning');
expect(getSeverity(24.99)).to.be('warning');
expect(getSeverity(0).id).to.be('warning');
expect(getSeverity(0.001).id).to.be('warning');
expect(getSeverity(24.99).id).to.be('warning');
});
it('returns minor for 25 <= score < 50', () => {
expect(getSeverity(25)).to.be('minor');
expect(getSeverity(49.99)).to.be('minor');
expect(getSeverity(25).id).to.be('minor');
expect(getSeverity(49.99).id).to.be('minor');
});
it('returns minor for 50 <= score < 75', () => {
expect(getSeverity(50)).to.be('major');
expect(getSeverity(74.99)).to.be('major');
expect(getSeverity(50).id).to.be('major');
expect(getSeverity(74.99).id).to.be('major');
});
it('returns critical for score >= 75', () => {
expect(getSeverity(75)).to.be('critical');
expect(getSeverity(100)).to.be('critical');
expect(getSeverity(1000)).to.be('critical');
expect(getSeverity(75).id).to.be('critical');
expect(getSeverity(100).id).to.be('critical');
expect(getSeverity(1000).id).to.be('critical');
});
it('returns unknown for scores less than 0 or string input', () => {
expect(getSeverity(-10)).to.be('unknown');
expect(getSeverity('value')).to.be('unknown');
expect(getSeverity(-10).id).to.be('unknown');
expect(getSeverity('value').id).to.be('unknown');
});
});
@ -213,35 +213,35 @@ describe('ML - anomaly utils', () => {
describe('getSeverityWithLow', () => {
it('returns low for 0 <= score < 3', () => {
expect(getSeverityWithLow(0)).to.be('low');
expect(getSeverityWithLow(0.001)).to.be('low');
expect(getSeverityWithLow(2.99)).to.be('low');
expect(getSeverityWithLow(0).id).to.be('low');
expect(getSeverityWithLow(0.001).id).to.be('low');
expect(getSeverityWithLow(2.99).id).to.be('low');
});
it('returns warning for 3 <= score < 25', () => {
expect(getSeverityWithLow(3)).to.be('warning');
expect(getSeverityWithLow(24.99)).to.be('warning');
expect(getSeverityWithLow(3).id).to.be('warning');
expect(getSeverityWithLow(24.99).id).to.be('warning');
});
it('returns minor for 25 <= score < 50', () => {
expect(getSeverityWithLow(25)).to.be('minor');
expect(getSeverityWithLow(49.99)).to.be('minor');
expect(getSeverityWithLow(25).id).to.be('minor');
expect(getSeverityWithLow(49.99).id).to.be('minor');
});
it('returns minor for 50 <= score < 75', () => {
expect(getSeverityWithLow(50)).to.be('major');
expect(getSeverityWithLow(74.99)).to.be('major');
expect(getSeverityWithLow(50).id).to.be('major');
expect(getSeverityWithLow(74.99).id).to.be('major');
});
it('returns critical for score >= 75', () => {
expect(getSeverityWithLow(75)).to.be('critical');
expect(getSeverityWithLow(100)).to.be('critical');
expect(getSeverityWithLow(1000)).to.be('critical');
expect(getSeverityWithLow(75).id).to.be('critical');
expect(getSeverityWithLow(100).id).to.be('critical');
expect(getSeverityWithLow(1000).id).to.be('critical');
});
it('returns unknown for scores less than 0 or string input', () => {
expect(getSeverityWithLow(-10)).to.be('unknown');
expect(getSeverityWithLow('value')).to.be('unknown');
expect(getSeverityWithLow(-10).id).to.be('unknown');
expect(getSeverityWithLow('value').id).to.be('unknown');
});
});

View file

@ -12,6 +12,7 @@
*/
import _ from 'lodash';
import { i18n } from '@kbn/i18n';
import { CONDITIONS_NOT_SUPPORTED_FUNCTIONS } from '../constants/detector_rule';
import { MULTI_BUCKET_IMPACT } from '../constants/multi_bucket_impact';
@ -23,19 +24,50 @@ const DISPLAY_ACTUAL_FUNCTIONS = ['count', 'distinct_count', 'lat_long', 'mean',
const DISPLAY_TYPICAL_FUNCTIONS = ['count', 'distinct_count', 'lat_long', 'mean', 'max', 'min', 'sum',
'median', 'varp', 'info_content', 'time'];
let severityTypes;
function getSeverityTypes() {
if (severityTypes) {
return severityTypes;
}
return severityTypes = {
critical: { id: 'critical', label: i18n.translate('xpack.ml.anomalyUtils.severity.criticalLabel', {
defaultMessage: 'critical',
}) },
major: { id: 'major', label: i18n.translate('xpack.ml.anomalyUtils.severity.majorLabel', {
defaultMessage: 'major',
}) },
minor: { id: 'minor', label: i18n.translate('xpack.ml.anomalyUtils.severity.minorLabel', {
defaultMessage: 'minor',
}) },
warning: { id: 'warning', label: i18n.translate('xpack.ml.anomalyUtils.severity.warningLabel', {
defaultMessage: 'warning',
}) },
unknown: { id: 'unknown', label: i18n.translate('xpack.ml.anomalyUtils.severity.unknownLabel', {
defaultMessage: 'unknown',
}) },
low: { id: 'low', label: i18n.translate('xpack.ml.anomalyUtils.severityWithLow.lowLabel', {
defaultMessage: 'low',
}) },
};
}
// Returns a severity label (one of critical, major, minor, warning or unknown)
// for the supplied normalized anomaly score (a value between 0 and 100).
export function getSeverity(normalizedScore) {
const severityTypesList = getSeverityTypes();
if (normalizedScore >= 75) {
return 'critical';
return severityTypesList.critical;
} else if (normalizedScore >= 50) {
return 'major';
return severityTypesList.major;
} else if (normalizedScore >= 25) {
return 'minor';
return severityTypesList.minor;
} else if (normalizedScore >= 0) {
return 'warning';
return severityTypesList.warning;
} else {
return 'unknown';
return severityTypesList.unknown;
}
}
@ -43,18 +75,20 @@ export function getSeverity(normalizedScore) {
// for the supplied normalized anomaly score (a value between 0 and 100), where scores
// less than 3 are assigned a severity of 'low'.
export function getSeverityWithLow(normalizedScore) {
const severityTypesList = getSeverityTypes();
if (normalizedScore >= 75) {
return 'critical';
return severityTypesList.critical;
} else if (normalizedScore >= 50) {
return 'major';
return severityTypesList.major;
} else if (normalizedScore >= 25) {
return 'minor';
return severityTypesList.minor;
} else if (normalizedScore >= 3) {
return 'warning';
return severityTypesList.warning;
} else if (normalizedScore >= 0) {
return 'low';
return severityTypesList.low;
} else {
return 'unknown';
return severityTypesList.unknown;
}
}
@ -81,13 +115,21 @@ export function getSeverityColor(normalizedScore) {
// which ranges from -5 to +5.
export function getMultiBucketImpactLabel(multiBucketImpact) {
if (multiBucketImpact >= MULTI_BUCKET_IMPACT.HIGH) {
return 'high';
return i18n.translate('xpack.ml.anomalyUtils.multiBucketImpact.highLabel', {
defaultMessage: 'high',
});
} else if (multiBucketImpact >= MULTI_BUCKET_IMPACT.MEDIUM) {
return 'medium';
return i18n.translate('xpack.ml.anomalyUtils.multiBucketImpact.mediumLabel', {
defaultMessage: 'medium',
});
} else if (multiBucketImpact >= MULTI_BUCKET_IMPACT.LOW) {
return 'low';
return i18n.translate('xpack.ml.anomalyUtils.multiBucketImpact.lowLabel', {
defaultMessage: 'low',
});
} else {
return 'none';
return i18n.translate('xpack.ml.anomalyUtils.multiBucketImpact.noneLabel', {
defaultMessage: 'none',
});
}
}

View file

@ -333,7 +333,7 @@ export class AnomalyDetails extends Component {
let anomalyDescription = i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.anomalyInLabel', {
defaultMessage: '{anomalySeverity} anomaly in {anomalyDetector}',
values: {
anomalySeverity: getSeverity(anomaly.severity),
anomalySeverity: getSeverity(anomaly.severity).label,
anomalyDetector: anomaly.detector,
}
});

View file

@ -72,7 +72,7 @@ function Influencer({ influencerFieldName, valueData }) {
<div className="field-value">mlcategory {valueData.influencerFieldValue}</div>
)}
</div>
<div className={`progress ${severity}`} value="{valueData.maxAnomalyScore}" max="100">
<div className={`progress ${severity.id}`} value="{valueData.maxAnomalyScore}" max="100">
<div className="progress-bar-holder">
<div className="progress-bar" style={barStyle}/>
</div>

View file

@ -378,7 +378,7 @@ export const ExplorerChartDistribution = injectI18n(class ExplorerChartDistribut
let markerClass = 'metric-value';
if (_.has(d, 'anomalyScore') && Number(d.anomalyScore) >= threshold.val) {
markerClass += ' anomaly-marker ';
markerClass += getSeverityWithLow(d.anomalyScore);
markerClass += getSeverityWithLow(d.anomalyScore).id;
}
return markerClass;
});

View file

@ -291,7 +291,7 @@ export const ExplorerChartSingleMetric = injectI18n(class ExplorerChartSingleMet
.attr('class', (d) => {
let markerClass = 'metric-value';
if (_.has(d, 'anomalyScore') && Number(d.anomalyScore) >= threshold.val) {
markerClass += ` anomaly-marker ${getSeverityWithLow(d.anomalyScore)}`;
markerClass += ` anomaly-marker ${getSeverityWithLow(d.anomalyScore).id}`;
}
return markerClass;
});
@ -307,7 +307,7 @@ export const ExplorerChartSingleMetric = injectI18n(class ExplorerChartSingleMet
multiBucketMarkers.enter().append('path')
.attr('d', d3.svg.symbol().size(MULTI_BUCKET_SYMBOL_SIZE).type('cross'))
.attr('transform', d => `translate(${lineChartXScale(d.date)}, ${lineChartYScale(d.value)})`)
.attr('class', d => `anomaly-marker multi-bucket ${getSeverityWithLow(d.anomalyScore)}`)
.attr('class', d => `anomaly-marker multi-bucket ${getSeverityWithLow(d.anomalyScore).id}`)
// Don't use an arrow function since we need access to `this`.
.on('mouseover', function (d) {
showLineChartTooltip(d, this);

View file

@ -778,7 +778,7 @@ export const TimeseriesChart = injectI18n(class TimeseriesChart extends React.Co
.attr('class', (d) => {
let markerClass = 'metric-value';
if (_.has(d, 'anomalyScore')) {
markerClass += ` anomaly-marker ${getSeverityWithLow(d.anomalyScore)}`;
markerClass += ` anomaly-marker ${getSeverityWithLow(d.anomalyScore).id}`;
}
return markerClass;
});
@ -801,7 +801,7 @@ export const TimeseriesChart = injectI18n(class TimeseriesChart extends React.Co
// Update all markers to new positions.
multiBucketMarkers.attr('transform', d => `translate(${this.focusXScale(d.date)}, ${this.focusYScale(d.value)})`)
.attr('class', d => `anomaly-marker multi-bucket ${getSeverityWithLow(d.anomalyScore)}`);
.attr('class', d => `anomaly-marker multi-bucket ${getSeverityWithLow(d.anomalyScore).id}`);
// Add rectangular markers for any scheduled events.
@ -1522,13 +1522,13 @@ export const TimeseriesChart = injectI18n(class TimeseriesChart extends React.Co
selectedMarker.enter().append('path')
.attr('d', d3.svg.symbol().size(MULTI_BUCKET_SYMBOL_SIZE).type('cross'))
.attr('transform', d => `translate(${focusXScale(d.date)}, ${focusYScale(d.value)})`)
.attr('class', d => `anomaly-marker multi-bucket ${getSeverityWithLow(d.anomalyScore)} highlighted`);
.attr('class', d => `anomaly-marker multi-bucket ${getSeverityWithLow(d.anomalyScore).id} highlighted`);
} else {
selectedMarker.enter().append('circle')
.attr('r', LINE_CHART_ANOMALY_RADIUS)
.attr('cx', d => focusXScale(d.date))
.attr('cy', d => focusYScale(d.value))
.attr('class', d => `anomaly-marker metric-value ${getSeverityWithLow(d.anomalyScore)} highlighted`);
.attr('class', d => `anomaly-marker metric-value ${getSeverityWithLow(d.anomalyScore).id} highlighted`);
}
// Display the chart tooltip for this marker.