Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ML] Explain log rate spikes: adds table sorting #137110

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ export function ProgressControls({
<EuiFlexItem grow={false}>
{!isRunning && (
<EuiButton size="s" onClick={onRefresh}>
<FormattedMessage id="xpack.aiops.refreshButtonTitle" defaultMessage="Refresh" />
<FormattedMessage
id="xpack.aiops.rerunAnalysisButtonTitle"
defaultMessage="Rerun analysis"
/>
</EuiButton>
)}
{isRunning && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,17 @@
*/

import React, { FC, useCallback, useMemo, useState } from 'react';
import { EuiBadge, EuiBasicTable, EuiBasicTableColumn } from '@elastic/eui';
import {
EuiBadge,
EuiBasicTable,
EuiBasicTableColumn,
EuiTableSortingType,
EuiToolTip,
} from '@elastic/eui';
import { sortBy } from 'lodash';

import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import type { ChangePoint } from '@kbn/ml-agg-utils';

import { MiniHistogram } from '../mini_histogram';
Expand All @@ -18,6 +27,8 @@ const PAGINATION_SIZE_OPTIONS = [5, 10, 20, 50];
const noDataText = i18n.translate('xpack.aiops.correlations.correlationsTable.noDataText', {
defaultMessage: 'No data',
});
const DEFAULT_SORT_FIELD = 'pValue';
const DEFAULT_SORT_DIRECTION = 'asc';

interface SpikeAnalysisTableProps {
changePoints: ChangePoint[];
Expand All @@ -38,6 +49,8 @@ export const SpikeAnalysisTable: FC<SpikeAnalysisTableProps> = ({
}) => {
const [pageIndex, setPageIndex] = useState(0);
const [pageSize, setPageSize] = useState(10);
const [sortField, setSortField] = useState(DEFAULT_SORT_FIELD);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest to use const [sortField, setSortField] = useState<keyof ChangePoint>(DEFAULT_SORT_FIELD); to limit allowed fields to ChangePoint attributes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call - updated in 2ce5f5a

const [sortDirection, setSortDirection] = useState(DEFAULT_SORT_DIRECTION);

const columns: Array<EuiBasicTableColumn<ChangePoint>> = [
{
Expand All @@ -60,14 +73,21 @@ export const SpikeAnalysisTable: FC<SpikeAnalysisTableProps> = ({
{
field: 'pValue',
name: (
<>
{i18n.translate(
'xpack.aiops.correlations.failedTransactions.correlationsTable.logRateLabel',
<EuiToolTip
Copy link
Contributor

@lcawl lcawl Jul 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other apps I'm used to seeing "?" icons that indicate that there's something to read. For example in failed_transactions_correlations.tsx

position="top"
content={i18n.translate(
'xpack.aiops.correlations.failedTransactions.correlationsTable.logRateColumnTooltip',
{
defaultMessage: 'Log rate',
defaultMessage:
'A visual representation of the amount of impact the given field name and value have on the message rate difference.',
lcawl marked this conversation as resolved.
Show resolved Hide resolved
}
)}
</>
>
<FormattedMessage
id="xpack.aiops.correlations.failedTransactions.correlationsTable.logRateLabel"
defaultMessage="Log rate"
/>
</EuiToolTip>
),
render: (_, { histogram, fieldName, fieldValue }) => {
return histogram ? (
Expand All @@ -78,56 +98,87 @@ export const SpikeAnalysisTable: FC<SpikeAnalysisTableProps> = ({
},
{
field: 'pValue',
name: 'p-value',
name: (
<EuiToolTip
position="top"
content={i18n.translate(
'xpack.aiops.correlations.failedTransactions.correlationsTable.pValueColumnTooltip',
{
defaultMessage:
'For statistically significant changes in the frequency of values, indicates how extreme the change is; lower values indicate greater change.',
lcawl marked this conversation as resolved.
Show resolved Hide resolved
}
)}
>
<FormattedMessage
id="xpack.aiops.correlations.failedTransactions.correlationsTable.pValueLabel"
defaultMessage="p-value"
/>
</EuiToolTip>
),
render: (pValue: number) => pValue.toPrecision(3),
sortable: true,
},
{
field: 'pValue',
name: (
<>
{i18n.translate(
'xpack.aiops.correlations.failedTransactions.correlationsTable.impactLabel',
<EuiToolTip
position="top"
content={i18n.translate(
'xpack.aiops.correlations.failedTransactions.correlationsTable.impactLabelColumnTooltip',
{
defaultMessage: 'Impact',
defaultMessage:
'Indicates the level of impact of the given field name and value on the message rate difference.',
lcawl marked this conversation as resolved.
Show resolved Hide resolved
}
)}
</>
>
<FormattedMessage
id="xpack.aiops.correlations.failedTransactions.correlationsTable.impactLabel"
defaultMessage="Impact"
/>
</EuiToolTip>
),
render: (_, { pValue }) => {
const label = getFailedTransactionsCorrelationImpactLabel(pValue);
return label ? <EuiBadge color={label.color}>{label.impact}</EuiBadge> : null;
},
sortable: true,
sortable: false,
peteharverson marked this conversation as resolved.
Show resolved Hide resolved
},
];

const onChange = useCallback((tableSettings) => {
const { index, size } = tableSettings.page;
const { field, direction } = tableSettings.sort;

setPageIndex(index);
setPageSize(size);
setSortField(field);
setSortDirection(direction);
}, []);

const { pagination, pageOfItems } = useMemo(() => {
const { pagination, pageOfItems, sorting } = useMemo(() => {
const pageStart = pageIndex * pageSize;

const itemCount = changePoints?.length ?? 0;

let items = changePoints ?? [];
items = sortBy(changePoints, (item: ChangePoint) => item[sortField as keyof ChangePoint]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the type is set on the first assignment the sorting line could be simpler:

let items: ChangePoint[] = changePoints ?? [];
items = sortBy(changePoints, (item) => item[sortField]);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use case-insensitive sort?

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in 2ce5f5a

items = sortDirection === 'asc' ? items : items.reverse();

return {
pageOfItems: changePoints
// Temporary default sorting by ascending pValue until we add native table sorting
?.sort((a, b) => {
return (a?.pValue ?? 1) - (b?.pValue ?? 0);
})
.slice(pageStart, pageStart + pageSize),
pageOfItems: items.slice(pageStart, pageStart + pageSize),
pagination: {
pageIndex,
pageSize,
totalItemCount: itemCount,
pageSizeOptions: PAGINATION_SIZE_OPTIONS,
},
sorting: {
sort: {
field: sortField,
direction: sortDirection,
},
},
};
}, [pageIndex, pageSize, changePoints]);
}, [pageIndex, pageSize, sortField, sortDirection, changePoints]);

return (
<EuiBasicTable
Expand All @@ -139,7 +190,7 @@ export const SpikeAnalysisTable: FC<SpikeAnalysisTableProps> = ({
pagination={pagination}
loading={loading}
error={error}
// sorting={sorting}
sorting={sorting as EuiTableSortingType<ChangePoint>}
rowProps={(changePoint) => {
return {
onClick: () => {
Expand Down