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] Add option for anomaly charts for metric detector should plot min, mean or max as appropriate #81662

Merged
merged 28 commits into from
Nov 9, 2020

Conversation

qn895
Copy link
Member

@qn895 qn895 commented Oct 26, 2020

Summary

This PR addresses #65078 by:

  1. Plot the function associated with the record with the highest anomaly high score in the Single Metric Viewer and Anomaly Explorer by default.
    ae_metric_previews
    smv_metric_preview_1

  2. Add additional select options so users can choose what function want to view by (e.g. avg, min, or max) where the anomaly markers will only show up if they correspond to the right view.
    smv_metric_preview_2

Checklist

Delete any items that are not applicable to this PR.

@qn895 qn895 self-assigned this Oct 26, 2020
@qn895 qn895 added the Feature:Anomaly Detection ML anomaly detection label Oct 27, 2020
@qn895 qn895 marked this pull request as ready for review October 27, 2020 13:26
@qn895 qn895 requested a review from a team as a code owner October 27, 2020 13:26
@elasticmachine
Copy link
Contributor

Pinging @elastic/ml-ui (:ml)

@peteharverson
Copy link
Contributor

As discussed, if feasible, I think it makes sense to filter the table and mini swim lane anomalies for the detector function (min / avg / max) as well as the main chart. That way the view shows information for the single series (detector, partitioning fields, function) being viewed.

image

mustCriteria.push({
term: {
function_description:
actualPlotFunctionIfMetric === 'avg' ? 'mean' : actualPlotFunctionIfMetric,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use the enums out of common/constants/aggregation_types here?

if (actualPlotFunction !== undefined) {
boolCriteria.push({
term: {
function_description: actualPlotFunction === 'avg' ? 'mean' : actualPlotFunction,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use the enums out of common/constants/aggregation_types here?

@@ -57,7 +57,8 @@ export function resultsServiceProvider(client: IScopedClusterClient) {
dateFormatTz: string,
maxRecords: number = ANOMALIES_TABLE_DEFAULT_QUERY_SIZE,
maxExamples: number = DEFAULT_MAX_EXAMPLES,
influencersFilterQuery: any
influencersFilterQuery?: any,
actualPlotFunction?: string | undefined
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be renamed to functionDescription to match the name of the property in the records?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here cb2429e

@@ -37,6 +37,7 @@ function getAnomaliesTableData(client: IScopedClusterClient, payload: any) {
maxRecords,
maxExamples,
influencersFilterQuery,
actualPlotFunction,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As before, maybe this should be renamed to functionDescription to match the name of the property in the records?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here cb2429e

@@ -26,6 +26,7 @@ export const anomaliesTableDataSchema = schema.object({
maxRecords: schema.number(),
maxExamples: schema.maybe(schema.number()),
influencersFilterQuery: schema.maybe(schema.any()),
actualPlotFunction: schema.maybe(schema.nullable(schema.string())),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, maybe this should be renamed to functionDescription to match the name of the property in the records?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here cb2429e

influencersFilterQuery: any
maxExamples?: number,
influencersFilterQuery?: any,
actualPlotFunction?: string | undefined
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be renamed to functionDescription to match the name of the property in the records?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here cb2429e

@peteharverson
Copy link
Contributor

Coming into the view from the jobs list, I see the function dropdown disappear after selecting a partitioning field:

metric_chart_control_bug

@peteharverson
Copy link
Contributor

Noticed some odd behavior in the chart when using the metric function, which is happening here and also on master. For these anomalies which are in min, the chart data seems to be plotted always with avg. Here the anomaly should be plotted with a value of 53.6:

image

  "analysis_config": {
    "bucket_span": "15m",
    "detectors": [
      {
        "detector_description": "metric(responsetime) partitionfield=airline",
        "function": "metric",
        "field_name": "responsetime",
        "partition_field_name": "airline",
        "detector_index": 0
      }
    ],
    "influencers": [
      "airline"
    ]
  },
  "analysis_limits": {
    "model_memory_limit": "13mb",
    "categorization_examples_limit": 4
  },
  "data_description": {
    "time_field": "@timestamp",
    "time_format": "epoch_ms"
  },
  "model_plot_config": {
    "enabled": true,
    "annotations_enabled": true
  },

@qn895
Copy link
Member Author

qn895 commented Nov 3, 2020

Coming into the view from the jobs list, I see the function dropdown disappear after selecting a partitioning field

@peteharverson I have added a fix for this issue. The dropdown should now work with or without the partitioning and should be updated.

Noticed some odd behavior in the chart when using the metric function, which is happening here and also on master. For these anomalies which are in min, the chart data seems to be plotted always with avg.

I also added a fix for this one in ea8d71f. Now, when model plot is enabled, it will 1) get the anomaly records based on the selected function description, and 2) plot the chart point with the actual data point.

Screen Shot 2020-11-03 at 14 15 08

Screen Shot 2020-11-03 at 14 15 16

}) => {
if (functionDescription === undefined) return null;
return (
<EuiFlexItem style={{ textAlign: 'right' }} grow={false}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to avoid inline styles, you can use EuiText with textAlign prop

Copy link
Member Author

@qn895 qn895 Nov 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized this style wasn't necessary so I removed it here a7e2482

@peteharverson
Copy link
Contributor

peteharverson commented Nov 4, 2020

Found what looks like an issue with setting the bounds on the focus chart:

image

Config is:

 "analysis_config": {
    "bucket_span": "15m",
    "detectors": [
      {
        "detector_description": "metric(responsetime) partitionfield=airline",
        "function": "metric",
        "field_name": "responsetime",
        "partition_field_name": "airline",
        "detector_index": 0
      }
    ],
    "influencers": [
      "airline"
    ]
  },

Same job - the bounds on the main chart aren't set correctly, and also the critical anomaly isn't marked in the swim lane.

image

Same config, but with model plot enabled - again the critical anomalies don't show up in the swim lane:
image

@qn895
Copy link
Member Author

qn895 commented Nov 4, 2020

@peteharverson I have fixed the two issues in my latest changes. The bounds should be now correct, and the mini swimlanes should should up correctly for when function = mean as well.

Screen Shot 2020-11-04 at 11 13 53

Screen Shot 2020-11-04 at 11 14 01

Copy link
Contributor

@walterra walterra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some questions, one is about risk of render looks or race conditions.

influencersFilterQuery: any
maxExamples?: number,
influencersFilterQuery?: any,
functionDescription?: string | undefined
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to remove | undefined because of the ?.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here 64ecedb

import { EuiFlexItem, EuiFormRow, EuiSelect } from '@elastic/eui';
import { i18n } from '@kbn/i18n';

const plotByFunctionOptions = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to translate these since they relate to Elasticsearch aggregations?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these are not strict terms that are excluded in the translation guide, I'll keep these translations here.

Comment on lines 399 to 401
if (currentSelectedJob === undefined) {
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this check is no longer necessary?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching that. This was removed by accident. I have revert the change in 64ecedb

previousProps.selectedDetectorIndex !== this.props.selectedDetectorIndex ||
!isEqual(previousProps.selectedEntities, this.props.selectedEntities)
) {
this.getFunctionDescription();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we run into problems with a race condition since this is async function?
(Just trying to understand the implications here, since previously only relying on a change previousProps did make sure we check against from changes coming from outside the components - wondering if with including perviousState and then again triggering async state functions if we might run into render loops)

Copy link
Contributor

@peteharverson peteharverson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested latest edits and LGTM.
Just left some minor comments on the code.

earliestMs: number | null,
latestMs: number | null,
maxResults: number | undefined,
functionDescription?: string | undefined
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, you should be able to remove | undefined because of the ?.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here 64ecedb

@@ -48,6 +49,10 @@ export function buildConfig(record) {
// define the metric series to be plotted.
config.entityFields = getEntityFieldList(record);

if (record.function === 'metric') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use ML_JOB_AGGREGATION.METRIC from common/constants/aggregation_types

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here 64ecedb

@@ -142,6 +143,8 @@ export function processDataForFocusAnomalies(
// Look for a chart point with the same time as the record.
// If none found, find closest time in chartData set.
const recordTime = record[TIME_FIELD_NAME];
if (record.function === 'metric' && record.function_description !== functionDescription) return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use ML_JOB_AGGREGATION.METRIC from common/constants/aggregation_types

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here 64ecedb

@@ -160,6 +163,10 @@ export function processDataForFocusAnomalies(
chartPoint.value = record.actual;
}

if (record.function === 'metric') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use ML_JOB_AGGREGATION.METRIC from common/constants/aggregation_types

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here 64ecedb

) => {
// if the detector's function is metric, fetch the highest scoring anomaly record
// and set to plot the function_description (avg/min/max) of that record by default
if (selectedJob?.analysis_config?.detectors[selectedDetectorIndex]?.function !== 'metric') return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use ML_JOB_AGGREGATION.METRIC from common/constants/aggregation_types

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here 64ecedb

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

@kbn/optimizer bundle module count

id before after diff
ml 1238 1242 +4

async chunks size

id before after diff
ml 6.6MB 6.7MB +17.3KB

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

Copy link
Contributor

@darnautov darnautov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@walterra walterra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, we can think of ways to improve componentDidUpdate() in the single metric viewer component in a follow up.

@qn895 qn895 merged commit 9c984f4 into elastic:master Nov 9, 2020
@qn895 qn895 deleted the ml-metric-plotting branch November 9, 2020 16:41
qn895 added a commit to qn895/kibana that referenced this pull request Nov 9, 2020
qn895 added a commit that referenced this pull request Nov 9, 2020
gmmorris added a commit to gmmorris/kibana that referenced this pull request Nov 10, 2020
* master: (39 commits)
  Fix ilm navigation (elastic#81664)
  [Lens] Distinct icons for XY and pie chart value labels toolbar (elastic#82927)
  [data.search.aggs] Throw an error when trying to create an agg type that doesn't exist. (elastic#81509)
  Index patterns api - load field list on server (elastic#82629)
  New events resolver (elastic#82170)
  [App Search] Misc naming tech debt (elastic#82770)
  load empty_kibana in test to have clean starting point (elastic#82772)
  Remove data <--> expressions circular dependencies. (elastic#82685)
  Update 8.0 breaking change template to gather information on how to programmatically detect it. (elastic#82905)
  Add alerting as codeowners to related documentation folder (elastic#82777)
  Add captions to user and space grid pages (elastic#82713)
  add alternate path for x-pack/Cloud test for Lens (elastic#82634)
  Uses asCurrentUser in getClusterUuid (elastic#82908)
  [Alerting][Connectors] Add new executor subaction to get 3rd party case fields (elastic#82519)
  Fix test import objects (elastic#82767)
  [ML] Add option for anomaly charts for metric detector should plot min, mean or max as appropriate (elastic#81662)
  Update alert type selection layout to rows instead of grid (elastic#73665)
  Prevent Kerberos and PKI providers from initiating a new session for unauthenticated XHR/API requests. (elastic#82817)
  Update grunt and related packages (elastic#79327)
  Allow the repository to search across all namespaces (elastic#82863)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants