mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
* [ML] Listing all categorization wizard checks * fixing translation * changes based on review * moving check * adding real values to messages * reordering checks enum * fixing types * updating tests * updating id Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
c0f901798c
commit
d959d4883f
17 changed files with 167 additions and 48 deletions
80
x-pack/plugins/ml/common/constants/categorization_job.ts
Normal file
80
x-pack/plugins/ml/common/constants/categorization_job.ts
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { VALIDATION_RESULT } from '../types/categories';
|
||||
|
||||
export const NUMBER_OF_CATEGORY_EXAMPLES = 5;
|
||||
export const CATEGORY_EXAMPLES_SAMPLE_SIZE = 1000;
|
||||
export const CATEGORY_EXAMPLES_WARNING_LIMIT = 0.75;
|
||||
export const CATEGORY_EXAMPLES_ERROR_LIMIT = 0.02;
|
||||
|
||||
export const VALID_TOKEN_COUNT = 3;
|
||||
export const MEDIAN_LINE_LENGTH_LIMIT = 400;
|
||||
export const NULL_COUNT_PERCENT_LIMIT = 0.75;
|
||||
|
||||
export enum CATEGORY_EXAMPLES_VALIDATION_STATUS {
|
||||
VALID = 'valid',
|
||||
PARTIALLY_VALID = 'partially_valid',
|
||||
INVALID = 'invalid',
|
||||
}
|
||||
|
||||
export const VALIDATION_CHECK_DESCRIPTION = {
|
||||
[VALIDATION_RESULT.NO_EXAMPLES]: i18n.translate(
|
||||
'xpack.ml.models.jobService.categorization.messages.validNoDataFound',
|
||||
{
|
||||
defaultMessage: 'Examples were successfully loaded.',
|
||||
}
|
||||
),
|
||||
[VALIDATION_RESULT.FAILED_TO_TOKENIZE]: i18n.translate(
|
||||
'xpack.ml.models.jobService.categorization.messages.validFailureToGetTokens',
|
||||
{
|
||||
defaultMessage: 'The examples loaded were tokenized successfully.',
|
||||
}
|
||||
),
|
||||
[VALIDATION_RESULT.TOKEN_COUNT]: i18n.translate(
|
||||
'xpack.ml.models.jobService.categorization.messages.validTokenLength',
|
||||
{
|
||||
defaultMessage:
|
||||
'More than {tokenCount} tokens per example were found in over {percentage}% of the examples loaded.',
|
||||
values: {
|
||||
percentage: Math.floor(CATEGORY_EXAMPLES_WARNING_LIMIT * 100),
|
||||
tokenCount: VALID_TOKEN_COUNT,
|
||||
},
|
||||
}
|
||||
),
|
||||
[VALIDATION_RESULT.MEDIAN_LINE_LENGTH]: i18n.translate(
|
||||
'xpack.ml.models.jobService.categorization.messages.validMedianLineLength',
|
||||
{
|
||||
defaultMessage:
|
||||
'The median line length of the examples loaded was less than {medianCharCount} characters.',
|
||||
values: {
|
||||
medianCharCount: MEDIAN_LINE_LENGTH_LIMIT,
|
||||
},
|
||||
}
|
||||
),
|
||||
[VALIDATION_RESULT.NULL_VALUES]: i18n.translate(
|
||||
'xpack.ml.models.jobService.categorization.messages.validNullValues',
|
||||
{
|
||||
defaultMessage: 'Less than {percentage}% of the examples loaded were null.',
|
||||
values: {
|
||||
percentage: Math.floor(100 - NULL_COUNT_PERCENT_LIMIT * 100),
|
||||
},
|
||||
}
|
||||
),
|
||||
[VALIDATION_RESULT.TOO_MANY_TOKENS]: i18n.translate(
|
||||
'xpack.ml.models.jobService.categorization.messages.validTooManyTokens',
|
||||
{
|
||||
defaultMessage: 'Less than 10000 tokens were found in total in the examples loaded.',
|
||||
}
|
||||
),
|
||||
[VALIDATION_RESULT.INSUFFICIENT_PRIVILEGES]: i18n.translate(
|
||||
'xpack.ml.models.jobService.categorization.messages.validUserPrivileges',
|
||||
{
|
||||
defaultMessage: 'The user has sufficient privileges to perform the checks.',
|
||||
}
|
||||
),
|
||||
};
|
|
@ -25,15 +25,3 @@ export const DEFAULT_RARE_BUCKET_SPAN = '1h';
|
|||
export const DEFAULT_QUERY_DELAY = '60s';
|
||||
|
||||
export const SHARED_RESULTS_INDEX_NAME = 'shared';
|
||||
|
||||
// Categorization
|
||||
export const NUMBER_OF_CATEGORY_EXAMPLES = 5;
|
||||
export const CATEGORY_EXAMPLES_SAMPLE_SIZE = 1000;
|
||||
export const CATEGORY_EXAMPLES_WARNING_LIMIT = 0.75;
|
||||
export const CATEGORY_EXAMPLES_ERROR_LIMIT = 0.02;
|
||||
|
||||
export enum CATEGORY_EXAMPLES_VALIDATION_STATUS {
|
||||
VALID = 'valid',
|
||||
PARTIALLY_VALID = 'partially_valid',
|
||||
INVALID = 'invalid',
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../constants/new_job';
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../constants/categorization_job';
|
||||
|
||||
export type CategoryId = number;
|
||||
|
||||
|
@ -39,12 +39,12 @@ export interface CategoryFieldExample {
|
|||
}
|
||||
|
||||
export enum VALIDATION_RESULT {
|
||||
NO_EXAMPLES,
|
||||
FAILED_TO_TOKENIZE,
|
||||
TOO_MANY_TOKENS,
|
||||
TOKEN_COUNT,
|
||||
MEDIAN_LINE_LENGTH,
|
||||
NULL_VALUES,
|
||||
NO_EXAMPLES,
|
||||
TOO_MANY_TOKENS,
|
||||
FAILED_TO_TOKENIZE,
|
||||
INSUFFICIENT_PRIVILEGES,
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ import {
|
|||
CREATED_BY_LABEL,
|
||||
DEFAULT_BUCKET_SPAN,
|
||||
DEFAULT_RARE_BUCKET_SPAN,
|
||||
CATEGORY_EXAMPLES_VALIDATION_STATUS,
|
||||
} from '../../../../../../common/constants/new_job';
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../../../common/constants/categorization_job';
|
||||
import { ML_JOB_AGGREGATION } from '../../../../../../common/constants/aggregation_types';
|
||||
import {
|
||||
CategorizationAnalyzer,
|
||||
|
|
|
@ -16,7 +16,7 @@ import { JobCreator, JobCreatorType, isCategorizationJobCreator } from '../job_c
|
|||
import { populateValidationMessages, checkForExistingJobAndGroupIds } from './util';
|
||||
import { ExistingJobsAndGroups } from '../../../../services/job_service';
|
||||
import { cardinalityValidator, CardinalityValidatorResult } from './validators';
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../../../common/constants/new_job';
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../../../common/constants/categorization_job';
|
||||
|
||||
// delay start of validation to allow the user to make changes
|
||||
// e.g. if they are typing in a new value, try not to validate
|
||||
|
|
|
@ -11,7 +11,7 @@ import { ml } from '../../../../services/ml_api_service';
|
|||
import {
|
||||
NUMBER_OF_CATEGORY_EXAMPLES,
|
||||
CATEGORY_EXAMPLES_VALIDATION_STATUS,
|
||||
} from '../../../../../../common/constants/new_job';
|
||||
} from '../../../../../../common/constants/categorization_job';
|
||||
|
||||
export class CategorizationExamplesLoader {
|
||||
private _jobCreator: CategorizationJobCreator;
|
||||
|
|
|
@ -5,11 +5,17 @@
|
|||
*/
|
||||
|
||||
import React, { FC, Fragment } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiAccordion, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
|
||||
import { CalendarsSelection } from './components/calendars';
|
||||
import { CustomUrlsSelection } from './components/custom_urls';
|
||||
|
||||
const ButtonContent = <Fragment>Additional settings</Fragment>;
|
||||
const buttonContent = i18n.translate(
|
||||
'xpack.ml.newJob.wizard.jobDetailsStep.additionalSectionButton',
|
||||
{
|
||||
defaultMessage: 'Additional settings',
|
||||
}
|
||||
);
|
||||
|
||||
interface Props {
|
||||
additionalExpanded: boolean;
|
||||
|
@ -22,7 +28,7 @@ export const AdditionalSection: FC<Props> = ({ additionalExpanded, setAdditional
|
|||
<EuiSpacer />
|
||||
<EuiAccordion
|
||||
id="advanced-section"
|
||||
buttonContent={ButtonContent}
|
||||
buttonContent={buttonContent}
|
||||
onToggle={setAdditionalExpanded}
|
||||
initialIsOpen={additionalExpanded}
|
||||
data-test-subj="mlJobWizardToggleAdditionalSettingsSection"
|
||||
|
|
|
@ -19,7 +19,7 @@ import { ModelMemoryLimitInput } from '../../../common/model_memory_limit';
|
|||
import { JobCreatorContext } from '../../../job_creator_context';
|
||||
import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job';
|
||||
|
||||
const ButtonContent = i18n.translate(
|
||||
const buttonContent = i18n.translate(
|
||||
'xpack.ml.newJob.wizard.jobDetailsStep.advancedSectionButton',
|
||||
{
|
||||
defaultMessage: 'Advanced',
|
||||
|
@ -55,7 +55,7 @@ export const AdvancedSection: FC<Props> = ({ advancedExpanded, setAdvancedExpand
|
|||
<EuiSpacer size="xl" />
|
||||
<EuiAccordion
|
||||
id="advanced-section"
|
||||
buttonContent={ButtonContent}
|
||||
buttonContent={buttonContent}
|
||||
onToggle={setAdvancedExpanded}
|
||||
initialIsOpen={advancedExpanded}
|
||||
data-test-subj="mlJobWizardToggleAdvancedSection"
|
||||
|
|
|
@ -5,7 +5,14 @@
|
|||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
import { EuiCallOut, EuiSpacer, EuiCallOutProps } from '@elastic/eui';
|
||||
import {
|
||||
EuiCallOut,
|
||||
EuiSpacer,
|
||||
EuiCallOutProps,
|
||||
EuiAccordion,
|
||||
EuiListGroup,
|
||||
EuiListGroupItemProps,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
|
@ -14,7 +21,11 @@ import {
|
|||
FieldExampleCheck,
|
||||
} from '../../../../../../../../../common/types/categories';
|
||||
import { EditCategorizationAnalyzerFlyout } from '../../../common/edit_categorization_analyzer_flyout';
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../../../../../../common/constants/new_job';
|
||||
import {
|
||||
CATEGORY_EXAMPLES_VALIDATION_STATUS,
|
||||
VALIDATION_CHECK_DESCRIPTION,
|
||||
} from '../../../../../../../../../common/constants/categorization_job';
|
||||
import { VALIDATION_RESULT } from '../../../../../../../../../common/types/categories';
|
||||
|
||||
interface Props {
|
||||
validationChecks: FieldExampleCheck[];
|
||||
|
@ -22,6 +33,13 @@ interface Props {
|
|||
categorizationAnalyzer: CategorizationAnalyzer;
|
||||
}
|
||||
|
||||
const allChecksButtonContent = i18n.translate(
|
||||
'xpack.ml.newJob.wizard.jobDetailsStep.allChecksButton',
|
||||
{
|
||||
defaultMessage: 'View all checks performed',
|
||||
}
|
||||
);
|
||||
|
||||
export const ExamplesValidCallout: FC<Props> = ({
|
||||
overallValidStatus,
|
||||
validationChecks,
|
||||
|
@ -66,6 +84,10 @@ export const ExamplesValidCallout: FC<Props> = ({
|
|||
))}
|
||||
<EuiSpacer size="s" />
|
||||
{analyzerUsed}
|
||||
<EuiSpacer size="s" />
|
||||
<EuiAccordion id="all-checks" buttonContent={allChecksButtonContent}>
|
||||
<AllValidationChecks validationChecks={validationChecks} />
|
||||
</EuiAccordion>
|
||||
</EuiCallOut>
|
||||
);
|
||||
};
|
||||
|
@ -96,3 +118,28 @@ const AnalyzerUsed: FC<{ categorizationAnalyzer: CategorizationAnalyzer }> = ({
|
|||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const AllValidationChecks: FC<{ validationChecks: FieldExampleCheck[] }> = ({
|
||||
validationChecks,
|
||||
}) => {
|
||||
const list: EuiListGroupItemProps[] = Object.keys(VALIDATION_CHECK_DESCRIPTION).map((k, i) => {
|
||||
const failedCheck = validationChecks.find(vc => vc.id === i);
|
||||
if (
|
||||
failedCheck !== undefined &&
|
||||
failedCheck?.valid !== CATEGORY_EXAMPLES_VALIDATION_STATUS.VALID
|
||||
) {
|
||||
return {
|
||||
iconType: 'cross',
|
||||
label: failedCheck.message,
|
||||
size: 's',
|
||||
};
|
||||
}
|
||||
return {
|
||||
iconType: 'check',
|
||||
label: VALIDATION_CHECK_DESCRIPTION[i as VALIDATION_RESULT],
|
||||
size: 's',
|
||||
};
|
||||
});
|
||||
|
||||
return <EuiListGroup listItems={list} maxWidth={false} />;
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
CategoryFieldExample,
|
||||
FieldExampleCheck,
|
||||
} from '../../../../../../../../../common/types/categories';
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../../../../../../common/constants/new_job';
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../../../../../../common/constants/categorization_job';
|
||||
import { LoadingWrapper } from '../../../charts/loading_wrapper';
|
||||
|
||||
interface Props {
|
||||
|
|
|
@ -11,7 +11,7 @@ import { JobCreatorContext } from '../../../job_creator_context';
|
|||
import { CategorizationJobCreator } from '../../../../../common/job_creator';
|
||||
import { Results } from '../../../../../common/results_loader';
|
||||
import { ml } from '../../../../../../../services/ml_api_service';
|
||||
import { NUMBER_OF_CATEGORY_EXAMPLES } from '../../../../../../../../../common/constants/new_job';
|
||||
import { NUMBER_OF_CATEGORY_EXAMPLES } from '../../../../../../../../../common/constants/categorization_job';
|
||||
|
||||
export const TopCategories: FC = () => {
|
||||
const { jobCreator: jc, resultsLoader } = useContext(JobCreatorContext);
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
CategoryFieldExample,
|
||||
FieldExampleCheck,
|
||||
} from '../../../../common/types/categories';
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../common/constants/new_job';
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../common/constants/categorization_job';
|
||||
import { Category } from '../../../../common/types/categories';
|
||||
|
||||
export const jobs = {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { chunk } from 'lodash';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { CATEGORY_EXAMPLES_SAMPLE_SIZE } from '../../../../../common/constants/new_job';
|
||||
import { CATEGORY_EXAMPLES_SAMPLE_SIZE } from '../../../../../common/constants/categorization_job';
|
||||
import {
|
||||
Token,
|
||||
CategorizationAnalyzer,
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
VALID_TOKEN_COUNT,
|
||||
MEDIAN_LINE_LENGTH_LIMIT,
|
||||
NULL_COUNT_PERCENT_LIMIT,
|
||||
CATEGORY_EXAMPLES_VALIDATION_STATUS,
|
||||
CATEGORY_EXAMPLES_ERROR_LIMIT,
|
||||
CATEGORY_EXAMPLES_WARNING_LIMIT,
|
||||
} from '../../../../../common/constants/new_job';
|
||||
} from '../../../../../common/constants/categorization_job';
|
||||
import {
|
||||
FieldExampleCheck,
|
||||
CategoryFieldExample,
|
||||
|
@ -17,10 +20,6 @@ import {
|
|||
} from '../../../../../common/types/categories';
|
||||
import { getMedianStringLength } from '../../../../../common/util/string_utils';
|
||||
|
||||
const VALID_TOKEN_COUNT = 3;
|
||||
const MEDIAN_LINE_LENGTH_LIMIT = 400;
|
||||
const NULL_COUNT_PERCENT_LIMIT = 0.75;
|
||||
|
||||
export class ValidationResults {
|
||||
private _results: FieldExampleCheck[] = [];
|
||||
|
||||
|
@ -187,7 +186,6 @@ export class ValidationResults {
|
|||
valid: CATEGORY_EXAMPLES_VALIDATION_STATUS.PARTIALLY_VALID,
|
||||
message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
exampleLength: 5,
|
||||
validationChecks: [
|
||||
{
|
||||
id: 0,
|
||||
id: 3,
|
||||
valid: 'valid',
|
||||
message: '1000 field values analyzed, 95% contain 3 or more tokens.',
|
||||
},
|
||||
|
@ -117,12 +117,12 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
exampleLength: 5,
|
||||
validationChecks: [
|
||||
{
|
||||
id: 1,
|
||||
id: 4,
|
||||
valid: 'partially_valid',
|
||||
message: 'The median length for the field values analyzed is over 400 characters.',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
id: 2,
|
||||
valid: 'invalid',
|
||||
message:
|
||||
'Tokenization of field value examples has failed due to more than 10000 tokens being found in a sample of 50 values.',
|
||||
|
@ -144,12 +144,12 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
exampleLength: 5,
|
||||
validationChecks: [
|
||||
{
|
||||
id: 0,
|
||||
id: 3,
|
||||
valid: 'valid',
|
||||
message: '250 field values analyzed, 95% contain 3 or more tokens.',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
id: 5,
|
||||
valid: 'partially_valid',
|
||||
message: 'More than 75% of field values are null.',
|
||||
},
|
||||
|
@ -170,12 +170,12 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
exampleLength: 5,
|
||||
validationChecks: [
|
||||
{
|
||||
id: 0,
|
||||
id: 3,
|
||||
valid: 'valid',
|
||||
message: '500 field values analyzed, 100% contain 3 or more tokens.',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
id: 4,
|
||||
valid: 'partially_valid',
|
||||
message: 'The median length for the field values analyzed is over 400 characters.',
|
||||
},
|
||||
|
@ -196,7 +196,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
exampleLength: 0,
|
||||
validationChecks: [
|
||||
{
|
||||
id: 3,
|
||||
id: 0,
|
||||
valid: 'invalid',
|
||||
message:
|
||||
'No examples for this field could be found. Please ensure the selected date range contains data.',
|
||||
|
@ -218,7 +218,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
exampleLength: 5,
|
||||
validationChecks: [
|
||||
{
|
||||
id: 0,
|
||||
id: 3,
|
||||
valid: 'invalid',
|
||||
message: '1000 field values analyzed, 0% contain 3 or more tokens.',
|
||||
},
|
||||
|
@ -242,7 +242,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
exampleLength: 5,
|
||||
validationChecks: [
|
||||
{
|
||||
id: 0,
|
||||
id: 3,
|
||||
valid: 'valid',
|
||||
message: '1000 field values analyzed, 100% contain 3 or more tokens.',
|
||||
},
|
||||
|
@ -263,7 +263,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
exampleLength: 5,
|
||||
validationChecks: [
|
||||
{
|
||||
id: 0,
|
||||
id: 3,
|
||||
valid: 'partially_valid',
|
||||
message: '1000 field values analyzed, 50% contain 3 or more tokens.',
|
||||
},
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import expect from '@kbn/expect';
|
||||
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../../plugins/ml/common/constants/new_job';
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../../plugins/ml/common/constants/categorization_job';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function({ getService }: FtrProviderContext) {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import expect from '@kbn/expect';
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../plugins/ml/common/constants/new_job';
|
||||
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../plugins/ml/common/constants/categorization_job';
|
||||
|
||||
export function MachineLearningJobWizardCategorizationProvider({ getService }: FtrProviderContext) {
|
||||
const comboBox = getService('comboBox');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue