From 6113e6c1e5437ea3ac3e3548722dfcda36a00872 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 17 Sep 2024 19:33:10 +1000 Subject: [PATCH] [8.x] [ML] Anomaly Explorer: Display markers for scheduled events in distribution type anomaly charts (#192377) (#193118) # Backport This will backport the following commits from `main` to `8.x`: - [[ML] Anomaly Explorer: Display markers for scheduled events in distribution type anomaly charts (#192377)](https://github.com/elastic/kibana/pull/192377) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) Co-authored-by: Robert Jaszczurek <92210485+rbrtj@users.noreply.github.com> --- x-pack/plugins/ml/common/constants/charts.ts | 2 ++ .../explorer_chart_distribution.js | 32 ++++++++++++++++--- .../models/results_service/anomaly_charts.ts | 16 ++++++++-- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/ml/common/constants/charts.ts b/x-pack/plugins/ml/common/constants/charts.ts index 046504a44177a..b2e9a8493b56f 100644 --- a/x-pack/plugins/ml/common/constants/charts.ts +++ b/x-pack/plugins/ml/common/constants/charts.ts @@ -13,3 +13,5 @@ export const CHART_TYPE = { } as const; export type ChartType = (typeof CHART_TYPE)[keyof typeof CHART_TYPE]; + +export const SCHEDULE_EVENT_MARKER_ENTITY = 'schedule_event_marker_entity'; diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js index 58052f5f35a65..79e8bd449876e 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js @@ -40,6 +40,7 @@ import { CHART_TYPE } from '../explorer_constants'; import { CHART_HEIGHT, TRANSPARENT_BACKGROUND } from './constants'; import { filter } from 'rxjs'; import { drawCursor } from './utils/draw_anomaly_explorer_charts_cursor'; +import { SCHEDULE_EVENT_MARKER_ENTITY } from '../../../../common/constants/charts'; const CONTENT_WRAPPER_HEIGHT = 215; const SCHEDULED_EVENT_MARKER_HEIGHT = 5; @@ -158,12 +159,29 @@ export class ExplorerChartDistribution extends React.Component { .key((d) => d.entity) .entries(chartData) .sort((a, b) => { + // To display calendar event markers we populate the chart with fake data points. + // If a category has fake data points, it should be sorted to the end. + const aHasFakeData = a.values.some((d) => d.entity === SCHEDULE_EVENT_MARKER_ENTITY); + const bHasFakeData = b.values.some((d) => d.entity === SCHEDULE_EVENT_MARKER_ENTITY); + + if (aHasFakeData && !bHasFakeData) { + return 1; + } + + if (bHasFakeData && !aHasFakeData) { + return -1; + } + return b.values.length - a.values.length; }) .filter((d, i) => { // only filter for rare charts if (chartType === CHART_TYPE.EVENT_DISTRIBUTION) { - return i < categoryLimit || d.key === highlight; + return ( + i < categoryLimit || + d.key === highlight || + d.values.some((d) => d.entity === SCHEDULE_EVENT_MARKER_ENTITY) + ); } return true; }) @@ -373,7 +391,8 @@ export class ExplorerChartDistribution extends React.Component { .orient('left') .innerTickSize(0) .outerTickSize(0) - .tickPadding(10); + .tickPadding(10) + .tickFormat((d) => (d === SCHEDULE_EVENT_MARKER_ENTITY ? null : d)); if (fieldFormat !== undefined) { yAxis.tickFormat((d) => fieldFormat.convert(d, 'text')); @@ -518,7 +537,8 @@ export class ExplorerChartDistribution extends React.Component { const tooltipData = [{ label: formattedDate }]; const seriesKey = config.detectorLabel; - if (marker.entity !== undefined) { + // Hide entity for scheduled events with mocked value. + if (marker.entity !== undefined && marker.entity !== SCHEDULE_EVENT_MARKER_ENTITY) { tooltipData.push({ label: i18n.translate('xpack.ml.explorer.distributionChart.entityLabel', { defaultMessage: 'entity', @@ -590,7 +610,11 @@ export class ExplorerChartDistribution extends React.Component { }); } } - } else if (chartType !== CHART_TYPE.EVENT_DISTRIBUTION) { + } else if ( + chartType !== CHART_TYPE.EVENT_DISTRIBUTION && + // Hide value for scheduled events with mocked value. + marker.entity !== SCHEDULE_EVENT_MARKER_ENTITY + ) { tooltipData.push({ label: i18n.translate( 'xpack.ml.explorer.distributionChart.valueWithoutAnomalyScoreLabel', diff --git a/x-pack/plugins/ml/server/models/results_service/anomaly_charts.ts b/x-pack/plugins/ml/server/models/results_service/anomaly_charts.ts index 8d14417a1d383..7e551b0624261 100644 --- a/x-pack/plugins/ml/server/models/results_service/anomaly_charts.ts +++ b/x-pack/plugins/ml/server/models/results_service/anomaly_charts.ts @@ -53,7 +53,7 @@ import { parseInterval } from '../../../common/util/parse_interval'; import { getDatafeedAggregations } from '../../../common/util/datafeed_utils'; import { findAggField } from '../../../common/util/validation_utils'; import type { ChartType } from '../../../common/constants/charts'; -import { CHART_TYPE } from '../../../common/constants/charts'; +import { CHART_TYPE, SCHEDULE_EVENT_MARKER_ENTITY } from '../../../common/constants/charts'; import { getChartType } from '../../../common/util/chart_utils'; import type { MlJob } from '../..'; @@ -1124,9 +1124,19 @@ export function anomalyChartsDataProvider(mlClient: MlClient, client: IScopedClu each(scheduledEvents, (events, time) => { const chartPoint = findChartPointForTime(chartDataForPointSearch, Number(time)); if (chartPoint !== undefined) { - // Note if the scheduled event coincides with an absence of the underlying metric data, - // we don't worry about plotting the event. chartPoint.scheduledEvents = events; + // We do not want to create additional points for single metric charts + // as it could break the chart. + } else if (chartType !== CHART_TYPE.SINGLE_METRIC) { + // If there's no underlying metric data point for the scheduled event, + // create a new chart point with a value of 0. + const eventChartPoint: ChartPoint = { + date: Number(time), + value: 0, + entity: SCHEDULE_EVENT_MARKER_ENTITY, + scheduledEvents: events, + }; + chartData.push(eventChartPoint); } }); }