Skip to content

Commit

Permalink
[ML] More helpful job validation success messages. (#21079)
Browse files Browse the repository at this point in the history
This provides more helpful texts for job validation success messages. Previously only a list of checks was shown to the user without any further explanation. This PR addresses this issue in the following way:
- At the bottom of the modal an introductory brief text about job validation including a link to documentation is inserted.
- The success messages in the list now provide a more helpful text including (where applicable) a deep link to documentation
- The messages now support a richer Callout layout including a header and additional text.
  • Loading branch information
walterra authored Jul 23, 2018
1 parent 7f57bf3 commit e05b668
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 28 deletions.
5 changes: 4 additions & 1 deletion x-pack/plugins/ml/common/util/job_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
});
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,25 @@ exports[`ValidateJob renders button and modal with a message 1`] = `
}
}
/>
<EuiText
grow={true}
>
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.
</EuiText>
<EuiText
grow={true}
>
For more information, see
<EuiLink
color="primary"
href="https://www.elastic.co/guide/en/kibana/my-metadata-branch/job-tips.html"
target="_blank"
type="button"
>
Machine Learning Job Tips
</EuiLink>
.
</EuiText>
</Modal>
</div>
`;
Expand Down Expand Up @@ -71,6 +90,26 @@ exports[`ValidateJob renders the button and modal with a success message 1`] = `
<Modal
close={[Function]}
title="Validate job test-id"
/>
>
<EuiText
grow={true}
>
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.
</EuiText>
<EuiText
grow={true}
>
For more information, see
<EuiLink
color="primary"
href="https://www.elastic.co/guide/en/kibana/my-metadata-branch/job-tips.html"
target="_blank"
type="button"
>
Machine Learning Job Tips
</EuiLink>
.
</EuiText>
</Modal>
</div>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -101,9 +106,11 @@ const Callout = ({ message }) => (
<EuiCallOut
color={statusToEuiColor(message.status)}
size="s"
title={<Message message={message} />}
title={message.heading || <Message message={message} />}
iconType={statusToEuiIconType(message.status)}
/>
>
{message.heading && <Message message={message} />}
</EuiCallOut>
<EuiSpacer size="m" />
</React.Fragment>
);
Expand Down Expand Up @@ -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 (
<div>
<EuiButton
Expand All @@ -235,6 +241,13 @@ class ValidateJob extends Component {
{this.state.data.messages.map(
(m, i) => <Callout key={`${m.id}_${i}`} message={m} />
)}
<EuiText>
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.
</EuiText>
<EuiText>
For more information, see <EuiLink href={jobTipsUrl} target="_blank">Machine Learning Job Tips</EuiLink>.
</EuiText>
</Modal>
}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 50 additions & 20 deletions x-pack/plugins/ml/server/models/job_validation/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,57 +35,70 @@
},
"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",
"text": "The categorization filters are invalid."
},
"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",
"text": "Could not load fields from index."
},
"index_fields_valid": {
"status": "SUCCESS",
"text": "Index fields"
"text": "Index fields are present in the datafeed."
},
"influencer_high": {
"status": "WARNING",
Expand All @@ -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",
Expand All @@ -161,22 +186,27 @@
},
"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",
"text": "'{{timeField}}' cannot be used as the time-field because it's not a valid field of type 'date'."
},
"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."
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit e05b668

Please sign in to comment.