Skip to content

Commit

Permalink
[ML] Aggregate anomalies table data using configured Kibana timezone (#…
Browse files Browse the repository at this point in the history
…26192) (#26252)

* [ML] Aggregate anomalies table data using configured Kibana timezone

* [ML] Move dataFormatTz prop out of controller scope
  • Loading branch information
peteharverson authored Nov 27, 2018
1 parent 14e2396 commit 63b7c9d
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 8 deletions.
8 changes: 7 additions & 1 deletion x-pack/plugins/ml/public/explorer/explorer_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import _ from 'lodash';
import $ from 'jquery';
import DragSelect from 'dragselect';
import moment from 'moment';
import moment from 'moment-timezone';

import 'plugins/ml/components/anomalies_table';
import 'plugins/ml/components/controls';
Expand Down Expand Up @@ -76,6 +76,7 @@ module.controller('MlExplorerController', function (
$timeout,
AppState,
Private,
config,
mlCheckboxShowChartsService,
mlSelectLimitService,
mlSelectIntervalService,
Expand All @@ -87,6 +88,10 @@ module.controller('MlExplorerController', function (
timefilter.enableTimeRangeSelector();
timefilter.enableAutoRefreshSelector();

// Pass the timezone to the server for use when aggregating anomalies (by day / hour) for the table.
const tzConfig = config.get('dateFormat:tz');
const dateFormatTz = (tzConfig !== 'Browser') ? tzConfig : moment.tz.guess();

const TimeBuckets = Private(IntervalHelperProvider);
const queryFilter = Private(FilterBarQueryFilterProvider);
const mlJobSelectService = Private(JobSelectServiceProvider);
Expand Down Expand Up @@ -946,6 +951,7 @@ module.controller('MlExplorerController', function (
mlSelectSeverityService.state.get('threshold').val,
timeRange.earliestMs,
timeRange.latestMs,
dateFormatTz,
500,
MAX_CATEGORY_EXAMPLES
).then((resp) => {
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/ml/public/services/ml_api_service/results.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const results = {
threshold,
earliestMs,
latestMs,
dateFormatTz,
maxRecords,
maxExamples) {

Expand All @@ -35,6 +36,7 @@ export const results = {
threshold,
earliestMs,
latestMs,
dateFormatTz,
maxRecords,
maxExamples
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*/

import _ from 'lodash';
import moment from 'moment';
import moment from 'moment-timezone';

import 'plugins/ml/components/anomalies_table';
import 'plugins/ml/components/controls';
Expand Down Expand Up @@ -71,6 +71,7 @@ module.controller('MlTimeSeriesExplorerController', function (
$timeout,
Private,
AppState,
config,
mlSelectIntervalService,
mlSelectSeverityService) {

Expand Down Expand Up @@ -98,6 +99,10 @@ module.controller('MlTimeSeriesExplorerController', function (
$scope.showForecast = true; // Toggles display of forecast data in the focus chart
$scope.showForecastCheckbox = false;

// Pass the timezone to the server for use when aggregating anomalies (by day / hour) for the table.
const tzConfig = config.get('dateFormat:tz');
const dateFormatTz = (tzConfig !== 'Browser') ? tzConfig : moment.tz.guess();

$scope.permissions = {
canForecastJob: checkPermission('canForecastJob')
};
Expand Down Expand Up @@ -682,6 +687,7 @@ module.controller('MlTimeSeriesExplorerController', function (
}

function loadAnomaliesTableData(earliestMs, latestMs) {

ml.results.getAnomaliesTableData(
[$scope.selectedJob.job_id],
$scope.criteriaFields,
Expand All @@ -690,6 +696,7 @@ module.controller('MlTimeSeriesExplorerController', function (
mlSelectSeverityService.state.get('threshold').val,
earliestMs,
latestMs,
dateFormatTz,
ANOMALIES_MAX_RESULTS
).then((resp) => {
const anomalies = resp.anomalies;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


import _ from 'lodash';
import moment from 'moment';
import moment from 'moment-timezone';

import {
getEntityFieldName,
Expand All @@ -17,13 +17,15 @@ import {


// Builds the items for display in the anomalies table from the supplied list of anomaly records.
export function buildAnomalyTableItems(anomalyRecords, aggregationInterval) {
// Provide the timezone to use for aggregating anomalies (by day or hour) as set in the
// Kibana dateFormat:tz setting.
export function buildAnomalyTableItems(anomalyRecords, aggregationInterval, dateFormatTz) {

// Aggregate the anomaly records if necessary, and create skeleton display records with
// time, detector (description) and source record properties set.
let displayRecords = [];
if (aggregationInterval !== 'second') {
displayRecords = aggregateAnomalies(anomalyRecords, aggregationInterval);
displayRecords = aggregateAnomalies(anomalyRecords, aggregationInterval, dateFormatTz);
} else {
// Show all anomaly records.
displayRecords = anomalyRecords.map((record) => {
Expand Down Expand Up @@ -115,7 +117,7 @@ export function buildAnomalyTableItems(anomalyRecords, aggregationInterval) {
});
}

function aggregateAnomalies(anomalyRecords, interval) {
function aggregateAnomalies(anomalyRecords, interval, dateFormatTz) {
// Aggregate the anomaly records by time, jobId, detectorIndex, and entity (by/over/partition).
// anomalyRecords assumed to be supplied in ascending time order.
if (anomalyRecords.length === 0) {
Expand All @@ -125,7 +127,9 @@ function aggregateAnomalies(anomalyRecords, interval) {
const aggregatedData = {};
anomalyRecords.forEach((record) => {
// Use moment.js to get start of interval.
const roundedTime = moment(record.timestamp).startOf(interval).valueOf();
const roundedTime = (dateFormatTz !== undefined) ?
moment(record.timestamp).tz(dateFormatTz).startOf(interval).valueOf() :
moment(record.timestamp).startOf(interval).valueOf();
if (aggregatedData[roundedTime] === undefined) {
aggregatedData[roundedTime] = {};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export function resultsServiceProvider(callWithRequest) {
threshold,
earliestMs,
latestMs,
dateFormatTz,
maxRecords = DEFAULT_QUERY_SIZE,
maxExamples = DEFAULT_MAX_EXAMPLES) {

Expand Down Expand Up @@ -163,7 +164,7 @@ export function resultsServiceProvider(callWithRequest) {
tableData.interval = (daysDiff < 2 ? 'hour' : 'day');
}

tableData.anomalies = buildAnomalyTableItems(records, tableData.interval);
tableData.anomalies = buildAnomalyTableItems(records, tableData.interval, dateFormatTz);

// Load examples for any categorization anomalies.
const categoryAnomalies = tableData.anomalies.filter(item => item.entityName === 'mlcategory');
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/ml/server/routes/results_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function getAnomaliesTableData(callWithRequest, payload) {
threshold,
earliestMs,
latestMs,
dateFormatTz,
maxRecords,
maxExamples } = payload;
return rs.getAnomaliesTableData(
Expand All @@ -31,6 +32,7 @@ function getAnomaliesTableData(callWithRequest, payload) {
threshold,
earliestMs,
latestMs,
dateFormatTz,
maxRecords,
maxExamples);
}
Expand Down

0 comments on commit 63b7c9d

Please sign in to comment.