Skip to content

Commit

Permalink
'Auto' interval must be correctly calculated for natural numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
alexwizp committed Sep 21, 2020
1 parent 8347fd0 commit b19bfb7
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/plugins/data/common/search/aggs/buckets/histogram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ export const getHistogramBucketAgg = ({
maxBucketsUiSettings: getConfig(UI_SETTINGS.HISTOGRAM_MAX_BARS),
maxBucketsUserInput: aggConfig.params.maxBars,
intervalBase: aggConfig.params.intervalBase,
esTypes: aggConfig.params.field?.spec?.esTypes || [],
});
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
calculateHistogramInterval,
CalculateHistogramIntervalParams,
} from './histogram_calculate_interval';
import { ES_FIELD_TYPES } from '../../../../types';

describe('calculateHistogramInterval', () => {
describe('auto calculating mode', () => {
Expand All @@ -40,6 +41,60 @@ describe('calculateHistogramInterval', () => {
});

describe('maxBucketsUserInput is defined', () => {
test('should set 1 as an interval for natural (integer) numbers that are less than maxBuckets #1', () => {
const p = {
...params,
maxBucketsUserInput: 100,
values: {
min: 1,
max: 50,
},
esTypes: [ES_FIELD_TYPES.INTEGER],
};
expect(calculateHistogramInterval(p)).toEqual(1);
});

test('should set 1 as an interval for natural (integer) numbers that are less than maxBuckets #2', () => {
const p = {
...params,
maxBucketsUiSettings: 1000,
maxBucketsUserInput: 258,
values: {
min: 521,
max: 689,
},
esTypes: [ES_FIELD_TYPES.INTEGER],
};
expect(calculateHistogramInterval(p)).toEqual(1);
});

test('should set correct interval for natural (integer) numbers that are greater than maxBuckets #1', () => {
const p = {
...params,
maxBucketsUserInput: 100,
values: {
min: 400,
max: 790,
},
esTypes: [ES_FIELD_TYPES.INTEGER],
};
expect(calculateHistogramInterval(p)).toEqual(5);
});

test('should set correct interval for natural (integer) numbers that are greater than maxBuckets #2', () => {
// diff === 3456211; interval === 50000; buckets === 69
const p = {
...params,
maxBucketsUserInput: 100,
values: {
min: 567,
max: 3456778,
},
esTypes: [ES_FIELD_TYPES.LONG],
};
expect(calculateHistogramInterval(p)).toEqual(50000);
});

test('should not set interval which more than largest possible', () => {
const p = {
...params,
Expand All @@ -48,6 +103,7 @@ describe('calculateHistogramInterval', () => {
min: 150,
max: 250,
},
esTypes: [ES_FIELD_TYPES.SHORT],
};
expect(calculateHistogramInterval(p)).toEqual(1);
});
Expand All @@ -61,6 +117,7 @@ describe('calculateHistogramInterval', () => {
min: 0.1,
max: 0.9,
},
esTypes: [ES_FIELD_TYPES.FLOAT],
})
).toBe(0.02);
});
Expand All @@ -74,6 +131,7 @@ describe('calculateHistogramInterval', () => {
min: 10.45,
max: 1000.05,
},
esTypes: [ES_FIELD_TYPES.FLOAT],
})
).toBe(100);
});
Expand All @@ -88,6 +146,7 @@ describe('calculateHistogramInterval', () => {
min: 0,
max: 100,
},
esTypes: [ES_FIELD_TYPES.BYTE],
})
).toEqual(1);
});
Expand All @@ -100,8 +159,9 @@ describe('calculateHistogramInterval', () => {
min: 1,
max: 10,
},
esTypes: [ES_FIELD_TYPES.INTEGER],
})
).toEqual(0.1);
).toEqual(1);
});

test('should set intervals for integer numbers (diff more than maxBucketsUiSettings)', () => {
Expand All @@ -113,6 +173,7 @@ describe('calculateHistogramInterval', () => {
min: 45678,
max: 90123,
},
esTypes: [ES_FIELD_TYPES.INTEGER],
})
).toEqual(500);
});
Expand All @@ -127,6 +188,7 @@ describe('calculateHistogramInterval', () => {
min: 1.245,
max: 2.9,
},
esTypes: [ES_FIELD_TYPES.FLOAT],
})
).toEqual(0.02);
expect(
Expand All @@ -136,6 +198,7 @@ describe('calculateHistogramInterval', () => {
min: 0.5,
max: 2.3,
},
esTypes: [ES_FIELD_TYPES.FLOAT],
})
).toEqual(0.02);
});
Expand All @@ -149,6 +212,7 @@ describe('calculateHistogramInterval', () => {
min: 0.1,
max: 0.9,
},
esTypes: [ES_FIELD_TYPES.FLOAT],
})
).toBe(0.01);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

import { isAutoInterval } from '../_interval_options';
import { ES_FIELD_TYPES } from '../../../../types';

interface IntervalValuesRange {
min: number;
Expand All @@ -30,6 +31,7 @@ export interface CalculateHistogramIntervalParams {
maxBucketsUserInput?: number | '';
intervalBase?: number;
values?: IntervalValuesRange;
esTypes: ES_FIELD_TYPES[];
}

/**
Expand Down Expand Up @@ -77,11 +79,26 @@ const calculateForGivenInterval = (
- The lower power of 10, times 2
- The lower power of 10, times 5
**/
const calculateAutoInterval = (diff: number, maxBars: number) => {
const calculateAutoInterval = (diff: number, maxBars: number, esTypes: ES_FIELD_TYPES[]) => {
const exactInterval = diff / maxBars;

const lowerPower = Math.pow(10, Math.floor(Math.log10(exactInterval)));
// For integer fields that are less than maxBars, we should use 1 as the value of interval
// Elastic has 4 integer data types: long, integer, short, byte
// see: https://www.elastic.co/guide/en/elasticsearch/reference/current/number.html
if (
diff < maxBars &&
esTypes.length === 1 &&
[
ES_FIELD_TYPES.INTEGER,
ES_FIELD_TYPES.LONG,
ES_FIELD_TYPES.SHORT,
ES_FIELD_TYPES.BYTE,
].includes(esTypes[0])
) {
return 1;
}

const lowerPower = Math.pow(10, Math.floor(Math.log10(exactInterval)));
const autoBuckets = diff / lowerPower;

if (autoBuckets > maxBars) {
Expand All @@ -103,6 +120,7 @@ export const calculateHistogramInterval = ({
maxBucketsUserInput,
intervalBase,
values,
esTypes,
}: CalculateHistogramIntervalParams) => {
const isAuto = isAutoInterval(interval);
let calculatedInterval = isAuto ? 0 : parseFloat(interval);
Expand All @@ -119,8 +137,10 @@ export const calculateHistogramInterval = ({
calculatedInterval = isAuto
? calculateAutoInterval(
diff,

// Mind maxBucketsUserInput can be an empty string, hence we need to ensure it here
Math.min(maxBucketsUiSettings, maxBucketsUserInput || maxBucketsUiSettings)
Math.min(maxBucketsUiSettings, maxBucketsUserInput || maxBucketsUiSettings),
esTypes
)
: calculateForGivenInterval(diff, calculatedInterval, maxBucketsUiSettings);
}
Expand Down

0 comments on commit b19bfb7

Please sign in to comment.