Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ML] Add Anomaly charts embeddables to Dashboard from Anomaly Explorer page #95623

Merged
merged 48 commits into from
Apr 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
0f5046f
[ML] Add runtime support from index pattern for data viz
qn895 Mar 23, 2021
c542ca5
Merge upstream/master into branch
qn895 Mar 24, 2021
1e708e1
[ML] move runtime mappings outside of aggregatableFields loop
qn895 Mar 24, 2021
a6ae3ce
[ML] Change arg name to runtimeMappings
qn895 Mar 24, 2021
705d84c
Merge remote-tracking branch 'upstream/master' into data-viz-runtime-…
qn895 Mar 25, 2021
861d28f
[ML] Fix dv full time range broken
qn895 Mar 25, 2021
97c5890
[ML] Fix dv broken with time range
qn895 Mar 25, 2021
b68e736
[ML] Add better error handling/transparency
qn895 Mar 25, 2021
54b62f8
[ML] Update to using estypes.RuntimeField
qn895 Mar 26, 2021
ce813f0
[ML] Update to use some shared common functions between ml and transform
qn895 Mar 26, 2021
2b669c8
[ML] Remove mlJobService.getJob dependency
qn895 Mar 24, 2021
dad2872
[ML] Remove deprecated resultSelector, move anomalyChartRecords outsi…
qn895 Mar 24, 2021
95587c7
[ML] Move to loadDataForCharts$
qn895 Mar 24, 2021
cdee080
[ML] Add setChartsDataLoading
qn895 Mar 24, 2021
343bb61
Revert "[ML] Update to use some shared common functions between ml an…
qn895 Mar 28, 2021
99982e0
Merge remote-tracking branch 'upstream/master' into ml-anomaly-embedd…
qn895 Mar 28, 2021
b680c38
[ML] Consolidate explorer and swimlane add to dashboard controls
qn895 Mar 28, 2021
fc3ec9e
[ML] Update mocks
qn895 Mar 28, 2021
a7cbcd0
[ML] Update disabled check
qn895 Mar 28, 2021
2c5e8de
[ML] Disable context menu if no charts
qn895 Mar 29, 2021
f2a91bb
Merge branch 'ml-anomaly-embeddable-refactor-ui-actions' of https://g…
qn895 Mar 29, 2021
6c9bd89
Merge upstream/master into branch
qn895 Mar 29, 2021
d71da6f
[ML] Add max series input
qn895 Mar 29, 2021
21cb5de
Adjust calls of waitForSwimLanesToLoad
pheyos Mar 29, 2021
14d5acd
Revert "Adjust calls of waitForSwimLanesToLoad"
qn895 Mar 30, 2021
56a3e1b
[ML] Clear data to prevent charts data from old job selection being r…
qn895 Mar 30, 2021
abed912
Merge remote-tracking branch 'upstream/master' into ml-anomaly-embedd…
qn895 Mar 30, 2021
c1a3c62
Merge remote-tracking branch 'upstream/master' into ml-anomaly-embedd…
qn895 Mar 30, 2021
d979425
Merge remote-tracking branch 'upstream/master' into ml-anomaly-embedd…
qn895 Mar 30, 2021
078ba80
Merge remote-tracking branch 'upstream/master' into ml-anomaly-embedd…
qn895 Mar 30, 2021
1968113
[ML] Add getRecordsForInfluencer to rx service, use jobsService cache…
qn895 Mar 30, 2021
2847d28
[ML] Fix bug with resulting influencers not being the correct one
qn895 Mar 30, 2021
88047d7
Merge upstream/master into branch
qn895 Mar 30, 2021
47dccf9
Fix imports
qn895 Mar 30, 2021
937a84e
Merge upstream/master into branch
qn895 Apr 1, 2021
33cbbff
Fix duplicate isRuntimeMappings
qn895 Apr 1, 2021
4b21deb
[ML] Fix RuntimeType
qn895 Apr 1, 2021
25c1df6
Merge upstream/master into branch
qn895 Apr 5, 2021
b7f8427
[ML] Fix type
qn895 Apr 5, 2021
dbd5e91
[ML] Fix merge overrides
qn895 Apr 6, 2021
83c6974
Merge remote-tracking branch 'upstream/master' into ml-anomaly-embedd…
qn895 Apr 6, 2021
e901434
Merge remote-tracking branch 'upstream/master' into ml-anomaly-embedd…
qn895 Apr 6, 2021
653d612
Merge branch 'master' into ml-anomaly-embeddable-refactor-ui-actions
kibanamachine Apr 6, 2021
47ecb4d
Merge branch 'master' into ml-anomaly-embeddable-refactor-ui-actions
kibanamachine Apr 7, 2021
d8de444
Merge remote-tracking branch 'upstream/master' into ml-anomaly-embedd…
qn895 Apr 7, 2021
2e0bb30
[ML] Fix AnnotationDomainType -> AnnotationDomainTypes
qn895 Apr 7, 2021
422c705
Merge remote-tracking branch 'upstream/master' into ml-anomaly-embedd…
qn895 Apr 8, 2021
5efc9e6
Revert "[ML] Fix AnnotationDomainType -> AnnotationDomainTypes"
qn895 Apr 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion x-pack/plugins/ml/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export { ChartData } from './types/field_histograms';
export { ANOMALY_SEVERITY, ANOMALY_THRESHOLD, SEVERITY_COLORS } from './constants/anomalies';
export { getSeverityColor, getSeverityType } from './util/anomaly_utils';
export { isPopulatedObject } from './util/object_utils';
export { isRuntimeMappings } from './util/runtime_field_utils';
export { composeValidators, patternValidator } from './util/validators';
export { isRuntimeMappings, isRuntimeField } from './util/runtime_field_utils';
export { extractErrorMessage } from './util/errors';
export type { RuntimeMappings } from './types/fields';
15 changes: 1 addition & 14 deletions x-pack/plugins/ml/common/types/fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export interface Field {
aggregatable?: boolean;
aggIds?: AggId[];
aggs?: Aggregation[];
runtimeField?: RuntimeField;
runtimeField?: estypes.RuntimeField;
}

export interface Aggregation {
Expand Down Expand Up @@ -108,17 +108,4 @@ export interface AggCardinality {

export type RollupFields = Record<FieldId, [Record<'agg', ES_AGGREGATION>]>;

// Replace this with import once #88995 is merged
export const RUNTIME_FIELD_TYPES = ['keyword', 'long', 'double', 'date', 'ip', 'boolean'] as const;
export type RuntimeType = typeof RUNTIME_FIELD_TYPES[number];

export interface RuntimeField {
type: RuntimeType;
script?:
| string
| {
source: string;
};
}

export type RuntimeMappings = estypes.RuntimeFields;
6 changes: 3 additions & 3 deletions x-pack/plugins/ml/common/util/runtime_field_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { estypes } from '@elastic/elasticsearch';
import { isPopulatedObject } from './object_utils';
import { RUNTIME_FIELD_TYPES } from '../../../../../src/plugins/data/common';
import type { RuntimeField, RuntimeMappings } from '../types/fields';
import type { RuntimeMappings } from '../types/fields';

type RuntimeType = typeof RUNTIME_FIELD_TYPES[number];

export function isRuntimeField(arg: unknown): arg is RuntimeField {
export function isRuntimeField(arg: unknown): arg is estypes.RuntimeField {
return (
((isPopulatedObject(arg, ['type']) && Object.keys(arg).length === 1) ||
(isPopulatedObject(arg, ['type', 'script']) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { i18n } from '@kbn/i18n';

import { CoreSetup } from 'src/core/public';

import type { estypes } from '@elastic/elasticsearch';
import {
IndexPattern,
IFieldType,
Expand Down Expand Up @@ -49,7 +50,7 @@ import { getNestedProperty } from '../../util/object_utils';
import { mlFieldFormatService } from '../../services/field_format_service';

import { DataGridItem, IndexPagination, RenderCellValue } from './types';
import { RuntimeMappings, RuntimeField } from '../../../../common/types/fields';
import { RuntimeMappings } from '../../../../common/types/fields';
import { isRuntimeMappings } from '../../../../common/util/runtime_field_utils';

export const INIT_MAX_COLUMNS = 10;
Expand Down Expand Up @@ -179,7 +180,7 @@ export const getDataGridSchemasFromFieldTypes = (fieldTypes: FieldTypes, results
export const NON_AGGREGATABLE = 'non-aggregatable';

export const getDataGridSchemaFromESFieldType = (
fieldType: ES_FIELD_TYPES | undefined | RuntimeField['type']
fieldType: ES_FIELD_TYPES | undefined | estypes.RuntimeField['type']
): string | undefined => {
// Built-in values are ['boolean', 'currency', 'datetime', 'numeric', 'json']
// To fall back to the default string schema it needs to be undefined.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
*/

import { i18n } from '@kbn/i18n';
import { estypes } from '@elastic/elasticsearch';
import { ES_FIELD_TYPES } from '../../../../../../../../../../src/plugins/data/public';
import { RuntimeType } from '../../../../../../../../../../src/plugins/data/common';
import { EVENT_RATE_FIELD_ID } from '../../../../../../../common/types/fields';
import { ANALYSIS_CONFIG_TYPE } from '../../../../common/analytics';
import { AnalyticsJobType } from '../../../analytics_management/hooks/use_create_analytics_form/state';
Expand All @@ -18,7 +18,7 @@ export const CATEGORICAL_TYPES = new Set(['ip', 'keyword']);
// Regression supports numeric fields. Classification supports categorical, numeric, and boolean.
export const shouldAddAsDepVarOption = (
fieldId: string,
fieldType: ES_FIELD_TYPES | RuntimeType,
fieldType: ES_FIELD_TYPES | estypes.RuntimeField['type'],
jobType: AnalyticsJobType
) => {
if (fieldId === EVENT_RATE_FIELD_ID) return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { CoreSetup } from 'src/core/public';

import { IndexPattern } from '../../../../../../../../../src/plugins/data/public';
import { isRuntimeMappings } from '../../../../../../common/util/runtime_field_utils';
import { RuntimeMappings, RuntimeField } from '../../../../../../common/types/fields';
import { RuntimeMappings } from '../../../../../../common/types/fields';
import { DEFAULT_SAMPLER_SHARD_SIZE } from '../../../../../../common/constants/field_histograms';

import { DataLoader } from '../../../../datavisualizer/index_based/data_loader';
Expand Down Expand Up @@ -44,7 +44,7 @@ interface MLEuiDataGridColumn extends EuiDataGridColumn {
function getRuntimeFieldColumns(runtimeMappings: RuntimeMappings) {
return Object.keys(runtimeMappings).map((id) => {
const field = runtimeMappings[id];
const schema = getDataGridSchemaFromESFieldType(field.type as RuntimeField['type']);
const schema = getDataGridSchemaFromESFieldType(field.type as estypes.RuntimeField['type']);
return { id, schema, isExpandable: schema !== 'boolean', isRuntimeFieldColumn: true };
});
}
Expand All @@ -64,7 +64,7 @@ export const useIndexData = (
const field = indexPattern.fields.getByName(id);
const isRuntimeFieldColumn = field?.runtimeField !== undefined;
const schema = isRuntimeFieldColumn
? getDataGridSchemaFromESFieldType(field?.type as RuntimeField['type'])
? getDataGridSchemaFromESFieldType(field?.type as estypes.RuntimeField['type'])
: getDataGridSchemaFromKibanaFieldType(field);
return {
id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { isEqual } from 'lodash';
import useObservable from 'react-use/lib/useObservable';

import { forkJoin, of, Observable, Subject } from 'rxjs';
import { mergeMap, switchMap, tap } from 'rxjs/operators';
import { mergeMap, switchMap, tap, map } from 'rxjs/operators';

import { useCallback, useMemo } from 'react';
import { explorerService } from '../explorer_dashboard_service';
Expand All @@ -21,7 +21,6 @@ import {
getSelectionTimeRange,
loadAnnotationsTableData,
loadAnomaliesTableData,
loadDataForCharts,
loadFilteredTopInfluencers,
loadTopInfluencers,
AppStateSelectedCells,
Expand All @@ -36,8 +35,9 @@ import { ANOMALY_SWIM_LANE_HARD_LIMIT } from '../explorer_constants';
import { TimefilterContract } from '../../../../../../../src/plugins/data/public';
import { AnomalyExplorerChartsService } from '../../services/anomaly_explorer_charts_service';
import { CombinedJob } from '../../../../common/types/anomaly_detection_jobs';
import { mlJobService } from '../../services/job_service';
import { InfluencersFilterQuery } from '../../../../common/types/es_client';
import { ExplorerChartsData } from '../explorer_charts/explorer_charts_container_service';
import { mlJobService } from '../../services/job_service';

// Memoize the data fetching methods.
// wrapWithLastRefreshArg() wraps any given function and preprends a `lastRefresh` argument
Expand All @@ -58,7 +58,6 @@ const memoize = <T extends (...a: any[]) => any>(func: T, context?: any) => {
const memoizedLoadAnnotationsTableData = memoize<typeof loadAnnotationsTableData>(
loadAnnotationsTableData
);
const memoizedLoadDataForCharts = memoize<typeof loadDataForCharts>(loadDataForCharts);
const memoizedLoadFilteredTopInfluencers = memoize<typeof loadFilteredTopInfluencers>(
loadFilteredTopInfluencers
);
Expand Down Expand Up @@ -96,7 +95,7 @@ export const isLoadExplorerDataConfig = (arg: any): arg is LoadExplorerDataConfi
const loadExplorerDataProvider = (
mlResultsService: MlResultsService,
anomalyTimelineService: AnomalyTimelineService,
anomalyExplorerService: AnomalyExplorerChartsService,
anomalyExplorerChartsService: AnomalyExplorerChartsService,
timefilter: TimefilterContract
) => {
const memoizedLoadOverallData = memoize(
Expand All @@ -108,8 +107,8 @@ const loadExplorerDataProvider = (
anomalyTimelineService
);
const memoizedAnomalyDataChange = memoize(
anomalyExplorerService.getAnomalyData,
anomalyExplorerService
anomalyExplorerChartsService.getAnomalyData,
anomalyExplorerChartsService
);

return (config: LoadExplorerDataConfig): Observable<Partial<ExplorerState>> => {
Expand Down Expand Up @@ -160,9 +159,7 @@ const loadExplorerDataProvider = (
swimlaneBucketInterval.asSeconds(),
bounds
),
anomalyChartRecords: memoizedLoadDataForCharts(
lastRefresh,
mlResultsService,
anomalyChartRecords: anomalyExplorerChartsService.loadDataForCharts$(
jobIds,
timerange.earliestMs,
timerange.latestMs,
Expand Down Expand Up @@ -214,42 +211,30 @@ const loadExplorerDataProvider = (
// show the view-by loading indicator
// and pass on the data we already fetched.
tap(explorerService.setViewBySwimlaneLoading),
// Trigger a side-effect to update the charts.
tap(({ anomalyChartRecords, topFieldValues }) => {
if (selectedCells !== undefined && Array.isArray(anomalyChartRecords)) {
memoizedAnomalyDataChange(
lastRefresh,
explorerService,
combinedJobRecords,
swimlaneContainerWidth,
anomalyChartRecords,
timerange.earliestMs,
timerange.latestMs,
timefilter,
tableSeverity
);
} else {
memoizedAnomalyDataChange(
lastRefresh,
explorerService,
combinedJobRecords,
swimlaneContainerWidth,
[],
timerange.earliestMs,
timerange.latestMs,
timefilter,
tableSeverity
);
}
}),
// Load view-by swimlane data and filtered top influencers.
// mergeMap is used to have access to the already fetched data and act on it in arg #1.
// In arg #2 of mergeMap we combine the data and pass it on in the action format
// which can be consumed by explorerReducer() later on.
tap(explorerService.setChartsDataLoading),
mergeMap(
({ anomalyChartRecords, influencers, overallState, topFieldValues }) =>
({
anomalyChartRecords,
influencers,
overallState,
topFieldValues,
annotationsData,
tableData,
}) =>
forkJoin({
influencers:
anomalyChartsData: memoizedAnomalyDataChange(
lastRefresh,
combinedJobRecords,
swimlaneContainerWidth,
selectedCells !== undefined && Array.isArray(anomalyChartRecords)
? anomalyChartRecords
: [],
timerange.earliestMs,
timerange.latestMs,
timefilter,
tableSeverity
),
filteredTopInfluencers:
(selectionInfluencers.length > 0 || influencersFilterQuery !== undefined) &&
anomalyChartRecords !== undefined &&
anomalyChartRecords.length > 0
Expand Down Expand Up @@ -280,24 +265,26 @@ const loadExplorerDataProvider = (
swimlaneContainerWidth,
influencersFilterQuery
),
}),
(
{ annotationsData, overallState, tableData },
{ influencers, viewBySwimlaneState }
): Partial<ExplorerState> => {
return {
annotations: annotationsData,
influencers: influencers as any,
loading: false,
viewBySwimlaneDataLoading: false,
overallSwimlaneData: overallState,
viewBySwimlaneData: viewBySwimlaneState as any,
tableData,
swimlaneLimit: isViewBySwimLaneData(viewBySwimlaneState)
? viewBySwimlaneState.cardinality
: undefined,
};
}
}).pipe(
tap(({ anomalyChartsData }) => {
explorerService.setCharts(anomalyChartsData as ExplorerChartsData);
}),
map(({ viewBySwimlaneState, filteredTopInfluencers }) => {
return {
annotations: annotationsData,
influencers: filteredTopInfluencers as any,
loading: false,
viewBySwimlaneDataLoading: false,
anomalyChartsDataLoading: false,
overallSwimlaneData: overallState,
viewBySwimlaneData: viewBySwimlaneState as any,
tableData,
swimlaneLimit: isViewBySwimLaneData(viewBySwimlaneState)
? viewBySwimlaneState.cardinality
: undefined,
};
})
)
)
);
};
Expand All @@ -319,15 +306,15 @@ export const useExplorerData = (): [Partial<ExplorerState> | undefined, (d: any)
uiSettings,
mlResultsService
);
const anomalyExplorerService = new AnomalyExplorerChartsService(
const anomalyExplorerChartsService = new AnomalyExplorerChartsService(
timefilter,
mlApiServices,
mlResultsService
);
return loadExplorerDataProvider(
mlResultsService,
anomalyTimelineService,
anomalyExplorerService,
anomalyExplorerChartsService,
timefilter
);
}, []);
Expand Down
Loading