diff --git a/x-pack/plugins/ml/common/util/job_utils.js b/x-pack/plugins/ml/common/util/job_utils.js index 59e9273b236a8..85a1bfc6d9042 100644 --- a/x-pack/plugins/ml/common/util/job_utils.js +++ b/x-pack/plugins/ml/common/util/job_utils.js @@ -350,7 +350,10 @@ export function basicJobValidation(job, fields, limits) { messages.push({ id: 'bucket_span_invalid' }); valid = false; } else { - messages.push({ id: 'bucket_span_valid' }); + messages.push({ + id: 'bucket_span_valid', + bucketSpan: job.analysis_config.bucket_span + }); } } diff --git a/x-pack/plugins/ml/public/components/validate_job/__snapshots__/validate_job_view.test.js.snap b/x-pack/plugins/ml/public/components/validate_job/__snapshots__/validate_job_view.test.js.snap index 485d4a5530342..50ea6c2fc67e5 100644 --- a/x-pack/plugins/ml/public/components/validate_job/__snapshots__/validate_job_view.test.js.snap +++ b/x-pack/plugins/ml/public/components/validate_job/__snapshots__/validate_job_view.test.js.snap @@ -31,6 +31,25 @@ exports[`ValidateJob renders button and modal with a message 1`] = ` } } /> + + Job validation performs certain checks against job configurations and underlying source data and provides specific advice on how to adjust settings that are more likely to produce insightful results. + + + For more information, see + + Machine Learning Job Tips + + . + `; @@ -71,6 +90,26 @@ exports[`ValidateJob renders the button and modal with a success message 1`] = ` + > + + Job validation performs certain checks against job configurations and underlying source data and provides specific advice on how to adjust settings that are more likely to produce insightful results. + + + For more information, see + + Machine Learning Job Tips + + . + + `; diff --git a/x-pack/plugins/ml/public/components/validate_job/validate_job_view.js b/x-pack/plugins/ml/public/components/validate_job/validate_job_view.js index ddd37a5246b72..adfd66bdd7722 100644 --- a/x-pack/plugins/ml/public/components/validate_job/validate_job_view.js +++ b/x-pack/plugins/ml/public/components/validate_job/validate_job_view.js @@ -23,9 +23,14 @@ import { EuiModalHeader, EuiModalHeaderTitle, EuiOverlayMask, - EuiSpacer + EuiSpacer, + EuiText } from '@elastic/eui'; +import { metadata } from 'ui/metadata'; +// metadata.branch corresponds to the version used in documentation links. +const jobTipsUrl = `https://www.elastic.co/guide/en/kibana/${metadata.branch}/job-tips.html`; + // don't use something like plugins/ml/../common // because it won't work with the jest tests import { VALIDATION_STATUS } from '../../../common/constants/validation'; @@ -101,9 +106,11 @@ const Callout = ({ message }) => ( } + title={message.heading || } iconType={statusToEuiIconType(message.status)} - /> + > + {message.heading && } + ); @@ -212,7 +219,6 @@ class ValidateJob extends Component { const isCurrentJobConfig = (this.props.isCurrentJobConfig !== true) ? false : true; const isDisabled = (this.props.isDisabled !== true) ? false : true; - return (
)} + + Job validation performs certain checks against job configurations and underlying source data + and provides specific advice on how to adjust settings that are more likely to produce insightful results. + + + For more information, see Machine Learning Job Tips. + }
diff --git a/x-pack/plugins/ml/server/models/job_validation/job_validation.js b/x-pack/plugins/ml/server/models/job_validation/job_validation.js index c148ffb81ffae..524370b65c711 100644 --- a/x-pack/plugins/ml/server/models/job_validation/job_validation.js +++ b/x-pack/plugins/ml/server/models/job_validation/job_validation.js @@ -104,6 +104,9 @@ export async function validateJob(callWithRequest, payload, kbnVersion = 'curren return uniqWithIsEqual(validationMessages).map(message => { if (typeof messages[message.id] !== 'undefined') { // render the message template with the provided metadata + if (typeof messages[message.id].heading !== 'undefined') { + message.heading = renderTemplate(messages[message.id].heading, message); + } message.text = renderTemplate(messages[message.id].text, message); // check if the error message provides a link with further information // if so, add it to the message to be returned with it diff --git a/x-pack/plugins/ml/server/models/job_validation/messages.json b/x-pack/plugins/ml/server/models/job_validation/messages.json index 7f3fec66ffcc0..dfb33592c84ba 100644 --- a/x-pack/plugins/ml/server/models/job_validation/messages.json +++ b/x-pack/plugins/ml/server/models/job_validation/messages.json @@ -35,7 +35,8 @@ }, "categorization_filters_valid": { "status": "SUCCESS", - "text": "Categorization filters" + "text": "Categorization filters checks passed.", + "url": "https://www.elastic.co/guide/en/x-pack/{{version}}/ml-configuring-categories.html#ml-configuring-categories" }, "categorization_filters_invalid": { "status": "ERROR", @@ -43,41 +44,53 @@ }, "bucket_span_empty": { "status": "ERROR", - "text": "The bucket span field must be specified." + "text": "The bucket span field must be specified.", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/{{version}}/ml-job-resource.html#ml-analysisconfig" }, "bucket_span_estimation_mismatch": { "status": "INFO", + "heading": "Bucket span", "text": "Current bucket span is \"{{currentBucketSpan}}\", but bucket span estimation returned \"{{estimateBucketSpan}}\".", "url": "https://www.elastic.co/guide/en/kibana/{{version}}/job-tips.html#bucket-span" }, "bucket_span_high": { "status": "INFO", + "heading": "Bucket span", "text": "Bucket span is 1 day or more. Be aware that days are considered as UTC days, not local days.", "url": "https://www.elastic.co/guide/en/kibana/{{version}}/job-tips.html#bucket-span" }, "bucket_span_valid": { "status": "SUCCESS", - "text": "Bucket span format" + "heading": "Bucket span", + "text": "Format of \"{{bucketSpan}}\" is valid.", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/{{version}}/ml-job-resource.html#ml-analysisconfig" }, "bucket_span_invalid": { "status": "ERROR", - "text": "The specified bucket span is not a valid time interval format e.g. 10m, 1h. It also needs to be higher than zero." + "heading": "Bucket span", + "text": "The specified bucket span is not a valid time interval format e.g. 10m, 1h. It also needs to be higher than zero.", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/{{version}}/ml-job-resource.html#ml-analysisconfig" }, "detectors_duplicates": { "status": "ERROR", - "text": "Duplicate detectors were found. Detectors having the same combined configuration for 'function', 'field_name', 'by_field_name', 'over_field_name' and 'partition_field_name' are not allowed within the same job." + "text": "Duplicate detectors were found. Detectors having the same combined configuration for 'function', 'field_name', 'by_field_name', 'over_field_name' and 'partition_field_name' are not allowed within the same job.", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/{{version}}/ml-job-resource.html#ml-detectorconfig" }, "detectors_empty": { "status": "ERROR", - "text": "No detectors were found. At least one detector must be specified." + "text": "No detectors were found. At least one detector must be specified.", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/{{version}}/ml-job-resource.html#ml-detectorconfig" }, "detectors_function_empty": { "status": "ERROR", - "text": "One of the detector functions is empty." + "text": "One of the detector functions is empty.", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/{{version}}/ml-job-resource.html#ml-detectorconfig" }, "detectors_function_not_empty": { "status": "SUCCESS", - "text": "Detector functions format" + "heading": "Dectector functions", + "text": "Presence of detector functions validated in all detectors.", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/{{version}}/ml-job-resource.html#ml-detectorconfig" }, "index_fields_invalid": { "status": "ERROR", @@ -85,7 +98,7 @@ }, "index_fields_valid": { "status": "SUCCESS", - "text": "Index fields" + "text": "Index fields are present in the datafeed." }, "influencer_high": { "status": "WARNING", @@ -109,39 +122,51 @@ }, "job_id_empty": { "status": "ERROR", - "text": "The job name field must not be empty." + "text": "The job name field must not be empty.", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/{{version}}/ml-job-resource.html#ml-job-resource" }, "job_id_invalid": { "status": "ERROR", - "text": "The job name is invalid. It can contain lowercase alphanumeric (a-z and 0-9) characters, hyphens or underscores and must start and end with an alphanumeric character." + "text": "The job name is invalid. It can contain lowercase alphanumeric (a-z and 0-9) characters, hyphens or underscores and must start and end with an alphanumeric character.", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/{{version}}/ml-job-resource.html#ml-job-resource" }, "job_id_valid": { "status": "SUCCESS", - "text": "Job id" + "heading": "Job id format is valid.", + "text": "Lowercase alphanumeric (a-z and 0-9) characters, hyphens or underscores, starts and ends with an alphanumeric character.", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/{{version}}/ml-job-resource.html#ml-job-resource" }, "job_group_id_invalid": { "status": "ERROR", - "text": "One of the job group names is invalid. They can contain lowercase alphanumeric (a-z and 0-9) characters, hyphens or underscores and must start and end with an alphanumeric character." + "text": "One of the job group names is invalid. They can contain lowercase alphanumeric (a-z and 0-9) characters, hyphens or underscores and must start and end with an alphanumeric character.", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/{{version}}/ml-job-resource.html#ml-job-resource" }, "job_group_id_valid": { "status": "SUCCESS", - "text": "Job group ids" + "heading": "Job group id formats are valid.", + "text": "Lowercase alphanumeric (a-z and 0-9) characters, hyphens or underscores, starts and ends with an alphanumeric character.", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/{{version}}/ml-job-resource.html#ml-job-resource" }, "skipped_extended_tests": { "status": "WARNING", - "text": "Skipped some checks because the basic requirements of the job configuration were not met." + "text": "Skipped additional checks because the basic requirements of the job configuration were not met." }, "success_cardinality": { "status": "SUCCESS", - "text": "Cardinality" + "heading": "Cardinality", + "text": "Cardinality of detector fields is within recommended bounds.", + "url": "https://www.elastic.co/guide/en/kibana/{{version}}/job-tips.html#cardinality" }, "success_bucket_span": { "status": "SUCCESS", - "text": "Bucket span" + "heading": "Bucket span", + "text": "Format of \"{{bucketSpan}}\" is valid and passed validation checks.", + "url": "https://www.elastic.co/guide/en/kibana/{{version}}/job-tips.html#bucket-span" }, "success_influencers": { "status": "SUCCESS", - "text": "Influencers" + "text": "Influencer configuration passed the validation checks.", + "url": "https://www.elastic.co/guide/en/kibana/{{version}}/job-tips.html#influencers" }, "estimated_mml_greater_than_max_mml": { "status": "WARNING", @@ -161,11 +186,14 @@ }, "success_mml": { "status": "SUCCESS", - "text": "Model memory limit" + "heading": "Model memory limit", + "text": "Valid and within the estimated model memory limit.", + "url": "https://www.elastic.co/guide/en/x-pack/{{version}}/ml-gs-job1-manage.html#ml-gs-job1-manage" }, "success_time_range": { "status": "SUCCESS", - "text": "Time range" + "heading": "Time range", + "text": "Valid and long enough to model patterns in the data." }, "time_field_invalid": { "status": "ERROR", @@ -173,10 +201,12 @@ }, "time_range_short": { "status": "WARNING", + "heading": "Time range", "text": "The selected or available time range might be too short. The recommended minimum time range should be at least {{minTimeSpanReadable}} and {{bucketSpanCompareFactor}} times the bucket span." }, "time_range_before_epoch": { "status": "WARNING", + "heading": "Time range", "text": "The selected or available time range contains data with timestamps before the UNIX epoch beginning. Timestamps before 01/01/1970 00:00:00 (UTC) are not supported for machine learning jobs." } } diff --git a/x-pack/plugins/ml/server/models/job_validation/validate_bucket_span.js b/x-pack/plugins/ml/server/models/job_validation/validate_bucket_span.js index 8e74005d43fd4..fe7fdf991233a 100644 --- a/x-pack/plugins/ml/server/models/job_validation/validate_bucket_span.js +++ b/x-pack/plugins/ml/server/models/job_validation/validate_bucket_span.js @@ -72,7 +72,10 @@ export async function validateBucketSpan(callWithRequest, job, duration) { if (SKIP_BUCKET_SPAN_ESTIMATION) { if (messages.length === 0) { - messages.push({ id: 'success_bucket_span' }); + messages.push({ + id: 'success_bucket_span', + bucketSpan: job.analysis_config.bucket_span + }); } return messages; } @@ -151,7 +154,10 @@ export async function validateBucketSpan(callWithRequest, job, duration) { } if (messages.length === 0) { - messages.push({ id: 'success_bucket_span' }); + messages.push({ + id: 'success_bucket_span', + bucketSpan: job.analysis_config.bucket_span + }); } return messages;