[ML] Creating category validation package (#161261)

Moves the server and client side code which performs analysis on data to
see whether it is suitable for categorization.
This is currently only used by the categorization job wizard to display
this callout:

![image](08db5321-0c38-474d-9bfe-90b8a9ad984a)

However this analysis will be useful for the Log Pattern Analysis
feature and so moving the code to a package allows easier sharing
between ML and AIOPs plugins.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
James Gowdy 2023-07-19 12:34:29 +01:00 committed by GitHub
parent 85c85e90f9
commit 219426dc7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 354 additions and 126 deletions

1
.github/CODEOWNERS vendored
View file

@ -484,6 +484,7 @@ x-pack/plugins/maps @elastic/kibana-gis
x-pack/packages/maps/vector_tile_utils @elastic/kibana-gis
x-pack/packages/ml/agg_utils @elastic/ml-ui
x-pack/packages/ml/anomaly_utils @elastic/ml-ui
x-pack/packages/ml/category_validator @elastic/ml-ui
x-pack/packages/ml/data_frame_analytics_utils @elastic/ml-ui
x-pack/packages/ml/data_grid @elastic/ml-ui
x-pack/packages/ml/date_picker @elastic/ml-ui

View file

@ -500,6 +500,7 @@
"@kbn/maps-vector-tile-utils": "link:x-pack/packages/maps/vector_tile_utils",
"@kbn/ml-agg-utils": "link:x-pack/packages/ml/agg_utils",
"@kbn/ml-anomaly-utils": "link:x-pack/packages/ml/anomaly_utils",
"@kbn/ml-category-validator": "link:x-pack/packages/ml/category_validator",
"@kbn/ml-data-frame-analytics-utils": "link:x-pack/packages/ml/data_frame_analytics_utils",
"@kbn/ml-data-grid": "link:x-pack/packages/ml/data_grid",
"@kbn/ml-date-picker": "link:x-pack/packages/ml/date_picker",

View file

@ -962,6 +962,8 @@
"@kbn/ml-agg-utils/*": ["x-pack/packages/ml/agg_utils/*"],
"@kbn/ml-anomaly-utils": ["x-pack/packages/ml/anomaly_utils"],
"@kbn/ml-anomaly-utils/*": ["x-pack/packages/ml/anomaly_utils/*"],
"@kbn/ml-category-validator": ["x-pack/packages/ml/category_validator"],
"@kbn/ml-category-validator/*": ["x-pack/packages/ml/category_validator/*"],
"@kbn/ml-data-frame-analytics-utils": ["x-pack/packages/ml/data_frame_analytics_utils"],
"@kbn/ml-data-frame-analytics-utils/*": ["x-pack/packages/ml/data_frame_analytics_utils/*"],
"@kbn/ml-data-grid": ["x-pack/packages/ml/data_grid"],

View file

@ -54,6 +54,7 @@
"packages/ml/data_grid",
"packages/ml/date_picker",
"packages/ml/trained_models_utils",
"packages/ml/category_validator",
"plugins/ml"
],
"xpack.monitoring": ["plugins/monitoring"],

View file

@ -0,0 +1,3 @@
# @kbn/ml-category-validator
Provides functions for validating data to see whether it is suitable for categorization

View file

@ -6,76 +6,136 @@
*/
import { i18n } from '@kbn/i18n';
import { VALIDATION_RESULT } from '../types/categories';
export const NUMBER_OF_CATEGORY_EXAMPLES = 5;
/**
* The number of category examples to use for analysis.
*/
export const CATEGORY_EXAMPLES_SAMPLE_SIZE = 1000;
/**
* The warning limit for category examples. If the category examples validation falls below this limit, a warning is triggered.
*/
export const CATEGORY_EXAMPLES_WARNING_LIMIT = 0.75;
/**
* The error limit for category examples. If the category examples validation falls below this limit, an error is triggered.
*/
export const CATEGORY_EXAMPLES_ERROR_LIMIT = 0.02;
/**
* The valid token count for category examples.
*/
export const VALID_TOKEN_COUNT = 3;
/**
* The limit for the median line length of category examples.
*/
export const MEDIAN_LINE_LENGTH_LIMIT = 400;
/**
* The limit for the percentage of null values in category examples.
*/
export const NULL_COUNT_PERCENT_LIMIT = 0.75;
/**
* Enum representing the validation status of category examples.
*/
export enum CATEGORY_EXAMPLES_VALIDATION_STATUS {
VALID = 'valid',
PARTIALLY_VALID = 'partially_valid',
INVALID = 'invalid',
}
/**
* Enum representing the validation results for field examples.
*/
export enum VALIDATION_RESULT {
NO_EXAMPLES,
FAILED_TO_TOKENIZE,
TOO_MANY_TOKENS,
TOKEN_COUNT,
MEDIAN_LINE_LENGTH,
NULL_VALUES,
INSUFFICIENT_PRIVILEGES,
}
/**
* Description for each validation result.
*/
export const VALIDATION_CHECK_DESCRIPTION = {
/**
* Examples were successfully loaded.
*/
[VALIDATION_RESULT.NO_EXAMPLES]: i18n.translate(
'xpack.ml.models.jobService.categorization.messages.validNoDataFound',
{
defaultMessage: 'Examples were successfully loaded.',
defaultMessage: 'Examples were successfully loaded.',
}
),
) as string,
/**
* The loaded examples were tokenized successfully.
*/
[VALIDATION_RESULT.FAILED_TO_TOKENIZE]: i18n.translate(
'xpack.ml.models.jobService.categorization.messages.validFailureToGetTokens',
{
defaultMessage: 'The examples loaded were tokenized successfully.',
defaultMessage: 'The loaded examples were tokenized successfully.',
}
),
) as string,
/**
* More than {tokenCount} tokens per example were found in over {percentage}% of the loaded examples.
*/
[VALIDATION_RESULT.TOKEN_COUNT]: i18n.translate(
'xpack.ml.models.jobService.categorization.messages.validTokenLength',
{
defaultMessage:
'More than {tokenCount} tokens per example were found in over {percentage}% of the examples loaded.',
'More than {tokenCount} tokens per example were found in over {percentage}% of the loaded examples.',
values: {
percentage: Math.floor(CATEGORY_EXAMPLES_WARNING_LIMIT * 100),
tokenCount: VALID_TOKEN_COUNT,
},
}
),
) as string,
/**
* The median line length of the loaded examples was less than {medianCharCount} characters.
*/
[VALIDATION_RESULT.MEDIAN_LINE_LENGTH]: i18n.translate(
'xpack.ml.models.jobService.categorization.messages.validMedianLineLength',
{
defaultMessage:
'The median line length of the examples loaded was less than {medianCharCount} characters.',
'The median line length of the loaded examples was less than {medianCharCount} characters.',
values: {
medianCharCount: MEDIAN_LINE_LENGTH_LIMIT,
},
}
),
) as string,
/**
* Less than {percentage}% of the loaded examples were null.
*/
[VALIDATION_RESULT.NULL_VALUES]: i18n.translate(
'xpack.ml.models.jobService.categorization.messages.validNullValues',
{
defaultMessage: 'Less than {percentage}% of the examples loaded were null.',
defaultMessage: 'Less than {percentage}% of the loaded examples were null.',
values: {
percentage: Math.floor(100 - NULL_COUNT_PERCENT_LIMIT * 100),
},
}
),
) as string,
/**
* Less than 10000 tokens were found in total in the loaded examples.
*/
[VALIDATION_RESULT.TOO_MANY_TOKENS]: i18n.translate(
'xpack.ml.models.jobService.categorization.messages.validTooManyTokens',
{
defaultMessage: 'Less than 10000 tokens were found in total in the examples loaded.',
defaultMessage: 'Less than 10000 tokens were found in total in the loaded examples.',
}
),
) as string,
/**
* The user has sufficient privileges to perform the checks.
*/
[VALIDATION_RESULT.INSUFFICIENT_PRIVILEGES]: i18n.translate(
'xpack.ml.models.jobService.categorization.messages.validUserPrivileges',
{
defaultMessage: 'The user has sufficient privileges to perform the checks.',
}
),
) as string,
};

View file

@ -0,0 +1,81 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import {
CATEGORY_EXAMPLES_VALIDATION_STATUS,
VALIDATION_RESULT,
} from '../constants/categorization';
/**
* Token
*/
export interface Token {
/**
* The token string.
*/
token: string;
/**
* The starting offset of the token.
*/
start_offset: number;
/**
* The ending offset of the token.
*/
end_offset: number;
/**
* The type of the token.
*/
type: string;
/**
* The position of the token.
*/
position: number;
}
/**
* Categorization analyzer with additional properties.
*/
export type CategorizationAnalyzer = estypes.MlCategorizationAnalyzerDefinition & {
/**
* The analyzer used for categorization.
*/
analyzer?: string;
};
/**
* Field example for a category.
*/
export interface CategoryFieldExample {
/**
* The text of the field example.
*/
text: string;
/**
* The tokens extracted from the field example.
*/
tokens: Token[];
}
/**
* Result of a field example check.
*/
export interface FieldExampleCheck {
/**
* The ID of the validation result.
*/
id: VALIDATION_RESULT;
/**
* The validation status of the field example.
*/
valid: CATEGORY_EXAMPLES_VALIDATION_STATUS;
/**
* The message associated with the validation result.
*/
message: string;
}

View file

@ -0,0 +1,25 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export { categorizationExamplesProvider } from './src/examples';
export type {
CategorizationAnalyzer,
CategoryFieldExample,
FieldExampleCheck,
Token,
} from './common/types/categories';
export {
CATEGORY_EXAMPLES_ERROR_LIMIT,
CATEGORY_EXAMPLES_SAMPLE_SIZE,
CATEGORY_EXAMPLES_VALIDATION_STATUS,
CATEGORY_EXAMPLES_WARNING_LIMIT,
MEDIAN_LINE_LENGTH_LIMIT,
NULL_COUNT_PERCENT_LIMIT,
VALID_TOKEN_COUNT,
VALIDATION_CHECK_DESCRIPTION,
VALIDATION_RESULT,
} from './common/constants/categorization';

View file

@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../../../..',
roots: ['<rootDir>/x-pack/packages/ml/category_validator'],
};

View file

@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/ml-category-validator",
"owner": "@elastic/ml-ui"
}

View file

@ -0,0 +1,6 @@
{
"name": "@kbn/ml-category-validator",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0"
}

View file

@ -7,29 +7,53 @@
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { IScopedClusterClient } from '@kbn/core/server';
import { chunk } from 'lodash';
import type { IScopedClusterClient } from '@kbn/core/server';
import type { RuntimeMappings } from '@kbn/ml-runtime-field-utils';
import { CATEGORY_EXAMPLES_SAMPLE_SIZE } from '../../../../../common/constants/categorization_job';
import {
import { CATEGORY_EXAMPLES_SAMPLE_SIZE } from '../common/constants/categorization';
import type {
Token,
CategorizationAnalyzer,
CategoryFieldExample,
} from '../../../../../common/types/categories';
import { IndicesOptions } from '../../../../../common/types/anomaly_detection_jobs';
} from '../common/types/categories';
import { ValidationResults } from './validation_results';
/**
* The size of each chunk for processing examples.
*
*/
const CHUNK_SIZE = 100;
export function categorizationExamplesProvider({
asCurrentUser,
asInternalUser,
}: IScopedClusterClient) {
/**
* Provides methods for checking whether categories can be
* produced from a field.
*
* @export
* @param client - IScopedClusterClient
*/
export function categorizationExamplesProvider(client: IScopedClusterClient) {
const { asCurrentUser, asInternalUser } = client;
const validationResults = new ValidationResults();
/**
* Retrieves the tokens for the provided examples and analyzer.
*
* @async
* @param {string} indexPatternTitle
* @param {estypes.QueryDslQueryContainer} query
* @param {number} size
* @param {string} categorizationFieldName
* @param {(string | undefined)} timeField
* @param {number} start
* @param {number} end
* @param {CategorizationAnalyzer} analyzer
* @param {(RuntimeMappings | undefined)} runtimeMappings
* @param {(estypes.IndicesOptions | undefined)} indicesOptions
* @returns {Promise<{ examples: CategoryFieldExample[]; error?: Error }>}
*/
async function categorizationExamples(
indexPatternTitle: string,
query: any,
query: estypes.QueryDslQueryContainer,
size: number,
categorizationFieldName: string,
timeField: string | undefined,
@ -37,8 +61,8 @@ export function categorizationExamplesProvider({
end: number,
analyzer: CategorizationAnalyzer,
runtimeMappings: RuntimeMappings | undefined,
indicesOptions: IndicesOptions | undefined
): Promise<{ examples: CategoryFieldExample[]; error?: any }> {
indicesOptions: estypes.IndicesOptions | undefined
): Promise<{ examples: CategoryFieldExample[]; error?: Error }> {
if (timeField !== undefined) {
const range = {
range: {
@ -178,7 +202,7 @@ export function categorizationExamplesProvider({
async function validateCategoryExamples(
indexPatternTitle: string,
query: any,
query: estypes.QueryDslQueryContainer,
size: number,
categorizationFieldName: string,
timeField: string | undefined,
@ -186,7 +210,7 @@ export function categorizationExamplesProvider({
end: number,
analyzer: CategorizationAnalyzer,
runtimeMappings: RuntimeMappings | undefined,
indicesOptions: IndicesOptions | undefined
indicesOptions: estypes.IndicesOptions | undefined
) {
const resp = await categorizationExamples(
indexPatternTitle,

View file

@ -0,0 +1,11 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export function getMedianStringLength(strings: string[]) {
const sortedStringLengths = strings.map((s) => s.length).sort((a, b) => a - b);
return sortedStringLengths[Math.floor(sortedStringLengths.length / 2)] || 0;
}

View file

@ -13,13 +13,10 @@ import {
CATEGORY_EXAMPLES_VALIDATION_STATUS,
CATEGORY_EXAMPLES_ERROR_LIMIT,
CATEGORY_EXAMPLES_WARNING_LIMIT,
} from '../../../../../common/constants/categorization_job';
import {
FieldExampleCheck,
CategoryFieldExample,
VALIDATION_RESULT,
} from '../../../../../common/types/categories';
import { getMedianStringLength } from '../../../../../common/util/string_utils';
} from '../common/constants/categorization';
import type { FieldExampleCheck, CategoryFieldExample } from '../common/types/categories';
import { getMedianStringLength } from './util';
export class ValidationResults {
private _results: FieldExampleCheck[] = [];

View file

@ -0,0 +1,21 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node"
]
},
"include": [
"**/*.ts",
],
"exclude": [
"target/**/*"
],
"kbn_references": [
"@kbn/i18n",
"@kbn/core",
"@kbn/ml-runtime-field-utils",
]
}

View file

@ -33,3 +33,5 @@ export const DEFAULT_RARE_BUCKET_SPAN = '1h';
export const DEFAULT_QUERY_DELAY = '60s';
export const SHARED_RESULTS_INDEX_NAME = 'shared';
export const NUMBER_OF_CATEGORY_EXAMPLES = 5;

View file

@ -5,8 +5,6 @@
* 2.0.
*/
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../constants/categorization_job';
export type CategoryId = number;
export interface Category {
@ -20,39 +18,3 @@ export interface Category {
partition_field_name?: string; // TODO: make non-optional once fields have been added to the results
partition_field_value?: string; // TODO: make non-optional once fields have been added to the results
}
export interface Token {
token: string;
start_offset: number;
end_offset: number;
type: string;
position: number;
}
export interface CategorizationAnalyzer {
char_filter?: any[];
tokenizer?: string;
filter?: any[];
analyzer?: string;
}
export interface CategoryFieldExample {
text: string;
tokens: Token[];
}
export enum VALIDATION_RESULT {
NO_EXAMPLES,
FAILED_TO_TOKENIZE,
TOO_MANY_TOKENS,
TOKEN_COUNT,
MEDIAN_LINE_LENGTH,
NULL_VALUES,
INSUFFICIENT_PRIVILEGES,
}
export interface FieldExampleCheck {
id: VALIDATION_RESULT;
valid: CATEGORY_EXAMPLES_VALIDATION_STATUS;
message: string;
}

View file

@ -5,14 +5,14 @@
* 2.0.
*/
import { CategorizationAnalyzer } from './categories';
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
export interface MlServerDefaults {
anomaly_detectors: {
categorization_examples_limit?: number;
model_memory_limit?: string;
model_snapshot_retention_days?: number;
categorization_analyzer?: CategorizationAnalyzer;
categorization_analyzer?: estypes.MlCategorizationAnalyzerDefinition;
};
datafeeds: { scroll_size?: number };
}

View file

@ -14,8 +14,19 @@ import {
ML_JOB_AGGREGATION,
} from '@kbn/ml-anomaly-utils';
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
import {
type CategorizationAnalyzer,
type CategoryFieldExample,
type FieldExampleCheck,
VALIDATION_RESULT,
CATEGORY_EXAMPLES_VALIDATION_STATUS,
} from '@kbn/ml-category-validator';
import { JobCreator } from './job_creator';
import { Job, Datafeed, Detector } from '../../../../../../common/types/anomaly_detection_jobs';
import type {
Job,
Datafeed,
Detector,
} from '../../../../../../common/types/anomaly_detection_jobs';
import { createBasicDetector } from './util/default_configs';
import {
JOB_TYPE,
@ -23,13 +34,7 @@ import {
DEFAULT_BUCKET_SPAN,
DEFAULT_RARE_BUCKET_SPAN,
} from '../../../../../../common/constants/new_job';
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../../../common/constants/categorization_job';
import {
CategorizationAnalyzer,
CategoryFieldExample,
FieldExampleCheck,
VALIDATION_RESULT,
} from '../../../../../../common/types/categories';
import { getRichDetectors } from './util/general';
import { CategorizationExamplesLoader } from '../results_loader';
import { getNewJobDefaults } from '../../../../services/ml_server_info';

View file

@ -8,6 +8,7 @@
import { ReactElement } from 'react';
import { combineLatest, Observable, ReplaySubject, Subject } from 'rxjs';
import { map, startWith, tap } from 'rxjs/operators';
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '@kbn/ml-category-validator';
import {
basicJobValidation,
basicDatafeedValidation,
@ -24,7 +25,7 @@ import {
JobExistsResult,
GroupsExistResult,
} from './validators';
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../../../common/constants/categorization_job';
import { JOB_TYPE } from '../../../../../../common/constants/new_job';
// delay start of validation to allow the user to make changes

View file

@ -6,13 +6,11 @@
*/
import type { DataView } from '@kbn/data-views-plugin/public';
import { IndexPatternTitle } from '../../../../../../common/types/kibana';
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '@kbn/ml-category-validator';
import { NUMBER_OF_CATEGORY_EXAMPLES } from '../../../../../../common/constants/new_job';
import type { IndexPatternTitle } from '../../../../../../common/types/kibana';
import { CategorizationJobCreator } from '../job_creator';
import { ml } from '../../../../services/ml_api_service';
import {
NUMBER_OF_CATEGORY_EXAMPLES,
CATEGORY_EXAMPLES_VALIDATION_STATUS,
} from '../../../../../../common/constants/categorization_job';
export class CategorizationExamplesLoader {
private _jobCreator: CategorizationJobCreator;

View file

@ -18,15 +18,14 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import {
CategorizationAnalyzer,
FieldExampleCheck,
} from '../../../../../../../../../common/types/categories';
import { EditCategorizationAnalyzerFlyout } from '../../../common/edit_categorization_analyzer_flyout';
import {
type CategorizationAnalyzer,
type FieldExampleCheck,
VALIDATION_RESULT,
CATEGORY_EXAMPLES_VALIDATION_STATUS,
VALIDATION_CHECK_DESCRIPTION,
} from '../../../../../../../../../common/constants/categorization_job';
import { VALIDATION_RESULT } from '../../../../../../../../../common/types/categories';
} from '@kbn/ml-category-validator';
import { EditCategorizationAnalyzerFlyout } from '../../../common/edit_categorization_analyzer_flyout';
interface Props {
validationChecks: FieldExampleCheck[];
@ -96,9 +95,12 @@ export const ExamplesValidCallout: FC<Props> = ({
const AnalyzerUsed: FC<{ categorizationAnalyzer: CategorizationAnalyzer }> = ({
categorizationAnalyzer,
}) => {
let analyzer = '';
let analyzer: string | null = null;
if (categorizationAnalyzer?.tokenizer !== undefined) {
if (
categorizationAnalyzer?.tokenizer !== undefined &&
typeof categorizationAnalyzer.tokenizer === 'string'
) {
analyzer = categorizationAnalyzer.tokenizer;
} else if (categorizationAnalyzer?.analyzer !== undefined) {
analyzer = categorizationAnalyzer.analyzer;
@ -106,13 +108,15 @@ const AnalyzerUsed: FC<{ categorizationAnalyzer: CategorizationAnalyzer }> = ({
return (
<>
<div>
<FormattedMessage
id="xpack.ml.newJob.wizard.pickFieldsStep.categorizationFieldAnalyzer"
defaultMessage="Analyzer used: {analyzer}"
values={{ analyzer }}
/>
</div>
{analyzer !== null ? (
<div>
<FormattedMessage
id="xpack.ml.newJob.wizard.pickFieldsStep.categorizationFieldAnalyzer"
defaultMessage="Analyzer used: {analyzer}"
values={{ analyzer }}
/>
</div>
) : null}
<div>
<EditCategorizationAnalyzerFlyout />
</div>

View file

@ -8,7 +8,7 @@
import React, { FC } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiBasicTable, EuiCodeBlock } from '@elastic/eui';
import { CategoryFieldExample } from '../../../../../../../../../common/types/categories';
import { CategoryFieldExample } from '@kbn/ml-category-validator';
interface Props {
fieldExamples: CategoryFieldExample[] | null;

View file

@ -7,6 +7,11 @@
import React, { FC, useContext, useEffect, useState } from 'react';
import { EuiHorizontalRule } from '@elastic/eui';
import {
CATEGORY_EXAMPLES_VALIDATION_STATUS,
type CategoryFieldExample,
type FieldExampleCheck,
} from '@kbn/ml-category-validator';
import { getToastNotificationService } from '../../../../../../../services/toast_notification_service';
import { JobCreatorContext } from '../../../job_creator_context';
@ -18,11 +23,6 @@ import { CategorizationPerPartitionField } from '../categorization_partition_fie
import { FieldExamples } from './field_examples';
import { ExamplesValidCallout } from './examples_valid_callout';
import { InvalidCssVersionCallout } from './invalid_ccs_version_valid_callout';
import {
CategoryFieldExample,
FieldExampleCheck,
} from '../../../../../../../../../common/types/categories';
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../../../../../../common/constants/categorization_job';
import { LoadingWrapper } from '../../../charts/loading_wrapper';
interface Props {

View file

@ -9,12 +9,12 @@ import React, { FC, useContext, useEffect, useState } from 'react';
import { EuiBasicTable, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { extractErrorProperties } from '@kbn/ml-error-utils';
import { NUMBER_OF_CATEGORY_EXAMPLES } from '../../../../../../../../../common/constants/new_job';
import { JobCreatorContext } from '../../../job_creator_context';
import { CategorizationJobCreator } from '../../../../../common/job_creator';
import { Results } from '../../../../../common/results_loader';
import { ml } from '../../../../../../../services/ml_api_service';
import { useToastNotificationService } from '../../../../../../../services/toast_notification_service';
import { NUMBER_OF_CATEGORY_EXAMPLES } from '../../../../../../../../../common/constants/categorization_job';
export const TopCategories: FC = () => {
const { displayErrorToast } = useToastNotificationService();

View file

@ -9,6 +9,12 @@ import { Observable } from 'rxjs';
import { useMemo } from 'react';
import type { AggFieldNamePair } from '@kbn/ml-anomaly-utils';
import type { RuntimeMappings } from '@kbn/ml-runtime-field-utils';
import {
type CategorizationAnalyzer,
type CategoryFieldExample,
type FieldExampleCheck,
CATEGORY_EXAMPLES_VALIDATION_STATUS,
} from '@kbn/ml-category-validator';
import { HttpService } from '../http_service';
import { useMlKibana } from '../../contexts/kibana';
@ -25,12 +31,7 @@ import type { JobMessage } from '../../../../common/types/audit_message';
import type { JobAction } from '../../../../common/constants/job_actions';
import type { Group } from '../../../../common/types/groups';
import type { ExistingJobsAndGroups } from '../job_service';
import type {
CategorizationAnalyzer,
CategoryFieldExample,
FieldExampleCheck,
} from '../../../../common/types/categories';
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '../../../../common/constants/categorization_job';
import type { Category } from '../../../../common/types/categories';
import type {
JobsExistResponse,

View file

@ -5,5 +5,4 @@
* 2.0.
*/
export { categorizationExamplesProvider } from './examples';
export { topCategoriesProvider } from './top_categories';

View file

@ -7,7 +7,7 @@
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { CategoryId, Category } from '../../../../../common/types/categories';
import type { CategoryId, Category } from '../../../../../common/types/categories';
import type { MlClient } from '../../../../lib/ml_client';
export function topCategoriesProvider(mlClient: MlClient) {

View file

@ -6,4 +6,4 @@
*/
export { newJobChartsProvider } from './charts';
export { categorizationExamplesProvider, topCategoriesProvider } from './categorization';
export { topCategoriesProvider } from './categorization';

View file

@ -7,6 +7,7 @@
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { schema } from '@kbn/config-schema';
import { categorizationExamplesProvider } from '@kbn/ml-category-validator';
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { wrapError } from '../client/error_wrapper';
import type { RouteInitialization } from '../types';
@ -32,7 +33,6 @@ import {
import { jobIdSchema } from './schemas/anomaly_detectors_schema';
import { jobServiceProvider } from '../models/job_service';
import { categorizationExamplesProvider } from '../models/job_service/new_job';
import { getAuthorizationHeader } from '../lib/request_authorization';
import type { Datafeed, Job } from '../../common/types/anomaly_detection_jobs';

View file

@ -95,6 +95,7 @@
"@kbn/ml-kibana-theme",
"@kbn/ml-runtime-field-utils",
"@kbn/ml-date-utils",
"@kbn/ml-category-validator",
"@kbn/deeplinks-ml",
"@kbn/core-notifications-browser-mocks",
"@kbn/unified-field-list",

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '@kbn/ml-plugin/common/constants/categorization_job';
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '@kbn/ml-category-validator';
import type { FtrProviderContext } from '../../../ftr_provider_context';
import type { FieldStatsType } from '../common/types';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '@kbn/ml-plugin/common/constants/categorization_job';
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '@kbn/ml-category-validator';
import type { PickFieldsConfig, DatafeedConfig, Detector } from './types';
import type { FtrProviderContext } from '../../../ftr_provider_context';

View file

@ -7,7 +7,7 @@
import expect from '@kbn/expect';
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '@kbn/ml-plugin/common/constants/categorization_job';
import { CATEGORY_EXAMPLES_VALIDATION_STATUS } from '@kbn/ml-category-validator';
import type { FtrProviderContext } from '../../ftr_provider_context';
import type { MlCommonFieldStatsFlyout } from './field_stats_flyout';

View file

@ -135,6 +135,7 @@
"@kbn/profiling-plugin",
"@kbn/observability-onboarding-plugin",
"@kbn/bfetch-plugin",
"@kbn/uptime-plugin"
"@kbn/uptime-plugin",
"@kbn/ml-category-validator"
]
}

View file

@ -4658,6 +4658,10 @@
version "0.0.0"
uid ""
"@kbn/ml-category-validator@link:x-pack/packages/ml/category_validator":
version "0.0.0"
uid ""
"@kbn/ml-data-frame-analytics-utils@link:x-pack/packages/ml/data_frame_analytics_utils":
version "0.0.0"
uid ""