Skip to content

Commit

Permalink
[ML] New Platform server shim: update filters routes to use new platf…
Browse files Browse the repository at this point in the history
…orm router (#57597)

* [ML] Update filters routes to use new platform router

* [ML] Edits to filters route following review

* [ML] Edits following review and fix job service api docs

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
peteharverson and elasticmachine authored Feb 14, 2020
1 parent 6bd09d6 commit 73cb0aa
Show file tree
Hide file tree
Showing 10 changed files with 410 additions and 200 deletions.
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

0 comments on commit 73cb0aa

Please sign in to comment.