Skip to content

Commit

Permalink
Merge branch '7.x' into backport/7.x/pr-64193
Browse files Browse the repository at this point in the history
  • Loading branch information
elasticmachine authored Apr 24, 2020
2 parents 0f9bc37 + 6d2097e commit 0b47c25
Show file tree
Hide file tree
Showing 36 changed files with 1,436 additions and 166 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions src/plugins/data/common/es_query/kuery/ast/ast.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,33 @@ describe('kuery AST API', () => {
expect(fromLiteralExpression('true')).toEqual(booleanTrueLiteral);
expect(fromLiteralExpression('false')).toEqual(booleanFalseLiteral);
expect(fromLiteralExpression('42')).toEqual(numberLiteral);

expect(fromLiteralExpression('.3').value).toEqual(0.3);
expect(fromLiteralExpression('.36').value).toEqual(0.36);
expect(fromLiteralExpression('.00001').value).toEqual(0.00001);
expect(fromLiteralExpression('3').value).toEqual(3);
expect(fromLiteralExpression('-4').value).toEqual(-4);
expect(fromLiteralExpression('0').value).toEqual(0);
expect(fromLiteralExpression('0.0').value).toEqual(0);
expect(fromLiteralExpression('2.0').value).toEqual(2.0);
expect(fromLiteralExpression('0.8').value).toEqual(0.8);
expect(fromLiteralExpression('790.9').value).toEqual(790.9);
expect(fromLiteralExpression('0.0001').value).toEqual(0.0001);
expect(fromLiteralExpression('96565646732345').value).toEqual(96565646732345);

expect(fromLiteralExpression('..4').value).toEqual('..4');
expect(fromLiteralExpression('.3text').value).toEqual('.3text');
expect(fromLiteralExpression('text').value).toEqual('text');
expect(fromLiteralExpression('.').value).toEqual('.');
expect(fromLiteralExpression('-').value).toEqual('-');
expect(fromLiteralExpression('001').value).toEqual('001');
expect(fromLiteralExpression('00.2').value).toEqual('00.2');
expect(fromLiteralExpression('0.0.1').value).toEqual('0.0.1');
expect(fromLiteralExpression('3.').value).toEqual('3.');
expect(fromLiteralExpression('--4').value).toEqual('--4');
expect(fromLiteralExpression('-.4').value).toEqual('-.4');
expect(fromLiteralExpression('-0').value).toEqual('-0');
expect(fromLiteralExpression('00949').value).toEqual('00949');
});

test('should allow escaping of special characters with a backslash', () => {
Expand Down
5 changes: 2 additions & 3 deletions src/plugins/data/common/es_query/kuery/ast/kuery.peg
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,8 @@ UnquotedLiteral
if (sequence === 'true') return buildLiteralNode(true);
if (sequence === 'false') return buildLiteralNode(false);
if (chars.includes(wildcardSymbol)) return buildWildcardNode(sequence);
const number = Number(sequence);
const value = isNaN(number) ? sequence : number;
return buildLiteralNode(value);
const isNumberPattern = /^(-?[1-9]+\d*([.]\d+)?)$|^(-?0[.]\d*[1-9]+)$|^0$|^0.0$|^[.]\d{1,}$/
return buildLiteralNode(isNumberPattern.test(sequence) ? Number(sequence) : sequence);
}

UnquotedCharacter
Expand Down
175 changes: 75 additions & 100 deletions x-pack/plugins/ml/server/models/calendar/calendar_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
*/

import { difference } from 'lodash';
import Boom from 'boom';
import { IScopedClusterClient } from 'kibana/server';
import { EventManager, CalendarEvent } from './event_manager';

Expand Down Expand Up @@ -33,43 +32,31 @@ export class CalendarManager {
}

async getCalendar(calendarId: string) {
try {
const resp = await this._client('ml.calendars', {
calendarId,
});

const calendars = resp.calendars;
if (calendars.length) {
const calendar = calendars[0];
calendar.events = await this._eventManager.getCalendarEvents(calendarId);
return calendar;
} else {
throw Boom.notFound(`Calendar with the id "${calendarId}" not found`);
}
} catch (error) {
throw Boom.badRequest(error);
}
const resp = await this._client('ml.calendars', {
calendarId,
});

const calendars = resp.calendars;
const calendar = calendars[0]; // Endpoint throws a 404 if calendar is not found.
calendar.events = await this._eventManager.getCalendarEvents(calendarId);
return calendar;
}

async getAllCalendars() {
try {
const calendarsResp = await this._client('ml.calendars');

const events: CalendarEvent[] = await this._eventManager.getAllEvents();
const calendars: Calendar[] = calendarsResp.calendars;
calendars.forEach(cal => (cal.events = []));

// loop events and combine with related calendars
events.forEach(event => {
const calendar = calendars.find(cal => cal.calendar_id === event.calendar_id);
if (calendar) {
calendar.events.push(event);
}
});
return calendars;
} catch (error) {
throw Boom.badRequest(error);
}
const calendarsResp = await this._client('ml.calendars');

const events: CalendarEvent[] = await this._eventManager.getAllEvents();
const calendars: Calendar[] = calendarsResp.calendars;
calendars.forEach(cal => (cal.events = []));

// loop events and combine with related calendars
events.forEach(event => {
const calendar = calendars.find(cal => cal.calendar_id === event.calendar_id);
if (calendar) {
calendar.events.push(event);
}
});
return calendars;
}

/**
Expand All @@ -78,88 +65,76 @@ export class CalendarManager {
* @returns {Promise<*>}
*/
async getCalendarsByIds(calendarIds: string) {
try {
const calendars: Calendar[] = await this.getAllCalendars();
return calendars.filter(calendar => calendarIds.includes(calendar.calendar_id));
} catch (error) {
throw Boom.badRequest(error);
}
const calendars: Calendar[] = await this.getAllCalendars();
return calendars.filter(calendar => calendarIds.includes(calendar.calendar_id));
}

async newCalendar(calendar: FormCalendar) {
const calendarId = calendar.calendarId;
const events = calendar.events;
delete calendar.calendarId;
delete calendar.events;
try {
await this._client('ml.addCalendar', {
calendarId,
body: calendar,
});

if (events.length) {
await this._eventManager.addEvents(calendarId, events);
}
await this._client('ml.addCalendar', {
calendarId,
body: calendar,
});

// return the newly created calendar
return await this.getCalendar(calendarId);
} catch (error) {
throw Boom.badRequest(error);
if (events.length) {
await this._eventManager.addEvents(calendarId, events);
}

// return the newly created calendar
return await this.getCalendar(calendarId);
}

async updateCalendar(calendarId: string, calendar: Calendar) {
const origCalendar: Calendar = await this.getCalendar(calendarId);
try {
// update job_ids
const jobsToAdd = difference(calendar.job_ids, origCalendar.job_ids);
const jobsToRemove = difference(origCalendar.job_ids, calendar.job_ids);

// workout the differences between the original events list and the new one
// if an event has no event_id, it must be new
const eventsToAdd = calendar.events.filter(
event => origCalendar.events.find(e => this._eventManager.isEqual(e, event)) === undefined
);

// if an event in the original calendar cannot be found, it must have been deleted
const eventsToRemove: CalendarEvent[] = origCalendar.events.filter(
event => calendar.events.find(e => this._eventManager.isEqual(e, event)) === undefined
);

// note, both of the loops below could be removed if the add and delete endpoints
// allowed multiple job_ids

// add all new jobs
if (jobsToAdd.length) {
await this._client('ml.addJobToCalendar', {
calendarId,
jobId: jobsToAdd.join(','),
});
}

// remove all removed jobs
if (jobsToRemove.length) {
await this._client('ml.removeJobFromCalendar', {
calendarId,
jobId: jobsToRemove.join(','),
});
}
// update job_ids
const jobsToAdd = difference(calendar.job_ids, origCalendar.job_ids);
const jobsToRemove = difference(origCalendar.job_ids, calendar.job_ids);

// workout the differences between the original events list and the new one
// if an event has no event_id, it must be new
const eventsToAdd = calendar.events.filter(
event => origCalendar.events.find(e => this._eventManager.isEqual(e, event)) === undefined
);

// if an event in the original calendar cannot be found, it must have been deleted
const eventsToRemove: CalendarEvent[] = origCalendar.events.filter(
event => calendar.events.find(e => this._eventManager.isEqual(e, event)) === undefined
);

// note, both of the loops below could be removed if the add and delete endpoints
// allowed multiple job_ids

// add all new jobs
if (jobsToAdd.length) {
await this._client('ml.addJobToCalendar', {
calendarId,
jobId: jobsToAdd.join(','),
});
}

// add all new events
if (eventsToAdd.length !== 0) {
await this._eventManager.addEvents(calendarId, eventsToAdd);
}
// remove all removed jobs
if (jobsToRemove.length) {
await this._client('ml.removeJobFromCalendar', {
calendarId,
jobId: jobsToRemove.join(','),
});
}

// remove all removed events
await Promise.all(
eventsToRemove.map(async event => {
await this._eventManager.deleteEvent(calendarId, event.event_id);
})
);
} catch (error) {
throw Boom.badRequest(error);
// add all new events
if (eventsToAdd.length !== 0) {
await this._eventManager.addEvents(calendarId, eventsToAdd);
}

// remove all removed events
await Promise.all(
eventsToRemove.map(async event => {
await this._eventManager.deleteEvent(calendarId, event.event_id);
})
);

// return the updated calendar
return await this.getCalendar(calendarId);
}
Expand Down
36 changes: 11 additions & 25 deletions x-pack/plugins/ml/server/models/calendar/event_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/

import Boom from 'boom';

import { GLOBAL_CALENDAR } from '../../../common/constants/calendars';

export interface CalendarEvent {
Expand All @@ -23,41 +21,29 @@ export class EventManager {
}

async getCalendarEvents(calendarId: string) {
try {
const resp = await this._client('ml.events', { calendarId });
const resp = await this._client('ml.events', { calendarId });

return resp.events;
} catch (error) {
throw Boom.badRequest(error);
}
return resp.events;
}

// jobId is optional
async getAllEvents(jobId?: string) {
const calendarId = GLOBAL_CALENDAR;
try {
const resp = await this._client('ml.events', {
calendarId,
jobId,
});
const resp = await this._client('ml.events', {
calendarId,
jobId,
});

return resp.events;
} catch (error) {
throw Boom.badRequest(error);
}
return resp.events;
}

async addEvents(calendarId: string, events: CalendarEvent[]) {
const body = { events };

try {
return await this._client('ml.addEvent', {
calendarId,
body,
});
} catch (error) {
throw Boom.badRequest(error);
}
return await this._client('ml.addEvent', {
calendarId,
body,
});
}

async deleteEvent(calendarId: string, eventId: string) {
Expand Down
4 changes: 3 additions & 1 deletion x-pack/plugins/ml/server/routes/anomaly_detectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,14 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) {
/**
* @apiGroup AnomalyDetectors
*
* @api {put} /api/ml/anomaly_detectors/:jobId Instantiate an anomaly detection job
* @api {put} /api/ml/anomaly_detectors/:jobId Create an anomaly detection job
* @apiName CreateAnomalyDetectors
* @apiDescription Creates an anomaly detection job.
*
* @apiSchema (params) jobIdSchema
* @apiSchema (body) anomalyDetectionJobSchema
*
* @apiSuccess {Object} job the configuration of the job that has been created.
*/
router.put(
{
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/ml/server/routes/apidoc.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"GetCategoryExamples",
"GetPartitionFieldsValues",

"DataRecognizer",
"Modules",
"RecognizeIndex",
"GetModule",
"SetupModule",
Expand Down
12 changes: 10 additions & 2 deletions x-pack/plugins/ml/server/routes/data_visualizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,12 @@ export function dataVisualizerRoutes({ router, mlLicense }: RouteInitialization)
*
* @api {post} /api/ml/data_visualizer/get_field_stats/:indexPatternTitle Get stats for fields
* @apiName GetStatsForFields
* @apiDescription Returns fields stats of the index pattern.
* @apiDescription Returns the stats on individual fields in the specified index pattern.
*
* @apiSchema (params) indexPatternTitleSchema
* @apiSchema (body) dataVisualizerFieldStatsSchema
*
* @apiSuccess {Object} fieldName stats by field, keyed on the name of the field.
*/
router.post(
{
Expand Down Expand Up @@ -130,10 +132,16 @@ export function dataVisualizerRoutes({ router, mlLicense }: RouteInitialization)
*
* @api {post} /api/ml/data_visualizer/get_overall_stats/:indexPatternTitle Get overall stats
* @apiName GetOverallStats
* @apiDescription Returns overall stats of the index pattern.
* @apiDescription Returns the top level overall stats for the specified index pattern.
*
* @apiSchema (params) indexPatternTitleSchema
* @apiSchema (body) dataVisualizerOverallStatsSchema
*
* @apiSuccess {number} totalCount total count of documents.
* @apiSuccess {Object} aggregatableExistsFields stats on aggregatable fields that exist in documents.
* @apiSuccess {Object} aggregatableNotExistsFields stats on aggregatable fields that do not exist in documents.
* @apiSuccess {Object} nonAggregatableExistsFields stats on non-aggregatable fields that exist in documents.
* @apiSuccess {Object} nonAggregatableNotExistsFields stats on non-aggregatable fields that do not exist in documents.
*/
router.post(
{
Expand Down
Loading

0 comments on commit 0b47c25

Please sign in to comment.