From 94dae7cd7da7b47dae7fa07cbd34b4e6c4791111 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 15 Dec 2022 10:46:30 +0100 Subject: [PATCH] fix to fetch correct histogram for groups with multiple values for a field --- .../server/routes/explain_log_rate_spikes.ts | 8 +--- .../routes/queries/get_group_filter.test.ts | 37 +++++++++++++++++++ .../server/routes/queries/get_group_filter.ts | 33 +++++++++++++++++ 3 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 x-pack/plugins/aiops/server/routes/queries/get_group_filter.test.ts create mode 100644 x-pack/plugins/aiops/server/routes/queries/get_group_filter.ts diff --git a/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts b/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts index 7da7a345eca3900..19ecf20ec34be69 100644 --- a/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts +++ b/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts @@ -47,6 +47,7 @@ import { fetchIndexInfo } from './queries/fetch_index_info'; import { dropDuplicates, fetchFrequentItems } from './queries/fetch_frequent_items'; import { getHistogramQuery } from './queries/get_histogram_query'; import { getChangePointGroups } from './queries/get_change_point_groups'; +import { getGroupFilter } from './queries/get_group_filter'; // 10s ping frequency to keep the stream alive. const PING_FREQUENCY = 10000; @@ -478,12 +479,7 @@ export const defineExplainLogRateSpikesRoute = ( } if (overallTimeSeries !== undefined) { - const histogramQuery = getHistogramQuery( - request.body, - cpg.group.map((d) => ({ - term: { [d.fieldName]: d.fieldValue }, - })) - ); + const histogramQuery = getHistogramQuery(request.body, getGroupFilter(cpg)); let cpgTimeSeries: NumericChartData; try { diff --git a/x-pack/plugins/aiops/server/routes/queries/get_group_filter.test.ts b/x-pack/plugins/aiops/server/routes/queries/get_group_filter.test.ts new file mode 100644 index 000000000000000..b2c15d70e83f93f --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/queries/get_group_filter.test.ts @@ -0,0 +1,37 @@ +/* + * 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 { finalChangePointGroups } from '../../../common/__mocks__/artificial_logs/final_change_point_groups'; + +import { getGroupFilter } from './get_group_filter'; + +describe('getGroupFilter', () => { + it('gets a query filter for the change points of a group with multiple values per field', () => { + expect(getGroupFilter(finalChangePointGroups[0])).toStrictEqual([ + { + term: { + response_code: '500', + }, + }, + { + terms: { + url: ['home.php', 'login.php'], + }, + }, + ]); + }); + + it('gets a query filter for the change points of a group with just a single field/value', () => { + expect(getGroupFilter(finalChangePointGroups[1])).toStrictEqual([ + { + term: { + user: 'Peter', + }, + }, + ]); + }); +}); diff --git a/x-pack/plugins/aiops/server/routes/queries/get_group_filter.ts b/x-pack/plugins/aiops/server/routes/queries/get_group_filter.ts new file mode 100644 index 000000000000000..fdd97eb10107214 --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/queries/get_group_filter.ts @@ -0,0 +1,33 @@ +/* + * 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 * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +import type { ChangePointGroup } from '@kbn/ml-agg-utils'; + +// Transforms a list of change point items from a group in a query filter. +// Uses a `term` filter for single field value combinations. +// For fields with multiple values it creates a single `terms` filter that includes +// all values. This avoids queries not returning any results otherwise because +// separate `term` filter for multiple values for the same field would rule each other out. +export function getGroupFilter( + changePointGroup: ChangePointGroup +): estypes.QueryDslQueryContainer[] { + return Object.entries( + changePointGroup.group.reduce>>((p, c) => { + if (p[c.fieldName]) { + p[c.fieldName].push(c.fieldValue); + } else { + p[c.fieldName] = [c.fieldValue]; + } + return p; + }, {}) + ).reduce((p, [key, values]) => { + p.push(values.length > 1 ? { terms: { [key]: values } } : { term: { [key]: values[0] } }); + return p; + }, []); +}