Histogram: Fix runaway bucket densification with extremely sparse + large datasets (#114557)
* test(histogram): failing test for runaway densification * fix(histogram): maximum bucket densification avoids OOM error * fix(histogram): handle multiple densified buckets
This commit is contained in:
@@ -896,6 +896,42 @@ describe('getHistogramFields', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should prevent excessive densification when sparse histogram has large gaps', () => {
|
||||
const result = getHistogramFields(
|
||||
toDataFrame({
|
||||
meta: {
|
||||
type: DataFrameType.HeatmapCells,
|
||||
},
|
||||
fields: [
|
||||
{ name: 'yMin', type: FieldType.number, values: [0.001, 1000] },
|
||||
{ name: 'yMax', type: FieldType.number, values: [0.00101, 1010] },
|
||||
{ name: 'count', type: FieldType.number, values: [10, 20] },
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result!.counts[0].values.length).toBeLessThanOrEqual(1001);
|
||||
});
|
||||
|
||||
it('should handle multiple observed buckets when hitting densification limit', () => {
|
||||
const result = getHistogramFields(
|
||||
toDataFrame({
|
||||
meta: {
|
||||
type: DataFrameType.HeatmapCells,
|
||||
},
|
||||
fields: [
|
||||
{ name: 'yMin', type: FieldType.number, values: [0.001, 1000, 2000] },
|
||||
{ name: 'yMax', type: FieldType.number, values: [0.00101, 1010, 2020] },
|
||||
{ name: 'count', type: FieldType.number, values: [10, 20, 30] },
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result!.counts[0].values.every((v) => !isNaN(v))).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('joinHistograms', () => {
|
||||
|
||||
@@ -210,6 +210,8 @@ export function getHistogramFields(frame: DataFrame): HistogramFields | undefine
|
||||
let denseMins: number[] = [];
|
||||
let denseMaxs: number[] = [];
|
||||
|
||||
const MAX_DENSIFIED_BUCKETS = 1000;
|
||||
|
||||
for (let i = 0; i < uniqueMaxs.length; i++) {
|
||||
let curMax = uniqueMaxs[i];
|
||||
let curMin = uniqueMins[i];
|
||||
@@ -223,13 +225,17 @@ export function getHistogramFields(frame: DataFrame): HistogramFields | undefine
|
||||
curMax = curMax * bucketFactor;
|
||||
curMin = curMin * bucketFactor;
|
||||
|
||||
while (curMax < nextMax * 0.999999) {
|
||||
while (curMax < nextMax * 0.999999 && denseMaxs.length < MAX_DENSIFIED_BUCKETS) {
|
||||
denseMaxs.push(curMax);
|
||||
denseMins.push(curMin);
|
||||
|
||||
curMax = curMax * bucketFactor;
|
||||
curMin = curMin * bucketFactor;
|
||||
}
|
||||
|
||||
if (denseMaxs.length >= MAX_DENSIFIED_BUCKETS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +244,10 @@ export function getHistogramFields(frame: DataFrame): HistogramFields | undefine
|
||||
|
||||
for (let i = 0; i < yMaxField.values.length; i++) {
|
||||
let max = yMaxField.values[i];
|
||||
countsByMax.set(max, countsByMax.get(max) + countField.values[i]);
|
||||
let currentCount = countsByMax.get(max);
|
||||
if (currentCount !== undefined) {
|
||||
countsByMax.set(max, currentCount + countField.values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
let fields = {
|
||||
|
||||
Reference in New Issue
Block a user