Skip to content

Commit

Permalink
[ML] DF Analytics results table: use index pattern field format if on…
Browse files Browse the repository at this point in the history
…e exists (#61709) (#61989)

* classification: use index field format in results table

* regression: use index field format in results table

* outlier: use index field format in results table

* update types

* add destIndex specific fields when using sourceIndex for fields
  • Loading branch information
alvarezmelissa87 authored Mar 31, 2020
1 parent 3727778 commit 8293684
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,8 @@ export function getFlattenedFields(obj: EsDocSource, resultsField: string): EsFi

export const getDefaultFieldsFromJobCaps = (
fields: Field[],
jobConfig: DataFrameAnalyticsConfig
jobConfig: DataFrameAnalyticsConfig,
needsDestIndexFields: boolean
): { selectedFields: Field[]; docFields: Field[]; depVarType?: ES_FIELD_TYPES } => {
const fieldsObj = { selectedFields: [], docFields: [] };
if (fields.length === 0) {
Expand All @@ -260,16 +261,22 @@ export const getDefaultFieldsFromJobCaps = (
const predictedField = `${resultsField}.${
predictionFieldName ? predictionFieldName : defaultPredictionField
}`;

const allFields: any = [
{
id: `${resultsField}.is_training`,
name: `${resultsField}.is_training`,
type: ES_FIELD_TYPES.BOOLEAN,
},
{ id: predictedField, name: predictedField, type },
...fields,
].sort(({ name: a }, { name: b }) => sortRegressionResultsFields(a, b, jobConfig));
// Only need to add these first two fields if we didn't use dest index pattern to get the fields
const allFields: any =
needsDestIndexFields === true
? [
{
id: `${resultsField}.is_training`,
name: `${resultsField}.is_training`,
type: ES_FIELD_TYPES.BOOLEAN,
},
{ id: predictedField, name: predictedField, type },
]
: [];

allFields.push(...fields);
// @ts-ignore
allFields.sort(({ name: a }, { name: b }) => sortRegressionResultsFields(a, b, jobConfig));

let selectedFields = allFields
.slice(0, DEFAULT_REGRESSION_COLUMNS * 2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/
import { ResultsSearchQuery, defaultSearchQuery } from '../../../../common/analytics';
import { LoadingPanel } from '../loading_panel';
import { getIndexPatternIdFromName } from '../../../../../util/index_utils';
import { IIndexPattern } from '../../../../../../../../../../src/plugins/data/common/index_patterns';
import { IndexPattern } from '../../../../../../../../../../src/plugins/data/public';
import { newJobCapsService } from '../../../../../services/new_job_capabilities_service';
import { useMlContext } from '../../../../../contexts/ml';
import { isGetDataFrameAnalyticsStatsResponseOk } from '../../../analytics_management/services/analytics_service/get_analytics';
Expand Down Expand Up @@ -53,6 +53,7 @@ interface Props {
export const ClassificationExploration: FC<Props> = ({ jobId }) => {
const [jobConfig, setJobConfig] = useState<DataFrameAnalyticsConfig | undefined>(undefined);
const [jobStatus, setJobStatus] = useState<DATA_FRAME_TASK_STATE | undefined>(undefined);
const [indexPattern, setIndexPattern] = useState<IndexPattern | undefined>(undefined);
const [isLoadingJobConfig, setIsLoadingJobConfig] = useState<boolean>(false);
const [isInitialized, setIsInitialized] = useState<boolean>(false);
const [jobConfigErrorMessage, setJobConfigErrorMessage] = useState<undefined | string>(undefined);
Expand Down Expand Up @@ -108,11 +109,27 @@ export const ClassificationExploration: FC<Props> = ({ jobId }) => {
const initializeJobCapsService = async () => {
if (jobConfig !== undefined) {
try {
const sourceIndex = jobConfig.source.index[0];
const indexPatternId = getIndexPatternIdFromName(sourceIndex) || sourceIndex;
const indexPattern: IIndexPattern = await mlContext.indexPatterns.get(indexPatternId);
if (indexPattern !== undefined) {
await newJobCapsService.initializeFromIndexPattern(indexPattern, false, false);
const destIndex = Array.isArray(jobConfig.dest.index)
? jobConfig.dest.index[0]
: jobConfig.dest.index;
const destIndexPatternId = getIndexPatternIdFromName(destIndex) || destIndex;
let indexP: IndexPattern | undefined;

try {
indexP = await mlContext.indexPatterns.get(destIndexPatternId);
} catch (e) {
indexP = undefined;
}

if (indexP === undefined) {
const sourceIndex = jobConfig.source.index[0];
const sourceIndexPatternId = getIndexPatternIdFromName(sourceIndex) || sourceIndex;
indexP = await mlContext.indexPatterns.get(sourceIndexPatternId);
}

if (indexP !== undefined) {
setIndexPattern(indexP);
await newJobCapsService.initializeFromIndexPattern(indexP, false, false);
}
setIsInitialized(true);
} catch (e) {
Expand All @@ -127,7 +144,7 @@ export const ClassificationExploration: FC<Props> = ({ jobId }) => {

useEffect(() => {
initializeJobCapsService();
}, [JSON.stringify(jobConfig)]);
}, [jobConfig && jobConfig.id]);

if (jobConfigErrorMessage !== undefined || jobCapsServiceErrorMessage !== undefined) {
return (
Expand All @@ -153,13 +170,17 @@ export const ClassificationExploration: FC<Props> = ({ jobId }) => {
)}
<EuiSpacer />
{isLoadingJobConfig === true && jobConfig === undefined && <LoadingPanel />}
{isLoadingJobConfig === false && jobConfig !== undefined && isInitialized === true && (
<ResultsTable
jobConfig={jobConfig}
jobStatus={jobStatus}
setEvaluateSearchQuery={setSearchQuery}
/>
)}
{isLoadingJobConfig === false &&
jobConfig !== undefined &&
indexPattern !== undefined &&
isInitialized === true && (
<ResultsTable
jobConfig={jobConfig}
indexPattern={indexPattern}
jobStatus={jobStatus}
setEvaluateSearchQuery={setSearchQuery}
/>
)}
</Fragment>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import {

import { Query as QueryType } from '../../../analytics_management/components/analytics_list/common';
import { ES_FIELD_TYPES } from '../../../../../../../../../../src/plugins/data/public';
import { mlFieldFormatService } from '../../../../../services/field_format_service';
import { IndexPattern } from '../../../../../../../../../../src/plugins/data/public';

import {
ColumnType,
Expand Down Expand Up @@ -61,7 +63,6 @@ import {
} from '../../../../common';
import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/columns';
import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common';

import { useExploreData, TableItem } from './use_explore_data';
import { ExplorationTitle } from './classification_exploration';

Expand All @@ -85,13 +86,14 @@ const showingFirstDocs = i18n.translate(
);

interface Props {
indexPattern: IndexPattern;
jobConfig: DataFrameAnalyticsConfig;
jobStatus?: DATA_FRAME_TASK_STATE;
setEvaluateSearchQuery: React.Dispatch<React.SetStateAction<object>>;
}

export const ResultsTable: FC<Props> = React.memo(
({ jobConfig, jobStatus, setEvaluateSearchQuery }) => {
({ indexPattern, jobConfig, jobStatus, setEvaluateSearchQuery }) => {
const [pageIndex, setPageIndex] = useState(0);
const [pageSize, setPageSize] = useState(25);
const [selectedFields, setSelectedFields] = useState([] as Field[]);
Expand Down Expand Up @@ -126,19 +128,33 @@ export const ResultsTable: FC<Props> = React.memo(
}
}

const needsDestIndexFields = indexPattern && indexPattern.title === jobConfig.source.index[0];

const {
errorMessage,
loadExploreData,
sortField,
sortDirection,
status,
tableItems,
} = useExploreData(jobConfig, selectedFields, setSelectedFields, setDocFields, setDepVarType);
} = useExploreData(
jobConfig,
needsDestIndexFields,
selectedFields,
setSelectedFields,
setDocFields,
setDepVarType
);

const columns: Array<ColumnType<TableItem>> = selectedFields
.sort(({ name: a }, { name: b }) => sortRegressionResultsFields(a, b, jobConfig))
.map(field => {
const { type } = field;
let format: any;

if (indexPattern !== undefined) {
format = mlFieldFormatService.getFieldFormatFromIndexPattern(indexPattern, field.id, '');
}
const isNumber =
type !== undefined &&
(BASIC_NUMERICAL_TYPES.has(type) || EXTENDED_NUMERICAL_TYPES.has(type));
Expand All @@ -151,6 +167,11 @@ export const ResultsTable: FC<Props> = React.memo(
};

const render = (d: any, fullItem: EsDoc) => {
if (format !== undefined) {
d = format.convert(d, 'text');
return d;
}

if (Array.isArray(d) && d.every(item => typeof item === 'string')) {
// If the cells data is an array of strings, return as a comma separated list.
// The list will get limited to 5 items with `…` at the end if there's more in the original array.
Expand Down Expand Up @@ -193,12 +214,16 @@ export const ResultsTable: FC<Props> = React.memo(
break;
case ES_FIELD_TYPES.DATE:
column.align = 'right';
column.render = (d: any) => {
if (d !== undefined) {
return formatHumanReadableDateTimeSeconds(moment(d).unix() * 1000);
}
return d;
};
if (format !== undefined) {
column.render = render;
} else {
column.render = (d: any) => {
if (d !== undefined) {
return formatHumanReadableDateTimeSeconds(moment(d).unix() * 1000);
}
return d;
};
}
break;
default:
column.render = render;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export interface UseExploreDataReturnType {

export const useExploreData = (
jobConfig: DataFrameAnalyticsConfig | undefined,
needsDestIndexFields: boolean,
selectedFields: Field[],
setSelectedFields: React.Dispatch<React.SetStateAction<Field[]>>,
setDocFields: React.Dispatch<React.SetStateAction<Field[]>>,
Expand All @@ -70,7 +71,7 @@ export const useExploreData = (
selectedFields: defaultSelected,
docFields,
depVarType,
} = getDefaultFieldsFromJobCaps(fields, jobConfig);
} = getDefaultFieldsFromJobCaps(fields, jobConfig, needsDestIndexFields);

setDepVarType(depVarType);
setSelectedFields(defaultSelected);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import { EuiDataGrid, EuiDataGridPaginationProps, EuiDataGridSorting } from '@el

import { euiDataGridStyle, euiDataGridToolbarSettings } from '../../../../common';

import { mlFieldFormatService } from '../../../../../services/field_format_service';

import { IndexPattern } from '../../../../../../../../../../src/plugins/data/public';

const FEATURE_INFLUENCE = 'feature_influence';
const PAGE_SIZE_OPTIONS = [5, 10, 25, 50];

Expand All @@ -21,6 +25,7 @@ type TableItem = Record<string, any>;
interface ExplorationDataGridProps {
colorRange: (d: number) => string;
columns: any[];
indexPattern: IndexPattern;
pagination: Pagination;
resultsField: string;
rowCount: number;
Expand All @@ -35,6 +40,7 @@ interface ExplorationDataGridProps {
export const ExplorationDataGrid: FC<ExplorationDataGridProps> = ({
colorRange,
columns,
indexPattern,
pagination,
resultsField,
rowCount,
Expand Down Expand Up @@ -63,6 +69,12 @@ export const ExplorationDataGrid: FC<ExplorationDataGridProps> = ({
return null;
}

let format: any;

if (indexPattern !== undefined) {
format = mlFieldFormatService.getFieldFormatFromIndexPattern(indexPattern, columnId, '');
}

const cellValue =
fullItem.hasOwnProperty(columnId) && fullItem[columnId] !== undefined
? fullItem[columnId]
Expand All @@ -87,6 +99,10 @@ export const ExplorationDataGrid: FC<ExplorationDataGridProps> = ({
});
}

if (format !== undefined) {
return format.convert(cellValue, 'text');
}

if (typeof cellValue === 'string' || cellValue === null) {
return cellValue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ export const OutlierExploration: FC<ExplorationProps> = React.memo(({ jobId }) =
<ExplorationDataGrid
colorRange={colorRange}
columns={columns}
indexPattern={indexPattern}
pagination={pagination}
resultsField={jobConfig.dest.results_field}
rowCount={rowCount}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ interface Props {
export const RegressionExploration: FC<Props> = ({ jobId }) => {
const [jobConfig, setJobConfig] = useState<DataFrameAnalyticsConfig | undefined>(undefined);
const [jobStatus, setJobStatus] = useState<DATA_FRAME_TASK_STATE | undefined>(undefined);
const [indexPattern, setIndexPattern] = useState<any | undefined>(undefined);
const [isLoadingJobConfig, setIsLoadingJobConfig] = useState<boolean>(false);
const [isInitialized, setIsInitialized] = useState<boolean>(false);
const [jobConfigErrorMessage, setJobConfigErrorMessage] = useState<undefined | string>(undefined);
Expand Down Expand Up @@ -99,11 +100,27 @@ export const RegressionExploration: FC<Props> = ({ jobId }) => {
const initializeJobCapsService = async () => {
if (jobConfig !== undefined) {
try {
const sourceIndex = jobConfig.source.index[0];
const indexPatternId = getIndexPatternIdFromName(sourceIndex) || sourceIndex;
const indexPattern: IIndexPattern = await mlContext.indexPatterns.get(indexPatternId);
if (indexPattern !== undefined) {
await newJobCapsService.initializeFromIndexPattern(indexPattern, false, false);
const destIndex = Array.isArray(jobConfig.dest.index)
? jobConfig.dest.index[0]
: jobConfig.dest.index;
const destIndexPatternId = getIndexPatternIdFromName(destIndex) || destIndex;
let indexP: IIndexPattern | undefined;

try {
indexP = await mlContext.indexPatterns.get(destIndexPatternId);
} catch (e) {
indexP = undefined;
}

if (indexP === undefined) {
const sourceIndex = jobConfig.source.index[0];
const sourceIndexPatternId = getIndexPatternIdFromName(sourceIndex) || sourceIndex;
indexP = await mlContext.indexPatterns.get(sourceIndexPatternId);
}

if (indexP !== undefined) {
setIndexPattern(indexP);
await newJobCapsService.initializeFromIndexPattern(indexP, false, false);
}
setIsInitialized(true);
} catch (e) {
Expand All @@ -118,7 +135,7 @@ export const RegressionExploration: FC<Props> = ({ jobId }) => {

useEffect(() => {
initializeJobCapsService();
}, [JSON.stringify(jobConfig)]);
}, [jobConfig && jobConfig.id]);

if (jobConfigErrorMessage !== undefined || jobCapsServiceErrorMessage !== undefined) {
return (
Expand All @@ -144,13 +161,17 @@ export const RegressionExploration: FC<Props> = ({ jobId }) => {
)}
<EuiSpacer />
{isLoadingJobConfig === true && jobConfig === undefined && <LoadingPanel />}
{isLoadingJobConfig === false && jobConfig !== undefined && isInitialized === true && (
<ResultsTable
jobConfig={jobConfig}
jobStatus={jobStatus}
setEvaluateSearchQuery={setSearchQuery}
/>
)}
{isLoadingJobConfig === false &&
jobConfig !== undefined &&
indexPattern !== undefined &&
isInitialized === true && (
<ResultsTable
jobConfig={jobConfig}
indexPattern={indexPattern}
jobStatus={jobStatus}
setEvaluateSearchQuery={setSearchQuery}
/>
)}
</Fragment>
);
};
Loading

0 comments on commit 8293684

Please sign in to comment.