Skip to content

Commit

Permalink
[ML] Fix Anomaly Detection wizard full time range chart blank with sa…
Browse files Browse the repository at this point in the history
…ved search containing runtime fields (#95700)

* [ML] Fix AD wizard full time range chart broken with saved search

* [ML] Update runtimeMappingsSchema to be its own thing for better reuse

* [ML] Remove undefined check
  • Loading branch information
qn895 authored Mar 30, 2021
1 parent d6370f4 commit a1bc9a5
Show file tree
Hide file tree
Showing 13 changed files with 52 additions and 24 deletions.
7 changes: 2 additions & 5 deletions x-pack/plugins/ml/common/util/runtime_field_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
*/

import { isPopulatedObject } from './object_utils';
import {
RUNTIME_FIELD_TYPES,
RuntimeType,
} from '../../../../../src/plugins/data/common/index_patterns';
import { RUNTIME_FIELD_TYPES } from '../../../../../src/plugins/data/common/index_patterns';
import type { RuntimeField, RuntimeMappings } from '../types/fields';

export function isRuntimeField(arg: unknown): arg is RuntimeField {
Expand All @@ -24,7 +21,7 @@ export function isRuntimeField(arg: unknown): arg is RuntimeField {
Object.keys(arg.script).length === 1 &&
arg.script.hasOwnProperty('source') &&
typeof arg.script.source === 'string')))) &&
RUNTIME_FIELD_TYPES.includes(arg.type as RuntimeType)
RUNTIME_FIELD_TYPES.includes(arg.type)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function chartLoaderProvider(mlResultsService: MlResultsService) {
job.data_counts.earliest_record_timestamp,
job.data_counts.latest_record_timestamp,
intervalMs,
job.datafeed_config.runtime_mappings,
// @ts-expect-error @elastic/elasticsearch Datafeed is missing indices_options
job.datafeed_config.indices_options
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export class ChartLoader {
start: number,
end: number,
intervalMs: number,
runtimeMappings?: RuntimeMappings,
indicesOptions?: IndicesOptions
): Promise<LineChartPoint[]> {
if (this._timeFieldName !== '') {
Expand All @@ -138,6 +139,7 @@ export class ChartLoader {
start,
end,
intervalMs * 3,
runtimeMappings,
indicesOptions
);
if (resp.error !== undefined) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const CategorizationDetectorsSummary: FC = () => {
jobCreator.start,
jobCreator.end,
chartInterval.getInterval().asMilliseconds(),
jobCreator.runtimeMappings ?? undefined,
// @ts-expect-error @elastic/elasticsearch Datafeed is missing indices_options
jobCreator.datafeedConfig.indices_options
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const TimeRangeStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep })
jobCreator.start,
jobCreator.end,
chartInterval.getInterval().asMilliseconds(),
jobCreator.runtimeMappings ?? undefined,
// @ts-expect-error @elastic/elasticsearch Datafeed is missing indices_options
jobCreator.datafeedConfig.indices_options
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import { JobId } from '../../../../../common/types/anomaly_detection_jobs';
import { ML_PAGES } from '../../../../../common/constants/ml_url_generator';
import { TIME_FORMAT } from '../../../../../common/constants/time_format';
import { JobsAwaitingNodeWarning } from '../../../components/jobs_awaiting_node_warning';
import { isPopulatedObject } from '../../../../../common/util/object_utils';
import { RuntimeMappings } from '../../../../../common/types/fields';

export interface ModuleJobUI extends ModuleJob {
datafeedResult?: DatafeedResponse;
Expand Down Expand Up @@ -133,10 +135,12 @@ export const Page: FC<PageProps> = ({ moduleId, existingGroupIds }) => {
timeRange: TimeRange
): Promise<TimeRange> => {
if (useFullIndexData) {
const runtimeMappings = indexPattern.getComputedFields().runtimeFields as RuntimeMappings;
const { start, end } = await ml.getTimeFieldRange({
index: indexPattern.title,
timeFieldName: indexPattern.timeFieldName,
query: combinedQuery,
...(isPopulatedObject(runtimeMappings) ? { runtimeMappings } : {}),
});
return {
start: start.epoch,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { MlApiServices } from '../ml_api_service';
import type { AnomalyRecordDoc } from '../../../../common/types/anomalies';
import { InfluencersFilterQuery } from '../../../../common/types/es_client';
import { EntityField } from '../../../../common/util/anomaly_utils';
import { RuntimeMappings } from '../../../../common/types/fields';

type RecordForInfluencer = AnomalyRecordDoc;
export function resultsServiceProvider(
Expand Down Expand Up @@ -64,6 +65,7 @@ export function resultsServiceProvider(
earliestMs: number,
latestMs: number,
intervalMs: number,
runtimeMappings?: RuntimeMappings,
indicesOptions?: IndicesOptions
): Promise<any>;
getEventDistributionData(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
SWIM_LANE_DEFAULT_PAGE_SIZE,
} from '../../explorer/explorer_constants';
import { aggregationTypeTransform } from '../../../../common/util/anomaly_utils';
import { isPopulatedObject } from '../../../../common/util/object_utils';

/**
* Service for carrying out Elasticsearch queries to obtain data for the Ml Results dashboards.
Expand Down Expand Up @@ -1059,6 +1060,7 @@ export function resultsServiceProvider(mlApiServices) {
earliestMs,
latestMs,
intervalMs,
runtimeMappings,
indicesOptions
) {
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -1109,6 +1111,12 @@ export function resultsServiceProvider(mlApiServices) {
},
},
},
// Runtime mappings only needed to support when query includes a runtime field
// even though the default timeField can be a search time runtime field
// because currently Kibana doesn't support that
...(isPopulatedObject(runtimeMappings) && query
? { runtime_mappings: runtimeMappings }
: {}),
},
...(indicesOptions ?? {}),
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,13 @@
*/

import { schema } from '@kbn/config-schema';
import { isRuntimeField } from '../../../common/util/runtime_field_utils';
import { runtimeMappingsSchema } from './runtime_mappings_schema';

export const indexPatternTitleSchema = schema.object({
/** Title of the index pattern for which to return stats. */
indexPatternTitle: schema.string(),
});

const runtimeMappingsSchema = schema.maybe(
schema.object(
{},
{
unknowns: 'allow',
validate: (v: object) => {
if (Object.values(v).some((o) => !isRuntimeField(o))) {
return 'Invalid runtime field';
}
},
}
)
);

export const dataVisualizerFieldHistogramsSchema = schema.object({
/** Query to match documents in the index. */
query: schema.any(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import { schema } from '@kbn/config-schema';
import { indicesOptionsSchema } from './datafeeds_schema';
import { runtimeMappingsSchema } from './runtime_mappings_schema';

export const getCardinalityOfFieldsSchema = schema.object({
/** Index or indexes for which to return the time range. */
Expand All @@ -31,6 +32,6 @@ export const getTimeFieldRangeSchema = schema.object({
/** Query to match documents in the index(es). */
query: schema.maybe(schema.any()),
/** Additional search options. */
runtimeMappings: schema.maybe(schema.any()),
runtimeMappings: runtimeMappingsSchema,
indicesOptions: indicesOptionsSchema,
});
5 changes: 3 additions & 2 deletions x-pack/plugins/ml/server/routes/schemas/job_service_schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { schema } from '@kbn/config-schema';
import { anomalyDetectionJobSchema } from './anomaly_detectors_schema';
import { datafeedConfigSchema, indicesOptionsSchema } from './datafeeds_schema';
import { runtimeMappingsSchema } from './runtime_mappings_schema';

export const categorizationFieldExamplesSchema = {
indexPatternTitle: schema.string(),
Expand All @@ -18,7 +19,7 @@ export const categorizationFieldExamplesSchema = {
start: schema.number(),
end: schema.number(),
analyzer: schema.any(),
runtimeMappings: schema.maybe(schema.any()),
runtimeMappings: runtimeMappingsSchema,
indicesOptions: indicesOptionsSchema,
};

Expand All @@ -32,7 +33,7 @@ export const chartSchema = {
aggFieldNamePairs: schema.arrayOf(schema.any()),
splitFieldName: schema.maybe(schema.nullable(schema.string())),
splitFieldValue: schema.maybe(schema.nullable(schema.string())),
runtimeMappings: schema.maybe(schema.any()),
runtimeMappings: runtimeMappingsSchema,
indicesOptions: indicesOptionsSchema,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { schema } from '@kbn/config-schema';
import { analysisConfigSchema, anomalyDetectionJobSchema } from './anomaly_detectors_schema';
import { datafeedConfigSchema, indicesOptionsSchema } from './datafeeds_schema';
import { runtimeMappingsSchema } from './runtime_mappings_schema';

export const estimateBucketSpanSchema = schema.object({
aggTypes: schema.arrayOf(schema.nullable(schema.string())),
Expand All @@ -18,7 +19,7 @@ export const estimateBucketSpanSchema = schema.object({
query: schema.any(),
splitField: schema.maybe(schema.string()),
timeField: schema.maybe(schema.string()),
runtimeMappings: schema.maybe(schema.any()),
runtimeMappings: runtimeMappingsSchema,
indicesOptions: indicesOptionsSchema,
});

Expand Down
23 changes: 23 additions & 0 deletions x-pack/plugins/ml/server/routes/schemas/runtime_mappings_schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { schema } from '@kbn/config-schema';
import { isRuntimeField } from '../../../common/util/runtime_field_utils';

export const runtimeMappingsSchema = schema.maybe(
schema.object(
{},
{
unknowns: 'allow',
validate: (v: object) => {
if (Object.values(v).some((o) => !isRuntimeField(o))) {
return 'Invalid runtime field';
}
},
}
)
);

0 comments on commit a1bc9a5

Please sign in to comment.