Skip to content

Commit 43d5ce5

Browse files
prevent creation if more than 2 distinct classes for class job. create form field validation file
1 parent 436f39a commit 43d5ce5

File tree

3 files changed

+59
-41
lines changed

3 files changed

+59
-41
lines changed

x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/create_analytics_form/create_analytics_form.tsx

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ import { i18n } from '@kbn/i18n';
2222
import { FormattedMessage } from '@kbn/i18n/react';
2323

2424
import { metadata } from 'ui/metadata';
25-
import { ES_FIELD_TYPES } from '../../../../../../../../../../../src/plugins/data/public';
2625
import { ml } from '../../../../../services/ml_api_service';
27-
import { Field, EVENT_RATE_FIELD_ID } from '../../../../../../../common/types/fields';
26+
import { Field } from '../../../../../../../common/types/fields';
2827
import { newJobCapsService } from '../../../../../services/new_job_capabilities_service';
2928
import { useKibanaContext } from '../../../../../contexts/kibana';
3029
import { CreateAnalyticsFormProps } from '../../hooks/use_create_analytics_form';
@@ -43,25 +42,7 @@ import {
4342
indexPatterns,
4443
} from '../../../../../../../../../../../src/plugins/data/public';
4544
import { DfAnalyticsExplainResponse, FieldSelectionItem } from '../../../../common/analytics';
46-
47-
const BASIC_NUMERICAL_TYPES = new Set([
48-
ES_FIELD_TYPES.LONG,
49-
ES_FIELD_TYPES.INTEGER,
50-
ES_FIELD_TYPES.SHORT,
51-
ES_FIELD_TYPES.BYTE,
52-
]);
53-
54-
const EXTENDED_NUMERICAL_TYPES = new Set([
55-
ES_FIELD_TYPES.DOUBLE,
56-
ES_FIELD_TYPES.FLOAT,
57-
ES_FIELD_TYPES.HALF_FLOAT,
58-
ES_FIELD_TYPES.SCALED_FLOAT,
59-
]);
60-
61-
const CATEGORICAL_TYPES = new Set(['ip', 'keyword', 'text']);
62-
63-
// List of system fields we want to ignore for the numeric field check.
64-
const OMIT_FIELDS: string[] = ['_source', '_type', '_index', '_id', '_version', '_score'];
45+
import { shouldAddAsDepVarOption, OMIT_FIELDS } from './form_options_validation';
6546

6647
export const CreateAnalyticsForm: FC<CreateAnalyticsFormProps> = ({ actions, state }) => {
6748
const { setFormState } = actions;
@@ -129,23 +110,6 @@ export const CreateAnalyticsForm: FC<CreateAnalyticsFormProps> = ({ actions, sta
129110
}
130111
};
131112

132-
// Regression supports numeric fields. Classification supports categorical, numeric, and boolean.
133-
const shouldAddAsDepVarOption = (field: Field) => {
134-
if (field.id === EVENT_RATE_FIELD_ID) return false;
135-
136-
const isBasicNumerical = BASIC_NUMERICAL_TYPES.has(field.type);
137-
138-
const isSupportedByClassification =
139-
isBasicNumerical ||
140-
CATEGORICAL_TYPES.has(field.type) ||
141-
field.type === ES_FIELD_TYPES.BOOLEAN;
142-
143-
if (jobType === JOB_TYPES.REGRESSION) {
144-
return isBasicNumerical || EXTENDED_NUMERICAL_TYPES.has(field.type);
145-
}
146-
if (jobType === JOB_TYPES.CLASSIFICATION) return isSupportedByClassification;
147-
};
148-
149113
const onCreateOption = (searchValue: string, flattenedOptions: EuiComboBoxOptionProps[]) => {
150114
const normalizedSearchValue = searchValue.trim().toLowerCase();
151115

@@ -159,7 +123,7 @@ export const CreateAnalyticsForm: FC<CreateAnalyticsFormProps> = ({ actions, sta
159123

160124
// Create the option if it doesn't exist.
161125
if (
162-
flattenedOptions.some(
126+
!flattenedOptions.some(
163127
(option: EuiComboBoxOptionProps) =>
164128
option.label.trim().toLowerCase() === normalizedSearchValue
165129
)
@@ -255,7 +219,7 @@ export const CreateAnalyticsForm: FC<CreateAnalyticsFormProps> = ({ actions, sta
255219
const depVarOptions: EuiComboBoxOptionProps[] = [];
256220

257221
fields.forEach((field: Field) => {
258-
if (shouldAddAsDepVarOption(field)) {
222+
if (shouldAddAsDepVarOption(field, jobType)) {
259223
depVarOptions.push({ label: field.id });
260224
}
261225
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { ES_FIELD_TYPES } from '../../../../../../../../../../../src/plugins/data/public';
8+
import { Field, EVENT_RATE_FIELD_ID } from '../../../../../../../common/types/fields';
9+
import { JOB_TYPES, AnalyticsJobType } from '../../hooks/use_create_analytics_form/state';
10+
11+
const BASIC_NUMERICAL_TYPES = new Set([
12+
ES_FIELD_TYPES.LONG,
13+
ES_FIELD_TYPES.INTEGER,
14+
ES_FIELD_TYPES.SHORT,
15+
ES_FIELD_TYPES.BYTE,
16+
]);
17+
18+
const EXTENDED_NUMERICAL_TYPES = new Set([
19+
ES_FIELD_TYPES.DOUBLE,
20+
ES_FIELD_TYPES.FLOAT,
21+
ES_FIELD_TYPES.HALF_FLOAT,
22+
ES_FIELD_TYPES.SCALED_FLOAT,
23+
]);
24+
25+
const CATEGORICAL_TYPES = new Set(['ip', 'keyword', 'text']);
26+
27+
// List of system fields we want to ignore for the numeric field check.
28+
export const OMIT_FIELDS: string[] = ['_source', '_type', '_index', '_id', '_version', '_score'];
29+
30+
// Regression supports numeric fields. Classification supports categorical, numeric, and boolean.
31+
export const shouldAddAsDepVarOption = (field: Field, jobType: AnalyticsJobType) => {
32+
if (field.id === EVENT_RATE_FIELD_ID) return false;
33+
34+
const isBasicNumerical = BASIC_NUMERICAL_TYPES.has(field.type);
35+
36+
const isSupportedByClassification =
37+
isBasicNumerical || CATEGORICAL_TYPES.has(field.type) || field.type === ES_FIELD_TYPES.BOOLEAN;
38+
39+
if (jobType === JOB_TYPES.REGRESSION) {
40+
return isBasicNumerical || EXTENDED_NUMERICAL_TYPES.has(field.type);
41+
}
42+
if (jobType === JOB_TYPES.CLASSIFICATION) return isSupportedByClassification;
43+
};

x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,15 @@ const getSourceIndexString = (state: State) => {
5454
};
5555

5656
export const validateAdvancedEditor = (state: State): State => {
57-
const { jobIdEmpty, jobIdValid, jobIdExists, jobType, createIndexPattern, excludes } = state.form;
57+
const {
58+
jobIdEmpty,
59+
jobIdValid,
60+
jobIdExists,
61+
jobType,
62+
createIndexPattern,
63+
excludes,
64+
maxDistinctValuesError,
65+
} = state.form;
5866
const { jobConfig } = state;
5967

6068
state.advancedEditorMessages = [];
@@ -197,6 +205,7 @@ export const validateAdvancedEditor = (state: State): State => {
197205
}
198206

199207
state.isValid =
208+
maxDistinctValuesError === undefined &&
200209
excludesValid &&
201210
state.form.modelMemoryLimitUnitValid &&
202211
!jobIdEmpty &&
@@ -226,6 +235,7 @@ const validateForm = (state: State): State => {
226235
destinationIndexPatternTitleExists,
227236
createIndexPattern,
228237
dependentVariable,
238+
maxDistinctValuesError,
229239
modelMemoryLimit,
230240
} = state.form;
231241

@@ -241,6 +251,7 @@ const validateForm = (state: State): State => {
241251
}
242252

243253
state.isValid =
254+
maxDistinctValuesError === undefined &&
244255
!jobTypeEmpty &&
245256
state.form.modelMemoryLimitUnitValid &&
246257
!jobIdEmpty &&

0 commit comments

Comments
 (0)