Преглед изворни кода

heatmap: add ES histogram converter

Alexander Zobnin пре 8 година
родитељ
комит
3170f0d84a

+ 67 - 5
public/app/plugins/panel/heatmap/heatmap_data_converter.ts

@@ -1,6 +1,7 @@
 ///<reference path="../../../headers/common.d.ts" />
 
 import _ from 'lodash';
+import TimeSeries from 'app/core/time_series2';
 
 let VALUE_INDEX = 0;
 let TIME_INDEX = 1;
@@ -15,6 +16,48 @@ interface YBucket {
   values: number[];
 }
 
+function elasticHistogramToHeatmap(series) {
+  let seriesBuckets = _.map(series, (s: TimeSeries) => {
+    return convertEsSeriesToHeatmap(s);
+  });
+  let buckets = mergeBuckets(seriesBuckets);
+  return buckets;
+}
+
+function convertEsSeriesToHeatmap(series: TimeSeries, saveZeroCounts = false) {
+  let xBuckets: XBucket[] = [];
+
+  _.forEach(series.datapoints, point => {
+    let bound = series.alias;
+    let count = point[VALUE_INDEX];
+    let values = new Array(count);
+    values.fill(Number(bound));
+
+    let valueBuckets = {};
+    valueBuckets[bound] = {
+      y: Number(bound),
+      values: values
+    };
+
+    let xBucket: XBucket = {
+      x: point[TIME_INDEX],
+      buckets: valueBuckets
+    };
+
+    // Don't push buckets vith 0 count until saveZeroCounts flag is set
+    if (count !== 0 || (count === 0 && saveZeroCounts)) {
+      xBuckets.push(xBucket);
+    }
+  });
+
+  let heatmap: any = {};
+  _.forEach(xBuckets, (bucket: XBucket) => {
+    heatmap[bucket.x] = bucket;
+  });
+
+  return heatmap;
+}
+
 /**
  * Convert set of time series into heatmap buckets
  * @return {Object}    Heatmap object:
@@ -321,20 +364,29 @@ function mergeBuckets(seriesBuckets) {
     } else {
       _.forEach(seriesBucket, (xBucket, xBound) => {
         if (mergedBuckets[xBound]) {
-          mergedBuckets[xBound].points = xBucket.points.concat(mergedBuckets[xBound].points);
-          mergedBuckets[xBound].values = xBucket.values.concat(mergedBuckets[xBound].values);
+          if (xBucket.points) {
+            mergedBuckets[xBound].points = xBucket.points.concat(mergedBuckets[xBound].points);
+          }
+          if (xBucket.values) {
+            mergedBuckets[xBound].values = xBucket.values.concat(mergedBuckets[xBound].values);
+          }
 
           _.forEach(xBucket.buckets, (yBucket, yBound) => {
             let bucket = mergedBuckets[xBound].buckets[yBound];
             if (bucket && bucket.values) {
               mergedBuckets[xBound].buckets[yBound].values = bucket.values.concat(yBucket.values);
-              mergedBuckets[xBound].buckets[yBound].points = bucket.points.concat(yBucket.points);
+
+              if (bucket.points) {
+                mergedBuckets[xBound].buckets[yBound].points = bucket.points.concat(yBucket.points);
+              }
             } else {
               mergedBuckets[xBound].buckets[yBound] = yBucket;
             }
 
             let points = mergedBuckets[xBound].buckets[yBound].points;
-            mergedBuckets[xBound].buckets[yBound].seriesStat = getSeriesStat(points);
+            if (points) {
+              mergedBuckets[xBound].buckets[yBound].seriesStat = getSeriesStat(points);
+            }
           });
         } else {
           mergedBuckets[xBound] = xBucket;
@@ -363,10 +415,15 @@ function logp(value, base) {
  * @param objB
  */
 function isHeatmapDataEqual(objA: any, objB: any): boolean {
-  let is_eql = true;
+  let is_eql = !emptyXOR(objA, objB);
 
   _.forEach(objA, (xBucket: XBucket, x) => {
     if (objB[x]) {
+      if (emptyXOR(xBucket.buckets, objB[x].buckets)) {
+        is_eql = false;
+        return false;
+      }
+
       _.forEach(xBucket.buckets, (yBucket: YBucket, y) => {
         if (objB[x].buckets && objB[x].buckets[y]) {
           if (objB[x].buckets[y].values) {
@@ -396,8 +453,13 @@ function isHeatmapDataEqual(objA: any, objB: any): boolean {
   return is_eql;
 }
 
+function emptyXOR(foo: any, bar: any): boolean {
+  return (_.isEmpty(foo) || _.isEmpty(bar)) && !(_.isEmpty(foo) && _.isEmpty(bar));
+}
+
 export {
   convertToHeatMap,
+  elasticHistogramToHeatmap,
   convertToCards,
   removeZeroBuckets,
   mergeZeroBuckets,

+ 68 - 1
public/app/plugins/panel/heatmap/specs/heatmap_data_converter_specs.ts

@@ -3,7 +3,7 @@
 import _ from 'lodash';
 import { describe, beforeEach, it, sinon, expect, angularMocks } from '../../../../../test/lib/common';
 import TimeSeries from 'app/core/time_series2';
-import { convertToHeatMap, isHeatmapDataEqual } from '../heatmap_data_converter';
+import { convertToHeatMap, elasticHistogramToHeatmap, isHeatmapDataEqual } from '../heatmap_data_converter';
 
 describe('isHeatmapDataEqual', () => {
   let ctx: any = {};
@@ -40,10 +40,27 @@ describe('isHeatmapDataEqual', () => {
     let heatmapE = _.cloneDeep(ctx.heatmapA);
     heatmapE['1422774000000'].buckets['1'].values = [1, 1.6];
 
+    let empty = {};
+    let emptyValues = _.cloneDeep(ctx.heatmapA);
+    emptyValues['1422774000000'].buckets['1'].values = [];
+
     expect(isHeatmapDataEqual(ctx.heatmapA, ctx.heatmapB)).to.be(true);
+    expect(isHeatmapDataEqual(ctx.heatmapB, ctx.heatmapA)).to.be(true);
+
     expect(isHeatmapDataEqual(ctx.heatmapA, heatmapC)).to.be(true);
+    expect(isHeatmapDataEqual(heatmapC, ctx.heatmapA)).to.be(true);
+
     expect(isHeatmapDataEqual(ctx.heatmapA, heatmapD)).to.be(false);
+    expect(isHeatmapDataEqual(heatmapD, ctx.heatmapA)).to.be(false);
+
     expect(isHeatmapDataEqual(ctx.heatmapA, heatmapE)).to.be(false);
+    expect(isHeatmapDataEqual(heatmapE, ctx.heatmapA)).to.be(false);
+
+    expect(isHeatmapDataEqual(empty, ctx.heatmapA)).to.be(false);
+    expect(isHeatmapDataEqual(ctx.heatmapA, empty)).to.be(false);
+
+    expect(isHeatmapDataEqual(emptyValues, ctx.heatmapA)).to.be(false);
+    expect(isHeatmapDataEqual(ctx.heatmapA, emptyValues)).to.be(false);
   });
 });
 
@@ -123,3 +140,53 @@ describe('HeatmapDataConverter', () => {
     });
   });
 });
+
+describe('ES Histogram converter', () => {
+  let ctx: any = {};
+
+  beforeEach(() => {
+    ctx.series = [];
+    ctx.series.push(new TimeSeries({
+      datapoints: [[1, 1422774000000], [0, 1422774060000]],
+      alias: '1', label: '1'
+    }));
+    ctx.series.push(new TimeSeries({
+      datapoints: [[1, 1422774000000], [3, 1422774060000]],
+      alias: '2', label: '2'
+    }));
+    ctx.series.push(new TimeSeries({
+      datapoints: [[0, 1422774000000], [1, 1422774060000]],
+      alias: '3', label: '3'
+    }));
+  });
+
+  describe('when converting ES histogram', () => {
+
+    beforeEach(() => {
+    });
+
+    it('should build proper heatmap data', () => {
+      let expectedHeatmap = {
+        '1422774000000': {
+          x: 1422774000000,
+          buckets: {
+            '1': { y: 1, values: [1] },
+            '2': { y: 2, values: [2] }
+          }
+        },
+        '1422774060000': {
+          x: 1422774060000,
+          buckets: {
+            '2': { y: 2, values: [2, 2, 2] },
+            '3': { y: 3, values: [3] }
+          }
+        },
+      };
+
+      let heatmap = elasticHistogramToHeatmap(ctx.series);
+      console.log(heatmap);
+      expect(isHeatmapDataEqual(heatmap, expectedHeatmap)).to.be(true);
+    });
+  });
+});
+