Skip to content

Commit af5215f

Browse files
[ML] Fix Single Metric Viewer for multi week bucket spans (#19759)
* [ML] Fix Single Metric Viewer for multi week bucket spans * [ML] Edit to comment in ML time buckets calcEsInterval
1 parent c853072 commit af5215f

File tree

2 files changed

+66
-4
lines changed

2 files changed

+66
-4
lines changed

x-pack/plugins/ml/public/util/__tests__/ml_time_buckets.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
import ngMock from 'ng_mock';
1010
import expect from 'expect.js';
1111
import moment from 'moment';
12-
import { IntervalHelperProvider, getBoundsRoundedToInterval } from '../ml_time_buckets';
12+
import {
13+
IntervalHelperProvider,
14+
getBoundsRoundedToInterval,
15+
calcEsInterval } from '../ml_time_buckets';
1316

1417
describe('ML - time buckets', () => {
1518

@@ -125,7 +128,7 @@ describe('ML - time buckets', () => {
125128

126129
});
127130

128-
describe('getBoundsRoundedToInterval ', () => {
131+
describe('getBoundsRoundedToInterval', () => {
129132
// Must include timezone when creating moments for this test to ensure
130133
// checks are correct when running tests in different timezones.
131134
const testBounds = { min: moment('2017-01-05T10:11:12.000+00:00'), max: moment('2017-10-26T09:08:07.000+00:00') };
@@ -156,4 +159,24 @@ describe('ML - time buckets', () => {
156159

157160
});
158161

162+
describe('calcEsInterval', () => {
163+
it('returns correct interval for various durations', () => {
164+
expect(calcEsInterval(moment.duration(500, 'ms'))).to.eql({ value: 500, unit: 'ms', expression: '500ms' });
165+
expect(calcEsInterval(moment.duration(1000, 'ms'))).to.eql({ value: 1, unit: 's', expression: '1s' });
166+
expect(calcEsInterval(moment.duration(15, 's'))).to.eql({ value: 15, unit: 's', expression: '15s' });
167+
expect(calcEsInterval(moment.duration(60, 's'))).to.eql({ value: 1, unit: 'm', expression: '1m' });
168+
expect(calcEsInterval(moment.duration(1, 'm'))).to.eql({ value: 1, unit: 'm', expression: '1m' });
169+
expect(calcEsInterval(moment.duration(60, 'm'))).to.eql({ value: 1, unit: 'h', expression: '1h' });
170+
expect(calcEsInterval(moment.duration(3, 'h'))).to.eql({ value: 3, unit: 'h', expression: '3h' });
171+
expect(calcEsInterval(moment.duration(24, 'h'))).to.eql({ value: 1, unit: 'd', expression: '1d' });
172+
expect(calcEsInterval(moment.duration(3, 'd'))).to.eql({ value: 3, unit: 'd', expression: '3d' });
173+
expect(calcEsInterval(moment.duration(7, 'd'))).to.eql({ value: 1, unit: 'w', expression: '1w' });
174+
expect(calcEsInterval(moment.duration(1, 'w'))).to.eql({ value: 1, unit: 'w', expression: '1w' });
175+
expect(calcEsInterval(moment.duration(4, 'w'))).to.eql({ value: 28, unit: 'd', expression: '28d' });
176+
expect(calcEsInterval(moment.duration(1, 'M'))).to.eql({ value: 1, unit: 'M', expression: '1M' });
177+
expect(calcEsInterval(moment.duration(12, 'M'))).to.eql({ value: 1, unit: 'y', expression: '1y' });
178+
expect(calcEsInterval(moment.duration(1, 'y'))).to.eql({ value: 1, unit: 'y', expression: '1y' });
179+
});
180+
});
181+
159182
});

x-pack/plugins/ml/public/util/ml_time_buckets.js

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@
66

77

88

9-
// custom TimeBuckets which inherits from the standrd kibana TimeBuckets
9+
// custom TimeBuckets which inherits from the standard kibana TimeBuckets
1010
// this adds the ability to override the barTarget and maxBars settings
1111
// allowing for a more granular visualization interval without having to
1212
// modify the global settings stored in the kibana config
1313

1414
import _ from 'lodash';
1515
import moment from 'moment';
16+
import dateMath from '@kbn/datemath';
1617

1718
import { TimeBucketsCalcAutoIntervalProvider } from 'plugins/ml/util/ml_calc_auto_interval';
1819
import { inherits } from 'plugins/ml/util/inherits';
19-
import { calcEsInterval } from 'ui/time_buckets/calc_es_interval';
20+
21+
const unitsDesc = dateMath.unitsDesc;
22+
const largeMax = unitsDesc.indexOf('w'); // Multiple units of week or longer converted to days for ES intervals.
2023

2124
import { TimeBuckets } from 'ui/time_buckets';
2225
export function IntervalHelperProvider(Private, timefilter, config) {
@@ -147,3 +150,39 @@ export function getBoundsRoundedToInterval(bounds, interval, inclusiveEnd = fals
147150
}
148151
return { min: moment(adjustedMinMs), max: moment(adjustedMaxMs) };
149152
}
153+
154+
export function calcEsInterval(duration) {
155+
// Converts a moment.duration into an Elasticsearch compatible interval expression,
156+
// and provides associated metadata.
157+
158+
// Note this is a copy of Kibana's ui/time_buckets/calc_es_interval,
159+
// but with the definition of a 'large' unit changed from 'M' to 'w',
160+
// bringing it into line with the time units supported by Elasticsearch
161+
for (let i = 0; i < unitsDesc.length; i++) {
162+
const unit = unitsDesc[i];
163+
const val = duration.as(unit);
164+
// find a unit that rounds neatly
165+
if (val >= 1 && Math.floor(val) === val) {
166+
167+
// if the unit is "large", like years, but isn't set to 1, ES will throw an error.
168+
// So keep going until we get out of the "large" units.
169+
if (i <= largeMax && val !== 1) {
170+
continue;
171+
}
172+
173+
return {
174+
value: val,
175+
unit: unit,
176+
expression: val + unit
177+
};
178+
}
179+
}
180+
181+
const ms = duration.as('ms');
182+
return {
183+
value: ms,
184+
unit: 'ms',
185+
expression: ms + 'ms'
186+
};
187+
}
188+

0 commit comments

Comments
 (0)