Skip to content

Commit

Permalink
[ML] Explain Log Rate Spikes: Fix client side code to transform group…
Browse files Browse the repository at this point in the history
…s into table rows. (#147592)

Fixes client side code to transform groups into table rows. Because the
transformation used a dictionary like structure with field names as
keys, we missed if there were multiple values for a field. This changes
the structure to an array of field/value pairs so we can support
multiple values per field.

(cherry picked from commit 92ffe27)

# Conflicts:
#	x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_groups.tsx
  • Loading branch information
walterra committed Dec 20, 2022
1 parent d868e36 commit 36fd173
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 71 deletions.
20 changes: 10 additions & 10 deletions x-pack/plugins/aiops/public/application/utils/query_utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [],
};

Expand Down
11 changes: 5 additions & 6 deletions x-pack/plugins/aiops/public/application/utils/query_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

/*
Expand Down Expand Up @@ -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 } });
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -163,15 +164,15 @@ export const ExplainLogRateSpikesAnalysis: FC<ExplainLogRateSpikesAnalysisProps>
const sortedGroup = group.sort((a, b) =>
a.fieldName > b.fieldName ? 1 : b.fieldName > a.fieldName ? -1 : 0
);
const dedupedGroup: Record<string, any> = {};
const repeatedValues: Record<string, any> = {};
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 });
}
});

Expand All @@ -197,7 +198,7 @@ export const ExplainLogRateSpikesAnalysis: FC<ExplainLogRateSpikesAnalysisProps>

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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -57,8 +57,8 @@ export interface GroupTableItem {
id: string;
docCount: number;
pValue: number | null;
group: Record<string, string | number>;
repeatedValues: Record<string, string | number>;
group: FieldValuePair[];
repeatedValues: FieldValuePair[];
histogram: ChangePoint['histogram'];
}

Expand Down Expand Up @@ -97,23 +97,22 @@ export const SpikeAnalysisGroupsTable: FC<SpikeAnalysisTableProps> = ({
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] = (
Expand Down Expand Up @@ -176,12 +175,12 @@ export const SpikeAnalysisGroupsTable: FC<SpikeAnalysisTableProps> = ({
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 '),
Expand Down Expand Up @@ -251,29 +250,26 @@ export const SpikeAnalysisGroupsTable: FC<SpikeAnalysisTableProps> = ({
),
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(
<>
<EuiBadge
key={`${fieldName}-id`}
data-test-subj="aiopsSpikeAnalysisTableColumnGroupBadge"
color="hollow"
>
<span>{`${fieldName}: `}</span>
<span
style={{ color: euiTheme.euiCodeBlockStringColor }}
>{`${group[fieldName]}`}</span>
</EuiBadge>
<EuiSpacer size="xs" />
</>
);
}
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(
<>
<EuiBadge
key={`${fieldName}-id`}
data-test-subj="aiopsSpikeAnalysisTableColumnGroupBadge"
color="hollow"
>
<span>{`${fieldName}: `}</span>
<span style={{ color: euiTheme.euiCodeBlockStringColor }}>{`${fieldValue}`}</span>
</EuiBadge>
<EuiSpacer size="xs" />
</>
);
}
if (Object.keys(repeatedValues).length > 0 || hasExtraBadges) {
if (repeatedValues.length > 0 || hasExtraBadges) {
valuesBadges.push(
<>
<EuiBadge
Expand All @@ -286,16 +282,16 @@ export const SpikeAnalysisGroupsTable: FC<SpikeAnalysisTableProps> = ({
<FormattedMessage
id="xpack.aiops.explainLogRateSpikes.spikeAnalysisTableGroups.moreLabel"
defaultMessage="+{count, plural, one {# more field/value pair} other {# more field/value pairs}}"
values={{ count: Object.keys(group).length - MAX_GROUP_BADGES }}
values={{ count: group.length - MAX_GROUP_BADGES }}
/>
<br />
</>
) : null}
{Object.keys(repeatedValues).length > 0 ? (
{repeatedValues.length > 0 ? (
<FormattedMessage
id="xpack.aiops.explainLogRateSpikes.spikeAnalysisTableGroups.moreRepeatedLabel"
defaultMessage="+{count, plural, one {# more field/value pair} other {# more field/value pairs}} also appearing in other groups"
values={{ count: Object.keys(repeatedValues).length }}
values={{ count: repeatedValues.length }}
/>
) : null}
</EuiBadge>
Expand Down
2 changes: 1 addition & 1 deletion x-pack/test/functional/apps/aiops/test_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
{
Expand Down

0 comments on commit 36fd173

Please sign in to comment.