Skip to content

Commit eb56bfe

Browse files
[ML] DF Analytics Regression exploration: replace table with data grid (#63650) (#63739)
* add feature_importance column correctly * wip: switch regression table to datagrid * add search bar to regression view * ensure feature importance fields show up correctly * wip: filter by training/testing * remove separate testing/training filter * make error more clear * handle lucene queries * remove unnecessary comment * ensure boolean shows up correctly.no sorting by feature importance * remove unused translations
1 parent 5a88920 commit eb56bfe

File tree

9 files changed

+549
-602
lines changed

9 files changed

+549
-602
lines changed

x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { ml } from '../../services/ml_api_service';
1313
import { Dictionary } from '../../../../common/types/common';
1414
import { getErrorMessage } from '../../../../common/util/errors';
1515
import { SavedSearchQuery } from '../../contexts/ml';
16-
import { SortDirection } from '../../components/ml_in_memory_table';
1716

1817
export type IndexName = string;
1918
export type IndexPattern = string;
@@ -53,13 +52,9 @@ export interface ClassificationAnalysis {
5352
classification: Classification;
5453
}
5554

56-
export interface LoadExploreDataArg {
57-
field: string;
58-
direction: SortDirection;
55+
export interface LoadRegressionExploreDataArg {
56+
filterByIsTraining?: boolean;
5957
searchQuery: SavedSearchQuery;
60-
requiresKeyword?: boolean;
61-
pageIndex?: number;
62-
pageSize?: number;
6358
}
6459

6560
export const SEARCH_SIZE = 1000;
@@ -272,6 +267,11 @@ export const isResultsSearchBoolQuery = (arg: any): arg is ResultsSearchBoolQuer
272267
return keys.length === 1 && keys[0] === 'bool';
273268
};
274269

270+
export const isQueryStringQuery = (arg: any): arg is QueryStringQuery => {
271+
const keys = Object.keys(arg);
272+
return keys.length === 1 && keys[0] === 'query_string';
273+
};
274+
275275
export const isRegressionEvaluateResponse = (arg: any): arg is RegressionEvaluateResponse => {
276276
const keys = Object.keys(arg);
277277
return (
@@ -396,6 +396,10 @@ interface ResultsSearchTermQuery {
396396
term: Dictionary<any>;
397397
}
398398

399+
interface QueryStringQuery {
400+
query_string: Dictionary<any>;
401+
}
402+
399403
export type ResultsSearchQuery = ResultsSearchBoolQuery | ResultsSearchTermQuery | SavedSearchQuery;
400404

401405
export function getEvalQueryBody({
@@ -409,16 +413,34 @@ export function getEvalQueryBody({
409413
searchQuery?: ResultsSearchQuery;
410414
ignoreDefaultQuery?: boolean;
411415
}) {
412-
let query: ResultsSearchQuery = {
416+
let query;
417+
418+
const trainingQuery: ResultsSearchQuery = {
413419
term: { [`${resultsField}.is_training`]: { value: isTraining } },
414420
};
415421

416-
if (searchQuery !== undefined && ignoreDefaultQuery === true) {
417-
query = searchQuery;
418-
} else if (searchQuery !== undefined && isResultsSearchBoolQuery(searchQuery)) {
419-
const searchQueryClone = cloneDeep(searchQuery);
420-
searchQueryClone.bool.must.push(query);
422+
const searchQueryClone = cloneDeep(searchQuery);
423+
424+
if (isResultsSearchBoolQuery(searchQueryClone)) {
425+
if (searchQueryClone.bool.must === undefined) {
426+
searchQueryClone.bool.must = [];
427+
}
428+
429+
searchQueryClone.bool.must.push(trainingQuery);
421430
query = searchQueryClone;
431+
} else if (isQueryStringQuery(searchQueryClone)) {
432+
query = {
433+
bool: {
434+
must: [searchQueryClone, trainingQuery],
435+
},
436+
};
437+
} else {
438+
// Not a bool or string query so we need to create it so can add the trainingQuery
439+
query = {
440+
bool: {
441+
must: [trainingQuery],
442+
},
443+
};
422444
}
423445
return query;
424446
}

x-pack/plugins/ml/public/application/data_frame_analytics/common/fields.ts

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,15 @@ export const getDefaultFieldsFromJobCaps = (
246246
fields: Field[],
247247
jobConfig: DataFrameAnalyticsConfig,
248248
needsDestIndexFields: boolean
249-
): { selectedFields: Field[]; docFields: Field[]; depVarType?: ES_FIELD_TYPES } => {
250-
const fieldsObj = { selectedFields: [], docFields: [] };
249+
): {
250+
selectedFields: Field[];
251+
docFields: Field[];
252+
depVarType?: ES_FIELD_TYPES;
253+
} => {
254+
const fieldsObj = {
255+
selectedFields: [],
256+
docFields: [],
257+
};
251258
if (fields.length === 0) {
252259
return fieldsObj;
253260
}
@@ -267,38 +274,37 @@ export const getDefaultFieldsFromJobCaps = (
267274
const featureImportanceFields = [];
268275

269276
if ((numTopFeatureImportanceValues ?? 0) > 0) {
270-
featureImportanceFields.push(
271-
...fields.map(d => ({
272-
id: `${resultsField}.feature_importance.${d.id}`,
273-
name: `${resultsField}.feature_importance.${d.name}`,
274-
type: KBN_FIELD_TYPES.NUMBER,
275-
}))
276-
);
277+
featureImportanceFields.push({
278+
id: `${resultsField}.feature_importance`,
279+
name: `${resultsField}.feature_importance`,
280+
type: KBN_FIELD_TYPES.NUMBER,
281+
});
277282
}
278283

284+
let allFields: any = [];
279285
// Only need to add these fields if we didn't use dest index pattern to get the fields
280-
const allFields: any =
281-
needsDestIndexFields === true
282-
? [
283-
{
284-
id: `${resultsField}.is_training`,
285-
name: `${resultsField}.is_training`,
286-
type: ES_FIELD_TYPES.BOOLEAN,
287-
},
288-
{ id: predictedField, name: predictedField, type },
289-
...featureImportanceFields,
290-
]
291-
: [];
292-
293-
allFields.push(...fields);
286+
if (needsDestIndexFields === true) {
287+
allFields.push(
288+
{
289+
id: `${resultsField}.is_training`,
290+
name: `${resultsField}.is_training`,
291+
type: ES_FIELD_TYPES.BOOLEAN,
292+
},
293+
{ id: predictedField, name: predictedField, type }
294+
);
295+
}
296+
297+
allFields.push(...fields, ...featureImportanceFields);
294298
allFields.sort(({ name: a }: { name: string }, { name: b }: { name: string }) =>
295299
sortRegressionResultsFields(a, b, jobConfig)
296300
);
301+
// Remove feature_importance fields provided by dest index since feature_importance is an array the path is not valid
302+
if (needsDestIndexFields === false) {
303+
allFields = allFields.filter((field: any) => !field.name.includes('.feature_importance.'));
304+
}
297305

298306
let selectedFields = allFields.filter(
299-
(field: any) =>
300-
field.name === predictedField ||
301-
(!field.name.includes('.keyword') && !field.name.includes('.feature_importance.'))
307+
(field: any) => field.name === predictedField || !field.name.includes('.keyword')
302308
);
303309

304310
if (selectedFields.length > DEFAULT_REGRESSION_COLUMNS) {

x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/use_explore_data.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import { newJobCapsService } from '../../../../../services/new_job_capabilities_
2222
import { Field } from '../../../../../../../common/types/fields';
2323
import { ES_FIELD_TYPES } from '../../../../../../../../../../src/plugins/data/public';
2424
import {
25-
LoadExploreDataArg,
2625
defaultSearchQuery,
2726
ResultsSearchQuery,
2827
isResultsSearchBoolQuery,
@@ -37,12 +36,23 @@ import {
3736
SEARCH_SIZE,
3837
SearchQuery,
3938
} from '../../../../common';
39+
import { SavedSearchQuery } from '../../../../../contexts/ml';
40+
41+
interface LoadClassificationExploreDataArg {
42+
direction: SortDirection;
43+
filterByIsTraining?: boolean;
44+
field: string;
45+
searchQuery: SavedSearchQuery;
46+
requiresKeyword?: boolean;
47+
pageIndex?: number;
48+
pageSize?: number;
49+
}
4050

4151
export type TableItem = Record<string, any>;
4252

4353
export interface UseExploreDataReturnType {
4454
errorMessage: string;
45-
loadExploreData: (arg: LoadExploreDataArg) => void;
55+
loadExploreData: (arg: LoadClassificationExploreDataArg) => void;
4656
sortField: EsFieldName;
4757
sortDirection: SortDirection;
4858
status: INDEX_STATUS;
@@ -84,7 +94,7 @@ export const useExploreData = (
8494
direction,
8595
searchQuery,
8696
requiresKeyword,
87-
}: LoadExploreDataArg) => {
97+
}: LoadClassificationExploreDataArg) => {
8898
if (jobConfig !== undefined) {
8999
setErrorMessage('');
90100
setStatus(INDEX_STATUS.LOADING);

0 commit comments

Comments
 (0)