Skip to content

Commit

Permalink
[ML] Update naming and refactor context
Browse files Browse the repository at this point in the history
- Refactor context -> legacyclient
- Update naming & formatted strings
- Update schema
- Update some functions to useCallback or useMemo
- Rename perPartitionStopOnWarn
  • Loading branch information
qn895 committed Aug 12, 2020
1 parent 1f3c5ec commit a94ecaf
Show file tree
Hide file tree
Showing 13 changed files with 86 additions and 72 deletions.
9 changes: 9 additions & 0 deletions x-pack/plugins/ml/common/types/results.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export interface GetStoppedPartitionResult {
jobs: string[] | Record<string, string[]>;
}
18 changes: 10 additions & 8 deletions x-pack/plugins/ml/public/application/explorer/explorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,14 +302,16 @@ export class Explorer extends React.Component {
{stoppedPartitions && (
<EuiCallOut
size={'s'}
title={i18n.translate('xpack.ml.explorer.stoppedPartitionsExistCallout', {
defaultMessage:
'There may be fewer results than there could have been because stop_on_warn is turned on. Both categorization and subsequent anomaly detection have stopped for some partitions in {jobsWithStoppedPartitions, plural, one {job} other {jobs}} [{stoppedPartitions}] where the categorization status has changed to warn.',
values: {
jobsWithStoppedPartitions: stoppedPartitions.length,
stoppedPartitions: stoppedPartitions.join(', '),
},
})}
title={
<FormattedMessage
id="xpack.ml.explorer.stoppedPartitionsExistCallout"
defaultMessage="There may be fewer results than there could have been because stop_on_warn is turned on. Both categorization and subsequent anomaly detection have stopped for some partitions in {jobsWithStoppedPartitions, plural, one {job} other {jobs}} [{stoppedPartitions}] where the categorization status has changed to warn."
values={{
jobsWithStoppedPartitions: stoppedPartitions.length,
stoppedPartitions: stoppedPartitions.join(', '),
}}
/>
}
/>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export class JobCreator {
private _stopAllRefreshPolls: {
stop: boolean;
} = { stop: false };
private _partitionField: string | null;
private _partitionField: string | null = null;

protected _wizardInitialized$ = new BehaviorSubject<boolean>(false);
public wizardInitialized$ = this._wizardInitialized$.asObservable();
Expand All @@ -82,7 +82,6 @@ export class JobCreator {
}

this._datafeed_config.query = query;
this._partitionField = null;
}

public get type(): JOB_TYPE {
Expand Down Expand Up @@ -645,11 +644,11 @@ export class JobCreator {
this._job_config.analysis_config.per_partition_categorization!.enabled = enabled;
}

public get partitionStopOnWarn() {
public get perPartitionStopOnWarn() {
return this._job_config.analysis_config.per_partition_categorization?.stop_on_warn === true;
}

public set partitionStopOnWarn(enabled: boolean) {
public set perPartitionStopOnWarn(enabled: boolean) {
this._initPerPartitionCategorization();
this._job_config.analysis_config.per_partition_categorization!.stop_on_warn = enabled;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,7 @@ export const ExtraSettings: FC = () => {
<SummaryCountField />
</EuiFlexItem>
</EuiFlexGroup>
{showCategorizationPerPartitionField && (
<EuiFlexGroup gutterSize="xl">
<EuiFlexItem>
<CategorizationPerPartitionField />
</EuiFlexItem>
</EuiFlexGroup>
)}
{showCategorizationPerPartitionField && <CategorizationPerPartitionField />}
</Fragment>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export const CategorizationPerPartitionField: FC = () => {
// if per-partition categorization is enabled
if (
jobCreator.perPartitionCategorization &&
jobCreator.categorizationPerPartitionField === null
jobCreator.categorizationPerPartitionField === null &&
filteredCategories.length > 0
) {
jobCreator.categorizationPerPartitionField = filteredCategories[0].id;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { FC, useContext } from 'react';
import React, { FC, useCallback, useContext, useMemo } from 'react';
import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui';

import { JobCreatorContext } from '../../../job_creator_context';
Expand All @@ -23,23 +23,30 @@ export const CategorizationPerPartitionFieldSelect: FC<Props> = ({
selectedField,
}) => {
const { jobCreator } = useContext(JobCreatorContext);
const options: EuiComboBoxOptionOption[] = [
...createFieldOptions(fields, jobCreator.additionalFields),
];

const selection: EuiComboBoxOptionOption[] = [];
if (selectedField !== null) {
selection.push({ label: selectedField });
}
const options: EuiComboBoxOptionOption[] = useMemo(
() => [...createFieldOptions(fields, jobCreator.additionalFields)],
[fields, jobCreator]
);

function onChange(selectedOptions: EuiComboBoxOptionOption[]) {
const option = selectedOptions[0];
if (typeof option !== 'undefined') {
changeHandler(option.label);
} else {
changeHandler(null);
const selection: EuiComboBoxOptionOption[] = useMemo(() => {
const selectedOptions: EuiComboBoxOptionOption[] = [];
if (selectedField !== null) {
selectedOptions.push({ label: selectedField });
}
}
return selectedOptions;
}, [selectedField]);

const onChange = useCallback(
(selectedOptions: EuiComboBoxOptionOption[]) => {
const option = selectedOptions[0];
if (typeof option !== 'undefined') {
changeHandler(option.label);
} else {
changeHandler(null);
}
},
[changeHandler]
);

return (
<EuiComboBox
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { FC, useContext, useEffect, useState } from 'react';
import React, { FC, useContext, useEffect, useCallback, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiSwitch } from '@elastic/eui';
import { JobCreatorContext } from '../../../job_creator_context';
Expand All @@ -17,13 +17,15 @@ export const CategorizationPerPartitionSwitch: FC = () => {
jobCreator.perPartitionCategorization
);

const toggleEnablePerPartitionCategorization = () =>
setEnablePerPartitionCategorization(!enablePerPartitionCategorization);
const toggleEnablePerPartitionCategorization = useCallback(
() => setEnablePerPartitionCategorization(!enablePerPartitionCategorization),
[enablePerPartitionCategorization]
);

useEffect(() => {
// also turn off stop on warn if per_partition_categorization is turned off
if (enablePerPartitionCategorization === false) {
jobCreator.partitionStopOnWarn = false;
jobCreator.perPartitionStopOnWarn = false;
}

jobCreator.perPartitionCategorization = enablePerPartitionCategorization;
Expand All @@ -32,7 +34,7 @@ export const CategorizationPerPartitionSwitch: FC = () => {

return (
<EuiSwitch
name="switch"
name="categorizationPerPartitionSwitch"
disabled={false}
checked={enablePerPartitionCategorization}
onChange={toggleEnablePerPartitionCategorization}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { FC, useContext, useEffect, useState } from 'react';
import React, { FC, useCallback, useContext, useEffect, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiSwitch } from '@elastic/eui';
import { JobCreatorContext } from '../../../job_creator_context';
Expand All @@ -13,18 +13,18 @@ import { AdvancedJobCreator, CategorizationJobCreator } from '../../../../../com
export const CategorizationPerPartitionStopOnWarnSwitch: FC = () => {
const { jobCreator: jc, jobCreatorUpdate } = useContext(JobCreatorContext);
const jobCreator = jc as AdvancedJobCreator | CategorizationJobCreator;
const [stopOnWarn, setStopOnWarn] = useState(jobCreator.partitionStopOnWarn);
const [stopOnWarn, setStopOnWarn] = useState(jobCreator.perPartitionStopOnWarn);

const toggleStopOnWarn = () => setStopOnWarn(!stopOnWarn);
const toggleStopOnWarn = useCallback(() => setStopOnWarn(!stopOnWarn), [stopOnWarn]);

useEffect(() => {
jobCreator.partitionStopOnWarn = stopOnWarn;
jobCreator.perPartitionStopOnWarn = stopOnWarn;
jobCreatorUpdate();
}, [stopOnWarn]);

return (
<EuiSwitch
name="switch"
name="categorizationPerPartitionStopOnWarnSwitch"
disabled={false}
checked={stopOnWarn}
onChange={toggleStopOnWarn}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
import { EuiDescribedFormGroup } from '@elastic/eui';

interface Props {
isOptional: boolean;
children: React.ReactNode;
}
export const Description: FC<Props> = memo(({ children }) => {
const title = i18n.translate('xpack.ml.newJob.wizard.perPartitionCategorization.enable.title', {
Expand Down
12 changes: 8 additions & 4 deletions x-pack/plugins/ml/public/application/routing/routes/explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { FC, useEffect, useState } from 'react';
import React, { FC, useEffect, useState, useCallback } from 'react';
import useObservable from 'react-use/lib/useObservable';

import { i18n } from '@kbn/i18n';
Expand Down Expand Up @@ -112,13 +112,17 @@ const ExplorerUrlStateManager: FC<ExplorerUrlStateManagerProps> = ({ jobsWithTim
}
}, [globalState?.time?.from, globalState?.time?.to]);

const getJobsWithStoppedPartitions = async (selectedJobIds: string[]) => {
const getJobsWithStoppedPartitions = useCallback(async (selectedJobIds: string[]) => {
try {
const fetchedStoppedPartitions = await ml.results.getStoppedPartitions(
selectedJobIds,
JOB_ID
);
if (fetchedStoppedPartitions.jobs.length > 0) {
if (
fetchedStoppedPartitions &&
Array.isArray(fetchedStoppedPartitions.jobs) &&
fetchedStoppedPartitions.jobs.length > 0
) {
setStoppedPartitions(fetchedStoppedPartitions.jobs);
} else {
setStoppedPartitions(undefined);
Expand All @@ -127,7 +131,7 @@ const ExplorerUrlStateManager: FC<ExplorerUrlStateManagerProps> = ({ jobsWithTim
// eslint-disable-next-line no-console
console.error(error);
}
};
});
useEffect(() => {
if (jobIds.length > 0) {
explorerService.updateJobSelection(jobIds);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
*/

// Service for obtaining data for the ML Results dashboards.
import { GetStoppedPartitionResult } from '../../../../common/types/results';
import { HttpService } from '../http_service';

import { basePath } from './index';

import { JobId } from '../../../../common/types/anomaly_detection_jobs';
import { JOB_ID, PARTITION_FIELD_VALUE } from '../../../../common/constants/anomalies';

import { PartitionFieldsDefinition } from '../results_service/result_service_rx';

export const resultsApiProvider = (httpService: HttpService) => ({
Expand Down Expand Up @@ -125,7 +123,7 @@ export const resultsApiProvider = (httpService: HttpService) => ({
jobIds,
fieldToBucket,
});
return httpService.http<any>({
return httpService.http<GetStoppedPartitionResult>({
path: `${basePath()}/results/stopped_partitions`,
method: 'POST',
body,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import _ from 'lodash';
import moment from 'moment';
import { SearchResponse } from 'elasticsearch';
import { ILegacyScopedClusterClient } from 'kibana/server';
import Boom from 'boom';
import { buildAnomalyTableItems } from './build_anomaly_table_items';
import { ML_RESULTS_INDEX_PATTERN } from '../../../common/constants/index_patterns';
import { ANOMALIES_TABLE_DEFAULT_QUERY_SIZE } from '../../../common/constants/search';
Expand All @@ -18,7 +19,7 @@ import {
AnomalyRecordDoc,
} from '../../../common/types/anomalies';
import { JOB_ID, PARTITION_FIELD_VALUE } from '../../../common/constants/anomalies';

import { GetStoppedPartitionResult } from '../../../common/types/results';
import { MlJobsResponse } from '../job_service/jobs';

// Service for carrying out Elasticsearch queries to obtain data for the
Expand All @@ -37,10 +38,6 @@ interface Influencer {
fieldValue: any;
}

export interface GetStoppedPartitionResult {
jobs: string[] | Record<string, string[]>;
}

export function resultsServiceProvider(mlClusterClient: ILegacyScopedClusterClient) {
const { callAsInternalUser } = mlClusterClient;
// Obtains data for the anomalies table, aggregating anomalies by day or hour as requested.
Expand Down Expand Up @@ -491,7 +488,7 @@ export function resultsServiceProvider(mlClusterClient: ILegacyScopedClusterClie
});

if (!jobConfigResponse || jobConfigResponse.jobs.length < 1) {
throw Error(`Unable to find anomaly detector jobs ${jobIds.join(', ')}`);
throw Boom.notFound(`Unable to find anomaly detector jobs ${jobIds.join(', ')}`);
}

const jobIdsWithStopOnWarnSet = jobConfigResponse.jobs
Expand Down
23 changes: 12 additions & 11 deletions x-pack/plugins/ml/server/routes/results_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,16 @@ function getPartitionFieldsValues(legacyClient: ILegacyScopedClusterClient, payl
return rs.getPartitionFieldsValues(jobId, searchTerm, criteriaFields, earliestMs, latestMs);
}

function getCategorizerStats(context: RequestHandlerContext, params: any, query: any) {
function getCategorizerStats(legacyClient: ILegacyScopedClusterClient, params: any, query: any) {
const { jobId } = params;
const { partitionByValue } = query;
const rs = resultsServiceProvider(context.ml!.mlClient);
const rs = resultsServiceProvider(legacyClient);
return rs.getCategorizerStats(jobId, partitionByValue);
}

function getStoppedPartitions(context: RequestHandlerContext, payload: any) {
function getStoppedPartitions(legacyClient: ILegacyScopedClusterClient, payload: any) {
const { jobIds, fieldToBucket } = payload;
const rs = resultsServiceProvider(context.ml!.mlClient);
const rs = resultsServiceProvider(legacyClient);
return rs.getStoppedPartitions(jobIds, fieldToBucket);
}

Expand Down Expand Up @@ -290,7 +290,8 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization)
* @api {get} /api/ml/results/:jobId/categorizer_stats
* @apiName GetCategorizerStats
* @apiDescription Returns the categorizer snapshots for the specified job ID
* @apiSchema (params) getCatergorizerStatsSchema
* @apiSchema (params) jobIdSchema
* @apiSchema (query) getCategorizerStatsSchema
*/
router.get(
{
Expand All @@ -303,9 +304,9 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization)
tags: ['access:ml:canGetJobs'],
},
},
mlLicense.fullLicenseAPIGuard(async (context, request, response) => {
mlLicense.fullLicenseAPIGuard(async ({ legacyClient, request, response }) => {
try {
const resp = await getCategorizerStats(context, request.params, request.query);
const resp = await getCategorizerStats(legacyClient, request.params, request.query);
return response.ok({
body: resp,
});
Expand All @@ -318,10 +319,10 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization)
/**
* @apiGroup ResultsService
*
* @api {get} /api/ml/results/:jobId/categorizer_stats
* @api {get} /api/ml/results/stopped_partitions
* @apiName GetStoppedPartitions
* @apiDescription Returns list of partitions we stopped categorizing whens status changed to warn
* @apiSchema (params) jobIdSchema
* @apiSchema (body) getStoppedPartitionsSchema
*/
router.post(
{
Expand All @@ -333,9 +334,9 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization)
tags: ['access:ml:canGetJobs'],
},
},
mlLicense.fullLicenseAPIGuard(async (context, request, response) => {
mlLicense.fullLicenseAPIGuard(async ({ legacyClient, request, response }) => {
try {
const resp = await getStoppedPartitions(context, request.body);
const resp = await getStoppedPartitions(legacyClient, request.body);
return response.ok({
body: resp,
});
Expand Down

0 comments on commit a94ecaf

Please sign in to comment.