From 32265b766ddce8123ec3a86b496566dbc980661a Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 20 Dec 2022 10:39:02 +0100 Subject: [PATCH] [8.6] [ML] Explain Log Rate Spikes: Fix client side code to transform groups into table rows. (#147592) (#147832) # Backport This will backport the following commits from `main` to `8.6`: - [[ML] Explain Log Rate Spikes: Fix client side code to transform groups into table rows. (#147592)](https://github.com/elastic/kibana/pull/147592) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) --- .../application/utils/query_utils.test.ts | 20 ++-- .../public/application/utils/query_utils.ts | 11 +-- .../explain_log_rate_spikes_analysis.tsx | 11 ++- .../spike_analysis_table_groups.tsx | 94 +++++++++---------- .../test/functional/apps/aiops/test_data.ts | 2 +- 5 files changed, 67 insertions(+), 71 deletions(-) diff --git a/x-pack/plugins/aiops/public/application/utils/query_utils.test.ts b/x-pack/plugins/aiops/public/application/utils/query_utils.test.ts index 59d680d236b15a..c886b16fa0ec2f 100644 --- a/x-pack/plugins/aiops/public/application/utils/query_utils.test.ts +++ b/x-pack/plugins/aiops/public/application/utils/query_utils.test.ts @@ -27,16 +27,16 @@ const selectedGroupMock: GroupTableItem = { id: '21289599', docCount: 20468, pValue: 2.2250738585072626e-308, - group: { - 'error.message': 'rate limit exceeded', - message: 'too many requests', - 'user_agent.original.keyword': 'Mozilla/5.0', - }, - repeatedValues: { - 'beat.hostname.keyword': 'ip-192-168-1-1', - 'beat.name.keyword': 'i-1234', - 'docker.container.id.keyword': 'asdf', - }, + group: [ + { fieldName: 'error.message', fieldValue: 'rate limit exceeded' }, + { fieldName: 'message', fieldValue: 'too many requests' }, + { fieldName: 'user_agent.original.keyword', fieldValue: 'Mozilla/5.0' }, + ], + repeatedValues: [ + { fieldName: 'beat.hostname.keyword', fieldValue: 'ip-192-168-1-1' }, + { fieldName: 'beat.name.keyword', fieldValue: 'i-1234' }, + { fieldName: 'docker.container.id.keyword', fieldValue: 'asdf' }, + ], histogram: [], }; diff --git a/x-pack/plugins/aiops/public/application/utils/query_utils.ts b/x-pack/plugins/aiops/public/application/utils/query_utils.ts index 1779b434df5086..0c0363d852bc96 100644 --- a/x-pack/plugins/aiops/public/application/utils/query_utils.ts +++ b/x-pack/plugins/aiops/public/application/utils/query_utils.ts @@ -15,7 +15,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Query } from '@kbn/es-query'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; -import type { ChangePoint } from '@kbn/ml-agg-utils'; +import type { ChangePoint, FieldValuePair } from '@kbn/ml-agg-utils'; import type { GroupTableItem } from '../../components/spike_analysis_table/spike_analysis_table_groups'; /* @@ -52,11 +52,10 @@ export function buildBaseFilterCriteria( const groupFilter = []; if (selectedGroup) { - const allItems = { ...selectedGroup.group, ...selectedGroup.repeatedValues }; - for (const fieldName in allItems) { - if (allItems.hasOwnProperty(fieldName)) { - groupFilter.push({ term: { [fieldName]: allItems[fieldName] } }); - } + const allItems: FieldValuePair[] = [...selectedGroup.group, ...selectedGroup.repeatedValues]; + for (const item of allItems) { + const { fieldName, fieldValue } = item; + groupFilter.push({ term: { [fieldName]: fieldValue } }); } } diff --git a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx index 4b8ad8a8919617..e84f50b02711c3 100644 --- a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx +++ b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx @@ -25,6 +25,7 @@ import type { WindowParameters } from '@kbn/aiops-utils'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { Query } from '@kbn/es-query'; +import type { FieldValuePair } from '@kbn/ml-agg-utils'; import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; import { initialState, streamReducer } from '../../../common/api/stream_reducer'; @@ -163,15 +164,15 @@ export const ExplainLogRateSpikesAnalysis: FC const sortedGroup = group.sort((a, b) => a.fieldName > b.fieldName ? 1 : b.fieldName > a.fieldName ? -1 : 0 ); - const dedupedGroup: Record = {}; - const repeatedValues: Record = {}; + const dedupedGroup: FieldValuePair[] = []; + const repeatedValues: FieldValuePair[] = []; sortedGroup.forEach((pair) => { const { fieldName, fieldValue } = pair; if (pair.duplicate === false) { - dedupedGroup[fieldName] = fieldValue; + dedupedGroup.push({ fieldName, fieldValue }); } else { - repeatedValues[fieldName] = fieldValue; + repeatedValues.push({ fieldName, fieldValue }); } }); @@ -197,7 +198,7 @@ export const ExplainLogRateSpikesAnalysis: FC const showSpikeAnalysisTable = data?.changePoints.length > 0; const groupItemCount = groupTableItems.reduce((p, c) => { - return p + Object.keys(c.group).length; + return p + c.group.length; }, 0); const foundGroups = groupTableItems.length > 0 && groupItemCount > 0; diff --git a/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_groups.tsx b/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_groups.tsx index b3e3f768a534b8..ba010bdf266978 100644 --- a/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_groups.tsx +++ b/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_groups.tsx @@ -25,7 +25,7 @@ import { import { i18n } from '@kbn/i18n'; import { escapeKuery } from '@kbn/es-query'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { ChangePoint } from '@kbn/ml-agg-utils'; +import type { ChangePoint, FieldValuePair } from '@kbn/ml-agg-utils'; import { SEARCH_QUERY_LANGUAGE } from '../../application/utils/search_utils'; import { useEuiTheme } from '../../hooks/use_eui_theme'; @@ -57,8 +57,8 @@ export interface GroupTableItem { id: string; docCount: number; pValue: number | null; - group: Record; - repeatedValues: Record; + group: FieldValuePair[]; + repeatedValues: FieldValuePair[]; histogram: ChangePoint['histogram']; } @@ -97,23 +97,22 @@ export const SpikeAnalysisGroupsTable: FC = ({ const { group, repeatedValues } = item; const expandedTableItems = []; - const fullGroup = { ...group, ...repeatedValues }; - - for (const fieldName in fullGroup) { - if (fullGroup.hasOwnProperty(fieldName)) { - const fieldValue = fullGroup[fieldName]; - expandedTableItems.push({ - fieldName: `${fieldName}`, - fieldValue: `${fullGroup[fieldName]}`, - ...(changePoints.find( - (changePoint) => - (changePoint.fieldName === fieldName || - changePoint.fieldName === `${fieldName}.keyword`) && - (changePoint.fieldValue === fieldValue || - changePoint.fieldValue === `${fieldValue}.keyword`) - ) ?? {}), - }); - } + const fullGroup: FieldValuePair[] = [...group, ...repeatedValues]; + + for (const fullGroupItem of fullGroup) { + const { fieldName, fieldValue } = fullGroupItem; + + expandedTableItems.push({ + ...(changePoints.find( + (changePoint) => + (changePoint.fieldName === fieldName || + changePoint.fieldName === `${fieldName}.keyword`) && + (changePoint.fieldValue === fieldValue || + changePoint.fieldValue === `${fieldValue}.keyword`) + ) ?? {}), + fieldName: `${fieldName}`, + fieldValue: `${fieldValue}`, + }); } itemIdToExpandedRowMapValues[item.id] = ( @@ -176,12 +175,12 @@ export const SpikeAnalysisGroupsTable: FC = ({ query: { language: SEARCH_QUERY_LANGUAGE.KUERY, query: [ - ...Object.entries(groupTableItem.group).map( - ([fieldName, fieldValue]) => + ...groupTableItem.group.map( + ({ fieldName, fieldValue }) => `${escapeKuery(fieldName)}:${escapeKuery(String(fieldValue))}` ), - ...Object.entries(groupTableItem.repeatedValues).map( - ([fieldName, fieldValue]) => + ...groupTableItem.repeatedValues.map( + ({ fieldName, fieldValue }) => `${escapeKuery(fieldName)}:${escapeKuery(String(fieldValue))}` ), ].join(' AND '), @@ -251,29 +250,26 @@ export const SpikeAnalysisGroupsTable: FC = ({ ), render: (_, { group, repeatedValues }) => { const valuesBadges = []; - const hasExtraBadges = Object.keys(group).length > MAX_GROUP_BADGES; - - for (const fieldName in group) { - if (group.hasOwnProperty(fieldName)) { - if (valuesBadges.length === MAX_GROUP_BADGES) break; - valuesBadges.push( - <> - - {`${fieldName}: `} - {`${group[fieldName]}`} - - - - ); - } + const hasExtraBadges = group.length > MAX_GROUP_BADGES; + + for (const groupItem of group) { + const { fieldName, fieldValue } = groupItem; + if (valuesBadges.length === MAX_GROUP_BADGES) break; + valuesBadges.push( + <> + + {`${fieldName}: `} + {`${fieldValue}`} + + + + ); } - if (Object.keys(repeatedValues).length > 0 || hasExtraBadges) { + if (repeatedValues.length > 0 || hasExtraBadges) { valuesBadges.push( <> = ({
) : null} - {Object.keys(repeatedValues).length > 0 ? ( + {repeatedValues.length > 0 ? ( ) : null}
diff --git a/x-pack/test/functional/apps/aiops/test_data.ts b/x-pack/test/functional/apps/aiops/test_data.ts index 4a07dcc8a7433b..f544225f14c971 100644 --- a/x-pack/test/functional/apps/aiops/test_data.ts +++ b/x-pack/test/functional/apps/aiops/test_data.ts @@ -55,7 +55,7 @@ export const artificialLogDataViewTestData: TestData = { totalDocCountFormatted: '8,400', analysisGroupsTable: [ { group: 'user: Peter', docCount: '1981' }, - { group: 'response_code: 500url: login.php', docCount: '792' }, + { group: 'response_code: 500url: home.phpurl: login.php', docCount: '792' }, ], analysisTable: [ {