[ML] AIOps Fixing field aliases in pattern analysis (#176586)

This commit is contained in:
James Gowdy 2024-02-13 20:32:31 +00:00 committed by GitHub
parent 2d36a14de9
commit d809be71f0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 60 additions and 20 deletions

View file

@ -50,7 +50,12 @@ export function processCategoryResults(
regex: b.regex,
};
});
// check the first category for examples to determine if examples are available
const hasExamples = categories[0]?.examples.some((e) => e !== undefined);
return {
categories,
hasExamples,
};
}

View file

@ -15,6 +15,8 @@ import {
EuiHorizontalRule,
EuiSpacer,
EuiButtonIcon,
EuiToolTip,
EuiIcon,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
@ -42,7 +44,7 @@ import type { EventRate } from '../use_categorize_request';
import { getLabels } from './labels';
import { TableHeader } from './table_header';
import { ExpandedRow } from './expanded_row';
import { FormattedPatternExamples } from '../format_category';
import { FormattedPatternExamples, FormattedTokens } from '../format_category';
interface Props {
categories: Category[];
@ -60,6 +62,7 @@ interface Props {
enableRowActions?: boolean;
additionalFilter?: CategorizationAdditionalFilter;
navigateToDiscover?: boolean;
displayExamples?: boolean;
}
export const CategoryTable: FC<Props> = ({
@ -78,6 +81,7 @@ export const CategoryTable: FC<Props> = ({
enableRowActions = true,
additionalFilter,
navigateToDiscover = true,
displayExamples = true,
}) => {
const euiTheme = useEuiTheme();
const primaryBackgroundColor = useEuiBackgroundColor('primary');
@ -142,11 +146,13 @@ export const CategoryTable: FC<Props> = ({
if (itemIdToExpandedRowMapValues[category.key]) {
delete itemIdToExpandedRowMapValues[category.key];
} else {
itemIdToExpandedRowMapValues[category.key] = <ExpandedRow category={category} />;
itemIdToExpandedRowMapValues[category.key] = (
<ExpandedRow category={category} displayExamples={displayExamples} />
);
}
setItemIdToExpandedRowMap(itemIdToExpandedRowMapValues);
},
[itemIdToExpandedRowMap]
[displayExamples, itemIdToExpandedRowMap]
);
const columns: Array<EuiBasicTableColumn<Category>> = [
@ -185,11 +191,7 @@ export const CategoryTable: FC<Props> = ({
defaultMessage: 'Examples',
}),
sortable: true,
render: (item: Category) => (
<>
<FormattedPatternExamples category={item} count={1} />
</>
),
render: (item: Category) => <FormattedPatternExamples category={item} count={1} />,
},
{
name: i18n.translate('xpack.aiops.logCategorization.column.actions', {
@ -218,6 +220,29 @@ export const CategoryTable: FC<Props> = ({
},
] as Array<EuiBasicTableColumn<Category>>;
if (displayExamples === false) {
// on the rare occasion that examples are not available, replace the examples column with tokens
columns.splice(2, 1, {
name: (
<EuiToolTip
position="top"
content={i18n.translate('xpack.aiops.logCategorization.column.tokens.tooltip', {
defaultMessage:
'If the selected field is an alias, example documents cannot be displayed. Showing pattern tokens instead.',
})}
>
<>
{i18n.translate('xpack.aiops.logCategorization.column.tokens', {
defaultMessage: 'Tokens',
})}
<EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" />
</>
</EuiToolTip>
),
render: (item: Category) => <FormattedTokens category={item} count={1} />,
});
}
if (showSparkline === true) {
columns.splice(2, 0, {
field: 'sparkline',

View file

@ -15,9 +15,10 @@ import { FormattedPatternExamples, FormattedRegex, FormattedTokens } from '../fo
interface ExpandedRowProps {
category: Category;
displayExamples?: boolean;
}
export const ExpandedRow: FC<ExpandedRowProps> = ({ category }) => {
export const ExpandedRow: FC<ExpandedRowProps> = ({ category, displayExamples = true }) => {
const { euiTheme } = useEuiTheme();
const cssExpandedRow = css({
marginRight: euiTheme.size.xxl,
@ -44,13 +45,15 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ category }) => {
<FormattedRegex category={category} />
</Section>
<Section
title={i18n.translate('xpack.aiops.logCategorization.expandedRow.title.examples', {
defaultMessage: 'Examples',
})}
>
<FormattedPatternExamples category={category} />
</Section>
{displayExamples ? (
<Section
title={i18n.translate('xpack.aiops.logCategorization.expandedRow.title.examples', {
defaultMessage: 'Examples',
})}
>
<FormattedPatternExamples category={category} />
</Section>
) : null}
</div>
);
};

View file

@ -110,6 +110,7 @@ export const LogCategorizationFlyout: FC<LogCategorizationPageProps> = ({
const [data, setData] = useState<{
categories: Category[];
categoriesInBucket: Category[] | null;
displayExamples: boolean;
} | null>(null);
const [fieldValidationResult, setFieldValidationResult] = useState<FieldValidationResults | null>(
null
@ -191,7 +192,7 @@ export const LogCategorizationFlyout: FC<LogCategorizationPageProps> = ({
if (mounted.current === true) {
setFieldValidationResult(validationResult);
const { categories } = categorizationResult;
const { categories, hasExamples } = categorizationResult;
const hasBucketCategories = categories.some((c) => c.subTimeRangeCount !== undefined);
let categoriesInBucket: any | null = null;
@ -210,6 +211,7 @@ export const LogCategorizationFlyout: FC<LogCategorizationPageProps> = ({
setData({
categories,
categoriesInBucket,
displayExamples: hasExamples,
});
setShowTabs(hasBucketCategories);
@ -388,6 +390,7 @@ export const LogCategorizationFlyout: FC<LogCategorizationPageProps> = ({
<EuiSpacer size="s" />
</>
) : null}
<CategoryTable
categories={
selectedTab === SELECTED_TAB.BUCKET && data.categoriesInBucket !== null
@ -412,6 +415,7 @@ export const LogCategorizationFlyout: FC<LogCategorizationPageProps> = ({
: undefined
}
navigateToDiscover={additionalFilter !== undefined}
displayExamples={data.displayExamples}
/>
</>
) : null}

View file

@ -89,6 +89,7 @@ export const LogCategorizationPage: FC<LogCategorizationPageProps> = ({ embeddin
const [pinnedCategory, setPinnedCategory] = useState<Category | null>(null);
const [data, setData] = useState<{
categories: Category[];
displayExamples: boolean;
} | null>(null);
const [fieldValidationResult, setFieldValidationResult] = useState<FieldValidationResults | null>(
null
@ -212,6 +213,7 @@ export const LogCategorizationPage: FC<LogCategorizationPageProps> = ({ embeddin
setFieldValidationResult(validationResult);
setData({
categories: categorizationResult.categories,
displayExamples: categorizationResult.hasExamples,
});
} catch (error) {
toasts.addError(error, {
@ -401,6 +403,7 @@ export const LogCategorizationPage: FC<LogCategorizationPageProps> = ({ embeddin
selectedCategory={selectedCategory}
setSelectedCategory={setSelectedCategory}
timefilter={timefilter}
displayExamples={data.displayExamples}
/>
) : null}
</EuiPageBody>

View file

@ -17,7 +17,7 @@ import {
createCategoryRequest,
} from '../../../common/api/log_categorization/create_category_request';
import { processCategoryResults } from '../../../common/api/log_categorization/process_category_results';
import type { Category, CatResponse } from '../../../common/api/log_categorization/types';
import type { CatResponse } from '../../../common/api/log_categorization/types';
import { useAiopsAppContext } from '../../hooks/use_aiops_app_context';
import {
@ -71,7 +71,7 @@ export function useCategorizeRequest() {
query: QueryDslQueryContainer,
intervalMs?: number,
additionalFilter?: CategorizationAdditionalFilter
): Promise<{ categories: Category[] }> => {
): Promise<ReturnType<typeof processCategoryResults>> => {
const { wrap, unwrap } = randomSampler.createRandomSamplerWrapper();
return new Promise((resolve, reject) => {
@ -101,7 +101,7 @@ export function useCategorizeRequest() {
},
error: (error) => {
if (error.name === 'AbortError') {
return resolve({ categories: [] });
return resolve({ categories: [], hasExamples: false });
}
reject(error);
},