Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ML] Package @kbn/ml-anomaly-utils #155697

Merged
merged 43 commits into from
May 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
8edbfe7
@kbn/ml-anomaly-utils package
walterra Apr 25, 2023
48d2dcc
move constants/anomalies, types/custom_urls, types/anomalies to package
walterra Apr 25, 2023
cae0354
fix imports
walterra Apr 25, 2023
7d06b20
fix i18n
walterra Apr 25, 2023
ed3e9c3
fix package.json
walterra Apr 25, 2023
ea25f77
fix imports
walterra Apr 25, 2023
6dffb58
fix imports
walterra Apr 25, 2023
b933b26
fix dependency setup
walterra Apr 25, 2023
6ce5405
fix exports
walterra Apr 25, 2023
0eefe99
restructure package for deep imports
walterra Apr 26, 2023
c941f77
deep imports to reduce bundle size
walterra Apr 26, 2023
759017a
deep imports
walterra Apr 26, 2023
451a5a2
use original package constants for apm
walterra Apr 26, 2023
da211b8
jsdoc
walterra Apr 26, 2023
13592c9
fix import
walterra Apr 26, 2023
1e4f911
jsdoc
walterra Apr 26, 2023
dd29ac7
comments
walterra Apr 26, 2023
33735b5
rename ANOMALY_SEVERITY to ML_ANOMALY_SEVERITY
walterra Apr 26, 2023
4c9349e
rename ANOMALY_THRESHOLD to ML_ANOMALY_THRESHOLD
walterra Apr 26, 2023
56030e7
rename SEVERITY_COLORS to ML_SEVERITY_COLORS
walterra Apr 26, 2023
74a9f29
rename ENTITY_FIELD_OPERATIONS to ML_ENTITY_FIELD_OPERATIONS
walterra Apr 26, 2023
56197fe
rename ANOMALY_RESULT_TYPE to ML_ANOMALY_RESULT_TYPE
walterra Apr 26, 2023
0844a3a
rename PARTITION_FIELD_VALUE to ML_PARTITION_FIELD_VALUE
walterra Apr 26, 2023
dfe73ab
rename PARTITION_FIELDS to ML_PARTITION_FIELDS
walterra Apr 26, 2023
91963ac
rename JOB_ID to ML_JOB_ID
walterra Apr 26, 2023
5cba382
rename SEVERITY_COLOR_RAMP to ML_SEVERITY_COLOR_RAMP
walterra Apr 26, 2023
7569097
rename detector rule constants
walterra Apr 26, 2023
8730ad4
rename PartitionFieldsType to MlPartitionFieldsType
walterra Apr 26, 2023
9c123b4
rename RecordForInfluencer to MlRecordForInfluencer
walterra Apr 26, 2023
c946189
rename Influencer to MlInfluencer
walterra Apr 26, 2023
c3f80d9
rename EntityFieldType to MLEntityFieldType
walterra Apr 26, 2023
9c14664
prefix renames
walterra Apr 26, 2023
9542b8d
rename CustomUrlAnomalyRecordDoc to MLCustomUrlAnomalyRecordDoc
walterra Apr 26, 2023
1111e22
rename KibanaUrlConfig to MlKibanaUrlConfig
walterra Apr 26, 2023
82aa383
prefix renames
walterra Apr 26, 2023
b19c0e5
fix infra imports
walterra Apr 26, 2023
fb30dd6
fix security_solution import
walterra Apr 26, 2023
bdee7cc
refactor severity types from getter to just a const
walterra Apr 26, 2023
ab7b120
jsdoc
walterra Apr 27, 2023
483706c
Merge branch 'main' into ml-package-anomaly-utils
walterra Apr 27, 2023
cae86e9
Merge branch 'main' into ml-package-anomaly-utils
walterra May 2, 2023
a979569
fix typo in ML_DETECTOR_RULE_*
walterra May 2, 2023
662f414
Merge branch 'main' into ml-package-anomaly-utils
walterra May 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ x-pack/examples/third_party_maps_source_example @elastic/kibana-gis
src/plugins/maps_ems @elastic/kibana-gis
x-pack/plugins/maps @elastic/kibana-gis
x-pack/packages/ml/agg_utils @elastic/ml-ui
x-pack/packages/ml/anomaly_utils @elastic/ml-ui
x-pack/packages/ml/date_picker @elastic/ml-ui
x-pack/packages/ml/error_utils @elastic/ml-ui
x-pack/packages/ml/is_defined @elastic/ml-ui
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@
"@kbn/maps-ems-plugin": "link:src/plugins/maps_ems",
"@kbn/maps-plugin": "link:x-pack/plugins/maps",
"@kbn/ml-agg-utils": "link:x-pack/packages/ml/agg_utils",
"@kbn/ml-anomaly-utils": "link:x-pack/packages/ml/anomaly_utils",
"@kbn/ml-date-picker": "link:x-pack/packages/ml/date_picker",
"@kbn/ml-error-utils": "link:x-pack/packages/ml/error_utils",
"@kbn/ml-is-defined": "link:x-pack/packages/ml/is_defined",
Expand Down
2 changes: 2 additions & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,8 @@
"@kbn/maps-plugin/*": ["x-pack/plugins/maps/*"],
"@kbn/ml-agg-utils": ["x-pack/packages/ml/agg_utils"],
"@kbn/ml-agg-utils/*": ["x-pack/packages/ml/agg_utils/*"],
"@kbn/ml-anomaly-utils": ["x-pack/packages/ml/anomaly_utils"],
"@kbn/ml-anomaly-utils/*": ["x-pack/packages/ml/anomaly_utils/*"],
"@kbn/ml-date-picker": ["x-pack/packages/ml/date_picker"],
"@kbn/ml-date-picker/*": ["x-pack/packages/ml/date_picker/*"],
"@kbn/ml-error-utils": ["x-pack/packages/ml/error_utils"],
Expand Down
9 changes: 7 additions & 2 deletions x-pack/.i18nrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"prefix": "xpack",
"paths": {
"xpack.actions": "plugins/actions",
"xpack.aiops": ["packages/ml/aiops_components", "plugins/aiops"],
"xpack.alerting": "plugins/alerting",
"xpack.eventLog": "plugins/event_log",
"xpack.stackAlerts": "plugins/stack_alerts",
Expand Down Expand Up @@ -45,8 +46,12 @@
"xpack.logstash": ["plugins/logstash"],
"xpack.main": "legacy/plugins/xpack_main",
"xpack.maps": ["plugins/maps"],
"xpack.aiops": ["packages/ml/aiops_components", "plugins/aiops"],
"xpack.ml": ["packages/ml/date_picker", "packages/ml/trained_models_utils", "plugins/ml"],
"xpack.ml": [
"packages/ml/anomaly_utils",
"packages/ml/date_picker",
"packages/ml/trained_models_utils",
"plugins/ml"
],
"xpack.monitoring": ["plugins/monitoring"],
"xpack.observability": "plugins/observability",
"xpack.observabilityShared": "plugins/observability_shared",
Expand Down
3 changes: 3 additions & 0 deletions x-pack/packages/ml/anomaly_utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @kbn/ml-anomaly-utils

Utility functions, constants and types for Machine Learning's Anomaly Detection.
63 changes: 63 additions & 0 deletions x-pack/packages/ml/anomaly_utils/anomaly_severity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

/**
* Labels displayed in the ML UI to indicate the severity of the anomaly according
* to the normalized anomaly score.
*/
export enum ML_ANOMALY_SEVERITY {
/**
* Anomalies are displayed as critical severity when the score is greater than or equal to 75.
*/
CRITICAL = 'critical',

/**
* Anomalies are displayed as major severity when the score is greater than or equal to 50 and less than 75.
*/
MAJOR = 'major',

/**
* Anomalies are displayed as minor severity when the score is greater than or equal to 25 and less than 50.
*/
MINOR = 'minor',

/**
* Anomalies are displayed as warning severity when the score is greater than or equal to 3 and less than 25.
* Note in some parts of the UI, warning severity is used when the score is greater than or equal to 0.
*/
WARNING = 'warning',

/**
* Anomalies are displayed as low severity in some parts of the ML UI when the score is greater than or equal to 0 and less than 3.
*/
LOW = 'low',

/**
* Anomalies are displayed as unknown severity if the anomaly score is not known.
*/
UNKNOWN = 'unknown',
}

/**
* Interface for severity types to be used in ML_ANOMALY_SEVERITY_TYPES.
*
* @export
* @interface MlSeverityType
* @typedef {MlSeverityType}
*/
export interface MlSeverityType {
/**
* One of ML_ANOMALY_SEVERITY
* @type {ML_ANOMALY_SEVERITY}
*/
id: ML_ANOMALY_SEVERITY;
/**
* Translated ML_ANOMALY_SEVERITY
* @type {string}
*/
label: string;
}
48 changes: 48 additions & 0 deletions x-pack/packages/ml/anomaly_utils/anomaly_severity_types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { i18n } from '@kbn/i18n';
import { type MlSeverityType, ML_ANOMALY_SEVERITY } from './anomaly_severity';

export const ML_ANOMALY_SEVERITY_TYPES: Record<ML_ANOMALY_SEVERITY, MlSeverityType> = {
critical: {
id: ML_ANOMALY_SEVERITY.CRITICAL,
label: i18n.translate('xpack.ml.anomalyUtils.severity.criticalLabel', {
defaultMessage: 'critical',
}),
},
major: {
id: ML_ANOMALY_SEVERITY.MAJOR,
label: i18n.translate('xpack.ml.anomalyUtils.severity.majorLabel', {
defaultMessage: 'major',
}),
},
minor: {
id: ML_ANOMALY_SEVERITY.MINOR,
label: i18n.translate('xpack.ml.anomalyUtils.severity.minorLabel', {
defaultMessage: 'minor',
}),
},
warning: {
id: ML_ANOMALY_SEVERITY.WARNING,
label: i18n.translate('xpack.ml.anomalyUtils.severity.warningLabel', {
defaultMessage: 'warning',
}),
},
unknown: {
id: ML_ANOMALY_SEVERITY.UNKNOWN,
label: i18n.translate('xpack.ml.anomalyUtils.severity.unknownLabel', {
defaultMessage: 'unknown',
}),
},
low: {
id: ML_ANOMALY_SEVERITY.LOW,
label: i18n.translate('xpack.ml.anomalyUtils.severityWithLow.lowLabel', {
defaultMessage: 'low',
}),
},
};
36 changes: 36 additions & 0 deletions x-pack/packages/ml/anomaly_utils/anomaly_threshold.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

/**
* Anomaly score numeric thresholds to indicate the severity of the anomaly.
*/
export enum ML_ANOMALY_THRESHOLD {
/**
* Threshold at which anomalies are labelled in the UI as critical.
*/
CRITICAL = 75,

/**
* Threshold at which anomalies are labelled in the UI as major.
*/
MAJOR = 50,

/**
* Threshold at which anomalies are labelled in the UI as minor.
*/
MINOR = 25,

/**
* Threshold at which anomalies are labelled in the UI as warning.
*/
WARNING = 3,

/**
* Threshold at which anomalies are labelled in the UI as low.
*/
LOW = 0,
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,22 @@
* 2.0.
*/

import { AnomalyRecordDoc } from '../types/anomalies';
import type { MlAnomalyRecordDoc } from './types';

import {
aggregationTypeTransform,
getEntityFieldList,
getEntityFieldName,
getEntityFieldValue,
getSeverity,
getSeverityWithLow,
getSeverityColor,
isRuleSupported,
showActualForFunction,
showTypicalForFunction,
isMultiBucketAnomaly,
} from './anomaly_utils';

describe('ML - anomaly utils', () => {
const partitionEntityRecord: AnomalyRecordDoc = {
const partitionEntityRecord: MlAnomalyRecordDoc = {
job_id: 'farequote',
result_type: 'record',
probability: 0.012818,
Expand All @@ -39,7 +37,7 @@ describe('ML - anomaly utils', () => {
field_name: 'responsetime',
};

const byEntityRecord: AnomalyRecordDoc = {
const byEntityRecord: MlAnomalyRecordDoc = {
job_id: 'farequote',
result_type: 'record',
probability: 0.012818,
Expand All @@ -56,7 +54,7 @@ describe('ML - anomaly utils', () => {
field_name: 'responsetime',
};

const overEntityRecord: AnomalyRecordDoc = {
const overEntityRecord: MlAnomalyRecordDoc = {
job_id: 'gallery',
result_type: 'record',
probability: 2.81806e-9,
Expand All @@ -74,7 +72,7 @@ describe('ML - anomaly utils', () => {
over_field_value: '37.157.32.164',
};

const noEntityRecord: AnomalyRecordDoc = {
const noEntityRecord: MlAnomalyRecordDoc = {
job_id: 'farequote_no_by',
result_type: 'record',
probability: 0.0191711,
Expand All @@ -89,7 +87,7 @@ describe('ML - anomaly utils', () => {
field_name: 'responsetime',
};

const metricNoEntityRecord: AnomalyRecordDoc = {
const metricNoEntityRecord: MlAnomalyRecordDoc = {
job_id: 'farequote_metric',
result_type: 'record',
probability: 0.030133495093182184,
Expand All @@ -113,7 +111,7 @@ describe('ML - anomaly utils', () => {
airline: ['NKS'],
};

const rareEntityRecord: AnomalyRecordDoc = {
const rareEntityRecord: MlAnomalyRecordDoc = {
job_id: 'gallery',
result_type: 'record',
probability: 0.02277014211908481,
Expand Down Expand Up @@ -166,34 +164,6 @@ describe('ML - anomaly utils', () => {
status: ['206'],
};

describe('getSeverity', () => {
test('returns warning for 0 <= score < 25', () => {
expect(getSeverity(0).id).toBe('warning');
expect(getSeverity(0.001).id).toBe('warning');
expect(getSeverity(24.99).id).toBe('warning');
});

test('returns minor for 25 <= score < 50', () => {
expect(getSeverity(25).id).toBe('minor');
expect(getSeverity(49.99).id).toBe('minor');
});

test('returns minor for 50 <= score < 75', () => {
expect(getSeverity(50).id).toBe('major');
expect(getSeverity(74.99).id).toBe('major');
});

test('returns critical for score >= 75', () => {
expect(getSeverity(75).id).toBe('critical');
expect(getSeverity(100).id).toBe('critical');
expect(getSeverity(1000).id).toBe('critical');
});

test('returns unknown for scores less than 0', () => {
expect(getSeverity(-10).id).toBe('unknown');
});
});

describe('getSeverityWithLow', () => {
test('returns low for 0 <= score < 3', () => {
expect(getSeverityWithLow(0).id).toBe('low');
Expand Down Expand Up @@ -227,41 +197,8 @@ describe('ML - anomaly utils', () => {
});
});

describe('getSeverityColor', () => {
test('returns correct hex code for low for 0 <= score < 3', () => {
expect(getSeverityColor(0)).toBe('#d2e9f7');
expect(getSeverityColor(0.001)).toBe('#d2e9f7');
expect(getSeverityColor(2.99)).toBe('#d2e9f7');
});

test('returns correct hex code for warning for 3 <= score < 25', () => {
expect(getSeverityColor(3)).toBe('#8bc8fb');
expect(getSeverityColor(24.99)).toBe('#8bc8fb');
});

test('returns correct hex code for minor for 25 <= score < 50', () => {
expect(getSeverityColor(25)).toBe('#fdec25');
expect(getSeverityColor(49.99)).toBe('#fdec25');
});

test('returns correct hex code for major for 50 <= score < 75', () => {
expect(getSeverityColor(50)).toBe('#fba740');
expect(getSeverityColor(74.99)).toBe('#fba740');
});

test('returns correct hex code for critical for score >= 75', () => {
expect(getSeverityColor(75)).toBe('#fe5050');
expect(getSeverityColor(100)).toBe('#fe5050');
expect(getSeverityColor(1000)).toBe('#fe5050');
});

test('returns correct hex code for unknown for scores less than 0', () => {
expect(getSeverityColor(-10)).toBe('#ffffff');
});
});

describe('isMultiBucketAnomaly', () => {
const singleBucketAnomaly: AnomalyRecordDoc = {
const singleBucketAnomaly: MlAnomalyRecordDoc = {
job_id: 'farequote_sb',
result_type: 'record',
probability: 0.0191711,
Expand All @@ -283,7 +220,7 @@ describe('ML - anomaly utils', () => {
},
};

const multiBucketAnomaly: AnomalyRecordDoc = {
const multiBucketAnomaly: MlAnomalyRecordDoc = {
job_id: 'farequote_mb',
result_type: 'record',
probability: 0.0191711,
Expand All @@ -305,7 +242,7 @@ describe('ML - anomaly utils', () => {
},
};

const multiBucketAnomaly2: AnomalyRecordDoc = {
const multiBucketAnomaly2: MlAnomalyRecordDoc = {
job_id: 'farequote_mb2',
result_type: 'record',
probability: 0.0191711,
Expand All @@ -326,7 +263,7 @@ describe('ML - anomaly utils', () => {
},
};

const noASEAnomaly: AnomalyRecordDoc = {
const noASEAnomaly: MlAnomalyRecordDoc = {
job_id: 'farequote_ase',
result_type: 'record',
probability: 0.0191711,
Expand All @@ -341,7 +278,7 @@ describe('ML - anomaly utils', () => {
field_name: 'responsetime',
};

const noMBIAnomaly: AnomalyRecordDoc = {
const noMBIAnomaly: MlAnomalyRecordDoc = {
job_id: 'farequote_sbi',
result_type: 'record',
probability: 0.0191711,
Expand All @@ -362,7 +299,7 @@ describe('ML - anomaly utils', () => {
},
};

const singleBucketAnomaly2: AnomalyRecordDoc = {
const singleBucketAnomaly2: MlAnomalyRecordDoc = {
job_id: 'farequote_sb2',
result_type: 'record',
probability: 0.0191711,
Expand Down
Loading