Skip to content

Commit 354cd01

Browse files
authored
[Lens] include empty rows setting for date histogram (#127453)
1 parent accb6bd commit 354cd01

43 files changed

Lines changed: 333 additions & 95 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/plugins/data/common/search/aggs/buckets/date_histogram.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Side Public License, v 1.
77
*/
88

9-
import { get, noop, find, every } from 'lodash';
9+
import { get, noop, find, every, omitBy, isNil } from 'lodash';
1010
import moment from 'moment-timezone';
1111
import { i18n } from '@kbn/i18n';
1212

@@ -71,6 +71,7 @@ export interface AggParamsDateHistogram extends BaseAggParams {
7171
format?: string;
7272
min_doc_count?: number;
7373
extended_bounds?: ExtendedBounds;
74+
extendToTimeRange?: boolean;
7475
}
7576

7677
export const getDateHistogramBucketAgg = ({
@@ -171,6 +172,11 @@ export const getDateHistogramBucketAgg = ({
171172
default: true,
172173
write: noop,
173174
},
175+
{
176+
name: 'extendToTimeRange',
177+
default: false,
178+
write: noop,
179+
},
174180
{
175181
name: 'scaleMetricValues',
176182
default: false,
@@ -303,6 +309,17 @@ export const getDateHistogramBucketAgg = ({
303309

304310
return;
305311
}
312+
313+
if (agg.params.extendToTimeRange && agg.buckets.hasBounds()) {
314+
const bucketBounds = agg.buckets.getBounds()!;
315+
output.params.extended_bounds = omitBy(
316+
{
317+
min: bucketBounds.min?.valueOf(),
318+
max: bucketBounds.max?.valueOf(),
319+
},
320+
isNil
321+
);
322+
}
306323
},
307324
toExpressionAst: extendedBoundsToAst,
308325
},

src/plugins/data/common/search/aggs/buckets/date_histogram_fn.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ describe('agg_expression_functions', () => {
2424
"params": Object {
2525
"customLabel": undefined,
2626
"drop_partials": undefined,
27+
"extendToTimeRange": undefined,
2728
"extended_bounds": undefined,
2829
"field": undefined,
2930
"format": undefined,
@@ -71,6 +72,7 @@ describe('agg_expression_functions', () => {
7172
"params": Object {
7273
"customLabel": undefined,
7374
"drop_partials": false,
75+
"extendToTimeRange": undefined,
7476
"extended_bounds": Object {
7577
"max": 2,
7678
"min": 1,

src/plugins/data/common/search/aggs/buckets/date_histogram_fn.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,13 @@ export const aggDateHistogram = (): FunctionDefinition => ({
118118
'With extended_bounds setting, you now can "force" the histogram aggregation to start building buckets on a specific min value and also keep on building buckets up to a max value ',
119119
}),
120120
},
121+
extendToTimeRange: {
122+
types: ['boolean'],
123+
help: i18n.translate('data.search.aggs.buckets.dateHistogram.extendToTimeRange.help', {
124+
defaultMessage:
125+
'Auto-sets the extended bounds to the currently applied time range. Is ignored if extended_bounds is set',
126+
}),
127+
},
121128
json: {
122129
types: ['string'],
123130
help: i18n.translate('data.search.aggs.buckets.dateHistogram.json.help', {

src/plugins/data/common/search/tabify/buckets.test.ts

Lines changed: 129 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import { TabifyBuckets } from './buckets';
10-
import { AggGroupNames } from '../aggs';
10+
import { AggGroupNames, IAggConfig } from '../aggs';
1111
import moment from 'moment';
1212

1313
interface Bucket {
@@ -58,20 +58,22 @@ describe('Buckets wrapper', () => {
5858
},
5959
};
6060

61-
const aggParams = {
62-
filters: [
63-
{
64-
label: '',
65-
input: { query: 'response:200' },
66-
},
67-
{
68-
label: '',
69-
input: { query: 'response:404' },
70-
},
71-
],
72-
};
61+
const agg = {
62+
params: {
63+
filters: [
64+
{
65+
label: '',
66+
input: { query: 'response:200' },
67+
},
68+
{
69+
label: '',
70+
input: { query: 'response:404' },
71+
},
72+
],
73+
},
74+
} as IAggConfig;
7375

74-
const buckets = new TabifyBuckets(aggResp, aggParams);
76+
const buckets = new TabifyBuckets(aggResp, agg);
7577

7678
expect(buckets).toHaveLength(2);
7779

@@ -88,20 +90,22 @@ describe('Buckets wrapper', () => {
8890
},
8991
};
9092

91-
const aggParams = {
92-
filters: [
93-
{
94-
label: '',
95-
input: { query: { query_string: { query: 'response:200' } } },
96-
},
97-
{
98-
label: '',
99-
input: { query: { query_string: { query: 'response:404' } } },
100-
},
101-
],
102-
};
93+
const agg = {
94+
params: {
95+
filters: [
96+
{
97+
label: '',
98+
input: { query: { query_string: { query: 'response:200' } } },
99+
},
100+
{
101+
label: '',
102+
input: { query: { query_string: { query: 'response:404' } } },
103+
},
104+
],
105+
},
106+
} as IAggConfig;
103107

104-
const buckets = new TabifyBuckets(aggResp, aggParams);
108+
const buckets = new TabifyBuckets(aggResp, agg);
105109

106110
expect(buckets).toHaveLength(2);
107111

@@ -117,16 +121,18 @@ describe('Buckets wrapper', () => {
117121
},
118122
};
119123

120-
const aggParams = {
121-
filters: [
122-
{
123-
label: '',
124-
input: { query: { match_all: {} } },
125-
},
126-
],
127-
};
124+
const agg = {
125+
params: {
126+
filters: [
127+
{
128+
label: '',
129+
input: { query: { match_all: {} } },
130+
},
131+
],
132+
},
133+
} as IAggConfig;
128134

129-
const buckets = new TabifyBuckets(aggResp, aggParams);
135+
const buckets = new TabifyBuckets(aggResp, agg);
130136

131137
expect(buckets).toHaveLength(1);
132138

@@ -174,103 +180,154 @@ describe('Buckets wrapper', () => {
174180
};
175181

176182
test('drops partial buckets when enabled', () => {
177-
const aggParams = {
178-
drop_partials: true,
179-
field: {
180-
name: 'date',
183+
const agg = {
184+
params: {
185+
drop_partials: true,
186+
field: {
187+
name: 'date',
188+
},
181189
},
182-
};
190+
} as IAggConfig;
183191
const timeRange = {
184192
from: moment(150),
185193
to: moment(350),
186194
timeFields: ['date'],
187195
};
188-
const buckets = new TabifyBuckets(aggResp, aggParams, timeRange);
196+
const buckets = new TabifyBuckets(aggResp, agg, timeRange);
189197

190198
expect(buckets).toHaveLength(1);
191199
});
192200

193-
test('keeps partial buckets when disabled', () => {
194-
const aggParams = {
195-
drop_partials: false,
196-
field: {
197-
name: 'date',
201+
test('drops partial buckets with missing buckets based on used_interval if provided', () => {
202+
const agg = {
203+
params: {
204+
drop_partials: true,
205+
used_interval: 'auto',
206+
field: {
207+
name: 'date',
208+
},
198209
},
210+
// interval is 100ms, but the data has holes
211+
serialize: () => ({
212+
params: { used_interval: '100ms' },
213+
}),
214+
} as unknown as IAggConfig;
215+
const timeRange = {
216+
from: moment(1050),
217+
to: moment(1700),
218+
timeFields: ['date'],
199219
};
220+
const buckets = new TabifyBuckets(
221+
{
222+
[AggGroupNames.Buckets]: [
223+
{ key: 0, value: {} },
224+
{ key: 1000, value: {} },
225+
{ key: 1100, value: {} },
226+
{ key: 1400, value: {} },
227+
{ key: 1500, value: {} },
228+
{ key: 1700, value: {} },
229+
{ key: 3000, value: {} },
230+
],
231+
},
232+
agg,
233+
timeRange
234+
);
235+
236+
// 1100, 1400 and 1500
237+
expect(buckets).toHaveLength(3);
238+
});
239+
240+
test('keeps partial buckets when disabled', () => {
241+
const agg = {
242+
params: {
243+
drop_partials: false,
244+
field: {
245+
name: 'date',
246+
},
247+
},
248+
} as IAggConfig;
200249
const timeRange = {
201250
from: moment(150),
202251
to: moment(350),
203252
timeFields: ['date'],
204253
};
205-
const buckets = new TabifyBuckets(aggResp, aggParams, timeRange);
254+
const buckets = new TabifyBuckets(aggResp, agg, timeRange);
206255

207256
expect(buckets).toHaveLength(4);
208257
});
209258

210259
test('keeps aligned buckets when enabled', () => {
211-
const aggParams = {
212-
drop_partials: true,
213-
field: {
214-
name: 'date',
260+
const agg = {
261+
params: {
262+
drop_partials: true,
263+
field: {
264+
name: 'date',
265+
},
215266
},
216-
};
267+
} as IAggConfig;
217268
const timeRange = {
218269
from: moment(100),
219270
to: moment(400),
220271
timeFields: ['date'],
221272
};
222-
const buckets = new TabifyBuckets(aggResp, aggParams, timeRange);
273+
const buckets = new TabifyBuckets(aggResp, agg, timeRange);
223274

224275
expect(buckets).toHaveLength(3);
225276
});
226277

227278
test('does not drop buckets for non-timerange fields', () => {
228-
const aggParams = {
229-
drop_partials: true,
230-
field: {
231-
name: 'other_time',
279+
const agg = {
280+
params: {
281+
drop_partials: true,
282+
field: {
283+
name: 'other_time',
284+
},
232285
},
233-
};
286+
} as IAggConfig;
234287
const timeRange = {
235288
from: moment(150),
236289
to: moment(350),
237290
timeFields: ['date'],
238291
};
239-
const buckets = new TabifyBuckets(aggResp, aggParams, timeRange);
292+
const buckets = new TabifyBuckets(aggResp, agg, timeRange);
240293

241294
expect(buckets).toHaveLength(4);
242295
});
243296

244297
test('does drop bucket when multiple time fields specified', () => {
245-
const aggParams = {
246-
drop_partials: true,
247-
field: {
248-
name: 'date',
298+
const agg = {
299+
params: {
300+
drop_partials: true,
301+
field: {
302+
name: 'date',
303+
},
249304
},
250-
};
305+
} as IAggConfig;
251306
const timeRange = {
252307
from: moment(100),
253308
to: moment(350),
254309
timeFields: ['date', 'other_datefield'],
255310
};
256-
const buckets = new TabifyBuckets(aggResp, aggParams, timeRange);
311+
const buckets = new TabifyBuckets(aggResp, agg, timeRange);
257312

258313
expect(buckets.buckets.map((b: Bucket) => b.key)).toEqual([100, 200]);
259314
});
260315

261316
test('does not drop bucket when no timeFields have been specified', () => {
262-
const aggParams = {
263-
drop_partials: true,
264-
field: {
265-
name: 'date',
317+
const agg = {
318+
params: {
319+
drop_partials: true,
320+
field: {
321+
name: 'date',
322+
},
266323
},
267-
};
324+
} as IAggConfig;
268325
const timeRange = {
269326
from: moment(100),
270327
to: moment(350),
271328
timeFields: [],
272329
};
273-
const buckets = new TabifyBuckets(aggResp, aggParams, timeRange);
330+
const buckets = new TabifyBuckets(aggResp, agg, timeRange);
274331

275332
expect(buckets.buckets.map((b: Bucket) => b.key)).toEqual([0, 100, 200, 300]);
276333
});

0 commit comments

Comments
 (0)