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] New Platform server shim: update filters routes to use new platform router #57597

Merged
merged 4 commits into from
Feb 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@
* Contains values for ML job detector rules.
*/

export const ACTION = {
SKIP_MODEL_UPDATE: 'skip_model_update',
SKIP_RESULT: 'skip_result',
};
export enum ACTION {
SKIP_MODEL_UPDATE = 'skip_model_update',
SKIP_RESULT = 'skip_result',
}

export const FILTER_TYPE = {
EXCLUDE: 'exclude',
INCLUDE: 'include',
};
export enum FILTER_TYPE {
EXCLUDE = 'exclude',
INCLUDE = 'include',
}

export const APPLIES_TO = {
ACTUAL: 'actual',
DIFF_FROM_TYPICAL: 'diff_from_typical',
TYPICAL: 'typical',
};
export enum APPLIES_TO {
ACTUAL = 'actual',
DIFF_FROM_TYPICAL = 'diff_from_typical',
TYPICAL = 'typical',
}

export const OPERATOR = {
LESS_THAN: 'lt',
LESS_THAN_OR_EQUAL: 'lte',
GREATER_THAN: 'gt',
GREATER_THAN_OR_EQUAL: 'gte',
};
export enum OPERATOR {
LESS_THAN = 'lt',
LESS_THAN_OR_EQUAL = 'lte',
GREATER_THAN = 'gt',
GREATER_THAN_OR_EQUAL = 'gte',
}

// List of detector functions which don't support rules with numeric conditions.
export const CONDITIONS_NOT_SUPPORTED_FUNCTIONS = ['freq_rare', 'lat_long', 'metric', 'rare'];
26 changes: 26 additions & 0 deletions x-pack/legacy/plugins/ml/common/types/detector_rules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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.
*/

import { ACTION, FILTER_TYPE, APPLIES_TO, OPERATOR } from '../constants/detector_rule';

export interface DetectorRuleScope {
[id: string]: {
filter_id: string;
filter_type: FILTER_TYPE;
};
}

export interface DetectorRuleCondition {
applies_to: APPLIES_TO;
operator: OPERATOR;
value: number;
}

export interface DetectorRule {
actions: ACTION[];
scope?: DetectorRuleScope;
conditions?: DetectorRuleCondition[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,75 @@
*/

import Boom from 'boom';
import { IScopedClusterClient } from 'src/core/server';

import { DetectorRule, DetectorRuleScope } from '../../../common/types/detector_rules';

export interface Filter {
filter_id: string;
description?: string;
items: string[];
}

export interface FormFilter {
filterId: string;
description?: string;
addItems?: string[];
removeItems?: string[];
}

export interface FilterRequest {
filter_id: string;
description?: string;
add_items?: string[];
remove_items?: string[];
}

interface FilterUsage {
jobs: string[];
detectors: string[];
}

interface FilterStats {
filter_id: string;
description?: string;
item_count: number;
used_by: FilterUsage;
}

interface FiltersInUse {
[id: string]: FilterUsage;
}

interface PartialDetector {
detector_description: string;
custom_rules: DetectorRule[];
}

interface PartialJob {
job_id: string;
analysis_config: {
detectors: PartialDetector[];
};
}

export class FilterManager {
constructor(callWithRequest) {
this.callWithRequest = callWithRequest;
private _client: IScopedClusterClient['callAsCurrentUser'];

constructor(client: IScopedClusterClient['callAsCurrentUser']) {
this._client = client;
}

async getFilter(filterId) {
async getFilter(filterId: string) {
try {
const [JOBS, FILTERS] = [0, 1];
const results = await Promise.all([
this.callWithRequest('ml.jobs'),
this.callWithRequest('ml.filters', { filterId }),
this._client('ml.jobs'),
this._client('ml.filters', { filterId }),
]);

if (results[FILTERS] && results[FILTERS].filters.length) {
let filtersInUse = {};
let filtersInUse: FiltersInUse = {};
if (results[JOBS] && results[JOBS].jobs) {
filtersInUse = this.buildFiltersInUse(results[JOBS].jobs);
}
Expand All @@ -38,7 +91,7 @@ export class FilterManager {

async getAllFilters() {
try {
const filtersResp = await this.callWithRequest('ml.filters');
const filtersResp = await this._client('ml.filters');
return filtersResp.filters;
} catch (error) {
throw Boom.badRequest(error);
Expand All @@ -48,13 +101,10 @@ export class FilterManager {
async getAllFilterStats() {
try {
const [JOBS, FILTERS] = [0, 1];
const results = await Promise.all([
this.callWithRequest('ml.jobs'),
this.callWithRequest('ml.filters'),
]);
const results = await Promise.all([this._client('ml.jobs'), this._client('ml.filters')]);

// Build a map of filter_ids against jobs and detectors using that filter.
let filtersInUse = {};
let filtersInUse: FiltersInUse = {};
if (results[JOBS] && results[JOBS].jobs) {
filtersInUse = this.buildFiltersInUse(results[JOBS].jobs);
}
Expand All @@ -64,10 +114,10 @@ export class FilterManager {
// description
// item_count
// jobs using the filter
const filterStats = [];
const filterStats: FilterStats[] = [];
if (results[FILTERS] && results[FILTERS].filters) {
results[FILTERS].filters.forEach(filter => {
const stats = {
results[FILTERS].filters.forEach((filter: Filter) => {
const stats: FilterStats = {
filter_id: filter.filter_id,
description: filter.description,
item_count: filter.items.length,
Expand All @@ -83,32 +133,32 @@ export class FilterManager {
}
}

async newFilter(filter) {
async newFilter(filter: FormFilter) {
const filterId = filter.filterId;
delete filter.filterId;
try {
// Returns the newly created filter.
return await this.callWithRequest('ml.addFilter', { filterId, body: filter });
return await this._client('ml.addFilter', { filterId, body: filter });
} catch (error) {
throw Boom.badRequest(error);
}
}

async updateFilter(filterId, description, addItems, removeItems) {
async updateFilter(filterId: string, filter: FormFilter) {
try {
const body = {};
if (description !== undefined) {
body.description = description;
const body: FilterRequest = { filter_id: filterId };
if (filter.description !== undefined) {
body.description = filter.description;
}
if (addItems !== undefined) {
body.add_items = addItems;
if (filter.addItems !== undefined) {
body.add_items = filter.addItems;
}
if (removeItems !== undefined) {
body.remove_items = removeItems;
if (filter.removeItems !== undefined) {
body.remove_items = filter.removeItems;
}

// Returns the newly updated filter.
return await this.callWithRequest('ml.updateFilter', {
return await this._client('ml.updateFilter', {
filterId,
body,
});
Expand All @@ -117,23 +167,24 @@ export class FilterManager {
}
}

async deleteFilter(filterId) {
return this.callWithRequest('ml.deleteFilter', { filterId });
async deleteFilter(filterId: string) {
return this._client('ml.deleteFilter', { filterId });
}

buildFiltersInUse(jobsList) {
buildFiltersInUse(jobsList: PartialJob[]) {
// Build a map of filter_ids against jobs and detectors using that filter.
const filtersInUse = {};
const filtersInUse: FiltersInUse = {};
jobsList.forEach(job => {
const detectors = job.analysis_config.detectors;
detectors.forEach(detector => {
if (detector.custom_rules) {
const rules = detector.custom_rules;
rules.forEach(rule => {
if (rule.scope) {
const scopeFields = Object.keys(rule.scope);
const ruleScope: DetectorRuleScope = rule.scope;
const scopeFields = Object.keys(ruleScope);
scopeFields.forEach(scopeField => {
const filter = rule.scope[scopeField];
const filter = ruleScope[scopeField];
const filterId = filter.filter_id;
if (filtersInUse[filterId] === undefined) {
filtersInUse[filterId] = { jobs: [], detectors: [] };
Expand Down
7 changes: 7 additions & 0 deletions x-pack/legacy/plugins/ml/server/models/filter/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* 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 { FilterManager, Filter, FormFilter } from './filter_manager';
19 changes: 19 additions & 0 deletions x-pack/legacy/plugins/ml/server/new_platform/filters_schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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.
*/

import { schema } from '@kbn/config-schema';

export const createFilterSchema = {
filterId: schema.string(),
description: schema.maybe(schema.string()),
items: schema.arrayOf(schema.string()),
};

export const updateFilterSchema = {
description: schema.maybe(schema.string()),
addItems: schema.maybe(schema.arrayOf(schema.string())),
removeItems: schema.maybe(schema.arrayOf(schema.string())),
};
1 change: 0 additions & 1 deletion x-pack/legacy/plugins/ml/server/new_platform/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ import { dataVisualizerRoutes } from '../routes/data_visualizer';
import { calendars } from '../routes/calendars';
// @ts-ignore: could not find declaration file for module
import { fieldsService } from '../routes/fields_service';
// @ts-ignore: could not find declaration file for module
import { filtersRoutes } from '../routes/filters';
// @ts-ignore: could not find declaration file for module
import { resultsServiceRoutes } from '../routes/results_service';
Expand Down
11 changes: 9 additions & 2 deletions x-pack/legacy/plugins/ml/server/routes/apidoc.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"DeleteJobs",
"CloseJobs",
"JobsSummary",
"JobsWithTimerange",
"JobsWithTimeRange",
"CreateFullJobsList",
"GetAllGroups",
"UpdateGroups",
Expand All @@ -69,6 +69,13 @@
"GetAllJobAndGroupIds",
"GetLookBackProgress",
"ValidateCategoryExamples",
"TopCategories"
"TopCategories",
"Filters",
"GetFilters",
"GetFilterById",
"CreateFilter",
"UpdateFilter",
"DeleteFilter",
"GetFiltersStats"
]
}
Loading